From 761fdd353fedab46543093c55392dd8c26c420ee Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Jan 2023 12:59:19 -0800 Subject: [PATCH 1/4] GPU: Avoid large constant in depal shader. --- GPU/Common/DepalettizeShaderCommon.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 9b63679fa4..6dc86a1251 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -61,7 +61,8 @@ void GenerateDepalShader300(ShaderWriter &writer, const DepalConfig &config) { if (config.depthUpperBits == 0x2) { writer.C(R"( int x = int((texcoord.x / scaleFactor) * texSize.x); - int temp = (x & 0xFFFFFE0F) | ((x >> 1) & 0xF0) | ((x << 4) & 0x100); + int xclear = x & 0x01F0; + int temp = (x - xclear) | ((x >> 1) & 0xF0) | ((x << 4) & 0x100); texcoord.x = (float(temp) / texSize.x) * scaleFactor; )"); } From 2b4a182b4608102e6b0da40c7a20dacfb459cb48 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Jan 2023 13:12:37 -0800 Subject: [PATCH 2/4] GLES: Use hex for uint constants. Apparently some Adreno drivers have issues (fixed in 2014): https://developer.qualcomm.com/forum/qdn-forums/maximize-hardware/mobile-gaming-graphics-adreno/27945 --- GPU/Common/FragmentShaderGenerator.cpp | 24 ++++++++++++------------ GPU/Common/VertexShaderGenerator.cpp | 18 +++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 6013d62766..19e2d7d050 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -702,16 +702,16 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu // Also, since we know the CLUT is smooth, we do not need to do the bilinear filter manually, we can just // lookup with the filtered value once. p.F(" vec4 t = ").SampleTexture2D("tex", "uv").C(";\n"); - p.C(" uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFU;\n"); - p.C(" uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3U;\n"); + p.C(" uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFu;\n"); + p.C(" uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3u;\n"); p.C(" float index0 = t.r;\n"); p.C(" float factor = 31.0 / 256.0;\n"); - p.C(" if (depalFmt == 0u) {\n"); // yes, different versions of Test Drive use different formats. Could do compile time by adding more compat flags but meh. - p.C(" if (depalShift == 5u) { index0 = t.g; factor = 63.0 / 256.0; }\n"); - p.C(" else if (depalShift == 11u) { index0 = t.b; }\n"); + p.C(" if (depalFmt == 0x0u) {\n"); // yes, different versions of Test Drive use different formats. Could do compile time by adding more compat flags but meh. + p.C(" if (depalShift == 0x5u) { index0 = t.g; factor = 63.0 / 256.0; }\n"); + p.C(" else if (depalShift == 0xBu) { index0 = t.b; }\n"); p.C(" } else {\n"); - p.C(" if (depalShift == 5u) { index0 = t.g; }\n"); - p.C(" else if (depalShift == 10u) { index0 = t.b; }\n"); + p.C(" if (depalShift == 0x5u) { index0 = t.g; }\n"); + p.C(" else if (depalShift == 0xAu) { index0 = t.b; }\n"); p.C(" }\n"); p.F(" t = ").SampleTexture2D("pal", "vec2(index0 * factor * 0.5, 0.0)").C(";\n"); // 0.5 for 512-entry CLUT. break; @@ -725,7 +725,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } WRITE(p, " vec2 tsize = vec2(textureSize(tex, 0).xy);\n"); WRITE(p, " vec2 fraction;\n"); - WRITE(p, " bool bilinear = (u_depal_mask_shift_off_fmt >> 31) != 0U;\n"); + WRITE(p, " bool bilinear = (u_depal_mask_shift_off_fmt >> 31) != 0x0u;\n"); WRITE(p, " if (bilinear) {\n"); WRITE(p, " uv_round = uv * tsize - vec2(0.5, 0.5);\n"); WRITE(p, " fraction = fract(uv_round);\n"); @@ -737,10 +737,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu p.C(" highp vec4 t1 = ").SampleTexture2DOffset("tex", "uv_round", 1, 0).C(";\n"); p.C(" highp vec4 t2 = ").SampleTexture2DOffset("tex", "uv_round", 0, 1).C(";\n"); p.C(" highp vec4 t3 = ").SampleTexture2DOffset("tex", "uv_round", 1, 1).C(";\n"); - WRITE(p, " uint depalMask = (u_depal_mask_shift_off_fmt & 0xFFU);\n"); - WRITE(p, " uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFU;\n"); - WRITE(p, " uint depalOffset = ((u_depal_mask_shift_off_fmt >> 16) & 0xFFU) << 4;\n"); - WRITE(p, " uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3U;\n"); + WRITE(p, " uint depalMask = (u_depal_mask_shift_off_fmt & 0xFFu);\n"); + WRITE(p, " uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFu;\n"); + WRITE(p, " uint depalOffset = ((u_depal_mask_shift_off_fmt >> 16) & 0xFFu) << 4;\n"); + WRITE(p, " uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3u;\n"); WRITE(p, " uvec4 col; uint index0; uint index1; uint index2; uint index3;\n"); WRITE(p, " switch (int(depalFmt)) {\n"); // We might want to include fmt in the shader ID if this is a performance issue. WRITE(p, " case 0:\n"); // 565 diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 34af7abfc4..ccb2cda4dc 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -967,10 +967,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } if (lightUberShader && hasColor) { - p.F(" vec4 ambientColor = ((u_lightControl & (1u << 20u)) != 0u) ? %s : u_matambientalpha;\n", srcCol); + p.F(" vec4 ambientColor = ((u_lightControl & (1u << 20u)) != 0x0u) ? %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); + p.F(" vec3 diffuseColor = ((u_lightControl & (1u << 21u)) != 0x0u) ? %s.rgb : u_matdiffuse;\n", srcCol); + p.F(" vec3 specularColor = ((u_lightControl & (1u << 22u)) != 0x0u) ? %s.rgb : u_matspecular.rgb;\n", srcCol); } } else { // This path also takes care of the lightUberShader && !hasColor path, because all comparisons fail. @@ -1031,10 +1031,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // Will need to change how the data is stored to loop efficiently. // u_lightControl is computed in PackLightControlBits(). for (int i = 0; i < 4; i++) { - p.F(" if ((u_lightControl & %du) != 0u) { \n", 1 << i); - p.F(" uint comp = (u_lightControl >> %d) & 3u;\n", 4 + 4 * i); - p.F(" uint type = (u_lightControl >> %d) & 3u;\n", 4 + 4 * i + 2); - p.C(" if (type == 0u) {\n"); // GE_LIGHTTYPE_DIRECTIONAL + p.F(" if ((u_lightControl & %du) != 0x0u) { \n", 1 << i); + p.F(" uint comp = (u_lightControl >> %d) & 0x3u;\n", 4 + 4 * i); + p.F(" uint type = (u_lightControl >> %d) & 0x3u;\n", 4 + 4 * i + 2); + p.C(" if (type == 0x0u) {\n"); // GE_LIGHTTYPE_DIRECTIONAL p.F(" toLight = u_lightpos%d;\n", i); p.C(" } else {\n"); p.F(" toLight = u_lightpos%d - worldpos;\n", i); @@ -1042,7 +1042,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.F(" toLight /= distance;\n", i); p.C(" }\n"); p.C(" ldot = dot(toLight, worldnormal);\n"); - p.C(" if (comp == 2u) {\n"); // GE_LIGHTCOMP_ONLYPOWDIFFUSE + p.C(" if (comp == 0x2u) {\n"); // GE_LIGHTCOMP_ONLYPOWDIFFUSE p.C(" if (u_matspecular.a <= 0.0) {\n"); p.C(" ldot = 1.0;\n"); p.C(" } else {\n"); @@ -1066,7 +1066,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag p.C(" break;\n"); p.C(" }\n"); p.F(" diffuse = (u_lightdiffuse%i * diffuseColor) * max(ldot, 0.0);\n", i); - p.C(" if (comp == 1u) {\n"); // do specular + p.C(" if (comp == 0x1u) {\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"); p.C(" if (u_matspecular.a <= 0.0) {\n"); From 5180486ded55f5c5d98bdd43acf28826894f10ba Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Jan 2023 13:21:47 -0800 Subject: [PATCH 3/4] GLES: Force frag test cache on for Intel. Seeing drivers report errors trying to shift the alpha value in the test. Only seeing these errors in fragment shaders, though. --- GPU/GLES/GPU_GLES.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 7ef12af3be..277fa4e1e2 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -168,7 +168,8 @@ u32 GPU_GLES::CheckGPUFeatures() const { if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float) features |= GPU_USE_TEXTURE_FLOAT; - if (!draw_->GetShaderLanguageDesc().bitwiseOps) { + // Intel drivers have been seen rejecting fragment shader uint shifts used in the alpha test. + if (!draw_->GetShaderLanguageDesc().bitwiseOps || draw_->GetDeviceCaps().vendor == Draw::GPUVendor::VENDOR_INTEL) { features |= GPU_USE_FRAGMENT_TEST_CACHE; } From c8728a12d0d64f1ecfa97bc288a2f8c47f79612f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 2 Jan 2023 13:25:40 -0800 Subject: [PATCH 4/4] GLES: Use mod() not fmod() in depal shaders. --- GPU/Common/DepalettizeShaderCommon.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 6dc86a1251..470a3a9326 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -193,7 +193,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config) { if (rgba_shift == 0 && mask == 0xFF) { sprintf(lookupMethod, "index.%c", rgba[shift]); } else { - sprintf(lookupMethod, "fmod(index.%c * %f, %d.0)", rgba[shift], 255.99f / (1 << rgba_shift), mask + 1); + sprintf(lookupMethod, "mod(index.%c * %f, %d.0)", rgba[shift], 255.99f / (1 << rgba_shift), mask + 1); index_multiplier = 1.0f / 256.0f; // Format was OK if there weren't bits from another component. formatOK = mask <= 255 - (1 << rgba_shift); @@ -211,7 +211,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config) { index_multiplier = 15.0f / 256.0f; } else { // Let's divide and mod to get the right bits. A common case is shift=0, mask=01. - sprintf(lookupMethod, "fmod(index.%c * %f, %d.0)", rgba[shift], 15.99f / (1 << rgba_shift), mask + 1); + sprintf(lookupMethod, "mod(index.%c * %f, %d.0)", rgba[shift], 15.99f / (1 << rgba_shift), mask + 1); index_multiplier = 1.0f / 256.0f; formatOK = mask <= 15 - (1 << rgba_shift); } @@ -231,7 +231,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config) { } else { // We just need to divide the right component by the right value, and then mod against the mask. // A common case is shift=1, mask=0f. - sprintf(lookupMethod, "fmod(index.%c * %f, %d.0)", rgba[shift], ((float)multipliers[shift] + 0.99f) / (1 << rgba_shift), mask + 1); + sprintf(lookupMethod, "mod(index.%c * %f, %d.0)", rgba[shift], ((float)multipliers[shift] + 0.99f) / (1 << rgba_shift), mask + 1); index_multiplier = 1.0f / 256.0f; formatOK = mask <= multipliers[shift] - (1 << rgba_shift); } @@ -251,7 +251,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config) { index_multiplier = 1.0f / 256.0f; } else { // A isn't possible here. - sprintf(lookupMethod, "fmod(index.%c * %f, %d.0)", rgba[shift], 31.99f / (1 << rgba_shift), mask + 1); + sprintf(lookupMethod, "mod(index.%c * %f, %d.0)", rgba[shift], 31.99f / (1 << rgba_shift), mask + 1); index_multiplier = 1.0f / 256.0f; formatOK = mask <= 31 - (1 << rgba_shift); }