I need an SDL3 GLSL Cheatsheet

Howdy folks, I’m trying out the new GPU API. So far it actually all reads pretty straightforward and seems very nice.

I’m having some problems with some of the numbers used in these layout sections. From what I can gather, this isn’t so much an SDL3 thing as it is a Vulkan/SPIRV thing, but it seems some of these numbers (set, binding) are mapped internally in SDL3, and I’m having trouble making sense of what they are.

After a few hours of fiddling, here’s what I think I know.

  • (set = 1) seems to be mapped to the vertex shader’s UBO
  • (set = 3) seems to be mapped to the fragment shader’s UBO
  • not really sure what these bindings do
  • and I’m also unsure what the slot_index in either of the PushGPUXXXUniformData functions do. (though the combination in this screenshot works)
  • there also seems to be some amount of struct padding inside the UBO that I’ve discovered, where it seems to be maybe 16B aligned, and two vec3’s in the same UBO will have 4B of padding between them.

Is there any kind of cheatsheet for these. Or maybe someone who’s more familiar about this realm of shader development can enlighten me.

Code is here, if anyone should like to look at it.

The SDL3 GPU docs say what bindings go where, and why.

A couple other things:

  1. It’s pretty much a given that structs are going to be padded. You’ll have to take care to make sure the padding assumed by the GPU matches the CPU. For GLSL, look up STD140 layout.

  2. IDK if Vulkan requires a minimum GLSL version, but the SDL examples specify #version 450. Also, this isn’t for OpenGL ES, so you can leave out the es part at the end of the #version line.

  3. Because this isn’t for OpenGL ES, you can leave out the line precision mediump float

Ah ok thank you! I’d looked in the SDL docs for SDL_PushGPUVertexUniformData and tried to read through SDL.h as well. Seems kind of an odd place to put these details, as they aren’t really relevant to that function.

  1. I have been reading up on that, this is my first time using a UBO like this. The thing is it’s not a matter of matching the padding of a struct, as I can have something like

    layout(set = 1, binding = 0) uniform UBO {
     vec3 addColor;
     vec3 subColor;
    };
    

    and pass in with

    float payload[6] = {1, 2, 3, 4, 5, 6};
    SDL_PushGPUVertexUniformData(cmdbuf, 1, &payload, sizeof(float) * 6);
    

    and the results will be

    addColor = {1, 2, 3};
    subColor = {UNDEFINED, 4, 5}; // 6 
    

    however if I change it to payload[8] and vec4 ..., then everything works. So it’s not simply struct padding matching on the CPU and GPU, but that the GPU has it’s own system for padding.

  2. It wasn’t so much that Vulkan required a particular version, but glslangValidator, which I’m using to compile the glsl to SPIRV does.

  3. Does setting the precision not translate to SPIRV either?

Thanks again, so that explains the set values. I’m still not sure where binding and slot_index come in, but maybe I should have a more thorough readthrough of the API docs. I wonder if I’m just a little early to this and should maybe wait for SDLSL or even the SDL3 book.

SDLSL won’t save you from needing to pay attention to shader struct alignment. That’s a requirement. I recommend thumbing through the wiki and our examples repo: GitHub - TheSpydog/SDL_gpu_examples: Example collection for the SDL_GPU API

I could probably be more explicit in the wiki about alignment requirements, I’ll fix that.

Yeah, that repo is how I managed to get the magic numbers for the set values. But I’m still not sure where the slot_index numbers come from, why mine work, and why I get such strange results when I change them.

For example, in SDL_gpu_examples DepthSampler.c

// PositionColorTransform.vert.hlsl
cbuffer UBO : register(b0, space1)
{
    float4x4 b : packoffset(c0);
    float4x4 transform : packoffset(c1);
};
// SolidColorDepth.frag
cbuffer UBO : register(b0, space3)
{
    float NearPlane;
    float FarPlane;
};
// DepthSampler.c
SDL_PushGPUVertexUniformData(cmdbuf, 1, &viewproj, sizeof(viewproj));
SDL_PushGPUFragmentUniformData(cmdbuf, 0, (float[]) { nearPlane, farPlane }, 8);

Why is the slot_index for the vert transform here 1? Because of this packoffset(c1)? That’d make sense I guess, but I don’t have any such analogue in my GLSL code. I thought maybe it’d be like 16B chunks into the UBO, but that doesn’t seem to test correctly, also it’d seem weird that indexing into the vert shader’s UBO would start at a different index than the frags.

I don’t know, any pointers?

Not sure where you got that line…

The slot index refers to the register index, so b0 is 0, b1 is 1, etc… for GLSL this would correspond to the binding index, so binding = 0 would be 0, binding = 1 would be 1, etc.

Oh shoot, I’m just a total goober, out here chasing shadows. I must have typed that in there when I was trying to figure out what those did.

My code works totally fine with both set to 0, as does the original example. My mistake was being reinforced by probably some UB, which coincidentally works.

sorry and thanks :sweat_smile:

1 Like