[chromium] Scissor rect optimization for chromium compositor
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 3 Dec 2011 06:14:08 +0000 (06:14 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 3 Dec 2011 06:14:08 +0000 (06:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=67341

Patch by Shawn Singh <shawnsingh@chromium.org> on 2011-12-02
Reviewed by James Robinson.

Mostly covered by damage tracker tests. Currently this relies on
manually running layout tests, because this patch requires partial
swaps that are not supported by DumpRenderTree. The feature
automatically disables if partial swap is not supported.

* platform/graphics/chromium/LayerRendererChromium.cpp:
(WebCore::LayerRendererChromium::initialize):
(WebCore::LayerRendererChromium::trackDamageForAllSurfaces):
(WebCore::LayerRendererChromium::drawLayersOntoRenderSurfaces):
(WebCore::LayerRendererChromium::drawLayersInternal):
(WebCore::LayerRendererChromium::swapBuffers):
(WebCore::LayerRendererChromium::drawLayer):
* platform/graphics/chromium/LayerRendererChromium.h:
* platform/graphics/chromium/cc/CCLayerTreeHost.h:
(WebCore::CCSettings::CCSettings):
(WebCore::LayerRendererCapabilities::LayerRendererCapabilities):
* platform/graphics/chromium/cc/CCRenderSurface.cpp:
(WebCore::CCRenderSurface::draw):
* platform/graphics/chromium/cc/CCRenderSurface.h:

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.h

index f7ac745..6bca13f 100644 (file)
@@ -1,3 +1,30 @@
+2011-12-02  Shawn Singh  <shawnsingh@chromium.org>
+
+        [chromium] Scissor rect optimization for chromium compositor
+        https://bugs.webkit.org/show_bug.cgi?id=67341
+
+        Reviewed by James Robinson.
+
+        Mostly covered by damage tracker tests. Currently this relies on
+        manually running layout tests, because this patch requires partial
+        swaps that are not supported by DumpRenderTree. The feature
+        automatically disables if partial swap is not supported.
+
+        * platform/graphics/chromium/LayerRendererChromium.cpp:
+        (WebCore::LayerRendererChromium::initialize):
+        (WebCore::LayerRendererChromium::trackDamageForAllSurfaces):
+        (WebCore::LayerRendererChromium::drawLayersOntoRenderSurfaces):
+        (WebCore::LayerRendererChromium::drawLayersInternal):
+        (WebCore::LayerRendererChromium::swapBuffers):
+        (WebCore::LayerRendererChromium::drawLayer):
+        * platform/graphics/chromium/LayerRendererChromium.h:
+        * platform/graphics/chromium/cc/CCLayerTreeHost.h:
+        (WebCore::CCSettings::CCSettings):
+        (WebCore::LayerRendererCapabilities::LayerRendererCapabilities):
+        * platform/graphics/chromium/cc/CCRenderSurface.cpp:
+        (WebCore::CCRenderSurface::draw):
+        * platform/graphics/chromium/cc/CCRenderSurface.h:
+
 2011-12-02  Dmitry Lomov  <dslomov@google.com>
 
         https://bugs.webkit.org/show_bug.cgi?id=73691
index 07974df..526f7fb 100644 (file)
@@ -53,6 +53,7 @@
 #include "TrackingTextureAllocator.h"
 #include "TreeSynchronizer.h"
 #include "WebGLLayerChromium.h"
+#include "cc/CCDamageTracker.h"
 #include "cc/CCLayerImpl.h"
 #include "cc/CCLayerTreeHostCommon.h"
 #include "cc/CCProxy.h"
@@ -107,6 +108,21 @@ static TransformationMatrix screenMatrix(int x, int y, int width, int height)
     return screen;
 }
 
+static TransformationMatrix computeScreenSpaceTransformForSurface(CCLayerImpl* renderSurfaceLayer)
+{
+    // The layer's screen space transform can be written as:
+    //   layerScreenSpaceTransform = surfaceScreenSpaceTransform * layerOriginTransform
+    // So, to compute the surface screen space, we can do:
+    //   surfaceScreenSpaceTransform = layerScreenSpaceTransform * inverse(layerOriginTransform)
+
+    TransformationMatrix layerOriginTransform = renderSurfaceLayer->drawTransform();
+    layerOriginTransform.translate(-0.5 * renderSurfaceLayer->bounds().width(), -0.5 * renderSurfaceLayer->bounds().height());
+    TransformationMatrix surfaceScreenSpaceTransform = renderSurfaceLayer->screenSpaceTransform();
+    surfaceScreenSpaceTransform.multiply(layerOriginTransform.inverse());
+
+    return surfaceScreenSpaceTransform;
+}
+
 #if USE(SKIA)
 bool contextSupportsAcceleratedPainting(GraphicsContext3D* context)
 {
@@ -191,9 +207,12 @@ bool LayerRendererChromium::initialize()
     if (m_capabilities.contextHasCachedFrontBuffer)
         extensions->ensureEnabled("GL_CHROMIUM_front_buffer_cached");
 
-    m_capabilities.usingPostSubBuffer = extensions->supports("GL_CHROMIUM_post_sub_buffer");
-    if (m_capabilities.usingPostSubBuffer)
+    m_capabilities.usingPartialSwap = extensions->supports("GL_CHROMIUM_post_sub_buffer");
+    if (m_capabilities.usingPartialSwap)
         extensions->ensureEnabled("GL_CHROMIUM_post_sub_buffer");
+    // FIXME: eventually we would like to have usingPartialSwap enabled by default,
+    //        whenever it is supported. For now, we force it off.
+    m_capabilities.usingPartialSwap = false;
 
     m_capabilities.usingMapSub = extensions->supports("GL_CHROMIUM_map_sub");
     if (m_capabilities.usingMapSub)
@@ -317,10 +336,30 @@ void LayerRendererChromium::drawLayers()
         copyOffscreenTextureToDisplay();
 }
 
+void LayerRendererChromium::trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList)
+{
+    // For now, we use damage tracking to compute a global scissor. To do this, we must
+    // compute all damage tracking before drawing anything, so that we know the root
+    // damage rect. The root damage rect is then used to scissor each surface.
+
+    ASSERT(m_capabilities.usingPartialSwap);
+
+    for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
+        CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex].get();
+        CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface();
+        ASSERT(renderSurface);
+        renderSurface->damageTracker()->updateDamageRectForNextFrame(renderSurface->layerList(), renderSurfaceLayer->id(), renderSurfaceLayer->maskLayer());
+    }
+}
+
 void LayerRendererChromium::drawLayersOntoRenderSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList)
 {
     TRACE_EVENT("LayerRendererChromium::drawLayersOntoRenderSurfaces", this, 0);
 
+    if (m_capabilities.usingPartialSwap)
+        trackDamageForAllSurfaces(rootDrawLayer, renderSurfaceLayerList);
+    m_rootDamageRect = rootDrawLayer->renderSurface()->damageTracker()->currentDamageRect();
+
     // Update the contents of the render surfaces. We traverse the render surfaces
     // from back to front to guarantee that nested render surfaces get rendered in
     // the correct order.
@@ -332,16 +371,31 @@ void LayerRendererChromium::drawLayersOntoRenderSurfaces(CCLayerImpl* rootDrawLa
 
         if (useRenderSurface(renderSurface)) {
 
+            FloatRect surfaceDamageRect;
+            if (m_capabilities.usingPartialSwap) {
+                // For now, we conservatively use the root damage as the damage for all
+                // surfaces, except perspective transforms.
+                TransformationMatrix screenSpaceTransform = computeScreenSpaceTransformForSurface(renderSurfaceLayer);
+                if (screenSpaceTransform.hasPerspective()) {
+                    // Perspective projections do not play nice with mapRect of inverse transforms.
+                    // In this uncommon case, its simpler to just redraw the entire surface.
+                    surfaceDamageRect = renderSurface->contentRect();
+                } else {
+                    TransformationMatrix inverseScreenSpaceTransform = screenSpaceTransform.inverse();
+                    surfaceDamageRect = inverseScreenSpaceTransform.mapRect(m_rootDamageRect);
+                }
+            }
+
             if (renderSurfaceLayer != rootDrawLayer) {
-                GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
+                if (m_capabilities.usingPartialSwap)
+                    setScissorToRect(enclosingIntRect(surfaceDamageRect));
                 GLC(m_context.get(), m_context->clearColor(0, 0, 0, 0));
                 GLC(m_context.get(), m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT));
-                GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST));
             }
 
             const CCLayerList& layerList = renderSurface->layerList();
             for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex)
-                drawLayer(layerList[layerIndex].get(), renderSurface);
+                drawLayer(layerList[layerIndex].get(), renderSurface, surfaceDamageRect);
         }
     }
 
@@ -392,20 +446,20 @@ void LayerRendererChromium::drawLayersInternal()
     // Bind the common vertex attributes used for drawing all the layers.
     m_sharedGeometry->prepareForDraw();
 
-    GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
     GLC(m_context.get(), m_context->disable(GraphicsContext3D::DEPTH_TEST));
     GLC(m_context.get(), m_context->disable(GraphicsContext3D::CULL_FACE));
 
     useRenderSurface(m_defaultRenderSurface);
 
     // Clear to blue to make it easier to spot unrendered regions.
+    if (m_capabilities.usingPartialSwap)
+        setScissorToRect(enclosingIntRect(m_rootDamageRect));
     m_context->clearColor(0, 0, 1, 1);
     m_context->colorMask(true, true, true, true);
     m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
 
     GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND));
     GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
-    GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST));
 
     drawLayersOntoRenderSurfaces(rootDrawLayer, renderSurfaceLayerList);
 
@@ -487,9 +541,17 @@ void LayerRendererChromium::swapBuffers()
     TRACE_EVENT("LayerRendererChromium::swapBuffers", this, 0);
     // We're done! Time to swapbuffers!
 
