OpenGL Renderer: Before rendering, determine the list of clipped polygons, and then only render the clipped polygons, just like how SoftRasterizer does it. Most 3D games will see a significant performance improvement. For certain games with very high polygon count scenes, those games will see a massive performance boost.

This commit is contained in:
rogerman 2019-01-21 16:21:32 -08:00
parent bb93a0a365
commit 4cd19ce522
10 changed files with 405 additions and 211 deletions

View File

@ -1264,12 +1264,12 @@ OpenGLRenderer::OpenGLRenderer()
OpenGLRenderer::~OpenGLRenderer() OpenGLRenderer::~OpenGLRenderer()
{ {
free_aligned(_framebufferColor); free_aligned(this->_framebufferColor);
free_aligned(_workingTextureUnpackBuffer); free_aligned(this->_workingTextureUnpackBuffer);
// Destroy OpenGL rendering states // Destroy OpenGL rendering states
delete ref; delete this->ref;
ref = NULL; this->ref = NULL;
} }
bool OpenGLRenderer::IsExtensionPresent(const std::set<std::string> *oglExtensionSet, const std::string extensionName) const bool OpenGLRenderer::IsExtensionPresent(const std::set<std::string> *oglExtensionSet, const std::string extensionName) const
@ -1833,9 +1833,9 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLYLIST *polyList, const
{ {
OGLRenderRef &OGLRef = *this->ref; OGLRenderRef &OGLRef = *this->ref;
if (lastIndex > (polyList->count - 1)) if (lastIndex > (this->_clippedPolyCount - 1))
{ {
lastIndex = polyList->count - 1; lastIndex = this->_clippedPolyCount - 1;
} }
if (firstIndex > lastIndex) if (firstIndex > lastIndex)
@ -1860,7 +1860,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLYLIST *polyList, const
}; };
// Set up the initial polygon // Set up the initial polygon
const POLY &initialPoly = polyList->list[indexList->list[firstIndex]]; const POLY &initialPoly = *this->_clipper.GetClippedPolyByIndex(firstIndex).poly;
TEXIMAGE_PARAM lastTexParams = initialPoly.texParam; TEXIMAGE_PARAM lastTexParams = initialPoly.texParam;
u32 lastTexPalette = initialPoly.texPalette; u32 lastTexPalette = initialPoly.texPalette;
u32 lastViewport = initialPoly.viewport; u32 lastViewport = initialPoly.viewport;
@ -1874,7 +1874,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLYLIST *polyList, const
for (size_t i = firstIndex; i <= lastIndex; i++) for (size_t i = firstIndex; i <= lastIndex; i++)
{ {
const POLY &thePoly = polyList->list[indexList->list[i]]; const POLY &thePoly = *this->_clipper.GetClippedPolyByIndex(i).poly;
// Set up the polygon if it changed // Set up the polygon if it changed
if (lastPolyAttr.value != thePoly.attribute.value) if (lastPolyAttr.value != thePoly.attribute.value)
@ -1914,7 +1914,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLYLIST *polyList, const
// the same and we're not drawing a line loop or line strip. // the same and we're not drawing a line loop or line strip.
if (i+1 <= lastIndex) if (i+1 <= lastIndex)
{ {
const POLY &nextPoly = polyList->list[indexList->list[i+1]]; const POLY &nextPoly = *this->_clipper.GetClippedPolyByIndex(i+1).poly;
if (lastPolyAttr.value == nextPoly.attribute.value && if (lastPolyAttr.value == nextPoly.attribute.value &&
lastTexParams.value == nextPoly.texParam.value && lastTexParams.value == nextPoly.texParam.value &&
@ -4051,7 +4051,7 @@ Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const POLYLIST *polyList, con
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
glStencilFunc(GL_NOTEQUAL, 0x40, 0x40); glStencilFunc(GL_NOTEQUAL, 0x40, 0x40);
this->DrawPolygonsForIndexRange<OGLPolyDrawMode_ZeroAlphaPass>(polyList, indexList, polyList->opaqueCount, polyList->count - 1, indexOffset, lastPolyAttr); this->DrawPolygonsForIndexRange<OGLPolyDrawMode_ZeroAlphaPass>(polyList, indexList, this->_clippedPolyOpaqueCount, this->_clippedPolyCount - 1, indexOffset, lastPolyAttr);
// Restore OpenGL states back to normal. // Restore OpenGL states back to normal.
this->_geometryProgramFlags = oldGProgramFlags; this->_geometryProgramFlags = oldGProgramFlags;
@ -4255,10 +4255,14 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine)
OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)&engine.vertList[0].color : OGLRef.color4fBuffer; OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)&engine.vertList[0].color : OGLRef.color4fBuffer;
} }
// Generate the clipped polygon list.
this->_PerformClipping<ClipperMode_DetermineClipOnly>(engine.vertList, engine.polylist, &engine.indexlist);
this->_renderNeedsDepthEqualsTest = false; this->_renderNeedsDepthEqualsTest = false;
for (size_t i = 0, vertIndexCount = 0; i < engine.polylist->count; i++) for (size_t i = 0, vertIndexCount = 0; i < this->_clippedPolyCount; i++)
{ {
const POLY &thePoly = engine.polylist->list[engine.indexlist.list[i]]; const POLY &thePoly = *this->_clipper.GetClippedPolyByIndex(i).poly;
const size_t polyType = thePoly.type; const size_t polyType = thePoly.type;
const VERT vert[4] = { const VERT vert[4] = {
engine.vertList[thePoly.vertIndexes[0]], engine.vertList[thePoly.vertIndexes[0]],
@ -4428,7 +4432,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D &engine)
Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State &renderState, const POLYLIST *polyList, const INDEXLIST *indexList) Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State &renderState, const POLYLIST *polyList, const INDEXLIST *indexList)
{ {
if (polyList->count > 0) if (this->_clippedPolyCount > 0)
{ {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST); glEnable(GL_STENCIL_TEST);
@ -4448,29 +4452,29 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State &renderState,
size_t indexOffset = 0; size_t indexOffset = 0;
const POLY &firstPoly = polyList->list[indexList->list[0]]; const POLY &firstPoly = *this->_clipper.GetClippedPolyByIndex(0).poly;
POLYGON_ATTR lastPolyAttr = firstPoly.attribute; POLYGON_ATTR lastPolyAttr = firstPoly.attribute;
if (polyList->opaqueCount > 0) if (this->_clippedPolyOpaqueCount > 0)
{ {
this->SetupPolygon(firstPoly, false, true); this->SetupPolygon(firstPoly, false, true);
this->DrawPolygonsForIndexRange<OGLPolyDrawMode_DrawOpaquePolys>(polyList, indexList, 0, polyList->opaqueCount - 1, indexOffset, lastPolyAttr); this->DrawPolygonsForIndexRange<OGLPolyDrawMode_DrawOpaquePolys>(polyList, indexList, 0, this->_clippedPolyOpaqueCount - 1, indexOffset, lastPolyAttr);
} }
if (polyList->opaqueCount < polyList->count) if (this->_clippedPolyOpaqueCount < this->_clippedPolyCount)
{ {
if (this->_needsZeroDstAlphaPass && this->_emulateSpecialZeroAlphaBlending) if (this->_needsZeroDstAlphaPass && this->_emulateSpecialZeroAlphaBlending)
{ {
if (polyList->opaqueCount == 0) if (this->_clippedPolyOpaqueCount == 0)
{ {
this->SetupPolygon(firstPoly, true, false); this->SetupPolygon(firstPoly, true, false);
} }
this->ZeroDstAlphaPass(polyList, indexList, renderState.enableAlphaBlending, indexOffset, lastPolyAttr); this->ZeroDstAlphaPass(polyList, indexList, renderState.enableAlphaBlending, indexOffset, lastPolyAttr);
if (polyList->opaqueCount > 0) if (this->_clippedPolyOpaqueCount > 0)
{ {
const POLY &lastOpaquePoly = polyList->list[indexList->list[polyList->opaqueCount - 1]]; const POLY &lastOpaquePoly = *this->_clipper.GetClippedPolyByIndex(this->_clippedPolyOpaqueCount - 1).poly;
lastPolyAttr = lastOpaquePoly.attribute; lastPolyAttr = lastOpaquePoly.attribute;
this->SetupPolygon(lastOpaquePoly, false, true); this->SetupPolygon(lastOpaquePoly, false, true);
} }
@ -4485,12 +4489,12 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry(const GFX3D_State &renderState,
glStencilMask(0xFF); glStencilMask(0xFF);
} }
if (polyList->opaqueCount == 0) if (this->_clippedPolyOpaqueCount == 0)
{ {
this->SetupPolygon(firstPoly, true, true); this->SetupPolygon(firstPoly, true, true);
} }
this->DrawPolygonsForIndexRange<OGLPolyDrawMode_DrawTranslucentPolys>(polyList, indexList, polyList->opaqueCount, polyList->count - 1, indexOffset, lastPolyAttr); this->DrawPolygonsForIndexRange<OGLPolyDrawMode_DrawTranslucentPolys>(polyList, indexList, this->_clippedPolyOpaqueCount, this->_clippedPolyCount - 1, indexOffset, lastPolyAttr);
} }
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@ -5558,10 +5562,14 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D &engine)
// Only copy as much vertex data as we need to, since this can be a potentially large upload size. // Only copy as much vertex data as we need to, since this can be a potentially large upload size.
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * engine.vertListCount, engine.vertList); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * engine.vertListCount, engine.vertList);
// Generate the clipped polygon list.
this->_PerformClipping<ClipperMode_DetermineClipOnly>(engine.vertList, engine.polylist, &engine.indexlist);
this->_renderNeedsDepthEqualsTest = false; this->_renderNeedsDepthEqualsTest = false;
for (size_t i = 0, vertIndexCount = 0; i < engine.polylist->count; i++) for (size_t i = 0, vertIndexCount = 0; i < this->_clippedPolyCount; i++)
{ {
const POLY &thePoly = engine.polylist->list[engine.indexlist.list[i]]; const POLY &thePoly = *this->_clipper.GetClippedPolyByIndex(i).poly;
const size_t polyType = thePoly.type; const size_t polyType = thePoly.type;
const VERT vert[4] = { const VERT vert[4] = {
engine.vertList[thePoly.vertIndexes[0]], engine.vertList[thePoly.vertIndexes[0]],

View File

@ -309,7 +309,8 @@ enum OGLTextureUnitID
enum OGLBindingPointID enum OGLBindingPointID
{ {
OGLBindingPointID_RenderStates = 0 OGLBindingPointID_RenderStates = 0,
OGLBindingPointID_PolyStates = 1
}; };
enum OGLErrorCode enum OGLErrorCode
@ -488,6 +489,7 @@ struct OGLRenderRef
// UBO / TBO // UBO / TBO
GLuint uboRenderStatesID; GLuint uboRenderStatesID;
GLuint uboPolyStatesID;
GLuint tboPolyStatesID; GLuint tboPolyStatesID;
GLuint texPolyStatesID; GLuint texPolyStatesID;
@ -715,6 +717,7 @@ protected:
Render3DError FlushFramebuffer(const FragmentColor *__restrict srcFramebuffer, FragmentColor *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16); Render3DError FlushFramebuffer(const FragmentColor *__restrict srcFramebuffer, FragmentColor *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16);
OpenGLTexture* GetLoadedTextureFromPolygon(const POLY &thePoly, bool enableTexturing); OpenGLTexture* GetLoadedTextureFromPolygon(const POLY &thePoly, bool enableTexturing);
template<OGLPolyDrawMode DRAWMODE> size_t DrawPolygonsForIndexRange(const POLYLIST *polyList, const INDEXLIST *indexList, size_t firstIndex, size_t lastIndex, size_t &indexOffset, POLYGON_ATTR &lastPolyAttr); template<OGLPolyDrawMode DRAWMODE> size_t DrawPolygonsForIndexRange(const POLYLIST *polyList, const INDEXLIST *indexList, size_t firstIndex, size_t lastIndex, size_t &indexOffset, POLYGON_ATTR &lastPolyAttr);
template<OGLPolyDrawMode DRAWMODE> Render3DError DrawAlphaTexturePolygon(const GLenum polyPrimitive, template<OGLPolyDrawMode DRAWMODE> Render3DError DrawAlphaTexturePolygon(const GLenum polyPrimitive,
const GLsizei vertIndexCount, const GLsizei vertIndexCount,

View File

@ -121,7 +121,14 @@ in vec4 inPosition;\n\
in vec2 inTexCoord0;\n\ in vec2 inTexCoord0;\n\
in vec3 inColor; \n\ in vec3 inColor; \n\
\n\ \n\
#if IS_USING_UBO_POLY_STATES\n\
layout (std140) uniform PolyStates\n\
{\n\
ivec4 value[4096];\n\
} polyState;\n\
#else\n\
uniform isamplerBuffer PolyStates;\n\ uniform isamplerBuffer PolyStates;\n\
#endif\n\
uniform int polyIndex;\n\ uniform int polyIndex;\n\
\n\ \n\
out vec2 vtxTexCoord;\n\ out vec2 vtxTexCoord;\n\
@ -136,7 +143,12 @@ flat out int texSingleBitAlpha;\n\
\n\ \n\
void main()\n\ void main()\n\
{\n\ {\n\
#if IS_USING_UBO_POLY_STATES\n\
ivec4 polyStateVec = polyState.value[polyIndex >> 2];\n\
int polyStateBits = polyStateVec[polyIndex & 0x03];\n\
#else\n\
int polyStateBits = texelFetch(PolyStates, polyIndex).r;\n\ int polyStateBits = texelFetch(PolyStates, polyIndex).r;\n\
#endif\n\
int texSizeShiftS = (polyStateBits >> 18) & 0x07;\n\ int texSizeShiftS = (polyStateBits >> 18) & 0x07;\n\
int texSizeShiftT = (polyStateBits >> 21) & 0x07;\n\ int texSizeShiftT = (polyStateBits >> 21) & 0x07;\n\
\n\ \n\
@ -772,6 +784,7 @@ void OGLCreateRenderer_3_2(OpenGLRenderer **rendererPtr)
OpenGLRenderer_3_2::OpenGLRenderer_3_2() OpenGLRenderer_3_2::OpenGLRenderer_3_2()
{ {
_is64kUBOSupported = false;
_syncBufferSetup = NULL; _syncBufferSetup = NULL;
} }
@ -797,6 +810,10 @@ Render3DError OpenGLRenderer_3_2::InitExtensions()
this->GetExtensionSet(&oglExtensionSet); this->GetExtensionSet(&oglExtensionSet);
// Get host GPU device properties // Get host GPU device properties
GLint maxUBOSize = 0;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUBOSize);
this->_is64kUBOSupported = (maxUBOSize >= 65536);
GLfloat maxAnisotropyOGL = 1.0f; GLfloat maxAnisotropyOGL = 1.0f;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL); glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL);
this->_deviceInfo.maxAnisotropy = (float)maxAnisotropyOGL; this->_deviceInfo.maxAnisotropy = (float)maxAnisotropyOGL;
@ -1271,6 +1288,42 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms()
Render3DError error = OGLERROR_NOERR; Render3DError error = OGLERROR_NOERR;
OGLRenderRef &OGLRef = *this->ref; OGLRenderRef &OGLRef = *this->ref;
// Create shader resources.
if (OGLRef.uboRenderStatesID == 0)
{
glGenBuffers(1, &OGLRef.uboRenderStatesID);
glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboRenderStatesID);
glBufferData(GL_UNIFORM_BUFFER, sizeof(OGLRenderStates), NULL, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, OGLBindingPointID_RenderStates, OGLRef.uboRenderStatesID);
}
if (this->_is64kUBOSupported)
{
if (OGLRef.uboPolyStatesID == 0)
{
glGenBuffers(1, &OGLRef.uboPolyStatesID);
glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboPolyStatesID);
glBufferData(GL_UNIFORM_BUFFER, MAX_CLIPPED_POLY_COUNT_FOR_UBO * sizeof(OGLPolyStates), NULL, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, OGLBindingPointID_PolyStates, OGLRef.uboPolyStatesID);
}
}
else
{
if (OGLRef.tboPolyStatesID == 0)
{
// Set up poly states TBO
glGenBuffers(1, &OGLRef.tboPolyStatesID);
glBindBuffer(GL_TEXTURE_BUFFER, OGLRef.tboPolyStatesID);
glBufferData(GL_TEXTURE_BUFFER, POLYLIST_SIZE * sizeof(OGLPolyStates), NULL, GL_DYNAMIC_DRAW);
glGenTextures(1, &OGLRef.texPolyStatesID);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates);
glBindTexture(GL_TEXTURE_BUFFER, OGLRef.texPolyStatesID);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, OGLRef.tboPolyStatesID);
glActiveTexture(GL_TEXTURE0);
}
}
OGLGeometryFlags programFlags; OGLGeometryFlags programFlags;
programFlags.value = 0; programFlags.value = 0;
@ -1284,6 +1337,8 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms()
vtxShaderHeader << "#version 150\n"; vtxShaderHeader << "#version 150\n";
} }
vtxShaderHeader << "\n"; vtxShaderHeader << "\n";
vtxShaderHeader << "#define IS_USING_UBO_POLY_STATES " << ((OGLRef.uboPolyStatesID != 0) ? 1 : 0) << "\n";
vtxShaderHeader << "\n";
std::string vtxShaderCode = vtxShaderHeader.str() + std::string(GeometryVtxShader_150); std::string vtxShaderCode = vtxShaderHeader.str() + std::string(GeometryVtxShader_150);
@ -1380,9 +1435,18 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms()
assert(uboSize == sizeof(OGLRenderStates)); assert(uboSize == sizeof(OGLRenderStates));
const GLint uniformTexRenderObject = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "texRenderObject"); const GLint uniformTexRenderObject = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "texRenderObject");
const GLint uniformTexBufferPolyStates = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "PolyStates");
glUniform1i(uniformTexRenderObject, 0); glUniform1i(uniformTexRenderObject, 0);
glUniform1i(uniformTexBufferPolyStates, OGLTextureUnitID_PolyStates);
if (OGLRef.uboPolyStatesID != 0)
{
const GLuint uniformBlockPolyStates = glGetUniformBlockIndex(OGLRef.programGeometryID[flagsValue], "PolyStates");
glUniformBlockBinding(OGLRef.programGeometryID[flagsValue], uniformBlockPolyStates, OGLBindingPointID_PolyStates);
}
else
{
const GLint uniformTexBufferPolyStates = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "PolyStates");
glUniform1i(uniformTexBufferPolyStates, OGLTextureUnitID_PolyStates);
}
OGLRef.uniformTexDrawOpaque[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "texDrawOpaque"); OGLRef.uniformTexDrawOpaque[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "texDrawOpaque");
OGLRef.uniformPolyDrawShadow[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDrawShadow"); OGLRef.uniformPolyDrawShadow[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDrawShadow");
@ -1390,28 +1454,6 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms()
OGLRef.uniformPolyDepthOffsetMode[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDepthOffsetMode"); OGLRef.uniformPolyDepthOffsetMode[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDepthOffsetMode");
} }
if (OGLRef.uboRenderStatesID == 0)
{
glGenBuffers(1, &OGLRef.uboRenderStatesID);
glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboRenderStatesID);
glBufferData(GL_UNIFORM_BUFFER, sizeof(OGLRenderStates), NULL, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, OGLBindingPointID_RenderStates, OGLRef.uboRenderStatesID);
}
if (OGLRef.tboPolyStatesID == 0)
{
// Set up poly states TBO
glGenBuffers(1, &OGLRef.tboPolyStatesID);
glBindBuffer(GL_TEXTURE_BUFFER, OGLRef.tboPolyStatesID);
glBufferData(GL_TEXTURE_BUFFER, POLYLIST_SIZE * sizeof(OGLPolyStates), NULL, GL_DYNAMIC_DRAW);
glGenTextures(1, &OGLRef.texPolyStatesID);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates);
glBindTexture(GL_TEXTURE_BUFFER, OGLRef.texPolyStatesID);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, OGLRef.tboPolyStatesID);
glActiveTexture(GL_TEXTURE0);
}
return error; return error;
} }
@ -1427,9 +1469,11 @@ void OpenGLRenderer_3_2::DestroyGeometryPrograms()
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBuffer(GL_TEXTURE_BUFFER, 0); glBindBuffer(GL_TEXTURE_BUFFER, 0);
glDeleteBuffers(1, &OGLRef.uboRenderStatesID); glDeleteBuffers(1, &OGLRef.uboRenderStatesID);
glDeleteBuffers(1, &OGLRef.uboPolyStatesID);
glDeleteBuffers(1, &OGLRef.tboPolyStatesID); glDeleteBuffers(1, &OGLRef.tboPolyStatesID);
OGLRef.uboRenderStatesID = 0; OGLRef.uboRenderStatesID = 0;
OGLRef.uboPolyStatesID = 0;
OGLRef.tboPolyStatesID = 0; OGLRef.tboPolyStatesID = 0;
for (size_t flagsValue = 0; flagsValue < 128; flagsValue++) for (size_t flagsValue = 0; flagsValue < 128; flagsValue++)
@ -1964,7 +2008,7 @@ Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const POLYLIST *polyList, con
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
glStencilFunc(GL_NOTEQUAL, 0x40, 0x40); glStencilFunc(GL_NOTEQUAL, 0x40, 0x40);
this->DrawPolygonsForIndexRange<OGLPolyDrawMode_ZeroAlphaPass>(polyList, indexList, polyList->opaqueCount, polyList->count - 1, indexOffset, lastPolyAttr); this->DrawPolygonsForIndexRange<OGLPolyDrawMode_ZeroAlphaPass>(polyList, indexList, this->_clippedPolyOpaqueCount, this->_clippedPolyCount - 1, indexOffset, lastPolyAttr);
// Restore OpenGL states back to normal. // Restore OpenGL states back to normal.
this->_geometryProgramFlags = oldGProgramFlags; this->_geometryProgramFlags = oldGProgramFlags;
@ -2165,13 +2209,27 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine)
this->_pendingRenderStates.toonColor[i].a = 1.0f; this->_pendingRenderStates.toonColor[i].a = 1.0f;
} }
glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboRenderStatesID);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(this->_pendingRenderStates), &this->_pendingRenderStates); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(this->_pendingRenderStates), &this->_pendingRenderStates);
// Generate the clipped polygon list.
this->_PerformClipping<ClipperMode_DetermineClipOnly>(engine.vertList, engine.polylist, &engine.indexlist);
if ( (OGLRef.uboPolyStatesID != 0) && (this->_clippedPolyCount > MAX_CLIPPED_POLY_COUNT_FOR_UBO) )
{
// In practice, there shouldn't be any game scene with a clipped polygon count that
// would exceed POLYLIST_SIZE. But if for some reason there is, then we need to limit
// the polygon count here. Please report if this happens!
printf("OpenGL: Clipped poly count of %d exceeds %d. Please report!!!\n", (int)this->_clippedPolyCount, MAX_CLIPPED_POLY_COUNT_FOR_UBO);
this->_clippedPolyCount = MAX_CLIPPED_POLY_COUNT_FOR_UBO;
}
// Set up the polygon states. // Set up the polygon states.
this->_renderNeedsDepthEqualsTest = false; this->_renderNeedsDepthEqualsTest = false;
for (size_t i = 0, vertIndexCount = 0; i < engine.polylist->count; i++) for (size_t i = 0, vertIndexCount = 0; i < this->_clippedPolyCount; i++)
{ {
const POLY &thePoly = engine.polylist->list[engine.indexlist.list[i]]; const POLY &thePoly = *this->_clipper.GetClippedPolyByIndex(i).poly;
const size_t polyType = thePoly.type; const size_t polyType = thePoly.type;
const VERT vert[4] = { const VERT vert[4] = {
engine.vertList[thePoly.vertIndexes[0]], engine.vertList[thePoly.vertIndexes[0]],
@ -2243,17 +2301,23 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine)
} }
} }
// Replace the entire index buffer as a hint to the driver that we can orphan the index buffer and // Replace the entire buffer as a hint to the driver to orphan the buffer and avoid a synchronization cost.
// avoid a synchronization cost.
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer);
// Some drivers seem to have problems with glMapBufferRange() and GL_TEXTURE_BUFFER, causing OGLPolyStates *polyStates = this->_pendingPolyStates;
// certain polygons to intermittently flicker in certain games. Therefore, we'll use glMapBuffer()
// in this case in order to prevent these glitches from happening. if (OGLRef.uboPolyStatesID == 0)
OGLPolyStates *polyStates = (OGLPolyStates *)glMapBuffer(GL_TEXTURE_BUFFER, GL_WRITE_ONLY);
for (size_t i = 0; i < engine.polylist->count; i++)
{ {
const POLY &thePoly = engine.polylist->list[engine.indexlist.list[i]]; // Some drivers seem to have problems with GL_TEXTURE_BUFFER used as the target for
// glMapBufferRange() or glBufferSubData(), causing certain polygons to intermittently
// flicker in certain games. Therefore, we'll use glMapBuffer() in this case in order
// to prevent these glitches from happening.
polyStates = (OGLPolyStates *)glMapBuffer(GL_TEXTURE_BUFFER, GL_WRITE_ONLY);
}
for (size_t i = 0; i < this->_clippedPolyCount; i++)
{
const POLY &thePoly = *this->_clipper.GetClippedPolyByIndex(i).poly;
// Get all of the polygon states that can be handled within the shader. // Get all of the polygon states that can be handled within the shader.
const NDSTextureFormat packFormat = this->_textureList[i]->GetPackFormat(); const NDSTextureFormat packFormat = this->_textureList[i]->GetPackFormat();
@ -2272,7 +2336,17 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D &engine)
polyStates[i].TexSizeShiftS = thePoly.texParam.SizeShiftS; // Note that we are using the preshifted size of S polyStates[i].TexSizeShiftS = thePoly.texParam.SizeShiftS; // Note that we are using the preshifted size of S
polyStates[i].TexSizeShiftT = thePoly.texParam.SizeShiftT; // Note that we are using the preshifted size of T polyStates[i].TexSizeShiftT = thePoly.texParam.SizeShiftT; // Note that we are using the preshifted size of T
} }
glUnmapBuffer(GL_TEXTURE_BUFFER);
if (OGLRef.uboPolyStatesID != 0)
{
// Replace the entire buffer as a hint to the driver to orphan the buffer and avoid a synchronization cost.
glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboPolyStatesID);
glBufferSubData(GL_UNIFORM_BUFFER, 0, MAX_CLIPPED_POLY_COUNT_FOR_UBO * sizeof(OGLPolyStates), this->_pendingPolyStates);
}
else
{
glUnmapBuffer(GL_TEXTURE_BUFFER);
}
// Set up the default draw call states. // Set up the default draw call states.
this->_geometryProgramFlags.EnableWDepth = (engine.renderState.wbuffer) ? 1 : 0; this->_geometryProgramFlags.EnableWDepth = (engine.renderState.wbuffer) ? 1 : 0;

