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

Commit 1474775d authored by Derek Sollenberger's avatar Derek Sollenberger Committed by Automerger Merge Worker
Browse files

Merge "Update RenderEngine to properly respect the roundRectCrop." into sc-dev...

Merge "Update RenderEngine to properly respect the roundRectCrop." into sc-dev am: 03fd6277 am: 6f9016e9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/14356543

Change-Id: I36799bdd0c421203ef2b569da9d1610a9923266b
parents 591994a8 6f9016e9
Loading
Loading
Loading
Loading
+103 −29
Original line number Original line Diff line number Diff line
@@ -667,6 +667,17 @@ void drawStretch(const SkRect& bounds, const StretchEffect& stretchEffect,
    canvas->drawRect(stretchBounds, paint);
    canvas->drawRect(stretchBounds, paint);
}
}


static SkRRect getBlurRRect(const BlurRegion& region) {
    const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom);
    const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL),
                               SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR),
                               SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR),
                               SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)};
    SkRRect roundedRect;
    roundedRect.setRectRadii(rect, radii);
    return roundedRect;
}

status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                                        const std::vector<const LayerSettings*>& layers,
                                        const std::vector<const LayerSettings*>& layers,
                                        const std::shared_ptr<ExternalTexture>& buffer,
                                        const std::shared_ptr<ExternalTexture>& buffer,
@@ -840,7 +851,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
        // Layers have a local transform that should be applied to them
        // Layers have a local transform that should be applied to them
        canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
        canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());


        const auto bounds = getSkRect(layer->geometry.boundaries);
        const auto [bounds, roundRectClip] = getBoundsAndClip(layer);
        if (mBlurFilter && layerHasBlur(layer)) {
        if (mBlurFilter && layerHasBlur(layer)) {
            std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
            std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;


@@ -850,7 +861,14 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                blurInput = activeSurface->makeImageSnapshot();
                blurInput = activeSurface->makeImageSnapshot();
            }
            }
            // rect to be blurred in the coordinate space of blurInput
            // rect to be blurred in the coordinate space of blurInput
            const auto blurRect = canvas->getTotalMatrix().mapRect(bounds);
            const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect());

            // if the clip needs to be applied then apply it now and make sure
            // it is restored before we attempt to draw any shadows.
            SkAutoCanvasRestore acr(canvas, true);
            if (!roundRectClip.isEmpty()) {
                canvas->clipRRect(roundRectClip, true);
            }


            // TODO(b/182216890): Filter out empty layers earlier
            // TODO(b/182216890): Filter out empty layers earlier
            if (blurRect.width() > 0 && blurRect.height() > 0) {
            if (blurRect.width() > 0 && blurRect.height() > 0) {
@@ -862,10 +880,10 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,


                    cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
                    cachedBlurs[layer->backgroundBlurRadius] = blurredImage;


                    mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect,
                    mBlurFilter->drawBlurRegion(canvas, bounds, layer->backgroundBlurRadius, 1.0f,
                                                blurredImage, blurInput);
                                                blurRect, blurredImage, blurInput);
                }
                }
                SkAutoCanvasRestore acr(canvas, true);

                canvas->concat(getSkM44(layer->blurRegionTransform).asM33());
                canvas->concat(getSkM44(layer->blurRegionTransform).asM33());
                for (auto region : layer->blurRegions) {
                for (auto region : layer->blurRegions) {
                    if (cachedBlurs[region.blurRadius] == nullptr) {
                    if (cachedBlurs[region.blurRadius] == nullptr) {
@@ -875,7 +893,8 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                                                      blurRect);
                                                      blurRect);
                    }
                    }


                    mBlurFilter->drawBlurRegion(canvas, region, blurRect,
                    mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius,
                                                region.alpha, blurRect,
                                                cachedBlurs[region.blurRadius], blurInput);
                                                cachedBlurs[region.blurRadius], blurInput);
                }
                }
            }
            }
