Clip blur to bounds of layer

The blur operation takes a snapshot of the whole surface and previously,
it would blur all of it. This CL restricts the blur operation+drawing
only to the layer bounds. So layers in split screen would only blur
half the screen for example. In addition, this saves some GPU cycles.

This CL computes the bounds of the layer that is requesting background
blur and passes an SkRect to the BlurFilter. The snapshot is always
taken in the original surface orientation (for phones this is portrait).
We need the correct bounds to restrict the blur operation to and
separately we need the correct bounds to draw the blurred surface on
the screen canvas. These are different if the screen surface canvas is
already transformed.

To simplify this, we save the transformations done to the canvas in a
matrix and apply them after the blurred surface is drawn. That makes the
blurred surface and the screen surface in the same orientation and
simplifies the computation of the rect bounds.

Bug: 171681577
Test: put blurs in the dim layer && check that dialog in split screen
      blurs only its own surface + when changing orientation
Change-Id: Iad114567752ecd18a08cf19f83b4f759b069aded
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 03c8e80..a9bacb7 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -482,7 +482,8 @@
     // displays might have different scaling when compared to the physical screen.
 
     canvas->clipRect(getSkRect(display.physicalDisplay));
-    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+    SkMatrix screenTransform;
+    screenTransform.setTranslate(display.physicalDisplay.left, display.physicalDisplay.top);
 
     const auto clipWidth = display.clip.width();
     const auto clipHeight = display.clip.height();
@@ -496,25 +497,28 @@
             static_cast<SkScalar>(rotatedClipWidth);
     const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
             static_cast<SkScalar>(rotatedClipHeight);
-    canvas->scale(scaleX, scaleY);
+    screenTransform.preScale(scaleX, scaleY);
 
     // Canvas rotation is done by centering the clip window at the origin, rotating, translating
     // back so that the top left corner of the clip is at (0, 0).
-    canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
-    canvas->rotate(toDegrees(display.orientation));
-    canvas->translate(-clipWidth / 2, -clipHeight / 2);
-    canvas->translate(-display.clip.left, -display.clip.top);
+    screenTransform.preTranslate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+    screenTransform.preRotate(toDegrees(display.orientation));
+    screenTransform.preTranslate(-clipWidth / 2, -clipHeight / 2);
+    screenTransform.preTranslate(-display.clip.left, -display.clip.top);
     for (const auto& layer : layers) {
+        const SkMatrix drawTransform = getDrawTransform(layer, screenTransform);
+
         SkPaint paint;
         const auto& bounds = layer->geometry.boundaries;
         const auto dest = getSkRect(bounds);
         std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
 
         if (mBlurFilter) {
+            const auto layerRect = drawTransform.mapRect(dest);
             if (layer->backgroundBlurRadius > 0) {
                 ATRACE_NAME("BackgroundBlur");
                 auto blurredSurface =
-                        mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+                        mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius, layerRect);
                 cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
             }
             if (layer->blurRegions.size() > 0) {
@@ -523,7 +527,8 @@
                         continue;
                     }
                     ATRACE_NAME("BlurRegion");
-                    auto blurredSurface = mBlurFilter->generate(canvas, surface, region.blurRadius);
+                    auto blurredSurface =
+                            mBlurFilter->generate(canvas, surface, region.blurRadius, layerRect);
                     cachedBlurs[region.blurRadius] = blurredSurface;
                 }
             }
@@ -603,9 +608,8 @@
 
         paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
 
-        // Layers have a local transform matrix that should be applied to them.
         canvas->save();
-        canvas->concat(getSkM44(layer->geometry.positionTransform));
+        canvas->concat(drawTransform);
 
         for (const auto effectRegion : layer->blurRegions) {
             drawBlurRegion(canvas, effectRegion, dest, cachedBlurs[effectRegion.blurRadius]);
@@ -682,6 +686,13 @@
                  matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
 }
 
