diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index dd947db283..a2a2823245 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -137,3 +137,15 @@ enum DoLightComputation { LIGHT_SHADE, LIGHT_FULL, }; + +struct GLSLShaderCompat { + const char *varying; + const char *attribute; + const char *fragColor0; + const char *fragColor1; + const char *texture; + const char *texelFetch; + const char *lastFragData; + bool glslES30; + bool bitwiseOps; +}; diff --git a/GPU/Directx9/FragmentShaderGeneratorHLSL.cpp b/GPU/Directx9/FragmentShaderGeneratorHLSL.cpp index 9f5eb1fe7b..4cbe2c50ff 100644 --- a/GPU/Directx9/FragmentShaderGeneratorHLSL.cpp +++ b/GPU/Directx9/FragmentShaderGeneratorHLSL.cpp @@ -66,6 +66,21 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag StencilValueType replaceAlphaWithStencilType = (StencilValueType)id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4); + // Output some compatibility defines + switch (lang) { + case ShaderLanguage::HLSL_DX9: + WRITE(p, "#define DISCARD clip(-1)\n"); + break; + case ShaderLanguage::HLSL_D3D11: + case ShaderLanguage::HLSL_D3D11_LEVEL9: + WRITE(p, "#define DISCARD discard\n"); + break; + } + WRITE(p, "#define vec2 float2\n"); + WRITE(p, "#define vec3 float3\n"); + WRITE(p, "#define vec4 float4\n"); + WRITE(p, "#define splat3(x) float3(x, x, x)\n"); + if (lang == HLSL_DX9) { if (doTexture) WRITE(p, "sampler tex : register(s0);\n"); @@ -288,7 +303,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, " clip(-1);\n"); + WRITE(p, " DISCARD;\n"); } } else { const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; // never/always don't make sense @@ -298,11 +313,11 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); } else { // TODO: Use a texture to lookup bitwise ops? - WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) clip(-1);\n", alphaTestFuncs[alphaTestFunc]); + WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) DISCARD;\n", alphaTestFuncs[alphaTestFunc]); } } else { // This means NEVER. See above. - WRITE(p, lang == HLSL_DX9 ? " clip(-1);\n" : " discard;\n"); + WRITE(p, " DISCARD;\n"); } } } @@ -317,14 +332,14 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag // When testing against 0 (common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. if (colorTestFunc == GE_COMP_NOTEQUAL) { - WRITE(p, " if (v.r < 0.002 && v.g < 0.002 && v.b < 0.002) clip(-1);\n"); + WRITE(p, " if (v.r < 0.002 && v.g < 0.002 && v.b < 0.002) DISCARD;\n"); } else if (colorTestFunc != GE_COMP_NEVER) { // Anything else is a test for == 0. - WRITE(p, " if (v.r > 0.002 || v.g > 0.002 || v.b > 0.002) clip(-1);\n"); + WRITE(p, " if (v.r > 0.002 || v.g > 0.002 || v.b > 0.002) DISCARD;\n"); } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, lang == HLSL_DX9 ? " clip(-1);\n" : " discard;\n"); + WRITE(p, " DISCARD;\n"); } } else { const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; // never/always don't make sense @@ -335,15 +350,15 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag 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); + 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(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); + WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b)) DISCARD;\n", test, test, test); } } else { - WRITE(p, lang == HLSL_DX9 ? " clip(-1);\n" : " discard;\n"); + WRITE(p, " DISCARD;\n"); } } } diff --git a/GPU/Directx9/VertexShaderGeneratorHLSL.cpp b/GPU/Directx9/VertexShaderGeneratorHLSL.cpp index 5af4e57ba6..c8b87305cb 100644 --- a/GPU/Directx9/VertexShaderGeneratorHLSL.cpp +++ b/GPU/Directx9/VertexShaderGeneratorHLSL.cpp @@ -95,6 +95,12 @@ bool GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage numBoneWeights = 1 + id.Bits(VS_BIT_BONES, 3); } + // Output some compatibility defines + WRITE(p, "#define vec2 float2\n"); + WRITE(p, "#define vec3 float3\n"); + WRITE(p, "#define vec4 float4\n"); + WRITE(p, "#define splat3(x) float3(x, x, x)\n"); + if (lang == HLSL_DX9) { WRITE(p, "#pragma warning( disable : 3571 )\n"); if (isModeThrough) { diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index f45f3ed407..66365bff31 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -42,16 +42,16 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni *uniformMask = 0; // In GLSL ES 3.0, you use "in" variables instead of varying. - bool glslES30 = false; - const char *varying = "varying"; - const char *fragColor0 = "gl_FragColor"; - const char *fragColor1 = "fragColor1"; - const char *texture = "texture2D"; - const char *texelFetch = NULL; + GLSLShaderCompat compat{}; + compat.varying = "varying"; + compat.fragColor0 = "gl_FragColor"; + compat.fragColor1 = "fragColor1"; + compat.texture = "texture2D"; + compat.texelFetch = NULL; + compat.bitwiseOps = false; + compat.lastFragData = nullptr; bool highpFog = false; bool highpTexcoord = false; - bool bitwiseOps = false; - const char *lastFragData = nullptr; ReplaceAlphaType stencilToAlpha = static_cast(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)); @@ -59,11 +59,11 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni // ES doesn't support dual source alpha :( if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300)) { WRITE(p, "#version 300 es\n"); // GLSL ES 3.0 - fragColor0 = "fragColor0"; - texture = "texture"; - glslES30 = true; - bitwiseOps = true; - texelFetch = "texelFetch"; + compat.fragColor0 = "fragColor0"; + compat.texture = "texture"; + compat.glslES30 = true; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch"; if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { WRITE(p, "#extension GL_EXT_blend_func_extended : require\n"); @@ -72,12 +72,12 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni WRITE(p, "#version 100\n"); // GLSL ES 1.0 if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - bitwiseOps = true; - texelFetch = "texelFetch2D"; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch2D"; } if (gl_extensions.EXT_blend_func_extended) { // Oldy moldy GLES, so use the fixed output name. - fragColor1 = "gl_SecondaryFragColorEXT"; + compat.fragColor1 = "gl_SecondaryFragColorEXT"; if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { WRITE(p, "#extension GL_EXT_blend_func_extended : require\n"); @@ -93,17 +93,17 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300) && gl_extensions.EXT_shader_framebuffer_fetch) { WRITE(p, "#extension GL_EXT_shader_framebuffer_fetch : require\n"); - lastFragData = "fragColor0"; + compat.lastFragData = "fragColor0"; } else if (gl_extensions.EXT_shader_framebuffer_fetch) { WRITE(p, "#extension GL_EXT_shader_framebuffer_fetch : require\n"); - lastFragData = "gl_LastFragData[0]"; + compat.lastFragData = "gl_LastFragData[0]"; } else if (gl_extensions.NV_shader_framebuffer_fetch) { // GL_NV_shader_framebuffer_fetch is available on mobile platform and ES 2.0 only but not on desktop. WRITE(p, "#extension GL_NV_shader_framebuffer_fetch : require\n"); - lastFragData = "gl_LastFragData[0]"; + compat.lastFragData = "gl_LastFragData[0]"; } else if (gl_extensions.ARM_shader_framebuffer_fetch) { WRITE(p, "#extension GL_ARM_shader_framebuffer_fetch : require\n"); - lastFragData = "gl_LastFragColorARM"; + compat.lastFragData = "gl_LastFragColorARM"; } } @@ -111,16 +111,16 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni } else { if (!gl_extensions.ForceGL2 || gl_extensions.IsCoreContext) { if (gl_extensions.VersionGEThan(3, 3, 0)) { - fragColor0 = "fragColor0"; - texture = "texture"; - glslES30 = true; - bitwiseOps = true; - texelFetch = "texelFetch"; + compat.fragColor0 = "fragColor0"; + compat.texture = "texture"; + compat.glslES30 = true; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch"; WRITE(p, "#version 330\n"); } else if (gl_extensions.VersionGEThan(3, 0, 0)) { - fragColor0 = "fragColor0"; - bitwiseOps = true; - texelFetch = "texelFetch"; + compat.fragColor0 = "fragColor0"; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch"; WRITE(p, "#version 130\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); @@ -129,8 +129,8 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni WRITE(p, "#version 110\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - bitwiseOps = true; - texelFetch = "texelFetch2D"; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch2D"; } } } @@ -141,8 +141,8 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni WRITE(p, "#define highp\n"); } - if (glslES30 || gl_extensions.IsCoreContext) { - varying = "in"; + if (compat.glslES30 || gl_extensions.IsCoreContext) { + compat.varying = "in"; } bool lmode = id.Bit(FS_BIT_LMODE); @@ -180,7 +180,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni } const char *shading = ""; - if (glslES30) + if (compat.glslES30) shading = doFlatShading ? "flat" : ""; if (doTexture) @@ -189,7 +189,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) { *uniformMask |= DIRTY_SHADERBLEND; if (!gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) && replaceBlend == REPLACE_BLEND_COPY_FBO) { - if (!texelFetch) { + if (!compat.texelFetch) { WRITE(p, "uniform vec2 u_fbotexSize;\n"); } WRITE(p, "uniform sampler2D fbotex;\n"); @@ -216,7 +216,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni } else { *uniformMask |= DIRTY_ALPHACOLORREF; WRITE(p, "uniform vec4 u_alphacolorref;\n"); - if (bitwiseOps && ((enableColorTest && !colorTestAgainstZero) || (enableAlphaTest && !alphaTestAgainstZero))) { + if (compat.bitwiseOps && ((enableColorTest && !colorTestAgainstZero) || (enableAlphaTest && !alphaTestAgainstZero))) { *uniformMask |= DIRTY_ALPHACOLORMASK; WRITE(p, "uniform ivec4 u_alphacolormask;\n"); } @@ -239,21 +239,21 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni WRITE(p, "uniform vec3 u_texenv;\n"); } - WRITE(p, "%s %s vec4 v_color0;\n", shading, varying); + WRITE(p, "%s %s vec4 v_color0;\n", shading, compat.varying); if (lmode) - WRITE(p, "%s %s vec3 v_color1;\n", shading, varying); + WRITE(p, "%s %s vec3 v_color1;\n", shading, compat.varying); if (enableFog) { *uniformMask |= DIRTY_FOGCOLOR; WRITE(p, "uniform vec3 u_fogcolor;\n"); - WRITE(p, "%s %s float v_fogdepth;\n", varying, highpFog ? "highp" : "mediump"); + WRITE(p, "%s %s float v_fogdepth;\n", compat.varying, highpFog ? "highp" : "mediump"); } if (doTexture) { - WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); + WRITE(p, "%s %s vec3 v_texcoord;\n", compat.varying, highpTexcoord ? "highp" : "mediump"); } if (!g_Config.bFragmentTestCache) { if (enableAlphaTest && !alphaTestAgainstZero) { - if (bitwiseOps) { + if (compat.bitwiseOps) { WRITE(p, "int roundAndScaleTo255i(in float x) { return int(floor(x * 255.0 + 0.5)); }\n"); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { WRITE(p, "float roundTo255thf(in mediump float x) { mediump float y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); @@ -262,7 +262,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni } } if (enableColorTest && !colorTestAgainstZero) { - if (bitwiseOps) { + if (compat.bitwiseOps) { WRITE(p, "ivec3 roundAndScaleTo255iv(in vec3 x) { return ivec3(floor(x * 255.0 + 0.5)); }\n"); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { WRITE(p, "vec3 roundTo255thv(in vec3 x) { vec3 y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); @@ -272,9 +272,9 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni } } - if (!strcmp(fragColor0, "fragColor0")) { + if (!strcmp(compat.fragColor0, "fragColor0")) { const char *qualifierColor0 = "out"; - if (lastFragData && !strcmp(lastFragData, fragColor0)) { + if (compat.lastFragData && !strcmp(compat.lastFragData, compat.fragColor0)) { qualifierColor0 = "inout"; } // Output the output color definitions. @@ -353,9 +353,9 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni if (!shaderDepal) { if (doTextureProjection) { - WRITE(p, " vec4 t = %sProj(tex, %s);\n", texture, texcoord); + WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord); } else { - WRITE(p, " vec4 t = %s(tex, %s.xy);\n", texture, texcoord); + WRITE(p, " vec4 t = %s(tex, %s.xy);\n", compat.texture, texcoord); } } else { if (doTextureProjection) { @@ -375,10 +375,10 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni WRITE(p, " } else {\n"); WRITE(p, " uv_round = uv;\n"); WRITE(p, " }\n"); - WRITE(p, " vec4 t = %s(tex, uv_round);\n", texture); - WRITE(p, " vec4 t1 = %sOffset(tex, uv_round, ivec2(1, 0));\n", texture); - WRITE(p, " vec4 t2 = %sOffset(tex, uv_round, ivec2(0, 1));\n", texture); - WRITE(p, " vec4 t3 = %sOffset(tex, uv_round, ivec2(1, 1));\n", texture); + WRITE(p, " vec4 t = %s(tex, uv_round);\n", compat.texture); + WRITE(p, " vec4 t1 = %sOffset(tex, uv_round, ivec2(1, 0));\n", compat.texture); + WRITE(p, " vec4 t2 = %sOffset(tex, uv_round, ivec2(0, 1));\n", compat.texture); + WRITE(p, " vec4 t3 = %sOffset(tex, uv_round, ivec2(1, 1));\n", compat.texture); WRITE(p, " int depalMask = (u_depal & 0xFF);\n"); WRITE(p, " int depalShift = ((u_depal >> 8) & 0xFF);\n"); WRITE(p, " int depalOffset = (((u_depal >> 16) & 0xFF) << 4);\n"); @@ -552,12 +552,12 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni WRITE(p, " %s\n", discardStatement); } } else if (g_Config.bFragmentTestCache) { - WRITE(p, " float aResult = %s(testtex, vec2(%s, 0)).a;\n", texture, alphaTestXCoord.c_str()); + WRITE(p, " float aResult = %s(testtex, vec2(%s, 0)).a;\n", compat.texture, alphaTestXCoord.c_str()); WRITE(p, " if (aResult < 0.5) %s\n", discardStatement); } else { const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; if (alphaTestFuncs[alphaTestFunc][0] != '#') { - if (bitwiseOps) { + if (compat.bitwiseOps) { WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s int(u_alphacolorref.a)) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { // Work around bad PVR driver problem where equality check + discard just doesn't work. @@ -589,9 +589,9 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni WRITE(p, " %s\n", discardStatement); } } else if (g_Config.bFragmentTestCache) { - WRITE(p, " float rResult = %s(testtex, vec2(vScale256.r, 0)).r;\n", texture); - WRITE(p, " float gResult = %s(testtex, vec2(vScale256.g, 0)).g;\n", texture); - WRITE(p, " float bResult = %s(testtex, vec2(vScale256.b, 0)).b;\n", texture); + WRITE(p, " float rResult = %s(testtex, vec2(vScale256.r, 0)).r;\n", compat.texture); + WRITE(p, " float gResult = %s(testtex, vec2(vScale256.g, 0)).g;\n", compat.texture); + WRITE(p, " float bResult = %s(testtex, vec2(vScale256.b, 0)).b;\n", compat.texture); if (colorTestFunc == GE_COMP_EQUAL) { // Equal means all parts must be equal (so discard if any is not.) WRITE(p, " if (rResult < 0.5 || gResult < 0.5 || bResult < 0.5) %s\n", discardStatement); @@ -602,7 +602,7 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni } else { const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; if (colorTestFuncs[colorTestFunc][0] != '#') { - if (bitwiseOps) { + if (compat.bitwiseOps) { // Apparently GLES3 does not support vector bitwise ops. 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)"; @@ -649,11 +649,11 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni // If we have NV_shader_framebuffer_fetch / EXT_shader_framebuffer_fetch, we skip the blit. // We can just read the prev value more directly. if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { - WRITE(p, " lowp vec4 destColor = %s;\n", lastFragData); - } else if (!texelFetch) { - WRITE(p, " lowp vec4 destColor = %s(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", texture); + WRITE(p, " lowp vec4 destColor = %s;\n", compat.lastFragData); + } else if (!compat.texelFetch) { + WRITE(p, " lowp vec4 destColor = %s(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture); } else { - WRITE(p, " lowp vec4 destColor = %s(fbotex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);\n", texelFetch); + WRITE(p, " lowp vec4 destColor = %s(fbotex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);\n", compat.texelFetch); } const char *srcFactor = "vec3(1.0)"; @@ -755,16 +755,16 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni switch (stencilToAlpha) { case REPLACE_ALPHA_DUALSOURCE: - WRITE(p, " %s = vec4(v.rgb, %s);\n", fragColor0, replacedAlpha.c_str()); - WRITE(p, " %s = vec4(0.0, 0.0, 0.0, v.a);\n", fragColor1); + WRITE(p, " %s = vec4(v.rgb, %s);\n", compat.fragColor0, replacedAlpha.c_str()); + WRITE(p, " %s = vec4(0.0, 0.0, 0.0, v.a);\n", compat.fragColor1); break; case REPLACE_ALPHA_YES: - WRITE(p, " %s = vec4(v.rgb, %s);\n", fragColor0, replacedAlpha.c_str()); + WRITE(p, " %s = vec4(v.rgb, %s);\n", compat.fragColor0, replacedAlpha.c_str()); break; case REPLACE_ALPHA_NO: - WRITE(p, " %s = v;\n", fragColor0); + WRITE(p, " %s = v;\n", compat.fragColor0); break; default: @@ -775,10 +775,10 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni LogicOpReplaceType replaceLogicOpType = (LogicOpReplaceType)id.Bits(FS_BIT_REPLACE_LOGIC_OP_TYPE, 2); switch (replaceLogicOpType) { case LOGICOPTYPE_ONE: - WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0);\n", fragColor0); + WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0);\n", compat.fragColor0); break; case LOGICOPTYPE_INVERT: - WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0) - %s.rgb;\n", fragColor0, fragColor0); + WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0) - %s.rgb;\n", compat.fragColor0, compat.fragColor0); break; case LOGICOPTYPE_NORMAL: break; @@ -788,15 +788,6 @@ bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uni return false; } -#ifdef DEBUG_SHADER - if (doTexture) { - WRITE(p, " %s = texture2D(tex, v_texcoord.xy);\n", fragColor0); - WRITE(p, " %s += vec4(0.3,0,0.3,0.3);\n", fragColor0); - } else { - WRITE(p, " %s = vec4(1,0,1,1);\n", fragColor0); - } -#endif - if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { const double scale = DepthSliceFactor() * 65535.0; diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index c6b623e58d..3e8f03e5d4 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -94,24 +94,25 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM // #define USE_FOR_LOOP // In GLSL ES 3.0, you use "out" variables instead. - bool glslES30 = false; - const char *varying = "varying"; - const char *attribute = "attribute"; + GLSLShaderCompat compat{}; + compat.glslES30 = false; + compat.varying = "varying"; + compat.attribute = "attribute"; const char * const * boneWeightDecl = boneWeightAttrDecl; - const char *texelFetch = NULL; + compat.texelFetch = NULL; bool highpFog = false; bool highpTexcoord = false; if (gl_extensions.IsGLES) { if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300)) { WRITE(p, "#version 300 es\n"); - glslES30 = true; - texelFetch = "texelFetch"; + compat.glslES30 = true; + compat.texelFetch = "texelFetch"; } else { WRITE(p, "#version 100\n"); // GLSL ES 1.0 if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - texelFetch = "texelFetch2D"; + compat.texelFetch = "texelFetch2D"; } } WRITE(p, "precision highp float;\n"); @@ -123,20 +124,20 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM } else { if (!gl_extensions.ForceGL2 || gl_extensions.IsCoreContext) { if (gl_extensions.VersionGEThan(3, 3, 0)) { - glslES30 = true; + compat.glslES30 = true; WRITE(p, "#version 330\n"); - texelFetch = "texelFetch"; + compat.texelFetch = "texelFetch"; } else if (gl_extensions.VersionGEThan(3, 0, 0)) { WRITE(p, "#version 130\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - texelFetch = "texelFetch"; + compat.texelFetch = "texelFetch"; } } else { WRITE(p, "#version 110\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - texelFetch = "texelFetch2D"; + compat.texelFetch = "texelFetch2D"; } } } @@ -148,9 +149,9 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM } WRITE(p, "#define splat3(x) vec3(x)\n"); - if (glslES30 || gl_extensions.IsCoreContext) { - attribute = "in"; - varying = "out"; + if (compat.glslES30 || gl_extensions.IsCoreContext) { + compat.attribute = "in"; + compat.varying = "out"; boneWeightDecl = boneWeightInDecl; } @@ -186,7 +187,7 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS); const char *shading = ""; - if (glslES30) + if (compat.glslES30) shading = doFlatShading ? "flat " : ""; DoLightComputation doLight[4] = { LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF }; @@ -212,31 +213,31 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM } if (useHWTransform) - WRITE(p, "%s vec3 position;\n", attribute); + WRITE(p, "%s vec3 position;\n", compat.attribute); else - WRITE(p, "%s vec4 position;\n", attribute); // need to pass the fog coord in w + WRITE(p, "%s vec4 position;\n", compat.attribute); // need to pass the fog coord in w *attrMask |= 1 << ATTR_POSITION; if (useHWTransform && hasNormal) { - WRITE(p, "%s mediump vec3 normal;\n", attribute); + WRITE(p, "%s mediump vec3 normal;\n", compat.attribute); *attrMask |= 1 << ATTR_NORMAL; } bool texcoordVec3In = false; if (doTexture && hasTexcoord) { if (!useHWTransform && doTextureProjection && !isModeThrough) { - WRITE(p, "%s vec3 texcoord;\n", attribute); + WRITE(p, "%s vec3 texcoord;\n", compat.attribute); texcoordVec3In = true; } else { - WRITE(p, "%s vec2 texcoord;\n", attribute); + WRITE(p, "%s vec2 texcoord;\n", compat.attribute); } *attrMask |= 1 << ATTR_TEXCOORD; } if (hasColor) { - WRITE(p, "%s lowp vec4 color0;\n", attribute); + WRITE(p, "%s lowp vec4 color0;\n", compat.attribute); *attrMask |= 1 << ATTR_COLOR0; if (lmode && !useHWTransform) { // only software transform supplies color1 as vertex data - WRITE(p, "%s lowp vec3 color1;\n", attribute); + WRITE(p, "%s lowp vec3 color1;\n", compat.attribute); *attrMask |= 1 << ATTR_COLOR1; } } @@ -335,21 +336,21 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM *uniformMask |= DIRTY_CULLRANGE; } - WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, varying); + WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, compat.varying); if (lmode) { - WRITE(p, "%s%s lowp vec3 v_color1;\n", shading, varying); + WRITE(p, "%s%s lowp vec3 v_color1;\n", shading, compat.varying); } if (doTexture) { - WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); + WRITE(p, "%s %s vec3 v_texcoord;\n", compat.varying, highpTexcoord ? "highp" : "mediump"); } if (enableFog) { // See the fragment shader generator if (highpFog) { - WRITE(p, "%s highp float v_fogdepth;\n", varying); + WRITE(p, "%s highp float v_fogdepth;\n", compat.varying); } else { - WRITE(p, "%s mediump float v_fogdepth;\n", varying); + WRITE(p, "%s mediump float v_fogdepth;\n", compat.varying); } } @@ -416,17 +417,17 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM for (int j = 0; j < 4; j++) { WRITE(p, " index_u = (%i + point_pos.x);\n", j); WRITE(p, " index_v = (%i + point_pos.y);\n", i); - WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index_u, index_v), 0).xyz;\n", i * 4 + j, texelFetch); + WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index_u, index_v), 0).xyz;\n", i * 4 + j, compat.texelFetch); if (doTexture && hasTexcoordTess) - WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts, index_v), 0).xy;\n", i * 4 + j, texelFetch); + WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts, index_v), 0).xy;\n", i * 4 + j, compat.texelFetch); if (hasColorTess) - WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts * 2, index_v), 0).rgba;\n", i * 4 + j, texelFetch); + WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts * 2, index_v), 0).rgba;\n", i * 4 + j, compat.texelFetch); } } // Basis polynomials as weight coefficients - WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(weight_idx.x * 2, 0)"); - WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(weight_idx.y * 2, 0)"); + WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.x * 2, 0)"); + WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.y * 2, 0)"); WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate @@ -443,8 +444,8 @@ bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrM WRITE(p, " tess.col = u_matambientalpha;\n"); if (hasNormalTess) { // Derivatives as weight coefficients - WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(weight_idx.x * 2 + 1, 0)"); - WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(weight_idx.y * 2 + 1, 0)"); + WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.x * 2 + 1, 0)"); + WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.y * 2 + 1, 0)"); WRITE(p, " vec3 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); WRITE(p, " vec3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n");