[GTK] Use XDamage to simplify RedirectedXCompositeWindow
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Sep 2012 15:53:42 +0000 (15:53 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Sep 2012 15:53:42 +0000 (15:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=97267

Reviewed by Alejandro G. Castro.

Use XDamage to queue redraws of the widget when redirecting accelerated compositing
to an offscreen window. This allows removing a finicky timer-based approach, improves
performance, and allows simplifying things greatly.

.:

* configure.ac: Add support for finding XDamage via pkg-config.

Source/WebCore:

No new tests. This is covered by existing tests.

* GNUmakefile.am: Add the XDamage CFLAGS in the appropriate place.
* platform/gtk/RedirectedXCompositeWindow.cpp:
(WebCore::getWindowHashMap): Added.
(WebCore::filterXDamageEvent): Added.
(WebCore::supportsXDamageAndXComposite): Added.
(WebCore::RedirectedXCompositeWindow::create): Fail to create the window if
the XServer doesn't support XDamage and XComposite.
(WebCore::RedirectedXCompositeWindow::RedirectedXCompositeWindow): Add XDamage support and
remove the m_usable size distinction. Add the window the window HashMap now.
(WebCore::RedirectedXCompositeWindow::~RedirectedXCompositeWindow): Remove the window
from the window HashMap.
(WebCore::RedirectedXCompositeWindow::resize): Now just immediately update the size.
(WebCore::RedirectedXCompositeWindow::callDamageNotifyCallback): Added.
* platform/gtk/RedirectedXCompositeWindow.h:
(WebCore::RedirectedXCompositeWindow::setDamageNotifyCallback): Added.

Source/WebKit/gtk:

* GNUmakefile.am: Add the XDamage CFLAGS and LIBS.
* WebCoreSupport/AcceleratedCompositingContext.h:
(AcceleratedCompositingContext): Change the signature of compositeLayersToContext
to accept an enum that explains the composite purpose.
* WebCoreSupport/AcceleratedCompositingContextGL.cpp:
(WebKit::redirectedWindowDamagedCallback): Added.
(WebKit::AcceleratedCompositingContext::initialize): Handle the situation where
the RedirectedXCompositeWindow returns a null pointer.
(WebKit::AcceleratedCompositingContext::enabled): Ditto.
(WebKit::AcceleratedCompositingContext::renderLayersToWindow): Remove the code handling
the usable size of the RedirectedXCompositeWindow. The usable size is now always equal
to the size.
(WebKit::AcceleratedCompositingContext::compositeLayersToContext): When drawing for a
resize, first clear the entire context. Remove the double swap-buffer, as it's no
longer necessary.
(WebKit::AcceleratedCompositingContext::setRootCompositingLayer): Handle the case that
the redirected window is null.
(WebKit::AcceleratedCompositingContext::resizeRootLayer): Instead of doing another
immediate layer flush, just recomposite the current layer state and schedule a new
flush. This should make resizing faster.
(WebKit::AcceleratedCompositingContext::flushAndRenderLayers): We no longer need to
queue a redraw, unless we want to force one.

Source/WebKit2:

* GNUmakefile.am: Add the XDamage CFLAGS and LIBS to the appropriate places.
* UIProcess/API/gtk/WebKitWebViewBase.cpp:
(_WebKitWebViewBasePrivate): Remove readyToRenderAcceleratedCompositingResults as
it's no longer necessary.
(webkit_web_view_base_init): Handle the situation where the RedirectedXCompositeWindow
is null.
(webkitWebViewRenderAcceleratedCompositingResults): Ditto.
(resizeWebKitWebViewBaseFromAllocation): Ditto.
(webkitWebViewBaseCreateWebPage): Ditto.
(redirectedWindowDamagedCallback): Added.
* UIProcess/WebPageProxy.h: Remove InvalidateWidget message.
* UIProcess/WebPageProxy.messages.in: Ditto.
* UIProcess/gtk/WebPageProxyGtk.cpp: Ditto.
* WebProcess/WebPage/WebPage.h: Ditto.
* WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp:
(WebKit::LayerTreeHostGtk::compositeLayersToContext): No longer need to
trigger the invalidateWindow message.
* WebProcess/WebPage/gtk/WebPageGtk.cpp: Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@129651 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
ChangeLog
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.am
Source/WebCore/platform/gtk/RedirectedXCompositeWindow.cpp
Source/WebCore/platform/gtk/RedirectedXCompositeWindow.h
Source/WebKit/gtk/ChangeLog
Source/WebKit/gtk/GNUmakefile.am
Source/WebKit/gtk/WebCoreSupport/AcceleratedCompositingContext.h
Source/WebKit/gtk/WebCoreSupport/AcceleratedCompositingContextGL.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/GNUmakefile.am
Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/UIProcess/gtk/WebPageProxyGtk.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp
Source/WebKit2/WebProcess/WebPage/gtk/WebPageGtk.cpp
configure.ac

index bc1ba0d..fc35c79 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2012-09-26  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Use XDamage to simplify RedirectedXCompositeWindow
+        https://bugs.webkit.org/show_bug.cgi?id=97267
+
+        Reviewed by Alejandro G. Castro.
+
+        Use XDamage to queue redraws of the widget when redirecting accelerated compositing
+        to an offscreen window. This allows removing a finicky timer-based approach, improves
+        performance, and allows simplifying things greatly.
+
+        * configure.ac: Add support for finding XDamage via pkg-config.
+
 2012-09-26  Simon Hausmann  <simon.hausmann@digia.com>
 
         [Qt] Remove Qt Quick 1 support
index c8478b3..5016d9d 100644 (file)
@@ -1,3 +1,32 @@
+2012-09-26  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Use XDamage to simplify RedirectedXCompositeWindow
+        https://bugs.webkit.org/show_bug.cgi?id=97267
+
+        Reviewed by Alejandro G. Castro.
+
+        Use XDamage to queue redraws of the widget when redirecting accelerated compositing
+        to an offscreen window. This allows removing a finicky timer-based approach, improves
+        performance, and allows simplifying things greatly.
+
+        No new tests. This is covered by existing tests.
+
+        * GNUmakefile.am: Add the XDamage CFLAGS in the appropriate place.
+        * platform/gtk/RedirectedXCompositeWindow.cpp:
+        (WebCore::getWindowHashMap): Added.
+        (WebCore::filterXDamageEvent): Added.
+        (WebCore::supportsXDamageAndXComposite): Added.
+        (WebCore::RedirectedXCompositeWindow::create): Fail to create the window if
+        the XServer doesn't support XDamage and XComposite.
+        (WebCore::RedirectedXCompositeWindow::RedirectedXCompositeWindow): Add XDamage support and
+        remove the m_usable size distinction. Add the window the window HashMap now.
+        (WebCore::RedirectedXCompositeWindow::~RedirectedXCompositeWindow): Remove the window
+        from the window HashMap.
+        (WebCore::RedirectedXCompositeWindow::resize): Now just immediately update the size.
+        (WebCore::RedirectedXCompositeWindow::callDamageNotifyCallback): Added.
+        * platform/gtk/RedirectedXCompositeWindow.h:
+        (WebCore::RedirectedXCompositeWindow::setDamageNotifyCallback): Added.
+
 2012-09-26  Ilya Tikhonovsky  <loislo@chromium.org>
 
         Web Inspector: NMI: replace manual JS external resources counting with MemoryInstrumentation
index f05669d..66c9f47 100644 (file)
@@ -697,6 +697,7 @@ libWebCoreGtk_la_CPPFLAGS = \
        $(SQLITE3_CFLAGS) \
        $(UNICODE_CFLAGS) \
        $(XCOMPOSITE_CFLAGS) \
+       $(XDAMAGE_CFLAGS) \
        $(XRENDER_CFLAGS) \
        $(XT_CFLAGS)
 
index 0d7bdba..5e69b44 100644 (file)
 #include "GLContextGLX.h"
 #include <GL/glx.h>
 #include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xdamage.h>
 #include <cairo-xlib.h>
 #include <gdk/gdkx.h>
 #include <glib.h>
 #include <gtk/gtk.h>
+#include <wtf/HashMap.h>
 
 namespace WebCore {
 
+typedef HashMap<Window, RedirectedXCompositeWindow*> WindowHashMap;
+static WindowHashMap& getWindowHashMap()
+{
+    DEFINE_STATIC_LOCAL(WindowHashMap, windowHashMap, ());
+    return windowHashMap;
+}
+
+static int gDamageEventBase;
+static GdkFilterReturn filterXDamageEvent(GdkXEvent* gdkXEvent, GdkEvent* event, void*)
+{
+    XEvent* xEvent = static_cast<XEvent*>(gdkXEvent);
+    if (xEvent->type != gDamageEventBase + XDamageNotify)
+        return GDK_FILTER_CONTINUE;
+
+    XDamageNotifyEvent* damageEvent = reinterpret_cast<XDamageNotifyEvent*>(xEvent);
+    WindowHashMap& windowHashMap = getWindowHashMap();
+    WindowHashMap::iterator i = windowHashMap.find(damageEvent->drawable);
+    if (i == windowHashMap.end())
+        return GDK_FILTER_CONTINUE;
+
+    i->second->callDamageNotifyCallback();
+    XDamageSubtract(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), damageEvent->damage, None, None);
+    return GDK_FILTER_REMOVE;
+}
+
+static bool supportsXDamageAndXComposite()
+{
+    static bool initialized = false;
+    static bool hasExtensions = false;
+
+    if (initialized)
+        return hasExtensions;
+
+    initialized = true;
+
+    int errorBase;
+    Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    if (!XDamageQueryExtension(display, &gDamageEventBase, &errorBase))
+        return false;
+
+    int eventBase;
+    if (!XCompositeQueryExtension(display, &eventBase, &errorBase))
+        return false;
+
+    // We need to support XComposite version 0.2.
+    int major, minor;
+    XCompositeQueryVersion(display, &major, &minor);
+    if (major < 0 || (!major && minor < 2))
+        return false;
+
+    hasExtensions = true;
+    return true;
+}
+
 PassOwnPtr<RedirectedXCompositeWindow> RedirectedXCompositeWindow::create(const IntSize& size)
 {
-    return adoptPtr(new RedirectedXCompositeWindow(size));
+    return supportsXDamageAndXComposite() ? adoptPtr(new RedirectedXCompositeWindow(size)) : nullptr;
 }
 
 RedirectedXCompositeWindow::RedirectedXCompositeWindow(const IntSize& size)
-    : m_usableSize(size)
+    : m_size(size)
     , m_window(0)
     , m_parentWindow(0)
     , m_pixmap(0)
     , m_surface(0)
     , m_pendingResizeSourceId(0)
     , m_needsNewPixmapAfterResize(false)
+    , m_damage(0)
+    , m_damageNotifyCallback(0)
+    , m_damageNotifyData(0)
 {
-    Display* display = GLContextGLX::sharedDisplay();
+    Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
 
     // This is based on code from Chromium: src/content/common/gpu/image_transport_surface_linux.cc
     XSetWindowAttributes windowAttributes;
@@ -81,6 +140,10 @@ RedirectedXCompositeWindow::RedirectedXCompositeWindow(const IntSize& size)
                              &windowAttributes);
     XMapWindow(display, m_window);
 
+    if (getWindowHashMap().isEmpty())
+        gdk_window_add_filter(0, reinterpret_cast<GdkFilterFunc>(filterXDamageEvent), 0);
+    getWindowHashMap().add(m_window, this);
+
     while (1) {
         XEvent event;
         XWindowEvent(display, m_window, StructureNotifyMask, &event);
@@ -88,54 +151,30 @@ RedirectedXCompositeWindow::RedirectedXCompositeWindow(const IntSize& size)
             break;
     }
     XSelectInput(display, m_window, NoEventMask);
-
     XCompositeRedirectWindow(display, m_window, CompositeRedirectManual);
-
-    resize(size);
+    m_damage = XDamageCreate(display, m_window, XDamageReportNonEmpty);
 }
 
 RedirectedXCompositeWindow::~RedirectedXCompositeWindow()
 {
-    Display* display = GLContextGLX::sharedDisplay();
-    if (m_window)
-        XDestroyWindow(display, m_window);
-    if (m_parentWindow)
-        XDestroyWindow(display, m_parentWindow);
-    cleanupPixmapAndPixmapSurface();
-
-    if (m_pendingResizeSourceId)
-        g_source_remove(m_pendingResizeSourceId);
-}
+    ASSERT(m_damage);
+    ASSERT(m_window);
+    ASSERT(m_parentWindow);
 
-gboolean RedirectedXCompositeWindow::resizeLaterCallback(RedirectedXCompositeWindow* window)
-{
-    window->resizeLater();
-    return FALSE;
-}
+    getWindowHashMap().remove(m_window);
+    if (getWindowHashMap().isEmpty())
+        gdk_window_remove_filter(0, reinterpret_cast<GdkFilterFunc>(filterXDamageEvent), 0);
 
-void RedirectedXCompositeWindow::resizeLater()
-{
-    m_usableSize = m_size;
-    m_pendingResizeSourceId = 0;
+    Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    XDamageDestroy(display, m_damage);
+    XDestroyWindow(display, m_window);
+    XDestroyWindow(display, m_parentWindow);
+    cleanupPixmapAndPixmapSurface();
 }
 
 void RedirectedXCompositeWindow::resize(const IntSize& size)
 {
-    // When enlarging a redirected window, for the first render, the newly exposed areas seem
-    // to contain uninitialized memory on Intel drivers. To avoid rendering artifacts while
-    // resizing, we wait to render those new areas until after a short timeout. Thus, the
-    // "usable size" of the window is smaller than the actual size of the window for the first
-    // render.
-    m_usableSize = size.shrunkTo(m_usableSize);
-    if (m_usableSize.width() < size.width() || m_usableSize.height() < size.height()) { // The window is growing.
-        // We're being very conservative here. Instead of risking drawing artifacts while doing continuous
-        // opaque resizing, we err on the side of having more undrawn areas.
-        if (m_pendingResizeSourceId)
-            g_source_remove(m_pendingResizeSourceId);
-        m_pendingResizeSourceId = g_timeout_add(0, reinterpret_cast<GSourceFunc>(resizeLaterCallback), this);
-    }
-
-    Display* display = GLContextGLX::sharedDisplay();
+    Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
     XResizeWindow(display, m_window, size.width(), size.height());
 
     XFlush(display);
@@ -216,6 +255,12 @@ cairo_surface_t* RedirectedXCompositeWindow::cairoSurfaceForWidget(GtkWidget* wi
     return m_surface.get();
 }
 
+void RedirectedXCompositeWindow::callDamageNotifyCallback()
+{
+    if (m_damageNotifyCallback)
+        m_damageNotifyCallback(m_damageNotifyData);
+}
+
 } // namespace WebCore
 
 #endif // USE(GLX)
index e5db0fa..865be3b 100644 (file)
@@ -35,6 +35,8 @@
 
 typedef unsigned long Pixmap;
 typedef unsigned long Window;
+typedef unsigned long Damage;
+typedef void (*DamageNotifyCallback)(void*);
 
 namespace WebCore {
 
@@ -42,24 +44,25 @@ class RedirectedXCompositeWindow {
 public:
     static PassOwnPtr<RedirectedXCompositeWindow> create(const IntSize&);
     virtual ~RedirectedXCompositeWindow();
-
-    const IntSize& usableSize() { return m_usableSize; }
     const IntSize& size() { return m_size; }
 
     void resize(const IntSize& newSize);
     GLContext* context();
     cairo_surface_t* cairoSurfaceForWidget(GtkWidget*);
     Window windowId() { return m_window; }
+    void callDamageNotifyCallback();
+
+    void setDamageNotifyCallback(DamageNotifyCallback callback, void* data)
+    {
+        m_damageNotifyCallback = callback;
+        m_damageNotifyData = data;
+    }
 
 private:
     RedirectedXCompositeWindow(const IntSize&);
-
-    static gboolean resizeLaterCallback(RedirectedXCompositeWindow*);
-    void resizeLater();
     void cleanupPixmapAndPixmapSurface();
 
     IntSize m_size;
-    IntSize m_usableSize;
     Window m_window;
     Window m_parentWindow;
     Pixmap m_pixmap;
@@ -67,6 +70,10 @@ private:
     RefPtr<cairo_surface_t> m_surface;
     unsigned int m_pendingResizeSourceId;
     bool m_needsNewPixmapAfterResize;
+
+    Damage m_damage;
+    DamageNotifyCallback m_damageNotifyCallback;
+    void* m_damageNotifyData;
 };
 
 } // namespace WebCore
index cef16d1..9f9ff4c 100644 (file)
@@ -1,3 +1,37 @@
+2012-09-26  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Use XDamage to simplify RedirectedXCompositeWindow
+        https://bugs.webkit.org/show_bug.cgi?id=97267
+
+        Reviewed by Alejandro G. Castro.
+
+        Use XDamage to queue redraws of the widget when redirecting accelerated compositing
+        to an offscreen window. This allows removing a finicky timer-based approach, improves
+        performance, and allows simplifying things greatly.
+
+        * GNUmakefile.am: Add the XDamage CFLAGS and LIBS.
+        * WebCoreSupport/AcceleratedCompositingContext.h:
+        (AcceleratedCompositingContext): Change the signature of compositeLayersToContext
+        to accept an enum that explains the composite purpose.
+        * WebCoreSupport/AcceleratedCompositingContextGL.cpp:
+        (WebKit::redirectedWindowDamagedCallback): Added.
+        (WebKit::AcceleratedCompositingContext::initialize): Handle the situation where
+        the RedirectedXCompositeWindow returns a null pointer.
+        (WebKit::AcceleratedCompositingContext::enabled): Ditto.
+        (WebKit::AcceleratedCompositingContext::renderLayersToWindow): Remove the code handling
+        the usable size of the RedirectedXCompositeWindow. The usable size is now always equal
+        to the size.
+        (WebKit::AcceleratedCompositingContext::compositeLayersToContext): When drawing for a
+        resize, first clear the entire context. Remove the double swap-buffer, as it's no
+        longer necessary.
+        (WebKit::AcceleratedCompositingContext::setRootCompositingLayer): Handle the case that
+        the redirected window is null.
+        (WebKit::AcceleratedCompositingContext::resizeRootLayer): Instead of doing another
+        immediate layer flush, just recomposite the current layer state and schedule a new
+        flush. This should make resizing faster.
+        (WebKit::AcceleratedCompositingContext::flushAndRenderLayers): We no longer need to
+        queue a redraw, unless we want to force one.
+
 2012-09-26  Zan Dobersek  <zandobersek@gmail.com>
 
         [GTK] Enable some of the unstable CSS features
index db6c9b0..5be9eb5 100644 (file)
@@ -66,6 +66,8 @@ libwebkitgtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CPPF
        $(LIBXSLT_CFLAGS) \
        $(SQLITE3_CFLAGS) \
        $(UNICODE_CFLAGS) \
+       $(XCOMPOSITE_LIBS) \
+       $(XDAMAGE_LIBS) \
        $(XT_CFLAGS) \
        $(ZLIB_CFLAGS)
 
@@ -102,6 +104,7 @@ libwebkitgtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LIBA
        $(SQLITE3_LIBS) \
        $(UNICODE_LIBS) \
        $(XCOMPOSITE_LIBS) \
+       $(XDAMAGE_LIBS) \
        $(XRENDER_LIBS) \
        $(XT_LIBS) \
        $(WINMM_LIBS) \
index 45ef470..926b219 100644 (file)
@@ -64,7 +64,10 @@ public:
     virtual bool showRepaintCounter(const WebCore::GraphicsLayer*) const;
 
     void initialize();
-    void compositeLayersToContext();
+
+    enum CompositePurpose { ForResize, NotForResize };
+    void compositeLayersToContext(CompositePurpose = NotForResize);
+
     void flushAndRenderLayers();
     bool flushPendingLayerChanges();
     void scrollNonCompositedContents(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset);
index 95da644..f1b10b9 100644 (file)
@@ -63,17 +63,26 @@ static IntSize getWebViewSize(WebKitWebView* webView)
     return IntSize(allocation.width, allocation.height);
 }
 
