Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1436)

Unified Diff: src/record/SkRecord.h

Issue 245853002: Refactor SkRecord opts, converting playback optimizations where possible. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: apply Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/record/SkRecordDraw.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/record/SkRecord.h
diff --git a/src/record/SkRecord.h b/src/record/SkRecord.h
index 4c2f5b5ed4d40510eabb14bb7bcb037d50b50f49..ddf1b3d95fabaf927c45bd7152263699f67a7097 100644
--- a/src/record/SkRecord.h
+++ b/src/record/SkRecord.h
@@ -31,59 +31,43 @@ public:
~SkRecord() {
Destroyer destroyer;
- this->mutate(destroyer);
+ for (unsigned i = 0; i < this->count(); i++) {
+ this->mutate(i, destroyer);
+ }
}
+ // Returns the number of canvas commands in this SkRecord.
unsigned count() const { return fCount; }
- // Accepts a visitor functor with this interface:
+ // Visit the i-th canvas command with a functor matching this interface:
// template <typename T>
// void operator()(const T& record) { ... }
- // This operator() must be defined for at least all SkRecords::*; your compiler will help you
- // get this right.
+ // This operator() must be defined for at least all SkRecords::*.
template <typename F>
void visit(unsigned i, F& f) const {
SkASSERT(i < this->count());
fRecords[i].visit(fTypes[i], f);
}
- // As above. f will be called on each recorded canvas call in the order they were append()ed.
- template <typename F>
- void visit(F& f) const {
- for (unsigned i = 0; i < fCount; i++) {
- this->visit(i, f);
- }
- }
-
- // Accepts a visitor functor with this interface:
+ // Mutate the i-th canvas command with a functor matching this interface:
// template <typename T>
// void operator()(T* record) { ... }
- // This operator() must be defined for at least all SkRecords::*; again, your compiler will help
- // you get this right.
+ // This operator() must be defined for at least all SkRecords::*.
template <typename F>
void mutate(unsigned i, F& f) {
SkASSERT(i < this->count());
fRecords[i].mutate(fTypes[i], f);
}
- // As above. f will be called on each recorded canvas call in the order they were append()ed.
- template <typename F>
- void mutate(F& f) {
- for (unsigned i = 0; i < fCount; i++) {
- this->mutate(i, f);
- }
- }
-
- // Allocate contiguous space for count Ts, to be destroyed (not just freed) when the SkRecord is
- // destroyed. For classes with constructors, placement new into this array. Throws on failure.
- // Here T can really be any class, not just those from SkRecords.
+ // Allocate contiguous space for count Ts, to be freed when the SkRecord is destroyed.
+ // Here T can be any class, not just those from SkRecords. Throws on failure.
template <typename T>
T* alloc(unsigned count = 1) {
return (T*)fAlloc.allocThrow(sizeof(T) * count);
}
- // Allocate space to record a canvas call of type T at the end of this SkRecord. You are
- // expected to placement new an object of type T onto this pointer.
+ // Add a new command of type T to the end of this SkRecord.
+ // You are expected to placement new an object of type T onto this pointer.
template <typename T>
T* append() {
if (fCount == fReserved) {
@@ -93,9 +77,26 @@ public:
}
fTypes[fCount] = T::kType;
- return fRecords[fCount++].alloc<T>(this);
+ return fRecords[fCount++].set(this->alloc<T>());
}
+ // Replace the i-th command with a new command of type T.
+ // You are expected to placement new an object of type T onto this pointer.
+ // References to the old command remain valid for the life of the SkRecord, but
+ // you must destroy the old command. (It's okay to destroy it first before calling replace.)
+ template <typename T>
+ T* replace(unsigned i) {
+ SkASSERT(i < this->count());
+ fTypes[i] = T::kType;
+ return fRecords[i].set(this->alloc<T>());
+ }
+
+ // A mutator that can be used with replace to destroy canvas commands.
+ struct Destroyer {
+ template <typename T>
+ void operator()(T* record) { record->~T(); }
+ };
+
private:
// Implementation notes!
//
@@ -131,23 +132,9 @@ private:
// SkRecord looking for just patterns of draw commands (or using this as a quick reject
// mechanism) though there's admittedly not a very good API exposed publically for this.
//
- // We pull one final sneaky trick in the implementation. When recording canvas calls that need
- // to store less than a pointer of data, we don't go through the usual path of allocating the
- // draw command in fAlloc and a pointer to it in fRecords; instead, we ignore fAlloc and
- // directly allocate the object in the space we would have put the pointer in fRecords. This is
- // why you'll see uintptr_t instead of void* in Record below.
- //
- // The cost of appending a single record into this structure is then:
- // - 1 + sizeof(void*) + sizeof(T) if sizeof(T) > sizeof(void*)
- // - 1 + sizeof(void*) if sizeof(T) <= sizeof(void*)
+ // The cost to append a T into this structure is 1 + sizeof(void*) + sizeof(T).
- // A mutator that calls destructors of all the canvas calls we've recorded.
- struct Destroyer {
- template <typename T>
- void operator()(T* record) { record->~T(); }
- };
-
// Logically the same as SkRecords::Type, but packed into 8 bits.
struct Type8 {
public:
@@ -159,19 +146,15 @@ private:
uint8_t fType;
};
- // Logically a void* to some bytes in fAlloc, but maybe has the bytes stored immediately
- // instead. This is also the main interface for devirtualized polymorphic dispatch: see visit()
- // and mutate(), which essentially do the work of the missing vtable.
+ // An untyped pointer to some bytes in fAlloc. This is the interface for polymorphic dispatch:
+ // visit() and mutate() work with the parallel fTypes array to do the work of a vtable.
struct Record {
public:
-
- // Allocate space for a T, perhaps using the SkRecord to allocate that space.
+ // Point this record to its data in fAlloc. Returns ptr for convenience.
template <typename T>
- T* alloc(SkRecord* record) {
- if (IsLarge<T>()) {
- fRecord = (uintptr_t)record->alloc<T>();
- }
- return this->ptr<T>();
+ T* set(T* ptr) {
+ fPtr = ptr;
+ return ptr;
}
// Visit this record with functor F (see public API above) assuming the record we're
@@ -194,13 +177,9 @@ private:
private:
template <typename T>
- T* ptr() const { return (T*)(IsLarge<T>() ? (void*)fRecord : &fRecord); }
-
- // Is T too big to fit directly into a uintptr_t, neededing external allocation?
- template <typename T>
- static bool IsLarge() { return sizeof(T) > sizeof(uintptr_t); }
+ T* ptr() const { return (T*)fPtr; }
- uintptr_t fRecord;
+ void* fPtr;
};
// fAlloc needs to be a data structure which can append variable length data in contiguous
« no previous file with comments | « no previous file | src/record/SkRecordDraw.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698