Reimplement Bounding Box calculation using the software renderer.

This commit is contained in:
crudelios 2014-09-14 17:52:51 +01:00
parent b7aed97508
commit 2d4b7e3f3f
13 changed files with 602 additions and 672 deletions

View file

@ -13,6 +13,7 @@
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TextureSampler.h"
#include "VideoBackends/Software/XFMemLoader.h"
#include "VideoCommon/BoundingBox.h"
#ifdef _DEBUG
#define ALLOW_TEV_DUMPS 1
@ -157,7 +158,7 @@ void Tev::SetRasColor(int colorChan, int swaptable)
RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2];
}
break;
case 5: // alpha bump
case 5: // alpha bump
{
for (s16& comp : RasColor)
{
@ -649,121 +650,138 @@ void Tev::Draw()
if (!TevAlphaTest(output[ALP_C]))
return;
// z texture
if (bpmem.ztex2.op)
// This part is only needed if we are not simply computing bbox
// (i. e., only needed when using the SW renderer)
if (!BoundingBox::active)
{
u32 ztex = bpmem.ztex1.bias;
switch (bpmem.ztex2.type)
// z texture
if (bpmem.ztex2.op)
{
case 0: // 8 bit
ztex += TexColor[ALP_C];
break;
case 1: // 16 bit
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
break;
case 2: // 24 bit
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
break;
u32 ztex = bpmem.ztex1.bias;
switch (bpmem.ztex2.type)
{
case 0: // 8 bit
ztex += TexColor[ALP_C];
break;
case 1: // 16 bit
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
break;
case 2: // 24 bit
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
break;
}
if (bpmem.ztex2.op == ZTEXTURE_ADD)
ztex += Position[2];
Position[2] = ztex & 0x00ffffff;
}
if (bpmem.ztex2.op == ZTEXTURE_ADD)
ztex += Position[2];
// fog
if (bpmem.fog.c_proj_fsel.fsel)
{
float ze;
Position[2] = ztex & 0x00ffffff;
if (bpmem.fog.c_proj_fsel.proj == 0)
{
// perspective
// ze = A/(B - (Zs >> B_SHF))
s32 denom = bpmem.fog.b_magnitude - (Position[2] >> bpmem.fog.b_shift);
//in addition downscale magnitude and zs to 0.24 bits
ze = (bpmem.fog.a.GetA() * 16777215.0f) / (float)denom;
}
else
{
// orthographic
// ze = a*Zs
//in addition downscale zs to 0.24 bits
ze = bpmem.fog.a.GetA() * ((float)Position[2] / 16777215.0f);
}
if (bpmem.fogRange.Base.Enabled)
{
// TODO: This is untested and should definitely be checked against real hw.
// - No idea if offset is really normalized against the viewport width or against the projection matrix or yet something else
// - scaling of the "k" coefficient isn't clear either.
// First, calculate the offset from the viewport center (normalized to 0..1)
float offset = (Position[0] - (bpmem.fogRange.Base.Center - 342)) / (float)xfmem.viewport.wd;
// Based on that, choose the index such that points which are far away from the z-axis use the 10th "k" value and such that central points use the first value.
float floatindex = 9.f - std::abs(offset) * 9.f;
floatindex = (floatindex < 0.f) ? 0.f : (floatindex > 9.f) ? 9.f : floatindex; // TODO: This shouldn't be necessary!
// Get the two closest integer indices, look up the corresponding samples
int indexlower = (int)floor(floatindex);
int indexupper = indexlower + 1;
// Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog is too strong without the factor)
float klower = bpmem.fogRange.K[indexlower/2].GetValue(indexlower%2) * 4.f;
float kupper = bpmem.fogRange.K[indexupper/2].GetValue(indexupper%2) * 4.f;
// linearly interpolate the samples and multiple ze by the resulting adjustment factor
float factor = indexupper - floatindex;
float k = klower * factor + kupper * (1.f - factor);
float x_adjust = sqrt(offset*offset + k*k)/k;
ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b
}
ze -= bpmem.fog.c_proj_fsel.GetC();
// clamp 0 to 1
float fog = (ze<0.0f) ? 0.0f : ((ze>1.0f) ? 1.0f : ze);
switch (bpmem.fog.c_proj_fsel.fsel)
{
case 4: // exp
fog = 1.0f - pow(2.0f, -8.0f * fog);
break;
case 5: // exp2
fog = 1.0f - pow(2.0f, -8.0f * fog * fog);
break;
case 6: // backward exp
fog = 1.0f - fog;
fog = pow(2.0f, -8.0f * fog);
break;
case 7: // backward exp2
fog = 1.0f - fog;
fog = pow(2.0f, -8.0f * fog * fog);
break;
}
// lerp from output to fog color
u32 fogInt = (u32)(fog * 256);
u32 invFog = 256 - fogInt;
output[RED_C] = (output[RED_C] * invFog + fogInt * bpmem.fog.color.r) >> 8;
output[GRN_C] = (output[GRN_C] * invFog + fogInt * bpmem.fog.color.g) >> 8;
output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8;
}
bool late_ztest = !bpmem.zcontrol.early_ztest || !g_SWVideoConfig.bZComploc;
if (late_ztest && bpmem.zmode.testenable)
{
// TODO: Check against hw if these values get incremented even if depth testing is disabled
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT);
if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
return;
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
}
}
// fog
if (bpmem.fog.c_proj_fsel.fsel)
{
float ze;
// branchless bounding box update
BoundingBox::coords[BoundingBox::LEFT] = std::min((u16)Position[0], BoundingBox::coords[BoundingBox::LEFT]);
BoundingBox::coords[BoundingBox::RIGHT] = std::max((u16)Position[0], BoundingBox::coords[BoundingBox::RIGHT]);
BoundingBox::coords[BoundingBox::TOP] = std::min((u16)Position[1], BoundingBox::coords[BoundingBox::TOP]);
BoundingBox::coords[BoundingBox::BOTTOM] = std::max((u16)Position[1], BoundingBox::coords[BoundingBox::BOTTOM]);
if (bpmem.fog.c_proj_fsel.proj == 0)
{
// perspective
// ze = A/(B - (Zs >> B_SHF))
s32 denom = bpmem.fog.b_magnitude - (Position[2] >> bpmem.fog.b_shift);
//in addition downscale magnitude and zs to 0.24 bits
ze = (bpmem.fog.a.GetA() * 16777215.0f) / (float)denom;
}
else
{
// orthographic
// ze = a*Zs
//in addition downscale zs to 0.24 bits
ze = bpmem.fog.a.GetA() * ((float)Position[2] / 16777215.0f);
// if we are only calculating the bounding box,
// there's no need to actually draw anything
if (BoundingBox::active)
return;
}
if (bpmem.fogRange.Base.Enabled)
{
// TODO: This is untested and should definitely be checked against real hw.
// - No idea if offset is really normalized against the viewport width or against the projection matrix or yet something else
// - scaling of the "k" coefficient isn't clear either.
// First, calculate the offset from the viewport center (normalized to 0..1)
float offset = (Position[0] - (bpmem.fogRange.Base.Center - 342)) / (float)xfmem.viewport.wd;
// Based on that, choose the index such that points which are far away from the z-axis use the 10th "k" value and such that central points use the first value.
float floatindex = 9.f - std::abs(offset) * 9.f;
floatindex = (floatindex < 0.f) ? 0.f : (floatindex > 9.f) ? 9.f : floatindex; // TODO: This shouldn't be necessary!
// Get the two closest integer indices, look up the corresponding samples
int indexlower = (int)floor(floatindex);
int indexupper = indexlower + 1;
// Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog is too strong without the factor)
float klower = bpmem.fogRange.K[indexlower/2].GetValue(indexlower%2) * 4.f;
float kupper = bpmem.fogRange.K[indexupper/2].GetValue(indexupper%2) * 4.f;
// linearly interpolate the samples and multiple ze by the resulting adjustment factor
float factor = indexupper - floatindex;
float k = klower * factor + kupper * (1.f - factor);
float x_adjust = sqrt(offset*offset + k*k)/k;
ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b
}
ze -= bpmem.fog.c_proj_fsel.GetC();
// clamp 0 to 1
float fog = (ze<0.0f) ? 0.0f : ((ze>1.0f) ? 1.0f : ze);
switch (bpmem.fog.c_proj_fsel.fsel)
{
case 4: // exp
fog = 1.0f - pow(2.0f, -8.0f * fog);
break;
case 5: // exp2
fog = 1.0f - pow(2.0f, -8.0f * fog * fog);
break;
case 6: // backward exp
fog = 1.0f - fog;
fog = pow(2.0f, -8.0f * fog);
break;
case 7: // backward exp2
fog = 1.0f - fog;
fog = pow(2.0f, -8.0f * fog * fog);
break;
}
// lerp from output to fog color
u32 fogInt = (u32)(fog * 256);
u32 invFog = 256 - fogInt;
output[RED_C] = (output[RED_C] * invFog + fogInt * bpmem.fog.color.r) >> 8;
output[GRN_C] = (output[GRN_C] * invFog + fogInt * bpmem.fog.color.g) >> 8;
output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8;
}
bool late_ztest = !bpmem.zcontrol.early_ztest || !g_SWVideoConfig.bZComploc;
if (late_ztest && bpmem.zmode.testenable)
{
// TODO: Check against hw if these values get incremented even if depth testing is disabled
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT);
if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
return;
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
}
#if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages)