Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit debda7a7 authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge changes If8778fcd,I37d39d40,I7b41d95e into main

* changes:
  Add benchmark for backdrop blur
  Simplify BackdropFilterDrawable
  Fix backdrop effect for prerotation
parents 41531a0d 2a31d236
Loading
Loading
Loading
Loading
+26 −41
Original line number Diff line number Diff line
@@ -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();
@@ -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
+1 −14
Original line number Diff line number Diff line
@@ -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;
+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);
        }});
+1 −1
Original line number Diff line number Diff line
@@ -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);
+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