Accelerated compositing: Checkerboard never goes away
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 3 Mar 2012 01:22:24 +0000 (01:22 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 3 Mar 2012 01:22:24 +0000 (01:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=79020
RIM PR #134164

Patch by Arvid Nilsson <anilsson@rim.com> on 2012-03-02
Reviewed by Adam Treat.

Checkerboard appears in accelerated compositing layers when there's no
texture for (part of) a layer. The layer renderer queues up some render
jobs and schedules a commit to make the WebKit thread process those
jobs. Render jobs performed during commit cause texture upload jobs to
be scheduled on the UI thread. Texture uploads are performed when next
drawing the layers.

Unfortunately, sometimes commit operation happens without a subsequent
call draw the layers.

In order to implement one-shot drawing sync, I added a call to
commitRootLayerIfNeeded() in BackingStore::renderContents(), and
I was lucky that most of the time, renderContents() is followed by
blit(Visible)Contents() which in turn draws the layers.
However, render is not always followed by a blit, for example when
rendering offscreen tiles in BackingStore::renderOnIdle(), and in
direct rendering mode.

Fixed by making sure that every call to commitRootLayerIfNeeded() that
returns true is followed by a call to drawLayersOnCommit(), unless a
blit was requested already.

Also tweak the logic for one-shot drawing sync to make the code in
drawLayersOnCommit() reusable outside of rootLayerCommitTimerFired().

* Api/BackingStore.cpp:
(BlackBerry::WebKit::BackingStorePrivate::BackingStorePrivate):
(BlackBerry::WebKit::BackingStorePrivate::renderOnTimer):
(BlackBerry::WebKit::BackingStorePrivate::renderOnIdle):
(BlackBerry::WebKit::BackingStorePrivate::willFireTimer):
(BlackBerry::WebKit::BackingStorePrivate::renderDirectToWindow):
(BlackBerry::WebKit::BackingStorePrivate::render):
(BlackBerry::WebKit::BackingStorePrivate::blitVisibleContents):
(BlackBerry::WebKit::BackingStorePrivate::blitContents):
(BlackBerry::WebKit::BackingStorePrivate::renderContents):
(WebKit):
(BlackBerry::WebKit::BackingStorePrivate::drawLayersOnCommitIfNeeded):
* Api/BackingStore_p.h:
(BackingStorePrivate):
(BlackBerry::WebKit::BackingStorePrivate::willDrawLayersOnCommit):

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

Source/WebKit/blackberry/Api/BackingStore.cpp
Source/WebKit/blackberry/Api/BackingStore_p.h
Source/WebKit/blackberry/ChangeLog

index 2b0a49d..5968fd2 100644 (file)
@@ -201,6 +201,9 @@ BackingStorePrivate::BackingStorePrivate()
     , m_currentWindowBackBuffer(0)
     , m_preferredTileMatrixDimension(Vertical)
     , m_blitGeneration(-1)
+#if USE(ACCELERATED_COMPOSITING)
+    , m_needsDrawLayersOnCommit(false)
+#endif
 {
     m_frontState = reinterpret_cast<unsigned>(new BackingStoreGeometry);
     m_backState = reinterpret_cast<unsigned>(new BackingStoreGeometry);
@@ -464,10 +467,12 @@ void BackingStorePrivate::renderOnTimer(WebCore::Timer<BackingStorePrivate>*)
     while (m_renderQueue->hasCurrentVisibleZoomJob() || m_renderQueue->hasCurrentVisibleScrollJob())
         m_renderQueue->render(!m_suspendRegularRenderJobs);
 
-    if (!shouldPerformRegularRenderJobs() || !m_renderQueue->hasCurrentRegularRenderJob())
-        return;
+    if (shouldPerformRegularRenderJobs() && m_renderQueue->hasCurrentRegularRenderJob())
+        m_renderQueue->renderAllCurrentRegularRenderJobs();
 
-    m_renderQueue->renderAllCurrentRegularRenderJobs();
+#if USE(ACCELERATED_COMPOSITING)
+    drawLayersOnCommitIfNeeded();
+#endif
 }
 
 void BackingStorePrivate::renderOnIdle()
@@ -483,6 +488,10 @@ void BackingStorePrivate::renderOnIdle()
 #endif
 
     m_renderQueue->render(!m_suspendRegularRenderJobs);
+
+#if USE(ACCELERATED_COMPOSITING)
+    drawLayersOnCommitIfNeeded();
+#endif
 }
 
 bool BackingStorePrivate::willFireTimer()
@@ -512,6 +521,10 @@ bool BackingStorePrivate::willFireTimer()
     if (m_renderQueue->hasCurrentRegularRenderJob())
         m_renderQueue->renderAllCurrentRegularRenderJobs();
 
+#if USE(ACCELERATED_COMPOSITING)
+    drawLayersOnCommitIfNeeded();
+#endif
+
     // Let the caller yield and reschedule the timer.
     return false;
 }
