Loading libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp +26 −41 Original line number Diff line number Diff line Loading @@ -29,37 +29,6 @@ namespace android { namespace uirenderer { namespace skiapipeline { BackdropFilterDrawable::~BackdropFilterDrawable() {} bool BackdropFilterDrawable::prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth, int backdropImageHeight) { // the drawing bounds for blurred content. mDstBounds.setWH(properties.getWidth(), properties.getHeight()); float alphaMultiplier = 1.0f; RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true); // get proper subset for previous content. canvas->getTotalMatrix().mapRect(&mImageSubset, mDstBounds); SkRect imageSubset(mImageSubset); // ensure the subset is inside bounds of previous content. if (!mImageSubset.intersect(SkRect::MakeWH(backdropImageWidth, backdropImageHeight))) { return false; } // correct the drawing bounds if subset was changed. if (mImageSubset != imageSubset) { SkMatrix inverse; if (canvas->getTotalMatrix().invert(&inverse)) { inverse.mapRect(&mDstBounds, mImageSubset); } } // follow the alpha from the target RenderNode. mPaint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier); return true; } void BackdropFilterDrawable::onDraw(SkCanvas* canvas) { const RenderProperties& properties = mTargetRenderNode->properties(); auto* backdropFilter = properties.layerProperties().getBackdropImageFilter(); Loading @@ -68,27 +37,43 @@ void BackdropFilterDrawable::onDraw(SkCanvas* canvas) { return; } auto backdropImage = surface->makeImageSnapshot(); // sync necessary properties from target RenderNode. if (!prepareToDraw(canvas, properties, backdropImage->width(), backdropImage->height())) { SkRect srcBounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight()); float alphaMultiplier = 1.0f; RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true); SkPaint paint; paint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier); SkRect surfaceSubset; canvas->getTotalMatrix().mapRect(&surfaceSubset, srcBounds); if (!surfaceSubset.intersect(SkRect::MakeWH(surface->width(), surface->height()))) { return; } auto imageSubset = mImageSubset.roundOut(); auto backdropImage = surface->makeImageSnapshot(surfaceSubset.roundOut()); SkIRect imageBounds = SkIRect::MakeWH(backdropImage->width(), backdropImage->height()); SkIPoint offset; SkIRect imageSubset; #ifdef __ANDROID__ if (canvas->recordingContext()) { backdropImage = SkImages::MakeWithFilter(canvas->recordingContext(), backdropImage, backdropFilter, imageSubset, imageSubset, &mOutSubset, &mOutOffset); imageBounds, imageBounds, &imageSubset, &offset); } else #endif { backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageSubset, imageSubset, &mOutSubset, &mOutOffset); backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageBounds, imageBounds, &imageSubset, &offset); } canvas->drawImageRect(backdropImage, SkRect::Make(mOutSubset), mDstBounds, SkSamplingOptions(SkFilterMode::kLinear), &mPaint, SkCanvas::kStrict_SrcRectConstraint); canvas->save(); canvas->resetMatrix(); canvas->drawImageRect(backdropImage, SkRect::Make(imageSubset), surfaceSubset, SkSamplingOptions(SkFilterMode::kLinear), &paint, SkCanvas::kFast_SrcRectConstraint); canvas->restore(); } } // namespace skiapipeline Loading libs/hwui/pipeline/skia/BackdropFilterDrawable.h +1 −14 Original line number Diff line number Diff line Loading @@ -37,23 +37,10 @@ public: BackdropFilterDrawable(RenderNode* renderNode, SkCanvas* canvas) : mTargetRenderNode(renderNode), mBounds(canvas->getLocalClipBounds()) {} ~BackdropFilterDrawable(); ~BackdropFilterDrawable() = default; private: RenderNode* mTargetRenderNode; SkPaint mPaint; SkRect mDstBounds; SkRect mImageSubset; SkIRect mOutSubset; SkIPoint mOutOffset; /** * Check all necessary properties before actual drawing. * Return true if ready to draw. */ bool prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth, int backdropImageHeight); protected: void onDraw(SkCanvas* canvas) override; Loading libs/hwui/tests/common/scenes/BackdropBlur.cpp 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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. */ #include <SkBlendMode.h> #include "SkImageFilter.h" #include "SkImageFilters.h" #include "TestSceneBase.h" #include "utils/Blur.h" class BackdropBlurAnimation : public TestScene { private: std::unique_ptr<TestScene> listView; public: explicit BackdropBlurAnimation(const TestScene::Options& opts) { listView.reset(TestScene::testMap()["listview"].createScene(opts)); } void createContent(int width, int height, Canvas& canvas) override { sp<RenderNode> list = TestUtils::createNode( 0, 0, width, height, [this, width, height](RenderProperties& props, Canvas& canvas) { props.setClipToBounds(false); listView->createContent(width, height, canvas); }); canvas.drawRenderNode(list.get()); int x = width / 8; int y = height / 4; sp<RenderNode> blurNode = TestUtils::createNode( x, y, width - x, height - y, [](RenderProperties& props, Canvas& canvas) { props.mutableOutline().setRoundRect(0, 0, props.getWidth(), props.getHeight(), dp(16), 1); props.mutableOutline().setShouldClip(true); sk_sp<SkImageFilter> blurFilter = SkImageFilters::Blur( Blur::convertRadiusToSigma(dp(8)), Blur::convertRadiusToSigma(dp(8)), SkTileMode::kClamp, nullptr, nullptr); props.mutateLayerProperties().setBackdropImageFilter(blurFilter.get()); canvas.drawColor(0x33000000, SkBlendMode::kSrcOver); }); canvas.drawRenderNode(blurNode.get()); } void doFrame(int frameNr) override { listView->doFrame(frameNr); } }; static TestScene::Registrar _BackdropBlur(TestScene::Info{ "backdropblur", "A rounded rect that does a blur-behind of a sky animation.", [](const TestScene::Options& opts) -> test::TestScene* { return new BackdropBlurAnimation(opts); }}); libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -1280,7 +1280,7 @@ RENDERTHREAD_TEST(BackdropFilterDrawable, drawing) { canvas->drawDrawable(&backdropDrawable); // the drawable is still visible, ok to draw. EXPECT_EQ(2, canvas->mDrawCounter); EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH - 30, CANVAS_HEIGHT - 30), canvas->mDstBounds); EXPECT_EQ(SkRect::MakeLTRB(30, 30, CANVAS_WIDTH, CANVAS_HEIGHT), canvas->mDstBounds); canvas->translate(CANVAS_WIDTH, CANVAS_HEIGHT); canvas->drawDrawable(&drawable); Loading tests/graphics/SilkFX/res/layout/view_blur_behind.xml 0 → 100644 +148 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2024 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. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="I'm a little teapot" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="Something. Something." /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="I'm a little teapot" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="Something. Something." /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" /> </LinearLayout> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <View android:layout_width="match_parent" android:layout_height="300dp" /> <com.android.test.silkfx.materials.BlurBehindContainer android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#33AAAAAA" android:padding="32dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="48dp" android:text="Blur!" /> </com.android.test.silkfx.materials.BlurBehindContainer> <View android:layout_width="match_parent" android:layout_height="1024dp" /> </LinearLayout> </ScrollView> </FrameLayout> No newline at end of file Loading
libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp +26 −41 Original line number Diff line number Diff line Loading @@ -29,37 +29,6 @@ namespace android { namespace uirenderer { namespace skiapipeline { BackdropFilterDrawable::~BackdropFilterDrawable() {} bool BackdropFilterDrawable::prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth, int backdropImageHeight) { // the drawing bounds for blurred content. mDstBounds.setWH(properties.getWidth(), properties.getHeight()); float alphaMultiplier = 1.0f; RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true); // get proper subset for previous content. canvas->getTotalMatrix().mapRect(&mImageSubset, mDstBounds); SkRect imageSubset(mImageSubset); // ensure the subset is inside bounds of previous content. if (!mImageSubset.intersect(SkRect::MakeWH(backdropImageWidth, backdropImageHeight))) { return false; } // correct the drawing bounds if subset was changed. if (mImageSubset != imageSubset) { SkMatrix inverse; if (canvas->getTotalMatrix().invert(&inverse)) { inverse.mapRect(&mDstBounds, mImageSubset); } } // follow the alpha from the target RenderNode. mPaint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier); return true; } void BackdropFilterDrawable::onDraw(SkCanvas* canvas) { const RenderProperties& properties = mTargetRenderNode->properties(); auto* backdropFilter = properties.layerProperties().getBackdropImageFilter(); Loading @@ -68,27 +37,43 @@ void BackdropFilterDrawable::onDraw(SkCanvas* canvas) { return; } auto backdropImage = surface->makeImageSnapshot(); // sync necessary properties from target RenderNode. if (!prepareToDraw(canvas, properties, backdropImage->width(), backdropImage->height())) { SkRect srcBounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight()); float alphaMultiplier = 1.0f; RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true); SkPaint paint; paint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier); SkRect surfaceSubset; canvas->getTotalMatrix().mapRect(&surfaceSubset, srcBounds); if (!surfaceSubset.intersect(SkRect::MakeWH(surface->width(), surface->height()))) { return; } auto imageSubset = mImageSubset.roundOut(); auto backdropImage = surface->makeImageSnapshot(surfaceSubset.roundOut()); SkIRect imageBounds = SkIRect::MakeWH(backdropImage->width(), backdropImage->height()); SkIPoint offset; SkIRect imageSubset; #ifdef __ANDROID__ if (canvas->recordingContext()) { backdropImage = SkImages::MakeWithFilter(canvas->recordingContext(), backdropImage, backdropFilter, imageSubset, imageSubset, &mOutSubset, &mOutOffset); imageBounds, imageBounds, &imageSubset, &offset); } else #endif { backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageSubset, imageSubset, &mOutSubset, &mOutOffset); backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageBounds, imageBounds, &imageSubset, &offset); } canvas->drawImageRect(backdropImage, SkRect::Make(mOutSubset), mDstBounds, SkSamplingOptions(SkFilterMode::kLinear), &mPaint, SkCanvas::kStrict_SrcRectConstraint); canvas->save(); canvas->resetMatrix(); canvas->drawImageRect(backdropImage, SkRect::Make(imageSubset), surfaceSubset, SkSamplingOptions(SkFilterMode::kLinear), &paint, SkCanvas::kFast_SrcRectConstraint); canvas->restore(); } } // namespace skiapipeline Loading
libs/hwui/pipeline/skia/BackdropFilterDrawable.h +1 −14 Original line number Diff line number Diff line Loading @@ -37,23 +37,10 @@ public: BackdropFilterDrawable(RenderNode* renderNode, SkCanvas* canvas) : mTargetRenderNode(renderNode), mBounds(canvas->getLocalClipBounds()) {} ~BackdropFilterDrawable(); ~BackdropFilterDrawable() = default; private: RenderNode* mTargetRenderNode; SkPaint mPaint; SkRect mDstBounds; SkRect mImageSubset; SkIRect mOutSubset; SkIPoint mOutOffset; /** * Check all necessary properties before actual drawing. * Return true if ready to draw. */ bool prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth, int backdropImageHeight); protected: void onDraw(SkCanvas* canvas) override; Loading
libs/hwui/tests/common/scenes/BackdropBlur.cpp 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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. */ #include <SkBlendMode.h> #include "SkImageFilter.h" #include "SkImageFilters.h" #include "TestSceneBase.h" #include "utils/Blur.h" class BackdropBlurAnimation : public TestScene { private: std::unique_ptr<TestScene> listView; public: explicit BackdropBlurAnimation(const TestScene::Options& opts) { listView.reset(TestScene::testMap()["listview"].createScene(opts)); } void createContent(int width, int height, Canvas& canvas) override { sp<RenderNode> list = TestUtils::createNode( 0, 0, width, height, [this, width, height](RenderProperties& props, Canvas& canvas) { props.setClipToBounds(false); listView->createContent(width, height, canvas); }); canvas.drawRenderNode(list.get()); int x = width / 8; int y = height / 4; sp<RenderNode> blurNode = TestUtils::createNode( x, y, width - x, height - y, [](RenderProperties& props, Canvas& canvas) { props.mutableOutline().setRoundRect(0, 0, props.getWidth(), props.getHeight(), dp(16), 1); props.mutableOutline().setShouldClip(true); sk_sp<SkImageFilter> blurFilter = SkImageFilters::Blur( Blur::convertRadiusToSigma(dp(8)), Blur::convertRadiusToSigma(dp(8)), SkTileMode::kClamp, nullptr, nullptr); props.mutateLayerProperties().setBackdropImageFilter(blurFilter.get()); canvas.drawColor(0x33000000, SkBlendMode::kSrcOver); }); canvas.drawRenderNode(blurNode.get()); } void doFrame(int frameNr) override { listView->doFrame(frameNr); } }; static TestScene::Registrar _BackdropBlur(TestScene::Info{ "backdropblur", "A rounded rect that does a blur-behind of a sky animation.", [](const TestScene::Options& opts) -> test::TestScene* { return new BackdropBlurAnimation(opts); }});
libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -1280,7 +1280,7 @@ RENDERTHREAD_TEST(BackdropFilterDrawable, drawing) { canvas->drawDrawable(&backdropDrawable); // the drawable is still visible, ok to draw. EXPECT_EQ(2, canvas->mDrawCounter); EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH - 30, CANVAS_HEIGHT - 30), canvas->mDstBounds); EXPECT_EQ(SkRect::MakeLTRB(30, 30, CANVAS_WIDTH, CANVAS_HEIGHT), canvas->mDstBounds); canvas->translate(CANVAS_WIDTH, CANVAS_HEIGHT); canvas->drawDrawable(&drawable); Loading
tests/graphics/SilkFX/res/layout/view_blur_behind.xml 0 → 100644 +148 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2024 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. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="I'm a little teapot" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="Something. Something." /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="I'm a little teapot" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="Something. Something." /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" android:textSize="24dp" android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" /> </LinearLayout> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <View android:layout_width="match_parent" android:layout_height="300dp" /> <com.android.test.silkfx.materials.BlurBehindContainer android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#33AAAAAA" android:padding="32dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="48dp" android:text="Blur!" /> </com.android.test.silkfx.materials.BlurBehindContainer> <View android:layout_width="match_parent" android:layout_height="1024dp" /> </LinearLayout> </ScrollView> </FrameLayout> No newline at end of file