OpenGL Renderer: Remove extraneous OpenGL v1.x classes, and do more aggressive capabilities checks on init.

- Keep OpenGLRenderer_1_2 as the sole OpenGL v1.x class, and then
remove the following classes: OpenGLRenderer_1_3, OpenGLRenderer_1_4,
OpenGLRenderer_1_5.
This commit is contained in:
rogerman 2017-07-28 11:22:34 -07:00
parent 1938dc2eed
commit 8c37d4acd6
2 changed files with 121 additions and 638 deletions

View File

@ -933,21 +933,6 @@ static Render3D* OpenGLRendererCreate()
newRenderer = new OpenGLRenderer_2_0;
newRenderer->SetVersion(2, 0, 0);
}
else if (IsVersionSupported(1, 5, 0))
{
newRenderer = new OpenGLRenderer_1_5;
newRenderer->SetVersion(1, 5, 0);
}
else if (IsVersionSupported(1, 4, 0))
{
newRenderer = new OpenGLRenderer_1_4;
newRenderer->SetVersion(1, 4, 0);
}
else if (IsVersionSupported(1, 3, 0))
{
newRenderer = new OpenGLRenderer_1_3;
newRenderer->SetVersion(1, 3, 0);
}
else if (IsVersionSupported(1, 2, 0))
{
newRenderer = new OpenGLRenderer_1_2;
@ -968,27 +953,27 @@ static Render3D* OpenGLRendererCreate()
error = newRenderer->InitExtensions();
if (error != OGLERROR_NOERR)
{
if ( IsVersionSupported(2, 0, 0) &&
if (error == OGLERROR_DRIVER_VERSION_TOO_OLD)
{
INFO("OpenGL: This driver does not support the minimum feature set required to run this renderer. Disabling 3D renderer.\n");
}
else if ( IsVersionSupported(2, 0, 0) &&
(error == OGLERROR_SHADER_CREATE_ERROR ||
error == OGLERROR_VERTEX_SHADER_PROGRAM_LOAD_ERROR ||
error == OGLERROR_FRAGMENT_SHADER_PROGRAM_LOAD_ERROR) )
{
INFO("OpenGL: Shaders are not working, even though they should be. Disabling 3D renderer.\n");
delete newRenderer;
newRenderer = NULL;
ENDGL();
return newRenderer;
}
else if (IsVersionSupported(3, 0, 0) && error == OGLERROR_FBO_CREATE_ERROR && OGLLoadEntryPoints_3_2_Func != NULL)
{
INFO("OpenGL: FBOs are not working, even though they should be. Disabling 3D renderer.\n");
delete newRenderer;
newRenderer = NULL;
ENDGL();
return newRenderer;
}
delete newRenderer;
newRenderer = NULL;
ENDGL();
return newRenderer;
}
ENDGL();
@ -1468,15 +1453,26 @@ Render3DError OpenGLRenderer_1_2::InitExtensions()
std::set<std::string> oglExtensionSet;
this->GetExtensionSet(&oglExtensionSet);
if (!this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_multitexture"))
{
return OGLERROR_DRIVER_VERSION_TOO_OLD;
}
else
{
GLint maxFixedFunctionTexUnitsOGL = 0;
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxFixedFunctionTexUnitsOGL);
if (maxFixedFunctionTexUnitsOGL < 4)
{
return OGLERROR_DRIVER_VERSION_TOO_OLD;
}
}
// Get host GPU device properties
GLfloat maxAnisotropyOGL = 1.0f;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL);
this->_deviceInfo.maxAnisotropy = maxAnisotropyOGL;
GLint maxSamplesOGL = 0;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamplesOGL);
this->_deviceInfo.maxSamples = (u8)maxSamplesOGL;
// Initialize OpenGL
this->InitTables();
@ -1486,43 +1482,57 @@ Render3DError OpenGLRenderer_1_2::InitExtensions()
this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_program");
if (this->isShaderSupported)
{
std::string vertexShaderProgram;
std::string fragmentShaderProgram;
GLint maxDrawBuffersOGL = 0;
GLint maxShaderTexUnitsOGL = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &maxDrawBuffersOGL);
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxShaderTexUnitsOGL);
error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram);
if (error == OGLERROR_NOERR)
if ( (maxDrawBuffersOGL >= 4) && (maxShaderTexUnitsOGL >= 8) )
{
error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram);
std::string vertexShaderProgram;
std::string fragmentShaderProgram;
error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram);
if (error == OGLERROR_NOERR)
{
std::string zeroAlphaPixelMaskVtxShaderString = std::string(ZeroAlphaPixelMaskVtxShader_100);
std::string zeroAlphaPixelMaskFragShaderString = std::string(ZeroAlphaPixelMaskFragShader_100);
std::string edgeMarkVtxShaderString = std::string(EdgeMarkVtxShader_100);
std::string edgeMarkFragShaderString = std::string(EdgeMarkFragShader_100);
std::string fogVtxShaderString = std::string(FogVtxShader_100);
std::string fogFragShaderString = std::string(FogFragShader_100);
std::string framebufferOutputVtxShaderString = std::string(FramebufferOutputVtxShader_100);
std::string framebufferOutputRGBA6665FragShaderString = std::string(FramebufferOutputRGBA6665FragShader_100);
std::string framebufferOutputRGBA8888FragShaderString = std::string(FramebufferOutputRGBA8888FragShader_100);
error = this->InitPostprocessingPrograms(zeroAlphaPixelMaskVtxShaderString,
zeroAlphaPixelMaskFragShaderString,
edgeMarkVtxShaderString,
edgeMarkFragShaderString,
fogVtxShaderString,
fogFragShaderString,
framebufferOutputVtxShaderString,
framebufferOutputRGBA6665FragShaderString,
framebufferOutputRGBA8888FragShaderString);
error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram);
if (error == OGLERROR_NOERR)
{
std::string zeroAlphaPixelMaskVtxShaderString = std::string(ZeroAlphaPixelMaskVtxShader_100);
std::string zeroAlphaPixelMaskFragShaderString = std::string(ZeroAlphaPixelMaskFragShader_100);
std::string edgeMarkVtxShaderString = std::string(EdgeMarkVtxShader_100);
std::string edgeMarkFragShaderString = std::string(EdgeMarkFragShader_100);
std::string fogVtxShaderString = std::string(FogVtxShader_100);
std::string fogFragShaderString = std::string(FogFragShader_100);
std::string framebufferOutputVtxShaderString = std::string(FramebufferOutputVtxShader_100);
std::string framebufferOutputRGBA6665FragShaderString = std::string(FramebufferOutputRGBA6665FragShader_100);
std::string framebufferOutputRGBA8888FragShaderString = std::string(FramebufferOutputRGBA8888FragShader_100);
error = this->InitPostprocessingPrograms(zeroAlphaPixelMaskVtxShaderString,
zeroAlphaPixelMaskFragShaderString,
edgeMarkVtxShaderString,
edgeMarkFragShaderString,
fogVtxShaderString,
fogFragShaderString,
framebufferOutputVtxShaderString,
framebufferOutputRGBA6665FragShaderString,
framebufferOutputRGBA8888FragShaderString);
}
}
if (error != OGLERROR_NOERR)
{
this->DestroyGeometryProgram();
this->isShaderSupported = false;
}
}
if (error != OGLERROR_NOERR)
else
{
this->DestroyGeometryProgram();
INFO("OpenGL: Driver does not support at least 4 draw buffers and 8 texture image units.\n");
this->isShaderSupported = false;
}
}
else
if (!this->isShaderSupported)
{
INFO("OpenGL: Shaders are unsupported. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n");
}
@ -1556,17 +1566,29 @@ Render3DError OpenGLRenderer_1_2::InitExtensions()
this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_packed_depth_stencil");
if (this->isFBOSupported)
{
// Set these flags now because CreateFBOs() will use them.
this->willFlipFramebufferOnGPU = this->isPBOSupported;
this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isPBOSupported);
GLint maxColorAttachments = 0;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments);
error = this->CreateFBOs();
if (error != OGLERROR_NOERR)
if (maxColorAttachments >= 4)
{
// Set these flags now because CreateFBOs() will use them.
this->willFlipFramebufferOnGPU = this->isPBOSupported;
this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isPBOSupported);
error = this->CreateFBOs();
if (error != OGLERROR_NOERR)
{
this->isFBOSupported = false;
}
}
else
{
INFO("OpenGL: Driver does not support at least 4 FBO color attachments.\n");
this->isFBOSupported = false;
}
}
else
if (!this->isFBOSupported)
{
INFO("OpenGL: FBOs are unsupported. Some emulation features will be disabled.\n");
}
@ -1576,13 +1598,26 @@ Render3DError OpenGLRenderer_1_2::InitExtensions()
this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_framebuffer_multisample");
if (this->isMultisampledFBOSupported)
{
error = this->CreateMultisampledFBO();
if (error != OGLERROR_NOERR)
GLint maxSamplesOGL = 0;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamplesOGL);
this->_deviceInfo.maxSamples = (u8)maxSamplesOGL;
if (maxSamplesOGL >= 2)
{
error = this->CreateMultisampledFBO();
if (error != OGLERROR_NOERR)
{
this->isMultisampledFBOSupported = false;
}
}
else
{
this->isMultisampledFBOSupported = false;
INFO("OpenGL: Driver does not support at least 2x multisampled FBOs.\n");
}
}
else
if (!this->isMultisampledFBOSupported)
{
INFO("OpenGL: Multisampled FBOs are unsupported. Multisample antialiasing will be disabled.\n");
}
@ -1903,7 +1938,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
if (this->willFlipFramebufferOnGPU)
{
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor);
glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FinalColor);
glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -1912,7 +1947,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
}
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor);
glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GColor);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -1928,7 +1963,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth);
glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GDepth);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -1936,7 +1971,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID);
glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GPolyID);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGPolyID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -1944,7 +1979,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_ZeroAlphaPixelMask);
glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_ZeroAlphaPixelMask);
glBindTexture(GL_TEXTURE_2D, OGLRef.texZeroAlphaPixelMaskID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -1952,7 +1987,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr);
glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FogAttr);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -1960,7 +1995,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0);
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -2030,7 +2065,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
{
INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
INFO("OpenGL: Failed to created FBOs!\n");
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID);
@ -2073,7 +2108,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
{
INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
INFO("OpenGL: Failed to created FBOs!\n");
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID);
@ -2120,7 +2155,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
{
INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
INFO("OpenGL: Failed to created FBOs!\n");
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID);
@ -2196,21 +2231,6 @@ void OpenGLRenderer_1_2::DestroyFBOs()
Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO()
{
// Check the maximum number of samples that the driver supports and use that.
// Since our target resolution is only 256x192 pixels, using the most samples
// possible is the best thing to do.
GLint maxSamples = (GLint)this->_deviceInfo.maxSamples;
if (maxSamples < 2)
{
INFO("OpenGL: Driver does not support at least 2x multisampled FBOs. Multisample antialiasing will be disabled.\n");
return OGLERROR_FEATURE_UNSUPPORTED;
}
else if (maxSamples > OGLRENDER_MAX_MULTISAMPLES)
{
maxSamples = OGLRENDER_MAX_MULTISAMPLES;
}
OGLRenderRef &OGLRef = *this->ref;
// Set up FBO render targets
@ -2220,6 +2240,12 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO()
glGenRenderbuffersEXT(1, &OGLRef.rboMSGFogAttrID);
glGenRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilID);
GLint maxSamples = this->_deviceInfo.maxSamples;
if (maxSamples > OGLRENDER_MAX_MULTISAMPLES)
{
maxSamples = OGLRENDER_MAX_MULTISAMPLES;
}
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID);
@ -2244,7 +2270,7 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO()
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
{
INFO("OpenGL: Failed to create multisampled FBO. Multisample antialiasing will be disabled.\n");
INFO("OpenGL: Failed to create multisampled FBO!\n");
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderID);
@ -4260,517 +4286,6 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h)
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_3::CreateToonTable()
{
OGLRenderRef &OGLRef = *this->ref;
u16 tempToonTable[32];
memset(tempToonTable, 0, sizeof(tempToonTable));
// The toon table is a special 1D texture where each pixel corresponds
// to a specific color in the toon table.
glGenTextures(1, &OGLRef.texToonTableID);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_ToonTable);
glBindTexture(GL_TEXTURE_1D, OGLRef.texToonTableID);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, tempToonTable);
glActiveTexture(GL_TEXTURE0);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_3::UpdateToonTable(const u16 *toonTableBuffer)
{
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_ToonTable);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, toonTableBuffer);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_3::UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 *__restrict polyIDBuffer)
{
OGLRenderRef &OGLRef = *this->ref;
if (this->isShaderSupported)
{
for (size_t i = 0; i < GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT; i++)
{
OGLRef.workingCIDepthStencilBuffer[i] = (depthBuffer[i] << 8) | polyIDBuffer[i];
OGLRef.workingCIDepthBuffer[i] = depthBuffer[i] | 0xFF000000;
OGLRef.workingCIFogAttributesBuffer[i] = (fogBuffer[i]) ? 0xFF0000FF : 0xFF000000;
OGLRef.workingCIPolyIDBuffer[i] = (GLuint)polyIDBuffer[i] | 0xFF000000;
}
}
else
{
for (size_t i = 0; i < GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT; i++)
{
OGLRef.workingCIDepthStencilBuffer[i] = (depthBuffer[i] << 8) | polyIDBuffer[i];
}
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, colorBuffer);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingCIDepthStencilBuffer);
if (this->isShaderSupported)
{
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIDepthBuffer);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIFogAttributesBuffer);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIPolyIDBuffer);
}
glBindTexture(GL_TEXTURE_2D, 0);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_3::SetFramebufferSize(size_t w, size_t h)
{
OGLRenderRef &OGLRef = *this->ref;
if (w < GPU_FRAMEBUFFER_NATIVE_WIDTH || h < GPU_FRAMEBUFFER_NATIVE_HEIGHT)
{
return OGLERROR_NOERR;
}
if (!BEGINGL())
{
return OGLERROR_BEGINGL_FAILED;
}
if (this->isPBOSupported)
{
if (this->_mappedFramebuffer != NULL)
{
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
this->_mappedFramebuffer = NULL;
}
}
if (this->isFBOSupported)
{
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, w, h, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_ZeroAlphaPixelMask);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
}
if (this->isMultisampledFBOSupported)
{
GLint maxSamples = (GLint)this->_deviceInfo.maxSamples;
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_DEPTH24_STENCIL8_EXT, w, h);
}
if (this->willFlipFramebufferOnGPU)
{
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor);
glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
}
if (this->willConvertFramebufferOnGPU)
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboFramebufferRGBA6665ID);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, w, h);
}
const size_t newFramebufferColorSizeBytes = w * h * sizeof(FragmentColor);
this->_framebufferWidth = w;
this->_framebufferHeight = h;
this->_framebufferColorSizeBytes = newFramebufferColorSizeBytes;
if (this->isPBOSupported)
{
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, newFramebufferColorSizeBytes, NULL, GL_STREAM_READ_ARB);
this->_framebufferColor = NULL;
}
else
{
FragmentColor *oldFramebufferColor = this->_framebufferColor;
FragmentColor *newFramebufferColor = (FragmentColor *)malloc_alignedCacheLine(newFramebufferColorSizeBytes);
this->_framebufferColor = newFramebufferColor;
free_aligned(oldFramebufferColor);
}
if (oglrender_framebufferDidResizeCallback != NULL)
{
oglrender_framebufferDidResizeCallback(w, h);
}
ENDGL();
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_4::InitFinalRenderStates(const std::set<std::string> *oglExtensionSet)
{
OGLRenderRef &OGLRef = *this->ref;
bool isBlendEquationSeparateSupported = this->IsExtensionPresent(oglExtensionSet, "GL_EXT_blend_equation_separate");
// Blending Support
if (isBlendEquationSeparateSupported)
{
// we want to use alpha destination blending so we can track the last-rendered alpha value
// test: new super mario brothers renders the stormclouds at the beginning
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA);
glBlendEquationSeparateEXT(GL_FUNC_ADD, GL_MAX);
}
else
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_DST_ALPHA);
}
// Mirrored Repeat Mode Support
OGLRef.stateTexMirroredRepeat = GL_MIRRORED_REPEAT;
// Map the vertex list's colors with 4 floats per color. This is being done
// because OpenGL needs 4-colors per vertex to support translucency. (The DS
// uses 3-colors per vertex, and adds alpha through the poly, so we can't
// simply reference the colors+alpha from just the vertices by themselves.)
OGLRef.color4fBuffer = (this->isShaderSupported) ? NULL : new GLfloat[VERTLIST_SIZE * 4];
// If VBOs aren't supported, then we need to create the index buffer on the
// client side so that we have a buffer to update.
OGLRef.vertIndexBuffer = (this->isVBOSupported) ? NULL : new GLushort[OGLRENDER_VERT_INDEX_BUFFER_COUNT];
return OGLERROR_NOERR;
}
OpenGLRenderer_1_5::~OpenGLRenderer_1_5()
{
glFinish();
DestroyVAOs();
DestroyVBOs();
DestroyPBOs();
}
Render3DError OpenGLRenderer_1_5::CreateVBOs()
{
OGLRenderRef &OGLRef = *this->ref;
glGenBuffers(1, &OGLRef.vboGeometryVtxID);
glGenBuffers(1, &OGLRef.iboGeometryIndexID);
glGenBuffers(1, &OGLRef.vboPostprocessVtxID);
glGenBuffers(1, &OGLRef.iboPostprocessIndexID);
glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
glBufferData(GL_ARRAY_BUFFER, VERTLIST_SIZE * sizeof(VERT), NULL, GL_STREAM_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort), NULL, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
glBufferData(GL_ARRAY_BUFFER, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(PostprocessElementBuffer), PostprocessElementBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return OGLERROR_NOERR;
}
void OpenGLRenderer_1_5::DestroyVBOs()
{
if (!this->isVBOSupported)
{
return;
}
OGLRenderRef &OGLRef = *this->ref;
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &OGLRef.vboGeometryVtxID);
glDeleteBuffers(1, &OGLRef.iboGeometryIndexID);
glDeleteBuffers(1, &OGLRef.vboPostprocessVtxID);
glDeleteBuffers(1, &OGLRef.iboPostprocessIndexID);
this->isVBOSupported = false;
}
Render3DError OpenGLRenderer_1_5::CreateVAOs()
{
OGLRenderRef &OGLRef = *this->ref;
glGenVertexArrays(1, &OGLRef.vaoGeometryStatesID);
glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID);
glBindVertexArray(OGLRef.vaoGeometryStatesID);
glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID);
glEnableVertexAttribArray(OGLVertexAttributeID_Position);
glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
glEnableVertexAttribArray(OGLVertexAttributeID_Color);
glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord));
glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord));
glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color));
glBindVertexArray(0);
glBindVertexArray(OGLRef.vaoPostprocessStatesID);
glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID);
glEnableVertexAttribArray(OGLVertexAttributeID_Position);
glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8));
glBindVertexArray(0);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_5::EnableVertexAttributes()
{
OGLRenderRef &OGLRef = *this->ref;
if (this->isVAOSupported)
{
glBindVertexArray(OGLRef.vaoGeometryStatesID);
}
else
{
if (this->isShaderSupported)
{
glEnableVertexAttribArray(OGLVertexAttributeID_Position);
glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
glEnableVertexAttribArray(OGLVertexAttributeID_Color);
glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrPosition);
glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrTexCoord);
glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), OGLRef.vtxPtrColor);
}
else
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glColorPointer(4, GL_FLOAT, 0, OGLRef.vtxPtrColor);
glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
glVertexPointer(4, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrPosition);
glTexCoordPointer(2, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrTexCoord);
}
}
glActiveTexture(GL_TEXTURE0);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_5::DisableVertexAttributes()
{
if (this->isVAOSupported)
{
glBindVertexArray(0);
}
else
{
if (this->isShaderSupported)
{
glDisableVertexAttribArray(OGLVertexAttributeID_Position);
glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
glDisableVertexAttribArray(OGLVertexAttributeID_Color);
}
else
{
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_5::BeginRender(const GFX3D &engine)
{
OGLRenderRef &OGLRef = *this->ref;
if(!BEGINGL())
{
return OGLERROR_BEGINGL_FAILED;
}
if (this->isShaderSupported)
{
glUseProgram(OGLRef.programGeometryID);
glUniform1i(OGLRef.uniformStateToonShadingMode, engine.renderState.shading);
glUniform1i(OGLRef.uniformStateEnableAlphaTest, (engine.renderState.enableAlphaTest) ? GL_TRUE : GL_FALSE);
glUniform1i(OGLRef.uniformStateEnableAntialiasing, (engine.renderState.enableAntialiasing) ? GL_TRUE : GL_FALSE);
glUniform1i(OGLRef.uniformStateEnableEdgeMarking, (engine.renderState.enableEdgeMarking) ? GL_TRUE : GL_FALSE);
glUniform1i(OGLRef.uniformStateUseWDepth, (engine.renderState.wbuffer) ? GL_TRUE : GL_FALSE);
glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
glUniform1i(OGLRef.uniformTexDrawOpaque, GL_FALSE);
glUniform1i(OGLRef.uniformPolyDrawShadow, GL_FALSE);
}
else
{
if(engine.renderState.enableAlphaTest && (engine.renderState.alphaTestRef > 0))
{
glAlphaFunc(GL_GEQUAL, divide5bitBy31_LUT[engine.renderState.alphaTestRef]);
}
else
{
glAlphaFunc(GL_GREATER, 0);
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID);
size_t vertIndexCount = 0;
GLushort *indexPtr = (GLushort *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
for (size_t i = 0; i < engine.polylist->count; i++)
{
const POLY *thePoly = &engine.polylist->list[engine.indexlist.list[i]];
const size_t polyType = thePoly->type;
if (this->isShaderSupported)
{
for (size_t j = 0; j < polyType; j++)
{
const GLushort vertIndex = thePoly->vertIndexes[j];
// While we're looping through our vertices, add each vertex index to
// a buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional
// vertices here to convert them to GL_TRIANGLES, which are much easier
// to work with and won't be deprecated in future OpenGL versions.
indexPtr[vertIndexCount++] = vertIndex;
if (thePoly->vtxFormat == GFX3D_QUADS || thePoly->vtxFormat == GFX3D_QUAD_STRIP)
{
if (j == 2)
{
indexPtr[vertIndexCount++] = vertIndex;
}
else if (j == 3)
{
indexPtr[vertIndexCount++] = thePoly->vertIndexes[0];
}
}
}
}
else
{
const GLfloat thePolyAlpha = (!thePoly->isWireframe() && thePoly->isTranslucent()) ? divide5bitBy31_LUT[thePoly->getAttributeAlpha()] : 1.0f;
for (size_t j = 0; j < polyType; j++)
{
const GLushort vertIndex = thePoly->vertIndexes[j];
const size_t colorIndex = vertIndex * 4;
// Consolidate the vertex color and the poly alpha to our internal color buffer
// so that OpenGL can use it.
const VERT *vert = &engine.vertlist->list[vertIndex];
OGLRef.color4fBuffer[colorIndex+0] = material_8bit_to_float[vert->color[0]];
OGLRef.color4fBuffer[colorIndex+1] = material_8bit_to_float[vert->color[1]];
OGLRef.color4fBuffer[colorIndex+2] = material_8bit_to_float[vert->color[2]];
OGLRef.color4fBuffer[colorIndex+3] = thePolyAlpha;
// While we're looping through our vertices, add each vertex index to a
// buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional
// vertices here to convert them to GL_TRIANGLES, which are much easier
// to work with and won't be deprecated in future OpenGL versions.
indexPtr[vertIndexCount++] = vertIndex;
if (thePoly->vtxFormat == GFX3D_QUADS || thePoly->vtxFormat == GFX3D_QUAD_STRIP)
{
if (j == 2)
{
indexPtr[vertIndexCount++] = vertIndex;
}
else if (j == 3)
{
indexPtr[vertIndexCount++] = thePoly->vertIndexes[0];
}
}
}
}
this->_textureList[i] = this->GetLoadedTextureFromPolygon(*thePoly, engine.renderState.enableTexturing);
}
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * engine.vertlist->count, engine.vertlist);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_2_0::InitFinalRenderStates(const std::set<std::string> *oglExtensionSet)
{
OGLRenderRef &OGLRef = *this->ref;
// we want to use alpha destination blending so we can track the last-rendered alpha value
// test: new super mario brothers renders the stormclouds at the beginning
// Blending Support
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
// Mirrored Repeat Mode Support
OGLRef.stateTexMirroredRepeat = GL_MIRRORED_REPEAT;
// Ignore our color buffer since we'll transfer the polygon alpha through a uniform.
OGLRef.color4fBuffer = NULL;
// VBOs are supported here, so just use the index buffer on the GPU.
OGLRef.vertIndexBuffer = NULL;
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_2_0::EnableVertexAttributes()
{
OGLRenderRef &OGLRef = *this->ref;

38
desmume/src/OGLRender.h Normal file → Executable file
View File

@ -311,6 +311,8 @@ enum OGLErrorCode
{
OGLERROR_NOERR = RENDER3DERROR_NOERR,
OGLERROR_DRIVER_VERSION_TOO_OLD,
OGLERROR_BEGINGL_FAILED,
OGLERROR_FEATURE_UNSUPPORTED,
@ -768,43 +770,9 @@ public:
virtual Render3DError SetFramebufferSize(size_t w, size_t h);
};
class OpenGLRenderer_1_3 : public OpenGLRenderer_1_2
class OpenGLRenderer_2_0 : public OpenGLRenderer_1_2
{
protected:
virtual Render3DError CreateToonTable();
virtual Render3DError UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 *__restrict polyIDBuffer);
public:
virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer);
virtual Render3DError SetFramebufferSize(size_t w, size_t h);
};
class OpenGLRenderer_1_4 : public OpenGLRenderer_1_3
{
protected:
virtual Render3DError InitFinalRenderStates(const std::set<std::string> *oglExtensionSet);
};
class OpenGLRenderer_1_5 : public OpenGLRenderer_1_4
{
protected:
virtual Render3DError CreateVBOs();
virtual void DestroyVBOs();
virtual Render3DError CreateVAOs();
virtual Render3DError EnableVertexAttributes();
virtual Render3DError DisableVertexAttributes();
virtual Render3DError BeginRender(const GFX3D &engine);
public:
~OpenGLRenderer_1_5();
};
class OpenGLRenderer_2_0 : public OpenGLRenderer_1_5
{
protected:
virtual Render3DError InitFinalRenderStates(const std::set<std::string> *oglExtensionSet);
virtual Render3DError EnableVertexAttributes();
virtual Render3DError DisableVertexAttributes();