Merge "Refactor SkImageFilter usage to cache results." into sc-dev am: 98f48b4c95
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14921729 Change-Id: I7eebfae710b972a6e84d2c579b352988a5bf74b3
This commit is contained in:
@@ -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(); });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -59,8 +59,7 @@ void StretchMask::draw(GrRecordingContext* context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<SkImage> maskImage = mMaskSurface->makeImageSnapshot();
|
sk_sp<SkImage> maskImage = mMaskSurface->makeImageSnapshot();
|
||||||
sk_sp<SkShader> maskStretchShader = stretch.getShader(
|
sk_sp<SkShader> maskStretchShader = stretch.getShader(width, height, maskImage, nullptr);
|
||||||
width, height, maskImage);
|
|
||||||
|
|
||||||
SkPaint maskPaint;
|
SkPaint maskPaint;
|
||||||
maskPaint.setShader(maskStretchShader);
|
maskPaint.setShader(maskStretchShader);
|
||||||
|
|||||||
Reference in New Issue
Block a user