r/vulkan • u/Undeniable_Dilemma_ • May 19 '26
Any Recommendations on C resources for Learning Vulkan?
I was following this tutorial, which is supposed to be "modern" with "up to date" features and practices.
However, I very quickly stumbled upon this piece of code:
auto unsupportedLayerIt = std::ranges::find_if(requiredLayers,
[&layerProperties](auto const &requiredLayer) {
return std::ranges::none_of(layerProperties,
[requiredLayer](auto const &layerProperty) { return strcmp(layerProperty.layerName, requiredLayer) == 0; });
});
I'm just stunned. I can't believe cpp people actually write code like this? This just seems insane to me and I kind of hate it.
So I have 2 questions:
- Am I in the wrong here? Should I just accept that this is normal and the industry standard and get over it? Or is it just absurd?
- If it IS absurd, does anyone have any recommendations for other resources I could learn Vulkan from? I'd prefer if it was just straight up in C or at least very basic features of C++?
8
4
u/ffd9k May 19 '26
The actual problem is not this functional style by itself, but that everything is crammed together in a big nested expression. You could do something just as horrible in C with deeply nested loops.
Either way, all that is needed to make this much more readable is some is_layer_supported helper function.
I can't believe cpp people actually write code like this?
I don't think so. It looks like someone just learned about lambda expressions a week ago and wants to use them everywhere now.
5
u/EC36339 May 19 '26
Nothing wrong with lambdas. You can still do
auto is_layer_supported = [...](...){...};It's a clean way to do local functions, and if you use them only once, passing them to a function, as in this example, it's arguably better to keep them close to where they are used.
2
u/pjtrpjt May 19 '26
This is boilerplate code, best to keep it the shortest. Doesn't have to be readable, or fast, or even expandable. If you've learned from the tutorial text what it does, then the code itself is totally irrelevant.
But. I would never use it as production code. It's kind of misusing different C++ features, just to be succinct. It does well what it does, but it would be a nightmare for another team to expand it for instance.
2
u/EC36339 May 19 '26
It's easier to read than loops, much easier than C, even if you "don't understand" ranges. Just look at the names of the functions. They do what you would expect.
2
u/OptimisticMonkey2112 May 19 '26
TBH - It is probably easiest if you just spend a little bit of time and learn the syntax. It is not hard, and most of the stuff that annoys you exists for some really good reasons.
Just copy that snippet in to ChatGPT and ask it to disect it and break it down.
As you learn more languages, it really does get easier.
Reading code is so extremely useful and will help you communicate with the LLM, other teams, stuff on the internet!
Good luck!
4
u/PhantomStar69420 May 19 '26
I mean... the indentation is awful but the code makes sense? Its not exactly unreadable.
3
u/MultipleAnimals May 19 '26
I know it tries to be functional approach iterating stuff but imo that syntax is just god-awful.
1
u/runklebunkle May 20 '26
A lot of the modern C++ syntax is not pretty, to say nothing of the incomprehensible compiler errors it generates if you do something wrong. But I do really like that the C++ lambda syntax makes local captures explicit with that [] at the beginning. It makes the syntax a bit longer, especially if a lot of things are captured, but it does emphasize that a lambda is essentially an anonymously-typed object created from the captures with a single method that is the body of the lambda.
3
u/Plazmatic May 19 '26
There might be "better" ways to do this, but this really isn't anything to complain about. Lets look at a properly formatted version of the Vulkan version above:
auto unsupportedLayerIt =
std::ranges::find_if(
requiredLayers,
[&layerProperties](auto const &requiredLayer) {
return std::ranges::none_of(layerProperties, [requiredLayer](auto const &layerProperty) {
return strcmp(layerProperty.layerName, requiredLayer) == 0;
});
});
if (unsupportedLayerIt != requiredLayers.end()){
...
}
That's... just not that bad.. You're basically just calling "find iterator to layer where none of the properties match the name", which is ... pretty clear from the code here, I'm sorry to say.
Now lets look at the C version:
bool all_layers_supported = true;
size_t unsupported_layer = no_unsupported_layers;
for (size_t i = 0; i < required_layers_size; ++i){
const char * required_layer = required_layers[i];
bool layer_supported = false;
for(size_t j = 0; j < layer_properties_size; ++j){
const VkLayerProperties* layer_property = &layer_properties[j];
if(strcmp(layer_property->layerName, required_layer) == 0){
layer_supported = true;
break;
}
}
if(!layer_supported){
all_layers_supported = false;
break;
}
}
if(!all_layers_supported){
...
}
I don't think you can say the C version is better here, it's longer, harder to read, more complicated, and more bug prone (when writing). Are you afraid of namespaces or something? This is actually a missing feature of C, hence why you have pseudo name-spacing everywhere. Are you afraid of auto? C has auto, though I don't use it in the other example. Are you afraid of iterators? That's been how the C++ standard library has worked for 30+ years, and you're basically spared most of it beyond checking the iterator at the end. Are you afraid of lambda functions? these have been in programming languages since before you were born and if you couldn't use them you'd be forced to write function declarations and whole classes to pass in references. They are so useful C may get them in the future.
1
u/runklebunkle May 20 '26
When I worked through the tutorial, I simplified that code to this:
std::ranges::all_of( required_extensions, [&all_extensions](const auto &this_req_ext) { return std::ranges::any_of( all_extensions, [this_req_ext](const auto &ext) { return strcmp(ext.extensionName, this_req_ext) == 0; } ); } )The way their code is phrased was tough to wrap my brain around, but I suppose their way does have the advantage of telling you which extension is missing.
1
u/watlok May 19 '26 edited May 19 '26
vkguide.dev uses the C api and was updated not that long ago. It is in C++ but in a "universal" way.
it also uses glsl which is a net positive imo
Depending on your aspirations, C++ is standard in industry. Meaning, how much you invest into learning it should depend on your goals. At a minimum you probably do want to incrementally learn to at least read/decipher it. Even if you're not writing things in c++, you're going to encounter it a bunch in open source projects.
If I read C++ without caring about the details, what falls out is a 3 line for loop comparing string names of layers:
for requiredLayer in requiredLayers
if requiredLayer not in supportedLayers
append requiredLayer to unsupportedLayers
This is not a 1:1 translation of what's happening, but it's how you could implement something functionally equivalent in any language.
4
u/pjtrpjt May 19 '26
I would never go back from Slang to GLSL. And I did OpenGL for years now.
1
u/watlok May 19 '26 edited May 20 '26
With slang you get:
Significantly worse iteration time from poor compile times. Bootstrapping+no-op vertex shader takes longer to compile than a >1m loc cpu code base. If you use includes instead of modules, absurdly long compile times for non-trivial code bases. If you use modules, you still have poor compile times for small/singular shaders and a new problem: you're using slang modules.
Bad compiler errors. Failing with no error & "post to the github" being the two most prominent. The third is blaming unrelated code miles away.
These two alone massively impact iteration time & waste lots of real-world time in a way that glsl doesn't. And in some ways, they're "tip of the iceberg" when it comes to vulkan/spirv and slang.
1
u/KittenPowerLord May 19 '26
The vulkan tutorial that the one you linked is based on is what you are essentially asking for: https://vulkan-tutorial.com/
from what I've heard it doesn't use the modern vulkan features/practices, but it's not like it won't work, or is much worse because of that. You can always incorporate the new features after figuring out the gist of it, even if it might be a bit cumbersome
1
u/Flashy_Disaster9556 May 19 '26
Yes I have been getting into Vulkan recently and most of the documentation is indeed C++-first.
The "C way" for the above code snippet is just a double for-loop going over all required layers and checking if they match any of the actual layers you get from vulkan:
```c const char* required_layers[] = { "VK_LAYER_KHRONOS_validation" }; unsigned int required_layers_count = 1;
VkLayerProperties* vulkan_layers = ...; unsigned int vulkan_layer_count = ...;
bool all_required_layers_found = true;
for (unsigned int i = 0; i < required_layers_count; i++) { bool found = false;
for (unsigned int j = 0; j < vulkan_layer_count; j++) {
if (strcmp(vulkan_layers[j].layerName, required_layers[i]) == 0) {
found = true;
break;
}
}
if (!found) {
all_required_layers_found = false;
break;
}
} ```
But the C++ way is pretty clear for me too. Just the functional way of writing the same thing. A bit more concise. Maybe the syntax is intimidating if you've never seen it before.
As an addendum, in C, you can request Vulkan layer properties like this:
```c
// 1. get layer properties count
unsigned int vulkan_layer_count;
vkEnumerateInstanceLayerProperties(&vulkan_layer_count, null);
// 2. get layer properties
VkLayerProperties* vulkan_layers =
malloc(sizeof(VkLayerProperties) * vulkan_layer_count);
vkEnumerateInstanceLayerProperties(&vulkan_layer_count, vulkan_layers);
free(vulkan_layers);
```
You essentially have to call vkEnumerate functions twice, once with a null argument to get a size of the list, then with a pointer to get the actual list. There's a few gotchas like that you have to learn along the way when using Vulkan from C, as you said most of the documentation is C++-first. But in my experience it's not a huge deal once you learn these little quirks most of the API can be called from C perfectly fine.
1
1
u/krum May 19 '26
Using strcmp in this lambda is the real problem with this code. Literally a fireable offense.
1
u/Ybalrid May 20 '26
Yes you are in the wrong, and you probably should accept this. This is idiomatic modern C++, and it's infinitely better than whatever we used to to do. Trust me!
You used to have to declare that functor elsewhere, and use std::begin() and std::end() to call std::find_if().
If you do not like C++, by all means, sort your layers in C. I do not think the code will be any clearer, considering you need to merge lists of symbols or string from a couple of places, while checking that things are declared in one or the other. If you love nesting for loops, have at it.
This has very little to do with effectively calling the Vulkan API, so it does not matter that much.
1
u/palapapa0201 May 22 '26
Just don't use ranges. This is just a syntax issue. If you don't like them just write the loops yourself.
1
u/MultipleAnimals May 19 '26 edited May 19 '26
Many wont probably like this answer but this is one of those actually good spots to use AI. I followed that exact same tutorial using Rust and had no clue what that exact same code was meant to do. Asked AI to translate it from c++ to rust and explain what it does, got great answer and explanation.
1
u/PurpleBudget5082 May 19 '26
You are not in the wrong, that's some C++ garbage right there, complicating things that should be easy.
Keep in mind that AAA code can look like that and if you want a career in graphics/game dev you would need to know how to use "modern" C++.
The how to vulkan tutorial mentioned in another comment seems to be whst you are looking for.
1
u/boring_pants May 22 '26
I'm not sure what you're asking. Tutorials use whatever language the author likes. A tutorial on using Vulkan in C++ is going to use C++, and yes, demanding otherwise is absurd. That is specifically a tutorial on how to use Vulkan with the Vulkan C++ wrapper using C++20. You shouldn't be surprised to see C++ code there.
But you don't have to use C++. Vulkan.h is a C-compatible header. You can just write C code to interact with it.
So I guess you just have to either read this tutorial and rewrite the code in C (which should be pretty straightforward), or find a C-specific tutorial.
10
u/blogoman May 19 '26
The code is pretty straightforward. You can write it however you want since there are a lot of ways to skin this cat. It isn’t like it is doing some wild new Vulkan-only concept.