aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Weissflog <floooh@gmail.com>2024-11-02 13:25:16 +0100
committerAndre Weissflog <floooh@gmail.com>2024-11-02 13:25:16 +0100
commit8b3d53124e7469602e3803e29aba40eefa43311e (patch)
tree97420df56166aa0ab9f2f3e4ffb389ae5ac16b3f
parentab5d83451a4d8bd11ed68ba93fc0bb06bf176b27 (diff)
sokol_gfx.h: documentation update wip (bindings cleanup)
-rw-r--r--sokol_gfx.h187
1 files changed, 120 insertions, 67 deletions
diff --git a/sokol_gfx.h b/sokol_gfx.h
index 8c766066..865e0a7f 100644
--- a/sokol_gfx.h
+++ b/sokol_gfx.h
@@ -148,7 +148,7 @@
sg_apply_pipeline(sg_pipeline pip)
--- fill an sg_bindings struct with the resource bindings for the next
- draw call (0..N vertex buffers, 0 or 1 index buffer, 0..N image-objects,
+ draw call (0..N vertex buffers, 0 or 1 index buffer, 0..N images,
samplers and storage-buffers), and call:
sg_apply_bindings(const sg_bindings* bindings)
@@ -1496,33 +1496,30 @@
- when writing WGSL shader code by hand, a specific bind-slot convention
must be used:
- All uniform block structs must use `@group(0)`, with up to
- 4 uniform blocks per shader stage.
- - Vertex shader uniform block bindings must start at `@group(0) @binding(0)`
- - Fragment shader uniform blocks bindings must start at `@group(0) @binding(4)`
+ All uniform block structs must use `@group(0)` and bindings in the
+ range 0..127:
- All textures and samplers must use `@group(1)` and start at specific
- offsets depending on resource type and shader stage.
- - Vertex shader textures must start at `@group(1) @binding(0)`
- - Vertex shader samplers must start at `@group(1) @binding(16)`
- - Vertex shader storage buffers must start at `@group(1) @binding(32)`
- - Fragment shader textures must start at `@group(1) @binding(48)`
- - Fragment shader samplers must start at `@group(1) @binding(64)`
- - Fragment shader storage buffers must start at `@group(1) @binding(80)`
+ @group(0) @binding(0..7)
- Note that the actual number of allowed per-stage texture- and sampler-bindings
- in sokol-gfx is currently lower than the above ranges (currently only up to
- 12 textures, 8 samplers and 8 storage buffers are allowed per shader stage).
+ All textures, samplers and storage buffers must use `@group(1)` and
+ bindings must be in the range 0..127:
+
+ @group(1) @binding(0..127)
+
+ Note that the number of texture, sampler and storage buffer bindings
+ is still limited despite the large bind range:
+
+ - up to 16 textures and sampler across all shader stages
+ - up to 8 storage buffers across all shader stages
If you use sokol-shdc to generate WGSL shader code, you don't need to worry
- about the above binding convention since sokol-shdc assigns bind slots
- automatically.
+ about the above binding conventions since sokol-shdc.
- The sokol-gfx WebGPU backend uses the sg_desc.uniform_buffer_size item
to allocate a single per-frame uniform buffer which must be big enough
to hold all data written by sg_apply_uniforms() during a single frame,
including a worst-case 256-byte alignment (e.g. each sg_apply_uniform
- call will cost 256 bytes of uniform buffer size). The default size
+ call will cost at least 256 bytes of uniform buffer size). The default size
is 4 MB, which is enough for 16384 sg_apply_uniform() calls per
frame (assuming the uniform data 'payload' is less than 256 bytes
per call). These rules are the same as for the Metal backend, so if
@@ -1544,7 +1541,7 @@
.wgpu.num_bindgroup_cache_vs_hash_key_mismatch
The value to pay attention to is `.wgpu.num_bindgroup_cache_collisions`,
- if this number if consistently higher than a few percent of the
+ if this number is consistently higher than a few percent of the
.wgpu.num_set_bindgroup value, it might be a good idea to bump the
bindgroups cache size to the next power-of-2.
@@ -1630,14 +1627,14 @@ extern "C" {
Resource id typedefs:
sg_buffer: vertex- and index-buffers
- sg_image: images used as textures and render targets
- sg_sampler sampler object describing how a texture is sampled in a shader
+ sg_image: images used as textures and render-pass attachments
+ sg_sampler sampler objects describing how a texture is sampled in a shader
sg_shader: vertex- and fragment-shaders and shader interface information
sg_pipeline: associated shader and vertex-layouts, and render states
sg_attachments: a baked collection of render pass attachment images
Instead of pointers, resource creation functions return a 32-bit
- number which uniquely identifies the resource object.
+ handle which uniquely identifies the resource object.
The 32-bit resource id is split into a 16-bit pool index in the lower bits,
and a 16-bit 'generation counter' in the upper bits. The index allows fast
@@ -1680,7 +1677,7 @@ typedef struct sg_range {
#define SG_RANGE_REF(x) &(sg_range){ &x, sizeof(x) }
#endif
-// various compile-time constants
+// various compile-time constants in the public API
enum {
SG_INVALID_ID = 0,
SG_NUM_INFLIGHT_FRAMES = 2,
@@ -1744,13 +1741,12 @@ typedef enum sg_backend {
- sample: the pixelformat can be sampled as texture at least with
nearest filtering
- - filter: the pixelformat can be samples as texture with linear
+ - filter: the pixelformat can be sampled as texture with linear
filtering
- - render: the pixelformat can be used for render targets
- - blend: blending is supported when using the pixelformat for
- render targets
- - msaa: multisample-antialiasing is supported when using the
- pixelformat for render targets
+ - render: the pixelformat can be used as render-pass attachment
+ - blend: blending is supported when used as render-pass attachment
+ - msaa: multisample-antialiasing is supported when used
+ as render-pass attachment
- depth: the pixelformat can be used for depth-stencil attachments
- compressed: this is a block-compressed format
- bytes_per_pixel: the numbers of bytes in a pixel (0 for compressed formats)
@@ -1853,27 +1849,25 @@ typedef enum sg_pixel_format {
} sg_pixel_format;
/*
- Runtime information about a pixel format, returned
- by sg_query_pixelformat().
+ Runtime information about a pixel format, returned by sg_query_pixelformat().
*/
typedef struct sg_pixelformat_info {
bool sample; // pixel format can be sampled in shaders at least with nearest filtering
bool filter; // pixel format can be sampled with linear filtering
- bool render; // pixel format can be used as render target
- bool blend; // alpha-blending is supported
- bool msaa; // pixel format can be used as MSAA render target
+ bool render; // pixel format can be used as render-pass attachment
+ bool blend; // pixel format supports alpha-blending when used as render-pass attachment
+ bool msaa; // pixel format supports MSAA when used as render-pass attachment
bool depth; // pixel format is a depth format
bool compressed; // true if this is a hardware-compressed format
int bytes_per_pixel; // NOTE: this is 0 for compressed formats, use sg_query_row_pitch() / sg_query_surface_pitch() as alternative
} sg_pixelformat_info;
/*
- Runtime information about available optional features,
- returned by sg_query_features()
+ Runtime information about available optional features, returned by sg_query_features()
*/
typedef struct sg_features {
- bool origin_top_left; // framebuffer and texture origin is in top left corner
- bool image_clamp_to_border; // border color and clamp-to-border UV-wrap mode is supported
+ bool origin_top_left; // framebuffer- and texture-origin is in top left corner
+ bool image_clamp_to_border; // border color and clamp-to-border uv-wrap mode is supported
bool mrt_independent_blend_state; // multiple-render-target rendering can use per-render-target blend state
bool mrt_independent_write_mask; // multiple-render-target rendering can use per-render-target color write masks
bool storage_buffer; // storage buffers are supported
@@ -1987,6 +1981,7 @@ typedef enum sg_buffer_type {
Indicates whether indexed rendering (fetching vertex-indices from an
index buffer) is used, and if yes, the index data type (16- or 32-bits).
+
This is used in the sg_pipeline_desc.index_type member when creating a
pipeline object.
@@ -2026,7 +2021,7 @@ typedef enum sg_image_type {
sg_image_sample_type
The basic data type of a texture sample as expected by a shader.
- Must be provided in sg_shader_image_desc and used by the validation
+ Must be provided in sg_shader_image and used by the validation
layer in sg_apply_bindings() to check if the provided image object
is compatible with what the shader expects. Apart from the sokol-gfx
validation layer, WebGPU is the only backend API which actually requires
@@ -2231,7 +2226,8 @@ typedef enum sg_vertex_step {
The data type of a uniform block member. This is used to
describe the internal layout of uniform blocks when creating
- a shader object.
+ a shader object. This is only required for the GL backend, all
+ other backends will ignore the interior layout of uniform blocks.
*/
typedef enum sg_uniform_type {
SG_UNIFORMTYPE_INVALID,
@@ -2252,7 +2248,7 @@ typedef enum sg_uniform_type {
sg_uniform_layout
A hint for the interior memory layout of uniform blocks. This is
- only really relevant for the GL backend where the internal layout
+ only relevant for the GL backend where the internal layout
of uniform blocks must be known to sokol-gfx. For all other backends the
internal memory layout of uniform blocks doesn't matter, sokol-gfx
will just pass uniform data as a single memory blob to the
@@ -2332,6 +2328,8 @@ typedef enum sg_face_winding {
in pipeline objects, and for texture samplers which perform a comparison
instead of regular sampling operation.
+ Used in the following structs:
+
sg_pipeline_desc
.depth
.compare
@@ -2345,7 +2343,7 @@ typedef enum sg_face_winding {
The default compare func for depth- and stencil-tests is
SG_COMPAREFUNC_ALWAYS.
- The default compare func for sampler is SG_COMPAREFUNC_NEVER.
+ The default compare func for samplers is SG_COMPAREFUNC_NEVER.
*/
typedef enum sg_compare_func {
_SG_COMPAREFUNC_DEFAULT, // value 0 reserved for default-init
@@ -2366,7 +2364,7 @@ typedef enum sg_compare_func {
The operation performed on a currently stored stencil-value when a
comparison test passes or fails. This is used when creating a pipeline
- object in the members:
+ object in the following sg_pipeline_desc struct items:
sg_pipeline_desc
.stencil
@@ -2437,8 +2435,8 @@ typedef enum sg_blend_factor {
sg_blend_op
Describes how the source and destination values are combined in the
- fragment blending operation. It is used in the following members when
- creating a pipeline object:
+ fragment blending operation. It is used in the following struct items
+ when creating a pipeline object:
sg_pipeline_desc
.colors[i]
@@ -2520,7 +2518,7 @@ typedef enum sg_load_action {
/*
sg_store_action
- Defines the store action that be performed at the end of a render pass:
+ Defines the store action that should be performed at the end of a render pass:
SG_STOREACTION_STORE: store the rendered content to the color attachment image
SG_STOREACTION_DONTCARE: allows the GPU to discard the rendered content
@@ -2539,11 +2537,11 @@ typedef enum sg_store_action {
The sg_pass_action struct defines the actions to be performed
at the start and end of a render pass.
- - at the start of the pass: whether the render targets should be cleared,
+ - at the start of the pass: whether the render attachments should be cleared,
loaded with their previous content, or start in an undefined state
- for clear operations: the clear value (color, depth, or stencil values)
- at the end of the pass: whether the rendering result should be
- stored back into the render target or discarded
+ stored back into the render attachment or discarded
*/
typedef struct sg_color_attachment_action {
sg_load_action load_action; // default: SG_LOADACTION_CLEAR
@@ -2591,8 +2589,9 @@ typedef struct sg_pass_action {
Additionally the following backend API specific objects must be passed in
as 'type erased' void pointers:
- GL: on all GL backends, a GL framebuffer object must be provided. This
- can be zero for the default framebuffer.
+ GL:
+ - on all GL backends, a GL framebuffer object must be provided. This
+ can be zero for the default framebuffer.
D3D11:
- an ID3D11RenderTargetView for the rendering surface, without
@@ -2610,7 +2609,7 @@ typedef struct sg_pass_action {
- when MSAA rendering is used, another WGPUTextureView
which serves as MSAA resolve target and will be displayed
- Metal (NOTE that the rolves of provided surfaces is slightly different
+ Metal (NOTE that the roles of provided surfaces is slightly different
than on D3D11 or WebGPU in case of MSAA vs non-MSAA rendering):
- A current CAMetalDrawable (NOT an MTLDrawable!) which will be presented.
@@ -2622,7 +2621,7 @@ typedef struct sg_pass_action {
CAMetalDrawable.
NOTE that for Metal you must use an ObjC __bridge cast to
- properly tunnel the ObjC object handle through a C void*, e.g.:
+ properly tunnel the ObjC object id through a C void*, e.g.:
swapchain.metal.current_drawable = (__bridge const void*) [mtkView currentDrawable];
@@ -2674,7 +2673,7 @@ typedef struct sg_swapchain {
function.
For an offscreen rendering pass, an sg_pass_action struct and sg_attachments
- object must be provided, and for swapchain passes, and sg_pass_action and
+ object must be provided, and for swapchain passes, an sg_pass_action and
an sg_swapchain struct. It is an error to provide both an sg_attachments
handle and an initialized sg_swapchain struct in the same sg_begin_pass().
@@ -2710,9 +2709,14 @@ typedef struct sg_pass {
/*
sg_bindings
- The sg_bindings structure defines the resource binding slots
- of the sokol_gfx render pipeline, used as argument to the
- sg_apply_bindings() function.
+ The sg_bindings structure defines the buffers, images and
+ samplers resource bindings for the next draw call.
+
+ To update the resource bindings, call sg_apply_bindings() with
+ a pointer to a populated sg_bindings struct. Note that
+ sg_apply_bindings() must be called after sg_apply_pipeline()
+ and that bindings are not preserved across sg_apply_pipeline()
+ calls, even when the new pipeline uses the same 'bindings layout'.
A resource binding struct contains:
@@ -2720,19 +2724,68 @@ typedef struct sg_pass {
- 0..N vertex buffer offsets
- 0..1 index buffers
- 0..1 index buffer offsets
- - 0..N vertex shader stage images
- - 0..N vertex shader stage samplers
- - 0..N vertex shader storage buffers
- - 0..N fragment shader stage images
- - 0..N fragment shader stage samplers
- - 0..N fragment shader storage buffers
+ - 0..N images
+ - 0..N samplers
+ - 0..N storage buffers
- For the max number of bindings, see the constant definitions:
+ Where 'N' is defined in the following constants:
- SG_MAX_VERTEXBUFFER_BINDSLOTS
- - SG_MAX_SHADERSTAGE_IMAGES
- - SG_MAX_SHADERSTAGE_SAMPLERS
- - SG_MAX_SHADERSTAGE_STORAGEBUFFERS
+ - SG_MAX_IMAGE_BINDLOTS
+ - SG_MAX_SAMPLER_BINDSLOTS
+ - SG_MAX_STORAGEBUFFER_BINDGLOTS
+
+ When using sokol-shdc for shader authoring, the `layout(binding=N)`
+ annotation in the shader code directly maps to the slot index for that
+ resource type in the bindings struct, for instance the following vertex-
+ and fragment-shader interface for sokol-shdc:
+
+ @vs vs
+ layout(binding=0) uniform vs_params { ... };
+ layout(binding=0) readonly buffer ssbo { ... };
+ layout(binding=0) uniform texture2D vs_tex;
+ layout(binding=0) uniform sampler vs_smp;
+ ...
+ @end
+
+ @fs fs
+ layout(binding=1) uniform fs_params { ... };
+ layout(binding=1) uniform texture2D fs_tex;
+ layout(binding=1) uniform sampler fs_smp;
+ ...
+ @end
+
+ ...would map to the following sg_bindings struct:
+
+ const sg_bindings bnd = {
+ .vertex_buffers[0] = ...,
+ .images[0] = vs_tex,
+ .images[1] = fs_tex,
+ .samplers[0] = vs_smp,
+ .samplers[1] = fs_smp,
+ .storage_buffers[0] = ssbo,
+ };
+
+ ...alternatively you can use code-generated slot indices:
+
+ const sg_bindings bnd = {
+ .vertex_buffers[0] = ...,
+ .images[IMG_vs_tex] = vs_tex,
+ .images[IMG_fs_tex] = fs_tex,
+ .samplers[SMP_vs_smp] = vs_smp,
+ .samplers[SMP_fs_smp] = fs_smp,
+ .storage_buffers[SBUF_ssbo] = ssbo,
+ };
+
+ Resource bindslots for a specific shader/pipeline may have gaps, and an
+ sg_bindings struct may have populated bind slots which are not used by a
+ specific shader. This allows to use the same sg_bindings struct across
+ different shader variants.
+
+ When not using sokol-shdc, the bindslot indices in the sg_bindings
+ struct need to match the per-resource reflection info slot indices
+ in the sg_shader_desc struct (for details about that see the
+ sg_shader_desc struct documentation).
The optional buffer offsets can be used to put different unrelated
chunks of vertex- and/or index-data into the same buffer objects.