@@ -888,7 +907,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
        if (layer->shadow.length > 0) {
        if (layer->shadow.length > 0) {
            const auto rect = layer->geometry.roundedCornersRadius > 0
            const auto rect = layer->geometry.roundedCornersRadius > 0
                    ? getSkRect(layer->geometry.roundedCornersCrop)
                    ? getSkRect(layer->geometry.roundedCornersCrop)
                    : bounds;
                    : bounds.rect();
            // This would require a new parameter/flag to SkShadowUtils::DrawShadow
            // This would require a new parameter/flag to SkShadowUtils::DrawShadow
            LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow");
            LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow");
            drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
            drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
@@ -953,7 +972,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
            // The shader does not respect the translation, so we add it to the texture
            // The shader does not respect the translation, so we add it to the texture
            // transform for the SkImage. This will make sure that the correct layer contents
            // transform for the SkImage. This will make sure that the correct layer contents
            // are drawn in the correct part of the screen.
            // are drawn in the correct part of the screen.
            matrix.postTranslate(layer->geometry.boundaries.left, layer->geometry.boundaries.top);
            matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop);


            sk_sp<SkShader> shader;
            sk_sp<SkShader> shader;


@@ -1015,9 +1034,13 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,


        paint.setColorFilter(displayColorTransform);
        paint.setColorFilter(displayColorTransform);


        if (layer->geometry.roundedCornersRadius > 0) {
        if (!roundRectClip.isEmpty()) {
            canvas->clipRRect(roundRectClip, true);
        }

        if (!bounds.isRect()) {
            paint.setAntiAlias(true);
            paint.setAntiAlias(true);
            canvas->drawRRect(getRoundedRect(layer), paint);
            canvas->drawRRect(bounds, paint);
        } else {
        } else {
            auto& stretchEffect = layer->stretchEffect;
            auto& stretchEffect = layer->stretchEffect;
            // TODO (njawad) temporarily disable manipulation of geometry
            // TODO (njawad) temporarily disable manipulation of geometry
@@ -1026,9 +1049,9 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
            // Keep the method call in a dead code path to make -Werror happy
            // Keep the method call in a dead code path to make -Werror happy
            // with unused methods
            // with unused methods
            if (stretchEffect.hasEffect() && /* DISABLES CODE */ (false)) {
            if (stretchEffect.hasEffect() && /* DISABLES CODE */ (false)) {
                drawStretch(bounds, stretchEffect, canvas, paint);
                drawStretch(bounds.rect(), stretchEffect, canvas, paint);
            } else {
            } else {
                canvas->drawRect(bounds, paint);
                canvas->drawRect(bounds.rect(), paint);
            }
            }
        }
        }
        if (kFlushAfterEveryLayer) {
        if (kFlushAfterEveryLayer) {
@@ -1077,25 +1100,76 @@ inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) {
    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
}
}


inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) {
inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(
    const auto rect = getSkRect(layer->geometry.roundedCornersCrop);
        const LayerSettings* layer) {
    const auto bounds = getSkRect(layer->geometry.boundaries);
    const auto crop = getSkRect(layer->geometry.roundedCornersCrop);
    const auto cornerRadius = layer->geometry.roundedCornersRadius;
    const auto cornerRadius = layer->geometry.roundedCornersRadius;
    return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);

}
    SkRRect clip;

    if (cornerRadius > 0) {
inline BlurRegion SkiaGLRenderEngine::getBlurRegion(const LayerSettings* layer) {
        // it the crop and the bounds are equivalent then we don't need a clip
    const auto rect = getSkRect(layer->geometry.boundaries);
        if (bounds == crop) {
    const auto cornersRadius = layer->geometry.roundedCornersRadius;
            return {SkRRect::MakeRectXY(bounds, cornerRadius, cornerRadius), clip};
    return BlurRegion{.blurRadius = static_cast<uint32_t>(layer->backgroundBlurRadius),
        }
                      .cornerRadiusTL = cornersRadius,

                      .cornerRadiusTR = cornersRadius,
        // This makes an effort to speed up common, simple bounds + clip combinations by
                      .cornerRadiusBL = cornersRadius,
        // converting them to a single RRect draw. It is possible there are other cases
                      .cornerRadiusBR = cornersRadius,
        // that can be converted.
                      .alpha = 1,
        if (crop.contains(bounds)) {
                      .left = static_cast<int>(rect.fLeft),
            bool intersectionIsRoundRect = true;
                      .top = static_cast<int>(rect.fTop),
            // check each cropped corner to ensure that it exactly matches the crop or is full
                      .right = static_cast<int>(rect.fRight),
            SkVector radii[4];
                      .bottom = static_cast<int>(rect.fBottom)};

            const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius);

            // compute the UpperLeft corner radius
            if (bounds.fLeft == crop.fLeft && bounds.fTop == crop.fTop) {
                radii[0].set(cornerRadius, cornerRadius);
            } else if (bounds.fLeft > insetCrop.fLeft && bounds.fTop > insetCrop.fTop) {
                radii[0].set(0, 0);
            } else {
                intersectionIsRoundRect = false;
            }
            // compute the UpperRight corner radius
            if (bounds.fRight == crop.fRight && bounds.fTop == crop.fTop) {
                radii[1].set(cornerRadius, cornerRadius);
            } else if (bounds.fRight < insetCrop.fRight && bounds.fTop > insetCrop.fTop) {
                radii[1].set(0, 0);
            } else {
                intersectionIsRoundRect = false;
            }
            // compute the BottomRight corner radius
            if (bounds.fRight == crop.fRight && bounds.fBottom == crop.fBottom) {
                radii[2].set(cornerRadius, cornerRadius);
            } else if (bounds.fRight < insetCrop.fRight && bounds.fBottom < insetCrop.fBottom) {
                radii[2].set(0, 0);
            } else {
                intersectionIsRoundRect = false;
            }
            // compute the BottomLeft corner radius
            if (bounds.fLeft == crop.fLeft && bounds.fBottom == crop.fBottom) {
                radii[3].set(cornerRadius, cornerRadius);
            } else if (bounds.fLeft > insetCrop.fLeft && bounds.fBottom < insetCrop.fBottom) {
                radii[3].set(0, 0);
            } else {
                intersectionIsRoundRect = false;
            }

            if (intersectionIsRoundRect) {
                SkRRect intersectionBounds;
                intersectionBounds.setRectRadii(bounds, radii);
                return {intersectionBounds, clip};
            }
        }

        // we didn't it any of our fast paths so set the clip to the cropRect
        clip.setRectXY(crop, cornerRadius, cornerRadius);
    }

    // if we hit this point then we either don't have rounded corners or we are going to rely
    // on the clip to round the corners for us
    return {SkRRect::MakeRect(bounds), clip};
}
}


inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer) {
inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer) {
+1 −2
Original line number Original line Diff line number Diff line
@@ -88,8 +88,7 @@ private:
                                                         int hwcFormat, Protection protection);
                                                         int hwcFormat, Protection protection);
    inline SkRect getSkRect(const FloatRect& layer);
    inline SkRect getSkRect(const FloatRect& layer);
    inline SkRect getSkRect(const Rect& layer);
    inline SkRect getSkRect(const Rect& layer);
    inline SkRRect getRoundedRect(const LayerSettings* layer);
    inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const LayerSettings* layer);
    inline BlurRegion getBlurRegion(const LayerSettings* layer);
    inline bool layerHasBlur(const LayerSettings* layer);
    inline bool layerHasBlur(const LayerSettings* layer);
    inline SkColor getSkColor(const vec4& color);
    inline SkColor getSkColor(const vec4& color);
    inline SkM44 getSkM44(const mat4& matrix);
    inline SkM44 getSkM44(const mat4& matrix);
+12 −23
Original line number Original line Diff line number Diff line
@@ -139,23 +139,21 @@ static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRec
    return matrix;
    return matrix;
}
}


void BlurFilter::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
                                const uint32_t blurRadius, const float blurAlpha,
                                const SkRect& blurRect, sk_sp<SkImage> blurredImage,
                                const SkRect& blurRect, sk_sp<SkImage> blurredImage,
                                sk_sp<SkImage> input) {
                                sk_sp<SkImage> input) {
    ATRACE_CALL();
    ATRACE_CALL();


    SkPaint paint;
    SkPaint paint;
    paint.setAlphaf(effectRegion.alpha);
    paint.setAlphaf(blurAlpha);
    if (effectRegion.alpha == 1.0f) {
        paint.setBlendMode(SkBlendMode::kSrc);
    }


    const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale);
    const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale);
    SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
    SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
    const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
    const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                                     linearSampling, &blurMatrix);
                                                     linearSampling, &blurMatrix);


    if (effectRegion.blurRadius < kMaxCrossFadeRadius) {
    if (blurRadius < kMaxCrossFadeRadius) {
        // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
        // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
        // case you might expect the matrix to simply be the canvas matrix.
        // case you might expect the matrix to simply be the canvas matrix.
        SkMatrix inputMatrix;
        SkMatrix inputMatrix;
@@ -168,30 +166,21 @@ void BlurFilter::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion
        blurBuilder.child("originalInput") =
        blurBuilder.child("originalInput") =
                input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
                input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
                                  inputMatrix);
                                  inputMatrix);
        blurBuilder.uniform("mixFactor") = effectRegion.blurRadius / kMaxCrossFadeRadius;
        blurBuilder.uniform("mixFactor") = blurRadius / kMaxCrossFadeRadius;


        paint.setShader(blurBuilder.makeShader(nullptr, true));
        paint.setShader(blurBuilder.makeShader(nullptr, true));
    } else {
    } else {
        paint.setShader(blurShader);
        paint.setShader(blurShader);
    }
    }


    // TODO we should AA at least the drawRoundRect which would mean no SRC blending
    if (effectRegion.isRect()) {
    // TODO this round rect calculation doesn't match the one used to draw in RenderEngine
        if (blurAlpha == 1.0f) {
    auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
            paint.setBlendMode(SkBlendMode::kSrc);
                                 effectRegion.bottom);
        }

        canvas->drawRect(effectRegion.rect(), paint);
    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 {
    } else {
        canvas->drawRect(rect, paint);
        paint.setAntiAlias(true);
        canvas->drawRRect(effectRegion, paint);
    }
    }
}
}


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