+void redirectedWindowDamagedCallback(void* data)
+{
+    gtk_widget_queue_draw(GTK_WIDGET(data));
+}
+
 void AcceleratedCompositingContext::initialize()
 {
     if (m_rootLayer)
         return;
 
     IntSize pageSize = getWebViewSize(m_webView);
-    if (!m_redirectedWindow)
-        m_redirectedWindow = RedirectedXCompositeWindow::create(pageSize);
-    else
+    if (!m_redirectedWindow) {
+        if (m_redirectedWindow = RedirectedXCompositeWindow::create(pageSize))
+            m_redirectedWindow->setDamageNotifyCallback(redirectedWindowDamagedCallback, m_webView);
+    } else
         m_redirectedWindow->resize(pageSize);
 
+    if (!m_redirectedWindow)
+        return;
+
     m_rootLayer = GraphicsLayer::create(this);
     m_rootLayer->setDrawsContent(false);
     m_rootLayer->setSize(pageSize);
@@ -120,7 +129,7 @@ void AcceleratedCompositingContext::stopAnyPendingLayerFlush()
 
 bool AcceleratedCompositingContext::enabled()
 {
-    return m_rootLayer && m_textureMapper;
+    return m_redirectedWindow && m_rootLayer && m_textureMapper;
 }
 
 bool AcceleratedCompositingContext::renderLayersToWindow(cairo_t* cr, const IntRect& clipRect)
@@ -130,19 +139,6 @@ bool AcceleratedCompositingContext::renderLayersToWindow(cairo_t* cr, const IntR
     if (!enabled())
         return false;
 
-    // It's important to paint a white background (if the WebView isn't transparent), because when growing
-    // the redirected window, the usable size of the window may be smaller than the allocation of our widget.
-    // We don't want to show artifacts in that case.
-    IntSize usableWindowSize = m_redirectedWindow->usableSize();
-    if (usableWindowSize != m_redirectedWindow->size()) {
-        if (!m_webView->priv->transparent) {
-            cairo_set_source_rgb(cr, 1, 1, 1);
-            cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
-        } else
-            cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
-        cairo_paint(cr);
-    }
-
     cairo_surface_t* windowSurface = m_redirectedWindow->cairoSurfaceForWidget(GTK_WIDGET(m_webView));
     if (!windowSurface)
         return true;
@@ -176,7 +172,7 @@ GLContext* AcceleratedCompositingContext::prepareForRendering()
     return context;
 }
 
-void AcceleratedCompositingContext::compositeLayersToContext()
+void AcceleratedCompositingContext::compositeLayersToContext(CompositePurpose purpose)
 {
     GLContext* context = prepareForRendering();
     if (!context)
@@ -185,21 +181,16 @@ void AcceleratedCompositingContext::compositeLayersToContext()
     const IntSize& windowSize = m_redirectedWindow->size();
     glViewport(0, 0, windowSize.width(), windowSize.height());
 
+    if (purpose == ForResize) {
+        glClearColor(1, 1, 1, 0);
+        glClear(GL_COLOR_BUFFER_BIT);
+    }
+
     m_textureMapper->beginPainting();
     toTextureMapperLayer(m_rootLayer.get())->paint();
     m_textureMapper->endPainting();
 
     context->swapBuffers();
-
-    // FIXME: It seems that when using double-buffering (and on some drivers single-buffering)
-    // and XComposite window redirection, two swap buffers are required to force the pixmap
-    // to update. This isn't a problem during animations, because swapBuffer is continuously
-    // called. For non-animation situations we use this terrible hack until we can get to the
-    // bottom of the issue.
-    if (!toTextureMapperLayer(m_rootLayer.get())->descendantsOrSelfHaveRunningAnimations()) {
-        context->swapBuffers();
-        context->swapBuffers();
-    }
 }
 
 void AcceleratedCompositingContext::clearEverywhere()
@@ -236,7 +227,8 @@ void AcceleratedCompositingContext::setRootCompositingLayer(GraphicsLayer* graph
         stopAnyPendingLayerFlush();
 
         // Shrink the offscreen window to save memory while accelerated compositing is turned off.
-        m_redirectedWindow->resize(IntSize(1, 1));
+        if (m_redirectedWindow)
+            m_redirectedWindow->resize(IntSize(1, 1));
         m_rootLayer = nullptr;
         m_nonCompositedContentLayer = nullptr;
         m_textureMapper = nullptr;
@@ -245,6 +237,9 @@ void AcceleratedCompositingContext::setRootCompositingLayer(GraphicsLayer* graph
 
     // Add the accelerated layer tree hierarchy.
     initialize();
+    if (!m_redirectedWindow)
+        return;
+
     m_nonCompositedContentLayer->removeAllChildren();
     m_nonCompositedContentLayer->addChild(graphicsLayer);
 
@@ -295,7 +290,8 @@ void AcceleratedCompositingContext::resizeRootLayer(const IntSize& newSize)
         m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height()));
 
     m_nonCompositedContentLayer->setNeedsDisplayInRect(IntRect(IntPoint(), newSize));
-    flushAndRenderLayers();
+    compositeLayersToContext(ForResize);
+    scheduleLayerFlush();
 }
 
 void AcceleratedCompositingContext::scrollNonCompositedContents(const IntRect& scrollRect, const IntSize& scrollOffset)