@@ -941,12 +954,15 @@ bool BackingStorePrivate::renderDirectToWindow(const Platform::IntRect& rect)
     renderContents(0, origin, dirtyRect);
     windowBackBufferState()->addBlittedRegion(screenRect);
 
-#if USE(ACCELERATED_COMPOSITING) && ENABLE_COMPOSITING_SURFACE
+#if USE(ACCELERATED_COMPOSITING)
+    drawLayersOnCommitIfNeeded();
+#if ENABLE_COMPOSITING_SURFACE
     if (m_webPage->d->m_client->window()->windowUsage() != BlackBerry::Platform::Graphics::Window::GLES2Usage) {
         Platform::IntRect clippedRect = intersection(dirtyRect, visibleContentsRect());
         blendCompositingSurface(clippedRect);
     }
 #endif
+#endif
 
     invalidateWindow(screenRect);
     return true;
@@ -979,8 +995,6 @@ bool BackingStorePrivate::render(const Platform::IntRect& rect)
     TileMap currentMap = currentState->tileMap();
 
     Platform::IntRect dirtyContentsRect;
-    const Platform::IntRect contentsRect = Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedContentsSize());
-    const Platform::IntRect viewportRect = Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedViewportSize());
 
     for (size_t i = 0; i < tileRectList.size(); ++i) {
         TileRect tileRect = tileRectList[i];
@@ -1106,6 +1120,11 @@ void BackingStorePrivate::blitVisibleContents(bool force)
     }
 
     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
+#if USE(ACCELERATED_COMPOSITING)
+        // The blit will call drawSubLayers if necessary
+        m_needsDrawLayersOnCommit = false;
+#endif
+
         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
             BlackBerry::Platform::createMethodCallMessage(
                 &BackingStorePrivate::blitVisibleContents, this, force));
@@ -1196,6 +1215,11 @@ void BackingStorePrivate::blitContents(const Platform::IntRect& dstRect,
     }
 
     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
+#if USE(ACCELERATED_COMPOSITING)
+        // The blit will call drawSubLayers if necessary
+        m_needsDrawLayersOnCommit = false;
+#endif
+
         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
             BlackBerry::Platform::createMethodCallMessage(
                 &BackingStorePrivate::blitContents, this, dstRect, srcRect, force));
@@ -2131,7 +2155,15 @@ void BackingStorePrivate::renderContents(BlackBerry::Platform::Graphics::Buffer*
         return;
 
 #if USE(ACCELERATED_COMPOSITING)
-    m_webPage->d->commitRootLayerIfNeeded();
+    // When committing the pending accelerated compositing layer changes, it's
+    // necessary to draw the new layer appearance. This is normally done as
+    // part of a blit, but if no blit happens because of this rendering, for
+    // example because we're rendering an offscreen rectangle, someone needs to
+    // catch this flag and make sure those layers get drawn.
+    // This is just a complicated way to do
+    // "if (commitRootLayerIfNeeded()) drawLayersOnCommit();"
+    if (m_webPage->d->commitRootLayerIfNeeded())
+        m_needsDrawLayersOnCommit = true;
 #endif
 
     BlackBerry::Platform::Graphics::Drawable* bufferDrawable =
@@ -2483,6 +2515,18 @@ bool BackingStorePrivate::drawSubLayers()
         WebCore::FloatRect(WebCore::IntRect(src)));
     return m_webPage->d->drawSubLayers(dst, contentsRect);
 }
