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

Commit ea74a6ce authored by Shan Huang's avatar Shan Huang
Browse files

Split blur into low sample and high sample shaders.

Bug: 353826438
Test: atest BlurTests
Flag: com.android.graphics.surfaceflinger.flags.window_blur_kawase2

Change-Id: I5d1a4b34dc6419bd355251153042c0e8d76f8bde
parent 01891635
Loading
Loading
Loading
Loading
+50 −16
Original line number Diff line number Diff line
@@ -39,12 +39,36 @@ namespace renderengine {
namespace skia {

KawaseBlurDualFilter::KawaseBlurDualFilter() : BlurFilter() {
    // A shader to sample each vertex of a unit regular heptagon
    // plus the original fragment coordinate.
    SkString blurString(R"(
    // A shader to sample each vertex of a square, plus the original fragment coordinate,
    // using a total of 5 samples.
    SkString lowSampleBlurString(R"(
        uniform shader child;
        uniform float in_blurOffset;
        uniform float in_crossFade;
        uniform float in_weightedCrossFade;

        const float2 STEP_0 = float2( 0.707106781, 0.707106781);
        const float2 STEP_1 = float2( 0.707106781, -0.707106781);
        const float2 STEP_2 = float2(-0.707106781, -0.707106781);
        const float2 STEP_3 = float2(-0.707106781, 0.707106781);

        half4 main(float2 xy) {
            half3 c = child.eval(xy).rgb;

            c += child.eval(xy + STEP_0 * in_blurOffset).rgb;
            c += child.eval(xy + STEP_1 * in_blurOffset).rgb;
            c += child.eval(xy + STEP_2 * in_blurOffset).rgb;
            c += child.eval(xy + STEP_3 * in_blurOffset).rgb;

            return half4(c * in_weightedCrossFade, in_crossFade);
        }
    )");

    // A shader to sample each vertex of a unit regular heptagon, plus the original fragment
    // coordinate, using a total of 8 samples.
    SkString highSampleBlurString(R"(
        uniform shader child;
        uniform float in_blurOffset;

        const float2 STEP_0 = float2( 1.0, 0.0);
        const float2 STEP_1 = float2( 0.623489802,  0.781831482);
@@ -65,39 +89,46 @@ KawaseBlurDualFilter::KawaseBlurDualFilter() : BlurFilter() {
            c += child.eval(xy + STEP_5 * in_blurOffset).rgb;
            c += child.eval(xy + STEP_6 * in_blurOffset).rgb;

            return half4(c * 0.125 * in_crossFade, in_crossFade);
            return half4(c * 0.125, 1.0);
        }
    )");

    auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
    LOG_ALWAYS_FATAL_IF(!blurEffect, "RuntimeShader error: %s", error.c_str());
    mBlurEffect = std::move(blurEffect);
    auto [lowSampleBlurEffect, error] = SkRuntimeEffect::MakeForShader(lowSampleBlurString);
    auto [highSampleBlurEffect, error2] = SkRuntimeEffect::MakeForShader(highSampleBlurString);
    LOG_ALWAYS_FATAL_IF(!lowSampleBlurEffect, "RuntimeShader error: %s", error.c_str());
    LOG_ALWAYS_FATAL_IF(!highSampleBlurEffect, "RuntimeShader error: %s", error2.c_str());
    mLowSampleBlurEffect = std::move(lowSampleBlurEffect);
    mHighSampleBlurEffect = std::move(highSampleBlurEffect);
}

void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface,
                                    const sk_sp<SkImage>& readImage, const float radius,
                                    const float alpha) const {
                                    const float alpha,
                                    const sk_sp<SkRuntimeEffect>& blurEffect) const {
    const float scale = static_cast<float>(drawSurface->width()) / readImage->width();
    SkMatrix blurMatrix = SkMatrix::Scale(scale, scale);
    blurInto(drawSurface,
             readImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                   SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
                                   blurMatrix),
             readImage->width() / static_cast<float>(drawSurface->width()), radius, alpha);
             radius, alpha, blurEffect);
}

void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface, sk_sp<SkShader> input,
                                    const float inverseScale, const float radius,
                                    const float alpha) const {
                                    const float radius, const float alpha,
                                    const sk_sp<SkRuntimeEffect>& blurEffect) const {
    SkPaint paint;
    if (radius == 0) {
        paint.setShader(std::move(input));
        paint.setAlphaf(alpha);
    } else {
        SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
        SkRuntimeShaderBuilder blurBuilder(blurEffect);
        blurBuilder.child("child") = std::move(input);
        blurBuilder.uniform("in_blurOffset") = radius;
        if (blurEffect == mLowSampleBlurEffect) {
            blurBuilder.uniform("in_crossFade") = alpha;
            blurBuilder.uniform("in_weightedCrossFade") = alpha * 0.2f;
        }
        blurBuilder.uniform("in_blurOffset") = radius;
        paint.setShader(blurBuilder.makeShader(nullptr));
    }
    paint.setBlendMode(alpha == 1.0f ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
@@ -163,16 +194,19 @@ sk_sp<SkImage> KawaseBlurDualFilter::generate(SkiaGpuContext* context, const uin
                input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                  SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
                                  blurMatrix);
        blurInto(surfaces[0], std::move(sourceShader), kInputScale, kWeights[0] * step, 1.0f);
        blurInto(surfaces[0], std::move(sourceShader), kWeights[0] * step, 1.0f,
                 mLowSampleBlurEffect);
    }
    // Next the remaining downscale blur passes.
    for (int i = 0; i < filterPasses; i++) {
        blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f);
        // Blur with the higher sample effect into the smaller buffers, for better visual quality.
        blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f,
                 i == 0 ? mLowSampleBlurEffect : mHighSampleBlurEffect);
    }
    // Finally blur+upscale back to our original size.
    for (int i = filterPasses - 1; i >= 0; i--) {
        blurInto(surfaces[i], surfaces[i + 1]->makeTemporaryImage(), kWeights[4 - i] * step,
                 std::min(1.0f, filterDepth - i));
                 std::min(1.0f, filterDepth - i), mLowSampleBlurEffect);
    }
    return surfaces[0]->makeTemporaryImage();
}
+4 −3
Original line number Diff line number Diff line
@@ -41,13 +41,14 @@ public:
                            const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override;

private:
    sk_sp<SkRuntimeEffect> mBlurEffect;
    sk_sp<SkRuntimeEffect> mLowSampleBlurEffect;
    sk_sp<SkRuntimeEffect> mHighSampleBlurEffect;

    void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkImage>& readImage,
                  const float radius, const float alpha) const;
                  const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;

    void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkShader> input,
                  const float inverseScale, const float radius, const float alpha) const;
                  const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;
};

} // namespace skia