@@ -351,14 +347,13 @@ void AcceleratedCompositingContext::flushAndRenderLayers()
     m_lastFlushTime = currentTime();
     compositeLayersToContext();
 
-    gtk_widget_queue_draw(GTK_WIDGET(m_webView));
-
     // If it's been a long time since we've actually painted, which means that events might
     // be starving the main loop, we should force a draw now. This seems to prevent display
     // lag on http://2012.beercamp.com.
-    if (m_redrawPendingTime && currentTime() - m_redrawPendingTime > gScheduleDelay)
+    if (m_redrawPendingTime && currentTime() - m_redrawPendingTime > gScheduleDelay) {
+        gtk_widget_queue_draw(GTK_WIDGET(m_webView));
         gdk_window_process_updates(gtk_widget_get_window(GTK_WIDGET(m_webView)), FALSE);
-    else if (!m_redrawPendingTime)
+    else if (!m_redrawPendingTime)
         m_redrawPendingTime = currentTime();
 }
 
index 5492dce..2ae1678 100644 (file)
@@ -1,3 +1,33 @@
+2012-09-26  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Use XDamage to simplify RedirectedXCompositeWindow
+        https://bugs.webkit.org/show_bug.cgi?id=97267
+
+        Reviewed by Alejandro G. Castro.
+
+        Use XDamage to queue redraws of the widget when redirecting accelerated compositing
+        to an offscreen window. This allows removing a finicky timer-based approach, improves
+        performance, and allows simplifying things greatly.
+
+        * GNUmakefile.am: Add the XDamage CFLAGS and LIBS to the appropriate places.
+        * UIProcess/API/gtk/WebKitWebViewBase.cpp:
+        (_WebKitWebViewBasePrivate): Remove readyToRenderAcceleratedCompositingResults as
+        it's no longer necessary.
+        (webkit_web_view_base_init): Handle the situation where the RedirectedXCompositeWindow
+        is null.
+        (webkitWebViewRenderAcceleratedCompositingResults): Ditto.
+        (resizeWebKitWebViewBaseFromAllocation): Ditto.
+        (webkitWebViewBaseCreateWebPage): Ditto.
+        (redirectedWindowDamagedCallback): Added.
+        * UIProcess/WebPageProxy.h: Remove InvalidateWidget message.
+        * UIProcess/WebPageProxy.messages.in: Ditto.
+        * UIProcess/gtk/WebPageProxyGtk.cpp: Ditto.
+        * WebProcess/WebPage/WebPage.h: Ditto.
+        * WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp:
+        (WebKit::LayerTreeHostGtk::compositeLayersToContext): No longer need to
+        trigger the invalidateWindow message.
+        * WebProcess/WebPage/gtk/WebPageGtk.cpp: Ditto.
+
 2012-09-25  Raphael Kubo da Costa  <raphael.kubo.da.costa@intel.com>
 
         [DRT][WTR] Support overriding the 'WebKitDisplayImagesKey' preference
