added r_alphaToCoverageMipBoost and did some other changes to A2C

- r_alphaToCoverageMipBoost scales the alpha value based on the current texture LoD
  this prevents the "fading with distance" effect
- mip 0 dimensions are tested to decide whether contrast boosting around 0.5 is enabled
  this is to deal with high r_picmip configs
- improved algorithm for excellent sharpness and minimized temporal artefacts
- GLSL 4.00 is required for the GL3 backend to use A2C (for textureQueryLod)
This commit is contained in:
myT 2020-07-07 03:49:52 +02:00
parent 180a0187b7
commit 7412c4b373
6 changed files with 64 additions and 18 deletions

View file

@ -4,10 +4,18 @@ See the end of this file for known issues.
DD Mmm 20 - 1.53
add: r_alphaToCoverageMipBoost <0.0 to 0.5> (default: 0.125) boosts the alpha value of higher mip levels
with A2C enabled, it prevents alpha-tested surfaces from fading (too much) in the distance
chg: with r_backend GL3, alpha to coverage now requires GLSL 4.00 at a minimum
fix: with alpha to coverage enabled, high r_picmip values should longer cause
alpha-tested surfaces to become transparent in the distance (e.g. q3wcp14 corridor floors)
fix: with r_backend GL3, shader uniforms caching could break with fog-only shaders
fix: with r_backend D3D11, partial clears incorrectly affected entire render targets
this was creating black views in CPMA multi-view with r_fastsky 1
example: black views in CPMA multi-view with r_fastsky 1
01 Jun 20 - 1.52

View file

@ -66,7 +66,7 @@ cbuffer PixelShaderBuffer
float invGamma;
float invBrightness;
float noiseScale;
float dummy;
float alphaBoost;
};
Texture2D texture0 : register(t0);
@ -101,10 +101,12 @@ float CorrectAlpha(float threshold, float alpha, float2 tc)
{
float w, h;
texture0.GetDimensions(w, h);
float dx = max(abs(ddx(tc.x * w)), 0.001);
float dy = max(abs(ddy(tc.y * h)), 0.001);
float dxy = max(dx, dy); // apply the smallest boost
float scale = max(1.0 / dxy, 1.0);
if(min(w, h) <= 8.0)
return alpha >= threshold ? 1.0 : 0.0;
alpha *= 1.0 + alphaBoost * texture0.CalculateLevelOfDetail(sampler0, tc);
float2 dtc = fwidth(tc * float2(w, h));
float recScale = max(0.25 * (dtc.x + dtc.y), 1.0 / 16384.0);
float scale = max(1.0 / recScale, 1.0);
float ac = threshold + (alpha - threshold) * scale;
return ac;
@ -132,10 +134,16 @@ float4 ps_main(VOut input) : SV_Target0
#endif
#ifdef CNQ3_A2C
// a < 0.5
// - a > -0.5
// 1.0 - a > 0.5
// 1.0 - a >= NextFloatAbove(0.5)
// 1.0 - a >= asfloat(0x3F000001)
// asfloat(0x3F000001) is 0.5 * 1.0000001192092896
if(alphaTest == 1)
r.a = r.a > 0.0 ? 1.0 : 0.0;
else if(alphaTest == 2)
r.a = CorrectAlpha(0.5, 1.0 - r.a, input.texCoords);
r.a = CorrectAlpha(asfloat(0x3F000001), 1.0 - r.a, input.texCoords);
else if(alphaTest == 3)
r.a = CorrectAlpha(0.5, r.a, input.texCoords);
#else

View file

@ -188,7 +188,7 @@ struct GenericPSData
float invGamma;
float invBrightness;
float noiseScale;
float dummy;
float alphaBoost;
};
struct DepthFadeVSData
@ -735,6 +735,7 @@ static void UploadPendingShaderData()
psData.invGamma = 1.0f / r_gamma->value;
psData.invBrightness = 1.0f / r_brightness->value;
psData.noiseScale = backEnd.projection2D ? 0.0f : r_ditherStrength->value;
psData.alphaBoost = r_alphaToCoverageMipBoost->value;
ResetShaderData(pipeline->vertexBuffer, &vsData, sizeof(vsData));
ResetShaderData(pipeline->pixelBuffer, &psData, sizeof(psData));
}

