From 8eb011c22d8917ca8e726cbf29c4fa954e412fc1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 9 Sep 2018 20:27:39 -0700 Subject: [PATCH] GPU: Clamp after color doubling. This is needed for blending to be correct - it blends a clamped value. --- GPU/Directx9/PixelShaderGeneratorDX9.cpp | 12 +++++++----- GPU/GLES/FragmentShaderGeneratorGLES.cpp | 10 ++++++---- GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp | 10 ++++++---- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index 1d489296e5..a18e39b5fc 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -306,7 +306,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag if (enableColorTest) { // Color doubling happens before the color test, but we try to optimize doubling when test is off. if (enableColorDoubling) { - WRITE(p, " v.rgb = v.rgb * 2.0;\n"); + WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n"); } if (colorTestAgainstZero) { @@ -327,14 +327,14 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag if (colorTestFuncs[colorTestFunc][0] != '#') { const char *test = colorTestFuncs[colorTestFunc]; if (lang == HLSL_D3D11) { - WRITE(p, " uint3 v_scaled = roundAndScaleTo255iv(clamp(v.rgb, 0.0, 1.0));\n"); + WRITE(p, " uint3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); WRITE(p, " uint3 v_masked = v_scaled & u_alphacolormask.rgb;\n"); WRITE(p, " uint3 colorTestRef = u_alphacolorref.rgb & u_alphacolormask.rgb;\n"); // We have to test the components separately, or we get incorrect results. See #10629. WRITE(p, " if (v_masked.r %s colorTestRef.r && v_masked.g %s colorTestRef.g && v_masked.b %s colorTestRef.b) discard;\n", test, test, test); } else { // TODO: Use a texture to lookup bitwise ops instead? - WRITE(p, " float3 colortest = roundAndScaleTo255v(clamp(v.rgb, 0.0, 1.0));\n"); + WRITE(p, " float3 colortest = roundAndScaleTo255v(v.rgb);\n"); WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b)) clip(-1);\n", test, test, test); } } @@ -349,8 +349,10 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag } else { // If there's no color test, we can potentially double and replace blend at once. if (enableColorDoubling && replaceBlend == REPLACE_BLEND_2X_SRC) { - WRITE(p, " v.rgb = v.rgb * 4.0;\n"); - } else if (enableColorDoubling || replaceBlend == REPLACE_BLEND_2X_SRC) { + WRITE(p, " v.rgb = clamp(v.rgb * 4.0, 0.0, 2.0);\n"); + } else if (enableColorDoubling) { + WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n"); + } else if (replaceBlend == REPLACE_BLEND_2X_SRC) { WRITE(p, " v.rgb = v.rgb * 2.0;\n"); } } diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index 64b43d35f8..10a4a33181 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -560,7 +560,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform if (enableColorTest) { // Color doubling happens before the color test, but we try to optimize doubling when test is off. if (enableColorDoubling) { - WRITE(p, " v.rgb = v.rgb * 2.0;\n"); + WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n"); if (g_Config.bFragmentTestCache && !colorTestAgainstZero) { WRITE(p, " vScale256.rgb = vScale256.rgb * 2.0;\n"); } @@ -595,7 +595,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform if (colorTestFuncs[colorTestFunc][0] != '#') { if (bitwiseOps) { // Apparently GLES3 does not support vector bitwise ops. - WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(clamp(v.rgb, 0.0, 1.0));\n"); + WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); const char *maskedFragColor = "ivec3(v_scaled.r & u_alphacolormask.r, v_scaled.g & u_alphacolormask.g, v_scaled.b & u_alphacolormask.b)"; const char *maskedColorRef = "ivec3(int(u_alphacolorref.r) & u_alphacolormask.r, int(u_alphacolorref.g) & u_alphacolormask.g, int(u_alphacolorref.b) & u_alphacolormask.b)"; WRITE(p, " if (%s %s %s) %s\n", maskedFragColor, colorTestFuncs[colorTestFunc], maskedColorRef, discardStatement); @@ -615,8 +615,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } else { // If there's no color test, we can potentially double and replace blend at once. if (enableColorDoubling && replaceBlend == REPLACE_BLEND_2X_SRC) { - WRITE(p, " v.rgb = v.rgb * 4.0;\n"); - } else if (enableColorDoubling || replaceBlend == REPLACE_BLEND_2X_SRC) { + WRITE(p, " v.rgb = clamp(v.rgb * 4.0, 0.0, 2.0);\n"); + } else if (enableColorDoubling) { + WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n"); + } else if (replaceBlend == REPLACE_BLEND_2X_SRC) { WRITE(p, " v.rgb = v.rgb * 2.0;\n"); } } diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index 13a1116291..57b341d377 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -377,7 +377,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) { if (enableColorTest) { // Color doubling happens before the color test, but we try to optimize doubling when test is off. if (enableColorDoubling) { - WRITE(p, " v.rgb = v.rgb * 2.0;\n"); + WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n"); } if (colorTestAgainstZero) { @@ -397,7 +397,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) { } else { const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; if (colorTestFuncs[colorTestFunc][0] != '#') { - WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(clamp(v.rgb, 0.0, 1.0));\n"); + WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); WRITE(p, " if ((v_scaled & base.alphacolormask.rgb) %s (base.alphacolorref.rgb & base.alphacolormask.rgb)) %s\n", colorTestFuncs[colorTestFunc], discardStatement); } else { WRITE(p, " %s\n", discardStatement); @@ -410,8 +410,10 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) { } else { // If there's no color test, we can potentially double and replace blend at once. if (enableColorDoubling && replaceBlend == REPLACE_BLEND_2X_SRC) { - WRITE(p, " v.rgb = v.rgb * 4.0;\n"); - } else if (enableColorDoubling || replaceBlend == REPLACE_BLEND_2X_SRC) { + WRITE(p, " v.rgb = clamp(v.rgb * 4.0, 0.0, 2.0);\n"); + } else if (enableColorDoubling) { + WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n"); + } else if (replaceBlend == REPLACE_BLEND_2X_SRC) { WRITE(p, " v.rgb = v.rgb * 2.0;\n"); } }