aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-07-09 16:20:47 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-10 13:28:15 +0000
commit418e658a6922923f8d1e1ce2cf00f0a0f6b18ff3 (patch)
tree3454ad2c2d0a10f2561511ab977753a7cffcc40e /modules
parent6d98257725b59e01a1a844b1b9c9e80912512b49 (diff)
[skottie] Apply fully opaque masks as clips
We already have a clip optimization when there is only one opaque mask. Extend to cover multiple opaque masks, using Merge scene nodes. TBR= Change-Id: I24b61f0c0d080b13438c6777e98a8e2fefd09fdd Reviewed-on: https://skia-review.googlesource.com/140002 Reviewed-by: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'modules')
-rw-r--r--modules/skottie/src/Skottie.cpp71
-rw-r--r--modules/sksg/include/SkSGMerge.h16
-rw-r--r--modules/sksg/src/SkSGMerge.cpp42
3 files changed, 89 insertions, 40 deletions
diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp
index 6cfeddcfce..60009b9bc0 100644
--- a/modules/skottie/src/Skottie.cpp
+++ b/modules/skottie/src/Skottie.cpp
@@ -376,11 +376,21 @@ sk_sp<sksg::PaintNode> AttachGradientStroke(const skjson::ObjectValue& jstroke,
return AttachStroke(jstroke, ctx, AttachPaint(jstroke, ctx, AttachGradient(jstroke, ctx)));
}
+sk_sp<sksg::Merge> Merge(std::vector<sk_sp<sksg::GeometryNode>>&& geos, sksg::Merge::Mode mode) {
+ std::vector<sksg::Merge::Rec> merge_recs;
+ merge_recs.reserve(geos.size());
+
+ for (const auto& geo : geos) {
+ merge_recs.push_back(
+ {std::move(geo), merge_recs.empty() ? sksg::Merge::Mode::kMerge : mode});
+ }
+
+ return sksg::Merge::Make(std::move(merge_recs));
+}
+
std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
const skjson::ObjectValue& jmerge, AttachContext*,
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
- std::vector<sk_sp<sksg::GeometryNode>> merged;
-
static constexpr sksg::Merge::Mode gModes[] = {
sksg::Merge::Mode::kMerge, // "mm": 1
sksg::Merge::Mode::kUnion, // "mm": 2
@@ -391,7 +401,9 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
const auto mode = gModes[SkTPin<int>(ParseDefault<int>(jmerge["mm"], 1) - 1,
0, SK_ARRAY_COUNT(gModes) - 1)];
- merged.push_back(sksg::Merge::Make(std::move(geos), mode));
+
+ std::vector<sk_sp<sksg::GeometryNode>> merged;
+ merged.push_back(Merge(std::move(geos), mode));
return merged;
}
@@ -410,7 +422,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
std::vector<sk_sp<sksg::GeometryNode>> inputs;
if (mode == Mode::kMerged) {
- inputs.push_back(sksg::Merge::Make(std::move(geos), sksg::Merge::Mode::kMerge));
+ inputs.push_back(Merge(std::move(geos), sksg::Merge::Mode::kMerge));
} else {
inputs = std::move(geos);
}
@@ -661,7 +673,7 @@ sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape, AttachShap
// If we still have multiple geos, reduce using 'merge'.
auto geo = drawGeos.size() > 1
- ? sksg::Merge::Make(std::move(drawGeos), sksg::Merge::Mode::kMerge)
+ ? Merge(std::move(drawGeos), sksg::Merge::Mode::kMerge)
: drawGeos[0];
SkASSERT(geo);
@@ -974,17 +986,22 @@ private:
};
struct MaskInfo {
- SkBlendMode fBlendMode;
- bool fInvertGeometry;
+ SkBlendMode fBlendMode; // used when masking with layers/blending
+ sksg::Merge::Mode fMergeMode; // used when clipping
+ bool fInvertGeometry;
};
const MaskInfo* GetMaskInfo(char mode) {
- static constexpr MaskInfo k_add_info = { SkBlendMode::kSrcOver , false };
- static constexpr MaskInfo k_int_info = { SkBlendMode::kSrcIn , false };
+ static constexpr MaskInfo k_add_info =
+ { SkBlendMode::kSrcOver , sksg::Merge::Mode::kUnion , false };
+ static constexpr MaskInfo k_int_info =
+ { SkBlendMode::kSrcIn , sksg::Merge::Mode::kIntersect , false };
// AE 'subtract' is the same as 'intersect' + inverted geometry
// (draws the opacity-adjusted paint *outside* the shape).
- static constexpr MaskInfo k_sub_info = { SkBlendMode::kSrcIn , true };
- static constexpr MaskInfo k_dif_info = { SkBlendMode::kDifference, false };
+ static constexpr MaskInfo k_sub_info =
+ { SkBlendMode::kSrcIn , sksg::Merge::Mode::kIntersect , true };
+ static constexpr MaskInfo k_dif_info =
+ { SkBlendMode::kDifference, sksg::Merge::Mode::kDifference, false };
switch (mode) {
case 'a': return &k_add_info;
@@ -1003,8 +1020,9 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
if (!jmask) return childNode;
struct MaskRecord {
- sk_sp<sksg::Path> mask_path;
- sk_sp<sksg::Color> mask_paint;
+ sk_sp<sksg::Path> mask_path; // for clipping and masking
+ sk_sp<sksg::Color> mask_paint; // for masking
+ sksg::Merge::Mode merge_mode; // for clipping
};
SkSTArray<4, MaskRecord, true> mask_stack;
@@ -1055,17 +1073,32 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
mask_paint->setOpacity(o * 0.01f);
}, &full_opacity);
- mask_stack.push_back({mask_path, mask_paint});
+ mask_stack.push_back({mask_path, mask_paint, mask_info->fMergeMode});
}
if (mask_stack.empty())
return childNode;
- if (mask_stack.count() == 1 && !has_opacity) {
- // Single, fully-opaque mask => clip path.
- return sksg::ClipEffect::Make(std::move(childNode),
- std::move(mask_stack.front().mask_path),
- true);
+ // If the masks are fully opaque, we can clip.
+ if (!has_opacity) {
+ sk_sp<sksg::GeometryNode> clip_node;
+
+ if (mask_stack.count() == 1) {
+ // Single path -> just clip.
+ clip_node = std::move(mask_stack.front().mask_path);
+ } else {
+ // Multiple clip paths -> merge.
+ std::vector<sksg::Merge::Rec> merge_recs;
+ merge_recs.reserve(SkToSizeT(mask_stack.count()));
+
+ for (const auto& mask : mask_stack) {
+ const auto mode = merge_recs.empty() ? sksg::Merge::Mode::kMerge : mask.merge_mode;
+ merge_recs.push_back({std::move(mask.mask_path), mode});
+ }
+ clip_node = sksg::Merge::Make(std::move(merge_recs));
+ }
+
+ return sksg::ClipEffect::Make(std::move(childNode), std::move(clip_node), true);
}
auto mask_group = sksg::Group::Make();
diff --git a/modules/sksg/include/SkSGMerge.h b/modules/sksg/include/SkSGMerge.h
index 54924d6475..c4957f45a1 100644
--- a/modules/sksg/include/SkSGMerge.h
+++ b/modules/sksg/include/SkSGMerge.h
@@ -36,8 +36,13 @@ public:
kXOR,
};
- static sk_sp<Merge> Make(std::vector<sk_sp<GeometryNode>>&& geos, Mode mode) {
- return sk_sp<Merge>(new Merge(std::move(geos), mode));
+ struct Rec {
+ sk_sp<GeometryNode> fGeo;
+ Mode fMode;
+ };
+
+ static sk_sp<Merge> Make(std::vector<Rec>&& recs) {
+ return sk_sp<Merge>(new Merge(std::move(recs)));
}
~Merge() override;
@@ -50,11 +55,10 @@ protected:
SkPath onAsPath() const override;
private:
- Merge(std::vector<sk_sp<GeometryNode>>&& geos, Mode);
+ Merge(std::vector<Rec>&& recs);
- std::vector<sk_sp<GeometryNode>> fGeos;
- SkPath fMerged;
- Mode fMode;
+ const std::vector<Rec> fRecs;
+ SkPath fMerged;
using INHERITED = GeometryNode;
};
diff --git a/modules/sksg/src/SkSGMerge.cpp b/modules/sksg/src/SkSGMerge.cpp
index be1ff4123a..ff50021047 100644
--- a/modules/sksg/src/SkSGMerge.cpp
+++ b/modules/sksg/src/SkSGMerge.cpp
@@ -12,17 +12,16 @@
namespace sksg {
-Merge::Merge(std::vector<sk_sp<GeometryNode>>&& geos, Mode mode)
- : fGeos(std::move(geos))
- , fMode(mode) {
- for (const auto& geo : fGeos) {
- this->observeInval(geo);
+Merge::Merge(std::vector<Rec>&& recs)
+ : fRecs(std::move(recs)) {
+ for (const auto& rec : fRecs) {
+ this->observeInval(rec.fGeo);
}
}
Merge::~Merge() {
- for (const auto& geo : fGeos) {
- this->unobserveInval(geo);
+ for (const auto& rec : fRecs) {
+ this->unobserveInval(rec.fGeo);
}
}
@@ -60,21 +59,34 @@ static SkPathOp mode_to_op(Merge::Mode mode) {
SkRect Merge::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
SkASSERT(this->hasInval());
- const auto op = mode_to_op(fMode);
SkOpBuilder builder;
fMerged.reset();
+ bool in_builder = false;
- for (const auto& geo : fGeos) {
- geo->revalidate(ic, ctm);
- if (fMode == Mode::kMerge) {
- fMerged.addPath(geo->asPath());
- } else {
- builder.add(geo->asPath(), geo == fGeos.front() ? kUnion_SkPathOp : op);
+ for (const auto& rec : fRecs) {
+ rec.fGeo->revalidate(ic, ctm);
+
+ // Merge is not currently supported by SkOpBuidler.
+ if (rec.fMode == Mode::kMerge) {
+ if (in_builder) {
+ builder.resolve(&fMerged);
+ in_builder = false;
+ }
+
+ fMerged.addPath(rec.fGeo->asPath());
+ continue;
}
+
+ if (!in_builder) {
+ builder.add(fMerged, kUnion_SkPathOp);
+ in_builder = true;
+ }
+
+ builder.add(rec.fGeo->asPath(), mode_to_op(rec.fMode));
}
- if (fMode != Mode::kMerge) {
+ if (in_builder) {
builder.resolve(&fMerged);
}