Make filters and the threaded compositor play well together.
authorsenorblanco@chromium.org <senorblanco@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Mar 2012 01:31:50 +0000 (01:31 +0000)
committersenorblanco@chromium.org <senorblanco@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Mar 2012 01:31:50 +0000 (01:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=78139

Use a dedicated GraphicsContext3D instance for all filters calls in
the threaded case.  Clone all FilterOperations for thread safety
in the threaded case.

Reviewed by James Robinson.

Covered by tests in LayoutTests/css3/filters.

* platform/graphics/chromium/LayerChromium.cpp:
(WebCore::LayerChromium::setFilters):
Set a global flag if we've seen content with filters, so we know
we need to create the filter context.
(WebCore::LayerChromium::pushPropertiesTo):
Clone all filter operations if we're in the threaded case.
* platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
(WebCore):
* platform/graphics/chromium/cc/CCLayerTreeHost.h:
(WebCore::CCLayerTreeHost::needsFilterContext):
(WebCore::CCLayerTreeHost::setNeedsFilterContext):
(CCLayerTreeHost):
Add flag and accessors for needsFilterContext.
* platform/graphics/chromium/cc/CCRenderSurface.cpp:
(WebCore::CCRenderSurface::applyFilters):
Pick up the appropriate context from SharedGraphicsContext3D,
depending if we're in the threaded case or not.
* platform/graphics/chromium/cc/CCThreadProxy.cpp:
(WebCore::CCThreadProxy::recreateContext):
For the threaded compositor re-create the filter context
alongside the main compositor context on lost context, if requested.
(WebCore::CCThreadProxy::beginFrame):
Create the filter context in beginFrame, if it was resquested and is
NULL.  This handles the first-use case.
* platform/graphics/filters/CustomFilterOperation.h:
(WebCore::CustomFilterOperation::clone):
Assert if trying to clone the custom filter operation (it has
non-threadsafe members).
* platform/graphics/filters/FilterOperation.h:
(WebCore::DefaultFilterOperation::clone):
(WebCore::PassthroughFilterOperation::clone):
(WebCore::ReferenceFilterOperation::clone):
(WebCore::BasicColorMatrixFilterOperation::clone):
(WebCore::BasicComponentTransferFilterOperation::clone):
(WebCore::GammaFilterOperation::clone):
(WebCore::BlurFilterOperation::clone):
(WebCore::DropShadowFilterOperation::clone):
Add clone methods for all FilterOperations.
* platform/graphics/gpu/SharedGraphicsContext3D.cpp:
(WebCore::SharedGraphicsContext3DImpl::getOrCreateContext):
(WebCore::SharedGraphicsContext3DImpl::getContext):
(WebCore::SharedGraphicsContext3DImpl::createContext):
(WebCore::SharedGraphicsContext3D::get):
(WebCore::getOrCreateContextForImplThread):
(WebCore::SharedGraphicsContext3D::getForImplThread):
(WebCore::SharedGraphicsContext3D::haveForImplThread):
(WebCore::SharedGraphicsContext3D::createForImplThread):
Split out context creation, lost context recovery, and retrieval
into separate functions, so the impl thread can use only the parts
it wants on the threads it wants (create and have on main, get on impl).
Add asserts to ensure that's how they're called.
* platform/graphics/gpu/SharedGraphicsContext3D.h:
(SharedGraphicsContext3D):
Reuse the SharedGraphicsContext infrastructure to create a new
context singleton for filter use in the threaded compositor.

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/LayerChromium.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.h
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.cpp
Source/WebCore/platform/graphics/chromium/cc/CCThreadProxy.cpp
Source/WebCore/platform/graphics/filters/CustomFilterOperation.h
Source/WebCore/platform/graphics/filters/FilterOperation.h
Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp
Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h

index bad330b..6171c52 100644 (file)
@@ -1,3 +1,72 @@
+2012-03-26  Stephen White  <senorblanco@chromium.org>
+
+        Make filters and the threaded compositor play well together.
+        https://bugs.webkit.org/show_bug.cgi?id=78139
+        
+        Use a dedicated GraphicsContext3D instance for all filters calls in
+        the threaded case.  Clone all FilterOperations for thread safety
+        in the threaded case.
+
+        Reviewed by James Robinson.
+        
+        Covered by tests in LayoutTests/css3/filters.
+
+        * platform/graphics/chromium/LayerChromium.cpp:
+        (WebCore::LayerChromium::setFilters):
+        Set a global flag if we've seen content with filters, so we know
+        we need to create the filter context.
+        (WebCore::LayerChromium::pushPropertiesTo):
+        Clone all filter operations if we're in the threaded case.
+        * platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
+        (WebCore):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.h:
+        (WebCore::CCLayerTreeHost::needsFilterContext):
+        (WebCore::CCLayerTreeHost::setNeedsFilterContext):
+        (CCLayerTreeHost):
+        Add flag and accessors for needsFilterContext.
+        * platform/graphics/chromium/cc/CCRenderSurface.cpp:
+        (WebCore::CCRenderSurface::applyFilters):
+        Pick up the appropriate context from SharedGraphicsContext3D,
+        depending if we're in the threaded case or not.
+        * platform/graphics/chromium/cc/CCThreadProxy.cpp:
+        (WebCore::CCThreadProxy::recreateContext):
+        For the threaded compositor re-create the filter context
+        alongside the main compositor context on lost context, if requested.
+        (WebCore::CCThreadProxy::beginFrame):
+        Create the filter context in beginFrame, if it was resquested and is
+        NULL.  This handles the first-use case.
+        * platform/graphics/filters/CustomFilterOperation.h:
+        (WebCore::CustomFilterOperation::clone):
+        Assert if trying to clone the custom filter operation (it has
+        non-threadsafe members).
+        * platform/graphics/filters/FilterOperation.h:
+        (WebCore::DefaultFilterOperation::clone):
+        (WebCore::PassthroughFilterOperation::clone):
+        (WebCore::ReferenceFilterOperation::clone):
+        (WebCore::BasicColorMatrixFilterOperation::clone):
+        (WebCore::BasicComponentTransferFilterOperation::clone):
+        (WebCore::GammaFilterOperation::clone):
+        (WebCore::BlurFilterOperation::clone):
+        (WebCore::DropShadowFilterOperation::clone):
+        Add clone methods for all FilterOperations.
+        * platform/graphics/gpu/SharedGraphicsContext3D.cpp:
+        (WebCore::SharedGraphicsContext3DImpl::getOrCreateContext):
+        (WebCore::SharedGraphicsContext3DImpl::getContext):
+        (WebCore::SharedGraphicsContext3DImpl::createContext):
+        (WebCore::SharedGraphicsContext3D::get):
+        (WebCore::getOrCreateContextForImplThread):
+        (WebCore::SharedGraphicsContext3D::getForImplThread):
+        (WebCore::SharedGraphicsContext3D::haveForImplThread):
+        (WebCore::SharedGraphicsContext3D::createForImplThread):
+        Split out context creation, lost context recovery, and retrieval
+        into separate functions, so the impl thread can use only the parts
+        it wants on the threads it wants (create and have on main, get on impl).
+        Add asserts to ensure that's how they're called.
+        * platform/graphics/gpu/SharedGraphicsContext3D.h:
+        (SharedGraphicsContext3D):
+        Reuse the SharedGraphicsContext infrastructure to create a new
+        context singleton for filter use in the threaded compositor.
+
 2012-03-26  Adam Barth  <abarth@webkit.org>
 
         FrameLoader::shouldAllowNavigation uses Frame for context rather than Document
index a5b3643..0cf8333 100644 (file)
@@ -318,6 +318,7 @@ void LayerChromium::setFilters(const FilterOperations& filters)
         return;
     m_filters = filters;
     setNeedsCommit();
+    CCLayerTreeHost::setNeedsFilterContext();
 }
 
 void LayerChromium::setOpacity(float opacity)
