diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 9e223d4071..74bcd2a2d9 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -2614,30 +2614,198 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGPUDeviceProperties(SDL_GPUD /** * Creates a pipeline object to be used in a compute workflow. * - * Shader resource bindings must be authored to follow a particular order - * depending on the shader format. + * Shader resource bindings must be authored to follow a particular convention + * depending on the shader format. See below for details. * - * For SPIR-V shaders, use the following resource sets: + * --- * - * - 0: Sampled textures, followed by read-only storage textures, followed by + * **SPIR-V** + * + * For compute shaders, use: + * + * - Set 0 for samplers, read-only storage textures, and read-only storage + * buffers + * - Set 1 for read-write storage textures and read-write storage buffers + * - Set 2 for uniform data + * + * The first resource in a given set must have a `binding` of 0. Additional + * resources must appear at consecutive bindings (1, 2, etc), leaving no gaps + * in the set. + * + * All samplers must come first in the binding order of Set 0, in order of how + * they are bound via `SDL_BindGPUComputeSamplers()`. + * + * All read-only storage textures must come after all samplers in the binding + * order, in order of how they are bound via + * `SDL_BindGPUComputeStorageTextures()`. + * + * All read-only storage buffers must come after all read-only storage + * textures in the binding order, in order of how they are bound via + * `SDL_BindGPUComputeStorageBuffers()`. + * + * All read-write storage textures must come first in the binding order of Set + * 1, in order of how they are bound via `SDL_BeginGPUComputePass()`. + * + * All read-write storage buffers must come after all read-write storage + * textures in the binding order, in order of how they are bound via + * `SDL_BeginGPUComputePass()`. + * + * **Example** + * + * If a compute shader binds 2 of each resource type, its binding layout + * should look like this: + * + * ```glsl + * // Any samplers come first in Set 0, in SDL bind slot order + * layout(set = 0, binding = 0) sampler2d samplerBoundToSlot0; + * layout(set = 0, binding = 1) sampler2d samplerBoundToSlot1; + * // Any read-only storage textures come next in Set 0, in SDL bind slot order + * layout(set = 0, binding = 2) image2d storageTextureBoundToSlot0; + * layout(set = 0, binding = 3) image2d storageTextureBoundToSlot1; + * // Any read-only storage buffers come next in Set 0, in SDL bind slot order + * layout(set = 0, binding = 4) buffer storageBufferBoundToSlot0; + * layout(set = 0, binding = 5) buffer storageBufferBoundToSlot1; + * // Any read-write storage textures come first in Set 1, in SDL bind slot order + * layout(set = 1, binding = 0) image2d rwStorageTextureBoundToSlot0; + * layout(set = 1, binding = 1) image2d rwStorageTextureBoundToSlot1; + * // Any read-write storage buffers come next in Set 1, in SDL bind slot order + * layout(set = 1, binding = 2) buffer rwStorageBufferBoundToSlot0; + * layout(set = 1, binding = 3) buffer rwStorageBufferBoundToSlot1; + * // Any uniform buffers are in Set 2, in SDL slot order + * layout(set = 2, binding = 0) uniform UniformDataBoundToSlot0 {}; + * layout(set = 2, binding = 1) uniform UniformDataBoundToSlot1 {}; + * ``` + * + * --- + * + * **DXBC / DXIL (HLSL)** + * + * For compute shaders, use: + * + * - `(t[n], space0)` for sampled textures, read-only storage textures, and * read-only storage buffers - * - 1: Read-write storage textures, followed by read-write storage buffers - * - 2: Uniform buffers + * - `(s[n], space0)` for samplers + * - `(u[n], space1)` for read-write storage textures and read-write storage + * buffers + * - `(b[n], space2)` for uniform data * - * For DXBC and DXIL shaders, use the following register order: + * The first resource in a given register set must have a register index of + * `0`. Additional resources must appear at consecutive indices (1, 2, etc), + * leaving no gaps in the register set. * - * - (t[n], space0): Sampled textures, followed by read-only storage textures, - * followed by read-only storage buffers - * - (u[n], space1): Read-write storage textures, followed by read-write - * storage buffers - * - (b[n], space2): Uniform buffers + * All sampled textures must come first in the `t` register set, in order of + * how they are bound via `SDL_BindGPUComputeSamplers()`. * - * For MSL/metallib, use the following order: + * All sampler objects must be in the `s` register set, in the same order as + * the textures above. * - * - [[buffer]]: Uniform buffers, followed by read-only storage buffers, - * followed by read-write storage buffers - * - [[texture]]: Sampled textures, followed by read-only storage textures, - * followed by read-write storage textures + * All read-only storage textures must come after all samplers in the `t` + * register set, in order of how they are bound via + * `SDL_BindComputeStorageTextures()`. + * + * All read-only storage buffers must come after all storage textures in the + * `t` register set, in order of how they are bound via + * `SDL_BindComputeStorageBuffers()`. + * + * All read-write storage textures must come first in the `u` register set in + * `space1`, in order of how they are bound via `SDL_BeginGPUComputePass()`. + * + * All read-write storage buffers must come after all read-write storage + * textures in the `u` register set in `space1`, in order of how they are + * bound via `SDL_BeginGPUComputePass()`. + * + * **Example** + * + * If a compute shader binds 2 of each resource type, the layout should look + * like this: + * + * ```c + * // Any samplers and sampled textures come first in their respective register sets, in SDL bind slot order + * SamplerState SamplerBoundToSlot0 : register( s0, space0 ); + * SamplerState SamplerBoundToSlot1 : register( s1, space0 ); + * Texture2D SampledTextureBoundToSlot0 : register( t0, space0 ); + * Texture2D SampledTextureBoundToSlot1 : register( t1, space0 ); + * // Any read-only storage textures come next in the `t` register set, in SDL bind slot order + * Texture2D StorageTextureBoundToSlot0 : register( t2, space0 ); + * Texture2D StorageTextureBoundToSlot1 : register( t3, space0 ); + * // Any read-only storage buffers come next in the `t` register set, in SDL bind slot order + * ByteAddressBuffer StorageBufferBoundToSlot0 : register( t4, space0 ); + * ByteAddressBuffer StorageBufferBoundToSlot1 : register( t5, space0 ); + * // Any read-write storage textures come first in the `u` register set in space1, in SDL bind slot order + * RWTexture2D RWStorageTextureBoundToSlot0 : register( u0, space1 ); + * RWTexture2D RWStorageTextureBoundToSlot1 : register( u1, space1 ); + * // Any read-write storage buffers come next in the `u` register set in space1, in SDL bind slot order + * RWByteAddressBuffer RWStorageTextureBoundToSlot0 : register( u2, space1 ); + * RWByteAddressBuffer RWStorageTextureBoundToSlot1 : register( u3, space1 ); + * // Any uniform buffers are in the `b` register set in space2, in SDL slot order + * cbuffer UniformDataBoundToSlot0 : register( b0, space2 ) { ... }; + * cbuffer UniformDataBoundToSlot1 : register( b1, space2 ) { ... }; + * ``` + * + * --- + * + * **MSL / Metallib (Metal Shading Language)** + * + * The first resource in a given argument table must have an index of `0`. + * Additional resources must appear at consecutive indices (1, 2, etc), + * leaving no gaps in the table. + * + * All sampled textures must come first in the `[[texture]]` argument table, + * in order of how they are bound via `SDL_BindGPUComputeSamplers()`. + * + * All sampler objects must be in the `[[sampler]]` argument table, in the + * same order as the textures above. + * + * All read-only storage textures must come after all sampled textures in the + * `[[texture]]` argument table, in order of how they are bound via + * `SDL_BindGPUComputeStorageTextures()`. + * + * All read-write storage textures must come after all read-only storage + * textures in the `[[texture]]` argument table, in order of how they are + * bound via `SDL_BeginGPUComputePass()`. + * + * All uniform buffers must come first in the `[[buffer]]` argument table, in + * order of their slots in `SDL_PushGPUComputeUniformData()`. + * + * All read-only storage buffers must come after all uniform buffers in the + * `[[buffer]]` argument table, in order of how they are bound via + * `SDL_BindGPUComputeStorageBuffers()`. + * + * All read-write storage buffers must come after all read-only storage + * buffers in the `[[buffer]]` argument table, in order of how they are bound + * via `SDL_BeginGPUComputePass()`. + * + * **Example** + * + * For a compute shader binding 2 of each resource type, the main function + * signature should look like this: + * + * ```c++ + * kernel void ExampleComputeShader( + * // Any samplers go in the `sampler` table, in SDL bind slot order + * sampler samplerBoundToSlot0 [[sampler(0)]], + * sampler samplerBoundToSlot1 [[sampler(1)]], + * // Any sampled textures come first in the `texture` table, in SDL bind slot order + * texture2d sampledTextureBoundToSlot0 [[texture(0)]], + * texture2d sampledTextureBoundToSlot1 [[texture(1)]], + * // Any read-only storage textures come next in the `texture` table, in SDL bind slot order + * texture2d storageTextureBoundToSlot0 [[texture(2)]], + * texture2d storageTextureBoundToSlot1 [[texture(3)]], + * // Any read-write storage textures come next in the `texture` table, in SDL bind slot order + * texture2d rwStorageTextureBoundToSlot0 [[texture(4)]]; + * texture2d rwStorageTextureBoundToSlot1 [[texture(5)]]; + * // Any uniform buffers come first in the `buffer` table, in SDL slot order + * constant SomeUniformStruct uniformDataBoundToSlot0 [[buffer(0)]], + * constant SomeUniformStruct uniformDataBoundToSlot1 [[buffer(1)]], + * // Any read-only storage buffers come next in the `buffer` table, in SDL bind slot order + * device SomeBufferStruct& storageBufferBoundToSlot0 [[buffer(2)]], + * device SomeBufferStruct& storageBufferBoundToSlot1 [[buffer(3)]]); + * // Any read-write storage buffers come next in the `buffer` table, in SDL bind slot order + * device SomeBufferStruct& rwStorageBufferBoundToSlot0 [[buffer(4)]]; + * device SomeBufferStruct& rwStorageBufferBoundToSlot1 [[buffer(5)]]); + * ``` + * + * --- * * There are optional properties that can be provided through `props`. These * are the supported properties: