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

Commit f2c79396 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Refactor SkImageFilter usage to cache results." into sc-dev am: 98f48b4c

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

Change-Id: I7eebfae710b972a6e84d2c579b352988a5bf74b3
parents 0e5a71d4 98f48b4c
Loading
Loading
Loading
Loading
+48 −2
Original line number Original line Diff line number Diff line
@@ -306,11 +306,17 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
        info.damageAccumulator->popTransform();
        info.damageAccumulator->popTransform();
        syncProperties();
        syncProperties();


        const StretchEffect& stagingStretch =
        auto& layerProperties = mProperties.layerProperties();
            mProperties.layerProperties().getStretchEffect();
        const StretchEffect& stagingStretch = layerProperties.getStretchEffect();
        if (stagingStretch.isEmpty()) {
        if (stagingStretch.isEmpty()) {
            mStretchMask.clear();
            mStretchMask.clear();
        }
        }

        if (layerProperties.getImageFilter() == nullptr) {
            mSnapshotResult.snapshot = nullptr;
            mTargetImageFilter = nullptr;
        }

        // We could try to be clever and only re-damage if the matrix changed.
        // We could try to be clever and only re-damage if the matrix changed.
        // However, we don't need to worry about that. The cost of over-damaging
        // However, we don't need to worry about that. The cost of over-damaging
        // here is only going to be a single additional map rect of this node
        // here is only going to be a single additional map rect of this node
@@ -321,6 +327,44 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
    }
    }
}
}


std::optional<RenderNode::SnapshotResult> RenderNode::updateSnapshotIfRequired(
    GrRecordingContext* context,
    const SkImageFilter* imageFilter,
    const SkIRect& clipBounds
) {
    auto* layerSurface = getLayerSurface();
    if (layerSurface == nullptr) {
        return std::nullopt;
    }

    sk_sp<SkImage> snapshot = layerSurface->makeImageSnapshot();
    const auto subset = SkIRect::MakeWH(properties().getWidth(),
                                        properties().getHeight());
    // If we don't have an ImageFilter just return the snapshot
    if (imageFilter == nullptr) {
        mSnapshotResult.snapshot = snapshot;
        mSnapshotResult.outSubset = subset;
        mSnapshotResult.outOffset = SkIPoint::Make(0.0f, 0.0f);
        mImageFilterClipBounds = clipBounds;
        mTargetImageFilter = nullptr;
    } else if (mSnapshotResult.snapshot == nullptr ||
        imageFilter != mTargetImageFilter.get() ||
        mImageFilterClipBounds != clipBounds) {
        // Otherwise create a new snapshot with the given filter and snapshot
        mSnapshotResult.snapshot =
                snapshot->makeWithFilter(context,
                                         imageFilter,
                                         subset,
                                         clipBounds,
                                         &mSnapshotResult.outSubset,
                                         &mSnapshotResult.outOffset);
        mTargetImageFilter = sk_ref_sp(imageFilter);
        mImageFilterClipBounds = clipBounds;
    }

    return mSnapshotResult;
}

void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
    // Make sure we inc first so that we don't fluctuate between 0 and 1,
    // Make sure we inc first so that we don't fluctuate between 0 and 1,
    // which would thrash the layer cache
    // which would thrash the layer cache