@@ -459,6 +460,18 @@ void LayerChromium::pushPropertiesTo(CCLayerImpl* layer)
     layer->setDebugName(m_debugName.isolatedCopy()); // We have to use isolatedCopy() here to safely pass ownership to another thread.
     layer->setDoubleSided(m_doubleSided);
     layer->setDrawsContent(drawsContent());
+    if (CCProxy::hasImplThread()) {
+        // Since FilterOperations contains a vector of RefPtrs, we must deep copy the filters.
+        FilterOperations filtersCopy;
+        for (unsigned i = 0; i < m_filters.size(); ++i) {
+            RefPtr<FilterOperation> clone = m_filters.at(i)->clone();
+            if (clone)
+                filtersCopy.operations().append(clone);
+        }
+        layer->setFilters(filtersCopy);
+    } else
+        layer->setFilters(filters());
+
     layer->setFilters(filters());
     layer->setIsNonCompositedContent(m_isNonCompositedContent);
     layer->setMasksToBounds(m_masksToBounds);
index f7e32d0..43ed747 100644 (file)
@@ -49,6 +49,8 @@ static int numLayerTreeInstances;
 
 namespace WebCore {
 
+bool CCLayerTreeHost::s_needsFilterContext = false;
+
 bool CCLayerTreeHost::anyLayerTreeHostInstanceExists()
 {
     return numLayerTreeInstances > 0;
index 6eb72ae..58db6d5 100644 (file)
@@ -129,6 +129,9 @@ public:
     // Returns true if any CCLayerTreeHost is alive.
     static bool anyLayerTreeHostInstanceExists();
 
+    static bool needsFilterContext() { return s_needsFilterContext; }
+    static void setNeedsFilterContext() { s_needsFilterContext = true; }
+
     // CCLayerTreeHost interface to CCProxy.
     void willBeginFrame() { m_client->willBeginFrame(); }
     void updateAnimations(double wallClockTime);
@@ -268,6 +271,7 @@ private:
 
     TextureList m_deleteTextureAfterCommitList;
     size_t m_partialTextureUpdateRequests;
+    static bool s_needsFilterContext;
 };
 
 }
