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:
rogerman 2015-05-07 19:06:13 +00:00
parent c36b8cbebb
commit dcbe28c94e
5 changed files with 204 additions and 31 deletions

View File

@ -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;
}
}

View File

@ -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 &param)
{
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));

View File

@ -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 &param);
// Base rendering methods
virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer);

View File

@ -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.

View File

@ -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