summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2015-11-13 12:00:59 +0000
committerMichael Meeks <michael.meeks@collabora.com>2015-12-10 12:01:31 +0000
commitb89920a6594c2d3271f4ab6877ec903d36594d2d (patch)
tree1f91edc5df4a2f7fe295891cb29992a4509b5571
parentGet Double-buffered context creation working on linux. (diff)
downloadcore-private/mmeeks/opengl-backbuffer2.tar.gz
core-private/mmeeks/opengl-backbuffer2.zip
tdf#93529 - move to a Mac-like double-buffered OpenGL model. private/mmeeks/opengl-backbuffer2
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 for debug. Change-Id: I6be08595b6c8deb7e6db0dbd81308b2c97d2b4ff
-rw-r--r--vcl/README.vars2
-rw-r--r--vcl/inc/opengl/texture.hxx8
-rw-r--r--vcl/inc/opengl/win/gdiimpl.hxx1
-rw-r--r--vcl/inc/opengl/x11/gdiimpl.hxx1
-rw-r--r--vcl/inc/openglgdiimpl.hxx44
-rw-r--r--vcl/opengl/framebuffer.cxx15
-rw-r--r--vcl/opengl/gdiimpl.cxx278
-rw-r--r--vcl/opengl/texture.cxx44
-rw-r--r--vcl/opengl/win/gdiimpl.cxx11
-rw-r--r--vcl/opengl/x11/gdiimpl.cxx12
-rw-r--r--vcl/source/opengl/OpenGLContext.cxx10
11 files changed, 353 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..b2969cc8088d 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,18 +75,27 @@ 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;
SalColor mnFillColor;
#ifdef DBG_UTIL
bool mProgramIsSolidColor;
+ sal_uInt32 mnDrawCount;
+ sal_uInt32 mnDrawCountAtFlush;
#endif
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..05994ddeaec7 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -37,19 +37,43 @@
#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)
+ , mnDrawCount(0)
+ , mnDrawCountAtFlush(0)
#endif
, 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,122 @@ 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();
+
+ glClearColor((float)rand()/RAND_MAX, (float)rand()/RAND_MAX,
+ (float)rand()/RAND_MAX, 1.0);
+ 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()