+
+bool BackingStorePrivate::drawLayersOnCommitIfNeeded()
+{
+    // Check if rendering caused a commit and we need to redraw the layers
+    if (!m_needsDrawLayersOnCommit)
+        return false;
+
+    m_needsDrawLayersOnCommit = false;
+    m_webPage->d->drawLayersOnCommit();
+
+    return true;
+}
 #endif
 
 bool BackingStorePrivate::isActive() const
index 49c70a6..49992e3 100644 (file)
@@ -196,6 +196,9 @@ public:
     void blendCompositingSurface(const Platform::IntRect& dstRect);
     void clearCompositingSurface();
     bool drawSubLayers();
+    bool drawLayersOnCommitIfNeeded();
+    // WebPage will call this when drawing layers to tell us we don't need to
+    void willDrawLayersOnCommit() { m_needsDrawLayersOnCommit = false; }
 #endif
 
     void blitHorizontalScrollbar(const Platform::IntPoint&);
@@ -347,6 +350,10 @@ public:
     pthread_mutex_t m_blitGenerationLock;
     pthread_cond_t m_blitGenerationCond;
     struct timespec m_currentBlitEnd;
+
+#if USE(ACCELERATED_COMPOSITING)
+    mutable bool m_needsDrawLayersOnCommit; // Not thread safe, WebKit thread only
+#endif
 };
 } // namespace WebKit
 } // namespace BlackBerry
index a4b01f6..cc49f4d 100644 (file)
@@ -1,3 +1,52 @@
+2012-03-02  Arvid Nilsson  <anilsson@rim.com>
+
+        Accelerated compositing: Checkerboard never goes away
+        https://bugs.webkit.org/show_bug.cgi?id=79020
+        RIM PR #134164
+
+        Reviewed by Adam Treat.
+
+        Checkerboard appears in accelerated compositing layers when there's no
+        texture for (part of) a layer. The layer renderer queues up some render
+        jobs and schedules a commit to make the WebKit thread process those
+        jobs. Render jobs performed during commit cause texture upload jobs to
+        be scheduled on the UI thread. Texture uploads are performed when next
+        drawing the layers.
+
+        Unfortunately, sometimes commit operation happens without a subsequent
+        call draw the layers.
+
+        In order to implement one-shot drawing sync, I added a call to
+        commitRootLayerIfNeeded() in BackingStore::renderContents(), and
+        I was lucky that most of the time, renderContents() is followed by
+        blit(Visible)Contents() which in turn draws the layers.
+        However, render is not always followed by a blit, for example when
+        rendering offscreen tiles in BackingStore::renderOnIdle(), and in
+        direct rendering mode.
+
+        Fixed by making sure that every call to commitRootLayerIfNeeded() that
+        returns true is followed by a call to drawLayersOnCommit(), unless a
+        blit was requested already.
+
+        Also tweak the logic for one-shot drawing sync to make the code in
+        drawLayersOnCommit() reusable outside of rootLayerCommitTimerFired().
+
+        * Api/BackingStore.cpp:
+        (BlackBerry::WebKit::BackingStorePrivate::BackingStorePrivate):
+        (BlackBerry::WebKit::BackingStorePrivate::renderOnTimer):
+        (BlackBerry::WebKit::BackingStorePrivate::renderOnIdle):
+        (BlackBerry::WebKit::BackingStorePrivate::willFireTimer):
+        (BlackBerry::WebKit::BackingStorePrivate::renderDirectToWindow):
+        (BlackBerry::WebKit::BackingStorePrivate::render):
+        (BlackBerry::WebKit::BackingStorePrivate::blitVisibleContents):
+        (BlackBerry::WebKit::BackingStorePrivate::blitContents):
+        (BlackBerry::WebKit::BackingStorePrivate::renderContents):
+        (WebKit):
+        (BlackBerry::WebKit::BackingStorePrivate::drawLayersOnCommitIfNeeded):
+        * Api/BackingStore_p.h:
+        (BackingStorePrivate):
+        (BlackBerry::WebKit::BackingStorePrivate::willDrawLayersOnCommit):
+
 2012-03-02  Adam Treat  <atreat@rim.com>
 
         https://bugs.webkit.org/show_bug.cgi?id=80161