index 4288bcb..815f1ef 100644 (file)
@@ -223,13 +223,16 @@ void CCRenderSurface::drawSurface(LayerRendererChromium* layerRenderer, CCLayerI
 
 SkBitmap CCRenderSurface::applyFilters(LayerRendererChromium* layerRenderer)
 {
-    // Don't use the utility context if we have a compositor thread, since
-    // it can race with canvas's use.
-    if (!m_contentsTexture || !m_filters.size() || CCProxy::hasImplThread())
+    if (!m_contentsTexture || !m_filters.size())
+        return SkBitmap();
+
+    RefPtr<GraphicsContext3D> filterContext = CCProxy::hasImplThread() ? SharedGraphicsContext3D::getForImplThread() : SharedGraphicsContext3D::get();
+    if (!filterContext)
         return SkBitmap();
 
     layerRenderer->context()->flush();
-    return CCRenderSurfaceFilters::apply(m_filters, m_contentsTexture->textureId(), m_contentRect.size(), SharedGraphicsContext3D::get().get());
+
+    return CCRenderSurfaceFilters::apply(m_filters, m_contentsTexture->textureId(), m_contentRect.size(), filterContext.get());
 }
 
 String CCRenderSurface::name() const
index e51a784..b3e2dbb 100644 (file)
@@ -27,6 +27,7 @@
 #include "cc/CCThreadProxy.h"
 
 #include "GraphicsContext3D.h"
+#include "SharedGraphicsContext3D.h"
 #include "TraceEvent.h"
 #include "cc/CCDelayBasedTimeSource.h"
 #include "cc/CCFrameRateController.h"
@@ -209,6 +210,10 @@ bool CCThreadProxy::recreateContext()
     RefPtr<GraphicsContext3D> context = m_layerTreeHost->createContext();
     if (!context)
         return false;
+    if (CCLayerTreeHost::needsFilterContext())
+        if (!SharedGraphicsContext3D::createForImplThread())
+            return false;
+
     ASSERT(context->hasOneRef());
 
     // Leak the context pointer so we can transfer ownership of it to the other side...
@@ -422,6 +427,9 @@ void CCThreadProxy::beginFrame()
         return;
     }
 