index 5202086..b072e0e 100644 (file)
@@ -110,6 +110,7 @@ libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CPP
        $(LIBSOUP_CFLAGS) \
        $(UNICODE_CFLAGS) \
        $(XCOMPOSITE_CFLAGS) \
+       $(XDAMAGE_CFLAGS) \
        $(XT_CFLAGS)
 
 libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CXXFLAGS = \
@@ -184,6 +185,7 @@ libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LIB
        $(UNICODE_LIBS) \
        $(XRENDER_LIBS) \
        $(XCOMPOSITE_LIBS) \
+       $(XDAMAGE_LIBS) \
        $(XT_LIBS) \
        $(ZLIB_LIBS)
 
index b42b2ee..aa13d7a 100644 (file)
@@ -75,6 +75,10 @@ using namespace WebCore;
 
 typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap;
 
+#if USE(TEXTURE_MAPPER_GL)
+void redirectedWindowDamagedCallback(void* data);
+#endif
+
 struct _WebKitWebViewBasePrivate {
     WebKitWebViewChildrenMap children;
     OwnPtr<PageClientImpl> pageClient;
@@ -111,7 +115,6 @@ struct _WebKitWebViewBasePrivate {
 
 #if USE(TEXTURE_MAPPER_GL)
     OwnPtr<RedirectedXCompositeWindow> redirectedWindow;
-    bool readyToRenderAcceleratedCompositingResults;
 #endif
 };
 
@@ -351,7 +354,8 @@ static void webkit_web_view_base_init(WebKitWebViewBase* webkitWebViewBase)
 
 #if USE(TEXTURE_MAPPER_GL)
     priv->redirectedWindow = RedirectedXCompositeWindow::create(IntSize(1, 1));
-    priv->readyToRenderAcceleratedCompositingResults = false;
+    if (priv->redirectedWindow)
+        priv->redirectedWindow->setDamageNotifyCallback(redirectedWindowDamagedCallback, webkitWebViewBase);
 #endif
 }
 
