Render3D:
- In SoftRasterizer, do multithreading optimization for the fog and edge mark pass. This involved a change to the edge marking algorithm, so this will need additional testing. - Fix bug where a SoftRasterizer renderer object wouldn’t get destroyed properly. (Regression from r5187.) - Fix bug where the user wasn’t able to switch between different threaded versions of SoftRasterizer. (Regression from r5187.) - Fix a potential bug that might occur if an OpenGL renderer object failed to create. (Regression from r5188.)
This commit is contained in:
parent
c36b8cbebb
commit
dcbe28c94e
|
@ -610,6 +610,8 @@ static Render3D* OpenGLRendererCreate()
|
|||
if(!strcmp(oglVendorString,"Intel") && strstr(oglRendererString,"965"))
|
||||
{
|
||||
INFO("OpenGL: Incompatible graphic card detected. Disabling OpenGL support.\n");
|
||||
|
||||
ENDGL();
|
||||
return newRenderer;
|
||||
}
|
||||
|
||||
|
@ -622,6 +624,7 @@ static Render3D* OpenGLRendererCreate()
|
|||
OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION,
|
||||
oglVersionString, oglVendorString, oglRendererString);
|
||||
|
||||
ENDGL();
|
||||
return newRenderer;
|
||||
}
|
||||
|
||||
|
@ -637,7 +640,10 @@ static Render3D* OpenGLRendererCreate()
|
|||
else
|
||||
{
|
||||
if(require_profile)
|
||||
{
|
||||
ENDGL();
|
||||
return newRenderer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -683,6 +689,8 @@ static Render3D* OpenGLRendererCreate()
|
|||
{
|
||||
INFO("OpenGL: Renderer did not initialize. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n",
|
||||
oglVersionString, oglVendorString, oglRendererString);
|
||||
|
||||
ENDGL();
|
||||
return newRenderer;
|
||||
}
|
||||
|
||||
|
@ -699,6 +707,7 @@ static Render3D* OpenGLRendererCreate()
|
|||
delete newRenderer;
|
||||
newRenderer = NULL;
|
||||
|
||||
ENDGL();
|
||||
return newRenderer;
|
||||
}
|
||||
else if (IsVersionSupported(3, 0, 0) && error == OGLERROR_FBO_CREATE_ERROR && OGLLoadEntryPoints_3_2_Func != NULL)
|
||||
|
@ -707,6 +716,7 @@ static Render3D* OpenGLRendererCreate()
|
|||
delete newRenderer;
|
||||
newRenderer = NULL;
|
||||
|
||||
ENDGL();
|
||||
return newRenderer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1111,6 +1111,14 @@ static void* SoftRasterizer_RunClearFramebuffer(void *arg)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void* SoftRasterizer_RunRenderEdgeMarkAndFog(void *arg)
|
||||
{
|
||||
SoftRasterizerPostProcessParams *params = (SoftRasterizerPostProcessParams *)arg;
|
||||
params->renderer->RenderEdgeMarkingAndFog(*params);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _HACK_Viewer_ExecUnit()
|
||||
{
|
||||
_HACK_viewer_rasterizerUnit.mainLoop<false>();
|
||||
|
@ -1121,10 +1129,19 @@ static Render3D* SoftRasterizerRendererCreate()
|
|||
return new SoftRasterizerRenderer;
|
||||
}
|
||||
|
||||
static void SoftRasterizerRendererDestroy()
|
||||
{
|
||||
if (CurrentRenderer != BaseRenderer)
|
||||
{
|
||||
delete (SoftRasterizerRenderer *)CurrentRenderer;
|
||||
CurrentRenderer = BaseRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
GPU3DInterface gpu3DRasterize = {
|
||||
"SoftRasterizer",
|
||||
SoftRasterizerRendererCreate,
|
||||
Render3DBaseDestroy
|
||||
SoftRasterizerRendererDestroy
|
||||
};
|
||||
|
||||
SoftRasterizerRenderer::SoftRasterizerRenderer()
|
||||
|
@ -1159,15 +1176,35 @@ SoftRasterizerRenderer::SoftRasterizerRenderer()
|
|||
rasterizerUnit[0]._debug_thisPoly = false;
|
||||
rasterizerUnit[0].SLI_MASK = 0;
|
||||
rasterizerUnit[0].SLI_VALUE = 0;
|
||||
|
||||
postprocessParam = new SoftRasterizerPostProcessParams[rasterizerCores];
|
||||
postprocessParam[0].renderer = this;
|
||||
postprocessParam[0].startLine = 0;
|
||||
postprocessParam[0].endLine = _framebufferHeight;
|
||||
postprocessParam[0].enableEdgeMarking = true;
|
||||
postprocessParam[0].enableFog = true;
|
||||
postprocessParam[0].fogColor = 0x80FFFFFF;
|
||||
postprocessParam[0].fogAlphaOnly = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t linesPerThread = _framebufferHeight / rasterizerCores;
|
||||
postprocessParam = new SoftRasterizerPostProcessParams[rasterizerCores];
|
||||
|
||||
for (size_t i = 0; i < rasterizerCores; i++)
|
||||
{
|
||||
rasterizerUnit[i]._debug_thisPoly = false;
|
||||
rasterizerUnit[i].SLI_MASK = (rasterizerCores - 1);
|
||||
rasterizerUnit[i].SLI_VALUE = i;
|
||||
rasterizerUnitTask[i].start(false);
|
||||
|
||||
postprocessParam[i].renderer = this;
|
||||
postprocessParam[i].startLine = i * linesPerThread;
|
||||
postprocessParam[i].endLine = (i < rasterizerCores - 1) ? (i + 1) * linesPerThread : _framebufferHeight;
|
||||
postprocessParam[i].enableEdgeMarking = true;
|
||||
postprocessParam[i].enableFog = true;
|
||||
postprocessParam[i].fogColor = 0x80FFFFFF;
|
||||
postprocessParam[i].fogAlphaOnly = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1192,6 +1229,8 @@ SoftRasterizerRenderer::~SoftRasterizerRenderer()
|
|||
}
|
||||
|
||||
rasterizerUnitTasksInited = false;
|
||||
delete[] postprocessParam;
|
||||
postprocessParam = NULL;
|
||||
|
||||
free(screenAttributes);
|
||||
free(screenColor);
|
||||
|
@ -1499,8 +1538,14 @@ 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.
|
||||
|
@ -1513,20 +1558,21 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarking(const u16 *colorTable, c
|
|||
{
|
||||
for (size_t x = 0; x < this->_framebufferWidth; x++, i++)
|
||||
{
|
||||
FragmentAttributes destFragment = screenAttributes[i];
|
||||
u8 self = destFragment.opaquePolyID;
|
||||
if(edgeMarkDisabled[self>>3]) continue;
|
||||
if(destFragment.isTranslucentPoly) continue;
|
||||
const FragmentAttributes dstAttributes = this->screenAttributes[i];
|
||||
const u8 polyID = dstAttributes.opaquePolyID;
|
||||
|
||||
if(this->edgeMarkDisabled[polyID>>3]) continue;
|
||||
if(dstAttributes.isTranslucentPoly) 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.
|
||||
|
||||
FragmentColor edgeColor = this->edgeMarkTable[self>>3];
|
||||
FragmentColor edgeColor = this->edgeMarkTable[polyID>>3];
|
||||
|
||||
#define PIXOFFSET(dx,dy) ((dx)+(GFX3D_FRAMEBUFFER_WIDTH*(dy)))
|
||||
#define ISEDGE(dx,dy) ((x+(dx)!=GFX3D_FRAMEBUFFER_WIDTH) && (x+(dx)!=-1) && (y+(dy)!=GFX3D_FRAMEBUFFER_HEIGHT) && (y+(dy)!=-1) && self > screenAttributes[i+PIXOFFSET(dx,dy)].opaquePolyID)
|
||||
#define PIXOFFSET(dx,dy) ((dx)+(this->_framebufferWidth*(dy)))
|
||||
#define ISEDGE(dx,dy) ((x+(dx) < this->_framebufferWidth) && (y+(dy) < this->_framebufferHeight) && polyID > this->screenAttributes[i+PIXOFFSET(dx,dy)].opaquePolyID)
|
||||
#define DRAWEDGE(dx,dy) alphaBlend(screenColor[i+PIXOFFSET(dx,dy)], edgeColor)
|
||||
|
||||
bool upleft = ISEDGE(-1,-1);
|
||||
|
@ -1558,7 +1604,6 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarking(const u16 *colorTable, c
|
|||
#undef PIXOFFSET
|
||||
#undef ISEDGE
|
||||
#undef DRAWEDGE
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1653,6 +1698,10 @@ 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)
|
||||
{
|
||||
u32 r = GFX3D_5TO6((color)&0x1F);
|
||||
|
@ -1694,6 +1743,99 @@ Render3DError SoftRasterizerRenderer::RenderFog(const u8 *densityTable, const u3
|
|||
return RENDER3DERROR_NOERR;
|
||||
}
|
||||
|
||||
Render3DError SoftRasterizerRenderer::RenderEdgeMarkingAndFog(const SoftRasterizerPostProcessParams ¶m)
|
||||
{
|
||||
for (size_t i = param.startLine * this->_framebufferWidth, y = param.startLine; y < param.endLine; y++)
|
||||
{
|
||||
for (size_t x = 0; x < this->_framebufferWidth; x++, i++)
|
||||
{
|
||||
FragmentColor &dstColor = screenColor[i];
|
||||
const FragmentAttributes dstAttributes = this->screenAttributes[i];
|
||||
const u32 depth = dstAttributes.depth;
|
||||
const u8 polyID = dstAttributes.opaquePolyID;
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
|
||||
FragmentColor edgeColor = this->edgeMarkTable[polyID>>3];
|
||||
bool right = false;
|
||||
bool down = false;
|
||||
bool left = false;
|
||||
bool up = false;
|
||||
|
||||
#define PIXOFFSET(dx,dy) ((dx)+(this->_framebufferWidth*(dy)))
|
||||
#define ISEDGE(dx,dy) ((x+(dx) < this->_framebufferWidth) && (y+(dy) < this->_framebufferHeight) && polyID != this->screenAttributes[i+PIXOFFSET(dx,dy)].opaquePolyID && depth >= this->screenAttributes[i+PIXOFFSET(dx,dy)].depth)
|
||||
|
||||
up = ISEDGE( 0,-1);
|
||||
left = ISEDGE(-1, 0);
|
||||
right = ISEDGE( 1, 0);
|
||||
down = ISEDGE( 0, 1);
|
||||
|
||||
if(this->edgeMarkDisabled[polyID>>3]) goto END_EDGE_MARK;
|
||||
if(dstAttributes.isTranslucentPoly) goto END_EDGE_MARK;
|
||||
|
||||
if (right)
|
||||
{
|
||||
edgeColor = this->edgeMarkTable[this->screenAttributes[i+PIXOFFSET( 1, 0)].opaquePolyID >> 3];
|
||||
alphaBlend(dstColor, edgeColor);
|
||||
}
|
||||
else if (down)
|
||||
{
|
||||
edgeColor = this->edgeMarkTable[this->screenAttributes[i+PIXOFFSET( 0, 1)].opaquePolyID >> 3];
|
||||
alphaBlend(dstColor, edgeColor);
|
||||
}
|
||||
else if (left)
|
||||
{
|
||||
edgeColor = this->edgeMarkTable[this->screenAttributes[i+PIXOFFSET(-1, 0)].opaquePolyID >> 3];
|
||||
alphaBlend(dstColor, edgeColor);
|
||||
}
|
||||
else if (up)
|
||||
{
|
||||
edgeColor = this->edgeMarkTable[this->screenAttributes[i+PIXOFFSET( 0,-1)].opaquePolyID >> 3];
|
||||
alphaBlend(dstColor, edgeColor);
|
||||
}
|
||||
|
||||
#undef PIXOFFSET
|
||||
#undef ISEDGE
|
||||
#undef DRAWEDGE
|
||||
|
||||
END_EDGE_MARK: ;
|
||||
}
|
||||
|
||||
if (param.enableFog)
|
||||
{
|
||||
const u32 r = GFX3D_5TO6((param.fogColor)&0x1F);
|
||||
const u32 g = GFX3D_5TO6((param.fogColor>>5)&0x1F);
|
||||
const u32 b = GFX3D_5TO6((param.fogColor>>10)&0x1F);
|
||||
const u32 a = (param.fogColor>>16)&0x1F;
|
||||
|
||||
const size_t fogIndex = depth >> 9;
|
||||
assert(fogIndex < 32768);
|
||||
const u8 fog = (dstAttributes.isFogged) ? this->fogTable[fogIndex] : 0;
|
||||
|
||||
if (!param.fogAlphaOnly)
|
||||
{
|
||||
dstColor.r = ((128-fog)*dstColor.r + r*fog)>>7;
|
||||
dstColor.g = ((128-fog)*dstColor.g + g*fog)>>7;
|
||||
dstColor.b = ((128-fog)*dstColor.b + b*fog)>>7;
|
||||
}
|
||||
|
||||
dstColor.a = ((128-fog)*dstColor.a + a*fog)>>7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RENDER3DERROR_NOERR;
|
||||
}
|
||||
|
||||
Render3DError SoftRasterizerRenderer::UpdateToonTable(const u16 *toonTableBuffer)
|
||||
{
|
||||
//convert the toon colors
|
||||
|
@ -1802,14 +1944,17 @@ Render3DError SoftRasterizerRenderer::EndRender(const u64 frameCount)
|
|||
// If we're not multithreaded, then just do the post-processing steps now.
|
||||
if (!this->_renderGeometryNeedsFinish)
|
||||
{
|
||||
if (this->currentRenderState->enableEdgeMarking)
|
||||
if (this->currentRenderState->enableEdgeMarking || this->currentRenderState->enableFog)
|
||||
{
|
||||
this->RenderEdgeMarking(this->currentRenderState->edgeMarkColorTable, this->currentRenderState->enableAntialiasing);
|
||||
}
|
||||
|
||||
if (this->currentRenderState->enableFog)
|
||||
{
|
||||
this->RenderFog(this->currentRenderState->fogDensityTable, this->currentRenderState->fogColor, this->currentRenderState->fogOffset, this->currentRenderState->fogShift, this->currentRenderState->enableFogAlphaOnly);
|
||||
this->postprocessParam[0].renderer = this;
|
||||
this->postprocessParam[0].startLine = 0;
|
||||
this->postprocessParam[0].endLine = this->_framebufferHeight;
|
||||
this->postprocessParam[0].enableEdgeMarking = this->currentRenderState->enableEdgeMarking;
|
||||
this->postprocessParam[0].enableFog = this->currentRenderState->enableFog;
|
||||
this->postprocessParam[0].fogColor = this->currentRenderState->fogColor;
|
||||
this->postprocessParam[0].fogAlphaOnly = this->currentRenderState->enableFogAlphaOnly;
|
||||
|
||||
this->RenderEdgeMarkingAndFog(this->postprocessParam[0]);
|
||||
}
|
||||
|
||||
memcpy(gfx3d_convertedScreen, this->screenColor, this->_framebufferWidth * this->_framebufferHeight * sizeof(FragmentColor));
|
||||
|
@ -1825,21 +1970,31 @@ Render3DError SoftRasterizerRenderer::RenderFinish()
|
|||
return RENDER3DERROR_NOERR;
|
||||
}
|
||||
|
||||
// Allow for the geometry rendering to finish.
|
||||
this->_renderGeometryNeedsFinish = false;
|
||||
|
||||
for (size_t i = 0; i < rasterizerCores; i++)
|
||||
{
|
||||
rasterizerUnitTask[i].finish();
|
||||
}
|
||||
|
||||
if (this->currentRenderState->enableEdgeMarking)
|
||||
// Do multithreaded post-processing.
|
||||
if (this->currentRenderState->enableEdgeMarking || this->currentRenderState->enableFog)
|
||||
{
|
||||
this->RenderEdgeMarking(this->currentRenderState->edgeMarkColorTable, this->currentRenderState->enableAntialiasing);
|
||||
}
|
||||
|
||||
if (this->currentRenderState->enableFog)
|
||||
{
|
||||
this->RenderFog(this->currentRenderState->fogDensityTable, this->currentRenderState->fogColor, this->currentRenderState->fogOffset, this->currentRenderState->fogShift, this->currentRenderState->enableFogAlphaOnly);
|
||||
for (size_t i = 0; i < rasterizerCores; i++)
|
||||
{
|
||||
this->postprocessParam[i].enableEdgeMarking = this->currentRenderState->enableEdgeMarking;
|
||||
this->postprocessParam[i].enableFog = this->currentRenderState->enableFog;
|
||||
this->postprocessParam[i].fogColor = this->currentRenderState->fogColor;
|
||||
this->postprocessParam[i].fogAlphaOnly = this->currentRenderState->enableFogAlphaOnly;
|
||||
|
||||
rasterizerUnitTask[i].execute(&SoftRasterizer_RunRenderEdgeMarkAndFog, &this->postprocessParam[i]);
|
||||
}
|
||||
|
||||
// Allow for post-processing to finish.
|
||||
for (size_t i = 0; i < rasterizerCores; i++)
|
||||
{
|
||||
rasterizerUnitTask[i].finish();
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(gfx3d_convertedScreen, this->screenColor, this->_framebufferWidth * this->_framebufferHeight * sizeof(FragmentColor));
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
extern GPU3DInterface gpu3DRasterize;
|
||||
|
||||
class TexCacheItem;
|
||||
class SoftRasterizerRenderer;
|
||||
|
||||
struct SoftRasterizerPostProcessParams
|
||||
{
|
||||
SoftRasterizerRenderer *renderer;
|
||||
size_t startLine;
|
||||
size_t endLine;
|
||||
bool enableEdgeMarking;
|
||||
bool enableFog;
|
||||
u32 fogColor;
|
||||
bool fogAlphaOnly;
|
||||
};
|
||||
|
||||
class SoftRasterizerRenderer : public Render3D
|
||||
{
|
||||
|
@ -64,6 +76,7 @@ public:
|
|||
size_t _framebufferWidth;
|
||||
size_t _framebufferHeight;
|
||||
GFX3D_State *currentRenderState;
|
||||
SoftRasterizerPostProcessParams *postprocessParam;
|
||||
|
||||
SoftRasterizerRenderer();
|
||||
virtual ~SoftRasterizerRenderer();
|
||||
|
@ -74,6 +87,7 @@ public:
|
|||
void setupTextures();
|
||||
Render3DError UpdateEdgeMarkColorTable(const u16 *edgeMarkColorTable);
|
||||
Render3DError UpdateFogTable(const u8 *fogDensityTable);
|
||||
Render3DError RenderEdgeMarkingAndFog(const SoftRasterizerPostProcessParams ¶m);
|
||||
|
||||
// Base rendering methods
|
||||
virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer);
|
||||
|
|
|
@ -70,12 +70,6 @@ bool NDS_3D_ChangeCore(int newCore)
|
|||
return result;
|
||||
}
|
||||
|
||||
if (newRenderInterface == gpu3D)
|
||||
{
|
||||
result = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Some resources are shared between renderers, such as the texture cache,
|
||||
// so we need to shut down the current renderer now to ensure that any
|
||||
// shared resources aren't in use.
|
||||
|
|
|
@ -139,7 +139,7 @@ public:
|
|||
// and only release the block when 3D rendering is finished. (Before reading the 3D layer, be
|
||||
// sure to always call this function.)
|
||||
|
||||
virtual Render3DError VramReconfigureSignal(); // Called when the emulator reconfigures its VRAM. Ypu may need to invalidate your texture cache.
|
||||
virtual Render3DError VramReconfigureSignal(); // Called when the emulator reconfigures its VRAM. You may need to invalidate your texture cache.
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue