Apply the layer's image filter to the hoisted image
authorrobertphillips <robertphillips@google.com>
Thu, 11 Dec 2014 16:20:31 +0000 (08:20 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 11 Dec 2014 16:20:31 +0000 (08:20 -0800)
Exposing SkSurface_Gpu makes me sad and I would welcome alternatives.

This change is desireable since it greatly decreases the render target swaps.

Review URL: https://codereview.chromium.org/792923002

gyp/gpu.gyp
gyp/gpu.gypi
src/gpu/GrLayerCache.h
src/gpu/GrLayerHoister.cpp
src/gpu/GrLayerHoister.h
src/gpu/SkGpuDevice.cpp
src/gpu/SkGpuDevice.h
src/image/SkSurface_Gpu.cpp
src/image/SkSurface_Gpu.h [new file with mode: 0644]

index 6319456..e835e34 100644 (file)
@@ -96,6 +96,7 @@
         '../include/gpu',
         '../src/core',
         '../src/gpu',
+        '../src/image/',
       ],
       'sources': [
         '<@(skgpu_sources)',
index 32603fe..1570ab4 100644 (file)
       '<(skia_src_path)/gpu/SkGrTexturePixelRef.cpp',
 
       '<(skia_src_path)/image/SkImage_Gpu.cpp',
+      '<(skia_src_path)/image/SkSurface_Gpu.h',
       '<(skia_src_path)/image/SkSurface_Gpu.cpp',
 
       '<(skia_src_path)/gpu/gl/SkGLContext.cpp'
index b9b59d0..0ea23b3 100644 (file)
@@ -12,6 +12,7 @@
 #include "GrRect.h"
 
 #include "SkChecksum.h"
+#include "SkImageFilter.h"
 #include "SkMessageBus.h"
 #include "SkPicture.h"
 #include "SkTDynamicHash.h"
@@ -151,16 +152,23 @@ public:
         , fStop(stop)
         , fBounds(bounds)
         , fPaint(paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL)
+        , fFilter(NULL)
         , fTexture(NULL)
         , fRect(SkIRect::MakeEmpty())
         , fPlot(NULL)
         , fUses(0)
         , fLocked(false) {
         SkASSERT(SK_InvalidGenID != pictureID);
+
+        if (fPaint) {
+            fFilter = SkSafeRef(fPaint->getImageFilter());
+            fPaint->setImageFilter(NULL);
+        }
     }
 
     ~GrCachedLayer() {
         SkSafeUnref(fTexture);
+        SkSafeUnref(fFilter);
         SkDELETE(fPaint);
     }
 
@@ -179,6 +187,7 @@ public:
     }
     GrTexture* texture() { return fTexture; }
     const SkPaint* paint() const { return fPaint; }
+    const SkImageFilter* filter() const { return fFilter; }
     const SkIRect& rect() const { return fRect; }
 
     void setPlot(GrPlot* plot) {
@@ -207,7 +216,11 @@ private:
 
     // The paint used when dropping the layer down into the owning canvas.
     // Can be NULL. This class makes a copy for itself.
-    const SkPaint*  fPaint;
+    SkPaint*  fPaint;
+
+    // The imagefilter that needs to be applied to the layer prior to it being
+    // composited with the rest of the scene.
+    const SkImageFilter* fFilter;
 
     // fTexture is a ref on the atlasing texture for atlased layers and a
     // ref on a GrTexture for non-atlased textures.
index 5d2d549..493e2f7 100644 (file)
 #include "GrRecordReplaceDraw.h"
 
 #include "SkCanvas.h"
+#include "SkGpuDevice.h"
 #include "SkGrPixelRef.h"
 #include "SkLayerInfo.h"
 #include "SkRecordDraw.h"
 #include "SkSurface.h"
+#include "SkSurface_Gpu.h"
 
 // Create the layer information for the hoisted layer and secure the
 // required texture/render target resources.
@@ -200,6 +202,7 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
             SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();)
 
             SkASSERT(!layerPaint || !layerPaint->getImageFilter());
+            SkASSERT(!layer->filter());
 
             atlasCanvas->save();
 
@@ -231,6 +234,37 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
     }
 }
 
+void GrLayerHoister::FilterLayer(GrContext* context, SkGpuDevice* device, GrCachedLayer* layer) {
+    SkASSERT(layer->filter());
+
+    static const int kDefaultCacheSize = 32 * 1024 * 1024;
+
+    if (layer->filter()->canFilterImageGPU()) {
+        SkBitmap filteredBitmap;
+        SkIPoint offset = SkIPoint::Make(0, 0);
+
+        SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop);
+        SkIRect clipBounds = layer->rect();
+
+        // This cache is transient, and is freed (along with all its contained
+        // textures) when it goes out of scope.
+        SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kDefaultCacheSize));
+        SkImageFilter::Context filterContext(SkMatrix::I(), clipBounds, cache);
+
+        if (!device->filterTexture(context, layer->texture(), layer->filter(),
+                                   filterContext, &filteredBitmap, &offset)) {
+            // Filtering failed. Press on with the unfiltered version
+            return;
+        }
+
+        // TODO: need to fix up offset
+        SkASSERT(0 == offset.fX && 0 == offset.fY);
+
+        SkIRect newRect = SkIRect::MakeWH(filteredBitmap.width(), filteredBitmap.height());
+        layer->setTexture(filteredBitmap.getTexture(), newRect);
+    }
+}
+
 void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLayer>& layers) {
     for (int i = 0; i < layers.count(); ++i) {
         GrCachedLayer* layer = layers[i].fLayer;
@@ -263,6 +297,12 @@ void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLay
                             layer->start()+1, layer->stop(), initialCTM);
 
         layerCanvas->flush();
+
+        if (layer->filter()) {
+            SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(surface.get());
+
+            FilterLayer(context, gpuSurf->getDevice(), layer);
+        }
     }
 }
 