@@ -364,10 +368,9 @@ static bool webkitWebViewRenderAcceleratedCompositingResults(WebKitWebViewBase*
     // To avoid flashes when initializing accelerated compositing for the first
     // time, we wait until we know there's a frame ready before rendering.
     WebKitWebViewBasePrivate* priv = webViewBase->priv;
-    if (!priv->readyToRenderAcceleratedCompositingResults)
+    if (!priv->redirectedWindow)
         return false;
 
-    ASSERT(priv->redirectedWindow);
     cairo_rectangle(cr, clipRect->x, clipRect->y, clipRect->width, clipRect->height);
     cairo_surface_t* surface = priv->redirectedWindow->cairoSurfaceForWidget(GTK_WIDGET(webViewBase));
     cairo_set_source_surface(cr, surface, 0, 0);
@@ -430,7 +433,7 @@ static void resizeWebKitWebViewBaseFromAllocation(WebKitWebViewBase* webViewBase
     }
 
 #if USE(TEXTURE_MAPPER_GL)
-    if (sizeChanged)
+    if (sizeChanged && webViewBase->priv->redirectedWindow)
         webViewBase->priv->redirectedWindow->resize(viewRect.size());
 #endif
 
@@ -801,7 +804,8 @@ void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, WebCon
 #endif
 
 #if USE(TEXTURE_MAPPER_GL)
-    priv->pageProxy->setAcceleratedCompositingWindowId(priv->redirectedWindow->windowId());
+    if (priv->redirectedWindow)
+        priv->pageProxy->setAcceleratedCompositingWindowId(priv->redirectedWindow->windowId());
 #endif
 }
 
