OpenGL Renderer: Lower host GPU requirements for performing on-GPU final framebuffer conversions.

- Framebuffer conversion now occurs purely in shaders, and also
performs flipping along with conversion. FBOs and PBOs are no longer
required to do this.
- If shaders are not available, then framebuffer flipping will occur if
FBOs are available. PBOs are no longer required to do this.
- Also fix a minor framebuffer attachment bug in the v3.2 renderer.
This commit is contained in:
rogerman 2017-07-29 19:39:21 -07:00
parent 5deec25409
commit 69f97b056a
3 changed files with 102 additions and 113 deletions

View File

@ -596,11 +596,12 @@ static const char *FogFragShader_100 = {"\
static const char *FramebufferOutputVtxShader_100 = {"\ static const char *FramebufferOutputVtxShader_100 = {"\
attribute vec2 inPosition;\n\ attribute vec2 inPosition;\n\
attribute vec2 inTexCoord0;\n\ attribute vec2 inTexCoord0;\n\
uniform vec2 framebufferSize;\n\
varying vec2 texCoord;\n\ varying vec2 texCoord;\n\
\n\ \n\
void main()\n\ void main()\n\
{\n\ {\n\
texCoord = inTexCoord0;\n\ texCoord = vec2(inTexCoord0.x, (framebufferSize.y - (framebufferSize.y * inTexCoord0.y)) / framebufferSize.y);\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\ gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\ }\n\
"}; "};
@ -632,6 +633,8 @@ static const char *FramebufferOutputRGBA8888FragShader_100 = {"\
\n\ \n\
void main()\n\ void main()\n\
{\n\ {\n\
// Note that we swap B and R since pixel readbacks are done in BGRA format for fastest\n\
// performance. The final color is still in RGBA format.\n\
gl_FragData[0] = texture2D(texInFragColor, texCoord).bgra;\n\ gl_FragData[0] = texture2D(texInFragColor, texCoord).bgra;\n\
}\n\ }\n\
"}; "};
@ -1051,8 +1054,8 @@ OpenGLRenderer::OpenGLRenderer()
isMultisampledFBOSupported = false; isMultisampledFBOSupported = false;
isShaderSupported = false; isShaderSupported = false;
isVAOSupported = false; isVAOSupported = false;
willFlipFramebufferOnGPU = false; willFlipOnlyFramebufferOnGPU = false;
willConvertFramebufferOnGPU = false; willFlipAndConvertFramebufferOnGPU = false;
// Init OpenGL rendering states // Init OpenGL rendering states
ref = new OGLRenderRef; ref = new OGLRenderRef;
@ -1456,16 +1459,16 @@ Render3DError OpenGLRenderer::_FlushFramebufferFlipAndConvertOnCPU(const Fragmen
Render3DError OpenGLRenderer::FlushFramebuffer(const FragmentColor *__restrict srcFramebuffer, FragmentColor *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16) Render3DError OpenGLRenderer::FlushFramebuffer(const FragmentColor *__restrict srcFramebuffer, FragmentColor *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16)
{ {
if (this->willFlipFramebufferOnGPU && this->willConvertFramebufferOnGPU) if (this->willFlipAndConvertFramebufferOnGPU && this->isPBOSupported)
{ {
this->_renderNeedsFlushMain = false; this->_renderNeedsFlushMain = false;
return Render3D::FlushFramebuffer(srcFramebuffer, NULL, dstFramebuffer16); return Render3D::FlushFramebuffer(srcFramebuffer, NULL, dstFramebuffer16);
} }
else else
{ {
this->_FlushFramebufferFlipAndConvertOnCPU(srcFramebuffer, return this->_FlushFramebufferFlipAndConvertOnCPU(srcFramebuffer,
dstFramebufferMain, dstFramebuffer16, dstFramebufferMain, dstFramebuffer16,
!this->willFlipFramebufferOnGPU, !this->willConvertFramebufferOnGPU); !this->willFlipOnlyFramebufferOnGPU, !this->willFlipAndConvertFramebufferOnGPU);
} }
return RENDER3DERROR_NOERR; return RENDER3DERROR_NOERR;
@ -1473,7 +1476,7 @@ Render3DError OpenGLRenderer::FlushFramebuffer(const FragmentColor *__restrict s
FragmentColor* OpenGLRenderer::GetFramebuffer() FragmentColor* OpenGLRenderer::GetFramebuffer()
{ {
return (this->willFlipFramebufferOnGPU && this->willConvertFramebufferOnGPU) ? this->_mappedFramebuffer : GPU->GetEngineMain()->Get3DFramebufferMain(); return (this->willFlipAndConvertFramebufferOnGPU && this->isPBOSupported) ? this->_mappedFramebuffer : GPU->GetEngineMain()->Get3DFramebufferMain();
} }
OpenGLTexture* OpenGLRenderer::GetLoadedTextureFromPolygon(const POLY &thePoly, bool enableTexturing) OpenGLTexture* OpenGLRenderer::GetLoadedTextureFromPolygon(const POLY &thePoly, bool enableTexturing)
@ -1679,10 +1682,6 @@ Render3DError OpenGLRenderer_1_2::InitExtensions()
if (maxColorAttachments >= 4) if (maxColorAttachments >= 4)
{ {
// Set these flags now because CreateFBOs() will use them.
this->willFlipFramebufferOnGPU = this->isPBOSupported;
this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isPBOSupported);
// This texture will be used as an FBO color attachment. // This texture will be used as an FBO color attachment.
// If this texture wasn't already created by passing the shader support check, // If this texture wasn't already created by passing the shader support check,
// then create the texture now. // then create the texture now.
@ -1756,8 +1755,8 @@ Render3DError OpenGLRenderer_1_2::InitExtensions()
} }
// Set rendering support flags based on driver features. // Set rendering support flags based on driver features.
this->willFlipFramebufferOnGPU = (this->isPBOSupported && this->isFBOSupported); this->willFlipAndConvertFramebufferOnGPU = this->isShaderSupported && this->isVBOSupported;
this->willConvertFramebufferOnGPU = (this->isShaderSupported && this->isPBOSupported && this->isFBOSupported); this->willFlipOnlyFramebufferOnGPU = this->willFlipAndConvertFramebufferOnGPU || this->isFBOSupported;
this->_deviceInfo.isEdgeMarkSupported = (this->isShaderSupported && this->isVBOSupported && this->isFBOSupported); this->_deviceInfo.isEdgeMarkSupported = (this->isShaderSupported && this->isVBOSupported && this->isFBOSupported);
this->_deviceInfo.isFogSupported = (this->isShaderSupported && this->isVBOSupported && this->isFBOSupported); this->_deviceInfo.isFogSupported = (this->isShaderSupported && this->isVBOSupported && this->isFBOSupported);
this->_deviceInfo.isTextureSmoothingSupported = this->isShaderSupported; this->_deviceInfo.isTextureSmoothingSupported = this->isShaderSupported;
@ -2982,10 +2981,12 @@ Render3DError OpenGLRenderer_1_2::InitFramebufferOutputShaderLocations()
OGLRenderRef &OGLRef = *this->ref; OGLRenderRef &OGLRef = *this->ref;
glUseProgram(OGLRef.programFramebufferRGBA6665OutputID); glUseProgram(OGLRef.programFramebufferRGBA6665OutputID);
OGLRef.uniformFramebufferSize_ConvertRGBA6665 = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID, "framebufferSize");
OGLRef.uniformTexInFragColor_ConvertRGBA6665 = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID, "texInFragColor"); OGLRef.uniformTexInFragColor_ConvertRGBA6665 = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID, "texInFragColor");
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_FinalColor); glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_FinalColor);
glUseProgram(OGLRef.programFramebufferRGBA8888OutputID); glUseProgram(OGLRef.programFramebufferRGBA8888OutputID);
OGLRef.uniformFramebufferSize_ConvertRGBA8888 = glGetUniformLocation(OGLRef.programFramebufferRGBA8888OutputID, "framebufferSize");
OGLRef.uniformTexInFragColor_ConvertRGBA8888 = glGetUniformLocation(OGLRef.programFramebufferRGBA8888OutputID, "texInFragColor"); OGLRef.uniformTexInFragColor_ConvertRGBA8888 = glGetUniformLocation(OGLRef.programFramebufferRGBA8888OutputID, "texInFragColor");
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA8888, OGLTextureUnitID_FinalColor); glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA8888, OGLTextureUnitID_FinalColor);
@ -3211,68 +3212,50 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels()
{ {
OGLRenderRef &OGLRef = *this->ref; OGLRenderRef &OGLRef = *this->ref;
if (!this->isPBOSupported)
{
this->_pixelReadNeedsFinish = true;
return OGLERROR_NOERR;
}
if (this->_mappedFramebuffer != NULL) if (this->_mappedFramebuffer != NULL)
{ {
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
this->_mappedFramebuffer = NULL; this->_mappedFramebuffer = NULL;
} }
// Flip the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware. if (this->willFlipAndConvertFramebufferOnGPU)
if (this->willFlipFramebufferOnGPU)
{ {
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID); // Both flips and converts the framebuffer on the GPU. No additional postprocessing
// should be necessary at this point.
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{
glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
this->_lastTextureDrawTarget = OGLTextureUnitID_FinalColor;
}
else
{
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
this->_lastTextureDrawTarget = OGLTextureUnitID_GColor;
}
glBlitFramebufferEXT(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
}
else
{
glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
}
}
if (this->willConvertFramebufferOnGPU)
{
// Perform the color space conversion while we're still on the GPU so
// that we can avoid having to do it on the CPU.
const GLuint convertProgramID = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.programFramebufferRGBA6665OutputID : OGLRef.programFramebufferRGBA8888OutputID; const GLuint convertProgramID = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.programFramebufferRGBA6665OutputID : OGLRef.programFramebufferRGBA8888OutputID;
const GLint uniformTexNumber = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.uniformTexInFragColor_ConvertRGBA6665 : OGLRef.uniformTexInFragColor_ConvertRGBA8888;
const GLint uniformFramebufferSize = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.uniformFramebufferSize_ConvertRGBA6665 : OGLRef.uniformFramebufferSize_ConvertRGBA8888;
glUseProgram(convertProgramID); glUseProgram(convertProgramID);
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) if (this->isFBOSupported)
{ {
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_GColor); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
this->_lastTextureDrawTarget = OGLTextureUnitID_FinalColor; if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{
glUniform1i(uniformTexNumber, OGLTextureUnitID_GColor);
glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
this->_lastTextureDrawTarget = OGLTextureUnitID_FinalColor;
}
else
{
glUniform1i(uniformTexNumber, OGLTextureUnitID_FinalColor);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
this->_lastTextureDrawTarget = OGLTextureUnitID_GColor;
}
} }
else else
{ {
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_FinalColor); glUniform1i(uniformTexNumber, OGLTextureUnitID_FinalColor);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FinalColor);
this->_lastTextureDrawTarget = OGLTextureUnitID_GColor; glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight);
glActiveTextureARB(GL_TEXTURE0_ARB);
} }
glUniform2f(uniformFramebufferSize, this->_framebufferWidth, this->_framebufferHeight);
glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight); glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
@ -3305,20 +3288,35 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels()
glDisableVertexAttribArray(OGLVertexAttributeID_Position); glDisableVertexAttribArray(OGLVertexAttributeID_Position);
glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0); glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
} }
}
else if (this->willFlipOnlyFramebufferOnGPU)
{
// Just flips the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware.
// Further colorspace conversion will need to be done in a later step.
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{ {
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
glBlitFramebufferEXT(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
} }
else else
{ {
glReadBuffer(GL_COLOR_ATTACHMENT1_EXT); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glBlitFramebufferEXT(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID);
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
} }
} }
// Read back the pixels in BGRA format, since legacy OpenGL devices may experience a performance if (this->isPBOSupported)
// penalty if the readback is in any other format. {
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0); // Read back the pixels in BGRA format, since legacy OpenGL devices may experience a performance
// penalty if the readback is in any other format.
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
}
this->_pixelReadNeedsFinish = true; this->_pixelReadNeedsFinish = true;
return OGLERROR_NOERR; return OGLERROR_NOERR;
@ -4349,13 +4347,10 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h)
return OGLERROR_BEGINGL_FAILED; return OGLERROR_BEGINGL_FAILED;
} }
if (this->isPBOSupported) if (this->_mappedFramebuffer != NULL)
{ {
if (this->_mappedFramebuffer != NULL) glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
{ this->_mappedFramebuffer = NULL;
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
this->_mappedFramebuffer = NULL;
}
} }
if (this->isShaderSupported || this->isFBOSupported) if (this->isShaderSupported || this->isFBOSupported)