View File

@ -56,14 +56,18 @@
#include "OGLRender.h" #include "OGLRender.h"
#define MAX_CLIPPED_POLY_COUNT_FOR_UBO 16384
void OGLLoadEntryPoints_3_2(); void OGLLoadEntryPoints_3_2();
void OGLCreateRenderer_3_2(OpenGLRenderer **rendererPtr); void OGLCreateRenderer_3_2(OpenGLRenderer **rendererPtr);
class OpenGLRenderer_3_2 : public OpenGLRenderer_2_1 class OpenGLRenderer_3_2 : public OpenGLRenderer_2_1
{ {
protected: protected:
bool _is64kUBOSupported;
GLsync _syncBufferSetup; GLsync _syncBufferSetup;
CACHE_ALIGN OGLRenderStates _pendingRenderStates; CACHE_ALIGN OGLRenderStates _pendingRenderStates;
CACHE_ALIGN OGLPolyStates _pendingPolyStates[POLYLIST_SIZE];
virtual Render3DError InitExtensions(); virtual Render3DError InitExtensions();

View File

@ -1,6 +1,6 @@
/* /*
Copyright (C) 2006 yopyop Copyright (C) 2006 yopyop
Copyright (C) 2008-2018 DeSmuME team Copyright (C) 2008-2019 DeSmuME team
This file is free software: you can redistribute it and/or modify This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -1745,9 +1745,9 @@ static BOOL gfx3d_glBoxTest(u32 v)
polys[5].setVertIndexes(0,4,5,1); //bottom polys[5].setVertIndexes(0,4,5,1); //bottom
//setup the clipper //setup the clipper
GFX3D_Clipper::TClippedPoly tempClippedPoly; CPoly tempClippedPoly;
boxtestClipper.clippedPolys = &tempClippedPoly; boxtestClipper.SetClippedPolyBufferPtr(&tempClippedPoly);
boxtestClipper.reset(); boxtestClipper.Reset();
////----------------------------- ////-----------------------------
////awesome hack: ////awesome hack:
@ -1800,10 +1800,10 @@ static BOOL gfx3d_glBoxTest(u32 v)
&verts[thePoly.vertIndexes[3]] &verts[thePoly.vertIndexes[3]]
}; };
boxtestClipper.clipPoly<false>(thePoly, vertTable); boxtestClipper.ClipPoly<ClipperMode_DetermineClipOnly>(thePoly, vertTable);
//if any portion of this poly was retained, then the test passes. //if any portion of this poly was retained, then the test passes.
if (boxtestClipper.clippedPolyCounter > 0) if (boxtestClipper.GetPolyCount() > 0)
{ {
//printf("%06d PASS %d\n",gxFIFO.size, i); //printf("%06d PASS %d\n",gxFIFO.size, i);
MMU_new.gxstat.tr = 1; MMU_new.gxstat.tr = 1;
@ -3037,8 +3037,8 @@ static T interpolate(const float ratio, const T& x0, const T& x1)
} }
//http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/as6/discussion.shtml //http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/as6/discussion.shtml
template<int COORD, int WHICH> template <ClipperMode CLIPPERMODE, int COORD, int WHICH>
static FORCEINLINE VERT clipPoint(bool hirez, const VERT *inside, const VERT *outside) static FORCEINLINE VERT clipPoint(const VERT *inside, const VERT *outside)
{ {
VERT ret; VERT ret;
const float coord_inside = inside->coord[COORD]; const float coord_inside = inside->coord[COORD];
@ -3050,16 +3050,23 @@ static FORCEINLINE VERT clipPoint(bool hirez, const VERT *inside, const VERT *ou
#define INTERP(X) ret . X = interpolate(t, inside-> X ,outside-> X ) #define INTERP(X) ret . X = interpolate(t, inside-> X ,outside-> X )
INTERP(coord[0]); INTERP(coord[1]); INTERP(coord[2]); INTERP(coord[3]); INTERP(coord[0]); INTERP(coord[1]); INTERP(coord[2]); INTERP(coord[3]);
INTERP(texcoord[0]); INTERP(texcoord[1]);
if (hirez) switch (CLIPPERMODE)
{ {
INTERP(fcolor[0]); INTERP(fcolor[1]); INTERP(fcolor[2]); case ClipperMode_Full:
} INTERP(texcoord[0]); INTERP(texcoord[1]);
else INTERP(color[0]); INTERP(color[1]); INTERP(color[2]);
{ ret.color_to_float();
INTERP(color[0]); INTERP(color[1]); INTERP(color[2]); break;
ret.color_to_float();
case ClipperMode_InterpolateFull:
INTERP(texcoord[0]); INTERP(texcoord[1]);
INTERP(fcolor[0]); INTERP(fcolor[1]); INTERP(fcolor[2]);
break;
case ClipperMode_DetermineClipOnly:
// Do nothing.
break;
} }
//this seems like a prudent measure to make sure that math doesnt make a point pop back out //this seems like a prudent measure to make sure that math doesnt make a point pop back out
@ -3073,10 +3080,10 @@ static FORCEINLINE VERT clipPoint(bool hirez, const VERT *inside, const VERT *ou
} }
#define MAX_SCRATCH_CLIP_VERTS (4*6 + 40) #define MAX_SCRATCH_CLIP_VERTS (4*6 + 40)
static VERT scratchClipVerts [MAX_SCRATCH_CLIP_VERTS]; static VERT scratchClipVerts[MAX_SCRATCH_CLIP_VERTS];
static int numScratchClipVerts = 0; static size_t numScratchClipVerts = 0;
template <int COORD, int WHICH, class NEXT> template <ClipperMode CLIPPERMODE, int COORD, int WHICH, class NEXT>
class ClipperPlane class ClipperPlane
{ {
public: public:
@ -3089,20 +3096,20 @@ public:
m_next.init(verts); m_next.init(verts);
} }
void clipVert(bool hirez, const VERT *vert) void clipVert(const VERT *vert)
{ {
if (m_prevVert) if (m_prevVert)
this->clipSegmentVsPlane(hirez, m_prevVert, vert); this->clipSegmentVsPlane(m_prevVert, vert);
else else
m_firstVert = (VERT *)vert; m_firstVert = (VERT *)vert;
m_prevVert = (VERT *)vert; m_prevVert = (VERT *)vert;
} }
// closes the loop and returns the number of clipped output verts // closes the loop and returns the number of clipped output verts
int finish(bool hirez) int finish()
{ {
this->clipVert(hirez, m_firstVert); this->clipVert(m_firstVert);
return m_next.finish(hirez); return m_next.finish();
} }
private: private:
@ -3110,7 +3117,7 @@ private:
VERT* m_firstVert; VERT* m_firstVert;
NEXT& m_next; NEXT& m_next;
FORCEINLINE void clipSegmentVsPlane(bool hirez, const VERT *vert0, const VERT *vert1) FORCEINLINE void clipSegmentVsPlane(const VERT *vert0, const VERT *vert1)
{ {
const float *vert0coord = vert0->coord; const float *vert0coord = vert0->coord;
const float *vert1coord = vert1->coord; const float *vert1coord = vert1->coord;
@ -3133,7 +3140,7 @@ private:
if (!out0 && !out1) if (!out0 && !out1)
{ {
CLIPLOG(" both inside\n"); CLIPLOG(" both inside\n");
m_next.clipVert(hirez, vert1); m_next.clipVert(vert1);
} }
//exiting volume: insert the clipped point //exiting volume: insert the clipped point
@ -3141,8 +3148,8 @@ private:
{ {
CLIPLOG(" exiting\n"); CLIPLOG(" exiting\n");
assert((u32)numScratchClipVerts < MAX_SCRATCH_CLIP_VERTS); assert((u32)numScratchClipVerts < MAX_SCRATCH_CLIP_VERTS);
scratchClipVerts[numScratchClipVerts] = clipPoint<COORD, WHICH>(hirez, vert0, vert1); scratchClipVerts[numScratchClipVerts] = clipPoint<CLIPPERMODE, COORD, WHICH>(vert0, vert1);
m_next.clipVert(hirez, &scratchClipVerts[numScratchClipVerts++]); m_next.clipVert(&scratchClipVerts[numScratchClipVerts++]);
} }
//entering volume: insert clipped point and the next (interior) point //entering volume: insert clipped point and the next (interior) point
@ -3150,9 +3157,9 @@ private:
{ {
CLIPLOG(" entering\n"); CLIPLOG(" entering\n");
assert((u32)numScratchClipVerts < MAX_SCRATCH_CLIP_VERTS); assert((u32)numScratchClipVerts < MAX_SCRATCH_CLIP_VERTS);
scratchClipVerts[numScratchClipVerts] = clipPoint<COORD, WHICH>(hirez, vert1, vert0); scratchClipVerts[numScratchClipVerts] = clipPoint<CLIPPERMODE, COORD, WHICH>(vert1, vert0);
m_next.clipVert(hirez, &scratchClipVerts[numScratchClipVerts++]); m_next.clipVert(&scratchClipVerts[numScratchClipVerts++]);
m_next.clipVert(hirez, vert1); m_next.clipVert(vert1);
} }
} }
}; };
@ -3166,14 +3173,14 @@ public:
m_numVerts = 0; m_numVerts = 0;
} }
void clipVert(bool hirez, const VERT *vert) void clipVert(const VERT *vert)
{ {
assert((u32)m_numVerts < MAX_CLIPPED_VERTS); assert((u32)m_numVerts < MAX_CLIPPED_VERTS);
*m_nextDestVert++ = *vert; *m_nextDestVert++ = *vert;
m_numVerts++; m_numVerts++;
} }
int finish(bool hirez) int finish()
{ {
return m_numVerts; return m_numVerts;
} }
@ -3185,28 +3192,107 @@ private:
// see "Template juggling with Sutherland-Hodgman" http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965__2/ // see "Template juggling with Sutherland-Hodgman" http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965__2/
// for the idea behind setting things up like this. // for the idea behind setting things up like this.
static ClipperOutput clipperOut;
typedef ClipperPlane<2, 1,ClipperOutput> Stage6; static Stage6 clipper6 (clipperOut); // back plane //TODO - we need to parameterize back plane clipping
typedef ClipperPlane<2,-1,Stage6> Stage5; static Stage5 clipper5 (clipper6); // front plane
typedef ClipperPlane<1, 1,Stage5> Stage4; static Stage4 clipper4 (clipper5); // top plane
typedef ClipperPlane<1,-1,Stage4> Stage3; static Stage3 clipper3 (clipper4); // bottom plane
typedef ClipperPlane<0, 1,Stage3> Stage2; static Stage2 clipper2 (clipper3); // right plane
typedef ClipperPlane<0,-1,Stage2> Stage1; static Stage1 clipper (clipper2); // left plane
template<bool USEHIRESINTERPOLATE> // Non-interpolated clippers
void GFX3D_Clipper::clipPoly(const POLY &poly, const VERT **verts) static ClipperOutput clipperOut;
typedef ClipperPlane<ClipperMode_Full, 2, 1,ClipperOutput> Stage6; static Stage6 clipper6 (clipperOut); // back plane //TODO - we need to parameterize back plane clipping
typedef ClipperPlane<ClipperMode_Full, 2,-1,Stage6> Stage5; static Stage5 clipper5 (clipper6); // front plane
typedef ClipperPlane<ClipperMode_Full, 1, 1,Stage5> Stage4; static Stage4 clipper4 (clipper5); // top plane
typedef ClipperPlane<ClipperMode_Full, 1,-1,Stage4> Stage3; static Stage3 clipper3 (clipper4); // bottom plane
typedef ClipperPlane<ClipperMode_Full, 0, 1,Stage3> Stage2; static Stage2 clipper2 (clipper3); // right plane
typedef ClipperPlane<ClipperMode_Full, 0,-1,Stage2> Stage1; static Stage1 clipper1 (clipper2); // left plane
// Interpolated clippers
static ClipperOutput clipperOuti;
typedef ClipperPlane<ClipperMode_InterpolateFull, 2, 1,ClipperOutput> Stage6i; static Stage6 clipper6i (clipperOuti); // back plane //TODO - we need to parameterize back plane clipping
typedef ClipperPlane<ClipperMode_InterpolateFull, 2,-1,Stage6i> Stage5i; static Stage5 clipper5i (clipper6i); // front plane
typedef ClipperPlane<ClipperMode_InterpolateFull, 1, 1,Stage5i> Stage4i; static Stage4 clipper4i (clipper5i); // top plane
typedef ClipperPlane<ClipperMode_InterpolateFull, 1,-1,Stage4i> Stage3i; static Stage3 clipper3i (clipper4i); // bottom plane
typedef ClipperPlane<ClipperMode_InterpolateFull, 0, 1,Stage3i> Stage2i; static Stage2 clipper2i (clipper3i); // right plane
typedef ClipperPlane<ClipperMode_InterpolateFull, 0,-1,Stage2i> Stage1i; static Stage1 clipper1i (clipper2i); // left plane
// Determine's clip status only
static ClipperOutput clipperOutd;
typedef ClipperPlane<ClipperMode_DetermineClipOnly, 2, 1,ClipperOutput> Stage6d; static Stage6 clipper6d (clipperOutd); // back plane //TODO - we need to parameterize back plane clipping
typedef ClipperPlane<ClipperMode_DetermineClipOnly, 2,-1,Stage6d> Stage5d; static Stage5 clipper5d (clipper6d); // front plane
typedef ClipperPlane<ClipperMode_DetermineClipOnly, 1, 1,Stage5d> Stage4d; static Stage4 clipper4d (clipper5d); // top plane
typedef ClipperPlane<ClipperMode_DetermineClipOnly, 1,-1,Stage4d> Stage3d; static Stage3 clipper3d (clipper4d); // bottom plane
typedef ClipperPlane<ClipperMode_DetermineClipOnly, 0, 1,Stage3d> Stage2d; static Stage2 clipper2d (clipper3d); // right plane
typedef ClipperPlane<ClipperMode_DetermineClipOnly, 0,-1,Stage2d> Stage1d; static Stage1 clipper1d (clipper2d); // left plane
GFX3D_Clipper::GFX3D_Clipper()
{
_clippedPolyList = NULL;
_clippedPolyCounter = 0;
}
const CPoly* GFX3D_Clipper::GetClippedPolyBufferPtr()
{
return this->_clippedPolyList;
}
void GFX3D_Clipper::SetClippedPolyBufferPtr(CPoly *bufferPtr)
{
this->_clippedPolyList = bufferPtr;
}
const CPoly& GFX3D_Clipper::GetClippedPolyByIndex(size_t index) const
{
return this->_clippedPolyList[index];
}
size_t GFX3D_Clipper::GetPolyCount() const
{
return this->_clippedPolyCounter;
}
void GFX3D_Clipper::Reset()
{
this->_clippedPolyCounter = 0;
}
template <ClipperMode CLIPPERMODE>
void GFX3D_Clipper::ClipPoly(const POLY &poly, const VERT **verts)
{ {
CLIPLOG("==Begin poly==\n"); CLIPLOG("==Begin poly==\n");
PolygonType outType;
const PolygonType type = poly.type; const PolygonType type = poly.type;
numScratchClipVerts = 0; numScratchClipVerts = 0;
clipper.init(clippedPolys[clippedPolyCounter].clipVerts);
for (size_t i = 0; i < type; i++)
clipper.clipVert(USEHIRESINTERPOLATE, verts[i]);
const PolygonType outType = (PolygonType)clipper.finish(USEHIRESINTERPOLATE); switch (CLIPPERMODE)
{
case ClipperMode_Full:
{
clipper1.init(this->_clippedPolyList[this->_clippedPolyCounter].clipVerts);
for (size_t i = 0; i < type; i++)
clipper1.clipVert(verts[i]);
outType = (PolygonType)clipper1.finish();
break;
}
case ClipperMode_InterpolateFull:
{
clipper1i.init(this->_clippedPolyList[this->_clippedPolyCounter].clipVerts);
for (size_t i = 0; i < type; i++)
clipper1i.clipVert(verts[i]);
outType = (PolygonType)clipper1i.finish();
break;
}
case ClipperMode_DetermineClipOnly:
{
clipper1d.init(this->_clippedPolyList[this->_clippedPolyCounter].clipVerts);
for (size_t i = 0; i < type; i++)
clipper1d.clipVert(verts[i]);
outType = (PolygonType)clipper1d.finish();
break;
}
}
assert((u32)outType < MAX_CLIPPED_VERTS); assert((u32)outType < MAX_CLIPPED_VERTS);
if (outType < POLYGON_TYPE_TRIANGLE) if (outType < POLYGON_TYPE_TRIANGLE)
{ {
@ -3215,24 +3301,13 @@ void GFX3D_Clipper::clipPoly(const POLY &poly, const VERT **verts)
} }
else else
{ {
clippedPolys[clippedPolyCounter].type = outType; this->_clippedPolyList[this->_clippedPolyCounter].type = outType;
clippedPolys[clippedPolyCounter].poly = (POLY *)&poly; this->_clippedPolyList[this->_clippedPolyCounter].poly = (POLY *)&poly;
clippedPolyCounter++; this->_clippedPolyCounter++;
} }
} }
//these templates needed to be instantiated manually //these templates needed to be instantiated manually
template void GFX3D_Clipper::clipPoly<true>(const POLY &poly, const VERT **verts); template void GFX3D_Clipper::ClipPoly<ClipperMode_Full>(const POLY &poly, const VERT **verts);
template void GFX3D_Clipper::clipPoly<false>(const POLY &poly, const VERT **verts); template void GFX3D_Clipper::ClipPoly<ClipperMode_InterpolateFull>(const POLY &poly, const VERT **verts);
template void GFX3D_Clipper::ClipPoly<ClipperMode_DetermineClipOnly>(const POLY &poly, const VERT **verts);
void GFX3D_Clipper::clipSegmentVsPlane(VERT** verts, const int coord, int which)
{
// not used (it's probably ok to delete this function)
assert(0);
}
void GFX3D_Clipper::clipPolyVsPlane(const int coord, int which)
{
// not used (it's probably ok to delete this function)
assert(0);
}

View File

@ -1,6 +1,6 @@
/* /*
Copyright (C) 2006 yopyop Copyright (C) 2006 yopyop
Copyright (C) 2008-2018 DeSmuME team Copyright (C) 2008-2019 DeSmuME team
This file is free software: you can redistribute it and/or modify This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -477,31 +477,37 @@ struct VIEWPORT {
//four corners of the hexagon, and you will observe a decagon //four corners of the hexagon, and you will observe a decagon
#define MAX_CLIPPED_VERTS 10 #define MAX_CLIPPED_VERTS 10
enum ClipperMode
{
ClipperMode_Full = 0,
ClipperMode_InterpolateFull = 1,
ClipperMode_DetermineClipOnly = 2
};
struct CPoly
{
PolygonType type; //otherwise known as "count" of verts
POLY *poly;
VERT clipVerts[MAX_CLIPPED_VERTS];
};
class GFX3D_Clipper class GFX3D_Clipper
{ {
public: protected:
size_t _clippedPolyCounter;
CPoly *_clippedPolyList; // The output of clipping operations goes into here. Be sure you init it before clipping!
struct TClippedPoly public:
{ GFX3D_Clipper();
PolygonType type; //otherwise known as "count" of verts
POLY *poly; const CPoly* GetClippedPolyBufferPtr();
VERT clipVerts[MAX_CLIPPED_VERTS]; void SetClippedPolyBufferPtr(CPoly *bufferPtr);
};
const CPoly& GetClippedPolyByIndex(size_t index) const;
//the entry point for poly clipping size_t GetPolyCount() const;
template<bool hirez> void clipPoly(const POLY &poly, const VERT **verts);
void Reset();
//the output of clipping operations goes into here. template<ClipperMode CLIPPERMODE> void ClipPoly(const POLY &poly, const VERT **verts); // the entry point for poly clipping
//be sure you init it before clipping!
TClippedPoly *clippedPolys;
size_t clippedPolyCounter;
void reset() { clippedPolyCounter=0; }
private:
TClippedPoly tempClippedPoly;
TClippedPoly outClippedPoly;
FORCEINLINE void clipSegmentVsPlane(VERT** verts, const int coord, int which);
FORCEINLINE void clipPolyVsPlane(const int coord, int which);
}; };
//used to communicate state to the renderer //used to communicate state to the renderer

View File

@ -1260,7 +1260,7 @@ void RasterizerUnit<RENDERER>::SetRenderer(SoftRasterizerRenderer *theRenderer)
template<bool RENDERER> template <bool SLI, bool USELINEHACK> template<bool RENDERER> template <bool SLI, bool USELINEHACK>
FORCEINLINE void RasterizerUnit<RENDERER>::Render() FORCEINLINE void RasterizerUnit<RENDERER>::Render()
{ {
const size_t polyCount = this->_softRender->_clippedPolyCount; const size_t polyCount = this->_softRender->GetClippedPolyCount();
if (polyCount == 0) if (polyCount == 0)
{ {
return; return;
@ -1270,7 +1270,7 @@ FORCEINLINE void RasterizerUnit<RENDERER>::Render()
const size_t dstWidth = this->_softRender->GetFramebufferWidth(); const size_t dstWidth = this->_softRender->GetFramebufferWidth();
const size_t dstHeight = this->_softRender->GetFramebufferHeight(); const size_t dstHeight = this->_softRender->GetFramebufferHeight();
const GFX3D_Clipper::TClippedPoly &firstClippedPoly = this->_softRender->clippedPolys[0]; const CPoly &firstClippedPoly = this->_softRender->GetClippedPolyByIndex(0);
const POLY &firstPoly = *firstClippedPoly.poly; const POLY &firstPoly = *firstClippedPoly.poly;
POLYGON_ATTR polyAttr = firstPoly.attribute; POLYGON_ATTR polyAttr = firstPoly.attribute;
TEXIMAGE_PARAM lastTexParams = firstPoly.texParam; TEXIMAGE_PARAM lastTexParams = firstPoly.texParam;
@ -1285,7 +1285,7 @@ FORCEINLINE void RasterizerUnit<RENDERER>::Render()
if (!this->_softRender->polyVisible[i]) continue; if (!this->_softRender->polyVisible[i]) continue;
this->_polynum = i; this->_polynum = i;
GFX3D_Clipper::TClippedPoly &clippedPoly = this->_softRender->clippedPolys[i]; const CPoly &clippedPoly = this->_softRender->GetClippedPolyByIndex(i);
const POLY &thePoly = *clippedPoly.poly; const POLY &thePoly = *clippedPoly.poly;
const int vertCount = clippedPoly.type; const int vertCount = clippedPoly.type;
const bool useLineHack = USELINEHACK && (thePoly.vtxFormat & 4); const bool useLineHack = USELINEHACK && (thePoly.vtxFormat & 4);
@ -1738,7 +1738,6 @@ SoftRasterizerRenderer::SoftRasterizerRenderer()
_task = NULL; _task = NULL;
_debug_drawClippedUserPoly = -1; _debug_drawClippedUserPoly = -1;
clippedPolys = clipper.clippedPolys = new GFX3D_Clipper::TClippedPoly[POLYLIST_SIZE*2];
_renderGeometryNeedsFinish = false; _renderGeometryNeedsFinish = false;
_framebufferAttributes = NULL; _framebufferAttributes = NULL;
@ -1868,27 +1867,6 @@ Render3DError SoftRasterizerRenderer::InitTables()
return RENDER3DERROR_NOERR; return RENDER3DERROR_NOERR;
} }
template<bool USEHIRESINTERPOLATE>
size_t SoftRasterizerRenderer::performClipping(const VERT *vertList, const POLYLIST *polyList, const INDEXLIST *indexList)
{
//submit all polys to clipper
clipper.reset();
for (size_t i = 0; i < polyList->count; i++)
{
const POLY &poly = polyList->list[indexList->list[i]];
const VERT *clipVerts[4] = {
&vertList[poly.vertIndexes[0]],
&vertList[poly.vertIndexes[1]],
&vertList[poly.vertIndexes[2]],
(poly.type == POLYGON_TYPE_QUAD) ? &vertList[poly.vertIndexes[3]] : NULL
};
clipper.clipPoly<USEHIRESINTERPOLATE>(poly, clipVerts);
}
return clipper.clippedPolyCounter;
}
void SoftRasterizerRenderer::performViewportTransforms() void SoftRasterizerRenderer::performViewportTransforms()
{ {
const float wScalar = (float)this->_framebufferWidth / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH; const float wScalar = (float)this->_framebufferWidth / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH;
@ -1897,7 +1875,7 @@ void SoftRasterizerRenderer::performViewportTransforms()
//viewport transforms //viewport transforms
for (size_t i = 0; i < this->_clippedPolyCount; i++) for (size_t i = 0; i < this->_clippedPolyCount; i++)
{ {
GFX3D_Clipper::TClippedPoly &poly = this->clippedPolys[i]; CPoly &poly = this->_clippedPolyList[i];
for (size_t j = 0; j < poly.type; j++) for (size_t j = 0; j < poly.type; j++)
{ {
VERT &vert = poly.clipVerts[j]; VERT &vert = poly.clipVerts[j];
@ -1953,7 +1931,7 @@ void SoftRasterizerRenderer::performCoordAdjustment()
{ {
for (size_t i = 0; i < this->_clippedPolyCount; i++) for (size_t i = 0; i < this->_clippedPolyCount; i++)
{ {
GFX3D_Clipper::TClippedPoly &clippedPoly = this->clippedPolys[i]; CPoly &clippedPoly = this->_clippedPolyList[i];
const PolygonType type = clippedPoly.type; const PolygonType type = clippedPoly.type;
VERT *verts = &clippedPoly.clipVerts[0]; VERT *verts = &clippedPoly.clipVerts[0];
@ -1970,7 +1948,7 @@ void SoftRasterizerRenderer::GetAndLoadAllTextures()
{ {
for (size_t i = 0; i < this->_clippedPolyCount; i++) for (size_t i = 0; i < this->_clippedPolyCount; i++)
{ {
const GFX3D_Clipper::TClippedPoly &clippedPoly = this->clippedPolys[i]; const CPoly &clippedPoly = this->_clippedPolyList[i];
const POLY &thePoly = *clippedPoly.poly; const POLY &thePoly = *clippedPoly.poly;
//make sure all the textures we'll need are cached //make sure all the textures we'll need are cached
@ -1985,7 +1963,7 @@ void SoftRasterizerRenderer::performBackfaceTests()
{ {
for (size_t i = 0; i < this->_clippedPolyCount; i++) for (size_t i = 0; i < this->_clippedPolyCount; i++)
{ {
const GFX3D_Clipper::TClippedPoly &clippedPoly = this->clippedPolys[i]; const CPoly &clippedPoly = this->_clippedPolyList[i];
const POLY &thePoly = *clippedPoly.poly; const POLY &thePoly = *clippedPoly.poly;
const PolygonType type = clippedPoly.type; const PolygonType type = clippedPoly.type;
const VERT *verts = &clippedPoly.clipVerts[0]; const VERT *verts = &clippedPoly.clipVerts[0];
@ -2045,11 +2023,11 @@ Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D &engine)
if (this->_enableHighPrecisionColorInterpolation) if (this->_enableHighPrecisionColorInterpolation)
{ {
this->_clippedPolyCount = this->performClipping<true>(engine.vertList, engine.polylist, &engine.indexlist); this->_PerformClipping<ClipperMode_InterpolateFull>(engine.vertList, engine.polylist, &engine.indexlist);
} }
else else
{ {
this->_clippedPolyCount = this->performClipping<false>(engine.vertList, engine.polylist, &engine.indexlist); this->_PerformClipping<ClipperMode_Full>(engine.vertList, engine.polylist, &engine.indexlist);
} }
const bool doMultithreadedStateSetup = (this->_threadCount >= 2); const bool doMultithreadedStateSetup = (this->_threadCount >= 2);
@ -2228,9 +2206,6 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarkingAndFog(const SoftRasteriz
if (param.enableEdgeMarking) if (param.enableEdgeMarking)
{ {
FragmentColor edgeMarkColor;
edgeMarkColor.color = 0;
// a good test case for edge marking is Sonic Rush: // a good test case for edge marking is Sonic Rush:
// - the edges are completely sharp/opaque on the very brief title screen intro, // - 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 level-start intro gets a pseudo-antialiasing effect around the silhouette,
@ -2245,46 +2220,32 @@ Render3DError SoftRasterizerRenderer::RenderEdgeMarkingAndFog(const SoftRasteriz
const bool left = (x < 1) ? isEdgeMarkingClearValues : ((polyID != this->_framebufferAttributes->opaquePolyID[i-1]) && (depth >= this->_framebufferAttributes->depth[i-1])); 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])); const bool up = (y < 1) ? isEdgeMarkingClearValues : ((polyID != this->_framebufferAttributes->opaquePolyID[i-this->_framebufferWidth]) && (depth >= this->_framebufferAttributes->depth[i-this->_framebufferWidth]));
FragmentColor edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
if (right) if (right)
{ {
if (x >= this->_framebufferWidth - 1) if (x < this->_framebufferWidth - 1)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{ {
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i+1] >> 3]; edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i+1] >> 3];
} }
} }
else if (down) else if (down)
{ {
if (y >= this->_framebufferHeight - 1) if (y < this->_framebufferHeight - 1)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{ {
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i+this->_framebufferWidth] >> 3]; edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i+this->_framebufferWidth] >> 3];
} }
} }
else if (left) else if (left)
{ {
if (x < 1) if (x > 0)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{ {
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i-1] >> 3]; edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i-1] >> 3];
} }
} }
else if (up) else if (up)
{ {
if (y < 1) if (y > 0)
{
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i] >> 3];
}
else
{ {
edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i-this->_framebufferWidth] >> 3]; edgeMarkColor = this->edgeMarkTable[this->_framebufferAttributes->opaquePolyID[i-this->_framebufferWidth] >> 3];
} }

View File

@ -106,7 +106,7 @@ protected:
SoftRasterizerRenderer *_softRender; SoftRasterizerRenderer *_softRender;
SoftRasterizerTexture *_currentTexture; SoftRasterizerTexture *_currentTexture;
VERT *_verts[MAX_CLIPPED_VERTS]; const VERT *_verts[MAX_CLIPPED_VERTS];
size_t _polynum; size_t _polynum;
u8 _textureWrapMode; u8 _textureWrapMode;
@ -158,7 +158,6 @@ protected:
size_t _customLinesPerThread; size_t _customLinesPerThread;
size_t _customPixelsPerThread; size_t _customPixelsPerThread;
GFX3D_Clipper clipper;
u8 fogTable[32768]; u8 fogTable[32768];
FragmentColor edgeMarkTable[8]; FragmentColor edgeMarkTable[8];
bool edgeMarkDisabled[8]; bool edgeMarkDisabled[8];
@ -171,8 +170,6 @@ protected:
// SoftRasterizer-specific methods // SoftRasterizer-specific methods
virtual Render3DError InitTables(); virtual Render3DError InitTables();
template<bool USEHIRESINTERPOLATE> size_t performClipping(const VERT *vertList, const POLYLIST *polyList, const INDEXLIST *indexList);
// Base rendering methods // Base rendering methods
virtual Render3DError BeginRender(const GFX3D &engine); virtual Render3DError BeginRender(const GFX3D &engine);
virtual Render3DError RenderGeometry(const GFX3D_State &renderState, const POLYLIST *polyList, const INDEXLIST *indexList); virtual Render3DError RenderGeometry(const GFX3D_State &renderState, const POLYLIST *polyList, const INDEXLIST *indexList);
@ -183,9 +180,7 @@ protected:
public: public:
int _debug_drawClippedUserPoly; int _debug_drawClippedUserPoly;
size_t _clippedPolyCount;
FragmentColor toonColor32LUT[32]; FragmentColor toonColor32LUT[32];
GFX3D_Clipper::TClippedPoly *clippedPolys;
FragmentAttributesBuffer *_framebufferAttributes; FragmentAttributesBuffer *_framebufferAttributes;
bool polyVisible[POLYLIST_SIZE]; bool polyVisible[POLYLIST_SIZE];
bool polyBackfacing[POLYLIST_SIZE]; bool polyBackfacing[POLYLIST_SIZE];

View File

@ -249,6 +249,9 @@ Render3D::Render3D()
_textureList[i] = NULL; _textureList[i] = NULL;
} }
_clippedPolyList = (CPoly *)malloc_alignedCacheLine(POLYLIST_SIZE * 2 * sizeof(CPoly));
_clipper.SetClippedPolyBufferPtr(_clippedPolyList);
memset(this->clearImageColor16Buffer, 0, sizeof(this->clearImageColor16Buffer)); memset(this->clearImageColor16Buffer, 0, sizeof(this->clearImageColor16Buffer));
memset(this->clearImageDepthBuffer, 0, sizeof(this->clearImageDepthBuffer)); memset(this->clearImageDepthBuffer, 0, sizeof(this->clearImageDepthBuffer));
memset(this->clearImageFogBuffer, 0, sizeof(this->clearImageFogBuffer)); memset(this->clearImageFogBuffer, 0, sizeof(this->clearImageFogBuffer));
@ -264,6 +267,8 @@ Render3D::~Render3D()
this->_textureDeposterizeDstSurface.Surface = NULL; this->_textureDeposterizeDstSurface.Surface = NULL;
this->_textureDeposterizeDstSurface.workingSurface[0] = NULL; this->_textureDeposterizeDstSurface.workingSurface[0] = NULL;
} }
free_aligned(this->_clippedPolyList);
} }
const Render3DDeviceInfo& Render3D::GetDeviceInfo() const Render3DDeviceInfo& Render3D::GetDeviceInfo()
@ -399,6 +404,54 @@ Render3DTexture* Render3D::GetTextureByPolygonRenderIndex(size_t polyRenderIndex
return this->_textureList[polyRenderIndex]; return this->_textureList[polyRenderIndex];
} }
const CPoly& Render3D::GetClippedPolyByIndex(size_t index) const
{
return this->_clippedPolyList[index];
}
size_t Render3D::GetClippedPolyCount() const
{
return this->_clippedPolyCount;
}
template <ClipperMode CLIPPERMODE>
void Render3D::_PerformClipping(const VERT *vertList, const POLYLIST *polyList, const INDEXLIST *indexList)
{
//submit all polys to clipper
this->_clipper.Reset();
size_t i = 0;
for (; i < polyList->opaqueCount; i++)
{
const POLY &poly = polyList->list[indexList->list[i]];
const VERT *clipVerts[4] = {
&vertList[poly.vertIndexes[0]],
&vertList[poly.vertIndexes[1]],
&vertList[poly.vertIndexes[2]],
(poly.type == POLYGON_TYPE_QUAD) ? &vertList[poly.vertIndexes[3]] : NULL
};
this->_clipper.ClipPoly<CLIPPERMODE>(poly, clipVerts);
}
this->_clippedPolyOpaqueCount = this->_clipper.GetPolyCount();
for (; i < polyList->count; i++)
{
const POLY &poly = polyList->list[indexList->list[i]];
const VERT *clipVerts[4] = {
&vertList[poly.vertIndexes[0]],
&vertList[poly.vertIndexes[1]],
&vertList[poly.vertIndexes[2]],
(poly.type == POLYGON_TYPE_QUAD) ? &vertList[poly.vertIndexes[3]] : NULL
};
this->_clipper.ClipPoly<CLIPPERMODE>(poly, clipVerts);
}
this->_clippedPolyCount = this->_clipper.GetPolyCount();
}
Render3DError Render3D::ApplyRenderingSettings(const GFX3D_State &renderState) Render3DError Render3D::ApplyRenderingSettings(const GFX3D_State &renderState)
{ {
this->_enableEdgeMark = (CommonSettings.GFX3D_EdgeMark) ? renderState.enableEdgeMarking : false; this->_enableEdgeMark = (CommonSettings.GFX3D_EdgeMark) ? renderState.enableEdgeMarking : false;
@ -966,5 +1019,9 @@ Render3DError Render3D_SSE2::ClearFramebuffer(const GFX3D_State &renderState)
#endif // defined(ENABLE_AVX2) || defined(ENABLE_SSE2) #endif // defined(ENABLE_AVX2) || defined(ENABLE_SSE2)
template void Render3D::_PerformClipping<ClipperMode_Full>(const VERT *vertList, const POLYLIST *polyList, const INDEXLIST *indexList);
template void Render3D::_PerformClipping<ClipperMode_InterpolateFull>(const VERT *vertList, const POLYLIST *polyList, const INDEXLIST *indexList);
template void Render3D::_PerformClipping<ClipperMode_DetermineClipOnly>(const VERT *vertList, const POLYLIST *polyList, const INDEXLIST *indexList);
template Render3D_SIMD<16>::Render3D_SIMD(); template Render3D_SIMD<16>::Render3D_SIMD();
template Render3D_SIMD<32>::Render3D_SIMD(); template Render3D_SIMD<32>::Render3D_SIMD();

View File

@ -62,7 +62,8 @@ enum RendererID
RENDERID_SOFTRASTERIZER = 1, RENDERID_SOFTRASTERIZER = 1,
RENDERID_OPENGL_AUTO = 1000, RENDERID_OPENGL_AUTO = 1000,
RENDERID_OPENGL_LEGACY = 1001, RENDERID_OPENGL_LEGACY = 1001,
RENDERID_OPENGL_3_2 = 1002 RENDERID_OPENGL_3_2 = 1002,
RENDERID_METAL = 2000
}; };
enum Render3DErrorCode enum Render3DErrorCode
@ -184,10 +185,17 @@ protected:
u32 *_textureUpscaleBuffer; u32 *_textureUpscaleBuffer;
Render3DTexture *_textureList[POLYLIST_SIZE]; Render3DTexture *_textureList[POLYLIST_SIZE];
size_t _clippedPolyCount;
size_t _clippedPolyOpaqueCount;
GFX3D_Clipper _clipper;
CPoly *_clippedPolyList;
CACHE_ALIGN u16 clearImageColor16Buffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN u16 clearImageColor16Buffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT];
CACHE_ALIGN u32 clearImageDepthBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN u32 clearImageDepthBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT];
CACHE_ALIGN u8 clearImageFogBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN u8 clearImageFogBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT];
template<ClipperMode CLIPPERMODE> void _PerformClipping(const VERT *vertList, const POLYLIST *polyList, const INDEXLIST *indexList);
template<bool ISCOLORBLANK, bool ISDEPTHBLANK> void _ClearImageScrolledLoop(const u8 xScroll, const u8 yScroll, const u16 *__restrict inColor16, const u16 *__restrict inDepth16, template<bool ISCOLORBLANK, bool ISDEPTHBLANK> void _ClearImageScrolledLoop(const u8 xScroll, const u8 yScroll, const u16 *__restrict inColor16, const u16 *__restrict inDepth16,
u16 *__restrict outColor16, u32 *__restrict outDepth24, u8 *__restrict outFog); u16 *__restrict outColor16, u32 *__restrict outDepth24, u8 *__restrict outFog);
@ -263,6 +271,9 @@ public:
void SetTextureProcessingProperties(); void SetTextureProcessingProperties();
Render3DTexture* GetTextureByPolygonRenderIndex(size_t polyRenderIndex) const; Render3DTexture* GetTextureByPolygonRenderIndex(size_t polyRenderIndex) const;
const CPoly& GetClippedPolyByIndex(size_t index) const;
size_t GetClippedPolyCount() const;
}; };
template <size_t SIMDBYTES> template <size_t SIMDBYTES>