Skip to content

Commit

Permalink
Merge pull request #16485 from unknownbrackets/softgpu-fog-nan
Browse files Browse the repository at this point in the history
softgpu: Handle infnan fog coefficients better
  • Loading branch information
hrydgard committed Dec 2, 2022
2 parents a349e2b + 1121a6f commit 116bc9d
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 38 deletions.
69 changes: 39 additions & 30 deletions Common/Math/expression_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,45 +59,54 @@ const ExpressionOpcode ExpressionOpcodes[] = {
{ "", 0, 0, 0, false } // EXOP_NONE
};

bool parseNumber(char* str, int defaultrad, int len, uint32_t& result)
{
static int radixFromZeroPrefix(char c) {
switch (tolower(c)) {
case 'b': return 2;
case 'o': return 8;
case 'x': return 16;
// Inventing a prefix since we default to hex.
case 'd': return 10;
}

return -1;
}

static int radixFromSuffix(char c, int defaultrad) {
switch (tolower(c)) {
case 'o': return 8;
case 'h': return 16;
case 'i': return 10;
case 'u': return 10;
case 'b': return defaultrad == 16 ? -1 : 2;
}

return -1;
}

bool parseNumber(char *str, int defaultrad, int len, uint32_t &result) {
int val = 0;
int r = 0;
if (len == 0) len = (int) strlen(str);

if (str[0] == '0' && tolower(str[1]) == 'x')
{
r = 16;
str+=2;
len-=2;
} else if (str[0] == '$')
{
if (len == 0)
len = (int)strlen(str);

if (str[0] == '0' && radixFromZeroPrefix(str[1]) != -1) {
r = radixFromZeroPrefix(str[1]);
str += 2;
len -= 2;
} else if (str[0] == '$') {
r = 16;
str++;
len--;
} else if (str[0] == '0' && tolower(str[1]) == 'o')
{
r = 8;
str+=2;
len-=2;
} else {
if (!(str[0] >= '0' && str[0] <= '9')) return false;

if (tolower(str[len-1]) == 'b' && defaultrad != 16)
{
r = 2;
len--;
} else if (tolower(str[len-1]) == 'o')
{
r = 8;
len--;
} else if (tolower(str[len-1]) == 'h')
{
r = 16;
} else if (str[0] >= '0' && str[0] <= '9') {
int suffix = radixFromSuffix(str[len - 1], defaultrad);
if (suffix != -1) {
r = suffix;
len--;
} else {
r = defaultrad;
}
} else {
return false;
}

switch (r)
Expand Down
11 changes: 11 additions & 0 deletions GPU/Common/GPUDebugInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Common/Math/expression_parser.h"
#include "Core/Debugger/SymbolMap.h"
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Debugger/GECommandTable.h"
#include "GPU/GPUState.h"

Expand All @@ -34,6 +35,8 @@ enum class GEReferenceIndex : uint32_t {
CLUTADDR,
TRANSFERSRC,
TRANSFERDST,
PRIMCOUNT,
LASTPRIMCOUNT,

TEXADDR0,
TEXADDR1,
Expand Down Expand Up @@ -74,6 +77,8 @@ static constexpr ReferenceName referenceNames[] = {
{ GEReferenceIndex::CLUTADDR, "clutaddr" },
{ GEReferenceIndex::TRANSFERSRC, "transfersrc" },
{ GEReferenceIndex::TRANSFERDST, "transferdst" },
{ GEReferenceIndex::PRIMCOUNT, "primcount" },
{ GEReferenceIndex::LASTPRIMCOUNT, "lastprimcount" },
{ GEReferenceIndex::TEXADDR0, "texaddr0" },
{ GEReferenceIndex::TEXADDR1, "texaddr1" },
{ GEReferenceIndex::TEXADDR2, "texaddr2" },
Expand Down Expand Up @@ -695,6 +700,12 @@ uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) {
case GEReferenceIndex::TRANSFERDST:
return state.getTransferDstAddress();

case GEReferenceIndex::PRIMCOUNT:
return GPUDebug::PrimsThisFrame();

case GEReferenceIndex::LASTPRIMCOUNT:
return GPUDebug::PrimsLastFrame();

case GEReferenceIndex::TEXADDR0:
case GEReferenceIndex::TEXADDR1:
case GEReferenceIndex::TEXADDR2:
Expand Down
33 changes: 25 additions & 8 deletions GPU/Software/TransformUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,17 +295,34 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) {
if (state->enableFog) {
float fogEnd = getFloat24(gstate.fog1);
float fogSlope = getFloat24(gstate.fog2);
// Same fixup as in ShaderManagerGLES.cpp
if (my_isnanorinf(fogEnd)) {
fogEnd = std::signbit(fogEnd) ? -INFINITY : INFINITY;
}
if (my_isnanorinf(fogSlope)) {
fogSlope = std::signbit(fogSlope) ? -INFINITY : INFINITY;
}

// We bake fog end and slope into the dot product.
state->posToFog = Vec4f(worldview[2], worldview[6], worldview[10], worldview[14] + fogEnd);
state->posToFog *= fogSlope;

// If either are NAN/INF, we simplify so there's no inf + -inf muddying things.
// This is required for Outrun to render proper skies, for example.
// The PSP treats these exponents as if they were valid.
if (my_isnanorinf(fogEnd)) {
bool sign = std::signbit(fogEnd);
// The multiply would reverse it if it wasn't infinity (doesn't matter if it's infnan.)
if (std::signbit(fogSlope))
sign = !sign;
// Also allow a multiply by zero (slope) to result in zero, regardless of sign.
// Act like it was negative and clamped to zero.
if (fogSlope == 0.0f)
sign = true;

// Since this is constant for the entire draw, we don't even use infinity.
float forced = sign ? 0.0f : 1.0f;
state->posToFog = Vec4f(0.0f, 0.0f, 0.0f, forced);
} else if (my_isnanorinf(fogSlope)) {
// We can't have signs differ with infinities, so we use a large value.
// Anything outside [0, 1] will clamp, so this essentially forces extremes.
fogSlope = std::signbit(fogSlope) ? -262144.0f : 262144.0f;
state->posToFog *= fogSlope;
} else {
state->posToFog *= fogSlope;
}
}

state->screenScale = Vec3f(gstate.getViewportXScale(), gstate.getViewportYScale(), gstate.getViewportZScale());
Expand Down

0 comments on commit 116bc9d

Please sign in to comment.