@@ -928,37 +932,9 @@ GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebView
 }
 
 #if USE(TEXTURE_MAPPER_GL)
-static gboolean queueAnotherDrawOfAcceleratedCompositingResults(gpointer* webViewBasePointer)
+void redirectedWindowDamagedCallback(void* data)
 {
-    // The WebViewBase may have been destroyed in the time since we queued this
-    // draw and the time we are actually executing.
-    if (!*webViewBasePointer) {
-        fastFree(webViewBasePointer);
-        return FALSE;
-    }
-
-    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(*webViewBasePointer);
-    gtk_widget_queue_draw(GTK_WIDGET(webViewBase));
-    webViewBase->priv->readyToRenderAcceleratedCompositingResults = true;
-
-    g_object_remove_weak_pointer(G_OBJECT(webViewBase), webViewBasePointer);
-    fastFree(webViewBasePointer);
-
-    return FALSE;
-}
-
-void webkitWebViewBaseQueueDrawOfAcceleratedCompositingResults(WebKitWebViewBase* webViewBase)
-{
-    gtk_widget_queue_draw(GTK_WIDGET(webViewBase));
-
-    // Redraw again, one frame later, as it might take some time for the new GL frame to be available.
-    // This prevents the display from always being one frame behind in the case GL hasn't yet finished
-    // rendering to the window.
-    // TODO: Add XDamage support to RedirectedXCompositeWindow to accomplish this.
-    gpointer* webViewBasePointer = static_cast<gpointer*>(fastMalloc(sizeof(gpointer)));
-    g_object_add_weak_pointer(G_OBJECT(webViewBase), webViewBasePointer);
-    *webViewBasePointer = webViewBase;
-    g_timeout_add(1000 / 60, reinterpret_cast<GSourceFunc>(queueAnotherDrawOfAcceleratedCompositingResults), webViewBasePointer);
+    gtk_widget_queue_draw(GTK_WIDGET(data));
 }
 #endif
 
