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

Commit 545ec44c authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

Improve RenderEngine's blur performance.

This CL uses new Skia APIs to skip the unnecessary glClear issued when
creating the temporary surfaces. On a Pixel 5 device this showed an
~6% improvement in total GPU time as well as a similar improvement on
the CPU time taken by Skia to isssue the calls to the GPU.

Test: perfetto traces
Bug: 176903027
Change-Id: If04b795ce44107670e9e752b10ab5470393e1e32
parent f0bcc77d
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -593,6 +593,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
    // view is still on-screen. The clear region could be re-specified as a black color layer,
    // however.
    if (!display.clearRegion.isEmpty()) {
        ATRACE_NAME("ClearRegion");
        size_t numRects = 0;
        Rect const* rects = display.clearRegion.getArray(&numRects);
        SkIRect skRects[numRects];
@@ -612,6 +613,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
    }

    for (const auto& layer : layers) {
        ATRACE_NAME("DrawLayer");
        canvas->save();

        if (mCapture->isCaptureRunning()) {
@@ -630,7 +632,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
        const auto& bounds = layer->geometry.boundaries;
        const auto dest = getSkRect(bounds);
        const auto layerRect = canvas->getTotalMatrix().mapRect(dest);
        std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
        std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
        if (mBlurFilter) {
            if (layer->backgroundBlurRadius > 0) {
                ATRACE_NAME("BackgroundBlur");
@@ -882,16 +884,14 @@ void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect,
}

void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
                                        const SkRect& layerRect, sk_sp<SkSurface> blurredSurface) {
                                        const SkRect& layerRect, sk_sp<SkImage> blurredImage) {
    ATRACE_CALL();

    SkPaint paint;
    paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
    const auto matrix = getBlurShaderTransform(canvas, layerRect);
    paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(
            SkTileMode::kClamp,
            SkTileMode::kClamp,
            SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}),
    SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
    paint.setShader(blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
                                             &matrix));

    auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ private:
    void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
                    const ShadowSettings& shadowSettings);
    void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
                        sk_sp<SkSurface> blurredSurface);
                        sk_sp<SkImage> blurredImage);
    SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
    // If mUseColorManagement is correct and layer needsLinearEffect, it returns a linear runtime
    // shader. Otherwise it returns the input shader.
+14 −46
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ BlurFilter::BlurFilter() {
    mBlurEffect = std::move(blurEffect);
}

sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
sk_sp<SkImage> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
                                    const uint32_t blurRadius, SkRect rect) const {
    // Kawase is an approximation of Gaussian, but it behaves differently from it.
    // A radius transformation is required for approximating them, and also to introduce
@@ -68,9 +68,6 @@ sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> i

    SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)rect.width() * kInputScale,
                                                        (float)rect.height() * kInputScale);
    SkRect scaledRect = SkRect::MakeWH(scaledInfo.width(), scaledInfo.height());

    auto drawSurface = canvas->makeSurface(scaledInfo);

    const float stepX = radiusByPasses;
    const float stepY = radiusByPasses;
@@ -85,49 +82,20 @@ sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> i
    blurBuilder.uniform("in_blurOffset") =
            SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};

    {
        // limit the lifetime of the input surface's snapshot to ensure that it goes out of
        // scope before the surface is written into to avoid any copy-on-write behavior.
        SkPaint paint;
        paint.setShader(blurBuilder.makeShader(nullptr, false));
        paint.setFilterQuality(kLow_SkFilterQuality);

        drawSurface->getCanvas()->drawRect(scaledRect, paint);

        blurBuilder.child("input") = nullptr;
    }

    // And now we'll ping pong between our surfaces, to accumulate the result of various offsets.
    auto lastDrawTarget = drawSurface;
    if (numberOfPasses > 1) {
        auto readSurface = drawSurface;
        drawSurface = canvas->makeSurface(scaledInfo);
    sk_sp<SkImage> tmpBlur(
            blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false));

    // And now we'll build our chain of scaled blur stages
    blurBuilder.uniform("in_inverseScale") = 1.0f;
    for (auto i = 1; i < numberOfPasses; i++) {
        const float stepScale = (float)i * kInputScale;

        blurBuilder.child("input") =
                    readSurface->makeImageSnapshot()->makeShader(SkTileMode::kClamp,
                                                                 SkTileMode::kClamp, linear);
            blurBuilder.uniform("in_inverseScale") = 1.0f;
                tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
        blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};

            SkPaint paint;
            paint.setShader(blurBuilder.makeShader(nullptr, false));
            paint.setFilterQuality(kLow_SkFilterQuality);

            drawSurface->getCanvas()->drawRect(scaledRect, paint);

            // Swap buffers for next iteration
            const auto tmp = drawSurface;
            drawSurface = readSurface;
            readSurface = tmp;
            blurBuilder.child("input") = nullptr;
        }
        lastDrawTarget = readSurface;
        tmpBlur = blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false);
    }

    return lastDrawTarget;
    return tmpBlur;
}

SkMatrix BlurFilter::getShaderMatrix() const {
+2 −2
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ public:
    virtual ~BlurFilter(){};

    // Execute blur, saving it to a texture
    sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
    sk_sp<SkImage> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
                            SkRect rect) const;
    // Returns a matrix that should be applied to the blur shader
    SkMatrix getShaderMatrix() const;