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

Commit 8635f10b authored by Lucas Dupin's avatar Lucas Dupin Committed by Android (Google) Code Review
Browse files

Merge "Port background blurs to SkiaRE"

parents 1728a550 f4cb4a00
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ filegroup {
    srcs: [
        "skia/SkiaRenderEngine.cpp",
        "skia/SkiaGLRenderEngine.cpp",
        "skia/filters/BlurFilter.cpp",
    ],
}

+15 −4
Original line number Diff line number Diff line
@@ -29,12 +29,14 @@
#include <utils/Trace.h>
#include "../gl/GLExtensions.h"
#include "SkiaGLRenderEngine.h"
#include "filters/BlurFilter.h"

#include <GrContextOptions.h>
#include <gl/GrGLInterface.h>

#include <SkCanvas.h>
#include <SkImage.h>
#include <SkImageFilters.h>
#include <SkShadowUtils.h>
#include <SkSurface.h>

@@ -194,7 +196,7 @@ std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create(

    // initialize the renderer while GL is current
    std::unique_ptr<SkiaGLRenderEngine> engine =
            std::make_unique<SkiaGLRenderEngine>(display, config, ctxt, placeholder,
            std::make_unique<SkiaGLRenderEngine>(args, display, config, ctxt, placeholder,
                                                 protectedContext, protectedPlaceholder);

    ALOGI("OpenGL ES informations:");
@@ -247,9 +249,9 @@ EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bo
    return config;
}

SkiaGLRenderEngine::SkiaGLRenderEngine(EGLDisplay display, EGLConfig config, EGLContext ctxt,
                                       EGLSurface placeholder, EGLContext protectedContext,
                                       EGLSurface protectedPlaceholder)
SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
                                       EGLConfig config, EGLContext ctxt, EGLSurface placeholder,
                                       EGLContext protectedContext, EGLSurface protectedPlaceholder)
      : mEGLDisplay(display),
        mEGLConfig(config),
        mEGLContext(ctxt),
@@ -273,6 +275,10 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(EGLDisplay display, EGLConfig config, EGL
    options.fPreferExternalImagesOverES3 = true;
    options.fDisableDistanceFieldPaths = true;
    mGrContext = GrDirectContext::MakeGL(std::move(glInterface), options);

    if (args.supportsBackgroundBlur) {
        mBlurFilter = new BlurFilter();
    }
}

base::unique_fd SkiaGLRenderEngine::flush() {
@@ -408,6 +414,11 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
        const auto& bounds = layer->geometry.boundaries;
        const auto dest = getSkRect(bounds);

        if (layer->backgroundBlurRadius > 0) {
            ATRACE_NAME("BackgroundBlur");
            mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
        }

        if (layer->source.buffer.buffer) {
            ATRACE_NAME("DrawImage");
            const auto& item = layer->source.buffer;
+4 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <SkSurface.h>

#include "SkiaRenderEngine.h"
#include "filters/BlurFilter.h"

namespace android {
namespace renderengine {
@@ -36,8 +37,8 @@ namespace skia {
class SkiaGLRenderEngine : public skia::SkiaRenderEngine {
public:
    static std::unique_ptr<SkiaGLRenderEngine> create(const RenderEngineCreationArgs& args);
    SkiaGLRenderEngine(EGLDisplay display, EGLConfig config, EGLContext ctxt,
                       EGLSurface placeholder, EGLContext protectedContext,
    SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config,
                       EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext,
                       EGLSurface protectedPlaceholder);
    ~SkiaGLRenderEngine() override{};

@@ -78,6 +79,7 @@ private:
    EGLSurface mPlaceholderSurface;
    EGLContext mProtectedEGLContext;
    EGLSurface mProtectedPlaceholderSurface;
    BlurFilter* mBlurFilter = nullptr;

    // Cache of GL images that we'll store per GraphicBuffer ID
    std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex);
+133 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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 "BlurFilter.h"
#include <SkCanvas.h>
#include <SkData.h>
#include <SkPaint.h>
#include <SkRuntimeEffect.h>
#include <SkSize.h>
#include <SkString.h>
#include <SkSurface.h>
#include <log/log.h>
#include <utils/Trace.h>

namespace android {
namespace renderengine {
namespace skia {

BlurFilter::BlurFilter() {
    SkString blurString(R"(
        in shader input;
        uniform float in_inverseScale;
        uniform float2 in_blurOffset;

        half4 main(float2 xy) {
            float2 scaled_xy = float2(xy.x * in_inverseScale, xy.y * in_inverseScale);

            float4 c = float4(sample(input, scaled_xy));
            c += float4(sample(input, scaled_xy + float2( in_blurOffset.x,  in_blurOffset.y)));
            c += float4(sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y)));
            c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x,  in_blurOffset.y)));
            c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y)));

            return half4(c.rgb * 0.2, 1.0);
        }
    )");

    auto [blurEffect, error] = SkRuntimeEffect::Make(blurString);
    if (!blurEffect) {
        LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
    }
    mBlurEffect = std::move(blurEffect);
}

