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) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index f5eed1e..ef06bfa 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -77,15 +77,15 @@
inline BlurRegion getBlurRegion(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();
bool waitFence(base::unique_fd fenceFd);
void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
const ShadowSettings& shadowSettings);
- void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion,
- const SkMatrix& drawTransform, sk_sp<SkSurface> blurrendSurface);
+ void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
+ sk_sp<SkSurface> blurredSurface);
+ SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
EGLDisplay mEGLDisplay;
EGLContext mEGLContext;
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index f19b64a..151d2ae 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -66,11 +66,10 @@
float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
float radiusByPasses = tmpRadius / (float)numberOfPasses;
- SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)input->width() * kInputScale,
- (float)input->height() * kInputScale);
+ SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)rect.width() * kInputScale,
+ (float)rect.height() * kInputScale);
+ SkRect scaledRect = SkRect::MakeWH(scaledInfo.width(), scaledInfo.height());
- SkRect scaledRect = {rect.fLeft * kInputScale, rect.fTop * kInputScale,
- rect.fRight * kInputScale, rect.fBottom * kInputScale};
auto drawSurface = canvas->makeSurface(scaledInfo);
const float stepX = radiusByPasses;
@@ -80,7 +79,8 @@
SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
blurBuilder.child("input") =
- input->makeImageSnapshot()->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
+ input->makeImageSnapshot(rect.round())
+ ->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
blurBuilder.uniform("in_blurOffset") =
SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};