using namespace std;
using namespace std;


@@ -52,8 +51,19 @@ public:
    sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
    sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
                            const sk_sp<SkImage> blurInput, const SkRect& blurRect) const;
                            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);
     * Draw the blurred content (from the generate method) into the canvas.
     * @param canvas is the destination/output for the blur
     * @param effectRegion the RoundRect in canvas coordinates that determines the blur coverage
     * @param blurRadius radius of the blur used to determine the intensity of the crossfade effect
     * @param blurAlpha alpha value applied to the effectRegion when the blur is drawn
     * @param blurRect bounds of the blurredImage translated into canvas coordinates
     * @param blurredImage down-sampled blurred content that was produced by the generate() method
     * @param input original unblurred input that is used to crossfade with the blurredImage
     */
    void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius,
                        const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage,
                        sk_sp<SkImage> input);


private:
private:
    sk_sp<SkRuntimeEffect> mBlurEffect;
    sk_sp<SkRuntimeEffect> mBlurEffect;
+50 −0
Original line number Original line Diff line number Diff line
@@ -263,6 +263,11 @@ public:
        }
        }
    }
    }


    void expectBufferColor(const Point& point, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
                           uint8_t tolerance = 0) {
        expectBufferColor(Rect(point.x, point.y, point.x + 1, point.y + 1), r, g, b, a, tolerance);
    }

    void expectBufferColor(const Rect& rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
    void expectBufferColor(const Rect& rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
                           uint8_t tolerance = 0) {
                           uint8_t tolerance = 0) {
        auto colorCompare = [tolerance](const uint8_t* colorA, const uint8_t* colorB) {
        auto colorCompare = [tolerance](const uint8_t* colorA, const uint8_t* colorB) {
@@ -1887,6 +1892,51 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) {
                      0, 255, 0, 255);
                      0, 255, 0, 255);
}
}


TEST_P(RenderEngineTest, testRoundedCornersParentCrop) {
    initializeRenderEngine();

    renderengine::DisplaySettings settings;
    settings.physicalDisplay = fullscreenRect();
    settings.clip = fullscreenRect();
    settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;

    std::vector<const renderengine::LayerSettings*> layers;

    renderengine::LayerSettings redLayer;
    redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
    redLayer.geometry.boundaries = fullscreenRect().toFloatRect();
    redLayer.geometry.roundedCornersRadius = 5.0f;
    redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
    // Red background.
    redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
    redLayer.alpha = 1.0f;

    layers.push_back(&redLayer);

    // Green layer with 1/2 size with parent crop rect.
    renderengine::LayerSettings greenLayer = redLayer;
    greenLayer.geometry.boundaries =
            FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2);
    greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f);

    layers.push_back(&greenLayer);

    invokeDraw(settings, layers);

    // Due to roundedCornersRadius, the corners are untouched.
    expectBufferColor(Point(0, 0), 0, 0, 0, 0);
    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0);
    expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0);
    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0);

    // top middle should be green and the bottom middle red
    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 0), 0, 255, 0, 255);
    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0, 255);

    // the bottom edge of the green layer should not be rounded
    expectBufferColor(Point(0, (DEFAULT_DISPLAY_HEIGHT / 2) - 1), 0, 255, 0, 255);
}

TEST_P(RenderEngineTest, testClear) {
TEST_P(RenderEngineTest, testClear) {
    initializeRenderEngine();
    initializeRenderEngine();