diff --git a/src/core/hle/D3D8/Direct3D9/Shader.cpp b/src/core/hle/D3D8/Direct3D9/Shader.cpp index 0eb331c14..c6b384e24 100644 --- a/src/core/hle/D3D8/Direct3D9/Shader.cpp +++ b/src/core/hle/D3D8/Direct3D9/Shader.cpp @@ -199,8 +199,14 @@ void ShaderHlsl::LoadShadersFromDisk() { auto insertionPoint = insertionPoints[i]; auto index = hlsl.find(insertionPoint, pos); - this->pixelShaderTemplateHlsl[i] = hlsl.substr(pos, index - pos); - pos = index + insertionPoint.length(); + if (index == std::string::npos) { + // Handle broken shaders + this->pixelShaderTemplateHlsl[i] = ""; + } + else { + this->pixelShaderTemplateHlsl[i] = hlsl.substr(pos, index - pos); + pos = index + insertionPoint.length(); + } } this->pixelShaderTemplateHlsl[insertionPoints.size()] = hlsl.substr(pos); } @@ -224,8 +230,17 @@ void ShaderHlsl::LoadShadersFromDisk() { 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()); + + if (index == std::string::npos) { + // Handle broken shaders + this->vertexShaderTemplateHlsl[0] = hlsl; + this->vertexShaderTemplateHlsl[1] = ""; + } + else + { + this->vertexShaderTemplateHlsl[0] = hlsl.substr(0, index); + this->vertexShaderTemplateHlsl[1] = hlsl.substr(index + insertionPoint.length()); + } } // Fixed Function Vertex Shader diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index 3b810e206..37544a42f 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -769,9 +769,11 @@ IDirect3DPixelShader9* GetFixedFunctionShader() int shaderVersion = g_ShaderHlsl.UpdateShaders(); if (pixelShaderVersion != shaderVersion) { pixelShaderVersion = shaderVersion; + g_pD3DDevice->SetPixelShader(nullptr); for (auto& hostShader : ffPsCache) { - hostShader.second->Release(); + if (hostShader.second) + hostShader.second->Release(); } ffPsCache.clear(); @@ -864,63 +866,69 @@ IDirect3DPixelShader9* GetFixedFunctionShader() // In D3D9 it seems we need to know hardcode if we're doing a 2D or 3D lookup const std::string sampleTypePattern = "TEXTURE_SAMPLE_TYPE;"; auto sampleTypeReplace = hlslTemplate.find(sampleTypePattern); + std::string finalShader = hlslTemplate; - static constexpr std::string_view typeToString[] = { - "SAMPLE_NONE", - "SAMPLE_2D", - "SAMPLE_3D", - "SAMPLE_CUBE" - }; + if (sampleTypeReplace != std::string::npos) { + static constexpr std::string_view typeToString[] = { + "SAMPLE_NONE", + "SAMPLE_2D", + "SAMPLE_3D", + "SAMPLE_CUBE" + }; - std::stringstream sampleTypeString; - sampleTypeString << "{" - << typeToString[sampleType[0]] << ", " - << typeToString[sampleType[1]] << ", " - << typeToString[sampleType[2]] << ", " - << typeToString[sampleType[3]] << "};"; + std::stringstream sampleTypeString; + sampleTypeString << "{" + << typeToString[sampleType[0]] << ", " + << typeToString[sampleType[1]] << ", " + << typeToString[sampleType[2]] << ", " + << typeToString[sampleType[3]] << "};"; - auto finalShader = hlslTemplate.replace(sampleTypeReplace, sampleTypePattern.size(), sampleTypeString.str()); + finalShader = hlslTemplate.replace(sampleTypeReplace, sampleTypePattern.size(), sampleTypeString.str()); + } // Hardcode the texture stage operations and arguments // So the shader handles exactly one combination of values const std::string stageDef = "// STAGE DEFINITIONS"; - auto stageDefInsert = finalShader.find(stageDef) + stageDef.size(); + auto stageDefInsert = finalShader.find(stageDef); + if (stageDefInsert != std::string::npos) { + stageDefInsert += stageDef.size(); - std::stringstream stageSetup; - stageSetup << '\n'; + std::stringstream stageSetup; + stageSetup << '\n'; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { #ifdef ENABLE_FF_ALPHAKILL - // Even when a stage is disabled, we still have to fully initialize it's values, to prevent - // "error X4000: variable 'stages' used without having been completely initialized" + // Even when a stage is disabled, we still have to fully initialize it's values, to prevent + // "error X4000: variable 'stages' used without having been completely initialized" #else - // The stage is initialized to be disabled - // We don't have to output anything - if (states[i].COLOROP == X_D3DTOP_DISABLE) - continue; + // The stage is initialized to be disabled + // We don't have to output anything + if (states[i].COLOROP == X_D3DTOP_DISABLE) + continue; #endif - std::string target = "stages[" + std::to_string(i) + "]."; + std::string target = "stages[" + std::to_string(i) + "]."; - auto s = states[i]; - stageSetup << target << "COLOROP = " << GetD3DTOPString(s.COLOROP) << ";\n"; + auto s = states[i]; + stageSetup << target << "COLOROP = " << GetD3DTOPString(s.COLOROP) << ";\n"; - stageSetup << target << "COLORARG0 = " << GetD3DTASumString(s.COLORARG0) << ";\n"; - stageSetup << target << "COLORARG1 = " << GetD3DTASumString(s.COLORARG1) << ";\n"; - stageSetup << target << "COLORARG2 = " << GetD3DTASumString(s.COLORARG2) << ";\n"; + stageSetup << target << "COLORARG0 = " << GetD3DTASumString(s.COLORARG0) << ";\n"; + stageSetup << target << "COLORARG1 = " << GetD3DTASumString(s.COLORARG1) << ";\n"; + stageSetup << target << "COLORARG2 = " << GetD3DTASumString(s.COLORARG2) << ";\n"; - stageSetup << target << "ALPHAOP = " << GetD3DTOPString(s.ALPHAOP) << ";\n"; + stageSetup << target << "ALPHAOP = " << GetD3DTOPString(s.ALPHAOP) << ";\n"; - stageSetup << target << "ALPHAARG0 = " << GetD3DTASumString(s.ALPHAARG0) << ";\n"; - stageSetup << target << "ALPHAARG1 = " << GetD3DTASumString(s.ALPHAARG1) << ";\n"; - stageSetup << target << "ALPHAARG2 = " << GetD3DTASumString(s.ALPHAARG2) << ";\n"; + stageSetup << target << "ALPHAARG0 = " << GetD3DTASumString(s.ALPHAARG0) << ";\n"; + stageSetup << target << "ALPHAARG1 = " << GetD3DTASumString(s.ALPHAARG1) << ";\n"; + stageSetup << target << "ALPHAARG2 = " << GetD3DTASumString(s.ALPHAARG2) << ";\n"; - stageSetup << target << "RESULTARG = " << GetD3DTASumString(s.RESULTARG, false) << ";\n"; - stageSetup << '\n'; + stageSetup << target << "RESULTARG = " << GetD3DTASumString(s.RESULTARG, false) << ";\n"; + stageSetup << '\n'; + } + + finalShader = finalShader.insert(stageDefInsert, stageSetup.str()); } - finalShader = finalShader.insert(stageDefInsert, stageSetup.str()); - // Compile the shader ID3DBlob* pShaderBlob; @@ -932,13 +940,15 @@ IDirect3DPixelShader9* GetFixedFunctionShader() auto pseudoSourceFile = hlslDir.append(pseudoFileName).string(); EmuCompileShader(finalShader, "ps_3_0", &pShaderBlob, pseudoSourceFile.c_str()); - // Create shader object for the device IDirect3DPixelShader9* pShader = nullptr; - auto hRet = g_pD3DDevice->CreatePixelShader((DWORD*)pShaderBlob->GetBufferPointer(), &pShader); - if (hRet != S_OK) { - EmuLog(LOG_LEVEL::ERROR2, "Failed to compile fixed function pixel shader"); + if (pShaderBlob) { + // Create shader object for the device + auto hRet = g_pD3DDevice->CreatePixelShader((DWORD*)pShaderBlob->GetBufferPointer(), &pShader); + if (hRet != S_OK) { + EmuLog(LOG_LEVEL::ERROR2, "Failed to compile fixed function pixel shader"); + } + pShaderBlob->Release(); } - pShaderBlob->Release(); // Insert the shader into the cache ffPsCache[key] = pShader; @@ -1023,9 +1033,11 @@ void DxbxUpdateActivePixelShader() // NOPATCH int shaderVersion = g_ShaderHlsl.UpdateShaders(); if (pixelShaderVersion != shaderVersion) { pixelShaderVersion = shaderVersion; + g_pD3DDevice->SetPixelShader(nullptr); for (auto& hostShader : g_RecompiledPixelShaders) { - hostShader.ConvertedPixelShader->Release(); + if (hostShader.ConvertedPixelShader) + hostShader.ConvertedPixelShader->Release(); } g_RecompiledPixelShaders.clear(); diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index e94c09694..7ee6006d5 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -1153,6 +1153,7 @@ void CxbxUpdateHostVertexShader() int shaderVersion = g_ShaderHlsl.UpdateShaders(); if (vertexShaderVersion != shaderVersion) { vertexShaderVersion = shaderVersion; + g_pD3DDevice->SetVertexShader(nullptr); EmuLog(LOG_LEVEL::INFO, "Loading vertex shaders...");