+    if (CCLayerTreeHost::needsFilterContext() && !SharedGraphicsContext3D::haveForImplThread())
+        SharedGraphicsContext3D::createForImplThread();
+
     OwnPtr<BeginFrameAndCommitState> request(m_pendingBeginFrameRequest.release());
 
     // Do not notify the impl thread of commit requests that occur during
index 4d83926..f8e3fa1 100644 (file)
@@ -62,6 +62,13 @@ public:
         return adoptRef(new CustomFilterOperation(program, sortedParameters, meshRows, meshColumns, meshBoxType, meshType));
     }
     
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        // Some member vars (e.g., m_program) are not thread-safe, so
+        // we can't be cloned.
+        return 0;
+    }
+    
     CustomFilterProgram* program() const { return m_program.get(); }
     
     const CustomFilterParameterList& parameters() { return m_parameters; }
index 9ee9557..576467a 100644 (file)
@@ -82,6 +82,8 @@ public:
     // True if the the value of one pixel can affect the value of another pixel under this operation, such as blur.
     virtual bool movesPixels() const { return false; }
 
+    virtual PassRefPtr<FilterOperation> clone() const = 0;
+
 protected:
     FilterOperation(OperationType type)
         : m_type(type)
@@ -98,6 +100,11 @@ public:
         return adoptRef(new DefaultFilterOperation(type));
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        return adoptRef(new DefaultFilterOperation(m_type));
+    }
+
 private:
 
     virtual bool operator==(const FilterOperation& o) const
@@ -120,6 +127,11 @@ public:
         return adoptRef(new PassthroughFilterOperation());
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        return adoptRef(new PassthroughFilterOperation());
+    }
+
 private:
 
     virtual bool operator==(const FilterOperation& o) const
@@ -140,6 +152,12 @@ public:
         return adoptRef(new ReferenceFilterOperation(reference, type));
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        // AtomicString is thread-hostile, so we can't be cloned.
+        return 0;
+    }
+
     virtual bool affectsOpacity() const { return true; }
     virtual bool movesPixels() const { return true; }
 
@@ -173,6 +191,11 @@ public:
         return adoptRef(new BasicColorMatrixFilterOperation(amount, type));
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        return adoptRef(new BasicColorMatrixFilterOperation(m_amount, m_type));
+    }
+
     double amount() const { return m_amount; }
 
     virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false);
@@ -205,6 +228,11 @@ public:
         return adoptRef(new BasicComponentTransferFilterOperation(amount, type));
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        return adoptRef(new BasicComponentTransferFilterOperation(m_amount, m_type));
+    }
+
     double amount() const { return m_amount; }
 
     virtual bool affectsOpacity() const { return m_type == OPACITY; }
@@ -238,6 +266,11 @@ public:
         return adoptRef(new GammaFilterOperation(amplitude, exponent, offset, type));
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        return adoptRef(new GammaFilterOperation(m_amplitude, m_exponent, m_offset, m_type));
+    }
+
     double amplitude() const { return m_amplitude; }
     double exponent() const { return m_exponent; }
     double offset() const { return m_offset; }
@@ -273,6 +306,11 @@ public:
         return adoptRef(new BlurFilterOperation(stdDeviation, type));
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        return adoptRef(new BlurFilterOperation(m_stdDeviation, m_type));
+    }
+
     Length stdDeviation() const { return m_stdDeviation; }
 
     virtual bool affectsOpacity() const { return true; }
@@ -305,6 +343,11 @@ public:
         return adoptRef(new DropShadowFilterOperation(x, y, stdDeviation, color, type));
     }
 
