summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2017-09-10 21:23:24 +0100
committerCaolán McNamara <caolanm@redhat.com>2017-09-11 11:45:06 +0200
commit22e39ae69825e0b83f03b343f22faf065602a72a (patch)
tree65b86499e17173b991ff7436e9b8babff50053b4
parentlong->sal_Int32 in various Get/SetVersion (diff)
downloadcore-22e39ae69825e0b83f03b343f22faf065602a72a.tar.gz
core-22e39ae69825e0b83f03b343f22faf065602a72a.zip
gtk3: flicker-free opengl transitions
leave the GtkGLArea opengl context alone except for the final render into it, create a new context for the slide transitions to play with set up a pair of framebuffers, a scratch one to let the transitions render into, the other to take a snapshot when the transition is finished with it and then tell GtkGLArea we're ready to render it and when the callback comes around copy the snapshot into it. Change-Id: I3515614baf7eea0ff53c46edbaf9cf66f926eef2 Reviewed-on: https://gerrit.libreoffice.org/42144 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx159
1 files changed, 140 insertions, 19 deletions
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 72b71c9d7519..3cab164d80cf 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -910,6 +910,14 @@ class GtkOpenGLContext : public OpenGLContext
GLWindow m_aGLWin;
#if GTK_CHECK_VERSION(3,16,0)
GtkWidget *m_pGLArea;
+ GdkGLContext *m_pContext;
+ guint m_nAreaFrameBuffer;
+ guint m_nFrameBuffer;
+ guint m_nRenderBuffer;
+ guint m_nDepthBuffer;
+ guint m_nFrameScratchBuffer;
+ guint m_nRenderScratchBuffer;
+ guint m_nDepthScratchBuffer;
#endif
public:
@@ -917,6 +925,14 @@ public:
: OpenGLContext()
#if GTK_CHECK_VERSION(3,16,0)
, m_pGLArea(nullptr)
+ , m_pContext(nullptr)
+ , m_nAreaFrameBuffer(0)
+ , m_nFrameBuffer(0)
+ , m_nRenderBuffer(0)
+ , m_nDepthBuffer(0)
+ , m_nFrameScratchBuffer(0)
+ , m_nRenderScratchBuffer(0)
+ , m_nDepthScratchBuffer(0)
#endif
{
}
@@ -947,8 +963,73 @@ private:
GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(context);
pThis->m_pGLArea = nullptr;
}
+
+ static gboolean signalRender(GtkGLArea*, GdkGLContext*, gpointer window)
+ {
+ GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(window);
+
+ int scale = gtk_widget_get_scale_factor(pThis->m_pGLArea);
+ int width = pThis->m_aGLWin.Width * scale;
+ int height = pThis->m_aGLWin.Height * scale;
+
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, pThis->m_nAreaFrameBuffer);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
+ GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+
+ gdk_gl_context_make_current(pThis->m_pContext);
+ return true;
+ }
+
#endif
+ virtual void adjustToNewSize() override
+ {
+#if GTK_CHECK_VERSION(3,16,0)
+ if (m_pGLArea)
+ {
+ int scale = gtk_widget_get_scale_factor(m_pGLArea);
+ int width = m_aGLWin.Width * scale;
+ int height = m_aGLWin.Height * scale;
+
+ gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderBuffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, width, height);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthBuffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nAreaFrameBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, m_nRenderBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, m_nDepthBuffer);
+
+ gdk_gl_context_make_current(m_pContext);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderBuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthBuffer);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, m_nRenderBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, m_nDepthBuffer);
+ glViewport(0, 0, width, height);
+
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderScratchBuffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, width, height);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthScratchBuffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, m_nRenderScratchBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, m_nDepthScratchBuffer);
+ glViewport(0, 0, width, height);
+ }
+#endif
+ }
+
virtual bool ImplInit() override
{
#if GTK_CHECK_VERSION(3,16,0)
@@ -956,14 +1037,28 @@ private:
GtkWidget *pParent = static_cast<GtkWidget*>(pEnvData->pWidget);
m_pGLArea = gtk_gl_area_new();
g_signal_connect(G_OBJECT(m_pGLArea), "destroy", G_CALLBACK(signalDestroy), this);
+ g_signal_connect(G_OBJECT(m_pGLArea), "render", G_CALLBACK(signalRender), this);
gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA(m_pGLArea), true);
gtk_gl_area_set_auto_render(GTK_GL_AREA(m_pGLArea), false);
gtk_widget_set_hexpand(m_pGLArea, true);
gtk_widget_set_vexpand(m_pGLArea, true);
gtk_container_add(GTK_CONTAINER(pParent), m_pGLArea);
gtk_widget_show_all(pParent);
+
gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea));
+ glGenFramebuffersEXT(1, &m_nAreaFrameBuffer);
+
+ GdkWindow *pWindow = gtk_widget_get_window(pParent);
+ m_pContext = gdk_window_create_gl_context(pWindow, nullptr);
+ gdk_gl_context_realize(m_pContext, nullptr);
+ gdk_gl_context_make_current(m_pContext);
+ glGenFramebuffersEXT(1, &m_nFrameBuffer);
+ glGenRenderbuffersEXT(1, &m_nRenderBuffer);
+ glGenRenderbuffersEXT(1, &m_nDepthBuffer);
+ glGenFramebuffersEXT(1, &m_nFrameScratchBuffer);
+ glGenRenderbuffersEXT(1, &m_nRenderScratchBuffer);
+ glGenRenderbuffersEXT(1, &m_nDepthScratchBuffer);
#endif
bool bRet = InitGL();
InitGLDebugging();
@@ -974,23 +1069,12 @@ private:
virtual void restoreDefaultFramebuffer() override
{
OpenGLContext::restoreDefaultFramebuffer();
- gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea));
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, m_nRenderScratchBuffer);
}
#endif
- virtual void adjustToNewSize() override
- {
-#if GTK_CHECK_VERSION(3,16,0)
- if (m_pGLArea)
- {
- int scale = gtk_widget_get_scale_factor(m_pGLArea);
- int width = m_aGLWin.Width * scale;
- int height = m_aGLWin.Height * scale;
- glViewport(0, 0, width, height);
- }
-#endif
- }
-
virtual void makeCurrent() override
{
if (isCurrent())
@@ -1000,7 +1084,22 @@ private:
#if GTK_CHECK_VERSION(3,16,0)
if (m_pGLArea)
- gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
+ {
+ int scale = gtk_widget_get_scale_factor(m_pGLArea);
+ int width = m_aGLWin.Width * scale;
+ int height = m_aGLWin.Height * scale;
+
+ gdk_gl_context_make_current(m_pContext);
+
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderScratchBuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthScratchBuffer);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, m_nRenderScratchBuffer);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, m_nDepthScratchBuffer);
+ glViewport(0, 0, width, height);
+ }
#endif
registerAsCurrent();
@@ -1016,7 +1115,7 @@ private:
virtual bool isCurrent() override
{
#if GTK_CHECK_VERSION(3,16,0)
- return m_pGLArea && gdk_gl_context_get_current() == gtk_gl_area_get_context(GTK_GL_AREA(m_pGLArea));
+ return m_pGLArea && gdk_gl_context_get_current() == m_pContext;
#else
return false;
#endif
@@ -1024,9 +1123,6 @@ private:
virtual void sync() override
{
-#if GTK_CHECK_VERSION(3,16,0)
- gtk_gl_area_queue_render(GTK_GL_AREA(m_pGLArea));
-#endif
}
virtual void resetCurrent() override
@@ -1040,10 +1136,35 @@ private:
virtual void swapBuffers() override
{
#if GTK_CHECK_VERSION(3,16,0)
+ int scale = gtk_widget_get_scale_factor(m_pGLArea);
+ int width = m_aGLWin.Width * scale;
+ int height = m_aGLWin.Height * scale;
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_nFrameBuffer);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, m_nFrameScratchBuffer);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
+ GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_nFrameScratchBuffer);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
gtk_gl_area_queue_render(GTK_GL_AREA(m_pGLArea));
#endif
BuffersSwapped();
}
+#if GTK_CHECK_VERSION(3,16,0)
+ virtual ~GtkOpenGLContext() override
+ {
+ if (m_pContext)
+ {
+ g_clear_object(&m_pContext);
+ }
+ }
+#endif
};
OpenGLContext* GtkInstance::CreateOpenGLContext()