Loading libs/renderengine/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -93,7 +93,7 @@ filegroup { "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", "skia/filters/StretchShaderFactory.cpp" ], Loading libs/renderengine/skia/SkiaGLRenderEngine.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ #include "SkBlendMode.h" #include "SkImageInfo.h" #include "filters/BlurFilter.h" #include "filters/KawaseBlurFilter.h" #include "filters/LinearEffect.h" #include "log/log_main.h" #include "skia/debug/SkiaCapture.h" Loading Loading @@ -328,7 +329,7 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL if (args.supportsBackgroundBlur) { ALOGD("Background Blurs Enabled"); mBlurFilter = new BlurFilter(); mBlurFilter = new KawaseBlurFilter(); } mCapture = std::make_unique<SkiaCapture>(); } Loading libs/renderengine/skia/filters/BlurFilter.h +8 −18 Original line number Diff line number Diff line Loading @@ -27,29 +27,22 @@ namespace android { namespace renderengine { namespace skia { /** * This is an implementation of a Kawase blur, as described in here: * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf */ class BlurFilter { public: // Downsample FBO to improve performance static constexpr float kInputScale = 0.25f; // Downsample scale factor used to improve performance static constexpr float kInverseInputScale = 1.0f / kInputScale; // Maximum number of render passes static constexpr uint32_t kMaxPasses = 4; // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. static constexpr float kMaxCrossFadeRadius = 10.0f; explicit BlurFilter(); virtual ~BlurFilter(){}; explicit BlurFilter(){} virtual ~BlurFilter(){} // Execute blur, saving it to a texture sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius, const sk_sp<SkImage> blurInput, const SkRect& blurRect) const; virtual sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius, const sk_sp<SkImage> blurInput, const SkRect& blurRect) const = 0; /** * Draw the blurred content (from the generate method) into the canvas. Loading @@ -61,13 +54,10 @@ public: * @param blurredImage down-sampled blurred content that was produced by the generate() method * @param input original unblurred input that is used to crossfade with the blurredImage */ void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input); private: sk_sp<SkRuntimeEffect> mBlurEffect; sk_sp<SkRuntimeEffect> mMixEffect; virtual void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) = 0; }; } // namespace skia Loading libs/renderengine/skia/filters/BlurFilter.cpp→libs/renderengine/skia/filters/KawaseBlurFilter.cpp +14 −27 Original line number Diff line number Diff line /* * Copyright 2020 The Android Open Source Project * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -16,7 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "BlurFilter.h" #include "KawaseBlurFilter.h" #include <SkCanvas.h> #include <SkData.h> #include <SkPaint.h> Loading @@ -32,23 +32,17 @@ namespace android { namespace renderengine { namespace skia { BlurFilter::BlurFilter() { KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { SkString blurString(R"( uniform shader child; uniform float2 in_blurOffset; uniform float2 in_maxSizeXY; uniform float in_blurOffset; half4 main(float2 xy) { half4 c = child.eval(xy); c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset)); c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset)); c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset)); c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset)); return half4(c.rgb * 0.2, 1.0); } )"); Loading Loading @@ -76,8 +70,9 @@ BlurFilter::BlurFilter() { mMixEffect = std::move(mixEffect); } sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, const sk_sp<SkImage> input, const SkRect& blurRect) const { sk_sp<SkImage> KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, const sk_sp<SkImage> input, const SkRect& blurRect) 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. Loading @@ -89,9 +84,6 @@ sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), std::ceil(blurRect.height() * kInputScale)); const float stepX = radiusByPasses; const float stepY = radiusByPasses; // For sampling Skia's API expects the inverse of what logically seems appropriate. In this // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale) // but instead we must do the inverse. Loading @@ -103,20 +95,15 @@ sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t SkRuntimeShaderBuilder blurBuilder(mBlurEffect); blurBuilder.child("child") = input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix); blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale}; blurBuilder.uniform("in_maxSizeXY") = SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale; sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false)); // And now we'll build our chain of scaled blur stages for (auto i = 1; i < numberOfPasses; i++) { const float stepScale = (float)i * kInputScale; blurBuilder.child("child") = tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale}; blurBuilder.uniform("in_maxSizeXY") = SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale; tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false); } Loading @@ -139,7 +126,7 @@ static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRec return matrix; } void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, void KawaseBlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) { Loading libs/renderengine/skia/filters/KawaseBlurFilter.h 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "BlurFilter.h" #include <SkCanvas.h> #include <SkImage.h> #include <SkRuntimeEffect.h> #include <SkSurface.h> using namespace std; namespace android { namespace renderengine { namespace skia { /** * This is an implementation of a Kawase blur, as described in here: * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf */ class KawaseBlurFilter: public BlurFilter { public: // Maximum number of render passes static constexpr uint32_t kMaxPasses = 4; explicit KawaseBlurFilter(); virtual ~KawaseBlurFilter(){} // Execute blur, saving it to a texture sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius, const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override; /** * Draw the blurred content (from the generate method) into the canvas. * @param canvas is the destination/output for the blur * @param effectRegion the RoundRect in canvas coordinates that determines the blur coverage * @param blurRadius radius of the blur used to determine the intensity of the crossfade effect * @param blurAlpha alpha value applied to the effectRegion when the blur is drawn * @param blurRect bounds of the blurredImage translated into canvas coordinates * @param blurredImage down-sampled blurred content that was produced by the generate() method * @param input original unblurred input that is used to crossfade with the blurredImage */ void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) override; private: sk_sp<SkRuntimeEffect> mBlurEffect; sk_sp<SkRuntimeEffect> mMixEffect; }; } // namespace skia } // namespace renderengine } // namespace android Loading
libs/renderengine/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -93,7 +93,7 @@ filegroup { "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", "skia/filters/StretchShaderFactory.cpp" ], Loading
libs/renderengine/skia/SkiaGLRenderEngine.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ #include "SkBlendMode.h" #include "SkImageInfo.h" #include "filters/BlurFilter.h" #include "filters/KawaseBlurFilter.h" #include "filters/LinearEffect.h" #include "log/log_main.h" #include "skia/debug/SkiaCapture.h" Loading Loading @@ -328,7 +329,7 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL if (args.supportsBackgroundBlur) { ALOGD("Background Blurs Enabled"); mBlurFilter = new BlurFilter(); mBlurFilter = new KawaseBlurFilter(); } mCapture = std::make_unique<SkiaCapture>(); } Loading
libs/renderengine/skia/filters/BlurFilter.h +8 −18 Original line number Diff line number Diff line Loading @@ -27,29 +27,22 @@ namespace android { namespace renderengine { namespace skia { /** * This is an implementation of a Kawase blur, as described in here: * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf */ class BlurFilter { public: // Downsample FBO to improve performance static constexpr float kInputScale = 0.25f; // Downsample scale factor used to improve performance static constexpr float kInverseInputScale = 1.0f / kInputScale; // Maximum number of render passes static constexpr uint32_t kMaxPasses = 4; // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. static constexpr float kMaxCrossFadeRadius = 10.0f; explicit BlurFilter(); virtual ~BlurFilter(){}; explicit BlurFilter(){} virtual ~BlurFilter(){} // Execute blur, saving it to a texture sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius, const sk_sp<SkImage> blurInput, const SkRect& blurRect) const; virtual sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius, const sk_sp<SkImage> blurInput, const SkRect& blurRect) const = 0; /** * Draw the blurred content (from the generate method) into the canvas. Loading @@ -61,13 +54,10 @@ public: * @param blurredImage down-sampled blurred content that was produced by the generate() method * @param input original unblurred input that is used to crossfade with the blurredImage */ void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input); private: sk_sp<SkRuntimeEffect> mBlurEffect; sk_sp<SkRuntimeEffect> mMixEffect; virtual void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) = 0; }; } // namespace skia Loading
libs/renderengine/skia/filters/BlurFilter.cpp→libs/renderengine/skia/filters/KawaseBlurFilter.cpp +14 −27 Original line number Diff line number Diff line /* * Copyright 2020 The Android Open Source Project * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -16,7 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "BlurFilter.h" #include "KawaseBlurFilter.h" #include <SkCanvas.h> #include <SkData.h> #include <SkPaint.h> Loading @@ -32,23 +32,17 @@ namespace android { namespace renderengine { namespace skia { BlurFilter::BlurFilter() { KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { SkString blurString(R"( uniform shader child; uniform float2 in_blurOffset; uniform float2 in_maxSizeXY; uniform float in_blurOffset; half4 main(float2 xy) { half4 c = child.eval(xy); c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x), clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y))); c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset)); c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset)); c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset)); c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset)); return half4(c.rgb * 0.2, 1.0); } )"); Loading Loading @@ -76,8 +70,9 @@ BlurFilter::BlurFilter() { mMixEffect = std::move(mixEffect); } sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, const sk_sp<SkImage> input, const SkRect& blurRect) const { sk_sp<SkImage> KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, const sk_sp<SkImage> input, const SkRect& blurRect) 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. Loading @@ -89,9 +84,6 @@ sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), std::ceil(blurRect.height() * kInputScale)); const float stepX = radiusByPasses; const float stepY = radiusByPasses; // For sampling Skia's API expects the inverse of what logically seems appropriate. In this // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale) // but instead we must do the inverse. Loading @@ -103,20 +95,15 @@ sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t SkRuntimeShaderBuilder blurBuilder(mBlurEffect); blurBuilder.child("child") = input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix); blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale}; blurBuilder.uniform("in_maxSizeXY") = SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale; sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false)); // And now we'll build our chain of scaled blur stages for (auto i = 1; i < numberOfPasses; i++) { const float stepScale = (float)i * kInputScale; blurBuilder.child("child") = tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale}; blurBuilder.uniform("in_maxSizeXY") = SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale}; blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale; tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false); } Loading @@ -139,7 +126,7 @@ static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRec return matrix; } void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, void KawaseBlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) { Loading
libs/renderengine/skia/filters/KawaseBlurFilter.h 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "BlurFilter.h" #include <SkCanvas.h> #include <SkImage.h> #include <SkRuntimeEffect.h> #include <SkSurface.h> using namespace std; namespace android { namespace renderengine { namespace skia { /** * This is an implementation of a Kawase blur, as described in here: * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf */ class KawaseBlurFilter: public BlurFilter { public: // Maximum number of render passes static constexpr uint32_t kMaxPasses = 4; explicit KawaseBlurFilter(); virtual ~KawaseBlurFilter(){} // Execute blur, saving it to a texture sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius, const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override; /** * Draw the blurred content (from the generate method) into the canvas. * @param canvas is the destination/output for the blur * @param effectRegion the RoundRect in canvas coordinates that determines the blur coverage * @param blurRadius radius of the blur used to determine the intensity of the crossfade effect * @param blurAlpha alpha value applied to the effectRegion when the blur is drawn * @param blurRect bounds of the blurredImage translated into canvas coordinates * @param blurredImage down-sampled blurred content that was produced by the generate() method * @param input original unblurred input that is used to crossfade with the blurredImage */ void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) override; private: sk_sp<SkRuntimeEffect> mBlurEffect; sk_sp<SkRuntimeEffect> mMixEffect; }; } // namespace skia } // namespace renderengine } // namespace android