index 4cbafa3..97e1ba2 100644 (file)
@@ -717,7 +717,6 @@ public:
 
 #if PLATFORM(GTK) && USE(TEXTURE_MAPPER_GL)
     void setAcceleratedCompositingWindowId(uint64_t nativeWindowId);
-    void invalidateWidget();
 #endif
 
     void setSuppressVisibilityUpdates(bool flag) { m_suppressVisibilityUpdates = flag; }
index 3a755e1..05cbb23 100644 (file)
@@ -178,10 +178,6 @@ messages -> WebPageProxy {
     BindAccessibilityTree(WTF::String plugID)
 #endif
 
-#if PLATFORM(GTK) && USE(TEXTURE_MAPPER_GL)
-    InvalidateWidget()
-#endif
-
     # BackForward messages
     BackForwardAddItem(uint64_t itemID)
     BackForwardGoToItem(uint64_t itemID) -> (WebKit::SandboxExtension::Handle sandboxExtensionHandle)
index 80881bf..6b01bb0 100644 (file)
@@ -114,11 +114,6 @@ void WebPageProxy::setAcceleratedCompositingWindowId(uint64_t nativeWindowId)
 {
     process()->send(Messages::WebPage::SetAcceleratedCompositingWindowId(nativeWindowId), m_pageID);
 }
-
-void WebPageProxy::invalidateWidget()
-{
-    webkitWebViewBaseQueueDrawOfAcceleratedCompositingResults(WEBKIT_WEB_VIEW_BASE(static_cast<PageClientImpl*>(m_pageClient)->viewWidget()));
-}
 #endif
 
 } // namespace WebKit