View file

@ -38,6 +38,7 @@ Current info:
- fancy mip-map generations requires:
- OpenGL 4.3 (or equivalent extensions)
- GLSL 4.30
- alpha to coverage requires GLSL 4.00
Vertex and index data streaming notes:
- everyone: persistent coherent buffer mapping is the best option whenever available
@ -149,7 +150,8 @@ enum GenericUniform
GU_PROJECTION,
GU_CLIP_PLANE,
GU_ALPHA_TEX,
GU_GAMMA_BRIGHT_NOISE_SEED, // @NOTE: not always defined
GU_GAMMA_BRIGHT_NOISE_SEED, // only defined when dithering is enabled
GU_A2C_ALPHA_BOOST, // only defined when alpha to coverage is enabled
GU_COUNT
};
@ -322,6 +324,9 @@ static const char* generic_fs =
"#define noiseScale gammaBrightNoiseSeed.z\n"
"#define seed gammaBrightNoiseSeed.w\n"
"#endif\n"
"#ifdef CNQ3_A2C\n"
"uniform float alphaBoost;\n"
"#endif\n"
"\n"
"centroid in vec2 texCoords1FS;\n"
"centroid in vec2 texCoords2FS;\n"
@ -354,10 +359,12 @@ static const char* generic_fs =
"float CorrectAlpha(float threshold, float alpha, vec2 tc)\n"
"{\n"
" vec2 size = vec2(textureSize(texture1, 0));\n"
" float dx = max(abs(dFdx(tc.x * size.x)), 0.001);\n"
" float dy = max(abs(dFdy(tc.y * size.y)), 0.001);\n"
" float dxy = max(dx, dy); // apply the smallest boost\n"
" float scale = max(1.0 / dxy, 1.0);\n"
" if(min(size.x, size.y) <= 8.0)\n"
" return alpha >= threshold ? 1.0 : 0.0;\n"
" alpha *= 1.0 + alphaBoost * textureQueryLod(texture1, tc).x;"
" vec2 dtc = fwidth(tc * size);\n"
" float recScale = max(0.25 * (dtc.x + dtc.y), 1.0 / 16384.0);\n"
" float scale = max(1.0 / recScale, 1.0);\n"
" float ac = threshold + (alpha - threshold) * scale;\n"
"\n"
" return ac;\n"
@ -388,7 +395,7 @@ static const char* generic_fs =
" if(alphaTest == uint(1))\n"
" r.a = r.a > 0.0 ? 1.0 : 0.0;\n"
" if(alphaTest == uint(2))\n"
" r.a = CorrectAlpha(0.5, 1.0 - r.a, texCoords1FS);\n"
" r.a = CorrectAlpha(uintBitsToFloat(0x3F000001), 1.0 - r.a, texCoords1FS);\n"
" else if(alphaTest == uint(3))\n"
" r.a = CorrectAlpha(0.5, r.a, texCoords1FS);\n"
"#else\n"
@ -798,12 +805,21 @@ static const char* GetShaderTypeName(GLenum shaderType)
static qbool CreateShader(GLuint* shaderPtr, PipelineId pipelineId, GLenum shaderType, const char* shaderSource, const char* debugName)
{
// A2C now requires GLSL 4.00 for textureQueryLod
const qbool enableA2C =
pipelineId == PID_GENERIC &&
shaderType == GL_FRAGMENT_SHADER &&
glInfo.alphaToCoverageSupport;
const qbool enableDithering =
pipelineId == PID_GENERIC &&
shaderType == GL_FRAGMENT_SHADER &&
r_dither->integer;
const char* sourceArray[] =
{
shaderType == GL_COMPUTE_SHADER ? "#version 430\n" : "#version 140\n",
shaderType == GL_COMPUTE_SHADER ? "#version 430\n" : (enableA2C ? "#version 400\n" : "#version 140\n"),
"\n",
pipelineId == PID_GENERIC && glInfo.alphaToCoverageSupport && shaderType == GL_FRAGMENT_SHADER ? "#define CNQ3_A2C 1\n" : "#define CNQ3_A2C 0\n",
pipelineId == PID_GENERIC && r_dither->integer && shaderType == GL_FRAGMENT_SHADER ? "#define CNQ3_DITHER 1\n" : "#define CNQ3_DITHER 0\n",
enableA2C ? "#define CNQ3_A2C 1\n" : "#define CNQ3_A2C 0\n",
enableDithering ? "#define CNQ3_DITHER 1\n" : "#define CNQ3_DITHER 0\n",
shaderSource
};
@ -1904,6 +1920,7 @@ static void Init()
gl.pipelines[PID_GENERIC].uniformNames[GU_CLIP_PLANE] = "clipPlane";
gl.pipelines[PID_GENERIC].uniformNames[GU_ALPHA_TEX] = "alphaTex";
gl.pipelines[PID_GENERIC].uniformNames[GU_GAMMA_BRIGHT_NOISE_SEED] = "gammaBrightNoiseSeed";
gl.pipelines[PID_GENERIC].uniformNames[GU_A2C_ALPHA_BOOST] = "alphaBoost";
gl.pipelines[PID_DYNAMIC_LIGHT].arrayBuffers[VB_POSITION].enabled = qtrue;
gl.pipelines[PID_DYNAMIC_LIGHT].arrayBuffers[VB_POSITION].attribName = "position";
@ -1964,7 +1981,8 @@ static void Init()
{
pipeline->uniformLocations[i] = glGetUniformLocation(pipeline->program.program, pipeline->uniformNames[i]);
#if defined(_DEBUG)
if(!(r_dither->integer == 0 && p == PID_GENERIC && i == GU_GAMMA_BRIGHT_NOISE_SEED))
if(!(r_dither->integer == 0 && p == PID_GENERIC && i == GU_GAMMA_BRIGHT_NOISE_SEED) &&
!(r_alphaToCoverage->integer == 0 && p == PID_GENERIC && i == GU_A2C_ALPHA_BOOST))
{
assert(pipeline->uniformLocations[i] != -1);
}
@ -2168,6 +2186,12 @@ static void DrawGeneric()
(float)rand() / (float)RAND_MAX);
pipeline->uniformsDirty[GU_GAMMA_BRIGHT_NOISE_SEED] = qfalse;
}
if(pipeline->uniformsDirty[GU_A2C_ALPHA_BOOST] &&
pipeline->uniformLocations[GU_A2C_ALPHA_BOOST] != -1)
{
glUniform1f(pipeline->uniformLocations[GU_A2C_ALPHA_BOOST], r_alphaToCoverageMipBoost->value);
pipeline->uniformsDirty[GU_A2C_ALPHA_BOOST] = qfalse;
}
UploadVertexArray(VB_POSITION, tess.xyz);
UploadIndices(tess.indexes, tess.numIndexes);

