Implement blur region in RenderEngine
Blur regions should be be piped through SurfaceFlinger
all the way down to the compositor, in order to render
blurs.
It's also necessary to cache them if multiple regions require
the same blur radius.
Test: manual
Test: atest SurfaceInterceptor_test
Test: atest OutputUpdateAndWriteCompositionStateTest
Bug: 159712515
Change-Id: Id4759f65eb2522a80e9328062fe641fe29786a30
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 69ad189..03c8e80 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -23,6 +23,14 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
+#include <sync/sync.h>
+#include <ui/BlurRegion.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+#include "../gl/GLExtensions.h"
+#include "SkiaGLRenderEngine.h"
+#include "filters/BlurFilter.h"
+
#include <GrContextOptions.h>
#include <SkCanvas.h>
#include <SkColorFilter.h>
@@ -500,10 +508,25 @@
SkPaint paint;
const auto& bounds = layer->geometry.boundaries;
const auto dest = getSkRect(bounds);
+ std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
- if (layer->backgroundBlurRadius > 0) {
- ATRACE_NAME("BackgroundBlur");
- mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+ if (mBlurFilter) {
+ if (layer->backgroundBlurRadius > 0) {
+ ATRACE_NAME("BackgroundBlur");
+ auto blurredSurface =
+ mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+ cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
+ }
+ if (layer->blurRegions.size() > 0) {
+ for (auto region : layer->blurRegions) {
+ if (cachedBlurs[region.blurRadius]) {
+ continue;
+ }
+ ATRACE_NAME("BlurRegion");
+ auto blurredSurface = mBlurFilter->generate(canvas, surface, region.blurRadius);
+ cachedBlurs[region.blurRadius] = blurredSurface;
+ }
+ }
}
if (layer->source.buffer.buffer) {
@@ -571,7 +594,11 @@
} else {
ATRACE_NAME("DrawColor");
const auto color = layer->source.solidColor;
- paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
+ paint.setShader(SkShaders::Color(SkColor4f{.fR = color.r,
+ .fG = color.g,
+ .fB = color.b,
+ layer->alpha},
+ nullptr));
}
paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
@@ -580,6 +607,10 @@
canvas->save();
canvas->concat(getSkM44(layer->geometry.positionTransform));
+ for (const auto effectRegion : layer->blurRegions) {
+ drawBlurRegion(canvas, effectRegion, dest, cachedBlurs[effectRegion.blurRadius]);
+ }
+
if (layer->shadow.length > 0) {
const auto rect = layer->geometry.roundedCornersRadius > 0
? getSkRect(layer->geometry.roundedCornersCrop)
@@ -592,6 +623,7 @@
} else {
canvas->drawRect(dest, paint);
}
+
canvas->restore();
}
{
@@ -678,6 +710,34 @@
flags);
}
+void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
+ const SkRect& layerBoundaries,
+ sk_sp<SkSurface> blurredSurface) {
+ ATRACE_CALL();
+ SkPaint paint;
+ paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
+ const auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+ effectRegion.bottom);
+
+ const auto matrix = mBlurFilter->getShaderMatrix(
+ SkMatrix::MakeTrans(layerBoundaries.left(), layerBoundaries.top()));
+ paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(matrix));
+
+ if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
+ effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
+ const SkVector radii[4] =
+ {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
+ SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
+ SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
+ SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
+ SkRRect roundedRect;
+ roundedRect.setRectRadii(rect, radii);
+ canvas->drawRRect(roundedRect, paint);
+ } else {
+ canvas->drawRect(rect, paint);
+ }
+}
+
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 ed4ba11..0143445 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -75,6 +75,8 @@
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 SkRect& layerBounds,
+ sk_sp<SkSurface> blurrendSurface);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 8704b3a..f6a316f 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -55,8 +55,10 @@
mBlurEffect = std::move(blurEffect);
}
-void BlurFilter::draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t blurRadius) const {
+sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t blurRadius) const {
ATRACE_CALL();
+
// 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.
@@ -111,25 +113,35 @@
drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
// Swap buffers for next iteration
- auto tmp = drawSurface;
+ const auto tmp = drawSurface;
drawSurface = readSurface;
readSurface = tmp;
blurBuilder.child("input") = nullptr;
}
lastDrawTarget = readSurface;
}
+ lastDrawTarget->flushAndSubmit();
+ return lastDrawTarget;
+}
- drawSurface->flushAndSubmit();
+sk_sp<SkSurface> BlurFilter::draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t blurRadius) const {
+ ATRACE_CALL();
+ auto surface = generate(canvas, input, blurRadius);
- // do the final composition, with alpha blending to hide downscaling artifacts.
- {
- SkPaint paint;
- paint.setShader(lastDrawTarget->makeImageSnapshot()->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);
- }
+ 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);
+ return surface;
+}
+
+SkMatrix BlurFilter::getShaderMatrix(const SkMatrix& transformMatrix) const {
+ SkMatrix matrix;
+ matrix.setConcat(transformMatrix, SkMatrix::MakeScale(kInverseInputScale));
+ return matrix;
}
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 94b3673..6f973d7 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -47,8 +47,14 @@
explicit BlurFilter();
virtual ~BlurFilter(){};
- // Execute blur passes, rendering to a canvas.
- void draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t radius) const;
+ // Execute blur, saving it to a texture
+ sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+ const uint32_t radius) 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;
+ // Returns a matrix that should be applied to the blur shader
+ SkMatrix getShaderMatrix(const SkMatrix& transformMatrix) const;
private:
sk_sp<SkRuntimeEffect> mBlurEffect;