Make blur surface with bounds of layer

This CL changes the blur logic to take a snapshot only of the layer, not
the whole screen.

This has 2 benefits:
1. The blur shader samples only within the bounds of the surface, so
this change fixes a black frame around the blurred layer
2. The blur surface is smaller when the layer is not fullscreen, so less
information gets copied around

Bug: 174464919
Test: check background blur doesn't have a black frame
Test: check blur regions are in place
Change-Id: Ic31742248cc8441225503af48f13e6ef95a59443
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index a0660fb..1c8ce9f 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -494,8 +494,7 @@
     // displays might have different scaling when compared to the physical screen.
 
     canvas->clipRect(getSkRect(display.physicalDisplay));
-    SkMatrix screenTransform;
-    screenTransform.setTranslate(display.physicalDisplay.left, display.physicalDisplay.top);
+    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
 
     const auto clipWidth = display.clip.width();
     const auto clipHeight = display.clip.height();
@@ -509,31 +508,33 @@
             static_cast<SkScalar>(rotatedClipWidth);
     const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
             static_cast<SkScalar>(rotatedClipHeight);
-    screenTransform.preScale(scaleX, scaleY);
+    canvas->scale(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).
-    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);
+    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);
     for (const auto& layer : layers) {
-        const SkMatrix drawTransform = getDrawTransform(layer, screenTransform);
+        canvas->save();
+
+        // Layers have a local transform that should be applied to them
+        canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
 
         SkPaint paint;
         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;
-
         if (mBlurFilter) {
-            const auto layerRect = drawTransform.mapRect(dest);
             if (layer->backgroundBlurRadius > 0) {
                 ATRACE_NAME("BackgroundBlur");
                 auto blurredSurface = mBlurFilter->generate(canvas, surface,
                                                             layer->backgroundBlurRadius, layerRect);
                 cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
 
-                drawBlurRegion(canvas, getBlurRegion(layer), drawTransform, blurredSurface);
+                drawBlurRegion(canvas, getBlurRegion(layer), layerRect, blurredSurface);
             }
             if (layer->blurRegions.size() > 0) {
                 for (auto region : layer->blurRegions) {
@@ -679,12 +680,9 @@
         paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
 
         for (const auto effectRegion : layer->blurRegions) {
-            drawBlurRegion(canvas, effectRegion, drawTransform,
-                           cachedBlurs[effectRegion.blurRadius]);
+            drawBlurRegion(canvas, effectRegion, layerRect, cachedBlurs[effectRegion.blurRadius]);
         }
 
-        canvas->save();
-        canvas->concat(drawTransform);
         if (layer->shadow.length > 0) {
             const auto rect = layer->geometry.roundedCornersRadius > 0
                     ? getSkRect(layer->geometry.roundedCornersCrop)
@@ -771,13 +769,6 @@
                  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);
 }
@@ -807,18 +798,16 @@
 }
 
 void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
-                                        const SkMatrix& drawTransform,
-                                        sk_sp<SkSurface> blurredSurface) {
+                                        const SkRect& layerRect, sk_sp<SkSurface> blurredSurface) {
     ATRACE_CALL();
 
     SkPaint paint;
     paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
-    const auto matrix = mBlurFilter->getShaderMatrix();
-    paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(matrix));
+    paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(
+            getBlurShaderTransform(canvas, layerRect)));
 
     auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
                                  effectRegion.bottom);
-    drawTransform.mapRect(&rect);
 
     if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
         effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
@@ -835,6 +824,24 @@
     }
 }
 
+SkMatrix SkiaGLRenderEngine::getBlurShaderTransform(const SkCanvas* canvas,
+                                                    const SkRect& layerRect) {
+    // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
+    auto matrix = mBlurFilter->getShaderMatrix();
+    // 2. Since the blurred surface has the size of the layer, we align it with the
+    // top left corner of the layer position.
+    matrix.postConcat(SkMatrix::Translate(layerRect.fLeft, layerRect.fTop));
+    // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
+    // original surface orientation. The inverse matrix has to be applied to align the blur
+    // surface with the current orientation/position of the canvas.
+    SkMatrix drawInverse;
+    if (canvas->getTotalMatrix().invert(&drawInverse)) {
+        matrix.postConcat(drawInverse);
+    }
+
+    return matrix;
+}
+
 EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
                                                 EGLContext shareContext, bool useContextPriority,
                                                 Protection protection) {