diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp index dd747c4513..fb2fbddbcd 100644 --- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp +++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp @@ -76,9 +76,6 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std choice_backend->Disable(); } - // rasterizer - szr_rendering->Add(new SettingCheckBox(page_general, _("Hardware rasterization"), "", vconfig.bHwRasterizer)); - // xfb szr_rendering->Add(new SettingCheckBox(page_general, _("Bypass XFB"), "", vconfig.bBypassXFB)); } diff --git a/Source/Core/VideoBackends/Software/CMakeLists.txt b/Source/Core/VideoBackends/Software/CMakeLists.txt index 089261adcc..7b86ffae5c 100644 --- a/Source/Core/VideoBackends/Software/CMakeLists.txt +++ b/Source/Core/VideoBackends/Software/CMakeLists.txt @@ -5,7 +5,6 @@ set(SRCS BPMemLoader.cpp DebugUtil.cpp EfbCopy.cpp EfbInterface.cpp - HwRasterizer.cpp SWmain.cpp OpcodeDecoder.cpp RasterFont.cpp diff --git a/Source/Core/VideoBackends/Software/DebugUtil.cpp b/Source/Core/VideoBackends/Software/DebugUtil.cpp index 4f7d732c0b..7be0692088 100644 --- a/Source/Core/VideoBackends/Software/DebugUtil.cpp +++ b/Source/Core/VideoBackends/Software/DebugUtil.cpp @@ -11,7 +11,6 @@ #include "VideoBackends/Software/BPMemLoader.h" #include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/EfbInterface.h" -#include "VideoBackends/Software/HwRasterizer.h" #include "VideoBackends/Software/SWCommandProcessor.h" #include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWStatistics.h" @@ -25,8 +24,6 @@ namespace DebugUtil { -static bool drawingHwTriangles = false; - static const int NUM_OBJECT_BUFFERS = 40; static u32 *ObjectBuffer[NUM_OBJECT_BUFFERS]; @@ -207,12 +204,6 @@ void OnObjectBegin() { if (g_SWVideoConfig.bDumpTextures && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd) DumpActiveTextures(); - - if (g_SWVideoConfig.bHwRasterizer) - { - HwRasterizer::BeginTriangles(); - drawingHwTriangles = true; - } } } @@ -225,12 +216,6 @@ void OnObjectEnd() File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), swstats.thisFrame.numDrawnObjects)); - if (g_SWVideoConfig.bHwRasterizer || drawingHwTriangles) - { - HwRasterizer::EndTriangles(); - drawingHwTriangles = false; - } - for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) { if (DrawnToBuffer[i]) diff --git a/Source/Core/VideoBackends/Software/EfbCopy.cpp b/Source/Core/VideoBackends/Software/EfbCopy.cpp index 688a5cddb9..42759e20e9 100644 --- a/Source/Core/VideoBackends/Software/EfbCopy.cpp +++ b/Source/Core/VideoBackends/Software/EfbCopy.cpp @@ -9,7 +9,6 @@ #include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/EfbCopy.h" #include "VideoBackends/Software/EfbInterface.h" -#include "VideoBackends/Software/HwRasterizer.h" #include "VideoBackends/Software/SWCommandProcessor.h" #include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWStatistics.h" @@ -31,47 +30,41 @@ namespace EfbCopy { GLInterface->Update(); // update the render window position and the backbuffer size - if (!g_SWVideoConfig.bHwRasterizer) + INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f", + xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma); + + if (!g_SWVideoConfig.bBypassXFB) { - INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f", - xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma); + EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed *) Memory::GetPointer(xfbAddr); - if (!g_SWVideoConfig.bBypassXFB) - { - EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed *) Memory::GetPointer(xfbAddr); + EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma); + } + else + { + // Ask SWRenderer for the next color texture + u8 *colorTexture = SWRenderer::GetNextColorTexture(); - EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma); - } - else - { - // Ask SWRenderer for the next color texture - u8 *colorTexture = SWRenderer::GetNextColorTexture(); + EfbInterface::BypassXFB(colorTexture, fbWidth, fbHeight, sourceRc, Gamma); - EfbInterface::BypassXFB(colorTexture, fbWidth, fbHeight, sourceRc, Gamma); + // Tell SWRenderer we are now finished with it. + SWRenderer::SwapColorTexture(); - // Tell SWRenderer we are now finished with it. - SWRenderer::SwapColorTexture(); - - // FifoPlayer is broken and never calls BeginFrame/EndFrame. - // Hence, we manually force a swap now. This emulates the behavior - // of hardware backends with XFB emulation disabled. - // TODO: Fix FifoPlayer by making proper use of VideoInterface! - // This requires careful synchronization since GPU commands - // are processed on a different thread than VI commands. - SWRenderer::Swap(fbWidth, fbHeight); - DebugUtil::OnFrameEnd(fbWidth, fbHeight); - } + // FifoPlayer is broken and never calls BeginFrame/EndFrame. + // Hence, we manually force a swap now. This emulates the behavior + // of hardware backends with XFB emulation disabled. + // TODO: Fix FifoPlayer by making proper use of VideoInterface! + // This requires careful synchronization since GPU commands + // are processed on a different thread than VI commands. + SWRenderer::Swap(fbWidth, fbHeight); + DebugUtil::OnFrameEnd(fbWidth, fbHeight); } } static void CopyToRam() { - if (!g_SWVideoConfig.bHwRasterizer) - { - u8 *dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5); + u8 *dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5); - TextureEncoder::Encode(dest_ptr); - } + TextureEncoder::Encode(dest_ptr); } static void ClearEfb() @@ -138,10 +131,7 @@ namespace EfbCopy if (bpmem.triggerEFBCopy.clear) { - if (g_SWVideoConfig.bHwRasterizer) - HwRasterizer::Clear(); - else - ClearEfb(); + ClearEfb(); } } } diff --git a/Source/Core/VideoBackends/Software/HwRasterizer.cpp b/Source/Core/VideoBackends/Software/HwRasterizer.cpp deleted file mode 100644 index 7ddf15bb38..0000000000 --- a/Source/Core/VideoBackends/Software/HwRasterizer.cpp +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright 2009 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "Common/CommonTypes.h" -#include "Common/MemoryUtil.h" - -#include "VideoBackends/OGL/GLInterfaceBase.h" -#include "VideoBackends/Software/BPMemLoader.h" -#include "VideoBackends/Software/DebugUtil.h" -#include "VideoBackends/Software/HwRasterizer.h" -#include "VideoBackends/Software/NativeVertexFormat.h" - -#include "VideoCommon/VideoCommon.h" - -#define TEMP_SIZE (1024*1024*4) - -namespace HwRasterizer -{ - static float efbHalfWidth; - static float efbHalfHeight; - static bool hasTexture; - - static u8 *temp; - - // Programs - static GLuint colProg, texProg, clearProg; - - // Texture type - static GLenum texType; - - // Color - static GLint col_apos = -1, col_atex = -1; - // Tex - static GLint tex_apos = -1, tex_atex = -1, tex_utex = -1; - // Clear shader - static GLint clear_apos = -1, clear_ucol = -1; - - static void CreateShaders() - { - // Color Vertices - static const char *fragcolText = - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" - "varying vec4 TexCoordOut;\n" - "void main() {\n" - " gl_FragColor = TexCoordOut;\n" - "}\n"; - // Texture Vertices - static const char *fragtexText = - "#ifdef GL_ES\n" - "precision highp float;\n" - "#define texture2DRect texture2D\n" - "#define sampler2DRect sampler2D\n" - "#endif\n" - "varying vec4 TexCoordOut;\n" - "uniform sampler2DRect Texture;\n" - "void main() {\n" - " gl_FragColor = texture2DRect(Texture, TexCoordOut.xy);\n" - "}\n"; - // Clear shader - static const char *fragclearText = - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" - "uniform vec4 Color;\n" - "void main() {\n" - " gl_FragColor = Color;\n" - "}\n"; - // Generic passthrough vertice shaders - static const char *vertShaderText = - "attribute vec4 pos;\n" - "attribute vec4 TexCoordIn;\n " - "varying vec4 TexCoordOut;\n " - "void main() {\n" - " gl_Position = pos;\n" - " TexCoordOut = TexCoordIn;\n" - "}\n"; - static const char *vertclearText = - "attribute vec4 pos;\n" - "void main() {\n" - " gl_Position = pos;\n" - "}\n"; - - // Color Program - colProg = OpenGL_CompileProgram(vertShaderText, fragcolText); - - // Texture Program - texProg = OpenGL_CompileProgram(vertShaderText, fragtexText); - - // Clear Program - clearProg = OpenGL_CompileProgram(vertclearText, fragclearText); - - // Color attributes - col_apos = glGetAttribLocation(colProg, "pos"); - col_atex = glGetAttribLocation(colProg, "TexCoordIn"); - // Texture attributes - tex_apos = glGetAttribLocation(texProg, "pos"); - tex_atex = glGetAttribLocation(texProg, "TexCoordIn"); - tex_utex = glGetUniformLocation(texProg, "Texture"); - // Clear attributes - clear_apos = glGetAttribLocation(clearProg, "pos"); - clear_ucol = glGetUniformLocation(clearProg, "Color"); - } - - void Init() - { - efbHalfWidth = EFB_WIDTH / 2.0f; - efbHalfHeight = 480 / 2.0f; - - temp = (u8*)AllocateMemoryPages(TEMP_SIZE); - } - void Shutdown() - { - glDeleteProgram(colProg); - glDeleteProgram(texProg); - glDeleteProgram(clearProg); - } - void Prepare() - { - //legacy multitexturing: select texture channel only. - glActiveTexture(GL_TEXTURE0); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - { - glShadeModel(GL_SMOOTH); - glDisable(GL_BLEND); - glClearDepth(1.0f); - glEnable(GL_SCISSOR_TEST); - glDisable(GL_LIGHTING); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClientActiveTexture(GL_TEXTURE0); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glStencilFunc(GL_ALWAYS, 0, 0); - glDisable(GL_STENCIL_TEST); - } - // used by hw rasterizer if it enables blending and depth test - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthFunc(GL_LEQUAL); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - CreateShaders(); - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - texType = GL_TEXTURE_RECTANGLE; - else - texType = GL_TEXTURE_2D; - } - static float width, height; - static void LoadTexture() - { - FourTexUnits &texUnit = bpmem.tex[0]; - u32 imageAddr = texUnit.texImage3[0].image_base; - // Texture Rectangle uses pixel coordinates - // While GLES uses texture coordinates - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - { - width = (float)texUnit.texImage0[0].width; - height = (float)texUnit.texImage0[0].height; - } - else - { - width = 1; - height = 1; - } - TexCacheEntry &cacheEntry = textures[imageAddr]; - cacheEntry.Update(); - - glBindTexture(texType, cacheEntry.texture); - glTexParameteri(texType, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST); - glTexParameteri(texType, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST); - } - - void BeginTriangles() - { - // disabling depth test sometimes allows more things to be visible - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - - hasTexture = bpmem.tevorders[0].enable0; - - if (hasTexture) - LoadTexture(); - } - - void EndTriangles() - { - glBindTexture(texType, 0); - glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - } - - static void DrawColorVertex(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) - { - float x0 = (v0->screenPosition.x / efbHalfWidth) - 1.0f; - float y0 = 1.0f - (v0->screenPosition.y / efbHalfHeight); - float z0 = v0->screenPosition.z / (float)0x00ffffff; - - float x1 = (v1->screenPosition.x / efbHalfWidth) - 1.0f; - float y1 = 1.0f - (v1->screenPosition.y / efbHalfHeight); - float z1 = v1->screenPosition.z / (float)0x00ffffff; - - float x2 = (v2->screenPosition.x / efbHalfWidth) - 1.0f; - float y2 = 1.0f - (v2->screenPosition.y / efbHalfHeight); - float z2 = v2->screenPosition.z / (float)0x00ffffff; - - float r0 = v0->color[0][OutputVertexData::RED_C] / 255.0f; - float g0 = v0->color[0][OutputVertexData::GRN_C] / 255.0f; - float b0 = v0->color[0][OutputVertexData::BLU_C] / 255.0f; - - float r1 = v1->color[0][OutputVertexData::RED_C] / 255.0f; - float g1 = v1->color[0][OutputVertexData::GRN_C] / 255.0f; - float b1 = v1->color[0][OutputVertexData::BLU_C] / 255.0f; - - float r2 = v2->color[0][OutputVertexData::RED_C] / 255.0f; - float g2 = v2->color[0][OutputVertexData::GRN_C] / 255.0f; - float b2 = v2->color[0][OutputVertexData::BLU_C] / 255.0f; - - static const GLfloat verts[3][3] = { - { x0, y0, z0 }, - { x1, y1, z1 }, - { x2, y2, z2 } - }; - static const GLfloat col[3][4] = { - { r0, g0, b0, 1.0f }, - { r1, g1, b1, 1.0f }, - { r2, g2, b2, 1.0f } - }; - { - glUseProgram(colProg); - glEnableVertexAttribArray(col_apos); - glEnableVertexAttribArray(col_atex); - - glVertexAttribPointer(col_apos, 3, GL_FLOAT, GL_FALSE, 0, verts); - glVertexAttribPointer(col_atex, 4, GL_FLOAT, GL_FALSE, 0, col); - glDrawArrays(GL_TRIANGLES, 0, 3); - glDisableVertexAttribArray(col_atex); - glDisableVertexAttribArray(col_apos); - } - } - - static void DrawTextureVertex(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) - { - float x0 = (v0->screenPosition.x / efbHalfWidth) - 1.0f; - float y0 = 1.0f - (v0->screenPosition.y / efbHalfHeight); - float z0 = v0->screenPosition.z; - - float x1 = (v1->screenPosition.x / efbHalfWidth) - 1.0f; - float y1 = 1.0f - (v1->screenPosition.y / efbHalfHeight); - float z1 = v1->screenPosition.z; - - float x2 = (v2->screenPosition.x / efbHalfWidth) - 1.0f; - float y2 = 1.0f - (v2->screenPosition.y / efbHalfHeight); - float z2 = v2->screenPosition.z; - - float s0 = v0->texCoords[0].x / width; - float t0 = v0->texCoords[0].y / height; - - float s1 = v1->texCoords[0].x / width; - float t1 = v1->texCoords[0].y / height; - - float s2 = v2->texCoords[0].x / width; - float t2 = v2->texCoords[0].y / height; - - static const GLfloat verts[3][3] = { - { x0, y0, z0 }, - { x1, y1, z1 }, - { x2, y2, z2 } - }; - static const GLfloat tex[3][2] = { - { s0, t0 }, - { s1, t1 }, - { s2, t2 } - }; - { - glUseProgram(texProg); - glEnableVertexAttribArray(tex_apos); - glEnableVertexAttribArray(tex_atex); - - glVertexAttribPointer(tex_apos, 3, GL_FLOAT, GL_FALSE, 0, verts); - glVertexAttribPointer(tex_atex, 2, GL_FLOAT, GL_FALSE, 0, tex); - glUniform1i(tex_utex, 0); - glDrawArrays(GL_TRIANGLES, 0, 3); - glDisableVertexAttribArray(tex_atex); - glDisableVertexAttribArray(tex_apos); - } - } - - void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) - { - if (hasTexture) - DrawTextureVertex(v0, v1, v2); - else - DrawColorVertex(v0, v1, v2); - } - - void Clear() - { - u8 r = (bpmem.clearcolorAR & 0x00ff); - u8 g = (bpmem.clearcolorGB & 0xff00) >> 8; - u8 b = (bpmem.clearcolorGB & 0x00ff); - u8 a = (bpmem.clearcolorAR & 0xff00) >> 8; - - GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f; - GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight; - GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f; - GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight; - GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff; - static const GLfloat verts[4][3] = { - { left, top, depth }, - { right, top, depth }, - { right, bottom, depth }, - { left, bottom, depth } - }; - { - glUseProgram(clearProg); - glVertexAttribPointer(clear_apos, 3, GL_FLOAT, GL_FALSE, 0, verts); - glUniform4f(clear_ucol, r, g, b, a); - glEnableVertexAttribArray(col_apos); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(col_apos); - } - } - - TexCacheEntry::TexCacheEntry() - { - Create(); - } - - void TexCacheEntry::Create() - { - FourTexUnits &texUnit = bpmem.tex[0]; - - texImage0.hex = texUnit.texImage0[0].hex; - texImage1.hex = texUnit.texImage1[0].hex; - texImage2.hex = texUnit.texImage2[0].hex; - texImage3.hex = texUnit.texImage3[0].hex; - texTlut.hex = texUnit.texTlut[0].hex; - - int image_width = texImage0.width; - int image_height = texImage0.height; - - DebugUtil::GetTextureRGBA(temp, 0, 0, image_width, image_height); - - glGenTextures(1, (GLuint *)&texture); - glBindTexture(texType, texture); - glTexImage2D(texType, 0, GL_RGBA, (GLsizei)image_width, (GLsizei)image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp); - } - - void TexCacheEntry::Destroy() - { - if (texture == 0) - return; - - glDeleteTextures(1, &texture); - texture = 0; - } - - void TexCacheEntry::Update() - { - FourTexUnits &texUnit = bpmem.tex[0]; - - // extra checks cause textures to be reloaded much more - if (texUnit.texImage0[0].hex != texImage0.hex || - // texUnit.texImage1[0].hex != texImage1.hex || - // texUnit.texImage2[0].hex != texImage2.hex || - texUnit.texImage3[0].hex != texImage3.hex || - texUnit.texTlut[0].hex != texTlut.hex) - { - Destroy(); - Create(); - } - } -} - diff --git a/Source/Core/VideoBackends/Software/HwRasterizer.h b/Source/Core/VideoBackends/Software/HwRasterizer.h deleted file mode 100644 index a58f5416c4..0000000000 --- a/Source/Core/VideoBackends/Software/HwRasterizer.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2009 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "VideoBackends/OGL/GLUtil.h" -#include "VideoBackends/Software/BPMemLoader.h" - -struct OutputVertexData; - -namespace HwRasterizer -{ - void Init(); - void Shutdown(); - - void Prepare(); - - void BeginTriangles(); - void EndTriangles(); - - void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2); - - void Clear(); - - struct TexCacheEntry - { - TexImage0 texImage0; - TexImage1 texImage1; - TexImage2 texImage2; - TexImage3 texImage3; - TexTLUT texTlut; - - GLuint texture; - - TexCacheEntry(); - - void Create(); - void Destroy(); - void Update(); - }; - - typedef std::map TextureCache; - static TextureCache textures; -} diff --git a/Source/Core/VideoBackends/Software/Rasterizer.cpp b/Source/Core/VideoBackends/Software/Rasterizer.cpp index 9b6b9f593a..0db2765944 100644 --- a/Source/Core/VideoBackends/Software/Rasterizer.cpp +++ b/Source/Core/VideoBackends/Software/Rasterizer.cpp @@ -7,7 +7,6 @@ #include "Common/CommonTypes.h" #include "VideoBackends/Software/BPMemLoader.h" #include "VideoBackends/Software/EfbInterface.h" -#include "VideoBackends/Software/HwRasterizer.h" #include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/Rasterizer.h" #include "VideoBackends/Software/SWStatistics.h" @@ -129,7 +128,7 @@ inline void Draw(s32 x, s32 y, s32 xi, s32 yi) s32 z = (s32)MathUtil::Clamp(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f); - if (!BoundingBox::active && bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc) + if (bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc) { // TODO: Test if perf regs are incremented even if test is disabled EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC); @@ -332,12 +331,6 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer { INCSTAT(swstats.thisFrame.numTrianglesDrawn); - if (g_SWVideoConfig.bHwRasterizer && !BoundingBox::active) - { - HwRasterizer::DrawTriangleFrontFace(v0, v1, v2); - return; - } - // adapted from http://devmaster.net/posts/6145/advanced-rasterization // 28.4 fixed-pou32 coordinates. rounded to nearest and adjusted to match hardware output @@ -425,281 +418,88 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++; if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++; - // If drawing, rasterize every block - if (!BoundingBox::active) + // Start in corner of 8x8 block + minx &= ~(BLOCK_SIZE - 1); + miny &= ~(BLOCK_SIZE - 1); + + // Loop through blocks + for (s32 y = miny; y < maxy; y += BLOCK_SIZE) { - // Start in corner of 8x8 block - minx &= ~(BLOCK_SIZE - 1); - miny &= ~(BLOCK_SIZE - 1); - - // Loop through blocks - for (s32 y = miny; y < maxy; y += BLOCK_SIZE) + for (s32 x = minx; x < maxx; x += BLOCK_SIZE) { - for (s32 x = minx; x < maxx; x += 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) { - // 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 iy = 0; iy < BLOCK_SIZE; iy++) { - for (s32 iy = 0; iy < BLOCK_SIZE; iy++) + for (s32 ix = 0; ix < BLOCK_SIZE; ix++) { - 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++) + { + s32 CX1 = CY1; + s32 CX2 = CY2; + s32 CX3 = CY3; + + for (s32 ix = 0; ix < BLOCK_SIZE; ix++) + { + if (CX1 > 0 && CX2 > 0 && CX3 > 0) { Draw(x + ix, y + iy, ix, iy); } + + CX1 -= FDY12; + CX2 -= FDY23; + CX3 -= FDY31; } - } - 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++) - { - s32 CX1 = CY1; - s32 CX2 = CY2; - s32 CX3 = CY3; - - for (s32 ix = 0; ix < BLOCK_SIZE; ix++) - { - if (CX1 > 0 && CX2 > 0 && CX3 > 0) - { - Draw(x + ix, y + iy, ix, iy); - } - - CX1 -= FDY12; - CX2 -= FDY23; - CX3 -= FDY31; - } - - CY1 += FDX12; - CY2 += FDX23; - CY3 += FDX31; - } + CY1 += FDX12; + CY2 += FDX23; + CY3 += FDX31; } } } } - else - { - // Calculating bbox - // First check for alpha channel - don't do anything it if always fails, - // Change bbox to primitive size if it always passes - AlphaTest::TEST_RESULT alphaRes = bpmem.alpha_test.TestResult(); - - if (alphaRes != AlphaTest::UNDETERMINED) - { - if (alphaRes == AlphaTest::PASS) - { - BoundingBox::coords[BoundingBox::TOP] = std::min(BoundingBox::coords[BoundingBox::TOP], (u16) miny); - BoundingBox::coords[BoundingBox::LEFT] = std::min(BoundingBox::coords[BoundingBox::LEFT], (u16) minx); - BoundingBox::coords[BoundingBox::BOTTOM] = std::max(BoundingBox::coords[BoundingBox::BOTTOM], (u16) maxy); - BoundingBox::coords[BoundingBox::RIGHT] = std::max(BoundingBox::coords[BoundingBox::RIGHT], (u16) maxx); - } - return; - } - - // If we are calculating bbox with alpha, 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 FLEFT = minx << 4; - const s32 FRIGHT = maxx << 4; - s32 FTOP = miny << 4; - s32 FBOTTOM = maxy << 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 - PrepareBlock(x, y); - Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 1)); - - if (y >= BoundingBox::coords[BoundingBox::TOP]) - break; - } - - CX1 -= FDY12; - CX2 -= FDY23; - CX3 -= FDY31; - } - - CY1 += FDX12; - CY2 += FDX23; - CY3 += FDX31; - } - - // Update top limit - miny = std::max((s32) BoundingBox::coords[BoundingBox::TOP], miny); - FTOP = miny << 4; - - // 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; - - CY1 = CX1; - CY2 = CX2; - CY3 = CX3; - - for (s32 y = miny; y <= maxy; ++y) - { - if (CY1 > 0 && CY2 > 0 && CY3 > 0) - { - PrepareBlock(x, y); - Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 1)); - - if (x >= BoundingBox::coords[BoundingBox::LEFT]) - break; - } - - CY1 += FDX12; - CY2 += FDX23; - CY3 += FDX31; - } - - CX1 -= FDY12; - CX2 -= FDY23; - CX3 -= FDY31; - } - - // Update left limit - minx = std::max((s32) BoundingBox::coords[BoundingBox::LEFT], minx); - - // 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) - { - CX1 = CY1; - CX2 = CY2; - 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 - PrepareBlock(x, y); - Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 1)); - - if (y <= BoundingBox::coords[BoundingBox::BOTTOM]) - break; - } - - CX1 += FDY12; - CX2 += FDY23; - CX3 += FDY31; - } - - CY1 -= FDX12; - CY2 -= FDX23; - CY3 -= FDX31; - } - - // Update bottom limit - maxy = std::min((s32) BoundingBox::coords[BoundingBox::BOTTOM], maxy); - FBOTTOM = maxy << 4; - - // 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; - - CY1 = CX1; - CY2 = CX2; - CY3 = CX3; - - for (s32 y = maxy; y >= miny; --y) - { - if (CY1 > 0 && CY2 > 0 && CY3 > 0) - { - // Build the new raster block every other pixel - PrepareBlock(x, y); - Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 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/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index 761cc667df..df005fee40 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -211,8 +211,7 @@ void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidt void SWRenderer::Swap(u32 fbWidth, u32 fbHeight) { GLInterface->Update(); // just updates the render window position and the backbuffer size - if (!g_SWVideoConfig.bHwRasterizer) - SWRenderer::DrawTexture(GetCurrentColorTexture(), fbWidth, fbHeight); + SWRenderer::DrawTexture(GetCurrentColorTexture(), fbWidth, fbHeight); swstats.frameCount++; SWRenderer::SwapBuffer(); diff --git a/Source/Core/VideoBackends/Software/SWVideoConfig.cpp b/Source/Core/VideoBackends/Software/SWVideoConfig.cpp index 0d5fd12489..4bd011e2df 100644 --- a/Source/Core/VideoBackends/Software/SWVideoConfig.cpp +++ b/Source/Core/VideoBackends/Software/SWVideoConfig.cpp @@ -14,7 +14,6 @@ SWVideoConfig::SWVideoConfig() bHideCursor = false; renderToMainframe = false; - bHwRasterizer = false; bBypassXFB = false; bShowStats = false; @@ -42,7 +41,6 @@ void SWVideoConfig::Load(const char* ini_file) hardware->Get("RenderToMainframe", &renderToMainframe, false); IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering"); - rendering->Get("HwRasterizer", &bHwRasterizer, false); rendering->Get("BypassXFB", &bBypassXFB, false); rendering->Get("ZComploc", &bZComploc, true); rendering->Get("ZFreeze", &bZFreeze, true); @@ -71,7 +69,6 @@ void SWVideoConfig::Save(const char* ini_file) hardware->Set("RenderToMainframe", renderToMainframe); IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering"); - rendering->Set("HwRasterizer", bHwRasterizer); rendering->Set("BypassXFB", bBypassXFB); rendering->Set("ZComploc", bZComploc); rendering->Set("ZFreeze", bZFreeze); diff --git a/Source/Core/VideoBackends/Software/SWVideoConfig.h b/Source/Core/VideoBackends/Software/SWVideoConfig.h index cd3ec9f0c3..7a58af41a6 100644 --- a/Source/Core/VideoBackends/Software/SWVideoConfig.h +++ b/Source/Core/VideoBackends/Software/SWVideoConfig.h @@ -20,7 +20,6 @@ struct SWVideoConfig : NonCopyable bool bHideCursor; bool renderToMainframe; - bool bHwRasterizer; bool bBypassXFB; // Emulation features diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index b49fa8fc4f..93dd37f03f 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -17,12 +17,12 @@ #include "Core/HW/VideoInterface.h" #include "VideoBackends/OGL/GLInterfaceBase.h" +#include "VideoBackends/OGL/GLUtil.h" #include "VideoBackends/OGL/GLExtensions/GLExtensions.h" #include "VideoBackends/Software/BPMemLoader.h" #include "VideoBackends/Software/Clipper.h" #include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/EfbInterface.h" -#include "VideoBackends/Software/HwRasterizer.h" #include "VideoBackends/Software/OpcodeDecoder.h" #include "VideoBackends/Software/Rasterizer.h" #include "VideoBackends/Software/SWCommandProcessor.h" @@ -91,7 +91,6 @@ bool VideoSoftware::Initialize(void *window_handle) OpcodeDecoder::Init(); Clipper::Init(); Rasterizer::Init(); - HwRasterizer::Init(); SWRenderer::Init(); DebugUtil::Init(); @@ -155,7 +154,6 @@ void VideoSoftware::EmuStateChange(EMUSTATE_CHANGE newState) void VideoSoftware::Shutdown() { // TODO: should be in Video_Cleanup - HwRasterizer::Shutdown(); SWRenderer::Shutdown(); DebugUtil::Shutdown(); @@ -190,7 +188,6 @@ void VideoSoftware::Video_Prepare() // Do our OSD callbacks OSD::DoCallbacks(OSD::OSD_INIT); - HwRasterizer::Prepare(); SWRenderer::Prepare(); INFO_LOG(VIDEO, "Video backend initialized."); @@ -221,14 +218,11 @@ void VideoSoftware::Video_EndField() Core::Callback_VideoCopiedToXFB(false); return; } - if (!g_SWVideoConfig.bHwRasterizer) + if (!g_SWVideoConfig.bBypassXFB) { - if (!g_SWVideoConfig.bBypassXFB) - { - EfbInterface::yuv422_packed *xfb = (EfbInterface::yuv422_packed *) Memory::GetPointer(s_beginFieldArgs.xfbAddr); + EfbInterface::yuv422_packed *xfb = (EfbInterface::yuv422_packed *) Memory::GetPointer(s_beginFieldArgs.xfbAddr); - SWRenderer::UpdateColorTexture(xfb, s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight); - } + SWRenderer::UpdateColorTexture(xfb, s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight); } // Ideally we would just move all the OpenGL context stuff to the CPU thread, diff --git a/Source/Core/VideoBackends/Software/Software.vcxproj b/Source/Core/VideoBackends/Software/Software.vcxproj index 161154df62..8874bce821 100644 --- a/Source/Core/VideoBackends/Software/Software.vcxproj +++ b/Source/Core/VideoBackends/Software/Software.vcxproj @@ -41,7 +41,6 @@ - @@ -65,7 +64,6 @@ - @@ -95,4 +93,4 @@ - \ No newline at end of file + diff --git a/Source/Core/VideoBackends/Software/Tev.cpp b/Source/Core/VideoBackends/Software/Tev.cpp index 6ea6eab051..552b60a99a 100644 --- a/Source/Core/VideoBackends/Software/Tev.cpp +++ b/Source/Core/VideoBackends/Software/Tev.cpp @@ -650,125 +650,120 @@ void Tev::Draw() if (!TevAlphaTest(output[ALP_C])) return; - // This part is only needed if we are not simply computing bbox - // (i. e., only needed when using the SW renderer) - if (!BoundingBox::active) + // z texture + if (bpmem.ztex2.op) { - // z texture - if (bpmem.ztex2.op) + u32 ztex = bpmem.ztex1.bias; + switch (bpmem.ztex2.type) { - 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; + 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; } - // fog - if (bpmem.fog.c_proj_fsel.fsel) + if (bpmem.ztex2.op == ZTEXTURE_ADD) + ztex += Position[2]; + + Position[2] = ztex & 0x00ffffff; + } + + // fog + if (bpmem.fog.c_proj_fsel.fsel) + { + float ze; + + if (bpmem.fog.c_proj_fsel.proj == 0) { - float ze; + // 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.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) + if (bpmem.fogRange.Base.Enabled) { - // TODO: Check against hw if these values get incremented even if depth testing is disabled - EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT); + // 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. - if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2])) - return; + // 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; - EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT); + // 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); } // branchless bounding box update @@ -777,12 +772,6 @@ void Tev::Draw() 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 we are only calculating the bounding box, - // there's no need to actually draw anything - if (BoundingBox::active) - return; - - #if ALLOW_TEV_DUMPS if (g_SWVideoConfig.bDumpTevStages) {