OpenGL Renderer: Properly clear the framebuffer during a power-off condition, just like how SoftRasterizer does it. (Related to commit 66b5da1 and commit 759a039. Fixes #234.)

- Also do a minor performance optimization by only doing the framebuffer clear once for each power-off condition, rather than repeatedly and unnecessarily clearing the framebuffer for each and every V-blank.
This commit is contained in:
rogerman 2018-12-04 21:23:58 -08:00
parent df22c6e14d
commit 3d573e150f
8 changed files with 182 additions and 57 deletions

View File

@ -3823,12 +3823,6 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels()
{
OGLRenderRef &OGLRef = *this->ref;
if (this->_mappedFramebuffer != NULL)
{
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
this->_mappedFramebuffer = NULL;
}
if (this->willFlipAndConvertFramebufferOnGPU)
{
// Both flips and converts the framebuffer on the GPU. No additional postprocessing
@ -3926,6 +3920,12 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels()
{
// Read back the pixels in BGRA format, since legacy OpenGL devices may experience a performance
// penalty if the readback is in any other format.
if (this->_mappedFramebuffer != NULL)
{
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
this->_mappedFramebuffer = NULL;
}
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
}
@ -4913,6 +4913,51 @@ Render3DError OpenGLRenderer_1_2::Reset()
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_2::RenderPowerOff()
{
OGLRenderRef &OGLRef = *this->ref;
if (!this->_isPoweredOn)
{
return OGLERROR_NOERR;
}
this->_isPoweredOn = false;
memset(GPU->GetEngineMain()->Get3DFramebufferMain(), 0, this->_framebufferColorSizeBytes);
memset(GPU->GetEngineMain()->Get3DFramebuffer16(), 0, this->_framebufferPixCount * sizeof(u16));
if(!BEGINGL())
{
return OGLERROR_BEGINGL_FAILED;
}
if (this->isFBOSupported)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID);
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (this->isPBOSupported)
{
if (this->_mappedFramebuffer != NULL)
{
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
this->_mappedFramebuffer = NULL;
}
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
}
ENDGL();
this->_pixelReadNeedsFinish = true;
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_1_2::RenderFinish()
{
if (!this->_renderNeedsFinish)
@ -4949,6 +4994,11 @@ Render3DError OpenGLRenderer_1_2::RenderFinish()
Render3DError OpenGLRenderer_1_2::RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16)
{
if (!this->_isPoweredOn)
{
return RENDER3DERROR_NOERR;
}
FragmentColor *framebufferMain = (willFlushBuffer32) ? GPU->GetEngineMain()->Get3DFramebufferMain() : NULL;
u16 *framebuffer16 = (willFlushBuffer16) ? GPU->GetEngineMain()->Get3DFramebuffer16() : NULL;
@ -5257,6 +5307,11 @@ Render3DError OpenGLRenderer_2_1::RenderFinish()
Render3DError OpenGLRenderer_2_1::RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16)
{
if (!this->_isPoweredOn)
{
return RENDER3DERROR_NOERR;
}
FragmentColor *framebufferMain = (willFlushBuffer32) ? GPU->GetEngineMain()->Get3DFramebufferMain() : NULL;
u16 *framebuffer16 = (willFlushBuffer16) ? GPU->GetEngineMain()->Get3DFramebuffer16() : NULL;

View File

@ -816,6 +816,7 @@ public:
virtual Render3DError InitExtensions();
virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer);
virtual Render3DError Reset();
virtual Render3DError RenderPowerOff();
virtual Render3DError RenderFinish();
virtual Render3DError RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16);
virtual Render3DError SetFramebufferSize(size_t w, size_t h);

View File

@ -1470,12 +1470,6 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels()
{
OGLRenderRef &OGLRef = *this->ref;
if (this->_mappedFramebuffer != NULL)
{
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
this->_mappedFramebuffer = NULL;
}
if (this->_outputFormat == NDSColorFormat_BGR666_Rev)
{
// Both flips and converts the framebuffer on the GPU. No additional postprocessing
@ -1510,6 +1504,12 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels()
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glBindVertexArray(0);
if (this->_mappedFramebuffer != NULL)
{
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
this->_mappedFramebuffer = NULL;
}
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
}
else
@ -1534,6 +1534,12 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels()
// 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.
if (this->_mappedFramebuffer != NULL)
{
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
this->_mappedFramebuffer = NULL;
}
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
@ -2075,3 +2081,41 @@ Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h)
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::RenderPowerOff()
{
OGLRenderRef &OGLRef = *this->ref;
static const GLfloat oglColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
if (!this->_isPoweredOn)
{
return OGLERROR_NOERR;
}
this->_isPoweredOn = false;
memset(GPU->GetEngineMain()->Get3DFramebufferMain(), 0, this->_framebufferColorSizeBytes);
memset(GPU->GetEngineMain()->Get3DFramebuffer16(), 0, this->_framebufferPixCount * sizeof(u16));
if(!BEGINGL())
{
return OGLERROR_BEGINGL_FAILED;
}
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClearBufferfv(GL_COLOR, 0, oglColor);
if (this->_mappedFramebuffer != NULL)
{
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
this->_mappedFramebuffer = NULL;
}
glReadPixels(0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
ENDGL();
this->_pixelReadNeedsFinish = true;
return OGLERROR_NOERR;
}

View File

@ -1,7 +1,7 @@
/*
Copyright (C) 2006 yopyop
Copyright (C) 2006-2007 shash
Copyright (C) 2008-2016 DeSmuME team
Copyright (C) 2008-2018 DeSmuME team
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
@ -106,6 +106,8 @@ protected:
public:
~OpenGLRenderer_3_2();
virtual Render3DError RenderPowerOff();
};
#endif

View File

@ -2506,10 +2506,7 @@ void gfx3d_VBlankEndSignal(bool skipFrame)
}
else
{
memset(GPU->GetEngineMain()->Get3DFramebufferMain(), 0, GPU->GetCustomFramebufferWidth() * GPU->GetCustomFramebufferHeight() * sizeof(FragmentColor));
memset(GPU->GetEngineMain()->Get3DFramebuffer16(), 0, GPU->GetCustomFramebufferWidth() * GPU->GetCustomFramebufferHeight() * sizeof(u16));
CurrentRenderer->SetRenderNeedsFinish(false);
GPU->GetEventHandler()->DidRender3DEnd();
CurrentRenderer->RenderPowerOff();
}
}

View File

@ -2529,6 +2529,7 @@ Render3DError SoftRasterizerRenderer::Reset()
Render3DError SoftRasterizerRenderer::Render(const GFX3D &engine)
{
Render3DError error = RENDER3DERROR_NOERR;
this->_isPoweredOn = true;
error = this->BeginRender(engine);
if (error != RENDER3DERROR_NOERR)
@ -2609,6 +2610,11 @@ Render3DError SoftRasterizerRenderer::RenderFinish()
Render3DError SoftRasterizerRenderer::RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16)
{
if (!this->_isPoweredOn)
{
return RENDER3DERROR_NOERR;
}
FragmentColor *framebufferMain = (willFlushBuffer32 && (this->_outputFormat == NDSColorFormat_BGR888_Rev)) ? GPU->GetEngineMain()->Get3DFramebufferMain() : NULL;
u16 *framebuffer16 = (willFlushBuffer16) ? GPU->GetEngineMain()->Get3DFramebuffer16() : NULL;
this->FlushFramebuffer(this->_framebufferColor, framebufferMain, framebuffer16);

View File

@ -220,6 +220,7 @@ Render3D::Render3D()
_renderNeedsFinish = false;
_renderNeedsFlushMain = false;
_renderNeedsFlush16 = false;
_isPoweredOn = false;
_textureUpscaleBuffer = NULL;
@ -673,15 +674,31 @@ Render3DError Render3D::Reset()
this->_renderNeedsFinish = false;
this->_renderNeedsFlushMain = false;
this->_renderNeedsFlush16 = false;
this->_isPoweredOn = false;
texCache.Reset();
return RENDER3DERROR_NOERR;
}
Render3DError Render3D::RenderPowerOff()
{
if (!this->_isPoweredOn)
{
return RENDER3DERROR_NOERR;
}
this->_isPoweredOn = false;
memset(GPU->GetEngineMain()->Get3DFramebufferMain(), 0, this->_framebufferColorSizeBytes);
memset(GPU->GetEngineMain()->Get3DFramebuffer16(), 0, this->_framebufferPixCount * sizeof(u16));
return RENDER3DERROR_NOERR;
}
Render3DError Render3D::Render(const GFX3D &engine)
{
Render3DError error = RENDER3DERROR_NOERR;
this->_isPoweredOn = true;
error = this->BeginRender(engine);
if (error != RENDER3DERROR_NOERR)

View File

@ -162,6 +162,7 @@ protected:
bool _renderNeedsFinish;
bool _renderNeedsFlushMain;
bool _renderNeedsFlush16;
bool _isPoweredOn;
bool _enableEdgeMark;
bool _enableFog;
@ -223,6 +224,8 @@ public:
virtual Render3DError Reset(); // Called when the emulator resets.
virtual Render3DError RenderPowerOff(); // Called when the renderer needs to handle a power-off condition by clearing its framebuffers.
virtual Render3DError Render(const GFX3D &engine); // Called when the renderer should do its job and render the current display lists.
virtual Render3DError RenderFinish(); // Called whenever 3D rendering needs to finish. This function should block the calling thread