Prepare for more GLSL testing

This commit is contained in:
Henrik Rydgård 2020-10-21 23:39:34 +02:00
parent 3d36049b65
commit 2c0a3c2e23
5 changed files with 142 additions and 117 deletions

View file

@ -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;
};

View file

@ -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");
}
}
}

View file

@ -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) {

View file

@ -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<ReplaceAlphaType>(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;

View file

@ -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");