From 4da2ca093595fe9d4b47efb07c58f5fb14d38d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 30 Aug 2022 11:14:55 +0200 Subject: [PATCH] Implement shader blending for D3D9 This was easy, dunno why I never got around to it before.. I guess I didn't know about VPOS. This does raise our minimum shader model requirement to ps_3_0. --- Common/GPU/D3D9/D3D9ShaderCompiler.cpp | 4 ++-- Common/GPU/D3D9/thin3d_d3d9.cpp | 6 +----- GPU/Common/FragmentShaderGenerator.cpp | 23 +++++++++++++---------- GPU/Directx9/StateMappingDX9.cpp | 3 +-- unittest/TestShaderGenerators.cpp | 2 +- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Common/GPU/D3D9/D3D9ShaderCompiler.cpp b/Common/GPU/D3D9/D3D9ShaderCompiler.cpp index e8585f15f3..f41ea3911d 100644 --- a/Common/GPU/D3D9/D3D9ShaderCompiler.cpp +++ b/Common/GPU/D3D9/D3D9ShaderCompiler.cpp @@ -54,7 +54,7 @@ LPD3DBLOB CompileShaderToByteCodeD3D9(const char *code, const char *target, std: } bool CompilePixelShaderD3D9(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DPIXELSHADER9 *pShader, std::string *errorMessage) { - LPD3DBLOB pShaderCode = CompileShaderToByteCodeD3D9(code, "ps_2_0", errorMessage); + LPD3DBLOB pShaderCode = CompileShaderToByteCodeD3D9(code, "ps_3_0", errorMessage); if (pShaderCode) { // Create pixel shader. device->CreatePixelShader((DWORD*)pShaderCode->GetBufferPointer(), pShader); @@ -66,7 +66,7 @@ bool CompilePixelShaderD3D9(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT } bool CompileVertexShaderD3D9(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DVERTEXSHADER9 *pShader, std::string *errorMessage) { - LPD3DBLOB pShaderCode = CompileShaderToByteCodeD3D9(code, "vs_2_0", errorMessage); + LPD3DBLOB pShaderCode = CompileShaderToByteCodeD3D9(code, "vs_3_0", errorMessage); if (pShaderCode) { // Create vertex shader. device->CreateVertexShader((DWORD*)pShaderCode->GetBufferPointer(), pShader); diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index cf73de79a3..dc72ed898d 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -1069,11 +1069,7 @@ bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, si auto compile = [&](const char *profile) -> HRESULT { return dyn_D3DCompile(source, (UINT)strlen(source), nullptr, defines, includes, "main", profile, 0, 0, &codeBuffer, &errorBuffer); }; - HRESULT hr = compile(stage_ == ShaderStage::Fragment ? "ps_2_0" : "vs_2_0"); - if (FAILED(hr) && hr == D3DXERR_INVALIDDATA) { - // Might be a post shader. Let's try using shader model 3. - hr = compile(stage_ == ShaderStage::Fragment ? "ps_3_0" : "vs_3_0"); - } + HRESULT hr = compile(stage_ == ShaderStage::Fragment ? "ps_3_0" : "vs_3_0"); if (FAILED(hr)) { const char *error = errorBuffer ? (const char *)errorBuffer->GetBufferPointer() : "(no errorbuffer returned)"; if (hr == ERROR_MOD_NOT_FOUND) { diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 77c8042435..8cf705cce5 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -132,11 +132,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu return false; } - if (readFramebuffer && compat.shaderLanguage == HLSL_D3D9) { - *errorString = "Framebuffer read not yet supported in HLSL D3D9"; - return false; - } - if (compat.shaderLanguage == ShaderLanguage::GLSL_VULKAN) { if (useDiscardStencilBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); @@ -227,7 +222,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } if (readFramebufferTex) { // No sampler required, we Load - WRITE(p, "Texture2D fboTex : register(t1);\n"); + WRITE(p, "Texture2D fbotex : register(t1);\n"); } WRITE(p, "cbuffer base : register(b0) {\n%s};\n", ub_baseStr); @@ -264,8 +259,12 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu if (enableFog) { WRITE(p, " float v_fogdepth: TEXCOORD1;\n"); } - if (compat.shaderLanguage == HLSL_D3D11 && needFragCoord) { - WRITE(p, " vec4 pixelPos : SV_POSITION;\n"); + if (needFragCoord) { + if (compat.shaderLanguage == HLSL_D3D11) { + WRITE(p, " vec4 pixelPos : SV_POSITION;\n"); + } else if (compat.shaderLanguage == HLSL_D3D9) { + WRITE(p, " vec4 pixelPos : VPOS;\n"); // VPOS is only supported for Shader Model 3.0, but we can probably forget about D3D9 SM2.0 at this point... + } } WRITE(p, "};\n"); @@ -457,7 +456,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } else if (compat.shaderLanguage == HLSL_D3D9) { WRITE(p, "PS_OUT main( PS_IN In ) {\n"); WRITE(p, " PS_OUT outfragment;\n"); - WRITE(p, " vec4 target;\n"); + if (needFragCoord) { + WRITE(p, " vec4 gl_FragCoord = In.pixelPos;\n"); + } } else { WRITE(p, "void main() {\n"); } @@ -477,7 +478,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu // Two things read from the old framebuffer - shader replacement blending and bit-level masking. if (readFramebuffer) { if (compat.shaderLanguage == HLSL_D3D11) { - WRITE(p, " vec4 destColor = fboTex.Load(int3((int)gl_FragCoord.x, (int)gl_FragCoord.y, 0));\n"); + WRITE(p, " vec4 destColor = fbotex.Load(int3((int)gl_FragCoord.x, (int)gl_FragCoord.y, 0));\n"); + } else if (compat.shaderLanguage == HLSL_D3D9) { + WRITE(p, " vec4 destColor = tex2D(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture); } else if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { // If we have EXT_shader_framebuffer_fetch / ARM_shader_framebuffer_fetch, we skip the blit. // We can just read the prev value more directly. diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 1e4d1d348c..3ebeb71fca 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -119,8 +119,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { bool useBufferedRendering = framebufferManager_->UseBufferedRendering(); if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) { - // Unfortunately, this isn't implemented on DX9 yet. - gstate_c.SetAllowFramebufferRead(false); + gstate_c.SetAllowFramebufferRead(!g_Config.bDisableSlowFramebufEffects); if (gstate.isModeClear()) { dxstate.blend.disable(); // Color Mask diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index 28ab16e2c4..d90d893ff3 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -102,7 +102,7 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, ShaderStage stag } case ShaderLanguage::HLSL_D3D9: { - LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, stage == ShaderStage::Vertex ? "vs_2_0" : "ps_2_0", errorMessage); + LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, stage == ShaderStage::Vertex ? "vs_3_0" : "ps_3_0", errorMessage); if (blob) { blob->Release(); return true;