Kaydet (Commit) 01bed808 authored tarafından Louis-Francis Ratté-Boulianne's avatar Louis-Francis Ratté-Boulianne Kaydeden (comit) Markus Mohrhard

vcl: Re-use a framebuffer of the same size when possible

Conflicts:
	include/vcl/opengl/OpenGLContext.hxx

Change-Id: Id9c7932976ce9d9282776c20d93d9cca4d290056
üst 4c424d78
...@@ -208,18 +208,21 @@ public: ...@@ -208,18 +208,21 @@ public:
// use these methods right after setting a context to make sure drawing happens // use these methods right after setting a context to make sure drawing happens
// in the right FBO (default one is for onscreen painting) // in the right FBO (default one is for onscreen painting)
bool BindFramebuffer( OpenGLFramebuffer* pFramebuffer );
bool AcquireDefaultFramebuffer(); bool AcquireDefaultFramebuffer();
bool AcquireFramebuffer( OpenGLFramebuffer* pFramebuffer );
OpenGLFramebuffer* AcquireFramebuffer( const OpenGLTexture& rTexture ); OpenGLFramebuffer* AcquireFramebuffer( const OpenGLTexture& rTexture );
void ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer ); void ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer );
void AddRef(); void AddRef();
void DeRef(); void DeRef();
void ReleaseFramebuffer( const OpenGLTexture& rTexture );
void ReleaseFramebuffers();
// retrieve a program from the cache or compile/link it // retrieve a program from the cache or compile/link it
OpenGLProgram* GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader ); OpenGLProgram* GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
OpenGLProgram* UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader ); OpenGLProgram* UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
bool isCurrent(); bool isCurrent();
void clearCurrent();
void makeCurrent(); void makeCurrent();
void resetCurrent(); void resetCurrent();
void swapBuffers(); void swapBuffers();
......
...@@ -20,12 +20,16 @@ class VCL_PLUGIN_PUBLIC OpenGLFramebuffer ...@@ -20,12 +20,16 @@ class VCL_PLUGIN_PUBLIC OpenGLFramebuffer
private: private:
GLuint mnId; GLuint mnId;
OpenGLTexture maAttachedTexture; OpenGLTexture maAttachedTexture;
int mnWidth;
int mnHeight;
public: public:
OpenGLFramebuffer(); OpenGLFramebuffer();
virtual ~OpenGLFramebuffer(); virtual ~OpenGLFramebuffer();
GLuint Id() const { return mnId; }; GLuint Id() const { return mnId; };
int GetWidth() const { return mnWidth; };
int GetHeight() const { return mnHeight; };
void Bind(); void Bind();
void Unbind(); void Unbind();
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
OpenGLFramebuffer::OpenGLFramebuffer() : OpenGLFramebuffer::OpenGLFramebuffer() :
mnId( 0 ), mnId( 0 ),
mnWidth( 0 ),
mnHeight( 0 ),
mpPrevFramebuffer( NULL ), mpPrevFramebuffer( NULL ),
mpNextFramebuffer( NULL ) mpNextFramebuffer( NULL )
{ {
...@@ -55,6 +57,8 @@ void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture ) ...@@ -55,6 +57,8 @@ void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture )
{ {
SAL_INFO( "vcl.opengl", "Attaching texture " << rTexture.Id() << " to framebuffer " << (int)mnId ); SAL_INFO( "vcl.opengl", "Attaching texture " << rTexture.Id() << " to framebuffer " << (int)mnId );
maAttachedTexture = rTexture; maAttachedTexture = rTexture;
mnWidth = rTexture.GetWidth();
mnHeight = rTexture.GetHeight();
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
maAttachedTexture.Id(), 0 ); maAttachedTexture.Id(), 0 );
CHECK_GL_ERROR(); CHECK_GL_ERROR();
......
...@@ -120,6 +120,8 @@ void OpenGLSalGraphicsImpl::Init() ...@@ -120,6 +120,8 @@ void OpenGLSalGraphicsImpl::Init()
maOffscreenTex.GetWidth() != GetWidth() || maOffscreenTex.GetWidth() != GetWidth() ||
maOffscreenTex.GetHeight() != GetHeight() ) maOffscreenTex.GetHeight() != GetHeight() )
{ {
if( mpContext ) // valid context
mpContext->ReleaseFramebuffer( maOffscreenTex );
maOffscreenTex = OpenGLTexture(); maOffscreenTex = OpenGLTexture();
} }
} }
...@@ -161,15 +163,18 @@ void OpenGLSalGraphicsImpl::PostDraw() ...@@ -161,15 +163,18 @@ void OpenGLSalGraphicsImpl::PostDraw()
mpProgram = NULL; mpProgram = NULL;
} }
mpContext->ReleaseFramebuffer( mpFramebuffer );
mpFramebuffer = NULL;
CHECK_GL_ERROR(); CHECK_GL_ERROR();
} }
void OpenGLSalGraphicsImpl::freeResources() void OpenGLSalGraphicsImpl::freeResources()
{ {
// TODO Delete shaders, programs and textures if not shared // TODO Delete shaders, programs and textures if not shared
if( mbOffscreen && mpContext && mpContext->isInitialized() )
{
mpContext->makeCurrent();
mpContext->ReleaseFramebuffer( maOffscreenTex );
}
ReleaseContext();
} }
void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask ) void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask )
...@@ -1429,6 +1434,7 @@ void OpenGLSalGraphicsImpl::endPaint() ...@@ -1429,6 +1434,7 @@ void OpenGLSalGraphicsImpl::endPaint()
if( mpContext->mnPainting == 0 && !mbOffscreen ) if( mpContext->mnPainting == 0 && !mbOffscreen )
{ {
mpContext->makeCurrent(); mpContext->makeCurrent();
mpContext->AcquireDefaultFramebuffer();
glFlush(); glFlush();
} }
} }
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
using namespace com::sun::star; using namespace com::sun::star;
#define MAX_FRAMEBUFFER_COUNT 30
// TODO use rtl::Static instead of 'static' // TODO use rtl::Static instead of 'static'
#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
static std::vector<GLXContext> g_vShareList; static std::vector<GLXContext> g_vShareList;
...@@ -57,6 +59,7 @@ OpenGLContext::OpenGLContext(): ...@@ -57,6 +59,7 @@ OpenGLContext::OpenGLContext():
mbRequestLegacyContext(false), mbRequestLegacyContext(false),
mbUseDoubleBufferedRendering(true), mbUseDoubleBufferedRendering(true),
mbRequestVirtualDevice(false), mbRequestVirtualDevice(false),
mnFramebufferCount(0),
mpCurrentFramebuffer(NULL), mpCurrentFramebuffer(NULL),
mpFirstFramebuffer(NULL), mpFirstFramebuffer(NULL),
mpLastFramebuffer(NULL), mpLastFramebuffer(NULL),
...@@ -1281,6 +1284,18 @@ bool OpenGLContext::isCurrent() ...@@ -1281,6 +1284,18 @@ bool OpenGLContext::isCurrent()
glXGetCurrentDrawable() == nDrawable); glXGetCurrentDrawable() == nDrawable);
#endif #endif
} }
void OpenGLContext::clearCurrent()
{
ImplSVData* pSVData = ImplGetSVData();
// release all framebuffers from the old context so we can re-attach the
// texture in the new context
OpenGLContext* pCurrentCtx = pSVData->maGDIData.mpLastContext;
if( pCurrentCtx && pCurrentCtx->isCurrent() )
pCurrentCtx->ReleaseFramebuffers();
}
void OpenGLContext::makeCurrent() void OpenGLContext::makeCurrent()
{ {
ImplSVData* pSVData = ImplGetSVData(); ImplSVData* pSVData = ImplGetSVData();
...@@ -1288,6 +1303,8 @@ void OpenGLContext::makeCurrent() ...@@ -1288,6 +1303,8 @@ void OpenGLContext::makeCurrent()
if (isCurrent()) if (isCurrent())
return; return;
clearCurrent();
#if defined( WNT ) #if defined( WNT )
if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
{ {
...@@ -1328,6 +1345,8 @@ void OpenGLContext::makeCurrent() ...@@ -1328,6 +1345,8 @@ void OpenGLContext::makeCurrent()
void OpenGLContext::resetCurrent() void OpenGLContext::resetCurrent()
{ {
clearCurrent();
#if defined( WNT ) #if defined( WNT )
wglMakeCurrent( m_aGLWin.hDC, 0 ); wglMakeCurrent( m_aGLWin.hDC, 0 );
#elif defined( MACOSX ) #elif defined( MACOSX )
...@@ -1395,14 +1414,10 @@ NSOpenGLView* OpenGLContext::getOpenGLView() ...@@ -1395,14 +1414,10 @@ NSOpenGLView* OpenGLContext::getOpenGLView()
} }
#endif #endif
bool OpenGLContext::AcquireFramebuffer( OpenGLFramebuffer* pFramebuffer ) bool OpenGLContext::BindFramebuffer( OpenGLFramebuffer* pFramebuffer )
{ {
if( pFramebuffer != mpCurrentFramebuffer ) if( pFramebuffer != mpCurrentFramebuffer )
{ {
// release the attached texture so it's available from the other contexts
//if( mpCurrentFramebuffer )
// mpCurrentFramebuffer->DetachTexture();
if( pFramebuffer ) if( pFramebuffer )
pFramebuffer->Bind(); pFramebuffer->Bind();
else else
...@@ -1415,13 +1430,14 @@ bool OpenGLContext::AcquireFramebuffer( OpenGLFramebuffer* pFramebuffer ) ...@@ -1415,13 +1430,14 @@ bool OpenGLContext::AcquireFramebuffer( OpenGLFramebuffer* pFramebuffer )
bool OpenGLContext::AcquireDefaultFramebuffer() bool OpenGLContext::AcquireDefaultFramebuffer()
{ {
return AcquireFramebuffer( NULL ); return BindFramebuffer( NULL );
} }
OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rTexture ) OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rTexture )
{ {
OpenGLFramebuffer* pFramebuffer = NULL; OpenGLFramebuffer* pFramebuffer = NULL;
OpenGLFramebuffer* pFreeFramebuffer = NULL; OpenGLFramebuffer* pFreeFbo = NULL;
OpenGLFramebuffer* pSameSizeFbo = NULL;
// check if there is already a framebuffer attached to that texture // check if there is already a framebuffer attached to that texture
pFramebuffer = mpLastFramebuffer; pFramebuffer = mpLastFramebuffer;
...@@ -1429,18 +1445,27 @@ OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rText ...@@ -1429,18 +1445,27 @@ OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rText
{ {
if( pFramebuffer->IsAttached( rTexture ) ) if( pFramebuffer->IsAttached( rTexture ) )
break; break;
if( !pFreeFramebuffer && pFramebuffer->IsFree() ) if( !pFreeFbo && pFramebuffer->IsFree() )
pFreeFramebuffer = pFramebuffer; pFreeFbo = pFramebuffer;
if( !pSameSizeFbo &&
pFramebuffer->GetWidth() == rTexture.GetWidth() &&
pFramebuffer->GetHeight() == rTexture.GetHeight() )
pSameSizeFbo = pFramebuffer;
pFramebuffer = pFramebuffer->mpPrevFramebuffer; pFramebuffer = pFramebuffer->mpPrevFramebuffer;
} }
// else use any framebuffer having the same size
if( !pFramebuffer && pSameSizeFbo )
pFramebuffer = pSameSizeFbo;
// else use the first free framebuffer // else use the first free framebuffer
if( !pFramebuffer && pFreeFramebuffer ) if( !pFramebuffer && pFreeFbo )
pFramebuffer = pFreeFramebuffer; pFramebuffer = pFreeFbo;
// if there isn't any free one, create a new one // if there isn't any free one, create a new one if the limit isn't reached
if( !pFramebuffer ) if( !pFramebuffer && mnFramebufferCount < MAX_FRAMEBUFFER_COUNT )
{ {
mnFramebufferCount++;
pFramebuffer = new OpenGLFramebuffer(); pFramebuffer = new OpenGLFramebuffer();
if( mpLastFramebuffer ) if( mpLastFramebuffer )
{ {
...@@ -1455,9 +1480,14 @@ OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rText ...@@ -1455,9 +1480,14 @@ OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rText
} }
} }
AcquireFramebuffer( pFramebuffer ); // last try, use any framebuffer
if( pFramebuffer->IsFree() ) // TODO order the list of framebuffers as a LRU
pFramebuffer->AttachTexture( rTexture ); if( !pFramebuffer )
pFramebuffer = mpFirstFramebuffer;
assert( pFramebuffer );
BindFramebuffer( pFramebuffer );
pFramebuffer->AttachTexture( rTexture );
glViewport( 0, 0, rTexture.GetWidth(), rTexture.GetHeight() ); glViewport( 0, 0, rTexture.GetWidth(), rTexture.GetHeight() );
return pFramebuffer; return pFramebuffer;
...@@ -1469,6 +1499,32 @@ void OpenGLContext::ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer ) ...@@ -1469,6 +1499,32 @@ void OpenGLContext::ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer )
pFramebuffer->DetachTexture(); pFramebuffer->DetachTexture();
} }
void OpenGLContext::ReleaseFramebuffer( const OpenGLTexture& rTexture )
{
OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer;
while( pFramebuffer )
{
if( pFramebuffer->IsAttached( rTexture ) )
{
BindFramebuffer( pFramebuffer );
pFramebuffer->DetachTexture();
}
pFramebuffer = pFramebuffer->mpPrevFramebuffer;
}
}
void OpenGLContext::ReleaseFramebuffers()
{
OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer;
while( pFramebuffer )
{
BindFramebuffer( pFramebuffer );
pFramebuffer->DetachTexture();
pFramebuffer = pFramebuffer->mpPrevFramebuffer;
}
}
OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader ) OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
{ {
boost::unordered_map<ProgramKey, OpenGLProgram*>::iterator it; boost::unordered_map<ProgramKey, OpenGLProgram*>::iterator it;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment