Kaydet (Commit) e614a1e8 authored tarafından Michael Meeks's avatar Michael Meeks

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
üst 382eafb5
...@@ -21,6 +21,8 @@ EMF_PLUS_DISABLE - use EMF rendering and ignore EMF+ specifics ...@@ -21,6 +21,8 @@ EMF_PLUS_DISABLE - use EMF rendering and ignore EMF+ specifics
OpenGL OpenGL
------ ------
SAL_FORCEGL - force enable 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_WITHOUT_WIDGET_CACHE - disable LRU caching of native widget texutres
SAL_DISABLE_GLYPH_CACHING - don't render glyphs through OpenGL textures 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 SAL_DISABLE_GL_WATCHDOG - don't start the thread that watches for broken GL drivers
...@@ -37,6 +37,8 @@ public: ...@@ -37,6 +37,8 @@ public:
int mnWidth; int mnWidth;
int mnHeight; int mnHeight;
GLenum mnFilter; GLenum mnFilter;
GLuint mnOptStencil;
bool mbHasOptStencil;
std::unique_ptr<std::vector<int>> mpSlotReferences; std::unique_ptr<std::vector<int>> mpSlotReferences;
int mnFreeSlots; int mnFreeSlots;
...@@ -76,7 +78,8 @@ public: ...@@ -76,7 +78,8 @@ public:
} }
bool InitializeSlots(int nSlotSize); bool InitializeSlots(int nSlotSize);
int FindFreeSlot(); int FindFreeSlot();
GLuint AddStencil();
}; };
class VCL_DLLPUBLIC OpenGLTexture class VCL_DLLPUBLIC OpenGLTexture
...@@ -110,6 +113,9 @@ public: ...@@ -110,6 +113,9 @@ public:
void Bind(); void Bind();
void Unbind(); void Unbind();
void Read( GLenum nFormat, GLenum nType, sal_uInt8* pData ); void Read( GLenum nFormat, GLenum nType, sal_uInt8* pData );
GLuint AddStencil();
bool HasStencil() const;
GLuint StencilId() const;
void SaveToFile(const OUString& rFileName); void SaveToFile(const OUString& rFileName);
......
...@@ -31,7 +31,6 @@ public: ...@@ -31,7 +31,6 @@ public:
protected: protected:
virtual rtl::Reference<OpenGLContext> CreateWinContext() override; virtual rtl::Reference<OpenGLContext> CreateWinContext() override;
virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) override;
bool RenderTextureCombo(TextureCombo& rCombo, int nX, int nY); bool RenderTextureCombo(TextureCombo& rCombo, int nX, int nY);
......
...@@ -29,7 +29,6 @@ public: ...@@ -29,7 +29,6 @@ public:
protected: protected:
virtual rtl::Reference<OpenGLContext> CreateWinContext() override; 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); bool RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo);
......
...@@ -52,12 +52,20 @@ struct TextureCombo ...@@ -52,12 +52,20 @@ struct TextureCombo
std::unique_ptr<OpenGLTexture> mpMask; std::unique_ptr<OpenGLTexture> mpMask;
}; };
class OpenGLFlushIdle;
class VCL_DLLPUBLIC OpenGLSalGraphicsImpl : public SalGraphicsImpl class VCL_DLLPUBLIC OpenGLSalGraphicsImpl : public SalGraphicsImpl
{ {
friend class OpenGLTests; friend class OpenGLTests;
protected: 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; rtl::Reference<OpenGLContext> mpContext;
SalGraphics& mrParent; SalGraphics& mrParent;
/// Pointer to the SalFrame or SalVirtualDevice /// Pointer to the SalFrame or SalVirtualDevice
SalGeometryProvider* mpProvider; SalGeometryProvider* mpProvider;
...@@ -67,12 +75,19 @@ protected: ...@@ -67,12 +75,19 @@ protected:
/// Is it someone else's context we shouldn't be fiddling with ? /// Is it someone else's context we shouldn't be fiddling with ?
static bool IsForeignContext(const rtl::Reference<OpenGLContext> &xContext); static bool IsForeignContext(const rtl::Reference<OpenGLContext> &xContext);
/// This idle handler is used to swap buffers after rendering.
OpenGLFlushIdle *mpFlush;
// clipping // clipping
vcl::Region maClipRegion; vcl::Region maClipRegion;
bool mbUseScissor; bool mbUseScissor;
bool mbUseStencil; 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; OpenGLTexture maOffscreenTex;
SalColor mnLineColor; SalColor mnLineColor;
...@@ -80,6 +95,8 @@ protected: ...@@ -80,6 +95,8 @@ protected:
#ifdef DBG_UTIL #ifdef DBG_UTIL
bool mProgramIsSolidColor; bool mProgramIsSolidColor;
#endif #endif
sal_uInt32 mnDrawCount;
sal_uInt32 mnDrawCountAtFlush;
SalColor mProgramSolidColor; SalColor mProgramSolidColor;
double mProgramSolidTransparency; double mProgramSolidTransparency;
...@@ -131,7 +148,10 @@ public: ...@@ -131,7 +148,10 @@ public:
// get the height of the device // get the height of the device
GLfloat GetHeight() const { return mpProvider ? mpProvider->GetHeight() : 1; } 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(); } bool IsOffscreen() const { return mpProvider == nullptr || mpProvider->IsOffScreen(); }
// operations to do before painting // operations to do before painting
...@@ -144,14 +164,18 @@ protected: ...@@ -144,14 +164,18 @@ protected:
bool AcquireContext(); bool AcquireContext();
bool ReleaseContext(); bool ReleaseContext();
// retrieve the default context for offscreen rendering /// retrieve the default context for offscreen rendering
static rtl::Reference<OpenGLContext> GetDefaultContext(); 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; virtual rtl::Reference<OpenGLContext> CreateWinContext() = 0;
// check whether the given context can be used by this instance /// check whether the given context can be used for off-screen rendering
virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) = 0; bool UseContext( const rtl::Reference<OpenGLContext> &pContext )
{
return pContext->isInitialized() && // not released by the OS etc.
IsForeignContext( pContext ); // a genuine VCL context.
}
public: public:
OpenGLSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider *pProvider); OpenGLSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider *pProvider);
...@@ -328,8 +352,12 @@ public: ...@@ -328,8 +352,12 @@ public:
virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override;
virtual OpenGLContext *beginPaint() override; /// queue an idle flush of contents of the back-buffer to the screen
private: void flush();
public:
/// do flush of contents of the back-buffer to the screen & swap.
void doFlush();
}; };
#endif #endif
......
...@@ -72,6 +72,16 @@ void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture ) ...@@ -72,6 +72,16 @@ void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture )
mnHeight = rTexture.GetHeight(); mnHeight = rTexture.GetHeight();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mnAttachedTexture, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mnAttachedTexture, 0);
CHECK_GL_ERROR(); 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); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
CHECK_GL_ERROR(); CHECK_GL_ERROR();
if (status != GL_FRAMEBUFFER_COMPLETE) if (status != GL_FRAMEBUFFER_COMPLETE)
...@@ -87,6 +97,11 @@ void OpenGLFramebuffer::DetachTexture() ...@@ -87,6 +97,11 @@ void OpenGLFramebuffer::DetachTexture()
mnAttachedTexture = 0; mnAttachedTexture = 0;
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 );
CHECK_GL_ERROR(); 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();
} }
} }
......
...@@ -37,20 +37,44 @@ ...@@ -37,20 +37,44 @@
#include <vector> #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) OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider *pProvider)
: mpContext(nullptr) : mpContext(nullptr)
, mrParent(rParent) , mrParent(rParent)
, mpProvider(pProvider) , mpProvider(pProvider)
, mpFramebuffer(nullptr) , mpFramebuffer(nullptr)
, mpProgram(nullptr) , mpProgram(nullptr)
, mpFlush(new OpenGLFlushIdle(this))
, mbUseScissor(false) , mbUseScissor(false)
, mbUseStencil(false) , mbUseStencil(false)
, mbOffscreen(false)
, mnLineColor(SALCOLOR_NONE) , mnLineColor(SALCOLOR_NONE)
, mnFillColor(SALCOLOR_NONE) , mnFillColor(SALCOLOR_NONE)
#ifdef DBG_UTIL #ifdef DBG_UTIL
, mProgramIsSolidColor(false) , mProgramIsSolidColor(false)
#endif #endif
, mnDrawCount(0)
, mnDrawCountAtFlush(0)
, mProgramSolidColor(SALCOLOR_NONE) , mProgramSolidColor(SALCOLOR_NONE)
, mProgramSolidTransparency(0.0) , mProgramSolidTransparency(0.0)
{ {
...@@ -58,6 +82,11 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr ...@@ -58,6 +82,11 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr
OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl() OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl()
{ {
if( !IsOffscreen() && mnDrawCountAtFlush != mnDrawCount )
VCL_GL_INFO( "Destroying un-flushed on-screen graphics" );
delete mpFlush;
ReleaseContext(); ReleaseContext();
} }
...@@ -79,10 +108,9 @@ bool OpenGLSalGraphicsImpl::AcquireContext( ) ...@@ -79,10 +108,9 @@ bool OpenGLSalGraphicsImpl::AcquireContext( )
// We always prefer to bind our VirtualDevice / offscreen graphics // We always prefer to bind our VirtualDevice / offscreen graphics
// to the current OpenGLContext - to avoid switching contexts. // 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() ) if( mpContext.is() )
...@@ -97,15 +125,17 @@ bool OpenGLSalGraphicsImpl::AcquireContext( ) ...@@ -97,15 +125,17 @@ bool OpenGLSalGraphicsImpl::AcquireContext( )
while( pContext ) while( pContext )
{ {
// check if this context can be used by this SalGraphicsImpl instance // check if this context can be used by this SalGraphicsImpl instance
if( UseContext( pContext ) ) if( UseContext( pContext ) )
break; break;
pContext = pContext->mpPrevContext; pContext = pContext->mpPrevContext;
} }
if( pContext ) if( mpContext.is() )
mpContext = pContext; mpContext = pContext;
else if( mpWindowContext.is() )
mpContext = mpWindowContext;
else else
mpContext = mbOffscreen ? GetDefaultContext() : CreateWinContext(); mpContext = GetDefaultContext();
return mpContext.is(); return mpContext.is();
} }
...@@ -119,19 +149,20 @@ bool OpenGLSalGraphicsImpl::ReleaseContext() ...@@ -119,19 +149,20 @@ bool OpenGLSalGraphicsImpl::ReleaseContext()
void OpenGLSalGraphicsImpl::Init() 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 // check if we can simply re-use the same context
if( mpContext.is() ) if( mpContext.is() )
{ {
if( !mpContext->isInitialized() || if( !UseContext( mpContext ) )
!UseContext( mpContext ) )
ReleaseContext(); ReleaseContext();
} }
// reset the offscreen texture // Always create the offscreen texture
if( !mbOffscreen || if( maOffscreenTex.GetWidth() != GetWidth() ||
maOffscreenTex.GetWidth() != GetWidth() ||
maOffscreenTex.GetHeight() != GetHeight() ) maOffscreenTex.GetHeight() != GetHeight() )
{ {
if( maOffscreenTex && // don't work to release empty textures if( maOffscreenTex && // don't work to release empty textures
...@@ -141,6 +172,14 @@ void OpenGLSalGraphicsImpl::Init() ...@@ -141,6 +172,14 @@ void OpenGLSalGraphicsImpl::Init()
mpContext->ReleaseFramebuffer( maOffscreenTex ); mpContext->ReleaseFramebuffer( maOffscreenTex );
} }
maOffscreenTex = OpenGLTexture(); 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() ...@@ -155,12 +194,15 @@ void OpenGLSalGraphicsImpl::DeInit()
// get a shiny new context in AcquireContext:: next PreDraw. // get a shiny new context in AcquireContext:: next PreDraw.
if( mpContext.is() && !IsOffscreen() ) if( mpContext.is() && !IsOffscreen() )
mpContext->reset(); mpContext->reset();
mpContext.clear();
} }
void OpenGLSalGraphicsImpl::PreDraw() void OpenGLSalGraphicsImpl::PreDraw()
{ {
OpenGLZone::enter(); OpenGLZone::enter();
mnDrawCount++;
if( !AcquireContext() ) if( !AcquireContext() )
{ {
SAL_WARN( "vcl.opengl", "Couldn't acquire context" ); SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
...@@ -170,10 +212,7 @@ void OpenGLSalGraphicsImpl::PreDraw() ...@@ -170,10 +212,7 @@ void OpenGLSalGraphicsImpl::PreDraw()
mpContext->makeCurrent(); mpContext->makeCurrent();
CHECK_GL_ERROR(); CHECK_GL_ERROR();
if( !mbOffscreen ) CheckOffscreenTexture();
mpContext->AcquireDefaultFramebuffer();
else
CheckOffscreenTexture();
CHECK_GL_ERROR(); CHECK_GL_ERROR();
glViewport( 0, 0, GetWidth(), GetHeight() ); glViewport( 0, 0, GetWidth(), GetHeight() );
...@@ -185,15 +224,13 @@ void OpenGLSalGraphicsImpl::PreDraw() ...@@ -185,15 +224,13 @@ void OpenGLSalGraphicsImpl::PreDraw()
void OpenGLSalGraphicsImpl::PostDraw() void OpenGLSalGraphicsImpl::PostDraw()
{ {
if( !mbOffscreen && mpContext->mnPainting == 0 )
glFlush();
if( mbUseScissor ) if( mbUseScissor )
{ {
glDisable( GL_SCISSOR_TEST ); glDisable( GL_SCISSOR_TEST );
CHECK_GL_ERROR(); CHECK_GL_ERROR();
} }
if( mbUseStencil ) if( mbUseStencil )
{ {
glDisable( GL_STENCIL_TEST ); glDisable( GL_STENCIL_TEST );
CHECK_GL_ERROR(); CHECK_GL_ERROR();
} }
...@@ -205,6 +242,18 @@ void OpenGLSalGraphicsImpl::PostDraw() ...@@ -205,6 +242,18 @@ void OpenGLSalGraphicsImpl::PostDraw()
mProgramIsSolidColor = false; mProgramIsSolidColor = false;
#endif #endif
} }
assert (maOffscreenTex);
if( IsOffscreen() )
assert( !mpWindowContext.is() );
else
assert( mpWindowContext.is() );
// Always queue the flush.
if( !IsOffscreen() )
flush();
OpenGLZone::leave(); OpenGLZone::leave();
} }
...@@ -216,8 +265,9 @@ void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset) ...@@ -216,8 +265,9 @@ void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset)
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.is() && mpContext->isInitialized() ) if( mpContext.is() && mpContext->isInitialized() )
{ {
VCL_GL_INFO( "freeResources" );
mpContext->makeCurrent(); mpContext->makeCurrent();
mpContext->ReleaseFramebuffer( maOffscreenTex ); mpContext->ReleaseFramebuffer( maOffscreenTex );
} }
...@@ -227,6 +277,20 @@ void OpenGLSalGraphicsImpl::freeResources() ...@@ -227,6 +277,20 @@ void OpenGLSalGraphicsImpl::freeResources()
void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask ) void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask )
{ {
glEnable( GL_STENCIL_TEST ); 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(); CHECK_GL_ERROR();
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
CHECK_GL_ERROR(); CHECK_GL_ERROR();
...@@ -261,7 +325,7 @@ void OpenGLSalGraphicsImpl::ImplInitClipRegion() ...@@ -261,7 +325,7 @@ void OpenGLSalGraphicsImpl::ImplInitClipRegion()
if( maClipRegion != mpContext->maClipRegion ) if( maClipRegion != mpContext->maClipRegion )
{ {
mpContext->maClipRegion = maClipRegion; mpContext->maClipRegion = maClipRegion;
if( maClipRegion.IsRectangle() ) if( mbUseScissor )
{ {
Rectangle aRect( maClipRegion.GetBoundRect() ); Rectangle aRect( maClipRegion.GetBoundRect() );
glScissor( aRect.Left(), GetHeight() - aRect.Bottom() - 1, aRect.GetWidth() + 1, aRect.GetHeight() + 1 ); glScissor( aRect.Left(), GetHeight() - aRect.Bottom() - 1, aRect.GetWidth() + 1, aRect.GetHeight() + 1 );
...@@ -382,8 +446,29 @@ void OpenGLSalGraphicsImpl::SetROPFillColor( SalROPColor /*nROPColor*/ ) ...@@ -382,8 +446,29 @@ void OpenGLSalGraphicsImpl::SetROPFillColor( SalROPColor /*nROPColor*/ )
bool OpenGLSalGraphicsImpl::CheckOffscreenTexture() 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 ) if( !maOffscreenTex )
{
VCL_GL_INFO( "create texture of size "
<< GetWidth() << " x " << GetHeight() );
maOffscreenTex = OpenGLTexture( GetWidth(), GetHeight() ); maOffscreenTex = OpenGLTexture( GetWidth(), GetHeight() );
bClearTexture = true;
}
if( !maOffscreenTex.IsUnique() ) if( !maOffscreenTex.IsUnique() )
{ {
...@@ -400,8 +485,23 @@ bool OpenGLSalGraphicsImpl::CheckOffscreenTexture() ...@@ -400,8 +485,23 @@ bool OpenGLSalGraphicsImpl::CheckOffscreenTexture()
else else
{ {
mpFramebuffer = mpContext->AcquireFramebuffer( maOffscreenTex ); 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(); CHECK_GL_ERROR();
return true; return true;
} }
...@@ -1541,17 +1641,9 @@ void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGrap ...@@ -1541,17 +1641,9 @@ void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGrap
return; return;
} }
if( rImpl.mbOffscreen ) PreDraw();
{ DrawTexture( rImpl.maOffscreenTex, rPosAry );
PreDraw(); PostDraw();
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
} }
void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap )
...@@ -1878,12 +1970,126 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, ...@@ -1878,12 +1970,126 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
return true; return true;
} }
OpenGLContext *OpenGLSalGraphicsImpl::beginPaint() void OpenGLSalGraphicsImpl::flush()
{ {
if( mbOffscreen || !AcquireContext() ) if( IsOffscreen() )
return nullptr; 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 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) bool OpenGLSalGraphicsImpl::IsForeignContext(const rtl::Reference<OpenGLContext> &xContext)
......
...@@ -35,6 +35,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) ...@@ -35,6 +35,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate )
mnWidth( nWidth ), mnWidth( nWidth ),
mnHeight( nHeight ), mnHeight( nHeight ),
mnFilter( GL_NEAREST ), mnFilter( GL_NEAREST ),
mnOptStencil( 0 ),
mnFreeSlots(-1) mnFreeSlots(-1)
{ {
glGenTextures( 1, &mnTexture ); glGenTextures( 1, &mnTexture );
...@@ -67,6 +68,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) ...@@ -67,6 +68,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight )
mnWidth( nWidth ), mnWidth( nWidth ),
mnHeight( nHeight ), mnHeight( nHeight ),
mnFilter( GL_NEAREST ), mnFilter( GL_NEAREST ),
mnOptStencil( 0 ),
mnFreeSlots(-1) mnFreeSlots(-1)
{ {
// FIXME We need the window height here // FIXME We need the window height here
...@@ -99,6 +101,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int ...@@ -99,6 +101,7 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int
mnWidth( nWidth ), mnWidth( nWidth ),
mnHeight( nHeight ), mnHeight( nHeight ),
mnFilter( GL_NEAREST ), mnFilter( GL_NEAREST ),
mnOptStencil( 0 ),
mnFreeSlots(-1) mnFreeSlots(-1)
{ {
if( !mnTexture ) if( !mnTexture )
...@@ -126,6 +129,21 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int ...@@ -126,6 +129,21 @@ ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int
VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" ); 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() ImplOpenGLTexture::~ImplOpenGLTexture()
{ {
VCL_GL_INFO( "~OpenGLTexture " << mnTexture ); VCL_GL_INFO( "~OpenGLTexture " << mnTexture );
...@@ -136,9 +154,11 @@ ImplOpenGLTexture::~ImplOpenGLTexture() ...@@ -136,9 +154,11 @@ ImplOpenGLTexture::~ImplOpenGLTexture()
// Check we have been correctly un-bound from all framebuffers. // Check we have been correctly un-bound from all framebuffers.
ImplSVData* pSVData = ImplGetSVData(); ImplSVData* pSVData = ImplGetSVData();
rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext; rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext;
if (pContext.is()) if( pContext.is() )
pContext->UnbindTextureFromFramebuffers( mnTexture ); pContext->UnbindTextureFromFramebuffers( mnTexture );
if( mnOptStencil != 0 )
glDeleteRenderbuffers( 1, &mnOptStencil );
glDeleteTextures( 1, &mnTexture ); glDeleteTextures( 1, &mnTexture );
} }
} }
...@@ -279,6 +299,24 @@ int OpenGLTexture::GetHeight() const ...@@ -279,6 +299,24 @@ int OpenGLTexture::GetHeight() const
return maRect.GetHeight(); 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 void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const
{ {
VCL_GL_INFO( "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); VCL_GL_INFO( "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
...@@ -349,6 +387,10 @@ void OpenGLTexture::Bind() ...@@ -349,6 +387,10 @@ void OpenGLTexture::Bind()
glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture ); glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );
CHECK_GL_ERROR(); CHECK_GL_ERROR();
} }
else
VCL_GL_INFO( "OpenGLTexture::Binding invalid texture" );
CHECK_GL_ERROR();
} }
void OpenGLTexture::Unbind() void OpenGLTexture::Unbind()
......
...@@ -29,21 +29,10 @@ void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* ...@@ -29,21 +29,10 @@ void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics*
rtl::Reference<OpenGLContext> WinOpenGLSalGraphicsImpl::CreateWinContext() rtl::Reference<OpenGLContext> WinOpenGLSalGraphicsImpl::CreateWinContext()
{ {
rtl::Reference<OpenGLContext> pContext = OpenGLContext::Create(); rtl::Reference<OpenGLContext> pContext = OpenGLContext::Create();
pContext->requestSingleBufferedRendering();
pContext->init( mrParent.mhLocalDC, mrParent.mhWnd ); pContext->init( mrParent.mhLocalDC, mrParent.mhWnd );
return pContext; 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() void WinOpenGLSalGraphicsImpl::Init()
{ {
if ( !IsOffscreen() && mpContext.is() && mpContext->isInitialized() && if ( !IsOffscreen() && mpContext.is() && mpContext->isInitialized() &&
......
...@@ -58,18 +58,6 @@ rtl::Reference<OpenGLContext> X11OpenGLSalGraphicsImpl::CreateWinContext() ...@@ -58,18 +58,6 @@ rtl::Reference<OpenGLContext> X11OpenGLSalGraphicsImpl::CreateWinContext()
return pContext; 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 ) void X11OpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics )
{ {
OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrParent.GetImpl()); OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrParent.GetImpl());
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <vcl/bmpacc.hxx> #include <vcl/bmpacc.hxx>
#include <vcl/graph.hxx> #include <vcl/graph.hxx>
#include <osl/thread.hxx>
#if defined(MACOSX) #if defined(MACOSX)
#include <premac.h> #include <premac.h>
#include "OpenGLWrapper.hxx" #include "OpenGLWrapper.hxx"
...@@ -1486,6 +1488,14 @@ void OpenGLContext::swapBuffers() ...@@ -1486,6 +1488,14 @@ void OpenGLContext::swapBuffers()
#elif defined( UNX ) #elif defined( UNX )
glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win); glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win);
#endif #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() void OpenGLContext::sync()
......
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