index 2d68a94..9668ba6 100644 (file)
@@ -13,6 +13,7 @@
 
 struct GrCachedLayer;
 class GrReplacements;
+class SkGpuDevice;
 struct SkRect;
 
 class GrHoistedLayer {
@@ -102,6 +103,15 @@ public:
         @param context    Owner of the layer cache (and thus the layers)
      */
     static void PurgeCache(GrContext* context);
+
+private:
+    /** Update the GrTexture in 'layer' with its filtered version
+        @param context    Owner of the layer cache (and thus the layers)
+        @param device     Required by the filtering code
+        @param layer      A layer needing filtering prior to being composited
+     */
+    static void FilterLayer(GrContext* context, SkGpuDevice* device, GrCachedLayer* layer);
+
 };
 
 #endif
index c0439f5..4c9f0e2 100644 (file)
@@ -1528,9 +1528,9 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
         return;
     }
 
-    const SkBitmap& bm = dev->accessBitmap(false);
-    int w = bm.width();
-    int h = bm.height();
+    const SkImageInfo ii = dev->imageInfo();
+    int w = ii.width();
+    int h = ii.height();
 
     SkImageFilter* filter = paint.getImageFilter();
     // This bitmap will own the filtered result as a texture.
index 2fb6de7..9023a63 100644 (file)
@@ -124,6 +124,10 @@ public:
                              const SkImageFilter::Context&,
                              SkBitmap*, SkIPoint*) SK_OVERRIDE;
 
+    bool filterTexture(GrContext*, GrTexture*, const SkImageFilter*,
+                       const SkImageFilter::Context&,
+                       SkBitmap* result, SkIPoint* offset);
+
 protected:
     virtual bool onReadPixels(const SkImageInfo&, void*, size_t, int, int) SK_OVERRIDE;
     virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE;
@@ -203,10 +207,6 @@ private:
 
     bool drawDashLine(const SkPoint pts[2], const SkPaint& paint);
 
-    bool filterTexture(GrContext*, GrTexture*, const SkImageFilter*,
-                       const SkImageFilter::Context&,
-                       SkBitmap* result, SkIPoint* offset);
-
     static SkPicture::AccelData::Key ComputeAccelDataKey();
 
     typedef SkBaseDevice INHERITED;
index 8487094..e58375b 100644 (file)
 #include "SkImage_Base.h"
 #include "SkCanvas.h"
 #include "SkGpuDevice.h"
+#include "SkSurface_Gpu.h"
 
 #if SK_SUPPORT_GPU
 
-class SkSurface_Gpu : public SkSurface_Base {
-public:
-    SK_DECLARE_INST_COUNT(SkSurface_Gpu)
-
-    SkSurface_Gpu(GrRenderTarget*, const SkSurfaceProps*, bool doClear);
-    virtual ~SkSurface_Gpu();
-
-    virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
-    virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE;
-    virtual SkImage* onNewImageSnapshot() SK_OVERRIDE;
-    virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
-                        const SkPaint*) SK_OVERRIDE;
-    virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE;
-    virtual void onDiscard() SK_OVERRIDE;
-
-private:
-    SkGpuDevice* fDevice;
-
-    typedef SkSurface_Base INHERITED;
-};
-
 ///////////////////////////////////////////////////////////////////////////////
 
 SkSurface_Gpu::SkSurface_Gpu(GrRenderTarget* renderTarget, const SkSurfaceProps* props,
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
new file mode 100644 (file)
index 0000000..a02eb3e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSurface_Gpu_DEFINED
+#define SkSurface_Gpu_DEFINED
+
+#include "SkSurface_Base.h"
+
+#if SK_SUPPORT_GPU
+
+class SkGpuDevice;
+
+class SkSurface_Gpu : public SkSurface_Base {
+public:
+    SK_DECLARE_INST_COUNT(SkSurface_Gpu)
+
+    SkSurface_Gpu(GrRenderTarget*, const SkSurfaceProps*, bool doClear);
+    virtual ~SkSurface_Gpu();
+
+    virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
+    virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE;
+    virtual SkImage* onNewImageSnapshot() SK_OVERRIDE;
+    virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
+                        const SkPaint*) SK_OVERRIDE;
+    virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE;
+    virtual void onDiscard() SK_OVERRIDE;
+
+    SkGpuDevice* getDevice() { return fDevice; }
+
+private:
+    SkGpuDevice* fDevice;
+
+    typedef SkSurface_Base INHERITED;
+};
+
+#endif // SK_SUPPORT_GPU
+
+#endif // SkSurface_Gpu_DEFINED