+inline SkMatrix SkiaGLRenderEngine::getDrawTransform(const LayerSettings* layer,
+                                                     const SkMatrix& screenTransform) {
+    // Layers have a local transform matrix that should be applied to them.
+    const auto layerTransform = getSkM44(layer->geometry.positionTransform).asM33();
+    return SkMatrix::Concat(screenTransform, layerTransform);
+}
+
 inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) {
     return SkPoint3::Make(vector.x, vector.y, vector.z);
 }
@@ -817,4 +828,4 @@
 
 } // namespace skia
 } // namespace renderengine
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 0143445..c65e431 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -69,6 +69,7 @@
     inline SkRRect getRoundedRect(const LayerSettings* layer);
     inline SkColor getSkColor(const vec4& color);
     inline SkM44 getSkM44(const mat4& matrix);
+    inline SkMatrix getDrawTransform(const LayerSettings* layer, const SkMatrix& screenTransform);
     inline SkPoint3 getSkPoint3(const vec3& vector);
 
     base::unique_fd flush();
@@ -107,4 +108,4 @@
 } // namespace renderengine
 } // namespace android
 
-#endif /* SF_GLESRENDERENGINE_H_ */
\ No newline at end of file
+#endif /* SF_GLESRENDERENGINE_H_ */
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index f6a316f..dfb306f 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -56,7 +56,7 @@
 }
 
 sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
-                                      const uint32_t blurRadius) const {
+                                      const uint32_t blurRadius, SkRect rect) const {
     ATRACE_CALL();
 
     // Kawase is an approximation of Gaussian, but it behaves differently from it.
@@ -68,6 +68,9 @@
 
     SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)input->width() * kInputScale,
                                                         (float)input->height() * kInputScale);
+
+    SkRect scaledRect = {rect.fLeft * kInputScale, rect.fTop * kInputScale,
+                         rect.fRight * kInputScale, rect.fBottom * kInputScale};
     auto drawSurface = canvas->makeSurface(scaledInfo);
 
     const float stepX = radiusByPasses;
@@ -88,7 +91,9 @@
         SkPaint paint;
         paint.setShader(blurBuilder.makeShader(nullptr, false));
         paint.setFilterQuality(kLow_SkFilterQuality);
-        drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
+
+        drawSurface->getCanvas()->drawRect(scaledRect, paint);
+
         blurBuilder.child("input") = nullptr;
     }
 
@@ -110,7 +115,8 @@
             SkPaint paint;
             paint.setShader(blurBuilder.makeShader(nullptr, false));
             paint.setFilterQuality(kLow_SkFilterQuality);
-            drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
+
+            drawSurface->getCanvas()->drawRect(scaledRect, paint);
 
             // Swap buffers for next iteration
             const auto tmp = drawSurface;
@@ -125,16 +131,18 @@
 }
 
 sk_sp<SkSurface> BlurFilter::draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
-                                  const uint32_t blurRadius) const {
+                                  const uint32_t blurRadius, SkRect rect) const {
     ATRACE_CALL();
-    auto surface = generate(canvas, input, blurRadius);
+    sk_sp<SkSurface> surface = generate(canvas, input, blurRadius, rect);
+    const auto image = surface->makeImageSnapshot();
 
     SkPaint paint;
-    const auto image = surface->makeImageSnapshot();
     paint.setShader(image->makeShader(SkMatrix::MakeScale(kInverseInputScale)));
     paint.setFilterQuality(kLow_SkFilterQuality);
     paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
-    canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
+
+    canvas->drawRect(rect, paint);
+
     return surface;
 }
 
@@ -146,4 +154,4 @@
 
 } // namespace skia
 } // namespace renderengine
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 6f973d7..c0a92f6 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -48,11 +48,11 @@
     virtual ~BlurFilter(){};
 
     // Execute blur, saving it to a texture
-    sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
-                              const uint32_t radius) const;
+    sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
+                              SkRect rect) const;
     // Same as generate but also drawing to the screen
-    sk_sp<SkSurface> draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
-                          const uint32_t radius) const;
+    sk_sp<SkSurface> draw(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 SkMatrix& transformMatrix) const;