diff options
author | Michael Meeks <michael.meeks@collabora.com> | 2015-11-13 12:00:59 +0000 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2015-12-11 11:39:55 +0000 |
commit | 7bc1f1285e82982b5d900f54f3c6f877517598b8 (patch) | |
tree | f055198ff7acfa3cf2fac695186452530d539f19 | |
parent | 93185f720aab0e58564c050ea3518746d8597803 (diff) |
tdf#93529 - move to a Mac-like double-buffered OpenGL model.
This moves us to always rendering to an off-screen texture, and then
(at idle) blitting this to the screen & swapping buffers. Ideally we
should never see any rendering, or flicker again with this approach.
Several fixes are included:
+ avoid multiple OpenGL contexts being created for the same window,
created excessive flicker problems.
+ de-virtualize UseContext - which context we use is less critical.
+ kill 'mbOffscreen' distinction - all VCL rendering is offscreen.
+ implement 'doFlush' and high priority idle flushing.
+ bind stencil buffer for clipping vs. textures - fixing complex
clopping when rendering to virtual-devices, and off-screen.
+ document environment. variables.
+ use white as default background glClear color, but red or
random color for DBGUTIL.
Change-Id: I6be08595b6c8deb7e6db0dbd81308b2c97d2b4ff
-rw-r--r-- | vcl/README.vars | 2 | ||||
-rw-r--r-- | vcl/inc/opengl/texture.hxx | 8 | ||||
-rw-r--r-- | vcl/inc/opengl/win/gdiimpl.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/opengl/x11/gdiimpl.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/openglgdiimpl.hxx | 44 | ||||
-rw-r--r-- | vcl/opengl/framebuffer.cxx | 15 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 282 | ||||
-rw-r--r-- | vcl/opengl/texture.cxx | 44 | ||||
-rw-r--r-- | vcl/opengl/win/gdiimpl.cxx | 11 | ||||
-rw-r--r-- | vcl/opengl/x11/gdiimpl.cxx | 12 | ||||
-rw-r--r-- | vcl/source/opengl/OpenGLContext.cxx | 10 |
11 files changed, 357 insertions, 73 deletions
diff --git a/vcl/README.vars b/vcl/README.vars index 4f62333eed00..bf85485c1388 100644 --- a/vcl/README.vars +++ b/vcl/README.vars @@ -21,6 +21,8 @@ EMF_PLUS_DISABLE - use EMF rendering and ignore EMF+ specifics OpenGL ------ SAL_FORCEGL - force enable OpenGL +SAL_GL_NO_SWAP - disable buffer swapping if set (should show nothing) +SAL_GL_SLEEP_ON_SWAP - sleep for half a second on each swap-buffers. SAL_WITHOUT_WIDGET_CACHE - disable LRU caching of native widget texutres SAL_DISABLE_GLYPH_CACHING - don't render glyphs through OpenGL textures SAL_DISABLE_GL_WATCHDOG - don't start the thread that watches for broken GL drivers diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx index f67b3348d14d..e57aa9e32306 100644 --- a/vcl/inc/opengl/texture.hxx +++ b/vcl/inc/opengl/texture.hxx @@ -37,6 +37,8 @@ public: int mnWidth; int mnHeight; GLenum mnFilter; + GLuint mnOptStencil; + bool mbHasOptStencil; std::unique_ptr<std::vector<int>> mpSlotReferences; int mnFreeSlots; @@ -76,7 +78,8 @@ public: } bool InitializeSlots(int nSlotSize); - int FindFreeSlot(); + int FindFreeSlot(); + GLuint AddStencil(); }; class VCL_DLLPUBLIC OpenGLTexture @@ -110,6 +113,9 @@ public: void Bind(); void Unbind(); void Read( GLenum nFormat, GLenum nType, sal_uInt8* pData ); + GLuint AddStencil(); + bool HasStencil() const; + GLuint StencilId() const; void SaveToFile(const OUString& rFileName); diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx index ecefede6e7ea..8102d2ef5c07 100644 --- a/vcl/inc/opengl/win/gdiimpl.hxx +++ b/vcl/inc/opengl/win/gdiimpl.hxx @@ -31,7 +31,6 @@ public: protected: virtual rtl::Reference<OpenGLContext> CreateWinContext() override; - virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) override; bool RenderTextureCombo(TextureCombo& rCombo, int nX, int nY); diff --git a/vcl/inc/opengl/x11/gdiimpl.hxx b/vcl/inc/opengl/x11/gdiimpl.hxx index f07468d6a135..eccd0ef06ae9 100644 --- a/vcl/inc/opengl/x11/gdiimpl.hxx +++ b/vcl/inc/opengl/x11/gdiimpl.hxx @@ -29,7 +29,6 @@ public: protected: virtual rtl::Reference<OpenGLContext> CreateWinContext() override; - virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) override; bool RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo); diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx index 667b2ec095f0..a1c2a2539352 100644 --- a/vcl/inc/openglgdiimpl.hxx +++ b/vcl/inc/openglgdiimpl.hxx @@ -52,12 +52,20 @@ struct TextureCombo std::unique_ptr<OpenGLTexture> mpMask; }; +class OpenGLFlushIdle; + class VCL_DLLPUBLIC OpenGLSalGraphicsImpl : public SalGraphicsImpl { friend class OpenGLTests; protected: + /// This context is solely for blitting @maOffscreenTex + rtl::Reference<OpenGLContext> mpWindowContext; + + /// This context is whatever is most convenient to render + /// to @maOffscreenTex with. rtl::Reference<OpenGLContext> mpContext; + SalGraphics& mrParent; /// Pointer to the SalFrame or SalVirtualDevice SalGeometryProvider* mpProvider; @@ -67,12 +75,19 @@ protected: /// Is it someone else's context we shouldn't be fiddling with ? static bool IsForeignContext(const rtl::Reference<OpenGLContext> &xContext); + /// This idle handler is used to swap buffers after rendering. + OpenGLFlushIdle *mpFlush; + // clipping vcl::Region maClipRegion; bool mbUseScissor; bool mbUseStencil; - bool mbOffscreen; + /** + * All rendering happens to this off-screen texture. For + * non-virtual devices, ie. windows - we will blit it and + * swapBuffers later. + */ OpenGLTexture maOffscreenTex; SalColor mnLineColor; @@ -80,6 +95,8 @@ protected: #ifdef DBG_UTIL bool mProgramIsSolidColor; #endif + sal_uInt32 mnDrawCount; + sal_uInt32 mnDrawCountAtFlush; SalColor mProgramSolidColor; double mProgramSolidTransparency; @@ -131,7 +148,10 @@ public: // get the height of the device GLfloat GetHeight() const { return mpProvider ? mpProvider->GetHeight() : 1; } - // check whether this instance is used for offscreen rendering + /** + * check whether this instance is used for offscreen (Virtual Device) + * rendering ie. does it need its own context. + */ bool IsOffscreen() const { return mpProvider == nullptr || mpProvider->IsOffScreen(); } // operations to do before painting @@ -144,14 +164,18 @@ protected: bool AcquireContext(); bool ReleaseContext(); - // retrieve the default context for offscreen rendering + /// retrieve the default context for offscreen rendering static rtl::Reference<OpenGLContext> GetDefaultContext(); - // create a new context for window rendering + /// create a new context for rendering to the underlying window virtual rtl::Reference<OpenGLContext> CreateWinContext() = 0; - // check whether the given context can be used by this instance - virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) = 0; + /// check whether the given context can be used for off-screen rendering + bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) + { + return pContext->isInitialized() && // not released by the OS etc. + IsForeignContext( pContext ); // a genuine VCL context. + } public: OpenGLSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider *pProvider); @@ -328,8 +352,12 @@ public: virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; - virtual OpenGLContext *beginPaint() override; -private: + /// queue an idle flush of contents of the back-buffer to the screen + void flush(); + +public: + /// do flush of contents of the back-buffer to the screen & swap. + void doFlush(); }; #endif diff --git a/vcl/opengl/framebuffer.cxx b/vcl/opengl/framebuffer.cxx index c009ccb2601e..464662d31709 100644 --- a/vcl/opengl/framebuffer.cxx +++ b/vcl/opengl/framebuffer.cxx @@ -72,6 +72,16 @@ void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture ) mnHeight = rTexture.GetHeight(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mnAttachedTexture, 0); CHECK_GL_ERROR(); + + GLuint nStencil = rTexture.StencilId(); + if( nStencil ) + { + VCL_GL_INFO( "Attaching stencil " << nStencil << " to framebuffer " << (int)mnId ); + glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, nStencil ); + CHECK_GL_ERROR(); + } + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); CHECK_GL_ERROR(); if (status != GL_FRAMEBUFFER_COMPLETE) @@ -87,6 +97,11 @@ void OpenGLFramebuffer::DetachTexture() mnAttachedTexture = 0; glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 ); CHECK_GL_ERROR(); + + // FIXME: we could make this conditional on having a stencil ? + glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, 0 ); + CHECK_GL_ERROR(); } } diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index 3771d3cec740..380417d1aa70 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -37,20 +37,44 @@ #include <vector> +#include <stdlib.h> + +class OpenGLFlushIdle : public Idle +{ + OpenGLSalGraphicsImpl *m_pImpl; +public: + OpenGLFlushIdle( OpenGLSalGraphicsImpl *pImpl ) + : Idle( "gl idle swap" ) + , m_pImpl( pImpl ) + { + SetPriority( SchedulerPriority::HIGHEST ); + } + ~OpenGLFlushIdle() + { + } + virtual void Invoke() override + { + m_pImpl->doFlush(); + Stop(); + } +}; + OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider *pProvider) : mpContext(nullptr) , mrParent(rParent) , mpProvider(pProvider) , mpFramebuffer(nullptr) , mpProgram(nullptr) + , mpFlush(new OpenGLFlushIdle(this)) , mbUseScissor(false) , mbUseStencil(false) - , mbOffscreen(false) , mnLineColor(SALCOLOR_NONE) , mnFillColor(SALCOLOR_NONE) #ifdef DBG_UTIL , mProgramIsSolidColor(false) #endif + , mnDrawCount(0) + , mnDrawCountAtFlush(0) , mProgramSolidColor(SALCOLOR_NONE) , mProgramSolidTransparency(0.0) { @@ -58,6 +82,11 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl() { + if( !IsOffscreen() && mnDrawCountAtFlush != mnDrawCount ) + VCL_GL_INFO( "Destroying un-flushed on-screen graphics" ); + + delete mpFlush; + ReleaseContext(); } @@ -79,10 +108,9 @@ bool OpenGLSalGraphicsImpl::AcquireContext( ) // We always prefer to bind our VirtualDevice / offscreen graphics // to the current OpenGLContext - to avoid switching contexts. - if (mpContext.is() && mbOffscreen) + if (mpContext.is() && OpenGLContext::hasCurrent() && !mpContext->isCurrent()) { - if (OpenGLContext::hasCurrent() && !mpContext->isCurrent()) - mpContext.clear(); + mpContext.clear(); } if( mpContext.is() ) @@ -97,15 +125,17 @@ bool OpenGLSalGraphicsImpl::AcquireContext( ) while( pContext ) { // check if this context can be used by this SalGraphicsImpl instance - if( UseContext( pContext ) ) + if( UseContext( pContext ) ) break; pContext = pContext->mpPrevContext; } - if( pContext ) + if( mpContext.is() ) mpContext = pContext; + else if( mpWindowContext.is() ) + mpContext = mpWindowContext; else - mpContext = mbOffscreen ? GetDefaultContext() : CreateWinContext(); + mpContext = GetDefaultContext(); return mpContext.is(); } @@ -119,19 +149,20 @@ bool OpenGLSalGraphicsImpl::ReleaseContext() void OpenGLSalGraphicsImpl::Init() { - mbOffscreen = IsOffscreen(); + // Our init phase is strange ::Init is called twice for vdevs. + // the first time around with a NULL geometry provider. + if( !mpProvider ) + return; // check if we can simply re-use the same context if( mpContext.is() ) { - if( !mpContext->isInitialized() || - !UseContext( mpContext ) ) + if( !UseContext( mpContext ) ) ReleaseContext(); } - // reset the offscreen texture - if( !mbOffscreen || - maOffscreenTex.GetWidth() != GetWidth() || + // Always create the offscreen texture + if( maOffscreenTex.GetWidth() != GetWidth() || maOffscreenTex.GetHeight() != GetHeight() ) { if( maOffscreenTex && // don't work to release empty textures @@ -141,6 +172,14 @@ void OpenGLSalGraphicsImpl::Init() mpContext->ReleaseFramebuffer( maOffscreenTex ); } maOffscreenTex = OpenGLTexture(); + VCL_GL_INFO("::Init - re-size offscreen texture"); + } + + if( !IsOffscreen() ) + { + if( mpWindowContext.is() ) + mpWindowContext->reset(); + mpWindowContext = CreateWinContext(); } } @@ -155,12 +194,15 @@ void OpenGLSalGraphicsImpl::DeInit() // get a shiny new context in AcquireContext:: next PreDraw. if( mpContext.is() && !IsOffscreen() ) mpContext->reset(); + mpContext.clear(); } void OpenGLSalGraphicsImpl::PreDraw() { OpenGLZone::enter(); + mnDrawCount++; + if( !AcquireContext() ) { SAL_WARN( "vcl.opengl", "Couldn't acquire context" ); @@ -170,10 +212,7 @@ void OpenGLSalGraphicsImpl::PreDraw() mpContext->makeCurrent(); CHECK_GL_ERROR(); - if( !mbOffscreen ) - mpContext->AcquireDefaultFramebuffer(); - else - CheckOffscreenTexture(); + CheckOffscreenTexture(); CHECK_GL_ERROR(); glViewport( 0, 0, GetWidth(), GetHeight() ); @@ -185,15 +224,13 @@ void OpenGLSalGraphicsImpl::PreDraw() void OpenGLSalGraphicsImpl::PostDraw() { - if( !mbOffscreen && mpContext->mnPainting == 0 ) - glFlush(); if( mbUseScissor ) { glDisable( GL_SCISSOR_TEST ); CHECK_GL_ERROR(); } - if( mbUseStencil ) - { + if( mbUseStencil ) + { glDisable( GL_STENCIL_TEST ); CHECK_GL_ERROR(); } @@ -205,6 +242,18 @@ void OpenGLSalGraphicsImpl::PostDraw() mProgramIsSolidColor = false; #endif } + + assert (maOffscreenTex); + + if( IsOffscreen() ) + assert( !mpWindowContext.is() ); + else + assert( mpWindowContext.is() ); + + // Always queue the flush. + if( !IsOffscreen() ) + flush(); + OpenGLZone::leave(); } @@ -216,8 +265,9 @@ void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset) void OpenGLSalGraphicsImpl::freeResources() { // TODO Delete shaders, programs and textures if not shared - if( mbOffscreen && mpContext.is() && mpContext->isInitialized() ) + if( mpContext.is() && mpContext->isInitialized() ) { + VCL_GL_INFO( "freeResources" ); mpContext->makeCurrent(); mpContext->ReleaseFramebuffer( maOffscreenTex ); } @@ -227,6 +277,20 @@ void OpenGLSalGraphicsImpl::freeResources() void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask ) { glEnable( GL_STENCIL_TEST ); + + VCL_GL_INFO( "Adding complex clip / stencil" ); + GLuint nStencil = maOffscreenTex.StencilId(); + if( nStencil == 0 ) + { + nStencil = maOffscreenTex.AddStencil(); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, nStencil ); + CHECK_GL_ERROR(); + } + // else - we associated the stencil in + // AcquireFrameBuffer / AttachTexture + CHECK_GL_ERROR(); glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); CHECK_GL_ERROR(); @@ -261,7 +325,7 @@ void OpenGLSalGraphicsImpl::ImplInitClipRegion() if( maClipRegion != mpContext->maClipRegion ) { mpContext->maClipRegion = maClipRegion; - if( maClipRegion.IsRectangle() ) + if( mbUseScissor ) { Rectangle aRect( maClipRegion.GetBoundRect() ); glScissor( aRect.Left(), GetHeight() - aRect.Bottom() - 1, aRect.GetWidth() + 1, aRect.GetHeight() + 1 ); @@ -382,8 +446,29 @@ void OpenGLSalGraphicsImpl::SetROPFillColor( SalROPColor /*nROPColor*/ ) bool OpenGLSalGraphicsImpl::CheckOffscreenTexture() { + bool bClearTexture = false; + + VCL_GL_INFO( "Check Offscreen texture" ); + + // Always create the offscreen texture + if( maOffscreenTex ) + { + if( maOffscreenTex.GetWidth() != GetWidth() || + maOffscreenTex.GetHeight() != GetHeight() ) + { + mpContext->ReleaseFramebuffer( maOffscreenTex ); + maOffscreenTex = OpenGLTexture(); + VCL_GL_INFO( "re-size offscreen texture" ); + } + } + if( !maOffscreenTex ) + { + VCL_GL_INFO( "create texture of size " + << GetWidth() << " x " << GetHeight() ); maOffscreenTex = OpenGLTexture( GetWidth(), GetHeight() ); + bClearTexture = true; + } if( !maOffscreenTex.IsUnique() ) { @@ -400,8 +485,23 @@ bool OpenGLSalGraphicsImpl::CheckOffscreenTexture() else { mpFramebuffer = mpContext->AcquireFramebuffer( maOffscreenTex ); + CHECK_GL_ERROR(); + + if( bClearTexture ) + { + glDrawBuffer( GL_COLOR_ATTACHMENT0 ); +#if OSL_DEBUG_LEVEL > 0 // lets have some red debugging background. + GLfloat clearColor[4] = { 1.0, 0, 0, 0 }; +#else + GLfloat clearColor[4] = { 1.0, 1.0, 1.0, 0 }; +#endif + glClearBufferfv( GL_COLOR, 0, clearColor ); + // FIXME: use glClearTexImage if we have it ? + } } + assert( maOffscreenTex ); + CHECK_GL_ERROR(); return true; } @@ -1541,17 +1641,9 @@ void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGrap return; } - if( rImpl.mbOffscreen ) - { - PreDraw(); - DrawTexture( rImpl.maOffscreenTex, rPosAry ); - PostDraw(); - return; - } - - SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** copyBits" ); - // TODO: Copy from one FBO to the other (glBlitFramebuffer) - // ie. copying from one visible window to another visible window + PreDraw(); + DrawTexture( rImpl.maOffscreenTex, rPosAry ); + PostDraw(); } void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) @@ -1878,12 +1970,126 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, return true; } -OpenGLContext *OpenGLSalGraphicsImpl::beginPaint() +void OpenGLSalGraphicsImpl::flush() { - if( mbOffscreen || !AcquireContext() ) - return nullptr; + if( IsOffscreen() ) + return; + + if( !Application::IsInExecute() ) + { + // otherwise nothing would trigger idle rendering + doFlush(); + } + else if( !mpFlush->IsActive() ) + mpFlush->Start(); +} + +void OpenGLSalGraphicsImpl::doFlush() +{ + if( IsOffscreen() ) + return; + + assert( mpWindowContext.is() ); + + if( !maOffscreenTex ) + { + VCL_GL_INFO( "flushAndSwap - odd no texture !" ); + return; + } + + if (mnDrawCountAtFlush == mnDrawCount) + { + VCL_GL_INFO( "eliding redundant flushAndSwap, no drawing since last!" ); + return; + } + + mnDrawCountAtFlush = mnDrawCount; + + OpenGLZone aZone; + + VCL_GL_INFO( "flushAndSwap" ); + + // Interesting ! -> this destroys a context [ somehow ] ... + mpWindowContext->makeCurrent(); + CHECK_GL_ERROR(); + + VCL_GL_INFO( "flushAndSwap - acquire default frame buffer" ); + + mpWindowContext->AcquireDefaultFramebuffer(); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); // FIXME: paranoid double check. + CHECK_GL_ERROR(); + + VCL_GL_INFO( "flushAndSwap - acquired default frame buffer" ); + + glDisable( GL_SCISSOR_TEST ); // FIXME: paranoia ... + CHECK_GL_ERROR(); + glDisable( GL_STENCIL_TEST ); // FIXME: paranoia ... + CHECK_GL_ERROR(); + + glViewport( 0, 0, GetWidth(), GetHeight() ); + CHECK_GL_ERROR(); + +#if OSL_DEBUG_LEVEL > 0 // random background glClear + glClearColor((float)rand()/RAND_MAX, (float)rand()/RAND_MAX, + (float)rand()/RAND_MAX, 1.0); +#else + glClearColor(1.0, 1.0, 1.0, 1.0); +#endif + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + CHECK_GL_ERROR(); + + SalTwoRect aPosAry( 0, 0, maOffscreenTex.GetWidth(), maOffscreenTex.GetHeight(), + 0, 0, maOffscreenTex.GetWidth(), maOffscreenTex.GetHeight() ); + VCL_GL_INFO( "Texture height " << maOffscreenTex.GetHeight() << " vs. window height " << GetHeight() ); + + OpenGLProgram *pProgram = + mpWindowContext->UseProgram( "textureVertexShader", "textureFragmentShader", "" ); + if( !pProgram ) + VCL_GL_INFO( "Can't compile simple copying shader !" ); else - return mpContext.get(); + { + pProgram->Use(); // FIXME: paranoia ... + VCL_GL_INFO( "done paranoid re-use." ); + pProgram->SetTexture( "sampler", maOffscreenTex ); + maOffscreenTex.Bind(); // FIXME: paranoia ... + + VCL_GL_INFO( "bound bits etc." ); + + GLfloat aTexCoord[8]; + maOffscreenTex.GetCoord( aTexCoord, aPosAry, false ); + pProgram->SetTextureCoord( aTexCoord ); + + long nX1( aPosAry.mnDestX ); + long nY1( aPosAry.mnDestY ); + long nX2( nX1 + aPosAry.mnDestWidth ); + long nY2( nY1 + aPosAry.mnDestHeight ); + const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 }, + { nX2, nY1 }, { nX2, nY2 }}; + + sal_uInt32 nPoints = 4; + std::vector<GLfloat> aVertices(nPoints * 2); + sal_uInt32 i, j; + + for( i = 0, j = 0; i < nPoints; i++, j += 2 ) + { + aVertices[j] = GLfloat(aPoints[i].mnX); + aVertices[j+1] = GLfloat(aPoints[i].mnY); + } + + pProgram->ApplyMatrix(GetWidth(), GetHeight(), 0.0); + pProgram->SetVertices( &aVertices[0] ); + glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints ); + + pProgram->Clean(); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + static bool bNoSwap = getenv("SAL_GL_NO_SWAP"); + if (!bNoSwap) + mpWindowContext->swapBuffers(); + } + + VCL_GL_INFO( "flushAndSwap - end." ); } bool OpenGLSalGraphicsImpl::IsForeignContext(const rtl::Reference<OpenGLContext> &xContext) diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx index 2d4cb4041fc6..bf4aa1d5e7bd 100644 --- a/vcl/opengl/texture.cxx +++ b/vcl/opengl/texture.cxx @@ -35,6 +35,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) mnWidth( nWidth ), mnHeight( nHeight ), mnFilter( GL_NEAREST ), + mnOptStencil( 0 ), mnFreeSlots(-1) { glGenTextures( 1, &mnTexture ); @@ -67,6 +68,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) mnWidth( nWidth ), mnHeight( nHeight ), mnFilter( GL_NEAREST ), + mnOptStencil( 0 ), mnFreeSlots(-1) { // FIXME We need the window height here @@ -99,6 +101,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int mnWidth( nWidth ), mnHeight( nHeight ), mnFilter( GL_NEAREST ), + mnOptStencil( 0 ), mnFreeSlots(-1) { if( !mnTexture ) @@ -126,6 +129,21 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" ); } +GLuint ImplOpenGLTexture::AddStencil() +{ + assert( mnOptStencil == 0 ); + + glGenRenderbuffers( 1, &mnOptStencil ); + glBindRenderbuffer( GL_RENDERBUFFER, mnOptStencil ); + CHECK_GL_ERROR(); + VCL_GL_INFO( "Allocate stencil " << mnWidth << " x " << mnHeight ); + glRenderbufferStorage( GL_RENDERBUFFER, GL_STENCIL_INDEX, + mnWidth, mnHeight ); + CHECK_GL_ERROR(); + + return mnOptStencil; +} + ImplOpenGLTexture::~ImplOpenGLTexture() { VCL_GL_INFO( "~OpenGLTexture " << mnTexture ); @@ -136,9 +154,11 @@ ImplOpenGLTexture::~ImplOpenGLTexture() // Check we have been correctly un-bound from all framebuffers. ImplSVData* pSVData = ImplGetSVData(); rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext; - if (pContext.is()) + if( pContext.is() ) pContext->UnbindTextureFromFramebuffers( mnTexture ); + if( mnOptStencil != 0 ) + glDeleteRenderbuffers( 1, &mnOptStencil ); glDeleteTextures( 1, &mnTexture ); } } @@ -279,6 +299,24 @@ int OpenGLTexture::GetHeight() const return maRect.GetHeight(); } +bool OpenGLTexture::HasStencil() const +{ + return mpImpl && mpImpl->mnOptStencil != 0; +} + +GLuint OpenGLTexture::StencilId() const +{ + return mpImpl ? mpImpl->mnOptStencil : 0; +} + +GLuint OpenGLTexture::AddStencil() +{ + if (mpImpl) + return mpImpl->AddStencil(); + else + return 0; +} + void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const { VCL_GL_INFO( "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); @@ -349,6 +387,10 @@ void OpenGLTexture::Bind() glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture ); CHECK_GL_ERROR(); } + else + VCL_GL_INFO( "OpenGLTexture::Binding invalid texture" ); + + CHECK_GL_ERROR(); } void OpenGLTexture::Unbind() diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx index f57c82d307e1..666cdbfa393e 100644 --- a/vcl/opengl/win/gdiimpl.cxx +++ b/vcl/opengl/win/gdiimpl.cxx @@ -29,21 +29,10 @@ void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* rtl::Reference<OpenGLContext> WinOpenGLSalGraphicsImpl::CreateWinContext() { rtl::Reference<OpenGLContext> pContext = OpenGLContext::Create(); - pContext->requestSingleBufferedRendering(); pContext->init( mrParent.mhLocalDC, mrParent.mhWnd ); return pContext; } -bool WinOpenGLSalGraphicsImpl::UseContext( const rtl::Reference<OpenGLContext> &pContext ) -{ - if( !pContext.is() || !pContext->isInitialized() || IsForeignContext( pContext ) ) - return false; - if( IsOffscreen() ) - return true; - return pContext->getOpenGLWindow().hWnd == mrParent.mhWnd && - pContext->getOpenGLWindow().hDC == mrParent.mhLocalDC; -} - void WinOpenGLSalGraphicsImpl::Init() { if ( !IsOffscreen() && mpContext.is() && mpContext->isInitialized() && diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx index 2418bc62f60e..595ca45ca4b0 100644 --- a/vcl/opengl/x11/gdiimpl.cxx +++ b/vcl/opengl/x11/gdiimpl.cxx @@ -58,18 +58,6 @@ rtl::Reference<OpenGLContext> X11OpenGLSalGraphicsImpl::CreateWinContext() return pContext; } -bool X11OpenGLSalGraphicsImpl::UseContext( const rtl::Reference<OpenGLContext> &pContext ) -{ - X11WindowProvider *pProvider = dynamic_cast<X11WindowProvider*>(mrParent.m_pFrame); - - if( !pContext->isInitialized() || IsForeignContext( pContext ) ) - return false; - if( !pProvider ) - return pContext->getOpenGLWindow().win != None; - else - return pContext->getOpenGLWindow().win == pProvider->GetX11Window(); -} - void X11OpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) { OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrParent.GetImpl()); diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx index 26148a607cff..98be555ba5ad 100644 --- a/vcl/source/opengl/OpenGLContext.cxx +++ b/vcl/source/opengl/OpenGLContext.cxx @@ -18,6 +18,8 @@ #include <vcl/bmpacc.hxx> #include <vcl/graph.hxx> +#include <osl/thread.hxx> + #if defined(MACOSX) #include <premac.h> #include <AppKit/NSOpenGLView.h> @@ -1487,6 +1489,14 @@ void OpenGLContext::swapBuffers() #elif defined( UNX ) glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win); #endif + + static bool bSleep = getenv("SAL_GL_SLEEP_ON_SWAP"); + if (bSleep) + { + // half a second. + TimeValue aSleep( 0, 500*1000*1000 ); + osl::Thread::wait( aSleep ); + } } void OpenGLContext::sync() |