aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar mtklein <mtklein@chromium.org>2015-10-20 08:26:54 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-10-20 08:26:54 -0700
commitc4d934f339693ecd039de05e9d882691adb7ec0f (patch)
tree2cd41e1daf24a1278c0e0b1c6d01668b89f5771b
parent045802dbb7202b52f5fd2758d725f39c156a6165 (diff)
SkRemote: add xfermodes
Note this changes the default ID for each type from a valid non-null value to a nullptr. All the ()++ are now ++(), so we always work with non-null IDs when we define things. Some of this is prematurely generalized with an eye for supporting other effects and ref-counted things. https://gold.skia.org/search2?issue=1412223002&unt=true&query=source_type%3Dgm&master=false&include=true BUG=skia: Review URL: https://codereview.chromium.org/1412223002
-rw-r--r--src/core/SkRemote.cpp153
-rw-r--r--src/core/SkRemote.h93
-rw-r--r--src/core/SkRemote_protocol.h8
3 files changed, 187 insertions, 67 deletions
diff --git a/src/core/SkRemote.cpp b/src/core/SkRemote.cpp
index 3966aaccc0..8efeb8b845 100644
--- a/src/core/SkRemote.cpp
+++ b/src/core/SkRemote.cpp
@@ -97,15 +97,16 @@ namespace SkRemote {
Cache* Cache::CreateNeverCache() {
struct NeverCache final : public Cache {
NeverCache()
- : fNextMatrix(Type::kMatrix)
- , fNextMisc (Type::kMisc)
- , fNextPath (Type::kPath)
- , fNextStroke(Type::kStroke)
+ : fNextMatrix (Type::kMatrix)
+ , fNextMisc (Type::kMisc)
+ , fNextPath (Type::kPath)
+ , fNextStroke (Type::kStroke)
+ , fNextXfermode(Type::kXfermode)
{}
void cleanup(Encoder*) override {}
static bool Helper(ID* next, ID* id, LookupScope* ls) {
- *id = (*next)++;
+ *id = ++(*next);
ls->undefineWhenDone(*id);
return false;
}
@@ -122,65 +123,120 @@ namespace SkRemote {
bool lookup(const Stroke&, ID* id, LookupScope* ls) override {
return Helper(&fNextStroke, id, ls);
}
+ bool lookup(const SkXfermode* xfermode, ID* id, LookupScope* ls) override {
+ if (!xfermode) {
+ *id = ID(Type::kXfermode);
+ return true; // Null IDs are always defined.
+ }
+ return Helper(&fNextXfermode, id, ls);
+ }
ID fNextMatrix,
fNextMisc,
fNextPath,
- fNextStroke;
+ fNextStroke,
+ fNextXfermode;
};
return new NeverCache;
}
- // Can't be declared locally inside AlwaysCache because of the templating. :(
- template <typename T, typename Map>
- static bool always_cache_helper(const T& val, Map* map, ID* next, ID* id) {
- if (ID* found = map->find(val)) {
- *id = *found;
- return true;
+ // These can't be declared locally inside AlwaysCache because of the templating. :(
+ namespace {
+ template <typename T, typename Map>
+ static bool always_cache_lookup(const T& val, Map* map, ID* next, ID* id) {
+ if (const ID* found = map->find(val)) {
+ *id = *found;
+ return true;
+ }
+ *id = ++(*next);
+ map->set(val, *id);
+ return false;
}
- *id = (*next)++;
- map->set(val, *id);
- return false;
- }
+
+ struct Undefiner {
+ Encoder* fEncoder;
+
+ template <typename T>
+ void operator()(const T&, ID* id) const { fEncoder->undefine(*id); }
+ };
+
+ // Maps const T* -> ID, and refs the key. nullptr always maps to ID(kType).
+ template <typename T, Type kType>
+ class RefKeyMap {
+ public:
+ RefKeyMap() {}
+ ~RefKeyMap() { fMap.foreach([](const T* key, ID*) { key->unref(); }); }
+
+ void set(const T* key, const ID& id) {
+ SkASSERT(key && id.type() == kType);
+ fMap.set(SkRef(key), id);
+ }
+
+ void remove(const T* key) {
+ SkASSERT(key);
+ fMap.remove(key);
+ key->unref();
+ }
+
+ const ID* find(const T* key) const {
+ static const ID nullID(kType);
+ return key ? fMap.find(key) : &nullID;
+ }
+
+ template <typename Fn>
+ void foreach(const Fn& fn) { fMap.foreach(fn); }
+ private:
+ SkTHashMap<const T*, ID> fMap;
+ };
+ } // namespace
Cache* Cache::CreateAlwaysCache() {
struct AlwaysCache final : public Cache {
AlwaysCache()
- : fNextMatrix(Type::kMatrix)
- , fNextMisc (Type::kMisc)
- , fNextPath (Type::kPath)
- , fNextStroke(Type::kStroke)
+ : fNextMatrix (Type::kMatrix)
+ , fNextMisc (Type::kMisc)
+ , fNextPath (Type::kPath)
+ , fNextStroke (Type::kStroke)
+ , fNextXfermode(Type::kXfermode)
{}
void cleanup(Encoder* encoder) override {
- fMatrix.foreach([=](const SkMatrix&, ID* id) { encoder->undefine(*id); });
- fMisc .foreach([=](const Misc&, ID* id) { encoder->undefine(*id); });
- fPath .foreach([=](const SkPath&, ID* id) { encoder->undefine(*id); });
- fStroke.foreach([=](const Stroke&, ID* id) { encoder->undefine(*id); });
+ Undefiner undef{encoder};
+ fMatrix .foreach(undef);
+ fMisc .foreach(undef);
+ fPath .foreach(undef);
+ fStroke .foreach(undef);
+ fXfermode.foreach(undef);
}
bool lookup(const SkMatrix& matrix, ID* id, LookupScope*) override {
- return always_cache_helper(matrix, &fMatrix, &fNextMatrix, id);
+ return always_cache_lookup(matrix, &fMatrix, &fNextMatrix, id);
}
bool lookup(const Misc& misc, ID* id, LookupScope*) override {
- return always_cache_helper(misc, &fMisc, &fNextMisc, id);
+ return always_cache_lookup(misc, &fMisc, &fNextMisc, id);
}
bool lookup(const SkPath& path, ID* id, LookupScope*) override {
- return always_cache_helper(path, &fPath, &fNextPath, id);
+ return always_cache_lookup(path, &fPath, &fNextPath, id);
}
bool lookup(const Stroke& stroke, ID* id, LookupScope*) override {
- return always_cache_helper(stroke, &fStroke, &fNextStroke, id);
+ return always_cache_lookup(stroke, &fStroke, &fNextStroke, id);
}
+ bool lookup(const SkXfermode* xfermode, ID* id, LookupScope*) override {
+ return always_cache_lookup(xfermode, &fXfermode, &fNextXfermode, id);
+ }
+
+ SkTHashMap<SkMatrix, ID> fMatrix;
+ SkTHashMap<Misc, ID, MiscHash> fMisc;
+ SkTHashMap<SkPath, ID> fPath;
+ SkTHashMap<Stroke, ID> fStroke;
+ RefKeyMap<SkXfermode, Type::kXfermode> fXfermode;
- SkTHashMap<SkMatrix, ID> fMatrix;
- SkTHashMap<Misc, ID, MiscHash> fMisc;
- SkTHashMap<SkPath, ID> fPath;
- SkTHashMap<Stroke, ID> fStroke;
ID fNextMatrix,
fNextMisc,
fNextPath,
- fNextStroke;
+ fNextStroke,
+ fNextXfermode;
};
return new AlwaysCache;
}
@@ -236,13 +292,14 @@ namespace SkRemote {
void Client::onDrawPath(const SkPath& path, const SkPaint& paint) {
LookupScope ls(fCache, fEncoder);
ID p = ls.lookup(path),
- m = ls.lookup(Misc::CreateFrom(paint));
+ m = ls.lookup(Misc::CreateFrom(paint)),
+ x = ls.lookup(paint.getXfermode());
if (paint.getStyle() == SkPaint::kFill_Style) {
- fEncoder->fillPath(p, m);
+ fEncoder->fillPath(p, m, x);
} else {
// TODO: handle kStrokeAndFill_Style
- fEncoder->strokePath(p, m, ls.lookup(Stroke::CreateFrom(paint)));
+ fEncoder->strokePath(p, m, x, ls.lookup(Stroke::CreateFrom(paint)));
}
}
@@ -302,17 +359,19 @@ namespace SkRemote {
Server::Server(SkCanvas* canvas) : fCanvas(canvas) {}
- void Server::define(ID id, const SkMatrix& v) { fMatrix.set(id, v); }
- void Server::define(ID id, const Misc& v) { fMisc .set(id, v); }
- void Server::define(ID id, const SkPath& v) { fPath .set(id, v); }
- void Server::define(ID id, const Stroke& v) { fStroke.set(id, v); }
+ void Server::define(ID id, const SkMatrix& v) { fMatrix .set(id, v); }
+ void Server::define(ID id, const Misc& v) { fMisc .set(id, v); }
+ void Server::define(ID id, const SkPath& v) { fPath .set(id, v); }
+ void Server::define(ID id, const Stroke& v) { fStroke .set(id, v); }
+ void Server::define(ID id, SkXfermode* v) { fXfermode.set(id, v); }
void Server::undefine(ID id) {
switch(id.type()) {
- case Type::kMatrix: return fMatrix.remove(id);
- case Type::kMisc: return fMisc .remove(id);
- case Type::kPath: return fPath .remove(id);
- case Type::kStroke: return fStroke.remove(id);
+ case Type::kMatrix: return fMatrix .remove(id);
+ case Type::kMisc: return fMisc .remove(id);
+ case Type::kPath: return fPath .remove(id);
+ case Type::kStroke: return fStroke .remove(id);
+ case Type::kXfermode: return fXfermode.remove(id);
case Type::kNone: SkASSERT(false);
};
@@ -326,17 +385,19 @@ namespace SkRemote {
void Server::clipPath(ID path, SkRegion::Op op, bool aa) {
fCanvas->clipPath(fPath.find(path), op, aa);
}
- void Server::fillPath(ID path, ID misc) {
+ void Server::fillPath(ID path, ID misc, ID xfermode) {
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
fMisc.find(misc).applyTo(&paint);
+ paint.setXfermode(fXfermode.find(xfermode));
fCanvas->drawPath(fPath.find(path), paint);
}
- void Server::strokePath(ID path, ID misc, ID stroke) {
+ void Server::strokePath(ID path, ID misc, ID xfermode, ID stroke) {
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
fMisc .find(misc ).applyTo(&paint);
fStroke.find(stroke).applyTo(&paint);
+ paint.setXfermode(fXfermode.find(xfermode));
fCanvas->drawPath(fPath.find(path), paint);
}
diff --git a/src/core/SkRemote.h b/src/core/SkRemote.h
index 72914d4382..ed99c0f866 100644
--- a/src/core/SkRemote.h
+++ b/src/core/SkRemote.h
@@ -45,6 +45,7 @@ namespace SkRemote {
virtual void define(ID, const Misc&) = 0;
virtual void define(ID, const SkPath&) = 0;
virtual void define(ID, const Stroke&) = 0;
+ virtual void define(ID, SkXfermode*) = 0;
virtual void undefine(ID) = 0;
@@ -53,24 +54,37 @@ namespace SkRemote {
virtual void setMatrix(ID matrix) = 0;
- virtual void clipPath(ID path, SkRegion::Op, bool aa) = 0;
- virtual void fillPath(ID path, ID misc) = 0;
- virtual void strokePath(ID path, ID misc, ID stroke) = 0;
+ // TODO: struct CommonIDs { ID misc; ID xfermode; ... }
+ // for IDs that affect both fill + stroke?
+
+ virtual void clipPath(ID path, SkRegion::Op, bool aa) = 0;
+ virtual void fillPath(ID path, ID misc, ID xfermode) = 0;
+ virtual void strokePath(ID path, ID misc, ID xfermode, ID stroke) = 0;
};
class LookupScope;
- // TODO: document
+ // The Cache interface encapsulates the caching logic of the Client.
+ //
+ // Each lookup() method must always fill ID* with a valid value,
+ // but ID may be cached. If so, the lookup() method returns true;
+ // if not the lookup() method returns false and the Client must
+ // then define() this ID -> Thing mapping before using the ID.
+ //
+ // The Caches may also add IDs to the LookupScope's list of IDs to
+ // undefine() on destruction. This lets the Cache purge IDs.
struct Cache {
virtual ~Cache() {}
- static Cache* CreateNeverCache();
- static Cache* CreateAlwaysCache();
+ static Cache* CreateNeverCache(); // Never caches anything.
+ static Cache* CreateAlwaysCache(); // Caches by value (not deep pointer equality).
+ // TODO: static Cache* CreateDeepCache(); // Caches by deep value.
- virtual bool lookup(const SkMatrix&, ID*, LookupScope*) = 0;
- virtual bool lookup(const Misc&, ID*, LookupScope*) = 0;
- virtual bool lookup(const SkPath&, ID*, LookupScope*) = 0;
- virtual bool lookup(const Stroke&, ID*, LookupScope*) = 0;
+ virtual bool lookup(const SkMatrix&, ID*, LookupScope*) = 0;
+ virtual bool lookup(const Misc&, ID*, LookupScope*) = 0;
+ virtual bool lookup(const SkPath&, ID*, LookupScope*) = 0;
+ virtual bool lookup(const Stroke&, ID*, LookupScope*) = 0;
+ virtual bool lookup(const SkXfermode*, ID*, LookupScope*) = 0;
virtual void cleanup(Encoder*) = 0;
};
@@ -120,6 +134,7 @@ namespace SkRemote {
void define(ID, const Misc&) override;
void define(ID, const SkPath&) override;
void define(ID, const Stroke&) override;
+ void define(ID, SkXfermode*) override;
void undefine(ID) override;
@@ -128,13 +143,19 @@ namespace SkRemote {
void setMatrix(ID matrix) override;
- void clipPath(ID path, SkRegion::Op, bool aa) override;
- void fillPath(ID path, ID misc) override;
- void strokePath(ID path, ID misc, ID stroke) override;
+ void clipPath(ID path, SkRegion::Op, bool aa) override;
+ void fillPath(ID path, ID misc, ID xfermode) override;
+ void strokePath(ID path, ID misc, ID xfermode, ID stroke) override;
+ // Maps ID -> T.
template <typename T, Type kType>
class IDMap {
public:
+ ~IDMap() {
+ // A well-behaved client always cleans up its definitions.
+ SkASSERT(fMap.count() == 0);
+ }
+
void set(const ID& id, const T& val) {
SkASSERT(id.type() == kType);
fMap.set(id, val);
@@ -156,10 +177,48 @@ namespace SkRemote {
SkTHashMap<ID, T> fMap;
};
- IDMap<SkMatrix, Type::kMatrix> fMatrix;
- IDMap<Misc , Type::kMisc > fMisc;
- IDMap<SkPath , Type::kPath > fPath;
- IDMap<Stroke , Type::kStroke> fStroke;
+ // Maps ID -> T*, and keeps the T alive by reffing it.
+ template <typename T, Type kType>
+ class ReffedIDMap {
+ public:
+ ReffedIDMap() {
+ // A null ID always maps to nullptr.
+ fMap.set(ID(kType), nullptr);
+ }
+ ~ReffedIDMap() {
+ // A well-behaved client always cleans up its definitions.
+ SkASSERT(fMap.count() == 1);
+ }
+
+ void set(const ID& id, T* val) {
+ SkASSERT(id.type() == kType && val);
+ fMap.set(id, SkRef(val));
+ }
+
+ void remove(const ID& id) {
+ SkASSERT(id.type() == kType);
+ T** val = fMap.find(id);
+ SkASSERT(val && *val);
+ (*val)->unref();
+ fMap.remove(id);
+ }
+
+ T* find(const ID& id) const {
+ SkASSERT(id.type() == kType);
+ T** val = fMap.find(id);
+ SkASSERT(val);
+ return *val;
+ }
+
+ private:
+ SkTHashMap<ID, T*> fMap;
+ };
+
+ IDMap<SkMatrix, Type::kMatrix> fMatrix;
+ IDMap<Misc , Type::kMisc > fMisc;
+ IDMap<SkPath , Type::kPath > fPath;
+ IDMap<Stroke , Type::kStroke> fStroke;
+ ReffedIDMap<SkXfermode, Type::kXfermode> fXfermode;
SkCanvas* fCanvas;
};
diff --git a/src/core/SkRemote_protocol.h b/src/core/SkRemote_protocol.h
index 997521356e..23fa60cfc9 100644
--- a/src/core/SkRemote_protocol.h
+++ b/src/core/SkRemote_protocol.h
@@ -21,6 +21,7 @@ namespace SkRemote {
kMisc,
kPath,
kStroke,
+ kXfermode,
};
class ID {
@@ -35,11 +36,10 @@ namespace SkRemote {
uint64_t val() const { return fVal & ~((uint64_t)0xFF << 56); }
bool operator==(ID o) const { return fVal == o.fVal; }
- ID operator++(int) {
- ID prev = *this;
- fVal++;
+ ID operator++() {
+ ++fVal;
SkASSERT(this->val() != 0); // Overflow is particularly bad as it'd change our Type.
- return prev;
+ return *this;
}
private: