Loading libs/renderengine/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,8 @@ filegroup { "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/GaussianBlurFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", "skia/filters/StretchShaderFactory.cpp" Loading libs/renderengine/skia/SkiaGLRenderEngine.cpp +3 −2 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/GaussianBlurFilter.h" #include "filters/KawaseBlurFilter.h" #include "filters/LinearEffect.h" #include "log/log_main.h" Loading Loading @@ -804,11 +805,11 @@ void SkiaGLRenderEngine::drawLayersInternal( continue; } if (layer.backgroundBlurRadius > 0 && layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) { requiresCompositionLayer = true; } for (auto region : layer.blurRegions) { if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) { if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) { requiresCompositionLayer = true; } } Loading libs/renderengine/skia/filters/BlurFilter.cpp 0 → 100644 +124 −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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "BlurFilter.h" #include <SkCanvas.h> #include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> #include <SkSize.h> #include <SkString.h> #include <SkSurface.h> #include <log/log.h> #include <utils/Trace.h> namespace android { namespace renderengine { namespace skia { static sk_sp<SkRuntimeEffect> createMixEffect() { SkString mixString(R"( uniform shader blurredInput; uniform shader originalInput; uniform float mixFactor; half4 main(float2 xy) { return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor)); } )"); auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString); if (!mixEffect) { LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str()); } return mixEffect; } static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, const float scale) { // 1. Apply the blur shader matrix, which scales up the blurred surface to its real size auto matrix = SkMatrix::Scale(scale, scale); // 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(blurRect.fLeft, blurRect.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 != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) { matrix.postConcat(drawInverse); } return matrix; } BlurFilter::BlurFilter(const float maxCrossFadeRadius) : mMaxCrossFadeRadius(maxCrossFadeRadius), mMixEffect(maxCrossFadeRadius > 0 ? createMixEffect() : nullptr) {} float BlurFilter::getMaxCrossFadeRadius() const { return mMaxCrossFadeRadius; } void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) { ATRACE_CALL(); SkPaint paint; paint.setAlphaf(blurAlpha); const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale); SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone); const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, &blurMatrix); if (blurRadius < mMaxCrossFadeRadius) { // For sampling Skia's API expects the inverse of what logically seems appropriate. In this // case you might expect the matrix to simply be the canvas matrix. SkMatrix inputMatrix; if (!canvas->getTotalMatrix().invert(&inputMatrix)) { ALOGE("matrix was unable to be inverted"); } SkRuntimeShaderBuilder blurBuilder(mMixEffect); blurBuilder.child("blurredInput") = blurShader; blurBuilder.child("originalInput") = input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, inputMatrix); blurBuilder.uniform("mixFactor") = blurRadius / mMaxCrossFadeRadius; paint.setShader(blurBuilder.makeShader(nullptr, true)); } else { paint.setShader(blurShader); } if (effectRegion.isRect()) { if (blurAlpha == 1.0f) { paint.setBlendMode(SkBlendMode::kSrc); } canvas->drawRect(effectRegion.rect(), paint); } else { paint.setAntiAlias(true); canvas->drawRRect(effectRegion, paint); } } } // namespace skia } // namespace renderengine } // namespace android libs/renderengine/skia/filters/BlurFilter.h +13 −6 Original line number Diff line number Diff line Loading @@ -33,11 +33,8 @@ public: static constexpr float kInputScale = 0.25f; // Downsample scale factor used to improve performance static constexpr float kInverseInputScale = 1.0f / kInputScale; // 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(){} explicit BlurFilter(float maxCrossFadeRadius = 10.0f); virtual ~BlurFilter(){} // Execute blur, saving it to a texture Loading @@ -54,10 +51,20 @@ 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 */ virtual void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, 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; sk_sp<SkImage> input); float getMaxCrossFadeRadius() const; private: // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. const float mMaxCrossFadeRadius; // Optional blend used for crossfade only if mMaxCrossFadeRadius > 0 const sk_sp<SkRuntimeEffect> mMixEffect; }; } // namespace skia Loading libs/renderengine/skia/filters/GaussianBlurFilter.cpp 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "GaussianBlurFilter.h" #include <SkCanvas.h> #include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> #include <SkImageFilters.h> #include <SkSize.h> #include <SkString.h> #include <SkSurface.h> #include <log/log.h> #include <utils/Trace.h> namespace android { namespace renderengine { namespace skia { // This constant approximates the scaling done in the software path's // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). static const float BLUR_SIGMA_SCALE = 0.57735f; GaussianBlurFilter::GaussianBlurFilter(): BlurFilter(/* maxCrossFadeRadius= */ 0.0f) {} sk_sp<SkImage> GaussianBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, const sk_sp<SkImage> input, const SkRect& blurRect) const { // Create blur surface with the bit depth and colorspace of the original surface SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), std::ceil(blurRect.height() * kInputScale)); sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, scaledInfo); SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); paint.setImageFilter(SkImageFilters::Blur( blurRadius * kInputScale * BLUR_SIGMA_SCALE, blurRadius * kInputScale * BLUR_SIGMA_SCALE, SkTileMode::kClamp, nullptr)); surface->getCanvas()->drawImageRect( input, blurRect, SkRect::MakeWH(scaledInfo.width(), scaledInfo.height()), SkSamplingOptions{SkFilterMode::kLinear, SkMipmapMode::kNone}, &paint, SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint); return surface->makeImageSnapshot(); } } // namespace skia } // namespace renderengine } // namespace android Loading
libs/renderengine/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,8 @@ filegroup { "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/GaussianBlurFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", "skia/filters/StretchShaderFactory.cpp" Loading
libs/renderengine/skia/SkiaGLRenderEngine.cpp +3 −2 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/GaussianBlurFilter.h" #include "filters/KawaseBlurFilter.h" #include "filters/LinearEffect.h" #include "log/log_main.h" Loading Loading @@ -804,11 +805,11 @@ void SkiaGLRenderEngine::drawLayersInternal( continue; } if (layer.backgroundBlurRadius > 0 && layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) { requiresCompositionLayer = true; } for (auto region : layer.blurRegions) { if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) { if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) { requiresCompositionLayer = true; } } Loading
libs/renderengine/skia/filters/BlurFilter.cpp 0 → 100644 +124 −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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "BlurFilter.h" #include <SkCanvas.h> #include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> #include <SkSize.h> #include <SkString.h> #include <SkSurface.h> #include <log/log.h> #include <utils/Trace.h> namespace android { namespace renderengine { namespace skia { static sk_sp<SkRuntimeEffect> createMixEffect() { SkString mixString(R"( uniform shader blurredInput; uniform shader originalInput; uniform float mixFactor; half4 main(float2 xy) { return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor)); } )"); auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString); if (!mixEffect) { LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str()); } return mixEffect; } static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, const float scale) { // 1. Apply the blur shader matrix, which scales up the blurred surface to its real size auto matrix = SkMatrix::Scale(scale, scale); // 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(blurRect.fLeft, blurRect.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 != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) { matrix.postConcat(drawInverse); } return matrix; } BlurFilter::BlurFilter(const float maxCrossFadeRadius) : mMaxCrossFadeRadius(maxCrossFadeRadius), mMixEffect(maxCrossFadeRadius > 0 ? createMixEffect() : nullptr) {} float BlurFilter::getMaxCrossFadeRadius() const { return mMaxCrossFadeRadius; } void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius, const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage, sk_sp<SkImage> input) { ATRACE_CALL(); SkPaint paint; paint.setAlphaf(blurAlpha); const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale); SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone); const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, &blurMatrix); if (blurRadius < mMaxCrossFadeRadius) { // For sampling Skia's API expects the inverse of what logically seems appropriate. In this // case you might expect the matrix to simply be the canvas matrix. SkMatrix inputMatrix; if (!canvas->getTotalMatrix().invert(&inputMatrix)) { ALOGE("matrix was unable to be inverted"); } SkRuntimeShaderBuilder blurBuilder(mMixEffect); blurBuilder.child("blurredInput") = blurShader; blurBuilder.child("originalInput") = input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling, inputMatrix); blurBuilder.uniform("mixFactor") = blurRadius / mMaxCrossFadeRadius; paint.setShader(blurBuilder.makeShader(nullptr, true)); } else { paint.setShader(blurShader); } if (effectRegion.isRect()) { if (blurAlpha == 1.0f) { paint.setBlendMode(SkBlendMode::kSrc); } canvas->drawRect(effectRegion.rect(), paint); } else { paint.setAntiAlias(true); canvas->drawRRect(effectRegion, paint); } } } // namespace skia } // namespace renderengine } // namespace android
libs/renderengine/skia/filters/BlurFilter.h +13 −6 Original line number Diff line number Diff line Loading @@ -33,11 +33,8 @@ public: static constexpr float kInputScale = 0.25f; // Downsample scale factor used to improve performance static constexpr float kInverseInputScale = 1.0f / kInputScale; // 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(){} explicit BlurFilter(float maxCrossFadeRadius = 10.0f); virtual ~BlurFilter(){} // Execute blur, saving it to a texture Loading @@ -54,10 +51,20 @@ 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 */ virtual void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, 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; sk_sp<SkImage> input); float getMaxCrossFadeRadius() const; private: // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. const float mMaxCrossFadeRadius; // Optional blend used for crossfade only if mMaxCrossFadeRadius > 0 const sk_sp<SkRuntimeEffect> mMixEffect; }; } // namespace skia Loading
libs/renderengine/skia/filters/GaussianBlurFilter.cpp 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. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "GaussianBlurFilter.h" #include <SkCanvas.h> #include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> #include <SkImageFilters.h> #include <SkSize.h> #include <SkString.h> #include <SkSurface.h> #include <log/log.h> #include <utils/Trace.h> namespace android { namespace renderengine { namespace skia { // This constant approximates the scaling done in the software path's // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). static const float BLUR_SIGMA_SCALE = 0.57735f; GaussianBlurFilter::GaussianBlurFilter(): BlurFilter(/* maxCrossFadeRadius= */ 0.0f) {} sk_sp<SkImage> GaussianBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, const sk_sp<SkImage> input, const SkRect& blurRect) const { // Create blur surface with the bit depth and colorspace of the original surface SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), std::ceil(blurRect.height() * kInputScale)); sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, scaledInfo); SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); paint.setImageFilter(SkImageFilters::Blur( blurRadius * kInputScale * BLUR_SIGMA_SCALE, blurRadius * kInputScale * BLUR_SIGMA_SCALE, SkTileMode::kClamp, nullptr)); surface->getCanvas()->drawImageRect( input, blurRect, SkRect::MakeWH(scaledInfo.width(), scaledInfo.height()), SkSamplingOptions{SkFilterMode::kLinear, SkMipmapMode::kNone}, &paint, SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint); return surface->makeImageSnapshot(); } } // namespace skia } // namespace renderengine } // namespace android