commit
edae1d3bcb
|
@ -76,9 +76,6 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
|
||||||
choice_backend->Disable();
|
choice_backend->Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// rasterizer
|
|
||||||
szr_rendering->Add(new SettingCheckBox(page_general, _("Hardware rasterization"), "", vconfig.bHwRasterizer));
|
|
||||||
|
|
||||||
// xfb
|
// xfb
|
||||||
szr_rendering->Add(new SettingCheckBox(page_general, _("Bypass XFB"), "", vconfig.bBypassXFB));
|
szr_rendering->Add(new SettingCheckBox(page_general, _("Bypass XFB"), "", vconfig.bBypassXFB));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ set(SRCS BPMemLoader.cpp
|
||||||
DebugUtil.cpp
|
DebugUtil.cpp
|
||||||
EfbCopy.cpp
|
EfbCopy.cpp
|
||||||
EfbInterface.cpp
|
EfbInterface.cpp
|
||||||
HwRasterizer.cpp
|
|
||||||
SWmain.cpp
|
SWmain.cpp
|
||||||
OpcodeDecoder.cpp
|
OpcodeDecoder.cpp
|
||||||
RasterFont.cpp
|
RasterFont.cpp
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include "VideoBackends/Software/BPMemLoader.h"
|
#include "VideoBackends/Software/BPMemLoader.h"
|
||||||
#include "VideoBackends/Software/DebugUtil.h"
|
#include "VideoBackends/Software/DebugUtil.h"
|
||||||
#include "VideoBackends/Software/EfbInterface.h"
|
#include "VideoBackends/Software/EfbInterface.h"
|
||||||
#include "VideoBackends/Software/HwRasterizer.h"
|
|
||||||
#include "VideoBackends/Software/SWCommandProcessor.h"
|
#include "VideoBackends/Software/SWCommandProcessor.h"
|
||||||
#include "VideoBackends/Software/SWRenderer.h"
|
#include "VideoBackends/Software/SWRenderer.h"
|
||||||
#include "VideoBackends/Software/SWStatistics.h"
|
#include "VideoBackends/Software/SWStatistics.h"
|
||||||
|
@ -25,8 +24,6 @@
|
||||||
namespace DebugUtil
|
namespace DebugUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
static bool drawingHwTriangles = false;
|
|
||||||
|
|
||||||
static const int NUM_OBJECT_BUFFERS = 40;
|
static const int NUM_OBJECT_BUFFERS = 40;
|
||||||
|
|
||||||
static u32 *ObjectBuffer[NUM_OBJECT_BUFFERS];
|
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)
|
if (g_SWVideoConfig.bDumpTextures && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd)
|
||||||
DumpActiveTextures();
|
DumpActiveTextures();
|
||||||
|
|
||||||
if (g_SWVideoConfig.bHwRasterizer)
|
|
||||||
{
|
|
||||||
HwRasterizer::BeginTriangles();
|
|
||||||
drawingHwTriangles = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,12 +216,6 @@ void OnObjectEnd()
|
||||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
||||||
swstats.thisFrame.numDrawnObjects));
|
swstats.thisFrame.numDrawnObjects));
|
||||||
|
|
||||||
if (g_SWVideoConfig.bHwRasterizer || drawingHwTriangles)
|
|
||||||
{
|
|
||||||
HwRasterizer::EndTriangles();
|
|
||||||
drawingHwTriangles = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||||
{
|
{
|
||||||
if (DrawnToBuffer[i])
|
if (DrawnToBuffer[i])
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include "VideoBackends/Software/DebugUtil.h"
|
#include "VideoBackends/Software/DebugUtil.h"
|
||||||
#include "VideoBackends/Software/EfbCopy.h"
|
#include "VideoBackends/Software/EfbCopy.h"
|
||||||
#include "VideoBackends/Software/EfbInterface.h"
|
#include "VideoBackends/Software/EfbInterface.h"
|
||||||
#include "VideoBackends/Software/HwRasterizer.h"
|
|
||||||
#include "VideoBackends/Software/SWCommandProcessor.h"
|
#include "VideoBackends/Software/SWCommandProcessor.h"
|
||||||
#include "VideoBackends/Software/SWRenderer.h"
|
#include "VideoBackends/Software/SWRenderer.h"
|
||||||
#include "VideoBackends/Software/SWStatistics.h"
|
#include "VideoBackends/Software/SWStatistics.h"
|
||||||
|
@ -31,47 +30,41 @@ namespace EfbCopy
|
||||||
{
|
{
|
||||||
GLInterface->Update(); // update the render window position and the backbuffer size
|
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",
|
EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed *) Memory::GetPointer(xfbAddr);
|
||||||
xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma);
|
|
||||||
|
|
||||||
if (!g_SWVideoConfig.bBypassXFB)
|
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
|
||||||
{
|
}
|
||||||
EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed *) Memory::GetPointer(xfbAddr);
|
else
|
||||||
|
{
|
||||||
|
// Ask SWRenderer for the next color texture
|
||||||
|
u8 *colorTexture = SWRenderer::GetNextColorTexture();
|
||||||
|
|
||||||
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
|
EfbInterface::BypassXFB(colorTexture, fbWidth, fbHeight, sourceRc, Gamma);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Ask SWRenderer for the next color texture
|
|
||||||
u8 *colorTexture = SWRenderer::GetNextColorTexture();
|
|
||||||
|
|
||||||
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.
|
// FifoPlayer is broken and never calls BeginFrame/EndFrame.
|
||||||
SWRenderer::SwapColorTexture();
|
// Hence, we manually force a swap now. This emulates the behavior
|
||||||
|
// of hardware backends with XFB emulation disabled.
|
||||||
// FifoPlayer is broken and never calls BeginFrame/EndFrame.
|
// TODO: Fix FifoPlayer by making proper use of VideoInterface!
|
||||||
// Hence, we manually force a swap now. This emulates the behavior
|
// This requires careful synchronization since GPU commands
|
||||||
// of hardware backends with XFB emulation disabled.
|
// are processed on a different thread than VI commands.
|
||||||
// TODO: Fix FifoPlayer by making proper use of VideoInterface!
|
SWRenderer::Swap(fbWidth, fbHeight);
|
||||||
// This requires careful synchronization since GPU commands
|
DebugUtil::OnFrameEnd(fbWidth, fbHeight);
|
||||||
// are processed on a different thread than VI commands.
|
|
||||||
SWRenderer::Swap(fbWidth, fbHeight);
|
|
||||||
DebugUtil::OnFrameEnd(fbWidth, fbHeight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyToRam()
|
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()
|
static void ClearEfb()
|
||||||
|
@ -138,10 +131,7 @@ namespace EfbCopy
|
||||||
|
|
||||||
if (bpmem.triggerEFBCopy.clear)
|
if (bpmem.triggerEFBCopy.clear)
|
||||||
{
|
{
|
||||||
if (g_SWVideoConfig.bHwRasterizer)
|
ClearEfb();
|
||||||
HwRasterizer::Clear();
|
|
||||||
else
|
|
||||||
ClearEfb();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright 2009 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#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<u32, TexCacheEntry> TextureCache;
|
|
||||||
static TextureCache textures;
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "VideoBackends/Software/BPMemLoader.h"
|
#include "VideoBackends/Software/BPMemLoader.h"
|
||||||
#include "VideoBackends/Software/EfbInterface.h"
|
#include "VideoBackends/Software/EfbInterface.h"
|
||||||
#include "VideoBackends/Software/HwRasterizer.h"
|
|
||||||
#include "VideoBackends/Software/NativeVertexFormat.h"
|
#include "VideoBackends/Software/NativeVertexFormat.h"
|
||||||
#include "VideoBackends/Software/Rasterizer.h"
|
#include "VideoBackends/Software/Rasterizer.h"
|
||||||
#include "VideoBackends/Software/SWStatistics.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<float>(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f);
|
s32 z = (s32)MathUtil::Clamp<float>(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
|
// TODO: Test if perf regs are incremented even if test is disabled
|
||||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
|
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
|
||||||
|
@ -332,12 +331,6 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
|
||||||
{
|
{
|
||||||
INCSTAT(swstats.thisFrame.numTrianglesDrawn);
|
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
|
// adapted from http://devmaster.net/posts/6145/advanced-rasterization
|
||||||
|
|
||||||
// 28.4 fixed-pou32 coordinates. rounded to nearest and adjusted to match hardware output
|
// 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 (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
|
||||||
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
|
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
|
||||||
|
|
||||||
// If drawing, rasterize every block
|
// Start in corner of 8x8 block
|
||||||
if (!BoundingBox::active)
|
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
|
for (s32 x = minx; x < maxx; x += BLOCK_SIZE)
|
||||||
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)
|
// 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
|
for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||||
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 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);
|
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++)
|
CY1 += FDX12;
|
||||||
{
|
CY2 += FDX23;
|
||||||
s32 CX1 = CY1;
|
CY3 += FDX31;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -211,8 +211,7 @@ void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidt
|
||||||
void SWRenderer::Swap(u32 fbWidth, u32 fbHeight)
|
void SWRenderer::Swap(u32 fbWidth, u32 fbHeight)
|
||||||
{
|
{
|
||||||
GLInterface->Update(); // just updates the render window position and the backbuffer size
|
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++;
|
swstats.frameCount++;
|
||||||
SWRenderer::SwapBuffer();
|
SWRenderer::SwapBuffer();
|
||||||
|
|
|
@ -14,7 +14,6 @@ SWVideoConfig::SWVideoConfig()
|
||||||
bHideCursor = false;
|
bHideCursor = false;
|
||||||
renderToMainframe = false;
|
renderToMainframe = false;
|
||||||
|
|
||||||
bHwRasterizer = false;
|
|
||||||
bBypassXFB = false;
|
bBypassXFB = false;
|
||||||
|
|
||||||
bShowStats = false;
|
bShowStats = false;
|
||||||
|
@ -42,7 +41,6 @@ void SWVideoConfig::Load(const char* ini_file)
|
||||||
hardware->Get("RenderToMainframe", &renderToMainframe, false);
|
hardware->Get("RenderToMainframe", &renderToMainframe, false);
|
||||||
|
|
||||||
IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering");
|
IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering");
|
||||||
rendering->Get("HwRasterizer", &bHwRasterizer, false);
|
|
||||||
rendering->Get("BypassXFB", &bBypassXFB, false);
|
rendering->Get("BypassXFB", &bBypassXFB, false);
|
||||||
rendering->Get("ZComploc", &bZComploc, true);
|
rendering->Get("ZComploc", &bZComploc, true);
|
||||||
rendering->Get("ZFreeze", &bZFreeze, true);
|
rendering->Get("ZFreeze", &bZFreeze, true);
|
||||||
|
@ -71,7 +69,6 @@ void SWVideoConfig::Save(const char* ini_file)
|
||||||
hardware->Set("RenderToMainframe", renderToMainframe);
|
hardware->Set("RenderToMainframe", renderToMainframe);
|
||||||
|
|
||||||
IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering");
|
IniFile::Section* rendering = iniFile.GetOrCreateSection("Rendering");
|
||||||
rendering->Set("HwRasterizer", bHwRasterizer);
|
|
||||||
rendering->Set("BypassXFB", bBypassXFB);
|
rendering->Set("BypassXFB", bBypassXFB);
|
||||||
rendering->Set("ZComploc", bZComploc);
|
rendering->Set("ZComploc", bZComploc);
|
||||||
rendering->Set("ZFreeze", bZFreeze);
|
rendering->Set("ZFreeze", bZFreeze);
|
||||||
|
|
|
@ -20,7 +20,6 @@ struct SWVideoConfig : NonCopyable
|
||||||
bool bHideCursor;
|
bool bHideCursor;
|
||||||
bool renderToMainframe;
|
bool renderToMainframe;
|
||||||
|
|
||||||
bool bHwRasterizer;
|
|
||||||
bool bBypassXFB;
|
bool bBypassXFB;
|
||||||
|
|
||||||
// Emulation features
|
// Emulation features
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
#include "Core/HW/VideoInterface.h"
|
#include "Core/HW/VideoInterface.h"
|
||||||
|
|
||||||
#include "VideoBackends/OGL/GLInterfaceBase.h"
|
#include "VideoBackends/OGL/GLInterfaceBase.h"
|
||||||
|
#include "VideoBackends/OGL/GLUtil.h"
|
||||||
#include "VideoBackends/OGL/GLExtensions/GLExtensions.h"
|
#include "VideoBackends/OGL/GLExtensions/GLExtensions.h"
|
||||||
#include "VideoBackends/Software/BPMemLoader.h"
|
#include "VideoBackends/Software/BPMemLoader.h"
|
||||||
#include "VideoBackends/Software/Clipper.h"
|
#include "VideoBackends/Software/Clipper.h"
|
||||||
#include "VideoBackends/Software/DebugUtil.h"
|
#include "VideoBackends/Software/DebugUtil.h"
|
||||||
#include "VideoBackends/Software/EfbInterface.h"
|
#include "VideoBackends/Software/EfbInterface.h"
|
||||||
#include "VideoBackends/Software/HwRasterizer.h"
|
|
||||||
#include "VideoBackends/Software/OpcodeDecoder.h"
|
#include "VideoBackends/Software/OpcodeDecoder.h"
|
||||||
#include "VideoBackends/Software/Rasterizer.h"
|
#include "VideoBackends/Software/Rasterizer.h"
|
||||||
#include "VideoBackends/Software/SWCommandProcessor.h"
|
#include "VideoBackends/Software/SWCommandProcessor.h"
|
||||||
|
@ -91,7 +91,6 @@ bool VideoSoftware::Initialize(void *window_handle)
|
||||||
OpcodeDecoder::Init();
|
OpcodeDecoder::Init();
|
||||||
Clipper::Init();
|
Clipper::Init();
|
||||||
Rasterizer::Init();
|
Rasterizer::Init();
|
||||||
HwRasterizer::Init();
|
|
||||||
SWRenderer::Init();
|
SWRenderer::Init();
|
||||||
DebugUtil::Init();
|
DebugUtil::Init();
|
||||||
|
|
||||||
|
@ -155,7 +154,6 @@ void VideoSoftware::EmuStateChange(EMUSTATE_CHANGE newState)
|
||||||
void VideoSoftware::Shutdown()
|
void VideoSoftware::Shutdown()
|
||||||
{
|
{
|
||||||
// TODO: should be in Video_Cleanup
|
// TODO: should be in Video_Cleanup
|
||||||
HwRasterizer::Shutdown();
|
|
||||||
SWRenderer::Shutdown();
|
SWRenderer::Shutdown();
|
||||||
DebugUtil::Shutdown();
|
DebugUtil::Shutdown();
|
||||||
|
|
||||||
|
@ -190,7 +188,6 @@ void VideoSoftware::Video_Prepare()
|
||||||
// Do our OSD callbacks
|
// Do our OSD callbacks
|
||||||
OSD::DoCallbacks(OSD::OSD_INIT);
|
OSD::DoCallbacks(OSD::OSD_INIT);
|
||||||
|
|
||||||
HwRasterizer::Prepare();
|
|
||||||
SWRenderer::Prepare();
|
SWRenderer::Prepare();
|
||||||
|
|
||||||
INFO_LOG(VIDEO, "Video backend initialized.");
|
INFO_LOG(VIDEO, "Video backend initialized.");
|
||||||
|
@ -221,14 +218,11 @@ void VideoSoftware::Video_EndField()
|
||||||
Core::Callback_VideoCopiedToXFB(false);
|
Core::Callback_VideoCopiedToXFB(false);
|
||||||
return;
|
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,
|
// Ideally we would just move all the OpenGL context stuff to the CPU thread,
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
<ClCompile Include="DebugUtil.cpp" />
|
<ClCompile Include="DebugUtil.cpp" />
|
||||||
<ClCompile Include="EfbCopy.cpp" />
|
<ClCompile Include="EfbCopy.cpp" />
|
||||||
<ClCompile Include="EfbInterface.cpp" />
|
<ClCompile Include="EfbInterface.cpp" />
|
||||||
<ClCompile Include="HwRasterizer.cpp" />
|
|
||||||
<ClCompile Include="OpcodeDecoder.cpp" />
|
<ClCompile Include="OpcodeDecoder.cpp" />
|
||||||
<ClCompile Include="RasterFont.cpp" />
|
<ClCompile Include="RasterFont.cpp" />
|
||||||
<ClCompile Include="Rasterizer.cpp" />
|
<ClCompile Include="Rasterizer.cpp" />
|
||||||
|
@ -65,7 +64,6 @@
|
||||||
<ClInclude Include="DebugUtil.h" />
|
<ClInclude Include="DebugUtil.h" />
|
||||||
<ClInclude Include="EfbCopy.h" />
|
<ClInclude Include="EfbCopy.h" />
|
||||||
<ClInclude Include="EfbInterface.h" />
|
<ClInclude Include="EfbInterface.h" />
|
||||||
<ClInclude Include="HwRasterizer.h" />
|
|
||||||
<ClInclude Include="NativeVertexFormat.h" />
|
<ClInclude Include="NativeVertexFormat.h" />
|
||||||
<ClInclude Include="OpcodeDecoder.h" />
|
<ClInclude Include="OpcodeDecoder.h" />
|
||||||
<ClInclude Include="RasterFont.h" />
|
<ClInclude Include="RasterFont.h" />
|
||||||
|
|
|
@ -650,125 +650,120 @@ void Tev::Draw()
|
||||||
if (!TevAlphaTest(output[ALP_C]))
|
if (!TevAlphaTest(output[ALP_C]))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// This part is only needed if we are not simply computing bbox
|
// z texture
|
||||||
// (i. e., only needed when using the SW renderer)
|
if (bpmem.ztex2.op)
|
||||||
if (!BoundingBox::active)
|
|
||||||
{
|
{
|
||||||
// z texture
|
u32 ztex = bpmem.ztex1.bias;
|
||||||
if (bpmem.ztex2.op)
|
switch (bpmem.ztex2.type)
|
||||||
{
|
{
|
||||||
u32 ztex = bpmem.ztex1.bias;
|
case 0: // 8 bit
|
||||||
switch (bpmem.ztex2.type)
|
ztex += TexColor[ALP_C];
|
||||||
{
|
break;
|
||||||
case 0: // 8 bit
|
case 1: // 16 bit
|
||||||
ztex += TexColor[ALP_C];
|
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
|
||||||
break;
|
break;
|
||||||
case 1: // 16 bit
|
case 2: // 24 bit
|
||||||
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
|
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
|
||||||
break;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fog
|
if (bpmem.ztex2.op == ZTEXTURE_ADD)
|
||||||
if (bpmem.fog.c_proj_fsel.fsel)
|
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 (bpmem.fogRange.Base.Enabled)
|
||||||
if (late_ztest && bpmem.zmode.testenable)
|
|
||||||
{
|
{
|
||||||
// TODO: Check against hw if these values get incremented even if depth testing is disabled
|
// TODO: This is untested and should definitely be checked against real hw.
|
||||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT);
|
// - 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]))
|
// First, calculate the offset from the viewport center (normalized to 0..1)
|
||||||
return;
|
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
|
// 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::TOP] = std::min((u16)Position[1], BoundingBox::coords[BoundingBox::TOP]);
|
||||||
BoundingBox::coords[BoundingBox::BOTTOM] = std::max((u16)Position[1], BoundingBox::coords[BoundingBox::BOTTOM]);
|
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 ALLOW_TEV_DUMPS
|
||||||
if (g_SWVideoConfig.bDumpTevStages)
|
if (g_SWVideoConfig.bDumpTevStages)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue