From e1ef5e076078db1ea5738fb29b4580d07d3a2244 Mon Sep 17 00:00:00 2001
From: Evan Hemsley <[EMAIL REDACTED]>
Date: Wed, 9 Jul 2025 15:16:30 -0700
Subject: [PATCH] Rework how resource counts are calculated (#159)
---
src/SDL_shadercross.c | 108 +++++++++++++++++++++++++++++++-----------
1 file changed, 81 insertions(+), 27 deletions(-)
diff --git a/src/SDL_shadercross.c b/src/SDL_shadercross.c
index a5f9a9f..7402903 100644
--- a/src/SDL_shadercross.c
+++ b/src/SDL_shadercross.c
@@ -1713,6 +1713,14 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
size_t num_outputs = 0;
size_t num_separate_samplers = 0; // HLSL edge case
size_t num_separate_images = 0; // HLSL edge case
+
+ // The client might have unused resources that get optimized out by the compiler.
+ // We output the resource count as the highest binding index + 1 to avoid bindings becoming out of order.
+ Sint32 highest_sampler_binding_index = -1;
+ Sint32 highest_storage_texture_binding_index = -1;
+ Sint32 highest_storage_buffer_binding_index = -1;
+ Sint32 highest_uniform_buffer_binding_index = -1;
+
(void) metadataProps;
if (code == NULL) {
@@ -1765,6 +1773,11 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
return NULL;
}
+ for (size_t i = 0; i < num_texture_samplers; i += 1)
+ {
+ highest_sampler_binding_index = SDL_max(highest_sampler_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
+
// If source is HLSL, we might have separate images and samplers
if (num_texture_samplers == 0) {
result = spvc_resources_get_resource_list_for_type(
@@ -1777,7 +1790,11 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
spvc_context_destroy(context);
return NULL;
}
- num_texture_samplers = num_separate_samplers;
+
+ for (size_t i = 0; i < num_separate_samplers; i += 1)
+ {
+ highest_sampler_binding_index = SDL_max(highest_sampler_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
}
// Storage textures
@@ -1792,6 +1809,11 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
return NULL;
}
+ for (size_t i = 0; i < num_storage_buffers; i += 1)
+ {
+ highest_storage_texture_binding_index = SDL_max(highest_storage_texture_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
+
// If source is HLSL, storage images might be marked as separate images
result = spvc_resources_get_resource_list_for_type(
resources,
@@ -1803,8 +1825,11 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
spvc_context_destroy(context);
return NULL;
}
- // The number of storage textures is the number of separate images minus the number of samplers.
- num_storage_textures += (num_separate_images - num_separate_samplers);
+
+ for (size_t i = 0; i < num_storage_buffers; i += 1)
+ {
+ highest_storage_texture_binding_index = SDL_max(highest_storage_texture_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
// Storage buffers
result = spvc_resources_get_resource_list_for_type(
@@ -1818,6 +1843,11 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
return NULL;
}
+ for (size_t i = 0; i < num_storage_buffers; i += 1)
+ {
+ highest_storage_buffer_binding_index = SDL_max(highest_storage_buffer_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
+
// Uniform buffers
result = spvc_resources_get_resource_list_for_type(
resources,
@@ -1830,6 +1860,11 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
return NULL;
}
+ for (size_t i = 0; i < num_uniform_buffers; i += 1)
+ {
+ highest_uniform_buffer_binding_index = SDL_max(highest_uniform_buffer_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
+
// Inputs (stage 1: count number of inputs, and name lengths)
result = spvc_resources_get_resource_list_for_type(
resources,
@@ -1902,10 +1937,10 @@ SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
SDL_ShaderCross_INTERNAL_GetIOVars(compiler, reflected_resources, num_outputs, allocMetadata->outputs, allocMemory + offset_outputnames);
spvc_context_destroy(context);
- allocMetadata->num_samplers = num_texture_samplers;
- allocMetadata->num_storage_textures = num_storage_textures;
- allocMetadata->num_storage_buffers = num_storage_buffers;
- allocMetadata->num_uniform_buffers = num_uniform_buffers;
+ allocMetadata->num_samplers = highest_sampler_binding_index + 1;
+ allocMetadata->num_storage_textures = highest_storage_texture_binding_index + 1;
+ allocMetadata->num_storage_buffers = highest_storage_buffer_binding_index + 1;
+ allocMetadata->num_uniform_buffers = highest_uniform_buffer_binding_index + 1;
allocMetadata->num_inputs = num_inputs;
allocMetadata->num_outputs = num_outputs;
@@ -1922,10 +1957,6 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
spvc_parsed_ir ir = NULL;
spvc_compiler compiler = NULL;
size_t num_texture_samplers = 0;
- size_t num_readonly_storage_textures = 0;
- size_t num_readonly_storage_buffers = 0;
- size_t num_readwrite_storage_textures = 0;
- size_t num_readwrite_storage_buffers = 0;
size_t num_uniform_buffers = 0;
size_t num_storage_textures = 0;
@@ -1933,6 +1964,14 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
size_t num_separate_samplers = 0; // HLSL edge case
size_t num_separate_images = 0; // HLSL edge case
+ // The client might have unused resources that get optimized out by the compiler.
+ // We output the resource count as the highest binding index + 1 to avoid bindings becoming out of order.
+ Sint32 highest_sampler_binding_index = -1;
+ Sint32 highest_readonly_storage_texture_binding_index = -1;
+ Sint32 highest_readwrite_storage_texture_binding_index = -1;
+ Sint32 highest_readonly_storage_buffer_binding_index = -1;
+ Sint32 highest_readwrite_storage_buffer_binding_index = -1;
+
(void) metadataProps;
if (bytecode == NULL) {
@@ -1985,6 +2024,11 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
return false;
}
+ for (size_t i = 0; i < num_texture_samplers; i += 1)
+ {
+ highest_sampler_binding_index = SDL_max(highest_sampler_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
+
// If source is HLSL, we might have separate images and samplers
if (num_texture_samplers == 0) {
result = spvc_resources_get_resource_list_for_type(
@@ -1997,7 +2041,11 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
spvc_context_destroy(context);
return false;
}
- num_texture_samplers = num_separate_samplers;
+
+ for (size_t i = 0; i < num_separate_samplers; i += 1)
+ {
+ highest_sampler_binding_index = SDL_max(highest_sampler_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
}
// Storage textures
@@ -2022,14 +2070,16 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
unsigned int descriptor_set_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet);
if (descriptor_set_index == 0) {
- num_readonly_storage_textures += 1;
+ highest_readonly_storage_texture_binding_index = SDL_max(highest_readonly_storage_texture_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+
} else if (descriptor_set_index == 1) {
- num_readwrite_storage_textures += 1;
+ highest_readwrite_storage_texture_binding_index = SDL_max(highest_readwrite_storage_texture_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
} else {
SDL_SetError("%s", "Descriptor set index for compute storage texture must be 0 or 1!");
spvc_context_destroy(context);
return false;
}
+
}
// If source is HLSL, readonly storage images might be marked as separate images
@@ -2044,9 +2094,6 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
return false;
}
- // The number of storage textures is the number of separate images minus the number of samplers.
- num_storage_textures += (num_separate_images - num_separate_samplers);
-
for (size_t i = num_separate_samplers; i < num_separate_images; i += 1) {
if (!spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet) || !spvc_compiler_has_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding)) {
SDL_SetError("%s", "Shader resources must have descriptor set and binding index!");
@@ -2057,14 +2104,15 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
unsigned int descriptor_set_index = spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationDescriptorSet);
if (descriptor_set_index == 0) {
- num_readonly_storage_textures += 1;
+ highest_readonly_storage_texture_binding_index = SDL_max(highest_readonly_storage_texture_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
} else if (descriptor_set_index == 1) {
- num_readwrite_storage_textures += 1;
+ highest_readwrite_storage_texture_binding_index = SDL_max(highest_readwrite_storage_texture_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
} else {
SDL_SetError("%s", "Descriptor set index for compute storage texture must be 0 or 1!");
spvc_context_destroy(context);
return false;
}
+
}
// Storage buffers
@@ -2095,9 +2143,9 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
}
if (descriptor_set_index == 0) {
- num_readonly_storage_buffers += 1;
+ highest_readonly_storage_buffer_binding_index = SDL_max(highest_readonly_storage_buffer_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
} else if (descriptor_set_index == 1) {
- num_readwrite_storage_buffers += 1;
+ highest_readwrite_storage_buffer_binding_index = SDL_max(highest_readwrite_storage_buffer_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
} else {
SDL_SetError("%s", "Descriptor set index for compute storage buffer must be 0 or 1!");
spvc_context_destroy(context);
@@ -2117,6 +2165,12 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
return false;
}
+ Sint32 highest_uniform_buffer_binding_index = -1;
+ for (size_t i = 0; i < num_uniform_buffers; i += 1)
+ {
+ highest_uniform_buffer_binding_index = SDL_max(highest_uniform_buffer_binding_index, (Sint32) spvc_compiler_get_decoration(compiler, reflected_resources[i].id, SpvDecorationBinding));
+ }
+
// Threadcount
SDL_ShaderCross_ComputePipelineMetadata *metadata = SDL_malloc(sizeof(SDL_ShaderCross_ComputePipelineMetadata));
if (!metadata) {
@@ -2128,12 +2182,12 @@ SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
spvc_context_destroy(context);
- metadata->num_samplers = num_texture_samplers;
- metadata->num_readonly_storage_textures = num_readonly_storage_textures;
- metadata->num_readonly_storage_buffers = num_readonly_storage_buffers;
- metadata->num_readwrite_storage_textures = num_readwrite_storage_textures;
- metadata->num_readwrite_storage_buffers = num_readwrite_storage_buffers;
- metadata->num_uniform_buffers = num_uniform_buffers;
+ metadata->num_samplers = highest_sampler_binding_index + 1;
+ metadata->num_readonly_storage_textures = highest_readonly_storage_texture_binding_index + 1;
+ metadata->num_readonly_storage_buffers = highest_readonly_storage_buffer_binding_index + 1;
+ metadata->num_readwrite_storage_textures = highest_readwrite_storage_texture_binding_index + 1;
+ metadata->num_readwrite_storage_buffers = highest_readwrite_storage_buffer_binding_index + 1;
+ metadata->num_uniform_buffers = highest_uniform_buffer_binding_index + 1;
return metadata;
}