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

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

Merge "Multi-layer blur support"

parents a4860009 a6f8e13c
Loading
Loading
Loading
Loading
+25 −13
Original line number Diff line number Diff line
@@ -984,18 +984,19 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
    }

    std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
    // Let's find the topmost layer requesting background blur (if any.)
    // Blurs in multiple layers are not supported, given the cost of the shader.
    const LayerSettings* blurLayer = nullptr;
    // Gathering layers that requested blur, we'll need them to decide when to render to an
    // offscreen buffer, and when to render to the native buffer.
    std::deque<const LayerSettings*> blurLayers;
    if (CC_LIKELY(mBlurFilter != nullptr)) {
        for (auto const layer : layers) {
        for (auto layer : layers) {
            if (layer->backgroundBlurRadius > 0) {
                blurLayer = layer;
                blurLayers.push_back(layer);
            }
        }
    }
    const auto blurLayersSize = blurLayers.size();

    if (blurLayer == nullptr) {
    if (blurLayersSize == 0) {
        fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, useFramebufferCache);
        if (fbo->getStatus() != NO_ERROR) {
            ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
@@ -1006,7 +1007,8 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
        setViewportAndProjection(display.physicalDisplay, display.clip);
    } else {
        setViewportAndProjection(display.physicalDisplay, display.clip);
        auto status = mBlurFilter->setAsDrawTarget(display, blurLayer->backgroundBlurRadius);
        auto status =
                mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius);
        if (status != NO_ERROR) {
            ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
                  buffer->handle);
@@ -1039,7 +1041,9 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
                        .setCropCoords(2 /* size */)
                        .build();
    for (auto const layer : layers) {
        if (blurLayer == layer) {
        if (blurLayers.size() > 0 && blurLayers.front() == layer) {
            blurLayers.pop_front();

            auto status = mBlurFilter->prepare();
            if (status != NO_ERROR) {
                ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
@@ -1048,18 +1052,26 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
                return status;
            }

            if (blurLayers.size() == 0) {
                // Done blurring, time to bind the native FBO and render our blur onto it.
                fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer,
                                                                      useFramebufferCache);
                status = fbo->getStatus();
                setViewportAndProjection(display.physicalDisplay, display.clip);
            } else {
                // There's still something else to blur, so let's keep rendering to our FBO
                // instead of to the display.
                status = mBlurFilter->setAsDrawTarget(display,
                                                      blurLayers.front()->backgroundBlurRadius);
            }
            if (status != NO_ERROR) {
                ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
                      buffer->handle);
                checkErrors("Can't bind native framebuffer");
                return status;
            }
            setViewportAndProjection(display.physicalDisplay, display.clip);

            status = mBlurFilter->render();
            status = mBlurFilter->render(blurLayersSize > 1);
            if (status != NO_ERROR) {
                ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
                      buffer->handle);
+6 −2
Original line number Diff line number Diff line
@@ -96,13 +96,17 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) {
    mEngine.checkErrors("Drawing blur mesh");
}

status_t BlurFilter::render() {
status_t BlurFilter::render(bool multiPass) {
    ATRACE_NAME("BlurFilter::render");

    // Now let's scale our blur up. It will be interpolated with the larger composited
    // texture for the first frames, to hide downscaling artifacts.
    GLfloat mix = fmin(1.0, mRadius / kMaxCrossFadeRadius);
    if (mix >= 1) {

    // When doing multiple passes, we cannot try to read mCompositionFbo, given that we'll
    // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer,
    // as large as the screen size.
    if (mix >= 1 || multiPass) {
        mBlurredFbo.bindAsReadBuffer();
        glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0,
                          mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+1 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ public:
    // Execute blur passes, rendering to offscreen texture.
    virtual status_t prepare() = 0;
    // Render blur to the bound framebuffer (screen).
    status_t render();
    status_t render(bool multiPass);

protected:
    uint32_t mRadius;
+42 −0
Original line number Diff line number Diff line
@@ -279,6 +279,48 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadius) {
                      50 /* tolerance */);
}

TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusOnMultipleLayers) {
    char value[PROPERTY_VALUE_MAX];
    property_get("ro.surface_flinger.supports_background_blur", value, "0");
    if (!atoi(value)) {
        // This device doesn't support blurs, no-op.
        return;
    }

    auto size = 256;
    auto center = size / 2;
    auto blurRadius = 50;

    sp<SurfaceControl> backgroundLayer;
    ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
    ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));

    sp<SurfaceControl> leftLayer;
    ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
    ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));

    sp<SurfaceControl> blurLayer1;
    auto centralSquareSize = size / 2;
    ASSERT_NO_FATAL_FAILURE(blurLayer1 =
                                    createLayer("blur1", centralSquareSize, centralSquareSize));
    ASSERT_NO_FATAL_FAILURE(
            fillLayerColor(blurLayer1, Color::BLUE, centralSquareSize, centralSquareSize));

    sp<SurfaceControl> blurLayer2;
    ASSERT_NO_FATAL_FAILURE(blurLayer2 = createLayer("blur2", size, size));
    ASSERT_NO_FATAL_FAILURE(
            fillLayerColor(blurLayer2, Color::TRANSPARENT, centralSquareSize, centralSquareSize));

    Transaction()
            .setBackgroundBlurRadius(blurLayer1, blurRadius)
            .setBackgroundBlurRadius(blurLayer2, blurRadius)
            .apply();

    auto shot = getScreenCapture();
    shot->expectColor(Rect(center - 5, center - 5, center, center), Color{100, 100, 100, 255},
                      40 /* tolerance */);
}

TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
    sp<SurfaceControl> bufferLayer;
    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));