From 3acf9c17e5c6de6b7e6d6627f3db28ad87c1b148 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Thu, 7 Nov 2024 14:10:35 -0800 Subject: [PATCH] Rework Compile APIs --- CMakeLists.txt | 1 + .../SDL_gpu_shadercross.h | 59 +++++- src/SDL_gpu_shadercross.c | 190 +++++++++++++++--- 3 files changed, 214 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee61f15..8c5e51e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,7 @@ else() endif() endif() + set(DirectXShaderCompiler_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/external/DirectXShaderCompiler-binaries") find_package(DirectXShaderCompiler REQUIRED) endif() diff --git a/include/SDL3_gpu_shadercross/SDL_gpu_shadercross.h b/include/SDL3_gpu_shadercross/SDL_gpu_shadercross.h index e4b873a..e929111 100644 --- a/include/SDL3_gpu_shadercross/SDL_gpu_shadercross.h +++ b/include/SDL3_gpu_shadercross/SDL_gpu_shadercross.h @@ -60,6 +60,25 @@ typedef enum SDL_ShaderCross_ShaderModel SDL_SHADERCROSS_SHADERMODEL_6_0 } SDL_ShaderCross_ShaderModel; +typedef struct SDL_ShaderCross_ShaderResourceInfo { + 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_ShaderCross_ShaderResourceInfo; + +typedef struct SDL_ShaderCross_ComputeResourceInfo { + Uint32 num_samplers; /**< The number of samplers defined in the shader. */ + Uint32 num_readonly_storage_textures; /**< The number of storage textures defined in the shader. */ + Uint32 num_readonly_storage_buffers; /**< The number of storage buffers defined in the shader. */ + Uint32 num_readwrite_storage_textures; /**< The number of read-write storage textures defined in the shader. */ + Uint32 num_readwrite_storage_buffers; /**< The number of read-write storage buffers defined in the shader. */ + Uint32 num_uniform_buffers; /**< The number of uniform buffers defined in the shader. */ + Uint32 threadcount_x; /**< The number of threads in the X dimension. This should match the value in the shader. */ + Uint32 threadcount_y; /**< The number of threads in the Y dimension. This should match the value in the shader. */ + Uint32 threadcount_z; /**< The number of threads in the Z dimension. This should match the value in the shader. */ +} SDL_ShaderCross_ComputeResourceInfo; + /** * Initializes SDL_gpu_shadercross * @@ -157,27 +176,42 @@ extern SDL_DECLSPEC void * SDLCALL SDL_ShaderCross_CompileDXILFromSPIRV( * Compile an SDL GPU shader from SPIRV code. * * \param device the SDL GPU device. - * \param createInfo a pointer to an SDL_GPUShaderCreateInfo. + * \param bytecode the SPIRV bytecode. + * \param bytecodeSize the length of the SPIRV bytecode. + * \param entrypoint the entry point function name for the shader in UTF-8. + * \param shaderStage the shader stage to compile the shader with. + * \param resourceInfo a pointer to an SDL_ShaderCross_ShaderResourceInfo. * \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_GPUShaderCreateInfo *createInfo); + const Uint8 *bytecode, + size_t bytecodeSize, + const char *entrypoint, + SDL_GPUShaderStage shaderStage, + const SDL_ShaderCross_ShaderResourceInfo *resourceInfo); /** * Compile an SDL GPU compute pipeline from SPIRV code. * * \param device the SDL GPU device. - * \param createInfo a pointer to an SDL_GPUComputePipelineCreateInfo. + * \param bytecode the SPIRV bytecode. + * \param bytecodeSize the length of the SPIRV bytecode. + * \param entrypoint the entry point function name for the shader in UTF-8. + * \param resourceInfo a pointer to an SDL_ShaderCross_ShaderResourceInfo. * \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_GPUComputePipelineCreateInfo *createInfo); + const Uint8 *bytecode, + size_t bytecodeSize, + const char *entrypoint, + const SDL_ShaderCross_ComputeResourceInfo *resourceInfo); + #endif /* SDL_GPU_SHADERCROSS_SPIRVCROSS */ #if SDL_GPU_SHADERCROSS_HLSL @@ -249,34 +283,37 @@ extern SDL_DECLSPEC void * SDLCALL SDL_ShaderCross_CompileSPIRVFromHLSL( * Compile an SDL GPU shader from HLSL Shader Model 6.0 code. * * \param device the SDL GPU device. - * \param createInfo a pointer to an SDL_GPUShaderCreateInfo. * \param hlslSource the HLSL source code for the shader. + * \param entrypoint the entry point function name for the shader in UTF-8. * \param graphicsShaderStage the shader stage to compile the shader with. + * \param resourceInfo a pointer to an SDL_ShaderCross_ShaderResourceInfo. * \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_GPUShaderCreateInfo *createInfo, const char *hlslSource, - SDL_GPUShaderStage graphicsShaderStage); + const char *entrypoint, + SDL_GPUShaderStage graphicsShaderStage, + const SDL_ShaderCross_ShaderResourceInfo *resourceInfo); /** * Compile an SDL GPU compute pipeline from HLSL Shader Model 6.0 code. * * \param device the SDL GPU device. - * \param createInfo a pointer to an SDL_GPUComputePipelineCreateInfo. * \param hlslSource the HLSL source code for the shader. - * \param shaderStage the shader stage to compile the shader with. + * \param entrypoint the entry point function name for the shader in UTF-8. + * \param resourceInfo a pointer to an SDL_ShaderCross_ComputeResourceInfo. * \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_GPUComputePipelineCreateInfo *createInfo, - const char *hlslSource); + const char *hlslSource, + const char *entrypoint, + const SDL_ShaderCross_ComputeResourceInfo *resourceInfo); #endif /* SDL_GPU_SHADERCROSS_HLSL */ diff --git a/src/SDL_gpu_shadercross.c b/src/SDL_gpu_shadercross.c index 2be9df8..8a466f5 100644 --- a/src/SDL_gpu_shadercross.c +++ b/src/SDL_gpu_shadercross.c @@ -454,9 +454,10 @@ void *SDL_ShaderCross_CompileSPIRVFromHLSL( static void *SDL_ShaderCross_INTERNAL_CreateShaderFromDXC( SDL_GPUDevice *device, - const void *createInfo, const char *hlslSource, + const char *entrypoint, SDL_ShaderCross_ShaderStage shaderStage, + const void *resourceInfo, bool spirv) { void *result; @@ -467,14 +468,14 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromDXC( // If destination is DXIL, force roundtrip through SPIRV-Cross. bytecode = SDL_ShaderCross_CompileDXILFromHLSL( hlslSource, - ((const SDL_GPUShaderCreateInfo *)createInfo)->entrypoint, + entrypoint, shaderStage, &bytecodeSize); } else { // Otherwise just compile straight to SPIRV. bytecode = SDL_ShaderCross_INTERNAL_CompileUsingDXC( hlslSource, - ((const SDL_GPUShaderCreateInfo *)createInfo)->entrypoint, + entrypoint, shaderStage, spirv, &bytecodeSize); @@ -485,19 +486,37 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromDXC( } if (shaderStage == SDL_SHADERCROSS_SHADERSTAGE_COMPUTE) { + SDL_ShaderCross_ComputeResourceInfo *info = (SDL_ShaderCross_ComputeResourceInfo *)resourceInfo; SDL_GPUComputePipelineCreateInfo newCreateInfo; - newCreateInfo = *(const SDL_GPUComputePipelineCreateInfo *)createInfo; newCreateInfo.code = (const Uint8 *)bytecode; newCreateInfo.code_size = bytecodeSize; + newCreateInfo.entrypoint = entrypoint; newCreateInfo.format = spirv ? SDL_GPU_SHADERFORMAT_SPIRV : SDL_GPU_SHADERFORMAT_DXIL; + newCreateInfo.num_samplers = info->num_samplers; + newCreateInfo.num_readonly_storage_textures = info->num_readonly_storage_textures; + newCreateInfo.num_readonly_storage_buffers = info->num_readonly_storage_buffers; + newCreateInfo.num_readwrite_storage_textures = info->num_readwrite_storage_textures; + newCreateInfo.num_readwrite_storage_buffers = info->num_readwrite_storage_buffers; + newCreateInfo.num_uniform_buffers = info->num_uniform_buffers; + newCreateInfo.threadcount_x = info->threadcount_x; + newCreateInfo.threadcount_y = info->threadcount_y; + newCreateInfo.threadcount_z = info->threadcount_z; + newCreateInfo.props = 0; result = SDL_CreateGPUComputePipeline(device, &newCreateInfo); } else { + SDL_ShaderCross_ShaderResourceInfo *info = (SDL_ShaderCross_ShaderResourceInfo *)resourceInfo; SDL_GPUShaderCreateInfo newCreateInfo; - newCreateInfo = *(const SDL_GPUShaderCreateInfo *)createInfo; newCreateInfo.code = (const Uint8 *)bytecode; newCreateInfo.code_size = bytecodeSize; + newCreateInfo.entrypoint = entrypoint; newCreateInfo.format = spirv ? SDL_GPU_SHADERFORMAT_SPIRV : SDL_GPU_SHADERFORMAT_DXIL; + newCreateInfo.stage = (SDL_GPUShaderStage)shaderStage; + newCreateInfo.num_samplers = info->num_samplers; + newCreateInfo.num_storage_textures = info->num_storage_textures; + newCreateInfo.num_storage_buffers = info->num_storage_buffers; + newCreateInfo.num_uniform_buffers = info->num_uniform_buffers; + newCreateInfo.props = 0; result = SDL_CreateGPUShader(device, &newCreateInfo); } @@ -675,16 +694,17 @@ void *SDL_ShaderCross_CompileDXBCFromHLSL( static void *SDL_ShaderCross_INTERNAL_CreateShaderFromDXBC( SDL_GPUDevice *device, - const void *createInfo, const char *hlslSource, - SDL_ShaderCross_ShaderStage shaderStage) + const char *entrypoint, + SDL_ShaderCross_ShaderStage shaderStage, + const void *resourceInfo) { void *result; size_t bytecodeSize; void *bytecode = SDL_ShaderCross_CompileDXBCFromHLSL( hlslSource, - ((const SDL_GPUShaderCreateInfo *)createInfo)->entrypoint, + entrypoint, shaderStage, &bytecodeSize); @@ -693,19 +713,37 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromDXBC( } if (shaderStage == SDL_SHADERCROSS_SHADERSTAGE_COMPUTE) { + SDL_ShaderCross_ComputeResourceInfo *info = (SDL_ShaderCross_ComputeResourceInfo *)resourceInfo; SDL_GPUComputePipelineCreateInfo newCreateInfo; - newCreateInfo = *(const SDL_GPUComputePipelineCreateInfo *)createInfo; newCreateInfo.code = (const Uint8 *)bytecode; newCreateInfo.code_size = bytecodeSize; + newCreateInfo.entrypoint = entrypoint; newCreateInfo.format = SDL_GPU_SHADERFORMAT_DXBC; + newCreateInfo.num_samplers = info->num_samplers; + newCreateInfo.num_readonly_storage_textures = info->num_readonly_storage_textures; + newCreateInfo.num_readonly_storage_buffers = info->num_readonly_storage_buffers; + newCreateInfo.num_readwrite_storage_textures = info->num_readwrite_storage_textures; + newCreateInfo.num_readwrite_storage_buffers = info->num_readwrite_storage_buffers; + newCreateInfo.num_uniform_buffers = info->num_uniform_buffers; + newCreateInfo.threadcount_x = info->threadcount_x; + newCreateInfo.threadcount_y = info->threadcount_y; + newCreateInfo.threadcount_z = info->threadcount_z; + newCreateInfo.props = 0; result = SDL_CreateGPUComputePipeline(device, &newCreateInfo); } else { + SDL_ShaderCross_ShaderResourceInfo *info = (SDL_ShaderCross_ShaderResourceInfo *)resourceInfo; SDL_GPUShaderCreateInfo newCreateInfo; - newCreateInfo = *(const SDL_GPUShaderCreateInfo *)createInfo; newCreateInfo.code = (const Uint8 *)bytecode; newCreateInfo.code_size = bytecodeSize; + newCreateInfo.entrypoint = entrypoint; newCreateInfo.format = SDL_GPU_SHADERFORMAT_DXBC; + newCreateInfo.stage = (SDL_GPUShaderStage)shaderStage; + newCreateInfo.num_samplers = info->num_samplers; + newCreateInfo.num_storage_textures = info->num_storage_textures; + newCreateInfo.num_storage_buffers = info->num_storage_buffers; + newCreateInfo.num_uniform_buffers = info->num_uniform_buffers; + newCreateInfo.props = 0; result = SDL_CreateGPUShader(device, &newCreateInfo); } @@ -716,19 +754,68 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromDXBC( static void *SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL( SDL_GPUDevice *device, - const void *createInfo, const char *hlslSource, - SDL_ShaderCross_ShaderStage shaderStage) + const char *entrypoint, + SDL_ShaderCross_ShaderStage shaderStage, + const void *resourceInfo) { SDL_GPUShaderFormat format = SDL_GetGPUShaderFormats(device); if (format & SDL_GPU_SHADERFORMAT_DXBC) { - return SDL_ShaderCross_INTERNAL_CreateShaderFromDXBC(device, createInfo, hlslSource, shaderStage); + return SDL_ShaderCross_INTERNAL_CreateShaderFromDXBC( + device, + hlslSource, + entrypoint, + shaderStage, + resourceInfo); } if (format & SDL_GPU_SHADERFORMAT_DXIL) { - return SDL_ShaderCross_INTERNAL_CreateShaderFromDXC(device, createInfo, hlslSource, shaderStage, false); + return SDL_ShaderCross_INTERNAL_CreateShaderFromDXC( + device, + hlslSource, + entrypoint, + shaderStage, + resourceInfo, + false); } if (format & SDL_GPU_SHADERFORMAT_SPIRV) { - return SDL_ShaderCross_INTERNAL_CreateShaderFromDXC(device, createInfo, hlslSource, shaderStage, true); + return SDL_ShaderCross_INTERNAL_CreateShaderFromDXC( + device, + hlslSource, + entrypoint, + shaderStage, + resourceInfo, + true); + } + if (format & SDL_GPU_SHADERFORMAT_MSL) { + size_t bytecodeSize; + void *spirv = SDL_ShaderCross_CompileSPIRVFromHLSL( + hlslSource, + entrypoint, + shaderStage, + &bytecodeSize); + if (spirv == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", "Failed to compile SPIR-V!"); + return NULL; + } + void *result; + if (shaderStage == SDL_SHADERCROSS_SHADERSTAGE_COMPUTE) { + result = SDL_ShaderCross_CompileComputePipelineFromSPIRV( + device, + spirv, + bytecodeSize, + entrypoint, + (SDL_ShaderCross_ComputeResourceInfo *)resourceInfo); + } else { + result = SDL_ShaderCross_CompileGraphicsShaderFromSPIRV( + device, + spirv, + bytecodeSize, + entrypoint, + (SDL_GPUShaderStage)shaderStage, + (SDL_ShaderCross_ShaderResourceInfo *)resourceInfo); + } + SDL_free(spirv); + return result; } SDL_SetError("SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL: Unexpected SDL_GPUShaderFormat"); @@ -737,19 +824,31 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL( SDL_GPUShader *SDL_ShaderCross_CompileGraphicsShaderFromHLSL( SDL_GPUDevice *device, - const SDL_GPUShaderCreateInfo *createInfo, const char *hlslSource, - SDL_GPUShaderStage graphicsShaderStage) + const char *entrypoint, + SDL_GPUShaderStage graphicsShaderStage, + const SDL_ShaderCross_ShaderResourceInfo *resourceInfo) { - return (SDL_GPUShader *)SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL(device, createInfo, hlslSource, (SDL_ShaderCross_ShaderStage)graphicsShaderStage); + return (SDL_GPUShader *)SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL( + device, + hlslSource, + entrypoint, + (SDL_ShaderCross_ShaderStage)graphicsShaderStage, + (const void *)resourceInfo); } SDL_GPUComputePipeline *SDL_ShaderCross_CompileComputePipelineFromHLSL( SDL_GPUDevice *device, - const SDL_GPUComputePipelineCreateInfo *createInfo, - const char *hlslSource) + const char *hlslSource, + const char *entrypoint, + const SDL_ShaderCross_ComputeResourceInfo *resourceInfo) { - return (SDL_GPUComputePipeline *)SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL(device, createInfo, hlslSource, SDL_SHADERCROSS_SHADERSTAGE_COMPUTE); + return (SDL_GPUComputePipeline *)SDL_ShaderCross_INTERNAL_CreateShaderFromHLSL( + device, + hlslSource, + entrypoint, + SDL_SHADERCROSS_SHADERSTAGE_COMPUTE, + (const void *)resourceInfo); } #endif /* SDL_GPU_SHADERCROSS_HLSL */ @@ -1529,16 +1628,57 @@ static void *SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV( SDL_GPUShader *SDL_ShaderCross_CompileGraphicsShaderFromSPIRV( SDL_GPUDevice *device, - const SDL_GPUShaderCreateInfo *createInfo) + const Uint8 *bytecode, + size_t bytecodeSize, + const char *entrypoint, + SDL_GPUShaderStage shaderStage, + const SDL_ShaderCross_ShaderResourceInfo *resourceInfo) { - return (SDL_GPUShader *)SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(device, createInfo, (SDL_ShaderCross_ShaderStage)createInfo->stage); + SDL_GPUShaderCreateInfo createInfo; + createInfo.code = bytecode; + createInfo.code_size = bytecodeSize; + createInfo.entrypoint = entrypoint; + createInfo.format = SDL_GPU_SHADERFORMAT_SPIRV; + createInfo.stage = shaderStage; + createInfo.num_samplers = resourceInfo->num_samplers; + createInfo.num_storage_textures = resourceInfo->num_storage_textures; + createInfo.num_storage_buffers = resourceInfo->num_storage_buffers; + createInfo.num_uniform_buffers = resourceInfo->num_uniform_buffers; + createInfo.props = 0; + + return (SDL_GPUShader *)SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV( + device, + &createInfo, + (SDL_ShaderCross_ShaderStage)shaderStage); } SDL_GPUComputePipeline *SDL_ShaderCross_CompileComputePipelineFromSPIRV( SDL_GPUDevice *device, - const SDL_GPUComputePipelineCreateInfo *createInfo) + const Uint8 *bytecode, + size_t bytecodeSize, + const char *entrypoint, + const SDL_ShaderCross_ComputeResourceInfo *resourceInfo) { - return (SDL_GPUComputePipeline *)SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV(device, createInfo, SDL_SHADERCROSS_SHADERSTAGE_COMPUTE); + SDL_GPUComputePipelineCreateInfo createInfo; + createInfo.code = bytecode; + createInfo.code_size = bytecodeSize; + createInfo.entrypoint = entrypoint; + createInfo.format = SDL_GPU_SHADERFORMAT_SPIRV; + createInfo.num_samplers = resourceInfo->num_samplers; + createInfo.num_readonly_storage_textures = resourceInfo->num_readonly_storage_textures; + createInfo.num_readonly_storage_buffers = resourceInfo->num_readonly_storage_buffers; + createInfo.num_readwrite_storage_textures = resourceInfo->num_readwrite_storage_textures; + createInfo.num_readwrite_storage_buffers = resourceInfo->num_readwrite_storage_buffers; + createInfo.num_uniform_buffers = resourceInfo->num_uniform_buffers; + createInfo.threadcount_x = resourceInfo->threadcount_x; + createInfo.threadcount_y = resourceInfo->threadcount_y; + createInfo.threadcount_z = resourceInfo->threadcount_z; + createInfo.props = 0; + + return (SDL_GPUComputePipeline *)SDL_ShaderCross_INTERNAL_CreateShaderFromSPIRV( + device, + &createInfo, + SDL_SHADERCROSS_SHADERSTAGE_COMPUTE); } #endif /* SDL_GPU_SHADERCROSS_SPIRVCROSS */