-    // Note that currently this has the same effect as swapBuffers; we should
-    // consider exposing a different entry point on GraphicsContext3D.
-    m_context->prepareTexture();
+    if (m_capabilities.usingPartialSwap) {
+        // If supported, we can save significant bandwidth by only swapping the damaged/scissored region (clamped to the viewport)
+        IntRect subBuffer = enclosingIntRect(m_rootDamageRect);
+        subBuffer.intersect(IntRect(IntPoint::zero(), viewportSize()));
+        Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(m_context->getExtensions());
+        int flippedYPosOfRectBottom = viewportHeight() - subBuffer.y() - subBuffer.height();
+        extensions3DChromium->postSubBufferCHROMIUM(subBuffer.x(), flippedYPosOfRectBottom, subBuffer.width(), subBuffer.height());
+    } else
+        // Note that currently this has the same effect as swapBuffers; we should
+        // consider exposing a different entry point on GraphicsContext3D.
+        m_context->prepareTexture();
 
     m_headsUpDisplay->onSwapBuffers();
 }
@@ -582,10 +644,10 @@ bool LayerRendererChromium::useRenderSurface(CCRenderSurface* renderSurface)
     return true;
 }
 
-void LayerRendererChromium::drawLayer(CCLayerImpl* layer, CCRenderSurface* targetSurface)
+void LayerRendererChromium::drawLayer(CCLayerImpl* layer, CCRenderSurface* targetSurface, const FloatRect& surfaceDamageRect)
 {
     if (CCLayerTreeHostCommon::renderSurfaceContributesToTarget<CCLayerImpl>(layer, targetSurface->owningLayerId())) {
-        layer->renderSurface()->draw(this, layer->getDrawRect());
+        layer->renderSurface()->draw(this, surfaceDamageRect);
         layer->renderSurface()->releaseContentsTexture();
         return;
     }
@@ -593,7 +655,13 @@ void LayerRendererChromium::drawLayer(CCLayerImpl* layer, CCRenderSurface* targe
     if (layer->visibleLayerRect().isEmpty())
         return;
 
-    if (layer->usesLayerClipping())
+    if (layer->usesLayerClipping() && m_capabilities.usingPartialSwap) {
+        FloatRect clipAndDamageRect(layer->clipRect());
+        clipAndDamageRect.intersect(surfaceDamageRect);
+        setScissorToRect(enclosingIntRect(clipAndDamageRect));
+    } else if (m_capabilities.usingPartialSwap)
+        setScissorToRect(enclosingIntRect(surfaceDamageRect));
+    else if (layer->usesLayerClipping())
         setScissorToRect(layer->clipRect());
     else
         GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
index ff9e550..5c806d3 100644 (file)
@@ -165,7 +165,9 @@ private:
 
     void drawLayersInternal();
     void drawLayersOntoRenderSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList);
-    void drawLayer(CCLayerImpl*, CCRenderSurface*);
+    void drawLayer(CCLayerImpl*, CCRenderSurface*, const FloatRect&);
+
+    void trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList);
 
     ManagedTexture* getOffscreenLayerTexture();
     void copyOffscreenTextureToDisplay();