index fadd3bd..e21404b 100644 (file)
@@ -460,7 +460,6 @@ public:
     bool handleMousePressedEvent(const WebCore::PlatformMouseEvent&);
 #if USE(TEXTURE_MAPPER_GL)
     void setAcceleratedCompositingWindowId(int64_t nativeWindowHandle);
-    void invalidateWidget();
 #endif
 #endif
 
index 098a4c7..bcb2bef 100644 (file)
@@ -317,7 +317,6 @@ void LayerTreeHostGtk::compositeLayersToContext(CompositePurpose purpose)
     m_textureMapper->endPainting();
 
     context->swapBuffers();
-    m_webPage->invalidateWidget();
 }
 
 void LayerTreeHostGtk::flushAndRenderLayers()
index d9dde81..e28e74f 100644 (file)
@@ -160,11 +160,6 @@ void WebPage::setAcceleratedCompositingWindowId(int64_t nativeWindowHandle)
 {
     m_nativeWindowHandle = nativeWindowHandle;
 }
-
-void WebPage::invalidateWidget()
-{
-    send(Messages::WebPageProxy::InvalidateWidget());
-}
 #endif
 
 bool WebPage::handleMousePressedEvent(const PlatformMouseEvent& platformMouseEvent)
index f0196e9..c8f110d 100644 (file)
@@ -567,8 +567,11 @@ AC_MSG_RESULT([$with_acceleration_backend])
 
 if test "$with_acceleration_backend" = "opengl"; then
     PKG_CHECK_MODULES([XCOMPOSITE], [xcomposite]);
+    PKG_CHECK_MODULES([XDAMAGE], [xdamage]);
     AC_SUBST(XCOMPOSITE_CFLAGS)
     AC_SUBST(XCOMPOSITE_LIBS)
+    AC_SUBST(XDAMAGE_CFLAGS)
+    AC_SUBST(XDAMAGE_LIBS)
 fi
 
 # OpenGL is turned on by default (along with WebGL and accelerated compositing), but if