Permalink
Browse files

GPU: Apply fog before color test.

Hardware tests confirm the fog result is what's color tested.
  • Loading branch information...
unknownbrackets committed Sep 10, 2018
1 parent 8eb011c commit 022670d8820a0f6cace4b9a0f3ad13903418f739
@@ -268,6 +268,11 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
WRITE(p, " float4 v = p;\n"); break;
}
}
if (enableColorDoubling) {
// This happens before fog is applied.
WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n");
}
} else {
// No texture mapping
WRITE(p, " float4 v = In.v_color0 %s;\n", secondary);
@@ -303,12 +308,13 @@ 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 = clamp(v.rgb * 2.0, 0.0, 1.0);\n");
}
if (enableFog) {
WRITE(p, " float fogCoef = clamp(In.v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = lerp(float4(u_fogcolor, v.a), v, fogCoef);\n");
}
if (enableColorTest) {
if (colorTestAgainstZero) {
// When testing against 0 (common), we can avoid some math.
// 0.002 is approximately half of 1.0 / 255.0.
@@ -342,24 +348,10 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
WRITE(p, lang == HLSL_DX9 ? " clip(-1);\n" : " discard;\n");
}
}
if (replaceBlend == REPLACE_BLEND_2X_SRC) {
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
}
} 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 = 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");
}
}
if (enableFog) {
WRITE(p, " float fogCoef = clamp(In.v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = lerp(float4(u_fogcolor, v.a), v, fogCoef);\n");
if (replaceBlend == REPLACE_BLEND_2X_SRC) {
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
}
if (replaceBlend == REPLACE_BLEND_PRE_SRC || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) {
@@ -500,11 +500,22 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
WRITE(p, " vec4 v = p;\n"); break;
}
}
if (enableColorDoubling) {
// This happens before fog is applied.
WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n");
}
} else {
// No texture mapping
WRITE(p, " vec4 v = v_color0 %s;\n", secondary);
}
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
// WRITE(p, " v.x = v_depth;\n");
}
// Texture access is at half texels [0.5/256, 255.5/256], but colors are normalized [0, 255].
// So we have to scale to account for the difference.
std::string alphaTestXCoord = "0";
@@ -558,14 +569,6 @@ 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 = clamp(v.rgb * 2.0, 0.0, 1.0);\n");
if (g_Config.bFragmentTestCache && !colorTestAgainstZero) {
WRITE(p, " vScale256.rgb = vScale256.rgb * 2.0;\n");
}
}
if (colorTestAgainstZero) {
// When testing against 0 (common), we can avoid some math.
// 0.002 is approximately half of 1.0 / 255.0.
@@ -608,25 +611,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
WRITE(p, " %s\n", discardStatement);
}
}
if (replaceBlend == REPLACE_BLEND_2X_SRC) {
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
}
} 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 = 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");
}
}
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
// WRITE(p, " v.x = v_depth;\n");
if (replaceBlend == REPLACE_BLEND_2X_SRC) {
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
}
if (replaceBlend == REPLACE_BLEND_PRE_SRC || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) {
@@ -910,14 +910,23 @@ inline void DrawSinglePixel(const DrawingCoords &p, u16 z, u8 fog, const Vec4<in
if (z < gstate.getDepthRangeMin() || z > gstate.getDepthRangeMax())
return;
if (gstate.isColorTestEnabled() && !clearMode)
if (!ColorTestPassed(prim_color.rgb()))
return;
if (gstate.isAlphaTestEnabled() && !clearMode)
if (!AlphaTestPassed(prim_color.a()))
return;
// Fog is applied prior to color test.
if (gstate.isFogEnabled() && !gstate.isModeThrough() && !clearMode) {
Vec3<int> fogColor = Vec3<int>::FromRGB(gstate.fogcolor);
fogColor = (prim_color.rgb() * (int)fog + fogColor * (255 - (int)fog)) / 255;
prim_color.r() = fogColor.r();
prim_color.g() = fogColor.g();
prim_color.b() = fogColor.b();
}
if (gstate.isColorTestEnabled() && !clearMode)
if (!ColorTestPassed(prim_color.rgb()))
return;
// In clear mode, it uses the alpha color as stencil.
u8 stencil = clearMode ? prim_color.a() : GetPixelStencil(p.x, p.y);
if (!clearMode && (gstate.isStencilTestEnabled() || gstate.isDepthTestEnabled())) {
@@ -945,14 +954,6 @@ inline void DrawSinglePixel(const DrawingCoords &p, u16 z, u8 fog, const Vec4<in
SetPixelDepth(p.x, p.y, z);
}
if (gstate.isFogEnabled() && !gstate.isModeThrough() && !clearMode) {
Vec3<int> fogColor = Vec3<int>::FromRGB(gstate.fogcolor);
fogColor = (prim_color.rgb() * (int)fog + fogColor * (255 - (int)fog)) / 255;
prim_color.r() = fogColor.r();
prim_color.g() = fogColor.g();
prim_color.b() = fogColor.b();
}
const u32 old_color = GetPixelColor(p.x, p.y);
u32 new_color;
@@ -339,6 +339,11 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) {
WRITE(p, " vec4 v = p;\n"); break;
}
}
if (enableColorDoubling) {
// This happens before fog is applied.
WRITE(p, " v.rgb = clamp(v.rgb * 2.0, 0.0, 1.0);\n");
}
} else {
// No texture mapping
WRITE(p, " vec4 v = v_color0 %s;\n", secondary);
@@ -374,12 +379,13 @@ 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 = clamp(v.rgb * 2.0, 0.0, 1.0);\n");
}
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(base.fogcolor, v.a), v, fogCoef);\n");
// WRITE(p, " v.x = v_depth;\n");
}
if (enableColorTest) {
if (colorTestAgainstZero) {
// When testing against 0 (common), we can avoid some math.
// Have my doubts that this special case is actually worth it, but whatever.
@@ -403,25 +409,10 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) {
WRITE(p, " %s\n", discardStatement);
}
}
if (replaceBlend == REPLACE_BLEND_2X_SRC) {
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
}
} 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 = 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");
}
}
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(base.fogcolor, v.a), v, fogCoef);\n");
// WRITE(p, " v.x = v_depth;\n");
if (replaceBlend == REPLACE_BLEND_2X_SRC) {
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
}
if (replaceBlend == REPLACE_BLEND_PRE_SRC || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) {

0 comments on commit 022670d

Please sign in to comment.