+    virtual PassRefPtr<FilterOperation> clone() const
+    {
+        return adoptRef(new DropShadowFilterOperation(m_x, m_y, m_stdDeviation, m_color, m_type));
+    }
+
     int x() const { return m_x; }
     int y() const { return m_y; }
     int stdDeviation() const { return m_stdDeviation; }
index e5d5f9a..6cd9ee5 100644 (file)
 
 #include "SharedGraphicsContext3D.h"
 #include "Extensions3D.h"
+#include "cc/CCProxy.h"
 
 namespace WebCore {
 
 class SharedGraphicsContext3DImpl {
 public:
     SharedGraphicsContext3DImpl() : m_context(0) { }
-    PassRefPtr<GraphicsContext3D> get()
+    PassRefPtr<GraphicsContext3D> getOrCreateContext()
     {
         // If we lost the context, or can't make it current, create a new one.
         if (m_context && (!m_context->makeContextCurrent() || (m_context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR)))
             m_context.clear();
 
-        if (!m_context) {
-            GraphicsContext3D::Attributes attributes;
-            attributes.depth = false;
-            attributes.stencil = true;
-            attributes.antialias = false;
-            attributes.shareResources = true;
-            attributes.preferDiscreteGPU = true;
-            m_context = GraphicsContext3D::create(attributes, 0);
-        }
+        if (!m_context)
+            createContext();
 
         if (m_context && !m_context->makeContextCurrent())
             m_context.clear();
 
         return m_context;
     }
+
+    PassRefPtr<GraphicsContext3D> getContext()
+    {
+        return m_context;
+    }
+
+    PassRefPtr<GraphicsContext3D> createContext()
+    {
+        GraphicsContext3D::Attributes attributes;
+        attributes.depth = false;
+        attributes.stencil = true;
+        attributes.antialias = false;
+        attributes.shareResources = true;
+        attributes.preferDiscreteGPU = true;
+        m_context = GraphicsContext3D::create(attributes, 0);
+        return m_context;
+    }
 private:
     RefPtr<GraphicsContext3D> m_context;
 };
@@ -62,7 +73,35 @@ private:
 PassRefPtr<GraphicsContext3D> SharedGraphicsContext3D::get()
 {
     DEFINE_STATIC_LOCAL(SharedGraphicsContext3DImpl, impl, ());
-    return impl.get();
+    return impl.getOrCreateContext();
+}
+
+enum ContextOperation {
+    Get, Create
+};
+
+static PassRefPtr<GraphicsContext3D> getOrCreateContextForImplThread(ContextOperation op)
+{
+    DEFINE_STATIC_LOCAL(SharedGraphicsContext3DImpl, impl, ());
+    return op == Create ? impl.createContext() : impl.getContext();
+}
+
+PassRefPtr<GraphicsContext3D> SharedGraphicsContext3D::getForImplThread()
+{
+    ASSERT(CCProxy::isImplThread());
+    return getOrCreateContextForImplThread(Get);
+}
+
+bool SharedGraphicsContext3D::haveForImplThread()
+{
+    ASSERT(CCProxy::isMainThread());
+    return getOrCreateContextForImplThread(Get);
+}
+
+bool SharedGraphicsContext3D::createForImplThread()
+{
+    ASSERT(CCProxy::isMainThread());
+    return getOrCreateContextForImplThread(Create);
 }
 
 }
index 2cca5ff..850e63e 100644 (file)
@@ -40,6 +40,15 @@ public:
     // function again. Note that the return value may be 0 if the
     // GPU is unavailable.
     static PassRefPtr<GraphicsContext3D> get();
+    // This one returns the context, and does not touch it or re-create it.
+    // Should only be called on the impl thread.
+    static PassRefPtr<GraphicsContext3D> getForImplThread();
+    // This one returns if the threaded utility context exists.
+    // Should only be called on the main thread.
+    static bool haveForImplThread();
+    // This call creates the context unconditionally, but does not touch it.
+    // Should only be called on the main thread.
+    static bool createForImplThread();
 };
 
 }