View file

@ -104,6 +104,8 @@ cvar_t *r_portalOnly;
cvar_t *r_subdivisions;
cvar_t *r_lodCurveError;
cvar_t *r_alphaToCoverageMipBoost;
cvar_t *r_width;
cvar_t *r_height;
cvar_t *r_customaspect;
@ -411,6 +413,7 @@ static const cvarTableItem_t r_cvars[] =
{ &r_ditherStrength, "r_ditherStrength", "1.0", CVAR_ARCHIVE, CVART_FLOAT, "0.125", "8.0", help_r_ditherStrength },
{ &r_transpSort, "r_transpSort", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_transpSort },
{ &r_lodCurveError, "r_lodCurveError", "2000", CVAR_ARCHIVE, CVART_FLOAT, "250", "10000", "curved surfaces LOD scale" },
{ &r_alphaToCoverageMipBoost, "r_alphaToCoverageMipBoost", "0.125", CVAR_ARCHIVE, CVART_FLOAT, "0", "0.5", "increases the alpha value of higher mip levels" },
//
// temporary variables that can change at any time

View file

@ -1051,6 +1051,8 @@ extern cvar_t *r_portalOnly;
extern cvar_t *r_subdivisions;
extern cvar_t *r_lodCurveError;
extern cvar_t *r_alphaToCoverageMipBoost; // increases the alpha value of higher mip levels
extern cvar_t *r_ignoreGLErrors;
extern cvar_t *r_brightness;