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

Commit 72ef3f3d authored by Derek Sollenberger's avatar Derek Sollenberger Committed by Android (Google) Code Review
Browse files

Merge changes If836461c,I72a9e442 into sc-dev

* changes:
  Add support for crossfading blur with original input.
  Update RenderEngine blur to snap an image of the full surface.
parents 618dcfef 3f77aa46
Loading
Loading
Loading
Loading
+138 −115
Original line number Diff line number Diff line
@@ -286,6 +286,7 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL
    }

    if (args.supportsBackgroundBlur) {
        ALOGD("Background Blurs Enabled");
        mBlurFilter = new BlurFilter();
    }
    mCapture = std::make_unique<SkiaCapture>();
@@ -516,6 +517,45 @@ sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> sh
    return shader;
}

void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
    if (mCapture->isCaptureRunning()) {
        // Record display settings when capture is running.
        std::stringstream displaySettings;
        PrintTo(display, &displaySettings);
        // Store the DisplaySettings in additional information.
        canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
                               SkData::MakeWithCString(displaySettings.str().c_str()));
    }

    // Before doing any drawing, let's make sure that we'll start at the origin of the display.
    // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
    // displays might have different scaling when compared to the physical screen.

    canvas->clipRect(getSkRect(display.physicalDisplay));
    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);

    const auto clipWidth = display.clip.width();
    const auto clipHeight = display.clip.height();
    auto rotatedClipWidth = clipWidth;
    auto rotatedClipHeight = clipHeight;
    // Scale is contingent on the rotation result.
    if (display.orientation & ui::Transform::ROT_90) {
        std::swap(rotatedClipWidth, rotatedClipHeight);
    }
    const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
            static_cast<SkScalar>(rotatedClipWidth);
    const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
            static_cast<SkScalar>(rotatedClipHeight);
    canvas->scale(scaleX, scaleY);

    // Canvas rotation is done by centering the clip window at the origin, rotating, translating
    // back so that the top left corner of the clip is at (0, 0).
    canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
    canvas->rotate(toDegrees(display.orientation));
    canvas->translate(-clipWidth / 2, -clipHeight / 2);
    canvas->translate(-display.clip.left, -display.clip.top);
}

status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                                        const std::vector<const LayerSettings*>& layers,
                                        const sp<GraphicBuffer>& buffer,
@@ -570,57 +610,49 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
        }
    }

    sk_sp<SkSurface> surface =
    sk_sp<SkSurface> dstSurface =
            surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement
                                                                        ? display.outputDataspace
                                                                        : ui::Dataspace::UNKNOWN,
                                                                grContext.get());

    SkCanvas* canvas = mCapture->tryCapture(surface.get());
    if (canvas == nullptr) {
    SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
    if (dstCanvas == nullptr) {
        ALOGE("Cannot acquire canvas from Skia.");
        return BAD_VALUE;
    }
    // Clear the entire canvas with a transparent black to prevent ghost images.
    canvas->clear(SK_ColorTRANSPARENT);
    canvas->save();

    if (mCapture->isCaptureRunning()) {
        // Record display settings when capture is running.
        std::stringstream displaySettings;
        PrintTo(display, &displaySettings);
        // Store the DisplaySettings in additional information.
        canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
                               SkData::MakeWithCString(displaySettings.str().c_str()));
    // Find if any layers have requested blur, we'll use that info to decide when to render to an
    // offscreen buffer and when to render to the native buffer.
    sk_sp<SkSurface> activeSurface(dstSurface);
    SkCanvas* canvas = dstCanvas;
    const LayerSettings* blurCompositionLayer = nullptr;
    if (mBlurFilter) {
        bool requiresCompositionLayer = false;
        for (const auto& layer : layers) {
            if (layer->backgroundBlurRadius > 0) {
                // when skbug.com/11208 and b/176903027 are resolved we can add the additional
                // restriction for layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius
                requiresCompositionLayer = true;
            }
            for (auto region : layer->blurRegions) {
                if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) {
                    requiresCompositionLayer = true;
                }
            }
            if (requiresCompositionLayer) {
                activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
                canvas = activeSurface->getCanvas();
                blurCompositionLayer = layer;
                break;
            }
        }

    // Before doing any drawing, let's make sure that we'll start at the origin of the display.
    // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
    // displays might have different scaling when compared to the physical screen.

    canvas->clipRect(getSkRect(display.physicalDisplay));
    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);

    const auto clipWidth = display.clip.width();
    const auto clipHeight = display.clip.height();
    auto rotatedClipWidth = clipWidth;
    auto rotatedClipHeight = clipHeight;
    // Scale is contingent on the rotation result.
    if (display.orientation & ui::Transform::ROT_90) {
        std::swap(rotatedClipWidth, rotatedClipHeight);
    }
    const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
            static_cast<SkScalar>(rotatedClipWidth);
    const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
            static_cast<SkScalar>(rotatedClipHeight);
    canvas->scale(scaleX, scaleY);

    // Canvas rotation is done by centering the clip window at the origin, rotating, translating
    // back so that the top left corner of the clip is at (0, 0).
    canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
    canvas->rotate(toDegrees(display.orientation));
    canvas->translate(-clipWidth / 2, -clipHeight / 2);
    canvas->translate(-display.clip.left, -display.clip.top);
    canvas->save();
    // Clear the entire canvas with a transparent black to prevent ghost images.
    canvas->clear(SK_ColorTRANSPARENT);
    initCanvas(canvas, display);

    // TODO: clearRegion was required for SurfaceView when a buffer is not yet available but the
    // view is still on-screen. The clear region could be re-specified as a black color layer,
