sokol icon indicating copy to clipboard operation
sokol copied to clipboard

Planning: Resource binding cleanup

Open floooh opened this issue 1 year ago • 1 comments

This would make sense after the storage-buffer update:

General idea is to allow more flexibility when mapping the sokol-gfx 'bind slot convention' to the backend API bind slots.

  • Get rid of shader stages in sg_bindings:
typedef struct sg_bindings {
    uint32_t _start_canary;
    sg_buffer vertex_buffers[SG_MAX_VERTEXBUFFER_BINDINGS];
    int vertex_buffer_offsets[SG_MAX_VERTEXBUFFER_BINDINGS];
    sg_buffer index_buffer;
    int index_buffer_offset;
    sg_image images[SG_MAX_IMAGE_BINDINGS];
    sg_sampler samplers[SG_MAX_SAMPLER_BINDINGS];
    sg_buffer storage_buffers[SG_MAX_STORAGEBUFFER_BINDINGS];
    uint32_t _end_canary;
} sg_bindings;

The sg_shader_desc needs to provide a mapping from those unified "sokol-gfx bindslots" to shader stages and (probably backend-API specific) concrete bind slots (typically generated by sokol-shdc).

  • Q: also get rid of the 'implicit' backend-specific bind slot indices? This means the sg_shader_desc bind slot-mapping needs backend-specific slot indices (which is probably more transparent to the user)

  • while at it also get rid of the stage param in sg_apply_uniforms() (and provide a mapping in sg_shader_desc instead for backends which need this)

  • TL;DR: SG_SHADERSTAGE_VS/FS should only show up in sg_shader_desc.

floooh avatar Apr 29 '24 14:04 floooh

Planning braindump:

  • except for the simplified sg_bindings interior, no code changes should be required if sokol-shdc is used
  • remove (most of) the obscure hardwired bindslot relationship between the 'sokol bind model' and backend bind models by introducing a mapping from sokol bind slots to backend API bindings
  • allow gaps in the sokol bind slots, and don't complain if an sg_bindings struct has an occupied but 'unmapped' resource slot (this allows to re-use the same sg_bindings struct for different shader variants)
  • in sokol-shdc, add an optional @binding [type] [name] [slot] tag which allows to define a manual mapping from shader resources to sokol bind slots, type is one of uniform, image, sampler, storagebuffer, if those tags are missing, sokol-shdc will create an automatic mapping (Q: what if only sample slots are explicitly mapped?)
  • get rid of shader stages in the public API, they are now only a 3D-backend-specific detail in the sg_shader_desc bind slot mapping

The sokol-gfx resource binding model is:

  • one 'bind space' per resource type, and across all shader stages:
    • 1..X uniform bindings (the 'slot_index' in sg_apply_uniforms())
    • 1..Y image bindings (the index in sg_bindings.images[])
    • 1..Y sampler bindings (the index sg_bindings.samplers[])
    • 1..Z storage buffer bindings (the index in sg_bindings.storabe_buffers[])

The following information is required in sg_shader_desc to map sokol-gfx bind slots to 3D backend API bindings:

  • uniforms:
    • GL:
      • same as now (either a single name of a flattened array per uniform block, or a list of uniforms to be updated with a single sg_apply_uniforms call)
    • D3D11:
      • the shader stage
      • the N in ...: register(bN)
    • Metal:
      • the shader stage
      • the buffer bind slot (buffer(N) - shared bind space with vertex- and storage-buffers!) - still need hardwired reserved slots for vertex-buffers!)
    • WebGPU:
      • a slot index in hardwired @group(0) (@group(0) is reserved for uniforms)
  • images:
    • GL:
      • TBD (tricky because of combined-image-samplers...)
    • D3D11:
      • the shader stage
      • the N in ...: register(tN) (shared bind space with storage buffers!)
    • Metal:
      • the shader stage
      • the texture bind slot (texture(N))
    • WebGPU:
      • a slot index in @group(1) (@group(1) is reserved for images, sampler, storage buffers across all stages)
  • samplers:
    • GL:
      • TBD (tricky because of combined image samplers...)
    • D3D11
      • the shader stage
      • the N in ...: register(sN)
    • Metal:
      • the shader stage
      • the sampler bind slot (sampler(N))
    • WebGPU
      • a slot index in @group(1) (@group(1) is reserved for images, sampler, storage buffers across all stages)
  • storage buffers:
    • GL:
      • TBD
    • D3D11:
      • the shader stage
      • the N in ...: register(tN) (shared bind space with textures!)
    • Metal
      • the shader stage
      • the buffer bind slot (buffer(N) - shared bind space with vertex- and storage-buffers!)
    • WebGPU
      • a slot index in @group(1) (@group(1) is reserved for images, sampler, storage buffers across all stages)

floooh avatar Aug 25 '24 14:08 floooh