Loading libs/hwui/RenderNode.cpp +48 −2 Original line number Diff line number Diff line Loading @@ -306,11 +306,17 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { info.damageAccumulator->popTransform(); syncProperties(); const StretchEffect& stagingStretch = mProperties.layerProperties().getStretchEffect(); auto& layerProperties = mProperties.layerProperties(); const StretchEffect& stagingStretch = layerProperties.getStretchEffect(); if (stagingStretch.isEmpty()) { 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. // 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 Loading @@ -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) { // Make sure we inc first so that we don't fluctuate between 0 and 1, // which would thrash the layer cache Loading Loading @@ -411,6 +455,8 @@ void RenderNode::destroyLayers() { if (hasLayer()) { this->setLayerSurface(nullptr); } mSnapshotResult.snapshot = nullptr; mTargetImageFilter = nullptr; if (mDisplayList) { mDisplayList.updateChildren([](RenderNode* child) { child->destroyLayers(); }); } Loading libs/hwui/RenderNode.h +26 −0 Original line number Diff line number Diff line Loading @@ -345,6 +345,16 @@ public: 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(); } /** Loading Loading @@ -375,6 +385,22 @@ private: */ 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 { // keys uint32_t outlineID = 0; Loading libs/hwui/effects/StretchEffect.cpp +5 −3 Original line number Diff line number Diff line Loading @@ -188,7 +188,8 @@ static const float ZERO = 0.f; static const float INTERPOLATION_STRENGTH_VALUE = 0.7f; 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()) { return nullptr; } Loading @@ -206,8 +207,9 @@ sk_sp<SkShader> StretchEffect::getShader(float width, float height, mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect()); } mBuilder->child("uContentTexture") = snapshotImage->makeShader( SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear)); mBuilder->child("uContentTexture") = snapshotImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear), matrix); mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1); mBuilder->uniform("uStretchAffectedDistX").set(&width, 1); mBuilder->uniform("uStretchAffectedDistY").set(&height, 1); Loading libs/hwui/effects/StretchEffect.h +2 −2 Original line number Diff line number Diff line Loading @@ -93,8 +93,8 @@ public: */ float computeStretchedPositionY(float normalizedY) const; sk_sp<SkShader> getShader(float width, float height, const sk_sp<SkImage>& snapshotImage) const; sk_sp<SkShader> getShader(float width, float height, const sk_sp<SkImage>& snapshotImage, const SkMatrix* matrix) const; float maxStretchAmountX = 0; float maxStretchAmountY = 0; Loading libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +34 −13 Original line number Diff line number Diff line Loading @@ -171,17 +171,14 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) const { displayList->mProjectedOutline = nullptr; } static bool layerNeedsPaint(const sk_sp<SkImage>& snapshotImage, const LayerProperties& properties, float alphaMultiplier, SkPaint* paint) { static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier, SkPaint* paint) { if (alphaMultiplier < 1.0f || properties.alpha() < 255 || properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr || properties.getImageFilter() != nullptr || properties.getStretchEffect().requiresLayer()) { properties.getStretchEffect().requiresLayer()) { paint->setAlpha(properties.alpha() * alphaMultiplier); paint->setBlendMode(properties.xferMode()); paint->setColorFilter(sk_ref_sp(properties.getColorFilter())); sk_sp<SkImageFilter> imageFilter = sk_ref_sp(properties.getImageFilter()); paint->setImageFilter(std::move(imageFilter)); return true; } return false; Loading Loading @@ -223,6 +220,9 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { // TODO should we let the bound of the drawable do this for us? const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight()); 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) { SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl(); const LayerProperties& layerProperties = properties.layerProperties(); Loading @@ -230,8 +230,19 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { if (renderNode->getLayerSurface() && mComposeLayer) { SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer); SkPaint paint; sk_sp<SkImage> snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot(); layerNeedsPaint(snapshotImage, layerProperties, alphaMultiplier, &paint); layerNeedsPaint(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); // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so Loading @@ -257,7 +268,8 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { TransformCanvas transformCanvas(canvas, SkBlendMode::kClear); displayList->draw(&transformCanvas); } canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint, canvas->drawImageRect(snapshotImage, SkRect::Make(srcBounds), SkRect::Make(dstBounds), sampling, &paint, SkCanvas::kStrict_SrcRectConstraint); } else { // If we do have stretch effects and have hole punches, Loading @@ -265,6 +277,16 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { // get the corresponding hole punches. // Then apply the stretch to the mask and draw the mask to // 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()) { GrRecordingContext* context = canvas->recordingContext(); StretchMask& stretchMask = renderNode->getStretchMask(); Loading @@ -275,11 +297,10 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { canvas); } sk_sp<SkShader> stretchShader = stretch.getShader(bounds.width(), bounds.height(), snapshotImage); sk_sp<SkShader> stretchShader = stretch.getShader(bounds.width(), bounds.height(), snapshotImage, &matrix); paint.setShader(stretchShader); canvas->drawRect(bounds, paint); canvas->drawRect(SkRect::Make(dstBounds), paint); } if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) { Loading Loading
libs/hwui/RenderNode.cpp +48 −2 Original line number Diff line number Diff line Loading @@ -306,11 +306,17 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { info.damageAccumulator->popTransform(); syncProperties(); const StretchEffect& stagingStretch = mProperties.layerProperties().getStretchEffect(); auto& layerProperties = mProperties.layerProperties(); const StretchEffect& stagingStretch = layerProperties.getStretchEffect(); if (stagingStretch.isEmpty()) { 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. // 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 Loading @@ -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) { // Make sure we inc first so that we don't fluctuate between 0 and 1, // which would thrash the layer cache Loading Loading @@ -411,6 +455,8 @@ void RenderNode::destroyLayers() { if (hasLayer()) { this->setLayerSurface(nullptr); } mSnapshotResult.snapshot = nullptr; mTargetImageFilter = nullptr; if (mDisplayList) { mDisplayList.updateChildren([](RenderNode* child) { child->destroyLayers(); }); } Loading
libs/hwui/RenderNode.h +26 −0 Original line number Diff line number Diff line Loading @@ -345,6 +345,16 @@ public: 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(); } /** Loading Loading @@ -375,6 +385,22 @@ private: */ 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 { // keys uint32_t outlineID = 0; Loading
libs/hwui/effects/StretchEffect.cpp +5 −3 Original line number Diff line number Diff line Loading @@ -188,7 +188,8 @@ static const float ZERO = 0.f; static const float INTERPOLATION_STRENGTH_VALUE = 0.7f; 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()) { return nullptr; } Loading @@ -206,8 +207,9 @@ sk_sp<SkShader> StretchEffect::getShader(float width, float height, mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect()); } mBuilder->child("uContentTexture") = snapshotImage->makeShader( SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear)); mBuilder->child("uContentTexture") = snapshotImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear), matrix); mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1); mBuilder->uniform("uStretchAffectedDistX").set(&width, 1); mBuilder->uniform("uStretchAffectedDistY").set(&height, 1); Loading
libs/hwui/effects/StretchEffect.h +2 −2 Original line number Diff line number Diff line Loading @@ -93,8 +93,8 @@ public: */ float computeStretchedPositionY(float normalizedY) const; sk_sp<SkShader> getShader(float width, float height, const sk_sp<SkImage>& snapshotImage) const; sk_sp<SkShader> getShader(float width, float height, const sk_sp<SkImage>& snapshotImage, const SkMatrix* matrix) const; float maxStretchAmountX = 0; float maxStretchAmountY = 0; Loading
libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +34 −13 Original line number Diff line number Diff line Loading @@ -171,17 +171,14 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) const { displayList->mProjectedOutline = nullptr; } static bool layerNeedsPaint(const sk_sp<SkImage>& snapshotImage, const LayerProperties& properties, float alphaMultiplier, SkPaint* paint) { static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier, SkPaint* paint) { if (alphaMultiplier < 1.0f || properties.alpha() < 255 || properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr || properties.getImageFilter() != nullptr || properties.getStretchEffect().requiresLayer()) { properties.getStretchEffect().requiresLayer()) { paint->setAlpha(properties.alpha() * alphaMultiplier); paint->setBlendMode(properties.xferMode()); paint->setColorFilter(sk_ref_sp(properties.getColorFilter())); sk_sp<SkImageFilter> imageFilter = sk_ref_sp(properties.getImageFilter()); paint->setImageFilter(std::move(imageFilter)); return true; } return false; Loading Loading @@ -223,6 +220,9 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { // TODO should we let the bound of the drawable do this for us? const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight()); 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) { SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl(); const LayerProperties& layerProperties = properties.layerProperties(); Loading @@ -230,8 +230,19 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { if (renderNode->getLayerSurface() && mComposeLayer) { SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer); SkPaint paint; sk_sp<SkImage> snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot(); layerNeedsPaint(snapshotImage, layerProperties, alphaMultiplier, &paint); layerNeedsPaint(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); // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so Loading @@ -257,7 +268,8 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { TransformCanvas transformCanvas(canvas, SkBlendMode::kClear); displayList->draw(&transformCanvas); } canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint, canvas->drawImageRect(snapshotImage, SkRect::Make(srcBounds), SkRect::Make(dstBounds), sampling, &paint, SkCanvas::kStrict_SrcRectConstraint); } else { // If we do have stretch effects and have hole punches, Loading @@ -265,6 +277,16 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { // get the corresponding hole punches. // Then apply the stretch to the mask and draw the mask to // 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()) { GrRecordingContext* context = canvas->recordingContext(); StretchMask& stretchMask = renderNode->getStretchMask(); Loading @@ -275,11 +297,10 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { canvas); } sk_sp<SkShader> stretchShader = stretch.getShader(bounds.width(), bounds.height(), snapshotImage); sk_sp<SkShader> stretchShader = stretch.getShader(bounds.width(), bounds.height(), snapshotImage, &matrix); paint.setShader(stretchShader); canvas->drawRect(bounds, paint); canvas->drawRect(SkRect::Make(dstBounds), paint); } if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) { Loading