@@ -647,8 +679,36 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,

    for (const auto& layer : layers) {
        ATRACE_NAME("DrawLayer");

        sk_sp<SkImage> blurInput;
        if (blurCompositionLayer == layer) {
            LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
            LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);

            // save a snapshot of the activeSurface to use as input to the blur shaders
            blurInput = activeSurface->makeImageSnapshot();

            // TODO we could skip this step if we know the blur will cover the entire image
            //  blit the offscreen framebuffer into the destination AHB
            SkPaint paint;
            paint.setBlendMode(SkBlendMode::kSrc);
            activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);

            // assign dstCanvas to canvas and ensure that the canvas state is up to date
            canvas = dstCanvas;
            canvas->save();
            initCanvas(canvas, display);

            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
                                dstSurface->getCanvas()->getSaveCount());
            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
                                dstSurface->getCanvas()->getTotalMatrix());

            // assign dstSurface to activeSurface
            activeSurface = dstSurface;
        }

        canvas->save();
        if (mCapture->isCaptureRunning()) {
            // Record the name of the layer if the capture is running.
            std::stringstream layerSettings;
@@ -657,34 +717,42 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
            canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(),
                                   SkData::MakeWithCString(layerSettings.str().c_str()));
        }

        // Layers have a local transform that should be applied to them
        canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());

        SkPaint paint;
        const auto& bounds = layer->geometry.boundaries;
        const auto dest = getSkRect(bounds);
        const auto layerRect = canvas->getTotalMatrix().mapRect(dest);
        const auto bounds = getSkRect(layer->geometry.boundaries);
        if (mBlurFilter && layerHasBlur(layer)) {
            std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
        if (mBlurFilter) {

            // if multiple layers have blur, then we need to take a snapshot now because
            // only the lowest layer will have blurImage populated earlier
            if (!blurInput) {
                blurInput = activeSurface->makeImageSnapshot();
            }
            // rect to be blurred in the coordinate space of blurInput
            const auto blurRect = canvas->getTotalMatrix().mapRect(bounds);

            if (layer->backgroundBlurRadius > 0) {
                ATRACE_NAME("BackgroundBlur");
                auto blurredSurface = mBlurFilter->generate(canvas, surface,
                                                            layer->backgroundBlurRadius, layerRect);
                cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
                auto blurredImage =
                        mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius,
                                              blurInput, blurRect);

                cachedBlurs[layer->backgroundBlurRadius] = blurredImage;

                drawBlurRegion(canvas, getBlurRegion(layer), layerRect, blurredSurface);
                mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect, blurredImage,
                                            blurInput);
            }
            if (layer->blurRegions.size() > 0) {
            for (auto region : layer->blurRegions) {
                    if (cachedBlurs[region.blurRadius]) {
                        continue;
                    }
                if (cachedBlurs[region.blurRadius] != nullptr) {
                    ATRACE_NAME("BlurRegion");
                    auto blurredSurface =
                            mBlurFilter->generate(canvas, surface, region.blurRadius, layerRect);
                    cachedBlurs[region.blurRadius] = blurredSurface;
                    cachedBlurs[region.blurRadius] =
                            mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput,
                                                  blurRect);
                }

                mBlurFilter->drawBlurRegion(canvas, region, blurRect,
                                            cachedBlurs[region.blurRadius], blurInput);
            }
        }

@@ -698,6 +766,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                           : layer->sourceDataspace)
                : ui::Dataspace::UNKNOWN;

        SkPaint paint;
        if (layer->source.buffer.buffer) {
            ATRACE_NAME("DrawImage");
            const auto& item = layer->source.buffer;
@@ -724,7 +793,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
            // textureTansform was intended to be passed directly into a shader, so when
            // building the total matrix with the textureTransform we need to first
            // normalize it, then apply the textureTransform, then scale back up.
            texMatrix.preScale(1.0f / bounds.getWidth(), 1.0f / bounds.getHeight());
            texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
            texMatrix.postScale(image->width(), image->height());

            SkMatrix matrix;
@@ -794,14 +863,10 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,

        paint.setColorFilter(filter);

        for (const auto effectRegion : layer->blurRegions) {
            drawBlurRegion(canvas, effectRegion, layerRect, cachedBlurs[effectRegion.blurRadius]);
        }

        if (layer->shadow.length > 0) {
            const auto rect = layer->geometry.roundedCornersRadius > 0
                    ? getSkRect(layer->geometry.roundedCornersCrop)
                    : dest;
                    : bounds;
            drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
        } else {
            // Shadows are assumed to live only on their own layer - it's not valid
@@ -812,7 +877,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
            if (layer->geometry.roundedCornersRadius > 0) {
                canvas->clipRRect(getRoundedRect(layer), true);
            }
            canvas->drawRect(dest, paint);
            canvas->drawRect(bounds, paint);
        }
        canvas->restore();
    }
