From 9c63973c9a10b47d5ca63ceb3779c89805b95f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Sep 2022 10:39:09 +0200 Subject: [PATCH 1/5] Minor debugger fix --- Windows/GEDebugger/TabState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Windows/GEDebugger/TabState.cpp b/Windows/GEDebugger/TabState.cpp index 63a7199ed6..0a50b4fd19 100644 --- a/Windows/GEDebugger/TabState.cpp +++ b/Windows/GEDebugger/TabState.cpp @@ -447,7 +447,7 @@ void FormatStateRow(wchar_t *dest, const TabStateRow &info, u32 value, bool enab swprintf(dest, 255, L"%S", texformats[value]); } else if ((value & 0xF) < (u32)ARRAY_SIZE(texformats)) { - swprintf(dest, 255, L"%S (extra bits %06x)", texformats[value & 0xF], value); + swprintf(dest, 255, L"%S (extra bits %06x)", texformats[value & 0xF], value & ~0xF); } else { swprintf(dest, 255, L"%06x", value); From 196f8e3461304da10c6ab8851cd1b5dbec0830d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Sep 2022 10:39:27 +0200 Subject: [PATCH 2/5] Prepare for dynamic mat update --- Common/GPU/Vulkan/VulkanDebug.cpp | 1 - GPU/Common/VertexShaderGenerator.cpp | 28 +++++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp index b52e4396cb..83b3d974c0 100644 --- a/Common/GPU/Vulkan/VulkanDebug.cpp +++ b/Common/GPU/Vulkan/VulkanDebug.cpp @@ -93,4 +93,3 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback( // keep that behavior here. return false; } - diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 8de59ab191..5d2da2d06a 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -949,14 +949,16 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // TODO: Declare variables for dots for shade mapping if needed. - const char *ambientStr = (matUpdate & 1) && hasColor ? "color0" : "u_matambientalpha"; - const char *diffuseStr = (matUpdate & 2) && hasColor ? "color0.rgb" : "u_matdiffuse"; - const char *specularStr = (matUpdate & 4) && hasColor ? "color0.rgb" : "u_matspecular.rgb"; + const char *srcCol = "color0"; if (doBezier || doSpline) { // TODO: Probably, should use hasColorTess but FF4 has a problem with drawing the background. - ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "u_matambientalpha"; - diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "u_matdiffuse"; - specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "u_matspecular.rgb"; + srcCol = "tess"; + } + + p.F(" vec4 ambientColor = %s;\n", (matUpdate & 1) && hasColor ? srcCol : "u_matambientalpha"); + if (enableLighting) { + p.F(" vec3 diffuseColor = %s.rgb;\n", (matUpdate & 2) && hasColor ? srcCol : "u_matdiffuse"); + p.F(" vec3 specularColor = %s.rgb;\n", (matUpdate & 4) && hasColor ? srcCol : "u_matspecular"); } bool diffuseIsZero = true; @@ -964,7 +966,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool distanceNeeded = false; bool anySpots = false; if (enableLighting) { - WRITE(p, " lowp vec4 lightSum0 = u_ambient * %s + vec4(u_matemissive, 0.0);\n", ambientStr); + p.C(" lowp vec4 lightSum0 = u_ambient * ambientColor + vec4(u_matemissive, 0.0);\n"); for (int i = 0; i < 4; i++) { GELightType type = static_cast(id.Bits(VS_BIT_LIGHT0_TYPE + 4*i, 2)); @@ -1043,7 +1045,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.C(" lightScale = 1.0;\n"); p.C(" break;\n"); p.C(" }\n"); - p.F(" diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr); + p.F(" diffuse = (u_lightdiffuse%i * diffuseColor) * max(ldot, 0.0);\n", i); p.C(" if (comp == 1u) {\n"); // do specular p.C(" if (ldot >= 0.0) {\n"); p.C(" ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); @@ -1053,10 +1055,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); p.C(" }\n"); p.C(" if (ldot > 0.0)\n"); - p.F(" lightSum1 += u_lightspecular%i * %s * ldot * lightScale;\n", i, specularStr); + p.F(" lightSum1 += u_lightspecular%i * specularColor * ldot * lightScale;\n", i); p.C(" }\n"); p.C(" }\n"); - p.F(" lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse) * lightScale;\n", i, ambientStr); + p.F(" lightSum0.rgb += (u_lightambient%i * ambientColor.rgb + diffuse) * lightScale;\n", i); p.C(" }\n"); } } else { @@ -1116,7 +1118,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag break; } - p.F(" diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr); + p.F(" diffuse = (u_lightdiffuse%i * diffuseColor) * max(ldot, 0.0);\n", i); if (doSpecular) { p.C(" if (ldot >= 0.0) {\n"); p.C(" ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); @@ -1126,10 +1128,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); p.C(" }\n"); p.C(" if (ldot > 0.0)\n"); - p.F(" lightSum1 += u_lightspecular%i * %s * ldot %s;\n", i, specularStr, timesLightScale); + p.F(" lightSum1 += u_lightspecular%i * specularColor * ldot %s;\n", i, timesLightScale); p.C(" }\n"); } - p.F(" lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); + p.F(" lightSum0.rgb += (u_lightambient%i * ambientColor.rgb + diffuse)%s;\n", i, timesLightScale); } } From 76f03d30bf4c741d5dfb9c179f8c4e66b148d10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Sep 2022 11:07:19 +0200 Subject: [PATCH 3/5] Remove suspicious dirty flag --- GPU/GPUCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 00ac51f9c1..ce09871c6a 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -111,7 +111,7 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_LIGHTTYPE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT1 }, { GE_CMD_LIGHTTYPE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT2 }, { GE_CMD_LIGHTTYPE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT3 }, - { GE_CMD_MATERIALUPDATE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE }, // TODO: This should not need to dirty the fragment shader? + { GE_CMD_MATERIALUPDATE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE }, // These change both shaders so need flushing. { GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE }, From ad1021ea4b3a695980068c83a765941085dd0f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Sep 2022 11:55:47 +0200 Subject: [PATCH 4/5] Add some recent flags to FragmentShaderDesc --- GPU/Common/ShaderId.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 5ed727a638..d530758759 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -248,6 +248,9 @@ std::string FragmentShaderDesc(const FShaderID &id) { else if (id.Bit(FS_BIT_ALPHA_TEST)) desc << "AlphaTest " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " "; if (id.Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc << "ColorTest0 " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match; else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match + if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc << "TestDiscardToZero "; + if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc << "StencilDiscardWorkaround "; + if (id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) desc << "ReplaceLogic "; return desc.str(); } From 07ca9e46565e439a47976590d078c84bf561a8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Sep 2022 11:20:17 +0200 Subject: [PATCH 5/5] Fold the "materialUpdate" flag into the light ubershader part. This reduces the number of vertex shaders and thus pipelines by quite a bit more in a few games, like Tekken and GoW, continuing the fight against shader compile stutter. The perf impact should be minimal if not positive due to less pipeline changes. GLES fixes Make the vertex input declarations match (always declare fog input). Fixes D3D11 validation Tess fix --- GPU/Common/FragmentShaderGenerator.cpp | 10 +++------- GPU/Common/ShaderId.cpp | 2 +- GPU/Common/ShaderUniforms.cpp | 5 +++++ GPU/Common/VertexShaderGenerator.cpp | 21 +++++++++++++++------ GPU/GPUCommon.cpp | 8 ++++++++ GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- 6 files changed, 33 insertions(+), 15 deletions(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index e2088731af..04d8aa93ed 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -174,9 +174,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, "layout (location = 1) %s in lowp vec4 v_color0;\n", shading); if (lmode) WRITE(p, "layout (location = 2) %s in lowp vec3 v_color1;\n", shading); - if (enableFog) { - WRITE(p, "layout (location = 3) in highp float v_fogdepth;\n"); - } + WRITE(p, "layout (location = 3) in highp float v_fogdepth;\n"); if (doTexture) { WRITE(p, "layout (location = 0) in highp vec3 v_texcoord;\n"); } @@ -279,9 +277,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu if (lmode) { WRITE(p, " vec3 v_color1: COLOR1;\n"); } - if (enableFog) { - WRITE(p, " float v_fogdepth: TEXCOORD1;\n"); - } + WRITE(p, " float v_fogdepth: TEXCOORD1;\n"); if (needFragCoord) { if (compat.shaderLanguage == HLSL_D3D11) { WRITE(p, " vec4 pixelPos : SV_POSITION;\n"); @@ -394,8 +390,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu if (enableFog) { *uniformMask |= DIRTY_FOGCOLOR; WRITE(p, "uniform vec3 u_fogcolor;\n"); - WRITE(p, "%s %s float v_fogdepth;\n", compat.varying_fs, highpFog ? "highp" : "mediump"); } + WRITE(p, "%s %s float v_fogdepth;\n", compat.varying_fs, highpFog ? "highp" : "mediump"); if (doTexture) { WRITE(p, "%s %s vec3 v_texcoord;\n", compat.varying_fs, highpTexcoord ? "highp" : "mediump"); } diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index d530758759..bb8dd54237 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -123,11 +123,11 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, if (gstate.isLightingEnabled()) { // doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping. - id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate()); id.SetBit(VS_BIT_LIGHTING_ENABLE); if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { id.SetBit(VS_BIT_LIGHT_UBERSHADER); } else { + id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate()); // Light bits for (int i = 0; i < 4; i++) { bool chanEnabled = gstate.isLightChanEnabled(i) != 0; diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 8bf1f69356..f5cc8ca6c9 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -271,6 +271,8 @@ uint32_t PackLightControlBits() { // Bit organization // Bottom 4 bits are enable bits for each light. // Then, for each light, comes 2 bits for "comp" and 2 bits for "type". + // At the end, at bit 20, we put the three material update bits. + uint32_t lightControl = 0; for (int i = 0; i < 4; i++) { if (gstate.isLightChanEnabled(i)) { @@ -282,6 +284,9 @@ uint32_t PackLightControlBits() { lightControl |= computation << (4 + i * 4); lightControl |= type << (4 + i * 4 + 2); } + + lightControl |= gstate.getMaterialUpdate() << 20; + return lightControl; } diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 5d2da2d06a..4b0a16977f 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -552,7 +552,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (enableLighting) { WRITE(p, "uniform lowp vec4 u_ambient;\n"); *uniformMask |= DIRTY_AMBIENT; - if ((matUpdate & 2) == 0 || !hasColor) { + if (lightUberShader || (matUpdate & 2) == 0 || !hasColor) { WRITE(p, "uniform lowp vec3 u_matdiffuse;\n"); *uniformMask |= DIRTY_MATDIFFUSE; } @@ -952,13 +952,22 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag const char *srcCol = "color0"; if (doBezier || doSpline) { // TODO: Probably, should use hasColorTess but FF4 has a problem with drawing the background. - srcCol = "tess"; + srcCol = "tess.col"; } - p.F(" vec4 ambientColor = %s;\n", (matUpdate & 1) && hasColor ? srcCol : "u_matambientalpha"); - if (enableLighting) { - p.F(" vec3 diffuseColor = %s.rgb;\n", (matUpdate & 2) && hasColor ? srcCol : "u_matdiffuse"); - p.F(" vec3 specularColor = %s.rgb;\n", (matUpdate & 4) && hasColor ? srcCol : "u_matspecular"); + if (lightUberShader && hasColor) { + p.F(" vec4 ambientColor = ((u_lightControl & (1u << 20u)) != 0u) ? %s : u_matambientalpha;\n", srcCol); + if (enableLighting) { + p.F(" vec3 diffuseColor = ((u_lightControl & (1u << 21u)) != 0u) ? %s.rgb : u_matdiffuse;\n", srcCol); + p.F(" vec3 specularColor = ((u_lightControl & (1u << 22u)) != 0u) ? %s.rgb : u_matspecular.rgb;\n", srcCol); + } + } else { + // This path also takes care of the lightUberShader && !hasColor path, because all comparisons fail. + p.F(" vec4 ambientColor = %s;\n", (matUpdate & 1) && hasColor ? srcCol : "u_matambientalpha"); + if (enableLighting) { + p.F(" vec3 diffuseColor = %s.rgb;\n", (matUpdate & 2) && hasColor ? srcCol : "u_matdiffuse"); + p.F(" vec3 specularColor = %s.rgb;\n", (matUpdate & 4) && hasColor ? srcCol : "u_matspecular"); + } } bool diffuseIsZero = true; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index ce09871c6a..56dbbbcf59 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -465,6 +465,14 @@ void GPUCommon::UpdateCmdInfo() { cmdInfo_[GE_CMD_LIGHTTYPE0 + i].AddDirty(DIRTY_VERTEXSHADER_STATE); } } + + if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) { + cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_VERTEXSHADER_STATE); + cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_LIGHT_CONTROL); + } else { + cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_LIGHT_CONTROL); + cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_VERTEXSHADER_STATE); + } } void GPUCommon::BeginHostFrame() { diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index acdeba7b4a..6c39280a82 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -376,7 +376,7 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 27 +#define CACHE_VERSION 28 struct VulkanCacheHeader { uint32_t magic; uint32_t version;