From 79884bdf3d4017534860423b753f1f6cac12206e Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 9 Nov 2023 01:43:52 +1300 Subject: [PATCH] Move shader hlsl management into Shader.cpp - g_ShaderHlsl keeps track of hlsl - VS and PS source their hlsl from g_ShaderHlsl --- .../Direct3D9/CxbxPixelShaderTemplate.hlsl | 23 +-- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 5 +- src/core/hle/D3D8/Direct3D9/PixelShader.cpp | 13 +- src/core/hle/D3D8/Direct3D9/Shader.cpp | 164 ++++++++++++++++++ src/core/hle/D3D8/Direct3D9/Shader.h | 35 ++++ src/core/hle/D3D8/Direct3D9/VertexShader.cpp | 71 +------- src/core/hle/D3D8/Direct3D9/VertexShader.h | 2 - src/core/hle/D3D8/XbPixelShader.cpp | 27 +-- src/core/hle/D3D8/XbVertexShader.cpp | 72 +------- 9 files changed, 226 insertions(+), 186 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl b/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl index d80c6f98d..f4ef3864e 100644 --- a/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl +++ b/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl @@ -1,6 +1,3 @@ -// This starts the raw string (comment to get syntax highlighting, UNCOMMENT to compile) : -R"DELIMITER( - struct PS_INPUT // Declared identical to vertex shader output (see VS_OUTPUT) { float2 iPos : VPOS; // Screen space x,y pixel location @@ -92,10 +89,9 @@ uniform const float FRONTFACE_FACTOR : register(c27); // Note : PSH_XBOX_CONSTA #define PS_FINALCOMBINERSETTING_CLAMP_SUM #endif -)DELIMITER", /* This terminates the 1st raw string within the 16380 single-byte characters limit. // */ -// See https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?f1url=%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(C2026)%26rd%3Dtrue&view=vs-2019 -// Second raw string : -R"DELIMITER( + // Hardcoded state will be inserted here + // + // End hardcoded state // PS_COMBINERCOUNT_UNIQUE_C0 steers whether for C0 to use combiner stage-specific constants c0_0 .. c0_7, or c0_0 for all stages #ifdef PS_COMBINERCOUNT_UNIQUE_C0 @@ -173,10 +169,6 @@ R"DELIMITER( // HLSL : https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-lerp // lerp(x, y, s ) x*(1-s ) + y*s == x + s(y-x) // lerp(s2, s1, s0) s2*(1-s0) + s1*s0 -)DELIMITER", /* This terminates the 1st raw string within the 16380 single-byte characters limit. // */ -// See https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?f1url=%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(C2026)%26rd%3Dtrue&view=vs-2019 -// Second raw string : -R"DELIMITER( float m21d(const float input) { @@ -379,10 +371,9 @@ PS_OUTPUT main(const PS_INPUT xIn) v1 = isFrontFace ? xIn.iD1 : xIn.iB1; // Specular front/back fog = float4(c_fog.rgb, xIn.iFog); // color from PSH_XBOX_CONSTANT_FOG, alpha from vertex shader output / pixel shader input - // Xbox shader program -)DELIMITER", /* This terminates the 2nd raw string within the 16380 single-byte characters limit. // */ -// Third and last raw string, the footer : -R"DELIMITER( + // Xbox shader program will be inserted here + // + // End Xbox shader program // Copy r0.rgba to output PS_OUTPUT xOut; @@ -391,5 +382,3 @@ R"DELIMITER( return xOut; } - -// End of pixel shader footer)DELIMITER" /* This terminates the footer raw string" // */ diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 97a4d67fa..5762049df 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -42,6 +42,7 @@ #include "..\FixedFunctionState.h" #include "core\hle\D3D8\ResourceTracker.h" #include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For LPDIRECTDRAWSURFACE7 +#include "core\hle\D3D8\Direct3D9\Shader.h" // For InitShaderHotloading #include "core\hle\D3D8\XbVertexBuffer.h" #include "core\hle\D3D8\XbVertexShader.h" #include "core\hle\D3D8\XbPixelShader.h" // For DxbxUpdateActivePixelShader @@ -683,8 +684,8 @@ void CxbxInitWindow(bool bFullInit) ImGui_ImplWin32_Shutdown(); }); - extern void InitShaderHotloading(); - InitShaderHotloading(); + g_ShaderHlsl.UpdateShaders(); + g_ShaderHlsl.InitShaderHotloading(); } diff --git a/src/core/hle/D3D8/Direct3D9/PixelShader.cpp b/src/core/hle/D3D8/Direct3D9/PixelShader.cpp index 384780a70..02028708f 100644 --- a/src/core/hle/D3D8/Direct3D9/PixelShader.cpp +++ b/src/core/hle/D3D8/Direct3D9/PixelShader.cpp @@ -289,12 +289,7 @@ bool IsTextureSampled(DecodedRegisterCombiner* pShader, int reg) void BuildShader(DecodedRegisterCombiner* pShader, std::stringstream& hlsl) { - // Include HLSL header and footer as raw strings : - static const std::string hlsl_template[4] = { - #include "core\hle\D3D8\Direct3D9\CxbxPixelShaderTemplate.hlsl" - }; - - hlsl << hlsl_template[0]; // Start with the HLSL template header + hlsl << g_ShaderHlsl.pixelShaderTemplateHlsl[0]; // Start with the HLSL template header hlsl << "\n#define ALPHAKILL {" << (pShader->AlphaKill[0] ? "true, " : "false, ") @@ -341,9 +336,9 @@ void BuildShader(DecodedRegisterCombiner* pShader, std::stringstream& hlsl) OutputDefineFlag(hlsl, pShader->FinalCombiner.ComplementV1, "PS_FINALCOMBINERSETTING_COMPLEMENT_V1"); OutputDefineFlag(hlsl, pShader->FinalCombiner.ComplementR0, "PS_FINALCOMBINERSETTING_COMPLEMENT_R0"); OutputDefineFlag(hlsl, pShader->FinalCombiner.ClampSum, "PS_FINALCOMBINERSETTING_CLAMP_SUM"); + hlsl << '\n'; - hlsl << hlsl_template[1]; - hlsl << hlsl_template[2]; + hlsl << g_ShaderHlsl.pixelShaderTemplateHlsl[1]; // Generate all four texture stages for (unsigned i = 0; i < PSH_XBOX_MAX_T_REGISTER_COUNT; i++) { @@ -390,7 +385,7 @@ void BuildShader(DecodedRegisterCombiner* pShader, std::stringstream& hlsl) FinalCombinerStageHlsl(hlsl, pShader->FinalCombiner, pShader->hasFinalCombiner); - hlsl << hlsl_template[3]; // Finish with the HLSL template footer + hlsl << g_ShaderHlsl.pixelShaderTemplateHlsl[2]; // Finish with the HLSL template footer } // recompile xbox pixel shader function diff --git a/src/core/hle/D3D8/Direct3D9/Shader.cpp b/src/core/hle/D3D8/Direct3D9/Shader.cpp index 382fc0aab..0eb331c14 100644 --- a/src/core/hle/D3D8/Direct3D9/Shader.cpp +++ b/src/core/hle/D3D8/Direct3D9/Shader.cpp @@ -29,10 +29,18 @@ #include #include "Shader.h" +#include "common/FilePaths.hpp" // For szFilePath_CxbxReloaded_Exe #include "core\kernel\init\CxbxKrnl.h" // LOG_TEST_CASE #include "core\kernel\support\Emu.h" // EmuLog + +#include +#include +#include +#include //#include +ShaderHlsl g_ShaderHlsl; + std::string DebugPrependLineNumbers(std::string shaderString) { std::stringstream shader(shaderString); auto debugShader = std::stringstream(); @@ -140,3 +148,159 @@ extern HRESULT EmuCompileShader return hRet; } + +std::ifstream OpenWithRetry(const std::string& path) { + auto fstream = std::ifstream(path); + int failures = 0; + while (fstream.fail()) { + Sleep(50); + fstream = std::ifstream(path); + + if (failures++ > 10) { + // crash? + CxbxrAbort("Error opening shader file: %s", path); + break; + } + } + + return fstream; +} + +int ShaderHlsl::UpdateShaders() { + int versionOnDisk = shaderVersionOnDisk; + if (shaderVersionLoadedFromDisk != versionOnDisk) { + LoadShadersFromDisk(); + shaderVersionLoadedFromDisk = versionOnDisk; + } + + return shaderVersionLoadedFromDisk; +} + +void ShaderHlsl::LoadShadersFromDisk() { + const auto hlslDir = std::filesystem::path(szFilePath_CxbxReloaded_Exe) + .parent_path() + .append("hlsl"); + + // Pixel Shader Template + { + std::stringstream tmp; + auto dir = hlslDir; + dir.append("CxbxPixelShaderTemplate.hlsl"); + tmp << OpenWithRetry(dir.string()).rdbuf(); + std::string hlsl = tmp.str(); + + // Split the HLSL file on insertion points + std::array insertionPoints = { + "// \n", + "// \n", + }; + int pos = 0; + for (int i = 0; i < insertionPoints.size(); i++) { + auto insertionPoint = insertionPoints[i]; + auto index = hlsl.find(insertionPoint, pos); + + this->pixelShaderTemplateHlsl[i] = hlsl.substr(pos, index - pos); + pos = index + insertionPoint.length(); + } + this->pixelShaderTemplateHlsl[insertionPoints.size()] = hlsl.substr(pos); + } + + // Fixed Function Pixel Shader + { + auto dir = hlslDir; + this->fixedFunctionPixelShaderPath = dir.append("FixedFunctionPixelShader.hlsl").string(); + std::stringstream tmp; + tmp << OpenWithRetry(this->fixedFunctionPixelShaderPath).rdbuf(); + this->fixedFunctionPixelShaderHlsl = tmp.str(); + } + + // Vertex Shader Template + { + std::stringstream tmp; + auto dir = hlslDir; + dir.append("CxbxVertexShaderTemplate.hlsl"); + tmp << OpenWithRetry(dir.string()).rdbuf(); + std::string hlsl = tmp.str(); + + const std::string insertionPoint = "// \n"; + auto index = hlsl.find(insertionPoint); + this->vertexShaderTemplateHlsl[0] = hlsl.substr(0, index); + this->vertexShaderTemplateHlsl[1] = hlsl.substr(index + insertionPoint.length()); + } + + // Fixed Function Vertex Shader + { + auto dir = hlslDir; + this->fixedFunctionVertexShaderPath = dir.append("FixedFunctionVertexShader.hlsl").string(); + std::stringstream tmp; + tmp << OpenWithRetry(this->fixedFunctionVertexShaderPath).rdbuf(); + this->fixedFunctionVertexShaderHlsl = tmp.str(); + } + + // Passthrough Vertex Shader + { + auto dir = hlslDir; + this->vertexShaderPassthroughPath = dir.append("CxbxVertexShaderPassthrough.hlsl").string(); + std::stringstream tmp; + tmp << OpenWithRetry(this->vertexShaderPassthroughPath).rdbuf(); + this->vertexShaderPassthroughHlsl = tmp.str(); + } +} + +void ShaderHlsl::InitShaderHotloading() { + static std::thread fsWatcherThread; + + if (fsWatcherThread.joinable()) { + EmuLog(LOG_LEVEL::ERROR2, "Ignoring request to start shader file watcher - it has already been started."); + return; + } + + EmuLog(LOG_LEVEL::DEBUG, "Starting shader file watcher..."); + + fsWatcherThread = std::thread([]{ + // Determine the filename and directory for the fixed function shader + char cxbxExePath[MAX_PATH]; + GetModuleFileName(GetModuleHandle(nullptr), cxbxExePath, MAX_PATH); + auto hlslDir = std::filesystem::path(cxbxExePath) + .parent_path() + .append("hlsl/"); + + HANDLE changeHandle = FindFirstChangeNotification(hlslDir.string().c_str(), false, FILE_NOTIFY_CHANGE_LAST_WRITE); + + if (changeHandle == INVALID_HANDLE_VALUE) { + DWORD errorCode = GetLastError(); + EmuLog(LOG_LEVEL::ERROR2, "Error initializing shader file watcher: %d", errorCode); + + return 1; + } + + while (true) { + if (FindNextChangeNotification(changeHandle)) { + WaitForSingleObject(changeHandle, INFINITE); + + // Wait for changes to stop.. + // Will usually be at least two - one for the file and one for the directory + while (true) { + FindNextChangeNotification(changeHandle); + if (WaitForSingleObject(changeHandle, 100) == WAIT_TIMEOUT) { + break; + } + } + + EmuLog(LOG_LEVEL::DEBUG, "Change detected in shader folder"); + g_ShaderHlsl.shaderVersionOnDisk += 1; + } + else { + EmuLog(LOG_LEVEL::ERROR2, "Shader filewatcher failed to get the next notification"); + break; + } + } + + EmuLog(LOG_LEVEL::DEBUG, "Shader file watcher exiting..."); + + // until there is a way to disable hotloading + // this is always an error + FindCloseChangeNotification(changeHandle); + return 1; + }); +} diff --git a/src/core/hle/D3D8/Direct3D9/Shader.h b/src/core/hle/D3D8/Direct3D9/Shader.h index 1a89d14a5..e617d8f53 100644 --- a/src/core/hle/D3D8/Direct3D9/Shader.h +++ b/src/core/hle/D3D8/Direct3D9/Shader.h @@ -10,3 +10,38 @@ extern HRESULT EmuCompileShader ID3DBlob** ppHostShader, const char* pSourceName = nullptr ); + +struct ShaderHlsl { + // Pixel Shader + std::string pixelShaderTemplateHlsl[3]; + + std::string fixedFunctionPixelShaderHlsl; + std::string fixedFunctionPixelShaderPath; + + // Vertex Shader + std::string vertexShaderTemplateHlsl[2]; + + std::string fixedFunctionVertexShaderHlsl; + std::string fixedFunctionVertexShaderPath; + + std::string vertexShaderPassthroughHlsl; + std::string vertexShaderPassthroughPath; + + // Load shaders from disk (if out-of-date) + // and return the current loaded shader version + int UpdateShaders(); + + // Start a thread to watch for changes in the shader folder + void InitShaderHotloading(); + +private: + void LoadShadersFromDisk(); + + // counts upwards on every change detected to the shader source files at runtime + volatile int shaderVersionOnDisk = 0; + // current loaded shader version + // Initialized to < shaderVersionOnDisk + int shaderVersionLoadedFromDisk = -1; +}; + +extern ShaderHlsl g_ShaderHlsl; diff --git a/src/core/hle/D3D8/Direct3D9/VertexShader.cpp b/src/core/hle/D3D8/Direct3D9/VertexShader.cpp index e2571541b..88275f365 100644 --- a/src/core/hle/D3D8/Direct3D9/VertexShader.cpp +++ b/src/core/hle/D3D8/Direct3D9/VertexShader.cpp @@ -4,9 +4,7 @@ #include "VertexShader.h" // EmuCompileVertexShader #include "core\kernel\init\CxbxKrnl.h" // implicit CxbxKrnl_Xbe used in LOG_TEST_CASE #include "core\kernel\support\Emu.h" // LOG_TEST_CASE (via Logging.h) -#include "common/FilePaths.hpp" // For szFilePath_CxbxReloaded_Exe -#include #include // std::stringstream extern const char* g_vs_model = vs_model_3_0; @@ -283,67 +281,6 @@ void BuildShader(IntermediateVertexShader* pShader, std::stringstream& hlsl) } } -std::string vertexShaderTemplateHlsl[2]; -std::string fixedFunctionVertexShaderHlsl; -std::string fixedFunctionVertexShaderPath; -std::string vertexShaderPassthroughHlsl; -std::string vertexShaderPassthroughPath; - -std::ifstream OpenWithRetry(const std::string& path) { - auto fstream = std::ifstream(path); - int failures = 0; - while (fstream.fail()) { - Sleep(50); - fstream = std::ifstream(path); - - if (failures++ > 10) { - // crash? - CxbxrAbort("Error opening shader file: %s", path); - break; - } - } - - return fstream; -} - -void LoadShadersFromDisk() { - const auto hlslDir = std::filesystem::path(szFilePath_CxbxReloaded_Exe) - .parent_path() - .append("hlsl"); - - // Vertex Shader Template - { - std::stringstream tmp; - auto dir = hlslDir; - dir.append("CxbxVertexShaderTemplate.hlsl"); - tmp << OpenWithRetry(dir.string()).rdbuf(); - std::string hlsl = tmp.str(); - - const std::string insertionPoint = "// \n"; - auto index = hlsl.find(insertionPoint); - vertexShaderTemplateHlsl[0] = hlsl.substr(0, index); - vertexShaderTemplateHlsl[1] = hlsl.substr(index + insertionPoint.length()); - } - - // Fixed Function Vertex Shader - { - auto dir = hlslDir; - fixedFunctionVertexShaderPath = dir.append("FixedFunctionVertexShader.hlsl").string(); - std::stringstream tmp; - tmp << OpenWithRetry(fixedFunctionVertexShaderPath).rdbuf(); - fixedFunctionVertexShaderHlsl = tmp.str(); - } - - // Passthrough Vertex Shader - { - auto dir = hlslDir; - vertexShaderPassthroughPath = dir.append("CxbxVertexShaderPassthrough.hlsl").string(); - std::stringstream tmp; - tmp << OpenWithRetry(vertexShaderPassthroughPath).rdbuf(); - vertexShaderPassthroughHlsl = tmp.str(); - } -} - // recompile xbox vertex shader function extern HRESULT EmuCompileVertexShader ( @@ -355,9 +292,9 @@ extern HRESULT EmuCompileVertexShader // Combine the shader template with the shader program auto hlsl_stream = std::stringstream(); - hlsl_stream << vertexShaderTemplateHlsl[0]; // Start with the HLSL template header + hlsl_stream << g_ShaderHlsl.vertexShaderTemplateHlsl[0]; // Start with the HLSL template header BuildShader(pIntermediateShader, hlsl_stream); - hlsl_stream << vertexShaderTemplateHlsl[1]; // Finish with the HLSL template footer + hlsl_stream << g_ShaderHlsl.vertexShaderTemplateHlsl[1]; // Finish with the HLSL template footer std::string hlsl_str = hlsl_stream.str(); auto notionalSourceName = "CxbxVertexShaderTemplate.hlsl"; @@ -375,10 +312,10 @@ extern HRESULT EmuCompileVertexShader extern void EmuCompileFixedFunction(ID3DBlob** ppHostShader) { - EmuCompileShader(fixedFunctionVertexShaderHlsl, g_vs_model, ppHostShader, fixedFunctionVertexShaderPath.c_str()); + EmuCompileShader(g_ShaderHlsl.fixedFunctionVertexShaderHlsl, g_vs_model, ppHostShader, g_ShaderHlsl.fixedFunctionVertexShaderPath.c_str()); }; extern void EmuCompileXboxPassthrough(ID3DBlob** ppHostShader) { - EmuCompileShader(vertexShaderPassthroughHlsl, g_vs_model, ppHostShader, vertexShaderPassthroughPath.c_str()); + EmuCompileShader(g_ShaderHlsl.vertexShaderPassthroughHlsl, g_vs_model, ppHostShader, g_ShaderHlsl.vertexShaderPassthroughPath.c_str()); } diff --git a/src/core/hle/D3D8/Direct3D9/VertexShader.h b/src/core/hle/D3D8/Direct3D9/VertexShader.h index 845bff1d3..46c0c11eb 100644 --- a/src/core/hle/D3D8/Direct3D9/VertexShader.h +++ b/src/core/hle/D3D8/Direct3D9/VertexShader.h @@ -19,8 +19,6 @@ extern HRESULT EmuCompileVertexShader ID3DBlob** ppHostShader ); -void LoadShadersFromDisk(); - extern void EmuCompileFixedFunction(ID3DBlob** ppHostShader); extern void EmuCompileXboxPassthrough(ID3DBlob** ppHostShader); diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index 2cdcbe4ff..658b1b9f7 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -39,6 +39,7 @@ #include "core\kernel\support\Emu.h" #include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For g_pD3DDevice, g_pXbox_PixelShader +#include "core\hle\D3D8\Direct3D9\Shader.h" // For g_ShaderHlsl #include "core\hle\D3D8\XbPixelShader.h" #include "core\hle\D3D8\Direct3D9\PixelShader.h" // EmuCompilePixelShader #include "core\hle\D3D8\XbD3D8Logging.h" // For D3DErrorString() @@ -664,30 +665,8 @@ constexpr int PSH_XBOX_CONSTANT_FRONTFACE_FACTOR = PSH_XBOX_CONSTANT_LUM + 4; // constexpr int PSH_XBOX_CONSTANT_MAX = PSH_XBOX_CONSTANT_FRONTFACE_FACTOR + 1; // = 28 std::string GetFixedFunctionShaderTemplate() { - static bool loaded = false; - static std::string hlslString; - - // TODO does this need to be thread safe? - if (!loaded) { - loaded = true; - - // Determine the filename and directory for the fixed function shader - // TODO make this a relative path so we guarantee an LPCSTR for D3DCompile - auto hlslDir = std::filesystem::path(szFilePath_CxbxReloaded_Exe) - .parent_path() - .append("hlsl"); - - auto sourceFile = hlslDir.append("FixedFunctionPixelShader.hlsl").string(); - - // Load the shader into a string - std::ifstream hlslStream(sourceFile); - std::stringstream hlsl; - hlsl << hlslStream.rdbuf(); - - hlslString = hlsl.str(); - } - - return hlslString; + // TODO hlsl hotloading support + return g_ShaderHlsl.fixedFunctionPixelShaderHlsl; } std::string_view GetD3DTOPString(int d3dtop) { diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 81e4e2d6a..e94c09694 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -35,6 +35,7 @@ #include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For g_Xbox_VertexShader_Handle #include "core\hle\D3D8\Direct3D9\RenderStates.h" // For XboxRenderStateConverter #include "core\hle\D3D8\Direct3D9\VertexShaderCache.h" // For g_VertexShaderCache +#include "core\hle\D3D8\Direct3D9\Shader.h" // For g_ShaderHlsl #include "core\hle\D3D8\XbVertexBuffer.h" // For CxbxImpl_SetVertexData4f #include "core\hle\D3D8\XbVertexShader.h" #include "core\hle\D3D8\XbD3D8Logging.h" // For DEBUG_D3DRESULT @@ -1144,12 +1145,16 @@ IDirect3DVertexShader* InitShader(void (*compileFunc)(ID3DBlob**), const char* l void CxbxUpdateHostVertexShader() { extern bool g_bUsePassthroughHLSL; // TMP glue + // TODO move d3d9 state to VertexShader.cpp static IDirect3DVertexShader* fixedFunctionShader = nullptr; // TODO move to shader cache static IDirect3DVertexShader* passthroughShader = nullptr; + static int vertexShaderVersion = -1; + + int shaderVersion = g_ShaderHlsl.UpdateShaders(); + if (vertexShaderVersion != shaderVersion) { + vertexShaderVersion = shaderVersion; - if (isShaderFolderDirty) { EmuLog(LOG_LEVEL::INFO, "Loading vertex shaders..."); - LoadShadersFromDisk(); g_VertexShaderCache.Clear(); @@ -1164,8 +1169,6 @@ void CxbxUpdateHostVertexShader() passthroughShader = nullptr; } passthroughShader = InitShader(EmuCompileXboxPassthrough, "Passthrough Vertex Shader"); - - isShaderFolderDirty = false; } // TODO Call this when state is dirty @@ -1623,64 +1626,3 @@ extern void EmuParseVshFunction pCurToken += X_VSH_INSTRUCTION_SIZE; } } - - -void InitShaderHotloading() { - static HANDLE fsWatcherThread = 0; - - if (fsWatcherThread) { - EmuLog(LOG_LEVEL::ERROR2, "Ignoring request to start shader file watcher - it has already been started."); - return; - } - - EmuLog(LOG_LEVEL::DEBUG, "Starting shader file watcher..."); - - auto fsWatcher = [](void* param) -> DWORD { - // Determine the filename and directory for the fixed function shader - char cxbxExePath[MAX_PATH]; - GetModuleFileName(GetModuleHandle(nullptr), cxbxExePath, MAX_PATH); - auto hlslDir = std::filesystem::path(cxbxExePath) - .parent_path() - .append("hlsl/"); - - HANDLE changeHandle = FindFirstChangeNotification(hlslDir.string().c_str(), false, FILE_NOTIFY_CHANGE_LAST_WRITE); - - if (changeHandle == INVALID_HANDLE_VALUE) { - DWORD errorCode = GetLastError(); - EmuLog(LOG_LEVEL::ERROR2, "Error initializing shader file watcher: %d", errorCode); - - return 1; - } - - while (true) { - if (FindNextChangeNotification(changeHandle)) { - WaitForSingleObject(changeHandle, INFINITE); - - // Wait for changes to stop.. - // Will usually be at least two - one for the file and one for the directory - while (true) { - FindNextChangeNotification(changeHandle); - if (WaitForSingleObject(changeHandle, 100) == WAIT_TIMEOUT) { - break; - } - } - - EmuLog(LOG_LEVEL::DEBUG, "Change detected in shader folder"); - isShaderFolderDirty = true; - } - else { - EmuLog(LOG_LEVEL::ERROR2, "Shader filewatcher failed to get the next notification"); - break; - } - } - - EmuLog(LOG_LEVEL::DEBUG, "Shader file watcher exiting..."); - - // until there is a way to disable hotloading - // this is always an error - FindCloseChangeNotification(changeHandle); - return 1; - }; - - fsWatcherThread = CreateThread(nullptr, 0, fsWatcher, nullptr, 0, nullptr); -}