From 2d4b7e3f3f67f48ec2fb3d8eb8b2af3b70e4afcc Mon Sep 17 00:00:00 2001 From: crudelios Date: Sun, 14 Sep 2014 17:52:51 +0100 Subject: Reimplement Bounding Box calculation using the software renderer. --- Source/Core/VideoBackends/Software/BPMemLoader.cpp | 9 +- .../Core/VideoBackends/Software/EfbInterface.cpp | 6 - Source/Core/VideoBackends/Software/Rasterizer.cpp | 293 ++++++++++++++++----- Source/Core/VideoBackends/Software/Tev.cpp | 212 ++++++++------- 4 files changed, 352 insertions(+), 168 deletions(-) (limited to 'Source/Core/VideoBackends/Software') 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) -- cgit v1.2.3