diff --git a/.gitmodules b/.gitmodules index bf4fac3..1da3b2f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Vulkan-Headers"] path = Vulkan-Headers url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "SPIRV-Cross"] + path = SPIRV-Cross + url = https://github.com/KhronosGroup/SPIRV-Cross diff --git a/SPIRV-Cross b/SPIRV-Cross new file mode 160000 index 0000000..d5c3bd8 --- /dev/null +++ b/SPIRV-Cross @@ -0,0 +1 @@ +Subproject commit d5c3bd8b5e7db9e2d7fe809944b47b8f88e1c732 diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index 32c84e3..c3075be 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -31,6 +31,7 @@ #define COBJMACROS #include #include +#include #include "Refresh_Driver.h" #include "Refresh_Driver_D3D11_cdefines.h" @@ -38,6 +39,8 @@ #include #include +#include + /* Defines */ #define D3D11_DLL "d3d11.dll" @@ -78,6 +81,22 @@ ); \ } +/* D3DCompile signature */ + +typedef HRESULT(WINAPI *PFN_D3DCOMPILE)( + LPCVOID pSrcData, + SIZE_T SrcDataSize, + LPCSTR pSourceName, + const D3D_SHADER_MACRO* pDefines, + ID3DInclude* pInclude, + LPCSTR pEntrypoint, + LPCSTR pTarget, + UINT Flags1, + UINT Flags2, + ID3DBlob **ppCode, + ID3DBlob **ppErrorMsgs +); + /* Conversions */ static DXGI_FORMAT RefreshToD3D11_SurfaceFormat[] = @@ -302,6 +321,14 @@ typedef struct D3D11CommandBufferPool uint32_t capacity; } D3D11CommandBufferPool; +typedef struct D3D11ShaderModule +{ + spvc_context context; + size_t numEntryPoints; + const spvc_entry_point *entryPoints; + ID3D11DeviceChild **shaders; /* ID3D11VertexShader, ID3D11PixelShader, ID3D11ComputeShader */ +} D3D11ShaderModule; + typedef struct D3D11Renderer { ID3D11Device *device; @@ -310,6 +337,7 @@ typedef struct D3D11Renderer IDXGIAdapter1* adapter; void *d3d11_dll; void *dxgi_dll; + void *d3dcompiler_dll; SDL_mutex *contextLock; D3D11CommandBufferPool *commandBufferPool; @@ -323,6 +351,8 @@ typedef struct D3D11Renderer uint8_t debugMode; D3D_FEATURE_LEVEL featureLevel; + + PFN_D3DCOMPILE D3DCompileFunc; } D3D11Renderer; /* Predeclarations */ @@ -621,6 +651,7 @@ static void D3D11_DestroyDevice( /* Unload the DLLs */ SDL_UnloadObject(renderer->d3d11_dll); SDL_UnloadObject(renderer->dxgi_dll); + SDL_UnloadObject(renderer->d3dcompiler_dll); /* Free the renderer and Refresh Device */ SDL_free(renderer); @@ -700,10 +731,197 @@ static Refresh_Sampler* D3D11_CreateSampler( } static Refresh_ShaderModule* D3D11_CreateShaderModule( - Refresh_Renderer* driverData, - Refresh_ShaderModuleCreateInfo* shaderModuleCreateInfo + Refresh_Renderer *driverData, + Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo ) { - NOT_IMPLEMENTED + D3D11Renderer *renderer = (D3D11Renderer*) driverData; + spvc_context context; + spvc_result result; + spvc_parsed_ir parsedIR; + spvc_compiler compiler; + const spvc_entry_point *entryPoints; + size_t numEntryPoints; + spvc_compiler_options compilerOptions; + char *hlslSource; + const char *shaderModel; + ID3DBlob *blob; + ID3DBlob *errorBlob = NULL; + ID3D11DeviceChild **shaders; + D3D11ShaderModule *shaderModule; + uint32_t i; + HRESULT res; + + /* Create the context */ + result = spvc_context_create(&context); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not create SPIRV Cross context! Error: %X", result); + return NULL; + } + + /* Parse the SPIRV input */ + result = spvc_context_parse_spirv( + context, + shaderModuleCreateInfo->byteCode, + shaderModuleCreateInfo->codeSize / sizeof(uint32_t), /* word count, not byte length */ + &parsedIR + ); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not parse SPIRV! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Create the cross compiler */ + result = spvc_context_create_compiler( + context, + SPVC_BACKEND_HLSL, + parsedIR, + SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, + &compiler + ); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not create SPIRV to HLSL cross compiler! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Get entry points from the source bytecode */ + result = spvc_compiler_get_entry_points(compiler, &entryPoints, &numEntryPoints); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not get SPIRV entry points! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Set HLSL cross-compile options (target SM5.0) */ + spvc_compiler_create_compiler_options(compiler, &compilerOptions); + spvc_compiler_options_set_uint( + compilerOptions, + SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, + 50 /* shader model 5.0 */ + ); + spvc_compiler_install_compiler_options(compiler, compilerOptions); + + /* Cross compile to HLSL */ + result = spvc_compiler_compile(compiler, &hlslSource); + if (result != SPVC_SUCCESS) + { + Refresh_LogError("Could not cross-compile SPIRV to HLSL! Error: %X", result); + spvc_context_destroy(context); /* free all context-related memory */ + return NULL; + } + + /* Allocate memory for the D3D11 shader list */ + shaders = (ID3D11DeviceChild**) SDL_malloc(numEntryPoints * sizeof(ID3D11DeviceChild*)); + + /* Compile each HLSL entry point into a D3D shader */ + for (i = 0; i < numEntryPoints; i += 1) + { + /* Determine the exact shader model to use */ + switch (entryPoints[i].execution_model) + { + case SpvExecutionModelVertex: + shaderModel = "vs_5_0"; + break; + + case SpvExecutionModelFragment: + shaderModel = "ps_5_0"; + break; + + case SpvExecutionModelGLCompute: + shaderModel = "cs_5_0"; + break; + + default: + Refresh_LogError( + "Attempting to compile a shader with an unknown execution model: %X", + entryPoints[i].execution_model + ); + spvc_context_destroy(context); /* free all context-related memory */ + SDL_free(shaders); + return NULL; + } + + /* Compile the shader blob */ + res = renderer->D3DCompileFunc( + hlslSource, + SDL_strlen(hlslSource), + NULL, + NULL, + NULL, + entryPoints[i].name, + shaderModel, + 0, + 0, + &blob, + &errorBlob + ); + if (FAILED(res)) + { + Refresh_LogError( + "D3DCompile failed on HLSL shader with entry point '%s'! Error: %X\nCompiler error message: %s", + entryPoints[i].name, + res, + errorBlob ? (const char*) ID3D10Blob_GetBufferPointer(errorBlob) : "" + ); + spvc_context_destroy(context); /* free all context-related memory */ + SDL_free(shaders); + return NULL; + } + + /* Create the shader from the blob */ + switch (entryPoints[i].execution_model) + { + case SpvExecutionModelVertex: + res = ID3D11Device_CreateVertexShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11VertexShader**) &shaders[i] + ); + break; + + case SpvExecutionModelFragment: + res = ID3D11Device_CreatePixelShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11PixelShader**) &shaders[i] + ); + break; + + case SpvExecutionModelGLCompute: + res = ID3D11Device_CreateComputeShader( + renderer->device, + ID3D10Blob_GetBufferPointer(blob), + ID3D10Blob_GetBufferSize(blob), + NULL, + (ID3D11ComputeShader**) &shaders[i] + ); + break; + } + if (FAILED(res)) + { + Refresh_LogError("D3D11 shader creation failed! Error code: %X", res); + spvc_context_destroy(context); /* free all context-related memory */ + SDL_free(shaders); + return NULL; + } + } + + /* Create the final shader module object to return */ + shaderModule = (D3D11ShaderModule*) SDL_malloc(sizeof(D3D11ShaderModule)); + shaderModule->context = context; + shaderModule->entryPoints = entryPoints; + shaderModule->numEntryPoints = numEntryPoints; + shaderModule->shaders = shaders; + return (Refresh_ShaderModule*) shaderModule; } static Refresh_Texture* D3D11_CreateTexture( @@ -862,7 +1080,20 @@ static void D3D11_QueueDestroyShaderModule( Refresh_Renderer* driverData, Refresh_ShaderModule* shaderModule ) { - NOT_IMPLEMENTED + D3D11ShaderModule *d3dShaderModule = (D3D11ShaderModule*) shaderModule; + uint32_t i; + + /* Release the D3D11 shader objects and free the array */ + for (i = 0; i < d3dShaderModule->numEntryPoints; i += 1) + { + ID3D11DeviceChild_Release(d3dShaderModule->shaders[i]); + } + SDL_free(d3dShaderModule->shaders); + + /* Destroy the SPIRV-Cross context. + * This should destroy the entryPoints list as well. + */ + spvc_context_destroy(d3dShaderModule->context); } static void D3D11_QueueDestroyComputePipeline( @@ -1291,6 +1522,25 @@ static Refresh_Device* D3D11_CreateDevice( renderer = (D3D11Renderer*) SDL_malloc(sizeof(D3D11Renderer)); SDL_memset(renderer, 0, sizeof(D3D11Renderer)); + /* Load the D3DCompiler library */ + renderer->d3dcompiler_dll = SDL_LoadObject(D3DCOMPILER_DLL); + if (renderer->d3dcompiler_dll == NULL) + { + Refresh_LogError("Could not find " D3DCOMPILER_DLL); + return NULL; + } + + /* Load the D3DCompile function pointer */ + renderer->D3DCompileFunc = (PFN_D3DCOMPILE) SDL_LoadFunction( + renderer->d3dcompiler_dll, + "D3DCompile" + ); + if (renderer->D3DCompileFunc == NULL) + { + Refresh_LogError("Could not load D3DCompile function!"); + return NULL; + } + /* Load the DXGI library */ renderer->dxgi_dll = SDL_LoadObject(DXGI_DLL); if (renderer->dxgi_dll == NULL) diff --git a/visualc/Refresh.sln b/visualc/Refresh.sln index e69634a..b65b0a0 100644 --- a/visualc/Refresh.sln +++ b/visualc/Refresh.sln @@ -5,22 +5,50 @@ VisualStudioVersion = 16.0.30717.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Refresh", "Refresh.vcxproj", "{6DB15344-E000-45CB-A48A-1D72F7D6E945}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRV-Cross", "SPIRV-Cross\SPIRV-Cross.vcxproj", "{C9462931-41A4-4E61-B145-F2D2CDE43C69}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 MinSizeRel|x64 = MinSizeRel|x64 + MinSizeRel|x86 = MinSizeRel|x86 Release|x64 = Release|x64 + Release|x86 = Release|x86 RelWithDebInfo|x64 = RelWithDebInfo|x64 + RelWithDebInfo|x86 = RelWithDebInfo|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x64.ActiveCfg = Debug|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x64.Build.0 = Debug|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x86.ActiveCfg = Debug|Win32 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x86.Build.0 = Debug|Win32 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x64.ActiveCfg = Release|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x64.Build.0 = Release|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x86.ActiveCfg = Release|Win32 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x86.Build.0 = Release|Win32 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x64.ActiveCfg = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x64.Build.0 = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x86.ActiveCfg = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Debug|x86.Build.0 = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x64.ActiveCfg = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x64.Build.0 = Debug|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x86.ActiveCfg = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.MinSizeRel|x86.Build.0 = Debug|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x64.ActiveCfg = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x64.Build.0 = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x86.ActiveCfg = Release|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.Release|x86.Build.0 = Release|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x64.Build.0 = Release|x64 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 + {C9462931-41A4-4E61-B145-F2D2CDE43C69}.RelWithDebInfo|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/visualc/Refresh.vcxproj b/visualc/Refresh.vcxproj index 33b52ee..dd0053c 100644 --- a/visualc/Refresh.vcxproj +++ b/visualc/Refresh.vcxproj @@ -62,6 +62,7 @@ Level3 Disabled REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) + ..\SPIRV-Cross;%(AdditionalIncludeDirectories) DebugFull @@ -75,6 +76,7 @@ REFRESH_DRIVER_D3D11;REFRESH_DRIVER_VULKAN;%(PreprocessorDefinitions) true true + ..\SPIRV-Cross;%(AdditionalIncludeDirectories) true @@ -95,6 +97,11 @@ + + + {c9462931-41a4-4e61-b145-f2d2cde43c69} + + diff --git a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj new file mode 100644 index 0000000..8fd6f23 --- /dev/null +++ b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + 16.0 + Win32Proj + {c9462931-41a4-4e61-b145-f2d2cde43c69} + SPIRVCross + 10.0 + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + true + true + + + + + Level3 + true + _DEBUG;_LIB;%(PreprocessorDefinitions);SPIRV_CROSS_C_API_HLSL=1;SPIRV_CROSS_C_API_GLSL=1;SPIRV_CROSS_C_API_REFLECT=1 + true + + + + + true + + + + + Level3 + true + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions);SPIRV_CROSS_C_API_HLSL=1;SPIRV_CROSS_C_API_REFLECT=1 + true + Use + pch.h + + + + + true + true + true + + + + + + \ No newline at end of file diff --git a/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters new file mode 100644 index 0000000..95cf63a --- /dev/null +++ b/visualc/SPIRV-Cross/SPIRV-Cross.vcxproj.filters @@ -0,0 +1,43 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file