Improve RenderEngine's blur performance.

This CL uses new Skia APIs to skip the unnecessary glClear issued when
creating the temporary surfaces. On a Pixel 5 device this showed an
~6% improvement in total GPU time as well as a similar improvement on
the CPU time taken by Skia to isssue the calls to the GPU.

Test: perfetto traces
Bug: 176903027
Change-Id: If04b795ce44107670e9e752b10ab5470393e1e32
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index dc04f69..2ab3c6c 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -593,6 +593,7 @@
     // view is still on-screen. The clear region could be re-specified as a black color layer,
     // however.
     if (!display.clearRegion.isEmpty()) {
+        ATRACE_NAME("ClearRegion");
         size_t numRects = 0;
         Rect const* rects = display.clearRegion.getArray(&numRects);
         SkIRect skRects[numRects];
@@ -612,6 +613,7 @@
     }
 
     for (const auto& layer : layers) {
+        ATRACE_NAME("DrawLayer");
         canvas->save();
 
         if (mCapture->isCaptureRunning()) {
@@ -630,7 +632,7 @@
         const auto& bounds = layer->geometry.boundaries;
         const auto dest = getSkRect(bounds);
         const auto layerRect = canvas->getTotalMatrix().mapRect(dest);
-        std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
+        std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
         if (mBlurFilter) {
             if (layer->backgroundBlurRadius > 0) {
                 ATRACE_NAME("BackgroundBlur");
@@ -882,17 +884,15 @@
 }
 
 void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
-                                        const SkRect& layerRect, sk_sp<SkSurface> blurredSurface) {
+                                        const SkRect& layerRect, sk_sp<SkImage> blurredImage) {
     ATRACE_CALL();
 
     SkPaint paint;
     paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
     const auto matrix = getBlurShaderTransform(canvas, layerRect);
-    paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(
-            SkTileMode::kClamp,
-            SkTileMode::kClamp,
-            SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}),
-            &matrix));
+    SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
+    paint.setShader(blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
+                                             &matrix));
 
     auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
                                  effectRegion.bottom);
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index ed62a2a..c094680 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -89,7 +89,7 @@
     void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
                     const ShadowSettings& shadowSettings);
     void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
-                        sk_sp<SkSurface> blurredSurface);
+                        sk_sp<SkImage> blurredImage);
     SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
     // If mUseColorManagement is correct and layer needsLinearEffect, it returns a linear runtime
     // shader. Otherwise it returns the input shader.
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 8927be8..87b1a7c 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -57,8 +57,8 @@
     mBlurEffect = std::move(blurEffect);
 }
 
-sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
-                                      const uint32_t blurRadius, SkRect rect) const {
+sk_sp<SkImage> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+                                    const uint32_t blurRadius, SkRect rect) const {
     // Kawase is an approximation of Gaussian, but it behaves differently from it.
     // A radius transformation is required for approximating them, and also to introduce
     // non-integer steps, necessary to smoothly interpolate large radii.
@@ -68,9 +68,6 @@
 
     SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)rect.width() * kInputScale,
                                                         (float)rect.height() * kInputScale);
-    SkRect scaledRect = SkRect::MakeWH(scaledInfo.width(), scaledInfo.height());
-
-    auto drawSurface = canvas->makeSurface(scaledInfo);
 
     const float stepX = radiusByPasses;
     const float stepY = radiusByPasses;
@@ -85,49 +82,20 @@
     blurBuilder.uniform("in_blurOffset") =
             SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
 
-    {
-        // limit the lifetime of the input surface's snapshot to ensure that it goes out of
-        // scope before the surface is written into to avoid any copy-on-write behavior.
-        SkPaint paint;
-        paint.setShader(blurBuilder.makeShader(nullptr, false));
-        paint.setFilterQuality(kLow_SkFilterQuality);
+    sk_sp<SkImage> tmpBlur(
+            blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false));
 
-        drawSurface->getCanvas()->drawRect(scaledRect, paint);
-
-        blurBuilder.child("input") = nullptr;
+    // And now we'll build our chain of scaled blur stages
+    blurBuilder.uniform("in_inverseScale") = 1.0f;
+    for (auto i = 1; i < numberOfPasses; i++) {
+        const float stepScale = (float)i * kInputScale;
+        blurBuilder.child("input") =
+                tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
+        blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
+        tmpBlur = blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false);
     }
 
-    // And now we'll ping pong between our surfaces, to accumulate the result of various offsets.
-    auto lastDrawTarget = drawSurface;
-    if (numberOfPasses > 1) {
-        auto readSurface = drawSurface;
-        drawSurface = canvas->makeSurface(scaledInfo);
-
-        for (auto i = 1; i < numberOfPasses; i++) {
-            const float stepScale = (float)i * kInputScale;
-
-            blurBuilder.child("input") =
-                    readSurface->makeImageSnapshot()->makeShader(SkTileMode::kClamp,
-                                                                 SkTileMode::kClamp, linear);
-            blurBuilder.uniform("in_inverseScale") = 1.0f;
-            blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
-
-            SkPaint paint;
-            paint.setShader(blurBuilder.makeShader(nullptr, false));
-            paint.setFilterQuality(kLow_SkFilterQuality);
-
-            drawSurface->getCanvas()->drawRect(scaledRect, paint);
-
-            // Swap buffers for next iteration
-            const auto tmp = drawSurface;
-            drawSurface = readSurface;
-            readSurface = tmp;
-            blurBuilder.child("input") = nullptr;
-        }
-        lastDrawTarget = readSurface;
-    }
-
-    return lastDrawTarget;
+    return tmpBlur;
 }
 
 SkMatrix BlurFilter::getShaderMatrix() const {
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 734bfcb..08641c9 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -48,8 +48,8 @@
     virtual ~BlurFilter(){};
 
     // Execute blur, saving it to a texture
-    sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
-                              SkRect rect) const;
+    sk_sp<SkImage> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
+                            SkRect rect) const;
     // Returns a matrix that should be applied to the blur shader
     SkMatrix getShaderMatrix() const;