void BlurFilter::draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t blurRadius) const {
    ATRACE_CALL();
    // Kawase is an approximation of Gaussian, but it behaves differently from it.
    // A radius transformation is required for approximating them, and also to introduce
    // non-integer steps, necessary to smoothly interpolate large radii.
    float tmpRadius = (float)blurRadius / 6.0f;
    float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
    float radiusByPasses = tmpRadius / (float)numberOfPasses;

    SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)input->width() * kInputScale,
                                                        (float)input->height() * kInputScale);
    auto drawSurface = canvas->makeSurface(scaledInfo);

    const float stepX = radiusByPasses;
    const float stepY = radiusByPasses;

    // start by drawing and downscaling and doing the first blur pass
    SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
    blurBuilder.child("input") = input->makeImageSnapshot()->makeShader();
    blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
    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()->drawIRect(scaledInfo.bounds(), 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);

        for (auto i = 1; i < numberOfPasses; i++) {
            const float stepScale = (float)i * kInputScale;

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

            SkPaint paint;
            paint.setShader(blurBuilder.makeShader(nullptr, false));
            paint.setFilterQuality(kLow_SkFilterQuality);
            drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);

            // Swap buffers for next iteration
            auto tmp = drawSurface;
            drawSurface = readSurface;
            readSurface = tmp;
            blurBuilder.child("input") = nullptr;
        }
        lastDrawTarget = readSurface;
    }

    drawSurface->flushAndSubmit();

    // do the final composition, with alpha blending to hide downscaling artifacts.
    {
        SkPaint paint;
        paint.setShader(lastDrawTarget->makeImageSnapshot()->makeShader(
                SkMatrix::MakeScale(kInverseInputScale)));
        paint.setFilterQuality(kLow_SkFilterQuality);
        paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
        canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
    }
}

} // namespace skia
} // namespace renderengine
} // namespace android
 No newline at end of file
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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.
 */

#pragma once

#include <SkCanvas.h>
#include <SkImage.h>
#include <SkRuntimeEffect.h>
#include <SkSurface.h>

using namespace std;

namespace android {
namespace renderengine {
namespace skia {

/**
 * This is an implementation of a Kawase blur, as described in here:
 * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/
 * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf
 */
class BlurFilter {
public:
    // Downsample FBO to improve performance
    static constexpr float kInputScale = 0.25f;
    // Downsample scale factor used to improve performance
    static constexpr float kInverseInputScale = 1.0f / kInputScale;
    // Maximum number of render passes
    static constexpr uint32_t kMaxPasses = 4;
    // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
    // image, up to this radius.
    static constexpr float kMaxCrossFadeRadius = 30.0f;

    explicit BlurFilter();
    virtual ~BlurFilter(){};

    // Execute blur passes, rendering to a canvas.
    void draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t radius) const;

private:
    sk_sp<SkRuntimeEffect> mBlurEffect;
};

} // namespace skia
} // namespace renderengine
} // namespace android