summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Software
diff options
context:
space:
mode:
authorcrudelios <crudelios@gmail.com>2014-09-14 17:52:51 +0100
committercrudelios <crudelios@gmail.com>2014-10-10 12:27:06 +0100
commit2d4b7e3f3f67f48ec2fb3d8eb8b2af3b70e4afcc (patch)
treef81d5e738022be0234af2033badc51adef39ba49 /Source/Core/VideoBackends/Software
parentb7aed97508ba74116858a111030bbd5783a633cb (diff)
Reimplement Bounding Box calculation using the software renderer.
Diffstat (limited to 'Source/Core/VideoBackends/Software')
-rw-r--r--Source/Core/VideoBackends/Software/BPMemLoader.cpp9
-rw-r--r--Source/Core/VideoBackends/Software/EfbInterface.cpp6
-rw-r--r--Source/Core/VideoBackends/Software/Rasterizer.cpp293
-rw-r--r--Source/Core/VideoBackends/Software/Tev.cpp212
4 files changed, 352 insertions, 168 deletions
diff --git a/Source/Core/VideoBackends/Software/BPMemLoader.cpp b/Source/Core/VideoBackends/Software/BPMemLoader.cpp
index f2aa429c49..bf11258cb0 100644
--- a/Source/Core/VideoBackends/Software/BPMemLoader.cpp
+++ b/Source/Core/VideoBackends/Software/BPMemLoader.cpp
@@ -14,6 +14,7 @@
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/TextureDecoder.h"
+#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/VideoCommon.h"
@@ -73,12 +74,12 @@ void SWBPWritten(int address, int newvalue)
EfbCopy::CopyEfb();
break;
case BPMEM_CLEARBBOX1:
- PixelEngine::bbox[0] = newvalue >> 10;
- PixelEngine::bbox[1] = newvalue & 0x3ff;
+ BoundingBox::coords[BoundingBox::LEFT] = newvalue >> 10;
+ BoundingBox::coords[BoundingBox::RIGHT] = newvalue & 0x3ff;
break;
case BPMEM_CLEARBBOX2:
- PixelEngine::bbox[2] = newvalue >> 10;
- PixelEngine::bbox[3] = newvalue & 0x3ff;
+ BoundingBox::coords[BoundingBox::TOP] = newvalue >> 10;
+ BoundingBox::coords[BoundingBox::BOTTOM] = newvalue & 0x3ff;
break;
case BPMEM_CLEAR_PIXEL_PERF:
// TODO: I didn't test if the value written to this register affects the amount of cleared registers
diff --git a/Source/Core/VideoBackends/Software/EfbInterface.cpp b/Source/Core/VideoBackends/Software/EfbInterface.cpp
index 8afae35bd8..172dd5ae23 100644
--- a/Source/Core/VideoBackends/Software/EfbInterface.cpp
+++ b/Source/Core/VideoBackends/Software/EfbInterface.cpp
@@ -437,12 +437,6 @@ namespace EfbInterface
{
SetPixelAlphaOnly(offset, dstClrPtr[ALP_C]);
}
-
- // branchless bounding box update
- PixelEngine::bbox[0] = std::min(x, PixelEngine::bbox[0]);
- PixelEngine::bbox[1] = std::max(x, PixelEngine::bbox[1]);
- PixelEngine::bbox[2] = std::min(y, PixelEngine::bbox[2]);
- PixelEngine::bbox[3] = std::max(y, PixelEngine::bbox[3]);
}
void SetColor(u16 x, u16 y, u8 *color)
diff --git a/Source/Core/VideoBackends/Software/Rasterizer.cpp b/Source/Core/VideoBackends/Software/Rasterizer.cpp
index 5e8fdffd50..d797b9158e 100644
--- a/Source/Core/VideoBackends/Software/Rasterizer.cpp
+++ b/Source/Core/VideoBackends/Software/Rasterizer.cpp
@@ -14,6 +14,7 @@
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/XFMemLoader.h"
+#include "VideoCommon/BoundingBox.h"
#define BLOCK_SIZE 2
@@ -130,7 +131,7 @@ inline void Draw(s32 x, s32 y, s32 xi, s32 yi)
if (z < 0 || z > 0x00ffffff)
return;
- if (bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc)
+ if (!BoundingBox::active && bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc)
{
// TODO: Test if perf regs are incremented even if test is disabled
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
@@ -317,7 +318,7 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
{
INCSTAT(swstats.thisFrame.numTrianglesDrawn);
- if (g_SWVideoConfig.bHwRasterizer)
+ if (g_SWVideoConfig.bHwRasterizer && !BoundingBox::active)
{
HwRasterizer::DrawTriangleFrontFace(v0, v1, v2);
return;
@@ -414,82 +415,252 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
- // Loop through blocks
- for (s32 y = miny; y < maxy; y += BLOCK_SIZE)
+ // If drawing, rasterize every block
+ if (!BoundingBox::active)
{
- for (s32 x = minx; x < maxx; x += BLOCK_SIZE)
+ // Loop through blocks
+ for (s32 y = miny; y < maxy; y += BLOCK_SIZE)
{
- // Corners of block
- s32 x0 = x << 4;
- s32 x1 = (x + BLOCK_SIZE - 1) << 4;
- s32 y0 = y << 4;
- s32 y1 = (y + BLOCK_SIZE - 1) << 4;
-
- // Evaluate half-space functions
- bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
- bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
- bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
- bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
- int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
-
- bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
- bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
- bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
- bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
- int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
-
- bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
- bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
- bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
- bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
- int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
-
- // Skip block when outside an edge
- if (a == 0x0 || b == 0x0 || c == 0x0)
- continue;
-
- BuildBlock(x, y);
-
- // Accept whole block when totally covered
- if (a == 0xF && b == 0xF && c == 0xF)
+ for (s32 x = minx; x < maxx; x += BLOCK_SIZE)
{
- for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
+ // Corners of block
+ s32 x0 = x << 4;
+ s32 x1 = (x + BLOCK_SIZE - 1) << 4;
+ s32 y0 = y << 4;
+ s32 y1 = (y + BLOCK_SIZE - 1) << 4;
+
+ // Evaluate half-space functions
+ bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
+ bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
+ bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
+ bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
+ int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
+
+ bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
+ bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
+ bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
+ bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
+ int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
+
+ bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
+ bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
+ bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
+ bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
+ int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
+
+ // Skip block when outside an edge
+ if (a == 0x0 || b == 0x0 || c == 0x0)
+ continue;
+
+ BuildBlock(x, y);
+
+ // Accept whole block when totally covered
+ if (a == 0xF && b == 0xF && c == 0xF)
{
- for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
+ for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
{
- Draw(x + ix, y + iy, ix, iy);
+ for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
+ {
+ Draw(x + ix, y + iy, ix, iy);
+ }
}
}
- }
- else // Partially covered block
- {
- s32 CY1 = C1 + DX12 * y0 - DY12 * x0;
- s32 CY2 = C2 + DX23 * y0 - DY23 * x0;
- s32 CY3 = C3 + DX31 * y0 - DY31 * x0;
-
- for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
+ else // Partially covered block
{
- s32 CX1 = CY1;
- s32 CX2 = CY2;
- s32 CX3 = CY3;
+ s32 CY1 = C1 + DX12 * y0 - DY12 * x0;
+ s32 CY2 = C2 + DX23 * y0 - DY23 * x0;
+ s32 CY3 = C3 + DX31 * y0 - DY31 * x0;
- for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
+ for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
{
- if (CX1 > 0 && CX2 > 0 && CX3 > 0)
+ s32 CX1 = CY1;
+ s32 CX2 = CY2;
+ s32 CX3 = CY3;
+
+ for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
{
- Draw(x + ix, y + iy, ix, iy);
+ if (CX1 > 0 && CX2 > 0 && CX3 > 0)
+ {
+ Draw(x + ix, y + iy, ix, iy);
+ }
+
+ CX1 -= FDY12;
+ CX2 -= FDY23;
+ CX3 -= FDY31;
}
- CX1 -= FDY12;
- CX2 -= FDY23;
- CX3 -= FDY31;
+ CY1 += FDX12;
+ CY2 += FDX23;
+ CY3 += FDX31;
}
+ }
+ }
+ }
+ }
+ else
+ {
+ // If we are only calculating bbox, we only need to find the topmost,
+ // leftmost, bottom most and rightmost pixels to be drawn.
+ // So instead of drawing every single one of the triangle's pixels,
+ // four loops are run: one for the top pixel, one for the left, one for
+ // the bottom and one for the right. As soon as a pixel that is to be
+ // drawn is found, the loop breaks. This enables a ~150% speedbost in
+ // bbox calculation, albeit at the cost of some ugly repetitive code.
+ const s32 FTOP = miny << 4;
+ const s32 FLEFT = minx << 4;
+ const s32 FBOTTOM = maxy << 4;
+ const s32 FRIGHT = maxx << 4;
+
+ // Start checking for bbox top
+ s32 CY1 = C1 + DX12 * FTOP - DY12 * FLEFT;
+ s32 CY2 = C2 + DX23 * FTOP - DY23 * FLEFT;
+ s32 CY3 = C3 + DX31 * FTOP - DY31 * FLEFT;
+
+ // Loop
+ for (s32 y = miny; y <= maxy; ++y)
+ {
+ if (y >= BoundingBox::coords[BoundingBox::TOP])
+ break;
+
+ s32 CX1 = CY1;
+ s32 CX2 = CY2;
+ s32 CX3 = CY3;
+
+ for (s32 x = minx; x <= maxx; ++x)
+ {
+ if (CX1 > 0 && CX2 > 0 && CX3 > 0)
+ {
+ // Build the new raster block every other pixel
+ BuildBlock((x & ~(BLOCK_SIZE - 1)), y & ~(BLOCK_SIZE - 1));
+
+ Draw(x, y, x & 1, y & 1);
+
+ if (y >= BoundingBox::coords[BoundingBox::TOP])
+ break;
+ }
+
+ CX1 -= FDY12;
+ CX2 -= FDY23;
+ CX3 -= FDY31;
+ }
+
+ CY1 += FDX12;
+ CY2 += FDX23;
+ CY3 += FDX31;
+ }
+
+ // Checking for bbox left
+ s32 CX1 = C1 + DX12 * FTOP - DY12 * FLEFT;
+ s32 CX2 = C2 + DX23 * FTOP - DY23 * FLEFT;
+ s32 CX3 = C3 + DX31 * FTOP - DY31 * FLEFT;
+
+ // Loop
+ for (s32 x = minx; x <= maxx; ++x)
+ {
+ if (x >= BoundingBox::coords[BoundingBox::LEFT])
+ break;
+
+ s32 CY1 = CX1;
+ s32 CY2 = CX2;
+ s32 CY3 = CX3;
+
+ for (s32 y = miny; y <= maxy; ++y)
+ {
+ if (CY1 > 0 && CY2 > 0 && CY3 > 0)
+ {
+ // Build the new raster block every other pixel
+ BuildBlock((x & ~(BLOCK_SIZE - 1)), y & ~(BLOCK_SIZE - 1));
+
+ Draw(x, y, x & 1, y & 1);
+
+ if (x >= BoundingBox::coords[BoundingBox::LEFT])
+ break;
+ }
+
+ CY1 += FDX12;
+ CY2 += FDX23;
+ CY3 += FDX31;
+ }
+
+ CX1 -= FDY12;
+ CX2 -= FDY23;
+ CX3 -= FDY31;
+ }
+
+ // Checking for bbox bottom
+ CY1 = C1 + DX12 * FBOTTOM - DY12 * FRIGHT;
+ CY2 = C2 + DX23 * FBOTTOM - DY23 * FRIGHT;
+ CY3 = C3 + DX31 * FBOTTOM - DY31 * FRIGHT;
+
+ // Loop
+ for (s32 y = maxy; y >= miny; --y)
+ {
+ s32 CX1 = CY1;
+ s32 CX2 = CY2;
+ s32 CX3 = CY3;
+
+ if (y <= BoundingBox::coords[BoundingBox::BOTTOM])
+ break;
+
+ for (s32 x = maxx; x >= minx; --x)
+ {
+ if (CX1 > 0 && CX2 > 0 && CX3 > 0)
+ {
+ // Build the new raster block every other pixel
+ BuildBlock((x & ~(BLOCK_SIZE - 1)), y & ~(BLOCK_SIZE - 1));
+
+ Draw(x, y, x & 1, y & 1);
- CY1 += FDX12;
- CY2 += FDX23;
- CY3 += FDX31;
+ if (y <= BoundingBox::coords[BoundingBox::BOTTOM])
+ break;
}
+
+ CX1 += FDY12;
+ CX2 += FDY23;
+ CX3 += FDY31;
+ }
+
+ CY1 -= FDX12;
+ CY2 -= FDX23;
+ CY3 -= FDX31;
+ }
+
+ // Checking for bbox right
+ CX1 = C1 + DX12 * FBOTTOM - DY12 * FRIGHT;
+ CX2 = C2 + DX23 * FBOTTOM - DY23 * FRIGHT;
+ CX3 = C3 + DX31 * FBOTTOM - DY31 * FRIGHT;
+
+ // Loop
+ for (s32 x = maxx; x >= minx; --x)
+ {
+ if (x <= BoundingBox::coords[BoundingBox::RIGHT])
+ break;
+
+ s32 CY1 = CX1;
+ s32 CY2 = CX2;
+ s32 CY3 = CX3;
+
+ for (s32 y = maxy; y >= miny; --y)
+ {
+ if (CY1 > 0 && CY2 > 0 && CY3 > 0)
+ {
+ // Build the new raster block every other pixel
+ BuildBlock((x & ~(BLOCK_SIZE - 1)), y & ~(BLOCK_SIZE - 1));
+
+ Draw(x, y, x & 1, y & 1);
+
+ if (x <= BoundingBox::coords[BoundingBox::RIGHT])
+ break;
+ }
+
+ CY1 -= FDX12;
+ CY2 -= FDX23;
+ CY3 -= FDX31;
}
+
+ CX1 += FDY12;
+ CX2 += FDY23;
+ CX3 += FDY31;
}
}
}
diff --git a/Source/Core/VideoBackends/Software/Tev.cpp b/Source/Core/VideoBackends/Software/Tev.cpp
index 7d13fd7bb2..122e1293da 100644
--- a/Source/Core/VideoBackends/Software/Tev.cpp
+++ b/Source/Core/VideoBackends/Software/Tev.cpp
@@ -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);
- // fog
- if (bpmem.fog.c_proj_fsel.fsel)
- {
- float ze;
+ }
- 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();
- 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
- }
+ // clamp 0 to 1
+ float fog = (ze<0.0f) ? 0.0f : ((ze>1.0f) ? 1.0f : ze);
- ze -= bpmem.fog.c_proj_fsel.GetC();
+ 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;
+ }
- // clamp 0 to 1
- float fog = (ze<0.0f) ? 0.0f : ((ze>1.0f) ? 1.0f : ze);
+ // lerp from output to fog color
+ u32 fogInt = (u32)(fog * 256);
+ u32 invFog = 256 - fogInt;
- 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;
+ 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;
}
- // lerp from output to fog color
- u32 fogInt = (u32)(fog * 256);
- u32 invFog = 256 - fogInt;
+ 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);
- 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;
+ if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
+ return;
+
+ EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
+ }
}
- 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);
+ // 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 (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
- return;
+ // if we are only calculating the bounding box,
+ // there's no need to actually draw anything
+ if (BoundingBox::active)
+ return;
- EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
- }
#if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages)