From 7274173b440a7065ed53ff3af7494f93f32455bc Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Sun, 11 Feb 2024 00:07:01 -0600 Subject: [PATCH] Add shader type to the .refresh shader bytecode format --- shadercompiler/Program.cs | 11 ++ src/Refresh.c | 22 +++- src/Refresh_Driver.h | 18 ++- src/Refresh_Driver_D3D11.c | 209 ++++++++++++++------------------ src/Refresh_Driver_Template.txt | 2 +- src/Refresh_Driver_Vulkan.c | 2 +- 6 files changed, 134 insertions(+), 130 deletions(-) diff --git a/shadercompiler/Program.cs b/shadercompiler/Program.cs index a76a1de..7e3f10d 100644 --- a/shadercompiler/Program.cs +++ b/shadercompiler/Program.cs @@ -194,6 +194,17 @@ partial class Program // Magic writer.Write(new char[] { 'R', 'F', 'S', 'H'}); + // Type + uint shaderTypeIndex; + switch (shaderType) + { + default: + case ".vert": shaderTypeIndex = 0; break; + case ".frag": shaderTypeIndex = 1; break; + case ".comp": shaderTypeIndex = 2; break; + } + writer.Write(shaderTypeIndex); + if (data.vulkan) { string inputPath = Path.Combine(tempDir, $"{shaderName}.spv"); diff --git a/src/Refresh.c b/src/Refresh.c index 5bffa44..c3b0fbe 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -242,7 +242,7 @@ Refresh_ShaderModule* Refresh_CreateShaderModule( Refresh_Device *device, Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo ) { - Refresh_ShaderModuleCreateInfo driverSpecificCreateInfo = { 0, NULL }; + Refresh_Driver_ShaderModuleCreateInfo driverSpecificCreateInfo = { 0, NULL, 0 }; uint8_t *bytes; uint32_t i, size; @@ -252,12 +252,24 @@ Refresh_ShaderModule* Refresh_CreateShaderModule( bytes = (uint8_t*) shaderModuleCreateInfo->byteCode; if (bytes[0] != 'R' || bytes[1] != 'F' || bytes[2] != 'S' || bytes[3] != 'H') { - Refresh_LogError("Cannot parse malformed Refresh shader blob!"); + Refresh_LogError("Cannot parse malformed Refresh shader blob: Incorrect magic number"); + return NULL; + } + + /* get the type of shader */ + driverSpecificCreateInfo.type = (Refresh_Driver_ShaderType) *((uint32_t*) &bytes[4]); + if ( driverSpecificCreateInfo.type < 0 || + driverSpecificCreateInfo.type > REFRESH_DRIVER_SHADERTYPE_COMPUTE ) + { + Refresh_LogError( + "Cannot parse malformed Refresh shader blob: Unknown shader type (%d)", + driverSpecificCreateInfo.type + ); return NULL; } /* find the code for the selected backend */ - i = 4; + i = 8; while (i < shaderModuleCreateInfo->codeSize) { size = *((uint32_t*) &bytes[i + 1]); @@ -1074,9 +1086,7 @@ int Refresh_QueryFence( Refresh_Device *device, Refresh_Fence *fence ) { - if (device == NULL) { - return 0; - } + if (device == NULL) { return 0; } return device->QueryFence( device->driverData, diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 5e06f2e..f1cf090 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -211,6 +211,22 @@ static inline int32_t BytesPerImage( #define MAX_COLOR_TARGET_BINDINGS 4 #define MAX_PRESENT_COUNT 16 +/* Internal Shader Module Create Info */ + +typedef enum Refresh_Driver_ShaderType +{ + REFRESH_DRIVER_SHADERTYPE_VERTEX, + REFRESH_DRIVER_SHADERTYPE_FRAGMENT, + REFRESH_DRIVER_SHADERTYPE_COMPUTE +} Refresh_Driver_ShaderType; + +typedef struct Refresh_Driver_ShaderModuleCreateInfo +{ + size_t codeSize; + const uint32_t* byteCode; + Refresh_Driver_ShaderType type; +} Refresh_Driver_ShaderModuleCreateInfo; + /* Refresh_Device Definition */ typedef struct Refresh_Renderer Refresh_Renderer; @@ -240,7 +256,7 @@ struct Refresh_Device Refresh_ShaderModule* (*CreateShaderModule)( Refresh_Renderer *driverData, - Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo + Refresh_Driver_ShaderModuleCreateInfo *shaderModuleCreateInfo ); Refresh_Texture* (*CreateTexture)( diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 95ff71b..746d4a2 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -397,8 +397,6 @@ typedef struct D3D11ShaderModule { ID3D11DeviceChild *shader; /* ID3D11VertexShader, ID3D11PixelShader, ID3D11ComputeShader */ ID3D10Blob *blob; - char *shaderSource; - size_t shaderSourceLength; } D3D11ShaderModule; typedef struct D3D11GraphicsPipeline @@ -1183,44 +1181,8 @@ static Refresh_ComputePipeline* D3D11_CreateComputePipeline( ) { D3D11Renderer *renderer = (D3D11Renderer*) driverData; D3D11ShaderModule *shaderModule = (D3D11ShaderModule*) computeShaderInfo->shaderModule; - ID3D10Blob *errorBlob; - D3D11ComputePipeline *pipeline; - HRESULT res; - /* First, compile the shader since we didn't do that when creating the shader module */ - if (shaderModule->shader == NULL) - { - res = renderer->D3DCompileFunc( - shaderModule->shaderSource, - shaderModule->shaderSourceLength, - NULL, - NULL, - NULL, - "main", - "cs_5_0", - 0, - 0, - &shaderModule->blob, - &errorBlob - ); - if (FAILED(res)) - { - Refresh_LogError("Compute Shader Compile Error: %s", ID3D10Blob_GetBufferPointer(errorBlob)); - return NULL; - } - - res = ID3D11Device_CreateComputeShader( - renderer->device, - ID3D10Blob_GetBufferPointer(shaderModule->blob), - ID3D10Blob_GetBufferSize(shaderModule->blob), - NULL, - (ID3D11ComputeShader**) &shaderModule->shader - ); - ERROR_CHECK_RETURN("Could not create compute shader", NULL); - } - - /* Allocate and set up the pipeline */ - pipeline = SDL_malloc(sizeof(D3D11ComputePipeline)); + D3D11ComputePipeline *pipeline = SDL_malloc(sizeof(D3D11ComputePipeline)); pipeline->numTextures = computeShaderInfo->imageBindingCount; pipeline->numBuffers = computeShaderInfo->bufferBindingCount; pipeline->computeShader = (ID3D11ComputeShader*) shaderModule->shader; @@ -1239,75 +1201,8 @@ static Refresh_GraphicsPipeline* D3D11_CreateGraphicsPipeline( D3D11Renderer *renderer = (D3D11Renderer*) driverData; D3D11ShaderModule *vertShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->vertexShaderInfo.shaderModule; D3D11ShaderModule *fragShaderModule = (D3D11ShaderModule*) pipelineCreateInfo->fragmentShaderInfo.shaderModule; - ID3D10Blob *errorBlob; - D3D11GraphicsPipeline *pipeline; - HRESULT res; - /* First, compile the shaders since we didn't do that when creating the shader modules */ - if (vertShaderModule->shader == NULL) - { - res = renderer->D3DCompileFunc( - vertShaderModule->shaderSource, - vertShaderModule->shaderSourceLength, - NULL, - NULL, - NULL, - "main", - "vs_5_0", - 0, - 0, - &vertShaderModule->blob, - &errorBlob - ); - if (FAILED(res)) - { - Refresh_LogError("Vertex Shader Compile Error: %s", ID3D10Blob_GetBufferPointer(errorBlob)); - return NULL; - } - - res = ID3D11Device_CreateVertexShader( - renderer->device, - ID3D10Blob_GetBufferPointer(vertShaderModule->blob), - ID3D10Blob_GetBufferSize(vertShaderModule->blob), - NULL, - (ID3D11VertexShader**) &vertShaderModule->shader - ); - ERROR_CHECK_RETURN("Could not create vertex shader", NULL); - } - - if (fragShaderModule->shader == NULL) - { - res = renderer->D3DCompileFunc( - fragShaderModule->shaderSource, - fragShaderModule->shaderSourceLength, - NULL, - NULL, - NULL, - "main", - "ps_5_0", - 0, - 0, - &fragShaderModule->blob, - &errorBlob - ); - if (FAILED(res)) - { - Refresh_LogError("Fragment Shader Compile Error: %s", ID3D10Blob_GetBufferPointer(errorBlob)); - return NULL; - } - - res = ID3D11Device_CreatePixelShader( - renderer->device, - ID3D10Blob_GetBufferPointer(fragShaderModule->blob), - ID3D10Blob_GetBufferSize(fragShaderModule->blob), - NULL, - (ID3D11PixelShader**) &fragShaderModule->shader - ); - ERROR_CHECK_RETURN("Could not create pixel shader", NULL); - } - - /* Allocate and set up the pipeline */ - pipeline = SDL_malloc(sizeof(D3D11GraphicsPipeline)); + D3D11GraphicsPipeline *pipeline = SDL_malloc(sizeof(D3D11GraphicsPipeline)); /* Blend */ @@ -1454,23 +1349,96 @@ static Refresh_Sampler* D3D11_CreateSampler( static Refresh_ShaderModule* D3D11_CreateShaderModule( Refresh_Renderer *driverData, - Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo + Refresh_Driver_ShaderModuleCreateInfo *shaderModuleCreateInfo ) { D3D11Renderer *renderer = (D3D11Renderer*) driverData; - D3D11ShaderModule *shaderModule = (D3D11ShaderModule*) SDL_malloc(sizeof(D3D11ShaderModule)); + D3D11ShaderModule* shaderModule; + Refresh_Driver_ShaderType shaderType = shaderModuleCreateInfo->type; + const char *profileNames[] = { "vs_5_0", "ps_5_0", "cs_5_0" }; + ID3D10Blob *blob, *errorBlob; + ID3D11DeviceChild *shader = NULL; + HRESULT res; - /* We don't know whether this is a vertex, fragment, or compute shader, - * so wait to compile until we bind to a pipeline... - * - * FIXME: Could we store a flag in the shaderc output to mark if a shader is vertex/fragment/compute? - * Then we could compile on shader module creation instead of at bind time. - */ - shaderModule->shader = NULL; - shaderModule->blob = NULL; + /* Compile HLSL to DXBC */ + res = renderer->D3DCompileFunc( + shaderModuleCreateInfo->byteCode, + shaderModuleCreateInfo->codeSize, + NULL, + NULL, + NULL, + "main", /* API FIXME: Intentionally ignoring entryPointName because it MUST be "main" anyway */ + profileNames[shaderType], + 0, + 0, + &blob, + &errorBlob + ); + if (FAILED(res)) + { + Refresh_LogError( + "D3DCompile Error (%s): %s", + profileNames[shaderType], + ID3D10Blob_GetBufferPointer(errorBlob) + ); + ID3D10Blob_Release(errorBlob); + return NULL; + } - shaderModule->shaderSourceLength = shaderModuleCreateInfo->codeSize; - shaderModule->shaderSource = (char*) SDL_malloc(shaderModule->shaderSourceLength); - SDL_memcpy(shaderModule->shaderSource, shaderModuleCreateInfo->byteCode, shaderModuleCreateInfo->codeSize); + /* Actually create the shader */ + if (shaderType == REFRESH_DRIVER_SHADERTYPE_VERTEX) + { + res = ID3D11Device_CreateVertexShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11VertexShader**) &shader + ); + if (FAILED(res)) + { + D3D11_INTERNAL_LogError(renderer->device, "Could not compile vertex shader", res); + ID3D10Blob_Release(blob); + return NULL; + } + } + else if (shaderType == REFRESH_DRIVER_SHADERTYPE_FRAGMENT) + { + res = ID3D11Device_CreatePixelShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11PixelShader**) &shader + ); + if (FAILED(res)) + { + D3D11_INTERNAL_LogError(renderer->device, "Could not compile pixel shader", res); + ID3D10Blob_Release(blob); + return NULL; + } + } + else if (shaderType == REFRESH_DRIVER_SHADERTYPE_COMPUTE) + { + res = ID3D11Device_CreateComputeShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11ComputeShader**) &shader + ); + if (FAILED(res)) + { + D3D11_INTERNAL_LogError(renderer->device, "Could not compile compute shader", res); + ID3D10Blob_Release(blob); + return NULL; + } + } + + + /* Allocate and set up the shader module */ + shaderModule = (D3D11ShaderModule*) SDL_malloc(sizeof(D3D11ShaderModule)); + shaderModule->shader = shader; + shaderModule->blob = blob; return (Refresh_ShaderModule*) shaderModule; } @@ -2440,7 +2408,6 @@ static void D3D11_QueueDestroyShaderModule( ID3D10Blob_Release(d3dShaderModule->blob); } - SDL_free(d3dShaderModule->shaderSource); SDL_free(d3dShaderModule); } diff --git a/src/Refresh_Driver_Template.txt b/src/Refresh_Driver_Template.txt index a56ffb1..8052dfb 100644 --- a/src/Refresh_Driver_Template.txt +++ b/src/Refresh_Driver_Template.txt @@ -318,7 +318,7 @@ static Refresh_Sampler* TEMPLATE_CreateSampler( static Refresh_ShaderModule* TEMPLATE_CreateShaderModule( Refresh_Renderer *driverData, - Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo + Refresh_Driver_ShaderModuleCreateInfo *shaderModuleCreateInfo ) { NOT_IMPLEMENTED } diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index c4a34e5..890644a 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -6670,7 +6670,7 @@ static Refresh_Sampler* VULKAN_CreateSampler( static Refresh_ShaderModule* VULKAN_CreateShaderModule( Refresh_Renderer *driverData, - Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo + Refresh_Driver_ShaderModuleCreateInfo *shaderModuleCreateInfo ) { VulkanShaderModule *vulkanShaderModule = SDL_malloc(sizeof(VulkanShaderModule)); VkResult vulkanResult;