Render 3D: Improve the overall rendering accuracy of Edge Mark. Most notably, Edge Mark now properly renders at screen edges. As of now, the current algorithm is as accurate as its ever going to get under our current 3D rendering engine.

This commit is contained in:
rogerman 2018-12-14 17:08:16 -08:00
parent e6d6f2e10d
commit 7ff5c5eece
8 changed files with 248 additions and 221 deletions

View File

@ -454,7 +454,11 @@ static const char *EdgeMarkFragShader_100 = {"\
\n\
uniform sampler2D texInFragDepth;\n\
uniform sampler2D texInPolyID;\n\
\n\
uniform vec2 framebufferSize;\n\
uniform vec4 stateEdgeColor[8];\n\
uniform int clearPolyID;\n\
uniform float clearDepth;\n\
\n\
void main()\n\
{\n\
@ -491,12 +495,51 @@ static const char *EdgeMarkFragShader_100 = {"\
isWireframe[3] = bool(polyIDInfo[3].g);\n\
isWireframe[4] = bool(polyIDInfo[4].g);\n\
\n\
for (int i = 1; i < 5; i++)\n\
bool isEdgeMarkingClearValues = ((polyID[0] != clearPolyID) && (depth[0] < clearDepth) && !isWireframe[0]);\n\
vec2 pixelCoord = texCoord[0] * framebufferSize;\n\
\n\
if ( ((pixelCoord.x >= framebufferSize.x-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[1]) && (depth[0] >= depth[1]) && !isWireframe[1])) )\n\
{\n\
if ( (polyID[0] != polyID[i]) && (depth[0] >= depth[i]) && !isWireframe[i] )\n\
if (pixelCoord.x >= framebufferSize.x-1.0)\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[i]/8];\n\
break;\n\
newEdgeColor = stateEdgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[1]/8];\n\
}\n\
}\n\
else if ( ((pixelCoord.y >= framebufferSize.y-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[2]) && (depth[0] >= depth[2]) && !isWireframe[2])) )\n\
{\n\
if (pixelCoord.y >= framebufferSize.y-1.0)\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[2]/8];\n\
}\n\
}\n\
else if ( ((pixelCoord.x < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[3]) && (depth[0] >= depth[3]) && !isWireframe[3])) )\n\
{\n\
if (pixelCoord.x < 1.0)\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[3]/8];\n\
}\n\
}\n\
else if ( ((pixelCoord.y < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[4]) && (depth[0] >= depth[4]) && !isWireframe[4])) )\n\
{\n\
if (pixelCoord.y < 1.0)\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = stateEdgeColor[polyID[4]/8];\n\
}\n\
}\n\
}\n\
@ -3406,13 +3449,15 @@ Render3DError OpenGLRenderer_1_2::InitEdgeMarkProgramShaderLocations()
glUseProgram(OGLRef.programEdgeMarkID);
const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInFragDepth");
const GLint uniformTexGPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInPolyID");
const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInFragDepth");
const GLint uniformTexGPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInPolyID");
glUniform1i(uniformTexGDepth, OGLTextureUnitID_DepthStencil);
glUniform1i(uniformTexGPolyID, OGLTextureUnitID_GPolyID);
OGLRef.uniformFramebufferSize = glGetUniformLocation(OGLRef.programEdgeMarkID, "framebufferSize");
OGLRef.uniformStateEdgeColor = glGetUniformLocation(OGLRef.programEdgeMarkID, "stateEdgeColor");
OGLRef.uniformFramebufferSize_EdgeMark = glGetUniformLocation(OGLRef.programEdgeMarkID, "framebufferSize");
OGLRef.uniformStateClearPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "clearPolyID");
OGLRef.uniformStateClearDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "clearDepth");
OGLRef.uniformStateEdgeColor = glGetUniformLocation(OGLRef.programEdgeMarkID, "stateEdgeColor");
return OGLERROR_NOERR;
}
@ -3939,6 +3984,8 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine)
glUniform1i(OGLRef.uniformStateEnableAntialiasing, (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE);
glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (this->_enableEdgeMark) ? GL_TRUE : GL_FALSE);
glUniform1i(OGLRef.uniformStateUseWDepth, (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE);
glUniform1i(OGLRef.uniformStateClearPolyID, this->_clearAttributes.opaquePolyID);
glUniform1f(OGLRef.uniformStateClearDepth, (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF);
glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
glUniform1i(OGLRef.uniformTexDrawOpaque, GL_FALSE);
glUniform1i(OGLRef.uniformPolyDrawShadow, GL_FALSE);
@ -4236,7 +4283,9 @@ Render3DError OpenGLRenderer_1_2::RenderEdgeMarking(const u16 *colorTable, const
// Pass 2: Unblended edge mark colors to zero-alpha pixels
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glUseProgram(OGLRef.programEdgeMarkID);
glUniform2f(OGLRef.uniformFramebufferSize, this->_framebufferWidth, this->_framebufferHeight);
glUniform2f(OGLRef.uniformFramebufferSize_EdgeMark, this->_framebufferWidth, this->_framebufferHeight);
glUniform1i(OGLRef.uniformStateClearPolyID, this->_clearAttributes.opaquePolyID);
glUniform1f(OGLRef.uniformStateClearDepth, (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF);
glUniform4fv(OGLRef.uniformStateEdgeColor, 8, oglColor);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
glStencilFunc(GL_NOTEQUAL, 0x40, 0x40);
@ -4251,7 +4300,9 @@ Render3DError OpenGLRenderer_1_2::RenderEdgeMarking(const u16 *colorTable, const
else
{
glUseProgram(OGLRef.programEdgeMarkID);
glUniform2f(OGLRef.uniformFramebufferSize, this->_framebufferWidth, this->_framebufferHeight);
glUniform2f(OGLRef.uniformFramebufferSize_EdgeMark, this->_framebufferWidth, this->_framebufferHeight);
glUniform1i(OGLRef.uniformStateClearPolyID, this->_clearAttributes.opaquePolyID);
glUniform1f(OGLRef.uniformStateClearDepth, (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF);
glUniform4fv(OGLRef.uniformStateEdgeColor, 8, oglColor);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glDisable(GL_STENCIL_TEST);

View File

@ -372,10 +372,12 @@ struct OGLRenderStates
GLuint enableEdgeMarking;
GLuint enableFogAlphaOnly;
GLuint useWDepth;
GLuint clearPolyID;
GLfloat clearDepth;
GLfloat alphaTestRef;
GLfloat fogOffset;
GLfloat fogStep;
GLfloat pad_0; // This needs to be here to preserve alignment
GLfloat pad[3]; // This needs to be here to preserve alignment
GLvec4 fogColor;
GLvec4 fogDensity[32]; // Array of floats need to be padded as vec4
GLvec4 edgeColor[8];
@ -471,7 +473,6 @@ struct OGLRenderRef
GLuint programFramebufferRGBA6665OutputID;
GLuint programFramebufferRGBA8888OutputID;
GLint uniformFramebufferSize;
GLint uniformFramebufferSize_ConvertRGBA6665;
GLint uniformFramebufferSize_ConvertRGBA8888;
GLint uniformTexInFragColor_ConvertRGBA6665;
@ -483,6 +484,9 @@ struct OGLRenderRef
GLint uniformStateEnableFogAlphaOnly;
GLint uniformStateUseWDepth;
GLint uniformStateAlphaTestRef;
GLint uniformFramebufferSize_EdgeMark;
GLint uniformStateClearPolyID;
GLint uniformStateClearDepth;
GLint uniformStateEdgeColor;
GLint uniformStateFogColor;
GLint uniformStateFogDensity;
@ -639,6 +643,9 @@ protected:
bool _emulateDepthEqualsTestTolerance;
bool _emulateDepthLEqualPolygonFacing;
float _clearDepth;
FragmentColor *_mappedFramebuffer;
FragmentColor *_workingTextureUnpackBuffer;
bool _pixelReadNeedsFinish;

59
desmume/src/OGLRender_3_2.cpp Normal file → Executable file
View File

@ -23,6 +23,7 @@
#include <string.h>
#include <algorithm>
#include "utils/bits.h"
#include "common.h"
#include "debug.h"
#include "NDSSystem.h"
@ -177,6 +178,8 @@ static const char *GeometryFragShader_150 = {"\
bool enableEdgeMarking;\n\
bool enableFogAlphaOnly;\n\
bool useWDepth;\n\
int clearPolyID;\n\
float clearDepth;\n\
float alphaTestRef;\n\
float fogOffset;\n\
float fogStep;\n\
@ -351,6 +354,7 @@ static const char *EdgeMarkVtxShader_150 = {"\
\n\
in vec2 inPosition;\n\
in vec2 inTexCoord0;\n\
\n\
layout (std140) uniform RenderStates\n\
{\n\
vec2 framebufferSize;\n\
@ -360,6 +364,8 @@ static const char *EdgeMarkVtxShader_150 = {"\
bool enableEdgeMarking;\n\
bool enableFogAlphaOnly;\n\
bool useWDepth;\n\
int clearPolyID;\n\
float clearDepth;\n\
float alphaTestRef;\n\
float fogOffset;\n\
float fogStep;\n\
@ -401,6 +407,8 @@ static const char *EdgeMarkFragShader_150 = {"\
bool enableEdgeMarking;\n\
bool enableFogAlphaOnly;\n\
bool useWDepth;\n\
int clearPolyID;\n\
float clearDepth;\n\
float alphaTestRef;\n\
float fogOffset;\n\
float fogStep;\n\
@ -451,12 +459,51 @@ static const char *EdgeMarkFragShader_150 = {"\
isWireframe[3] = bool(polyIDInfo[3].g);\n\
isWireframe[4] = bool(polyIDInfo[4].g);\n\
\n\
for (int i = 1; i < 5; i++)\n\
bool isEdgeMarkingClearValues = ((polyID[0] != state.clearPolyID) && (depth[0] < state.clearDepth) && !isWireframe[0]);\n\
vec2 pixelCoord = texCoord[0] * state.framebufferSize;\n\
\n\
if ( ((pixelCoord.x >= state.framebufferSize.x-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[1]) && (depth[0] >= depth[1]) && !isWireframe[1])) )\n\
{\n\
if ( (polyID[0] != polyID[i]) && (depth[0] >= depth[i]) && !isWireframe[i] )\n\
if (pixelCoord.x >= state.framebufferSize.x-1.0)\n\
{\n\
newEdgeColor = state.edgeColor[polyID[i]/8];\n\
break;\n\
newEdgeColor = state.edgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = state.edgeColor[polyID[1]/8];\n\
}\n\
}\n\
else if ( ((pixelCoord.y >= state.framebufferSize.y-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[2]) && (depth[0] >= depth[2]) && !isWireframe[2])) )\n\
{\n\
if (pixelCoord.y >= state.framebufferSize.y-1.0)\n\
{\n\
newEdgeColor = state.edgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = state.edgeColor[polyID[2]/8];\n\
}\n\
}\n\
else if ( ((pixelCoord.x < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[3]) && (depth[0] >= depth[3]) && !isWireframe[3])) )\n\
{\n\
if (pixelCoord.x < 1.0)\n\
{\n\
newEdgeColor = state.edgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = state.edgeColor[polyID[3]/8];\n\
}\n\
}\n\
else if ( ((pixelCoord.y < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[4]) && (depth[0] >= depth[4]) && !isWireframe[4])) )\n\
{\n\
if (pixelCoord.y < 1.0)\n\
{\n\
newEdgeColor = state.edgeColor[polyID[0]/8];\n\
}\n\
else\n\
{\n\
newEdgeColor = state.edgeColor[polyID[4]/8];\n\
}\n\
}\n\
}\n\
@ -495,6 +542,8 @@ static const char *FogFragShader_150 = {"\
bool enableEdgeMarking;\n\
bool enableFogAlphaOnly;\n\
bool useWDepth;\n\
int clearPolyID;\n\
float clearDepth;\n\
float alphaTestRef;\n\
float fogOffset;\n\
float fogStep;\n\
@ -1560,6 +1609,8 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine)
state->enableEdgeMarking = (this->_enableEdgeMark) ? GL_TRUE : GL_FALSE;
state->enableFogAlphaOnly = (engine.renderState.enableFogAlphaOnly) ? GL_TRUE : GL_FALSE;
state->useWDepth = (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE;
state->clearPolyID = this->_clearAttributes.opaquePolyID;
state->clearDepth = (GLfloat)this->_clearAttributes.depth / (GLfloat)0x00FFFFFF;
state->alphaTestRef = divide5bitBy31_LUT[engine.renderState.alphaTestRef];
state->fogColor.r = divide5bitBy31_LUT[(engine.renderState.fogColor ) & 0x0000001F];
state->fogColor.g = divide5bitBy31_LUT[(engine.renderState.fogColor >> 5) & 0x0000001F];

View File

@ -408,7 +408,11 @@ static void makeTables()
for (size_t i = 0; i < 32768; i++)
{
// 15-bit to 24-bit depth formula from http://problemkaputt.de/gbatek.htm#ds3drearplane
dsDepthExtend_15bit_to_24bit[i] = LE_TO_LOCAL_32( (i*0x200)+((i+1)>>15)*0x01FF );
//dsDepthExtend_15bit_to_24bit[i] = LE_TO_LOCAL_32( (i*0x0200) + ((i+1)>>15)*0x01FF );
// Is GBATEK actually correct here? Let's try using a simplified formula and see if it's
// more accurate.
dsDepthExtend_15bit_to_24bit[i] = LE_TO_LOCAL_32( (i*0x0200) + 0x01FF );
}
for (size_t i = 0; i < 65536; i++)

View File

@ -62,6 +62,7 @@
#include "render3D.h"
#include "MMU.h"
#include "NDSSystem.h"
#include "utils/bits.h"
#include "utils/task.h"
#include "filter/filter.h"
#include "filter/xbrz.h"
@ -2131,77 +2132,6 @@ Render3DError SoftRasterizerRenderer::RenderGeometry(const GFX3D_State &renderSt
return RENDER3DERROR_NOERR;
}
// This method is currently unused right now, in favor of the new multithreaded
// SoftRasterizerRenderer::RenderEdgeMarkingAndFog() method. But let's keep this
// one around for reference just in case something goes horribly wrong with the
// new multithreaded method.
Render3DError SoftRasterizerRenderer::RenderEdgeMarking(const u16 *colorTable, const bool useAntialias)
{
// TODO: Old edge marking algorithm which tests only polyID, but checks the 8 surrounding pixels. Can this be removed?
// this looks ok although it's still pretty much a hack,
// it needs to be redone with low-level accuracy at some point,
// but that should probably wait until the shape renderer is more accurate.
// a good test case for edge marking is Sonic Rush:
// - the edges are completely sharp/opaque on the very brief title screen intro,
// - the level-start intro gets a pseudo-antialiasing effect around the silhouette,
// - the character edges in-level are clearly transparent, and also show well through shield powerups.
for (size_t i = 0, y = 0; y < this->_framebufferHeight; y++)
{
for (size_t x = 0; x < this->_framebufferWidth; x++, i++)
{
const u8 polyID = this->_framebufferAttributes->opaquePolyID[i];
if (this->edgeMarkDisabled[polyID>>3]) continue;
if (this->_framebufferAttributes->isTranslucentPoly[i] != 0) continue;
// > is used instead of != to prevent double edges
// between overlapping polys of different IDs.
// also note that the edge generally goes on the outside, not the inside, (maybe needs to change later)
// and that polys with the same edge color can make edges against each other.
const FragmentColor edgeColor = this->edgeMarkTable[polyID>>3];
#define PIXOFFSET(dx,dy) ((dx)+(this->_framebufferWidth*(dy)))
#define ISEDGE(dx,dy) ((x+(dx) < this->_framebufferWidth) && (y+(dy) < this->_framebufferHeight) && polyID > this->_framebufferAttributes->opaquePolyID[i+PIXOFFSET(dx,dy)])
#define DRAWEDGE(dx,dy) EdgeBlend(this->_framebufferColor[i+PIXOFFSET(dx,dy)], edgeColor)
bool upleft = ISEDGE(-1,-1);
bool up = ISEDGE( 0,-1);
bool upright = ISEDGE( 1,-1);
bool left = ISEDGE(-1, 0);
bool right = ISEDGE( 1, 0);
bool downleft = ISEDGE(-1, 1);
bool down = ISEDGE( 0, 1);
bool downright = ISEDGE( 1, 1);
if(upleft && upright && downleft && !downright)
DRAWEDGE(-1,-1);
if(up && !down)
DRAWEDGE(0,-1);
if(upleft && upright && !downleft && downright)
DRAWEDGE(1,-1);
if(left && !right)
DRAWEDGE(-1,0);
if(right && !left)
DRAWEDGE(1,0);
if(upleft && !upright && downleft && downright)
DRAWEDGE(-1,1);
if(down && !up)
DRAWEDGE(0,1);
if(!upleft && upright && downleft && downright)
DRAWEDGE(1,1);
#undef PIXOFFSET
#undef ISEDGE
#undef DRAWEDGE
}
}
return RENDER3DERROR_NOERR;
}
Render3DError SoftRasterizerRenderer::UpdateEdgeMarkColorTable(const u16 *edgeMarkColorTable)
{
//TODO: need to test and find out whether these get grabbed at flush time, or at render time
@ -2286,48 +2216,6 @@ Render3DError SoftRasterizerRenderer::UpdateFogTable(const u8 *fogDensityTable)
return RENDER3DERROR_NOERR;
}
// This method is currently unused right now, in favor of the new multithreaded
// SoftRasterizerRenderer::RenderEdgeMarkingAndFog() method. But let's keep this
// one around for reference just in case something goes horribly wrong with the
// new multithreaded method.
Render3DError SoftRasterizerRenderer::RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly)
{
FragmentColor fogColor;
fogColor.color = COLOR555TO6665( color & 0x7FFF, (color>>16) & 0x1F );
const size_t framebufferFragmentCount = this->_framebufferWidth * this->_framebufferHeight;
if (!alphaOnly)
{
for (size_t i = 0; i < framebufferFragmentCount; i++)
{
const size_t fogIndex = this->_framebufferAttributes->depth[i] >> 9;
assert(fogIndex < 32768);
const u8 fog = (this->_framebufferAttributes->isFogged[i] != 0) ? this->fogTable[fogIndex] : 0;
FragmentColor &destFragmentColor = this->_framebufferColor[i];
destFragmentColor.r = ((128-fog)*destFragmentColor.r + fogColor.r*fog)>>7;
destFragmentColor.g = ((128-fog)*destFragmentColor.g + fogColor.g*fog)>>7;
destFragmentColor.b = ((128-fog)*destFragmentColor.b + fogColor.b*fog)>>7;
destFragmentColor.a = ((128-fog)*destFragmentColor.a + fogColor.a*fog)>>7;
}
}
else
{
for (size_t i = 0; i < framebufferFragmentCount; i++)
{
const size_t fogIndex = this->_framebufferAttributes->depth[i] >> 9;
assert(fogIndex < 32768);
const u8 fog = (this->_framebufferAttributes->isFogged[i] != 0) ? this->fogTable[fogIndex] : 0;
FragmentColor &destFragmentColor = this->_framebufferColor[i];
destFragmentColor.a = ((128-fog)*destFragmentColor.a + fogColor.a*fog)>>7;
}
}
return RENDER3DERROR_NOERR;
}
Render3DError SoftRasterizerRenderer::RenderEdgeMarkingAndFog(const SoftRasterizerPostProcessParams &param)
{
for (size_t i = param.startLine * this->_framebufferWidth, y = param.startLine; y < param.endLine; y++)
@ -2338,45 +2226,75 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarkingAndFog(const SoftRasteriz
const u32 depth = this->_framebufferAttributes->depth[i];
const u8 polyID = this->_framebufferAttributes->opaquePolyID[i];
// TODO: New edge marking algorithm which tests both polyID and depth, but only checks 4 surrounding pixels. Can we keep this one?
if (param.enableEdgeMarking)
{
// this looks ok although it's still pretty much a hack,
// it needs to be redone with low-level accuracy at some point,
// but that should probably wait until the shape renderer is more accurate.
FragmentColor edgeMarkColor;
edgeMarkColor.color = 0;
// a good test case for edge marking is Sonic Rush:
// - the edges are completely sharp/opaque on the very brief title screen intro,
// - the level-start intro gets a pseudo-antialiasing effect around the silhouette,
// - the character edges in-level are clearly transparent, and also show well through shield powerups.
bool up = false;
bool left = false;
bool right = false;
bool down = false;
#define PIXOFFSET(dx,dy) ((dx)+(this->_framebufferWidth*(dy)))
#define ISEDGE(dx,dy) ((x+(dx) < this->_framebufferWidth) && (y+(dy) < this->_framebufferHeight) && polyID != this->_framebufferAttributes->opaquePolyID[i+PIXOFFSET(dx,dy)] && depth >= this->_framebufferAttributes->depth[i+PIXOFFSET(dx,dy)])
#define DRAWEDGE(dx,dy) EdgeBlend(dstColor, this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i+PIXOFFSET(dx,dy)] >> 3])
if (this->edgeMarkDisabled[polyID>>3] || this->_framebufferAttributes->isTranslucentPoly[i] != 0)
goto END_EDGE_MARK;
up = ISEDGE( 0,-1);
left = ISEDGE(-1, 0);
right = ISEDGE( 1, 0);
down = ISEDGE( 0, 1);
if (right) DRAWEDGE( 1, 0);
else if (down) DRAWEDGE( 0, 1);
else if (left) DRAWEDGE(-1, 0);
else if (up) DRAWEDGE( 0,-1);
#undef PIXOFFSET
#undef ISEDGE
#undef DRAWEDGE
END_EDGE_MARK: ;
if (!this->edgeMarkDisabled[polyID>>3] && this->_framebufferAttributes->isTranslucentPoly[i] == 0)
{
const bool isEdgeMarkingClearValues = ((polyID != this->_clearAttributes.opaquePolyID) && (depth < this->_clearAttributes.depth));
const bool right = (x >= this->_framebufferWidth-1) ? isEdgeMarkingClearValues : ((polyID != this->_framebufferAttributes->opaquePolyID[i+1]) && (depth >= this->_framebufferAttributes->depth[i+1]));
const bool down = (y >= this->_framebufferHeight-1) ? isEdgeMarkingClearValues : ((polyID != this->_framebufferAttributes->opaquePolyID[i+this->_framebufferWidth]) && (depth >= this->_framebufferAttributes->depth[i+this->_framebufferWidth]));
const bool left = (x < 1) ? isEdgeMarkingClearValues : ((polyID != this->_framebufferAttributes->opaquePolyID[i-1]) && (depth >= this->_framebufferAttributes->depth[i-1]));
const bool up = (y < 1) ? isEdgeMarkingClearValues : ((polyID != this->_framebufferAttributes->opaquePolyID[i-this->_framebufferWidth]) && (depth >= this->_framebufferAttributes->depth[i-this->_framebufferWidth]));
if (right)
{
if (x >= this->_framebufferWidth - 1)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i+1] >> 3];
}
}
else if (down)
{
if (y >= this->_framebufferHeight - 1)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i+this->_framebufferWidth] >> 3];
}
}
else if (left)
{
if (x < 1)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i-1] >> 3];
}
}
else if (up)
{
if (y < 1)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i-this->_framebufferWidth] >> 3];
}
}
if (right || down || left || up)
{
EdgeBlend(dstColor, edgeMarkColor);
}
}
}
if (param.enableFog)
@ -2476,9 +2394,6 @@ void SoftRasterizerRenderer::ClearUsingValues_Execute(const size_t startPixel, c
Render3DError SoftRasterizerRenderer::ClearUsingValues(const FragmentColor &clearColor6665, const FragmentAttributes &clearAttributes)
{
this->_clearColor6665 = clearColor6665;
this->_clearAttributes = clearAttributes;
const bool doMultithreadedClear = (this->_threadCount > 0);
if (doMultithreadedClear)
@ -2531,6 +2446,20 @@ Render3DError SoftRasterizerRenderer::Render(const GFX3D &engine)
Render3DError error = RENDER3DERROR_NOERR;
this->_isPoweredOn = true;
const u32 clearColorSwapped = LE_TO_LOCAL_32(engine.renderState.clearColor);
this->_clearColor6665.color = COLOR555TO6665(clearColorSwapped & 0x7FFF, (clearColorSwapped >> 16) & 0x1F);
this->_clearAttributes.opaquePolyID = (clearColorSwapped >> 24) & 0x3F;
//special value for uninitialized translucent polyid. without this, fires in spiderman2 dont display
//I am not sure whether it is right, though. previously this was cleared to 0, as a guess,
//but in spiderman2 some fires with polyid 0 try to render on top of the background
this->_clearAttributes.translucentPolyID = kUnsetTranslucentPolyID;
this->_clearAttributes.depth = engine.renderState.clearDepth;
this->_clearAttributes.stencil = 0;
this->_clearAttributes.isTranslucentPoly = 0;
this->_clearAttributes.polyFacing = PolyFacing_Unwritten;
this->_clearAttributes.isFogged = BIT15(clearColorSwapped);
error = this->BeginRender(engine);
if (error != RENDER3DERROR_NOERR)
{

View File

@ -158,9 +158,6 @@ protected:
size_t _customLinesPerThread;
size_t _customPixelsPerThread;
FragmentColor _clearColor6665;
FragmentAttributes _clearAttributes;
GFX3D_Clipper clipper;
u8 fogTable[32768];
FragmentColor edgeMarkTable[8];
@ -179,8 +176,6 @@ protected:
// Base rendering methods
virtual Render3DError BeginRender(const GFX3D &engine);
virtual Render3DError RenderGeometry(const GFX3D_State &renderState, const POLYLIST *polyList, const INDEXLIST *indexList);
virtual Render3DError RenderEdgeMarking(const u16 *colorTable, const bool useAntialias);
virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift, const bool alphaOnly);
virtual Render3DError EndRender(const u64 frameCount);
virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 *__restrict polyIDBuffer);

View File

@ -562,22 +562,6 @@ Render3DError Render3D::ClearFramebuffer(const GFX3D_State &renderState)
{
Render3DError error = RENDER3DERROR_NOERR;
const u32 clearColorSwapped = LE_TO_LOCAL_32(renderState.clearColor);
FragmentColor clearColor6665;
clearColor6665.color = COLOR555TO6665(clearColorSwapped & 0x7FFF, (clearColorSwapped >> 16) & 0x1F);
FragmentAttributes clearFragment;
clearFragment.opaquePolyID = (clearColorSwapped >> 24) & 0x3F;
//special value for uninitialized translucent polyid. without this, fires in spiderman2 dont display
//I am not sure whether it is right, though. previously this was cleared to 0, as a guess,
//but in spiderman2 some fires with polyid 0 try to render on top of the background
clearFragment.translucentPolyID = kUnsetTranslucentPolyID;
clearFragment.depth = renderState.clearDepth;
clearFragment.stencil = 0;
clearFragment.isTranslucentPoly = 0;
clearFragment.polyFacing = PolyFacing_Unwritten;
clearFragment.isFogged = BIT15(clearColorSwapped);
if (renderState.enableClearImage)
{
//the lion, the witch, and the wardrobe (thats book 1, suck it you new-school numberers)
@ -595,7 +579,7 @@ Render3DError Render3D::ClearFramebuffer(const GFX3D_State &renderState)
this->clearImageColor16Buffer[i] = clearColorBuffer[i];
this->clearImageDepthBuffer[i] = DS_DEPTH15TO24(clearDepthBuffer[i]);
this->clearImageFogBuffer[i] = BIT15(clearDepthBuffer[i]);
this->clearImagePolyIDBuffer[i] = clearFragment.opaquePolyID;
this->clearImagePolyIDBuffer[i] = this->_clearAttributes.opaquePolyID;
}
}
else
@ -605,22 +589,22 @@ Render3DError Render3D::ClearFramebuffer(const GFX3D_State &renderState)
if (!isClearColorBlank && !isClearDepthBlank)
{
this->_ClearImageScrolledLoop<false, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop<false, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
else if (isClearColorBlank)
{
this->_ClearImageScrolledLoop< true, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop< true, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
else if (isClearDepthBlank)
{
this->_ClearImageScrolledLoop<false, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop<false, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
else
{
this->_ClearImageScrolledLoop< true, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop< true, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
}
@ -628,12 +612,12 @@ Render3DError Render3D::ClearFramebuffer(const GFX3D_State &renderState)
error = this->ClearUsingImage(this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
if (error != RENDER3DERROR_NOERR)
{
error = this->ClearUsingValues(clearColor6665, clearFragment);
error = this->ClearUsingValues(this->_clearColor6665, this->_clearAttributes);
}
}
else
{
error = this->ClearUsingValues(clearColor6665, clearFragment);
error = this->ClearUsingValues(this->_clearColor6665, this->_clearAttributes);
}
return error;
@ -671,6 +655,9 @@ Render3DError Render3D::Reset()
memset(this->clearImagePolyIDBuffer, 0, sizeof(this->clearImagePolyIDBuffer));
memset(this->clearImageFogBuffer, 0, sizeof(this->clearImageFogBuffer));
this->_clearColor6665.color = 0;
memset(&this->_clearAttributes, 0, sizeof(FragmentAttributes));
this->_renderNeedsFinish = false;
this->_renderNeedsFlushMain = false;
this->_renderNeedsFlush16 = false;
@ -700,6 +687,20 @@ Render3DError Render3D::Render(const GFX3D &engine)
Render3DError error = RENDER3DERROR_NOERR;
this->_isPoweredOn = true;
const u32 clearColorSwapped = LE_TO_LOCAL_32(engine.renderState.clearColor);
this->_clearColor6665.color = COLOR555TO6665(clearColorSwapped & 0x7FFF, (clearColorSwapped >> 16) & 0x1F);
this->_clearAttributes.opaquePolyID = (clearColorSwapped >> 24) & 0x3F;
//special value for uninitialized translucent polyid. without this, fires in spiderman2 dont display
//I am not sure whether it is right, though. previously this was cleared to 0, as a guess,
//but in spiderman2 some fires with polyid 0 try to render on top of the background
this->_clearAttributes.translucentPolyID = kUnsetTranslucentPolyID;
this->_clearAttributes.depth = engine.renderState.clearDepth;
this->_clearAttributes.stencil = 0;
this->_clearAttributes.isTranslucentPoly = 0;
this->_clearAttributes.polyFacing = PolyFacing_Unwritten;
this->_clearAttributes.isFogged = BIT15(clearColorSwapped);
error = this->BeginRender(engine);
if (error != RENDER3DERROR_NOERR)
{
@ -772,21 +773,6 @@ Render3DError Render3D_SSE2::ClearFramebuffer(const GFX3D_State &renderState)
{
Render3DError error = RENDER3DERROR_NOERR;
FragmentColor clearColor6665;
clearColor6665.color = COLOR555TO6665(renderState.clearColor & 0x7FFF, (renderState.clearColor >> 16) & 0x1F);
FragmentAttributes clearFragment;
clearFragment.opaquePolyID = (renderState.clearColor >> 24) & 0x3F;
//special value for uninitialized translucent polyid. without this, fires in spiderman2 dont display
//I am not sure whether it is right, though. previously this was cleared to 0, as a guess,
//but in spiderman2 some fires with polyid 0 try to render on top of the background
clearFragment.translucentPolyID = kUnsetTranslucentPolyID;
clearFragment.depth = renderState.clearDepth;
clearFragment.stencil = 0;
clearFragment.isTranslucentPoly = 0;
clearFragment.polyFacing = PolyFacing_Unwritten;
clearFragment.isFogged = BIT15(renderState.clearColor);
if (renderState.enableClearImage)
{
//the lion, the witch, and the wardrobe (thats book 1, suck it you new-school numberers)
@ -797,7 +783,7 @@ Render3DError Render3D_SSE2::ClearFramebuffer(const GFX3D_State &renderState)
const u8 xScroll = scrollBits & 0xFF;
const u8 yScroll = (scrollBits >> 8) & 0xFF;
const __m128i opaquePolyID_vec128 = _mm_set1_epi8(clearFragment.opaquePolyID);
const __m128i opaquePolyID_vec128 = _mm_set1_epi8(this->_clearAttributes.opaquePolyID);
const __m128i calcDepthConstants = _mm_set1_epi32(0x01FF0200);
if (xScroll == 0 && yScroll == 0)
@ -811,18 +797,19 @@ Render3DError Render3D_SSE2::ClearFramebuffer(const GFX3D_State &renderState)
// Write the depth values to the depth buffer using the following formula from GBATEK.
// 15-bit to 24-bit depth formula from http://problemkaputt.de/gbatek.htm#ds3drearplane
// D24 = (D15 * 0x0200) + (((D15 + 1) >> 15) * 0x01FF);
//
// For now, let's forget GBATEK (which could be wrong) and try using a simpified formula:
// D24 = (D15 * 0x0200) + 0x01FF;
const __m128i clearDepthLo = _mm_load_si128((__m128i *)(clearDepthBuffer + i + 0));
const __m128i clearDepthHi = _mm_load_si128((__m128i *)(clearDepthBuffer + i + 8));
const __m128i clearDepthValueLo = _mm_and_si128(clearDepthLo, _mm_set1_epi16(0x7FFF));
const __m128i clearDepthValueHi = _mm_and_si128(clearDepthHi, _mm_set1_epi16(0x7FFF));
const __m128i highestDepthBitLo = _mm_srli_epi16( _mm_adds_epu16(clearDepthValueLo, _mm_set1_epi16(1)), 15);
const __m128i highestDepthBitHi = _mm_srli_epi16( _mm_adds_epu16(clearDepthValueHi, _mm_set1_epi16(1)), 15);
__m128i calcDepth0 = _mm_unpacklo_epi16(clearDepthValueLo, highestDepthBitLo);
__m128i calcDepth1 = _mm_unpackhi_epi16(clearDepthValueLo, highestDepthBitLo);
__m128i calcDepth2 = _mm_unpacklo_epi16(clearDepthValueHi, highestDepthBitHi);
__m128i calcDepth3 = _mm_unpackhi_epi16(clearDepthValueHi, highestDepthBitHi);
__m128i calcDepth0 = _mm_unpacklo_epi16(clearDepthValueLo, _mm_set1_epi16(1));
__m128i calcDepth1 = _mm_unpackhi_epi16(clearDepthValueLo, _mm_set1_epi16(1));
__m128i calcDepth2 = _mm_unpacklo_epi16(clearDepthValueHi, _mm_set1_epi16(1));
__m128i calcDepth3 = _mm_unpackhi_epi16(clearDepthValueHi, _mm_set1_epi16(1));
calcDepth0 = _mm_madd_epi16(calcDepth0, calcDepthConstants);
calcDepth1 = _mm_madd_epi16(calcDepth1, calcDepthConstants);
@ -948,22 +935,22 @@ Render3DError Render3D_SSE2::ClearFramebuffer(const GFX3D_State &renderState)
if (!isClearColorBlank && !isClearDepthBlank)
{
this->_ClearImageScrolledLoop<false, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop<false, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
else if (isClearColorBlank)
{
this->_ClearImageScrolledLoop< true, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop< true, false>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
else if (isClearDepthBlank)
{
this->_ClearImageScrolledLoop<false, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop<false, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
else
{
this->_ClearImageScrolledLoop< true, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, clearFragment.opaquePolyID,
this->_ClearImageScrolledLoop< true, true>(xScroll, yScroll, clearColorBuffer, clearDepthBuffer, this->_clearAttributes.opaquePolyID,
this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
}
}
@ -971,12 +958,12 @@ Render3DError Render3D_SSE2::ClearFramebuffer(const GFX3D_State &renderState)
error = this->ClearUsingImage(this->clearImageColor16Buffer, this->clearImageDepthBuffer, this->clearImageFogBuffer, this->clearImagePolyIDBuffer);
if (error != RENDER3DERROR_NOERR)
{
error = this->ClearUsingValues(clearColor6665, clearFragment);
error = this->ClearUsingValues(this->_clearColor6665, this->_clearAttributes);
}
}
else
{
error = this->ClearUsingValues(clearColor6665, clearFragment);
error = this->ClearUsingValues(this->_clearColor6665, this->_clearAttributes);
}
return error;

View File

@ -157,6 +157,9 @@ protected:
size_t _framebufferColorSizeBytes;
FragmentColor *_framebufferColor;
FragmentColor _clearColor6665;
FragmentAttributes _clearAttributes;
NDSColorFormat _internalRenderingFormat;
NDSColorFormat _outputFormat;
bool _renderNeedsFinish;