@@ -243,6 +245,8 @@ private:
     FloatQuad m_sharedGeometryQuad;
 
     bool m_isViewportChanged;
+
+    FloatRect m_rootDamageRect;
 };
 
 // Setting DEBUG_GL_CALLS to 1 will call glGetError() after almost every GL
index 9652d58..8224724 100644 (file)
@@ -73,14 +73,12 @@ struct CCSettings {
             , compositeOffscreen(false)
             , showFPSCounter(false)
             , showPlatformLayerTree(false)
-            , useDamageTracker(false)
             , refreshRate(0) { }
 
     bool acceleratePainting;
     bool compositeOffscreen;
     bool showFPSCounter;
     bool showPlatformLayerTree;
-    bool useDamageTracker;
     double refreshRate;
 };
 
@@ -89,7 +87,7 @@ struct LayerRendererCapabilities {
     LayerRendererCapabilities()
         : bestTextureFormat(0)
         , contextHasCachedFrontBuffer(false)
-        , usingPostSubBuffer(false)
+        , usingPartialSwap(false)
         , usingMapSub(false)
         , usingAcceleratedPainting(false)
         , usingSetVisibility(false)
@@ -98,7 +96,7 @@ struct LayerRendererCapabilities {
 
     GC3Denum bestTextureFormat;
     bool contextHasCachedFrontBuffer;
-    bool usingPostSubBuffer;
+    bool usingPartialSwap;
     bool usingMapSub;
     bool usingAcceleratedPainting;
     bool usingSetVisibility;
index 29db5a4..a4c9256 100644 (file)
@@ -101,7 +101,7 @@ void CCRenderSurface::releaseContentsTexture()
     m_contentsTexture->unreserve();
 }
 
-void CCRenderSurface::draw(LayerRendererChromium* layerRenderer, const IntRect&)
+void CCRenderSurface::draw(LayerRendererChromium* layerRenderer, const FloatRect& surfaceDamageRect)
 {
     if (m_skipsDraw || !m_contentsTexture)
         return;
@@ -115,7 +115,13 @@ void CCRenderSurface::draw(LayerRendererChromium* layerRenderer, const IntRect&)
     if (!m_maskLayer && m_owningLayer->replicaLayer())
         replicaMaskLayer = m_owningLayer->replicaLayer()->maskLayer();
 
-    if (m_owningLayer->parent() && m_owningLayer->parent()->usesLayerClipping())
+    if (m_owningLayer->parent() && m_owningLayer->parent()->usesLayerClipping() && layerRenderer->capabilities().usingPartialSwap) {
+        FloatRect clipAndDamageRect = m_clipRect;
+        clipAndDamageRect.intersect(surfaceDamageRect);
+        layerRenderer->setScissorToRect(enclosingIntRect(clipAndDamageRect));
+    } else if (layerRenderer->capabilities().usingPartialSwap)
+        layerRenderer->setScissorToRect(enclosingIntRect(surfaceDamageRect));
+    else if (m_owningLayer->parent() && m_owningLayer->parent()->usesLayerClipping())
         layerRenderer->setScissorToRect(m_clipRect);
     else
         GLC(layerRenderer->context(), layerRenderer->context()->disable(GraphicsContext3D::SCISSOR_TEST));
index d0e35a1..a8e87a9 100644 (file)
@@ -54,7 +54,7 @@ public:
     bool prepareContentsTexture(LayerRendererChromium*);
     void releaseContentsTexture();
     void cleanupResources();
-    void draw(LayerRendererChromium*, const IntRect& targetSurfaceRect);
+    void draw(LayerRendererChromium*, const FloatRect& surfaceDamageRect);
 
     String name() const;
     void dumpSurface(TextStream&, int indent) const;