libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
11.12k stars 1.95k forks source link

SDL3 GPU: SDL_DrawGPUIndexedPrimitivesIndirect sets instance count to 0? #11916

Open karabatov opened 1 week ago

karabatov commented 1 week ago

I'm trying to use SDL_DrawGPUIndexedPrimitivesIndirect to draw some quads with a Vulkan backend. I have an indirect buffer setup with one instance of SDL_GPUIndexedIndirectDrawCommand that I populate like so:

        text_allocation *alloc = &gf->texts[i];
        SDL_GPUIndexedIndirectDrawCommand *cmd = &gf->indirect_memory[i];

        cmd->num_indices = INDICES_PER_QUAD * cvector_size(alloc->quad_transforms); // = 66
        cmd->num_instances = 1;  // <-- Setting number of instances
        cmd->first_index = 0;
        cmd->vertex_offset = alloc->quad_transforms_gpu.start_index; // = 0
        cmd->first_instance = 0;

The in-memory array gets updated: image

After that I upload the in-memory array to an SDL_GPUBuffer created with SDL_GPU_BUFFERUSAGE_INDIRECT and sizeof(SDL_GPUIndexedIndirectDrawCommand), it gets uploaded without error.

I try to draw the geometry as follows:

    SDL_DrawGPUIndexedPrimitivesIndirect(
        render_pass, // <-- Valid render pass
        managed_buffer_get_buffer(gf->indirect_gpu), // <-- SDL_GPUBuffer of indirect data
        0, // <-- Offset in draw buffer
        gf->indirect_items_count // = 1
    );

As a result, nothing gets drawn. Nvidia Nsight Graphics shows that the geometry itself loads correctly but instance count is zero:

Screenshot 2025-01-11 170611

As an alternative, I tried to draw exactly the same geometry on the very next line using SDL_DrawGPUIndexedPrimitives with exactly the same parameters I used for populating the indirect draw command - it was drawn without issue:

    text_allocation *alloc = &gf->texts[0];
    SDL_DrawGPUIndexedPrimitives(
        render_pass, 
        INDICES_PER_QUAD * cvector_size(alloc->quad_transforms), // = 66
        1, // Number of instances
        0, // Start index in the index buffer
        alloc->quad_transforms_gpu.start_index, // Vertex offset, = 0
        0 // ID of the first instance
    );

I'm currently using the commit https://github.com/libsdl-org/SDL/commit/82125ec1d888e95f838b3cd683dfc8aa54013371.

karabatov commented 1 week ago

As an aside, the documentation for SDL_DrawGPUIndexedPrimitives mentions the parameter first_vertex that isn't there:

void __cdecl SDL_DrawGPUIndexedPrimitives(SDL_GPURenderPass *render_pass, Uint32 num_indices, Uint32 num_instances, Uint32 first_index, Sint32 vertex_offset, Uint32 first_instance) ... Note that the first_vertex and first_instance parameters are NOT compatible with built-in vertex/instance ID variables in shaders

flibitijibibo commented 1 week ago

Draw call in question https://github.com/libsdl-org/SDL/blob/main/src/gpu/vulkan/SDL_gpu_vulkan.c#L5383

Is it using the fake multidraw path maybe...? We have a test for this here: https://github.com/TheSpydog/SDL_gpu_examples/blob/main/Examples/DrawIndirect.c

karabatov commented 1 week ago

I'll try to trace it if I can too 👍 For now I can at least use the workaround with multiple draw calls.

thatcosmonaut commented 1 week ago

We don't have a lot of direct control over this behavior, we're basically just calling the vk function, so this is fairly surprising. The only thing I can think of on our end is that the memory barrier is incorrect but I just checked and that seems unlikely. Have you tried running this through RenderDoc and checking the parameter there? I'm almost suspicious of a driver bug but that would also be surprising.

karabatov commented 1 week ago

@thatcosmonaut I'd rather think it's me doing something that makes it do it :D

Have you tried running this through RenderDoc and checking the parameter there?

I'll try! I'm very new to graphics and don't know yet which tools are out there.

Have just tried it on a Mac and it doesn't draw too with the indirect indexed call, but draws with the indexed primitive call 😬 Which increases the likelihood of user error.

thatcosmonaut commented 1 week ago

Definitely check out RenderDoc, it's incredibly useful: https://renderdoc.org/