@@ -411,6 +455,8 @@ void RenderNode::destroyLayers() {
    if (hasLayer()) {
    if (hasLayer()) {
        this->setLayerSurface(nullptr);
        this->setLayerSurface(nullptr);
    }
    }
    mSnapshotResult.snapshot = nullptr;
    mTargetImageFilter = nullptr;
    if (mDisplayList) {
    if (mDisplayList) {
        mDisplayList.updateChildren([](RenderNode* child) { child->destroyLayers(); });
        mDisplayList.updateChildren([](RenderNode* child) { child->destroyLayers(); });
    }
    }
+26 −0
Original line number Original line Diff line number Diff line
@@ -345,6 +345,16 @@ public:
        return mSkiaLayer.get() ? mSkiaLayer->layerSurface.get() : nullptr;
        return mSkiaLayer.get() ? mSkiaLayer->layerSurface.get() : nullptr;
    }
    }


    struct SnapshotResult {
        sk_sp<SkImage> snapshot;
        SkIRect outSubset;
        SkIPoint outOffset;
    };

    std::optional<SnapshotResult> updateSnapshotIfRequired(GrRecordingContext* context,
                                            const SkImageFilter* imageFilter,
                                            const SkIRect& clipBounds);

    skiapipeline::SkiaLayer* getSkiaLayer() const { return mSkiaLayer.get(); }
    skiapipeline::SkiaLayer* getSkiaLayer() const { return mSkiaLayer.get(); }


    /**
    /**
@@ -375,6 +385,22 @@ private:
     */
     */
    std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;
    std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;


    /**
     * SkImageFilter used to create the mSnapshotResult
     */
    sk_sp<SkImageFilter> mTargetImageFilter;

    /**
     * Clip bounds used to create the mSnapshotResult
     */
    SkIRect mImageFilterClipBounds;

    /**
     * Result of the most recent snapshot with additional metadata used to
     * determine how to draw the contents
     */
    SnapshotResult mSnapshotResult;

    struct ClippedOutlineCache {
    struct ClippedOutlineCache {
        // keys
        // keys
        uint32_t outlineID = 0;
        uint32_t outlineID = 0;
+5 −3
Original line number Original line Diff line number Diff line
@@ -188,7 +188,8 @@ static const float ZERO = 0.f;
static const float INTERPOLATION_STRENGTH_VALUE = 0.7f;
static const float INTERPOLATION_STRENGTH_VALUE = 0.7f;


sk_sp<SkShader> StretchEffect::getShader(float width, float height,
sk_sp<SkShader> StretchEffect::getShader(float width, float height,
                                         const sk_sp<SkImage>& snapshotImage) const {
                                         const sk_sp<SkImage>& snapshotImage,
                                         const SkMatrix* matrix) const {
    if (isEmpty()) {
    if (isEmpty()) {
        return nullptr;
        return nullptr;
    }
    }
@@ -206,8 +207,9 @@ sk_sp<SkShader> StretchEffect::getShader(float width, float height,
        mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
        mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
    }
    }


    mBuilder->child("uContentTexture") = snapshotImage->makeShader(
    mBuilder->child("uContentTexture") =
            SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear));
            snapshotImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                      SkSamplingOptions(SkFilterMode::kLinear), matrix);
    mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1);
    mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1);
    mBuilder->uniform("uStretchAffectedDistX").set(&width, 1);
    mBuilder->uniform("uStretchAffectedDistX").set(&width, 1);
    mBuilder->uniform("uStretchAffectedDistY").set(&height, 1);
    mBuilder->uniform("uStretchAffectedDistY").set(&height, 1);
+2 −2
Original line number Original line Diff line number Diff line
@@ -93,8 +93,8 @@ public:
     */
     */
    float computeStretchedPositionY(float normalizedY) const;
    float computeStretchedPositionY(float normalizedY) const;


    sk_sp<SkShader> getShader(float width, float height,
    sk_sp<SkShader> getShader(float width, float height, const sk_sp<SkImage>& snapshotImage,
                              const sk_sp<SkImage>& snapshotImage) const;
                              const SkMatrix* matrix) const;


    float maxStretchAmountX = 0;
    float maxStretchAmountX = 0;
    float maxStretchAmountY = 0;
    float maxStretchAmountY = 0;
+34 −13
Original line number Original line Diff line number Diff line
@@ -171,17 +171,14 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) const {
    displayList->mProjectedOutline = nullptr;
    displayList->mProjectedOutline = nullptr;
}
}


static bool layerNeedsPaint(const sk_sp<SkImage>& snapshotImage, const LayerProperties& properties,
static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier,
                            float alphaMultiplier, SkPaint* paint) {
                            SkPaint* paint) {
    if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
    if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
        properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
        properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
        properties.getImageFilter() != nullptr || properties.getStretchEffect().requiresLayer()) {
        properties.getStretchEffect().requiresLayer()) {
        paint->setAlpha(properties.alpha() * alphaMultiplier);
        paint->setAlpha(properties.alpha() * alphaMultiplier);
        paint->setBlendMode(properties.xferMode());
        paint->setBlendMode(properties.xferMode());
        paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));
        paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));

        sk_sp<SkImageFilter> imageFilter = sk_ref_sp(properties.getImageFilter());
        paint->setImageFilter(std::move(imageFilter));
        return true;
        return true;
    }
    }
    return false;
    return false;
