From 97225f161dce2f224b855dcc108f0e351a6ffea8 Mon Sep 17 00:00:00 2001
From: Robert Knoester <[EMAIL REDACTED]>
Date: Fri, 6 Jun 2025 22:42:53 +0200
Subject: [PATCH] Added shader metadata for input/output variables. (#140)
---------
Co-authored-by: Anonymous Maarten <madebr@users.noreply.github.com>
Co-authored-by: Evan Hemsley <2342303+thatcosmonaut@users.noreply.github.com>
---
include/SDL3_shadercross/SDL_shadercross.h | 111 +++----
src/SDL_shadercross.c | 323 ++++++++++++++-------
src/cli.c | 180 ++++++++++--
3 files changed, 430 insertions(+), 184 deletions(-)
diff --git a/include/SDL3_shadercross/SDL_shadercross.h b/include/SDL3_shadercross/SDL_shadercross.h
index f5011ff..de06856 100644
--- a/include/SDL3_shadercross/SDL_shadercross.h
+++ b/include/SDL3_shadercross/SDL_shadercross.h
@@ -38,6 +38,21 @@ extern "C" {
#define SDL_SHADERCROSS_MINOR_VERSION 0
#define SDL_SHADERCROSS_MICRO_VERSION 0
+typedef enum SDL_ShaderCross_IOVarType {
+ SDL_SHADERCROSS_IOVAR_TYPE_UNKNOWN,
+ SDL_SHADERCROSS_IOVAR_TYPE_INT8,
+ SDL_SHADERCROSS_IOVAR_TYPE_UINT8,
+ SDL_SHADERCROSS_IOVAR_TYPE_INT16,
+ SDL_SHADERCROSS_IOVAR_TYPE_UINT16,
+ SDL_SHADERCROSS_IOVAR_TYPE_INT32,
+ SDL_SHADERCROSS_IOVAR_TYPE_UINT32,
+ SDL_SHADERCROSS_IOVAR_TYPE_INT64,
+ SDL_SHADERCROSS_IOVAR_TYPE_UINT64,
+ SDL_SHADERCROSS_IOVAR_TYPE_FLOAT16,
+ SDL_SHADERCROSS_IOVAR_TYPE_FLOAT32,
+ SDL_SHADERCROSS_IOVAR_TYPE_FLOAT64
+} SDL_ShaderCross_IOVarType;
+
typedef enum SDL_ShaderCross_ShaderStage
{
SDL_SHADERCROSS_SHADERSTAGE_VERTEX,
@@ -45,14 +60,24 @@ typedef enum SDL_ShaderCross_ShaderStage
SDL_SHADERCROSS_SHADERSTAGE_COMPUTE
} SDL_ShaderCross_ShaderStage;
+typedef struct SDL_ShaderCross_IOVarMetadata {
+ char *name; /**< The UTF-8 name of the variable. */
+ Uint32 location; /**< The location of the variable. */
+ Uint32 offset; /**< The byte offset of the variable. */
+ SDL_ShaderCross_IOVarType vector_type; /**< The vector type of the variable. */
+ Uint32 vector_size; /**< The number of components in the vector type of the variable. */
+} SDL_ShaderCross_IOVarMetadata;
+
typedef struct SDL_ShaderCross_GraphicsShaderMetadata
{
- Uint32 num_samplers; /**< The number of samplers defined in the shader. */
- Uint32 num_storage_textures; /**< The number of storage textures defined in the shader. */
- Uint32 num_storage_buffers; /**< The number of storage buffers defined in the shader. */
- Uint32 num_uniform_buffers; /**< The number of uniform buffers defined in the shader. */
-
- SDL_PropertiesID props; /**< A properties ID for extensions. This is allocated and freed by the caller, and should be 0 if no extensions are needed. */
+ Uint32 num_samplers; /**< The number of samplers defined in the shader. */
+ Uint32 num_storage_textures; /**< The number of storage textures defined in the shader. */
+ Uint32 num_storage_buffers; /**< The number of storage buffers defined in the shader. */
+ Uint32 num_uniform_buffers; /**< The number of uniform buffers defined in the shader. */
+ Uint32 num_inputs; /**< The number of inputs defined in the shader. */
+ SDL_ShaderCross_IOVarMetadata *inputs; /**< The inputs defined in the shader. */
+ Uint32 num_outputs; /**< The number of outputs defined in the shader. */
+ SDL_ShaderCross_IOVarMetadata *outputs; /**< The outputs defined in the shader. */
} SDL_ShaderCross_GraphicsShaderMetadata;
typedef struct SDL_ShaderCross_ComputePipelineMetadata
@@ -66,8 +91,6 @@ typedef struct SDL_ShaderCross_ComputePipelineMetadata
Uint32 threadcount_x; /**< The number of threads in the X dimension. */
Uint32 threadcount_y; /**< The number of threads in the Y dimension. */
Uint32 threadcount_z; /**< The number of threads in the Z dimension. */
-
- SDL_PropertiesID props; /**< A properties ID for extensions. This is allocated and freed by the caller, and should be 0 if no extensions are needed. */
} SDL_ShaderCross_ComputePipelineMetadata;
typedef struct SDL_ShaderCross_SPIRV_Info
@@ -109,6 +132,7 @@ typedef struct SDL_ShaderCross_HLSL_Info
* Initializes SDL_shadercross
*
* \threadsafety This should only be called once, from a single thread.
+ * \returns true on success, false otherwise.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_ShaderCross_Init(void);
/**
@@ -122,6 +146,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShaderCross_Quit(void);
* Get the supported shader formats that SPIRV cross-compilation can output
*
* \threadsafety It is safe to call this function from any thread.
+ * \returns GPU shader formats supported by SPIRV cross-compilation.
*/
extern SDL_DECLSPEC SDL_GPUShaderFormat SDLCALL SDL_ShaderCross_GetSPIRVShaderFormats(void);
@@ -174,66 +199,74 @@ extern SDL_DECLSPEC void * SDLCALL SDL_ShaderCross_CompileDXILFromSPIRV(
size_t *size);
/**
- * Compile an SDL GPU shader from SPIRV code.
+ * Compile an SDL GPU shader from SPIRV code. If your shader source is HLSL, you should obtain SPIR-V bytecode from SDL_ShaderCross_CompileSPIRVFromHLSL().
*
* \param device the SDL GPU device.
* \param info a struct describing the shader to transpile.
- * \param metadata a pointer filled in with shader metadata.
- * \returns a compiled SDL_GPUShader
+ * \param metadata a struct describing shader metadata. Can be obtained from SDL_ShaderCross_ReflectGraphicsSPIRV().
+ * \param props a properties object filled in with extra shader metadata.
+ * \returns a compiled SDL_GPUShader.
*
* \threadsafety It is safe to call this function from any thread.
*/
extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_ShaderCross_CompileGraphicsShaderFromSPIRV(
SDL_GPUDevice *device,
const SDL_ShaderCross_SPIRV_Info *info,
- SDL_ShaderCross_GraphicsShaderMetadata *metadata);
+ const SDL_ShaderCross_GraphicsShaderMetadata *metadata,
+ SDL_PropertiesID props);
/**
- * Compile an SDL GPU compute pipeline from SPIRV code.
+ * Compile an SDL GPU compute pipeline from SPIRV code. If your shader source is HLSL, you should obtain SPIR-V bytecode from SDL_ShaderCross_CompileSPIRVFromHLSL().
*
* \param device the SDL GPU device.
* \param info a struct describing the shader to transpile.
- * \param metadata a pointer filled in with compute pipeline metadata.
- * \returns a compiled SDL_GPUComputePipeline
+ * \param metadata a struct describing shader metadata. Can be obtained from SDL_ShaderCross_ReflectComputeSPIRV().
+ * \param props a properties object filled in with extra shader metadata.
+ * \returns a compiled SDL_GPUComputePipeline.
*
* \threadsafety It is safe to call this function from any thread.
*/
extern SDL_DECLSPEC SDL_GPUComputePipeline * SDLCALL SDL_ShaderCross_CompileComputePipelineFromSPIRV(
SDL_GPUDevice *device,
const SDL_ShaderCross_SPIRV_Info *info,
- SDL_ShaderCross_ComputePipelineMetadata *metadata);
+ const SDL_ShaderCross_ComputePipelineMetadata *metadata,
+ SDL_PropertiesID props);
/**
- * Reflect graphics shader info from SPIRV code.
+ * Reflect graphics shader info from SPIRV code. If your shader source is HLSL, you should obtain SPIR-V bytecode from SDL_ShaderCross_CompileSPIRVFromHLSL(). This must be freed with SDL_free() when you are done with the metadata.
*
* \param bytecode the SPIRV bytecode.
* \param bytecode_size the length of the SPIRV bytecode.
- * \param metadata a pointer filled in with shader metadata.
+ * \param props a properties object filled in with extra shader metadata, provided by the user.
+ * \returns A metadata struct on success, NULL otherwise. The struct must be free'd when it is no longer needed.
*
* \threadsafety It is safe to call this function from any thread.
*/
-extern SDL_DECLSPEC bool SDLCALL SDL_ShaderCross_ReflectGraphicsSPIRV(
+extern SDL_DECLSPEC SDL_ShaderCross_GraphicsShaderMetadata * SDLCALL SDL_ShaderCross_ReflectGraphicsSPIRV(
const Uint8 *bytecode,
size_t bytecode_size,
- SDL_ShaderCross_GraphicsShaderMetadata *metadata);
+ SDL_PropertiesID props);
/**
- * Reflect compute pipeline info from SPIRV code.
+ * Reflect compute pipeline info from SPIRV code. If your shader source is HLSL, you should obtain SPIR-V bytecode from SDL_ShaderCross_CompileSPIRVFromHLSL(). This must be freed with SDL_free() when you are done with the metadata.
*
* \param bytecode the SPIRV bytecode.
* \param bytecode_size the length of the SPIRV bytecode.
- * \param metadata a pointer filled in with compute pipeline metadata.
+ * \param props a properties object filled in with extra shader metadata, provided by the user.
+ * \returns A metadata struct on success, NULL otherwise.
*
* \threadsafety It is safe to call this function from any thread.
*/
-extern SDL_DECLSPEC bool SDLCALL SDL_ShaderCross_ReflectComputeSPIRV(
+extern SDL_DECLSPEC SDL_ShaderCross_ComputePipelineMetadata * SDLCALL SDL_ShaderCross_ReflectComputeSPIRV(
const Uint8 *bytecode,
size_t bytecode_size,
- SDL_ShaderCross_ComputePipelineMetadata *metadata);
+ SDL_PropertiesID props);
/**
* Get the supported shader formats that HLSL cross-compilation can output
*
+ * \returns GPU shader formats supported by HLSL cross-compilation.
+ *
* \threadsafety It is safe to call this function from any thread.
*/
extern SDL_DECLSPEC SDL_GPUShaderFormat SDLCALL SDL_ShaderCross_GetHLSLShaderFormats(void);
@@ -283,36 +316,6 @@ extern SDL_DECLSPEC void * SDLCALL SDL_ShaderCross_CompileSPIRVFromHLSL(
const SDL_ShaderCross_HLSL_Info *info,
size_t *size);
-/**
- * Compile an SDL GPU shader from HLSL code.
- *
- * \param device the SDL GPU device.
- * \param info a struct describing the shader to transpile.
- * \param metadata a pointer filled in with shader metadata.
- * \returns a compiled SDL_GPUShader
- *
- * \threadsafety It is safe to call this function from any thread.
- */
-extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_ShaderCross_CompileGraphicsShaderFromHLSL(
- SDL_GPUDevice *device,
- const SDL_ShaderCross_HLSL_Info *info,
- SDL_ShaderCross_GraphicsShaderMetadata *metadata);
-
-/**
- * Compile an SDL GPU compute pipeline from code.
- *
- * \param device the SDL GPU device.
- * \param info a struct describing the shader to transpile.
- * \param metadata a pointer filled in with compute pipeline metadata.
- * \returns a compiled SDL_GPUComputePipeline
- *
- * \threadsafety It is safe to call this function from any thread.
- */
-extern SDL_DECLSPEC SDL_GPUComputePipeline * SDLCALL SDL_ShaderCross_CompileComputePipelineFromHLSL(
- SDL_GPUDevice *device,
- const SDL_ShaderCross_HLSL_Info *info,
- SDL_ShaderCross_ComputePipelineMetadata *metadata);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/SDL_shadercross.c b/src/SDL_shadercross.c
index f6cebb7..eff5366 100644
--- a/src/SDL_shadercross.c
+++ b/src/SDL_shadercross.c
@@ -27,6 +27,9 @@
#define MAX_DEFINES 64
#define MAX_DEFINE_STRING_LENGTH 256
+/* Upper round X to multiple of V. V must be power of 2. */
+#define SDL_upper_multiple_power2(X, V) (((X) + (V) - 1) & ~((V) - 1))
+
/* Win32 Type Definitions */
typedef int HRESULT;
@@ -807,70 +810,6 @@ void *SDL_ShaderCross_CompileDXBCFromHLSL(
size);
}
-static void *SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL(
- SDL_GPUDevice *device,
- const SDL_ShaderCross_HLSL_Info *info,
- SDL_ShaderCross_GraphicsShaderMetadata *metadata)
-{
- size_t bytecodeSize;
-
- // We'll go through SPIRV-Cross for all of these to more easily obtain reflection metadata.
- void *spirv = SDL_ShaderCross_CompileSPIRVFromHLSL(
- info,
- &bytecodeSize);
-
- if (spirv == NULL) {
- // Error output from DXC will have already been set
- return NULL;
- }
-
- SDL_ShaderCross_SPIRV_Info spirvInfo;
- spirvInfo.bytecode = spirv;
- spirvInfo.bytecode_size = bytecodeSize;
- spirvInfo.entrypoint = info->entrypoint;
- spirvInfo.shader_stage = info->shader_stage;
- spirvInfo.enable_debug = info->enable_debug;
- spirvInfo.name = info->name;
- spirvInfo.props = 0;
-
- void *result;
- if (info->shader_stage == SDL_SHADERCROSS_SHADERSTAGE_COMPUTE) {
- result = SDL_ShaderCross_CompileComputePipelineFromSPIRV(
- device,
- &spirvInfo,
- (void *)metadata);
- } else {
- result = SDL_ShaderCross_CompileGraphicsShaderFromSPIRV(
- device,
- &spirvInfo,
- (void *)metadata);
- }
- SDL_free(spirv);
- return result;
-}
-
-SDL_GPUShader *SDL_ShaderCross_CompileGraphicsShaderFromHLSL(
- SDL_GPUDevice *device,
- const SDL_ShaderCross_HLSL_Info *info,
- SDL_ShaderCross_GraphicsShaderMetadata *metadata)
-{
- return (SDL_GPUShader *)SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL(
- device,
- info,
- (void *)metadata);
-}
-
-SDL_GPUComputePipeline *SDL_ShaderCross_CompileComputePipelineFromHLSL(
- SDL_GPUDevice *device,
- const SDL_ShaderCross_HLSL_Info *info,
- SDL_ShaderCross_ComputePipelineMetadata *metadata)
-{
- return (SDL_GPUComputePipeline *)SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL(
- device,
- info,
- (void *)metadata);
-}
-
#include <spirv_cross_c.h>
#define SPVC_ERROR(func) \
@@ -1656,12 +1595,90 @@ static SPIRVTranspileContext *SDL_ShaderCross_INTERNAL_TranspileFromSPIRV(
return transpileContext;
}
+size_t SDL_ShaderCross_INTERNAL_GetIOVarsStringLength(
+ spvc_reflected_resource* reflected_resources,
+ size_t num_vars)
+{
+ size_t total_string_size = 0;
+ for (size_t i = 0; i < num_vars; i++) {
+ spvc_reflected_resource* resource = &reflected_resources[i];
+ total_string_size += SDL_strlen(resource->name) + 1;
+ }
+ return total_string_size;
+}
+
+void SDL_ShaderCross_INTERNAL_GetIOVars(
+ spvc_compiler compiler,
+ spvc_reflected_resource* reflected_resources,
+ size_t num_vars,
+ SDL_ShaderCross_IOVarMetadata* vars,
+ char *name_buffer
+) {
+ Uint32 offset = 0;
+ size_t name_buffer_offset = 0;
+ for (size_t i = 0; i < num_vars; i++) {
+ SDL_ShaderCross_IOVarMetadata* var = &vars[i];
+ spvc_reflected_resource* resource = &reflected_resources[i];
+ spvc_type type = spvc_compiler_get_type_handle(compiler, resource->base_type_id);
+
+ switch (spvc_type_get_basetype(type)) {
+ case SPVC_BASETYPE_INT8:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_INT8;
+ break;
+ case SPVC_BASETYPE_UINT8:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_UINT8;
+ break;
+ case SPVC_BASETYPE_INT16:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_INT16;
+ break;
+ case SPVC_BASETYPE_UINT16:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_UINT16;
+ break;
+ case SPVC_BASETYPE_INT32:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_INT32;
+ break;
+ case SPVC_BASETYPE_UINT32:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_UINT32;
+ break;
+ case SPVC_BASETYPE_INT64:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_INT64;
+ break;
+ case SPVC_BASETYPE_UINT64:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_UINT64;
+ break;
+ case SPVC_BASETYPE_FP16:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_FLOAT16;
+ break;
+ case SPVC_BASETYPE_FP32:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_FLOAT32;
+ break;
+ case SPVC_BASETYPE_FP64:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_FLOAT64;
+ break;
+ default:
+ var->vector_type = SDL_SHADERCROSS_IOVAR_TYPE_UNKNOWN;
+ break;
+ }
+
+ Uint32 vector_size = spvc_type_get_vector_size(type);
+ var->vector_size = vector_size;
+
+ var->name = name_buffer + name_buffer_offset;
+ size_t length_name = SDL_strlen(resource->name) + 1;
+ SDL_memcpy(var->name, resource->name, length_name);
+ name_buffer_offset += length_name;
+ var->location = spvc_compiler_get_decoration(compiler, resource->id, SpvDecorationLocation);
+ var->offset = offset;
+ offset += (spvc_type_get_bit_width(type) / 8) * vector_size;
+ }
+}
+
// Acquire metadata from SPIRV bytecode.
// TODO: validate descriptor sets
-bool SDL_ShaderCross_ReflectGraphicsSPIRV(
+SDL_ShaderCross_GraphicsShaderMetadata * SDL_ShaderCross_ReflectGraphicsSPIRV(
const Uint8 *code,
size_t codeSize,
- SDL_ShaderCross_GraphicsShaderMetadata *metadata // filled in with reflected data
+ SDL_PropertiesID metadataProps
) {
spvc_result result;
spvc_context context = NULL;
@@ -1671,14 +1688,19 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
size_t num_storage_textures = 0;
size_t num_storage_buffers = 0;
size_t num_uniform_buffers = 0;
+ size_t string_length_input;
+ size_t num_inputs = 0;
+ size_t string_length_output;
+ size_t num_outputs = 0;
size_t num_separate_samplers = 0; // HLSL edge case
size_t num_separate_images = 0; // HLSL edge case
+ (void) metadataProps;
/* Create the SPIRV-Cross context */
result = spvc_context_create(&context);
if (result < 0) {
SDL_SetError("spvc_context_create failed: %X", result);
- return false;
+ return NULL;
}
/* Parse the SPIR-V into IR */
@@ -1686,7 +1708,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_context_parse_spirv);
spvc_context_destroy(context);
- return false;
+ return NULL;
}
/* Create a reflection-only compiler */
@@ -1694,7 +1716,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_context_create_compiler);
spvc_context_destroy(context);
- return false;
+ return NULL;
}
spvc_resources resources;
@@ -1704,7 +1726,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_compiler_create_shader_resources);
spvc_context_destroy(context);
- return false;
+ return NULL;
}
// Combined texture-samplers
@@ -1716,7 +1738,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_resources_get_resource_list_for_type);
spvc_context_destroy(context);
- return false;
+ return NULL;
}
// If source is HLSL, we might have separate images and samplers
@@ -1729,7 +1751,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_resources_get_resource_list_for_type);
spvc_context_destroy(context);
- return false;
+ return NULL;
}
num_texture_samplers = num_separate_samplers;
}
@@ -1743,7 +1765,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_resources_get_resource_list_for_type);
spvc_context_destroy(context);
- return false;
+ return NULL;
}
// If source is HLSL, storage images might be marked as separate images
@@ -1755,7 +1777,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_resources_get_resource_list_for_type);
spvc_context_destroy(context);
- return false;
+ 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);
@@ -1769,7 +1791,7 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_resources_get_resource_list_for_type);
spvc_context_destroy(context);
- return false;
+ return NULL;
}
// Uniform buffers
@@ -1781,22 +1803,95 @@ bool SDL_ShaderCross_ReflectGraphicsSPIRV(
if (result < 0) {
SPVC_ERROR(spvc_resources_get_resource_list_for_type);
spvc_context_destroy(context);
+ return NULL;
+ }
+
+ // Inputs (stage 1: count number of inputs, and name lengths)
+ result = spvc_resources_get_resource_list_for_type(
+ resources,
+ SPVC_RESOURCE_TYPE_STAGE_INPUT,
+ (const spvc_reflected_resource **)&reflected_resources,
+ &num_inputs);
+ if (result < 0) {
+ SPVC_ERROR(spvc_resources_get_resource_list_for_type);
+ spvc_context_destroy(context);
+ return NULL;
+ }
+ string_length_input = SDL_ShaderCross_INTERNAL_GetIOVarsStringLength(reflected_resources, num_inputs);
+
+ // Outputs (stage 1: count number of outputs, and name lengths)
+ result = spvc_resources_get_resource_list_for_type(
+ resources,
+ SPVC_RESOURCE_TYPE_STAGE_OUTPUT,
+ (const spvc_reflected_resource **)&reflected_resources,
+ &num_outputs);
+ if (result < 0) {
+ SPVC_ERROR(spvc_resources_get_resource_list_for_type);
+ spvc_context_destroy(context);
+ return NULL;
+ }
+ string_length_output = SDL_ShaderCross_INTERNAL_GetIOVarsStringLength(reflected_resources, num_outputs);
+
+ size_t offset_inputs = SDL_upper_multiple_power2(sizeof(SDL_ShaderCross_GraphicsShaderMetadata), sizeof(size_t));
+ size_t offset_outputs = offset_inputs + num_inputs * sizeof(SDL_ShaderCross_IOVarMetadata);
+ size_t offset_inputnames = offset_outputs + num_outputs * sizeof(SDL_ShaderCross_IOVarMetadata);
+ size_t offset_outputnames = offset_inputnames + string_length_input;
+
+ char *allocMemory = SDL_malloc(offset_outputnames + string_length_output);
+ if (!allocMemory) {
+ spvc_context_destroy(context);
+ return NULL;
+ }
+
+ SDL_ShaderCross_GraphicsShaderMetadata *allocMetadata = (SDL_ShaderCross_GraphicsShaderMetadata *)allocMemory;
+ allocMetadata->inputs = (SDL_ShaderCross_IOVarMetadata *)(allocMemory + offset_inputs);
+ allocMetadata->outputs = (SDL_ShaderCross_IOVarMetadata *)(allocMemory + offset_outputs);
+
+ // Inputs (stage 2: fill in inputs)
+ size_t num_inputs_run2 = 0;
+ result = spvc_resources_get_resource_list_for_type(
+ resources,
+ SPVC_RESOURCE_TYPE_STAGE_INPUT,
+ (const spvc_reflected_resource **)&reflected_resources,
+ &num_inputs_run2);
+ if (result < 0 || num_inputs != num_inputs_run2) {
+ SPVC_ERROR(spvc_resources_get_resource_list_for_type);
+ spvc_context_destroy(context);
+ SDL_free(allocMemory);
return false;
}
+ SDL_ShaderCross_INTERNAL_GetIOVars(compiler, reflected_resources, num_inputs, allocMetadata->inputs, allocMemory + offset_inputnames);
+ // Inputs (stage 2: fill in outputs)
+ size_t num_outputs_run2 = 0;
+ result = spvc_resources_get_resource_list_for_type(
+ resources,
+ SPVC_RESOURCE_TYPE_STAGE_OUTPUT,
+ (const spvc_reflected_resource **)&reflected_resources,
+ &num_outputs_run2);
+ if (result < 0 || num_outputs != num_outputs_run2) {
+ SPVC_ERROR(spvc_resources_get_resource_list_for_type);
+ spvc_context_destroy(context);
+ SDL_free(allocMemory);
+ return false;
+ }
+ SDL_ShaderCross_INTERNAL_GetIOVars(compiler, reflected_resources, num_outputs, allocMetadata->outputs, allocMemory + offset_outputnames);
spvc_context_destroy(context);
- metadata->num_samplers = num_texture_samplers;
- metadata->num_storage_textures = num_storage_textures;
- metadata->num_storage_buffers = num_storage_buffers;
- metadata->num_uniform_buffers = num_uniform_buffers;
- return true;
+ 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_inputs = num_inputs;
+ allocMetadata->num_outputs = num_outputs;
+
+ return allocMetadata;
}
-bool SDL_ShaderCross_ReflectComputeSPIRV(
+SDL_ShaderCross_ComputePipelineMetadata * SDL_ShaderCross_ReflectComputeSPIRV(
const Uint8 *bytecode,
size_t bytecodeSize,
- SDL_ShaderCross_ComputePipelineMetadata *metadata // filled in with reflected data
+ SDL_PropertiesID metadataProps
) {
spvc_result result;
spvc_context context = NULL;
@@ -1814,6 +1909,8 @@ bool SDL_ShaderCross_ReflectComputeSPIRV(
size_t num_separate_samplers = 0; // HLSL edge case
size_t num_separate_images = 0; // HLSL edge case
+ (void) metadataProps;
+
/* Create the SPIRV-Cross context */
result = spvc_context_create(&context);
if (result < 0) {
@@ -1992,6 +2089,10 @@ bool SDL_ShaderCross_ReflectComputeSPIRV(
}
// Threadcount
+ SDL_ShaderCross_ComputePipelineMetadata *metadata = SDL_malloc(sizeof(SDL_ShaderCross_ComputePipelineMetadata));
+ if (!metadata) {
+ return NULL;
+ }
metadata->threadcount_x = spvc_compiler_get_execution_mode_argument_by_index(compiler, SpvExecutionModeLocalSize, 0);
metadata->threadcount_y = spvc_compiler_get_execution_mode_argument_by_index(compiler, SpvExecutionModeLocalSize, 1);
metadata->threadcount_z = spvc_compiler_get_execution_mode_argument_by_index(compiler, SpvExecutionModeLocalSize, 2);
@@ -2004,14 +2105,14 @@ bool SDL_ShaderCross_ReflectComputeSPIRV(
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;
- return true;
+ return metadata;
}
static void *SDL_ShaderCross_INTERNAL_CompileFromSPIRV(
SDL_GPUDevice *device,
const SDL_ShaderCross_SPIRV_Info *info,
SDL_GPUShaderFormat targetFormat,
- void *metadata
+ SDL_PropertiesID metadataProps
) {
spvc_backend backend;
unsigned shadermodel = 0;
@@ -2045,12 +2146,12 @@ static void *SDL_ShaderCross_INTERNAL_CompileFromSPIRV(
void *shaderObject = NULL;
if (info->shader_stage == SDL_SHADERCROSS_SHADERSTAGE_COMPUTE) {
- SDL_GPUComputePipelineCreateInfo createInfo;
- SDL_ShaderCross_ComputePipelineMetadata *pipelineInfo = (SDL_ShaderCross_ComputePipelineMetadata *)metadata;
- SDL_ShaderCross_ReflectComputeSPIRV(
+ SDL_ShaderCross_ComputePipelineMetadata *pipelineInfo = SDL_ShaderCross_ReflectComputeSPIRV(
info->bytecode,
info->bytecode_size,
- pipelineInfo);
+ metadataProps);
+ SDL_GPUComputePipelineCreateInfo createInfo;
+
createInfo.entrypoint = transpileContext->cleansed_entrypoint;
createInfo.format = targetFormat;
createInfo.num_samplers = pipelineInfo->num_samplers;
@@ -2098,13 +2199,19 @@ static void *SDL_ShaderCross_INTERNAL_CompileFromSPIRV(
if (createInfo.props != 0) {
SDL_DestroyProperties(createInfo.props);
}
+ SDL_free(pipelineInfo);
} else {
SDL_GPUShaderCreateInfo createInfo;
- SDL_ShaderCross_GraphicsShaderMetadata *shaderInfo = (SDL_ShaderCross_GraphicsShaderMetadata *)metadata;
- SDL_ShaderCross_ReflectGraphicsSPIRV(
- info->bytecode,
- info->bytecode_size,
- shaderInfo);
+ SDL_ShaderCross_GraphicsShaderMetadata *shaderInfo =
+ SDL_ShaderCross_ReflectGraphicsSPIRV(
+ info->bytecode,
+ info->bytecode_size,
+ metadataProps);
+
+ if (shaderInfo == NULL) {
+ SDL_ShaderCross_INTERNAL_DestroyTranspileContext(transpileContext);
+ return NULL;
+ }
createInfo.entrypoint = transpileContext->cleansed_entrypoint;
createInfo.format = targetFormat;
createInfo.stage = (SDL_GPUShaderStage)info->shader_stage;
@@ -2148,6 +2255,8 @@ static void *SDL_ShaderCross_INTERNAL_CompileFromSPIRV(
if (createInfo.props != 0) {
SDL_DestroyProperties(createInfo.props);
}
+
+ SDL_free(shaderInfo);
}
SDL_ShaderCross_INTERNAL_DestroyTranspileContext(transpileContext);
@@ -2283,7 +2392,8 @@ void *SDL_ShaderCross_CompileDXILFromSPIRV(
static void *SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(
SDL_GPUDevice *device,
const SDL_ShaderCross_SPIRV_Info *info,
- void *metadata)
+ const void *metadata,
+ SDL_PropertiesID metadataProps)
{
SDL_GPUShaderFormat format;
@@ -2293,10 +2403,6 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(
if (info->shader_stage == SDL_SHADERCROSS_SHADERSTAGE_COMPUTE) {
SDL_GPUComputePipelineCreateInfo createInfo;
SDL_ShaderCross_ComputePipelineMetadata *pipelineMetadata = (SDL_ShaderCross_ComputePipelineMetadata *)metadata;
- SDL_ShaderCross_ReflectComputeSPIRV(
- info->bytecode,
- info->bytecode_size,
- pipelineMetadata);
createInfo.code = info->bytecode;
createInfo.code_size = info->bytecode_size;
createInfo.entrypoint = info->entrypoint;
@@ -2323,14 +2429,13 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(
SDL_DestroyProperties(createInfo.props);
}
+ SDL_free(pipelineMetadata);
+
return result;
} else {
SDL_GPUShaderCreateInfo createInfo;
SDL_ShaderCross_GraphicsShaderMetadata *shaderMetadata = (SDL_ShaderCross_GraphicsShaderMetadata *)metadata;
- SDL_ShaderCross_ReflectGraphicsSPIRV(
- info->bytecode,
- info->bytecode_size,
- shaderMetadata);
+
createInfo.code = info->bytecode;
createInfo.code_size = info->bytecode_size;
createInfo.entrypoint = info->entrypoint;
@@ -2376,29 +2481,33 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(
device,
info,
format,
- metadata);
+ metadataProps);
}
SDL_GPUShader *SDL_ShaderCross_CompileGraphicsShaderFromSPIRV(
SDL_GPUDevice *device,
const SDL_ShaderCross_SPIRV_Info *info,
- SDL_ShaderCross_GraphicsShaderMetadata *metadata)
+ const SDL_ShaderCross_GraphicsShaderMetadata *metadata,
+ SDL_PropertiesID props)
{
return (SDL_GPUShader *)SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(
device,
info,
- metadata);
+ (void*) metadata,
+ props);
}
SDL_GPUComputePipeline *SDL_ShaderCross_CompileComputePipelineFromSPIRV(
SDL_GPUDevice *device,
const SDL_ShaderCross_SPIRV_Info *info,
- SDL_ShaderCross_ComputePipelineMetadata *metadata)
+ const SDL_ShaderCross_ComputePipelineMetadata *metadata,
+ SDL_PropertiesID props)
{
return (SDL_GPUComputePipeline *)SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(
device,
info,
- metadata);
+ (void*) metadata,
+ props);
}
bool SDL_ShaderCross_Init(void)
diff --git a/src/cli.c b/src/cli.c
index 6c9ce1b..086e820 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -53,16 +53,152 @@ void print_help(void)
(Patch may be truncated, please check the link at the top of this post.)