OpenGL Renderer / SoftRasterizer: Properly handle cases where FogShiftSHR is greater than 10. Related to commit 9f4f3ec.

This commit is contained in:
rogerman 2021-09-09 19:54:06 -07:00
parent 9f4f3ecf95
commit df18eda84f
3 changed files with 43 additions and 17 deletions

View File

@ -550,19 +550,28 @@ void main()\n\
\n\
if (polyEnableFog)\n\
{\n\
float fogMixWeight = 0.0;\n\
int inFragDepthi = int( (inFragDepth * 32767.0) + 0.5 );\n\
int diffi = inFragDepthi - FOG_OFFSET + (FOG_STEP - 1);\n\
\n\
float interp = 1.0;\n\
if ( (inFragDepth > FOG_DEPTH_COMPARE_0) && (inFragDepth < FOG_DEPTH_COMPARE_31) )\n\
if (FOG_STEP == 0)\n\
{\n\
interp = float( (diffi & FOG_WEIGHT_TRUNCATE_MASK) + FOG_OFFSET - inFragDepthi ) / float(FOG_STEP);\n\
fogMixWeight = (inFragDepthi <= FOG_OFFSET) ? state.fogDensity[0].r : state.fogDensity[31].r;\n\
}\n\
else\n\
{\n\
int diffi = inFragDepthi - FOG_OFFSET + (FOG_STEP - 1);\n\
\n\
float interp = 1.0;\n\
if ( (inFragDepth > FOG_DEPTH_COMPARE_0) && (inFragDepth < FOG_DEPTH_COMPARE_31) )\n\
{\n\
interp = float( (diffi & FOG_WEIGHT_TRUNCATE_MASK) + FOG_OFFSET - inFragDepthi ) / float(FOG_STEP);\n\
}\n\
\n\
int idx = (diffi >> FOG_SHIFT_INV) - 1;\n\
idx = (idx < 1) ? 0 : (idx > 31) ? 31 : idx;\n\
\n\
fogMixWeight = mix(state.fogDensity[idx].r, state.fogDensity[idx].g, interp);\n\
}\n\
\n\
int idx = (diffi >> FOG_SHIFT_INV) - 1;\n\
idx = (idx < 1) ? 0 : (idx > 31) ? 31 : idx;\n\
\n\
float fogMixWeight = mix(state.fogDensity[idx].r, state.fogDensity[idx].g, interp);\n\
\n\
#if USE_DUAL_SOURCE_BLENDING\n\
outFogWeight = (state.enableFogAlphaOnly) ? vec4(vec3(0.0), fogMixWeight) : vec4(fogMixWeight);\n\
@ -1549,8 +1558,8 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro
const u32 fogOffset = fogProgramKey.offset;
const u32 fogStep = (0x0400 >> fogProgramKey.shift);
const u32 fogShiftInv = 10 - fogProgramKey.shift;
const u32 fogWeightTruncateMask = ~(fogStep - 1);
const u32 fogShiftInv = 10 - fogProgramKey.shift; // Rolls over if fogStep is 0 (do not use in this case)
const u32 fogWeightTruncateMask = ~(fogStep - 1); // Rolls over if fogStep is 0 (do not use in this case)
const GLfloat fogDepthCompare0 = std::min<GLfloat>((GLfloat)(fogOffset + (fogStep * 1)) / 32767.0f, 1.0f);
const GLfloat fogDepthCompare31 = std::min<GLfloat>((GLfloat)(fogOffset + (fogStep * 32)) / 32767.0f, 1.0f);

View File

@ -3093,11 +3093,12 @@ void gfx3d_parseCurrentDISP3DCNT()
gfx3d.state.enableEdgeMarking = (DISP3DCNT.EnableEdgeMarking != 0);
gfx3d.state.enableFogAlphaOnly = (DISP3DCNT.FogOnlyAlpha != 0);
gfx3d.state.enableFog = (DISP3DCNT.EnableFog != 0);
gfx3d.state.fogShift = (DISP3DCNT.FogShiftSHR <= 10) ? DISP3DCNT.FogShiftSHR : 11; // According to GBATEK, values higher than 10 force FogStep (0x400 >> FogShiftSHR) to become 0. So set FogShiftSHR to 11 in this case.
// TODO: Handle divide-by-zero cases of FogShiftSHR in SoftRasterizer and OpenGL.
// The fog weight is calculated using FogShiftSHR. However, if FogShiftSHR == 0, then this calculation can become a problem.
// We'll need to deal with the zero case at some point in the future.
gfx3d.state.enableClearImage = (DISP3DCNT.RearPlaneMode != 0);
// According to GBATEK, values greater than 10 force FogStep (0x400 >> FogShiftSHR) to become 0.
// So set FogShiftSHR to 11 in this case so that calculations using (0x400 >> FogShiftSHR) will
// equal 0.
gfx3d.state.fogShift = (DISP3DCNT.FogShiftSHR <= 10) ? DISP3DCNT.FogShiftSHR : 11;
}
void ParseReg_DISP3DCNT()

View File

@ -2114,9 +2114,25 @@ void SoftRasterizerRenderer::_UpdateEdgeMarkColorTable(const u16 *edgeMarkColorT
void SoftRasterizerRenderer::_UpdateFogTable(const u8 *fogDensityTable)
{
const s32 fogStep = 0x400 >> this->currentRenderState->fogShift;
const s32 fogShiftInv = 10 - this->currentRenderState->fogShift;
const s32 fogOffset = min<s32>( max<s32>((s32)this->currentRenderState->fogOffset, 0), 32768 );
const s32 fogStep = 0x400 >> this->currentRenderState->fogShift;
if (fogStep <= 0)
{
const s32 iMin = min<s32>( max<s32>(fogOffset, 0), 32768);
const s32 iMax = min<s32>( max<s32>(fogOffset + 1, 0), 32768);
// If the fog factor is 127, then treat it as 128.
u8 fogWeight = (fogDensityTable[0] >= 127) ? 128 : fogDensityTable[0];
memset(this->_fogTable, fogWeight, iMin);
fogWeight = (fogDensityTable[31] >= 127) ? 128 : fogDensityTable[31];
memset(this->_fogTable+iMax, fogWeight, 32768-iMax);
return;
}
const s32 fogShiftInv = 10 - this->currentRenderState->fogShift;
const s32 iMin = min<s32>( max<s32>((( 1 + 1) << fogShiftInv) + fogOffset + 1 - fogStep, 0), 32768);
const s32 iMax = min<s32>( max<s32>(((32 + 1) << fogShiftInv) + fogOffset + 1 - fogStep, 0), 32768);
assert(iMin <= iMax);