@@ -820,7 +885,8 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
    mCapture->endCapture();
    {
        ATRACE_NAME("flush surface");
        surface->flush();
        LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
        activeSurface->flush();
    }

    if (drawFence != nullptr) {
@@ -877,6 +943,10 @@ inline BlurRegion SkiaGLRenderEngine::getBlurRegion(const LayerSettings* layer)
                      .bottom = static_cast<int>(rect.fBottom)};
}

inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer) {
    return layer->backgroundBlurRadius > 0 || layer->blurRegions.size();
}

inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
    return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
}
@@ -916,53 +986,6 @@ void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect,
                              flags);
}

void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
                                        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);
    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,
                                 effectRegion.bottom);

    if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
        effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
        const SkVector radii[4] =
                {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
                 SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
                 SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
                 SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
        SkRRect roundedRect;
        roundedRect.setRectRadii(rect, radii);
        canvas->drawRRect(roundedRect, paint);
    } else {
        canvas->drawRect(rect, paint);
    }
}

SkMatrix SkiaGLRenderEngine::getBlurShaderTransform(const SkCanvas* canvas,
                                                    const SkRect& layerRect) {
    // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
    auto matrix = mBlurFilter->getShaderMatrix();
    // 2. Since the blurred surface has the size of the layer, we align it with the
    // top left corner of the layer position.
    matrix.postConcat(SkMatrix::Translate(layerRect.fLeft, layerRect.fTop));
    // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
    // original surface orientation. The inverse matrix has to be applied to align the blur
    // surface with the current orientation/position of the canvas.
    SkMatrix drawInverse;
    if (canvas->getTotalMatrix().invert(&drawInverse)) {
        matrix.postConcat(drawInverse);
    }

    return matrix;
}

EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
                                                EGLContext shareContext,
                                                std::optional<ContextPriority> contextPriority,
+2 −3
Original line number Diff line number Diff line
@@ -81,17 +81,16 @@ private:
    inline SkRect getSkRect(const Rect& layer);
    inline SkRRect getRoundedRect(const LayerSettings* layer);
    inline BlurRegion getBlurRegion(const LayerSettings* layer);
    inline bool layerHasBlur(const LayerSettings* layer);
    inline SkColor getSkColor(const vec4& color);
    inline SkM44 getSkM44(const mat4& matrix);
    inline SkPoint3 getSkPoint3(const vec3& vector);

    base::unique_fd flush();
    bool waitFence(base::unique_fd fenceFd);
    void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
    void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
                    const ShadowSettings& shadowSettings);
    void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
                        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.
    sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings* layer,
+107 −24

File changed.

Preview size limit exceeded, changes collapsed.

+7 −4
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <SkImage.h>
#include <SkRuntimeEffect.h>
#include <SkSurface.h>
#include <ui/BlurRegion.h>

using namespace std;

@@ -48,13 +49,15 @@ public:
    virtual ~BlurFilter(){};

    // Execute blur, saving it to a texture
    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;
    sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
                            const sk_sp<SkImage> blurInput, const SkRect& blurRect) const;

    void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& blurRect,
                        sk_sp<SkImage> blurredImage, sk_sp<SkImage> input);

private:
    sk_sp<SkRuntimeEffect> mBlurEffect;
    sk_sp<SkRuntimeEffect> mMixEffect;
};

} // namespace skia
+7 −4
Original line number Diff line number Diff line
@@ -950,15 +950,18 @@ void RenderEngineTest::fillBufferAndBlurBackground() {
    blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
    blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
    blurLayer.backgroundBlurRadius = blurRadius;
    SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
    blurLayer.alpha = 0;
    layers.push_back(&blurLayer);

    invokeDraw(settings, layers);

    expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
                      50 /* tolerance */);
    expectBufferColor(Rect(center, center - 5, center + 1, center + 5), 150, 150, 0, 255,
                      50 /* tolerance */);
    // solid color
    expectBufferColor(Rect(0, 0, 1, 1), 255, 0, 0, 255, 0 /* tolerance */);

    // blurred color (downsampling should result in the center color being close to 128)
    expectBufferColor(Rect(center - 1, center - 5, center + 1, center + 5), 128, 128, 0, 255,
                      10 /* tolerance */);
}

template <typename SourceVariant>