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

Commit ae03cf1f authored by Shan Huang's avatar Shan Huang Committed by Android (Google) Code Review
Browse files

Merge "Split blur into low sample and high sample shaders." into main

parents 3f9ee01a ea74a6ce
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