@@ -223,6 +220,9 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
    // TODO should we let the bound of the drawable do this for us?
    // TODO should we let the bound of the drawable do this for us?
    const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
    const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
    bool quickRejected = properties.getClipToBounds() && canvas->quickReject(bounds);
    bool quickRejected = properties.getClipToBounds() && canvas->quickReject(bounds);
    auto clipBounds = canvas->getLocalClipBounds();
    SkIRect srcBounds = SkIRect::MakeWH(bounds.width(), bounds.height());
    SkIPoint offset = SkIPoint::Make(0.0f, 0.0f);
    if (!quickRejected) {
    if (!quickRejected) {
        SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl();
        SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl();
        const LayerProperties& layerProperties = properties.layerProperties();
        const LayerProperties& layerProperties = properties.layerProperties();
@@ -230,8 +230,19 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
        if (renderNode->getLayerSurface() && mComposeLayer) {
        if (renderNode->getLayerSurface() && mComposeLayer) {
            SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer);
            SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer);
            SkPaint paint;
            SkPaint paint;
            sk_sp<SkImage> snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot();
            layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
            layerNeedsPaint(snapshotImage, layerProperties, alphaMultiplier, &paint);
            const auto snapshotResult = renderNode->updateSnapshotIfRequired(
                canvas->recordingContext(),
                layerProperties.getImageFilter(),
                clipBounds.roundOut()
            );
            sk_sp<SkImage> snapshotImage = snapshotResult->snapshot;
            srcBounds = snapshotResult->outSubset;
            offset = snapshotResult->outOffset;
            const auto dstBounds = SkIRect::MakeXYWH(offset.x(),
                                                     offset.y(),
                                                     srcBounds.width(),
                                                     srcBounds.height());
            SkSamplingOptions sampling(SkFilterMode::kLinear);
            SkSamplingOptions sampling(SkFilterMode::kLinear);


            // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so
            // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so
@@ -257,7 +268,8 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
                    TransformCanvas transformCanvas(canvas, SkBlendMode::kClear);
                    TransformCanvas transformCanvas(canvas, SkBlendMode::kClear);
                    displayList->draw(&transformCanvas);
                    displayList->draw(&transformCanvas);
                }
                }
                canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
                canvas->drawImageRect(snapshotImage, SkRect::Make(srcBounds),
                                      SkRect::Make(dstBounds), sampling, &paint,
                                      SkCanvas::kStrict_SrcRectConstraint);
                                      SkCanvas::kStrict_SrcRectConstraint);
            } else {
            } else {
                // If we do have stretch effects and have hole punches,
                // If we do have stretch effects and have hole punches,
@@ -265,6 +277,16 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
                // get the corresponding hole punches.
                // get the corresponding hole punches.
                // Then apply the stretch to the mask and draw the mask to
                // Then apply the stretch to the mask and draw the mask to
                // the destination
                // the destination
                // Also if the stretchy container has an ImageFilter applied
                // to it (i.e. blur) we need to take into account the offset
                // that will be generated with this result. Ex blurs will "grow"
                // the source image by the blur radius so we need to translate
                // the shader by the same amount to render in the same location
                SkMatrix matrix;
                matrix.setTranslate(
                    offset.x() - srcBounds.left(),
                    offset.y() - srcBounds.top()
                );
                if (renderNode->hasHolePunches()) {
                if (renderNode->hasHolePunches()) {
                    GrRecordingContext* context = canvas->recordingContext();
                    GrRecordingContext* context = canvas->recordingContext();
                    StretchMask& stretchMask = renderNode->getStretchMask();
                    StretchMask& stretchMask = renderNode->getStretchMask();
@@ -275,11 +297,10 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
                                     canvas);
                                     canvas);
                }
                }


                sk_sp<SkShader> stretchShader = stretch.getShader(bounds.width(),
                sk_sp<SkShader> stretchShader =
                                                                  bounds.height(),
                        stretch.getShader(bounds.width(), bounds.height(), snapshotImage, &matrix);
                                                                  snapshotImage);
                paint.setShader(stretchShader);
                paint.setShader(stretchShader);
                canvas->drawRect(bounds, paint);
                canvas->drawRect(SkRect::Make(dstBounds), paint);
            }
            }


            if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
            if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
Loading