View File

@ -617,8 +617,8 @@ protected:
bool isMultisampledFBOSupported; bool isMultisampledFBOSupported;
bool isShaderSupported; bool isShaderSupported;
bool isVAOSupported; bool isVAOSupported;
bool willFlipFramebufferOnGPU; bool willFlipOnlyFramebufferOnGPU;
bool willConvertFramebufferOnGPU; bool willFlipAndConvertFramebufferOnGPU;
FragmentColor *_mappedFramebuffer; FragmentColor *_mappedFramebuffer;
FragmentColor *_workingTextureUnpackBuffer; FragmentColor *_workingTextureUnpackBuffer;

View File

@ -549,11 +549,12 @@ static const char *FramebufferOutputVtxShader_150 = {"\
\n\ \n\
in vec2 inPosition;\n\ in vec2 inPosition;\n\
in vec2 inTexCoord0;\n\ in vec2 inTexCoord0;\n\
uniform vec2 framebufferSize;\n\
out vec2 texCoord;\n\ out vec2 texCoord;\n\
\n\ \n\
void main()\n\ void main()\n\
{\n\ {\n\
texCoord = inTexCoord0;\n\ texCoord = vec2(inTexCoord0.x, (framebufferSize.y - (framebufferSize.y * inTexCoord0.y)) / framebufferSize.y);\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\ gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\ }\n\
"}; "};
@ -570,7 +571,9 @@ static const char *FramebufferOutputFragShader_150 = {"\
\n\ \n\
void main()\n\ void main()\n\
{\n\ {\n\
vec4 colorRGBA6665 = texture(texInFragColor, texCoord);\n\ // Note that we swap B and R since pixel readbacks are done in BGRA format for fastest\n\
// performance. The final color is still in RGBA format.\n\
vec4 colorRGBA6665 = texture(texInFragColor, texCoord).bgra;\n\
colorRGBA6665 = floor((colorRGBA6665 * 255.0) + 0.5);\n\ colorRGBA6665 = floor((colorRGBA6665 * 255.0) + 0.5);\n\
colorRGBA6665.rgb = floor(colorRGBA6665.rgb / 4.0);\n\ colorRGBA6665.rgb = floor(colorRGBA6665.rgb / 4.0);\n\
colorRGBA6665.a = floor(colorRGBA6665.a / 8.0);\n\ colorRGBA6665.a = floor(colorRGBA6665.a / 8.0);\n\
@ -624,8 +627,8 @@ Render3DError OpenGLRenderer_3_2::InitExtensions()
this->isShaderSupported = true; this->isShaderSupported = true;
// OpenGL v3.2 Core Profile should have all the necessary features to be able to flip and convert the framebuffer. // OpenGL v3.2 Core Profile should have all the necessary features to be able to flip and convert the framebuffer.
this->willFlipFramebufferOnGPU = true; this->willFlipOnlyFramebufferOnGPU = true;
this->willConvertFramebufferOnGPU = true; this->willFlipAndConvertFramebufferOnGPU = true;
std::string vertexShaderProgram; std::string vertexShaderProgram;
std::string fragmentShaderProgram; std::string fragmentShaderProgram;
@ -803,10 +806,12 @@ Render3DError OpenGLRenderer_3_2::InitFramebufferOutputShaderLocations()
OGLRenderRef &OGLRef = *this->ref; OGLRenderRef &OGLRef = *this->ref;
glUseProgram(OGLRef.programFramebufferRGBA6665OutputID); glUseProgram(OGLRef.programFramebufferRGBA6665OutputID);
OGLRef.uniformFramebufferSize_ConvertRGBA6665 = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID, "framebufferSize");
OGLRef.uniformTexInFragColor_ConvertRGBA6665 = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID, "texInFragColor"); OGLRef.uniformTexInFragColor_ConvertRGBA6665 = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID, "texInFragColor");
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_FinalColor); glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_FinalColor);
glUseProgram(OGLRef.programFramebufferRGBA8888OutputID); glUseProgram(OGLRef.programFramebufferRGBA8888OutputID);
OGLRef.uniformFramebufferSize_ConvertRGBA8888 = glGetUniformLocation(OGLRef.programFramebufferRGBA8888OutputID, "framebufferSize");
OGLRef.uniformTexInFragColor_ConvertRGBA8888 = glGetUniformLocation(OGLRef.programFramebufferRGBA8888OutputID, "texInFragColor"); OGLRef.uniformTexInFragColor_ConvertRGBA8888 = glGetUniformLocation(OGLRef.programFramebufferRGBA8888OutputID, "texInFragColor");
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA8888, OGLTextureUnitID_FinalColor); glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA8888, OGLTextureUnitID_FinalColor);
@ -975,7 +980,6 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs()
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texGDepthID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texGDepthID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, OGLRef.texGPolyID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, OGLRef.texZeroAlphaPixelMaskID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
@ -1011,7 +1015,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs()
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboPostprocessID); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboPostprocessID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGLRef.texGColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGLRef.texGColorID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, OGLRef.texZeroAlphaPixelMaskID); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, OGLRef.texZeroAlphaPixelMaskID, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{ {
@ -1393,52 +1397,29 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels()
this->_mappedFramebuffer = NULL; this->_mappedFramebuffer = NULL;
} }
// Flip the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboPostprocessID);
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{
glDrawBuffer(GL_COLOR_ATTACHMENT1);
this->_lastTextureDrawTarget = OGLTextureUnitID_FinalColor;
}
else
{
glDrawBuffer(GL_COLOR_ATTACHMENT0);
this->_lastTextureDrawTarget = OGLTextureUnitID_GColor;
}
glBlitFramebuffer(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboPostprocessID);
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{
glReadBuffer(GL_COLOR_ATTACHMENT0);
}
else
{
glReadBuffer(GL_COLOR_ATTACHMENT1);
}
if (this->_outputFormat == NDSColorFormat_BGR666_Rev) if (this->_outputFormat == NDSColorFormat_BGR666_Rev)
{ {
// Perform the RGBA6665 color space conversion while we're still on the GPU so // Both flips and converts the framebuffer on the GPU. No additional postprocessing
// that we can avoid having to do it on the CPU. // should be necessary at this point.
glUseProgram(OGLRef.programFramebufferRGBA6665OutputID); glUseProgram(OGLRef.programFramebufferRGBA6665OutputID);
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboPostprocessID);
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{ {
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_GColor); glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_GColor);
glDrawBuffer(GL_COLOR_ATTACHMENT1); glDrawBuffer(GL_COLOR_ATTACHMENT1);
glReadBuffer(GL_COLOR_ATTACHMENT1);
this->_lastTextureDrawTarget = OGLTextureUnitID_FinalColor; this->_lastTextureDrawTarget = OGLTextureUnitID_FinalColor;
} }
else else
{ {
glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_FinalColor); glUniform1i(OGLRef.uniformTexInFragColor_ConvertRGBA6665, OGLTextureUnitID_FinalColor);
glDrawBuffer(GL_COLOR_ATTACHMENT0); glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
this->_lastTextureDrawTarget = OGLTextureUnitID_GColor; this->_lastTextureDrawTarget = OGLTextureUnitID_GColor;
} }
glUniform2f(OGLRef.uniformFramebufferSize_ConvertRGBA6665, this->_framebufferWidth, this->_framebufferHeight);
glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight); glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
@ -1451,19 +1432,32 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels()
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glBindVertexArray(0); glBindVertexArray(0);
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
}
else
{
// Just flips the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboPostprocessID);
if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor)
{ {
glReadBuffer(GL_COLOR_ATTACHMENT0); glDrawBuffer(GL_COLOR_ATTACHMENT1);
glBlitFramebuffer(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboPostprocessID);
glReadBuffer(GL_COLOR_ATTACHMENT1);
} }
else else
{ {
glReadBuffer(GL_COLOR_ATTACHMENT1); glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, this->_framebufferHeight, this->_framebufferWidth, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboPostprocessID);
glReadBuffer(GL_COLOR_ATTACHMENT0);
} }
}
// Read back the pixels in RGBA format, since an OpenGL 3.2 device should be able to read back this // Read back the pixels in RGBA format, since an OpenGL 3.2 device should be able to read back this
// format without a performance penalty. // format without a performance penalty.
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0); glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
this->_pixelReadNeedsFinish = true; this->_pixelReadNeedsFinish = true;
return OGLERROR_NOERR; return OGLERROR_NOERR;