Refactor SkImageFilter usage to cache results.
If an SkImageFilter is used, create an image
snapshot with the filter applied to avoid
re-computing it on each draw invocation
Bug: 188450217
Test: Re-ran CTS tests
Change-Id: Ib790669e14ada9d4ebbfac958d699e2b5242f2d7
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9a9e6d4..332f7e6 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -306,11 +306,17 @@
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
@@ -321,6 +327,44 @@
}
}
+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
@@ -411,6 +455,8 @@
if (hasLayer()) {
this->setLayerSurface(nullptr);
}
+ mSnapshotResult.snapshot = nullptr;
+ mTargetImageFilter = nullptr;
if (mDisplayList) {
mDisplayList.updateChildren([](RenderNode* child) { child->destroyLayers(); });
}