| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef SkRecord_DEFINED | 8 #ifndef SkRecord_DEFINED |
| 9 #define SkRecord_DEFINED | 9 #define SkRecord_DEFINED |
| 10 | 10 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 fRecords.realloc(fReserved); | 75 fRecords.realloc(fReserved); |
| 76 fTypes.realloc(fReserved); | 76 fTypes.realloc(fReserved); |
| 77 } | 77 } |
| 78 | 78 |
| 79 fTypes[fCount] = T::kType; | 79 fTypes[fCount] = T::kType; |
| 80 return fRecords[fCount++].set(this->alloc<T>()); | 80 return fRecords[fCount++].set(this->alloc<T>()); |
| 81 } | 81 } |
| 82 | 82 |
| 83 // Replace the i-th command with a new command of type T. | 83 // Replace the i-th command with a new command of type T. |
| 84 // You are expected to placement new an object of type T onto this pointer. | 84 // You are expected to placement new an object of type T onto this pointer. |
| 85 // References to the old command remain valid for the life of the SkRecord,
but | 85 // References to the original command are invalidated. |
| 86 // you must destroy the old command. (It's okay to destroy it first before
calling replace.) | |
| 87 template <typename T> | 86 template <typename T> |
| 88 T* replace(unsigned i) { | 87 T* replace(unsigned i) { |
| 89 SkASSERT(i < this->count()); | 88 SkASSERT(i < this->count()); |
| 89 |
| 90 Destroyer destroyer; |
| 91 this->mutate(i, destroyer); |
| 92 |
| 90 fTypes[i] = T::kType; | 93 fTypes[i] = T::kType; |
| 91 return fRecords[i].set(this->alloc<T>()); | 94 return fRecords[i].set(this->alloc<T>()); |
| 92 } | 95 } |
| 93 | 96 |
| 94 // A mutator that can be used with replace to destroy canvas commands. | 97 // Replace the i-th command with a new command of type T. |
| 95 struct Destroyer { | 98 // You are expected to placement new an object of type T onto this pointer. |
| 96 template <typename T> | 99 // You must show proof that you've already adopted the existing command. |
| 97 void operator()(T* record) { record->~T(); } | 100 template <typename T, typename Existing> |
| 98 }; | 101 T* replace(unsigned i, const SkRecords::Adopted<Existing>& proofOfAdoption)
{ |
| 102 SkASSERT(i < this->count()); |
| 103 |
| 104 SkASSERT(Existing::kType == fTypes[i]); |
| 105 SkASSERT(proofOfAdoption == fRecords[i].ptr<Existing>()); |
| 106 |
| 107 fTypes[i] = T::kType; |
| 108 return fRecords[i].set(this->alloc<T>()); |
| 109 } |
| 99 | 110 |
| 100 private: | 111 private: |
| 101 // Implementation notes! | 112 // Implementation notes! |
| 102 // | 113 // |
| 103 // Logically an SkRecord is structured as an array of pointers into a big ch
unk of memory where | 114 // Logically an SkRecord is structured as an array of pointers into a big ch
unk of memory where |
| 104 // records representing each canvas draw call are stored: | 115 // records representing each canvas draw call are stored: |
| 105 // | 116 // |
| 106 // fRecords: [*][*][*]... | 117 // fRecords: [*][*][*]... |
| 107 // | | | | 118 // | | | |
| 108 // | | | | 119 // | | | |
| (...skipping 18 matching lines...) Expand all Loading... |
| 127 // visit() or mutate(). The recorded canvas calls don't have to have any id
ea about the | 138 // visit() or mutate(). The recorded canvas calls don't have to have any id
ea about the |
| 128 // operations performed on them. | 139 // operations performed on them. |
| 129 // | 140 // |
| 130 // We store the types in a parallel fTypes array, mainly so that they can be
tightly packed as | 141 // We store the types in a parallel fTypes array, mainly so that they can be
tightly packed as |
| 131 // single bytes. This has the side effect of allowing very fast analysis pa
sses over an | 142 // single bytes. This has the side effect of allowing very fast analysis pa
sses over an |
| 132 // SkRecord looking for just patterns of draw commands (or using this as a q
uick reject | 143 // SkRecord looking for just patterns of draw commands (or using this as a q
uick reject |
| 133 // mechanism) though there's admittedly not a very good API exposed publical
ly for this. | 144 // mechanism) though there's admittedly not a very good API exposed publical
ly for this. |
| 134 // | 145 // |
| 135 // The cost to append a T into this structure is 1 + sizeof(void*) + sizeof(
T). | 146 // The cost to append a T into this structure is 1 + sizeof(void*) + sizeof(
T). |
| 136 | 147 |
| 148 // A mutator that can be used with replace to destroy canvas commands. |
| 149 struct Destroyer { |
| 150 template <typename T> |
| 151 void operator()(T* record) { record->~T(); } |
| 152 }; |
| 137 | 153 |
| 138 // Logically the same as SkRecords::Type, but packed into 8 bits. | 154 // Logically the same as SkRecords::Type, but packed into 8 bits. |
| 139 struct Type8 { | 155 struct Type8 { |
| 140 public: | 156 public: |
| 141 // This intentionally converts implicitly back and forth. | 157 // This intentionally converts implicitly back and forth. |
| 142 Type8(SkRecords::Type type) : fType(type) { SkASSERT(*this == type); } | 158 Type8(SkRecords::Type type) : fType(type) { SkASSERT(*this == type); } |
| 143 operator SkRecords::Type () { return (SkRecords::Type)fType; } | 159 operator SkRecords::Type () { return (SkRecords::Type)fType; } |
| 144 | 160 |
| 145 private: | 161 private: |
| 146 uint8_t fType; | 162 uint8_t fType; |
| 147 }; | 163 }; |
| 148 | 164 |
| 149 // An untyped pointer to some bytes in fAlloc. This is the interface for po
lymorphic dispatch: | 165 // An untyped pointer to some bytes in fAlloc. This is the interface for po
lymorphic dispatch: |
| 150 // visit() and mutate() work with the parallel fTypes array to do the work o
f a vtable. | 166 // visit() and mutate() work with the parallel fTypes array to do the work o
f a vtable. |
| 151 struct Record { | 167 struct Record { |
| 152 public: | 168 public: |
| 153 // Point this record to its data in fAlloc. Returns ptr for convenience
. | 169 // Point this record to its data in fAlloc. Returns ptr for convenience
. |
| 154 template <typename T> | 170 template <typename T> |
| 155 T* set(T* ptr) { | 171 T* set(T* ptr) { |
| 156 fPtr = ptr; | 172 fPtr = ptr; |
| 157 return ptr; | 173 return ptr; |
| 158 } | 174 } |
| 159 | 175 |
| 176 // Get the data in fAlloc, assuming it's of type T. |
| 177 template <typename T> |
| 178 T* ptr() const { return (T*)fPtr; } |
| 179 |
| 160 // Visit this record with functor F (see public API above) assuming the
record we're | 180 // Visit this record with functor F (see public API above) assuming the
record we're |
| 161 // pointing to has this type. | 181 // pointing to has this type. |
| 162 template <typename F> | 182 template <typename F> |
| 163 void visit(Type8 type, F& f) const { | 183 void visit(Type8 type, F& f) const { |
| 164 #define CASE(T) case SkRecords::T##_Type: return f(*this->ptr<SkRecords:
:T>()); | 184 #define CASE(T) case SkRecords::T##_Type: return f(*this->ptr<SkRecords:
:T>()); |
| 165 switch(type) { SK_RECORD_TYPES(CASE) } | 185 switch(type) { SK_RECORD_TYPES(CASE) } |
| 166 #undef CASE | 186 #undef CASE |
| 167 } | 187 } |
| 168 | 188 |
| 169 // Mutate this record with functor F (see public API above) assuming the
record we're | 189 // Mutate this record with functor F (see public API above) assuming the
record we're |
| 170 // pointing to has this type. | 190 // pointing to has this type. |
| 171 template <typename F> | 191 template <typename F> |
| 172 void mutate(Type8 type, F& f) { | 192 void mutate(Type8 type, F& f) { |
| 173 #define CASE(T) case SkRecords::T##_Type: return f(this->ptr<SkRecords::
T>()); | 193 #define CASE(T) case SkRecords::T##_Type: return f(this->ptr<SkRecords::
T>()); |
| 174 switch(type) { SK_RECORD_TYPES(CASE) } | 194 switch(type) { SK_RECORD_TYPES(CASE) } |
| 175 #undef CASE | 195 #undef CASE |
| 176 } | 196 } |
| 177 | 197 |
| 178 private: | 198 private: |
| 179 template <typename T> | |
| 180 T* ptr() const { return (T*)fPtr; } | |
| 181 | |
| 182 void* fPtr; | 199 void* fPtr; |
| 183 }; | 200 }; |
| 184 | 201 |
| 185 // fAlloc needs to be a data structure which can append variable length data
in contiguous | 202 // fAlloc needs to be a data structure which can append variable length data
in contiguous |
| 186 // chunks, returning a stable handle to that data for later retrieval. | 203 // chunks, returning a stable handle to that data for later retrieval. |
| 187 // | 204 // |
| 188 // fRecords and fTypes need to be data structures that can append fixed leng
th data, and need to | 205 // fRecords and fTypes need to be data structures that can append fixed leng
th data, and need to |
| 189 // support efficient forward iteration. (They don't need to be contiguous o
r indexable.) | 206 // support efficient forward iteration. (They don't need to be contiguous o
r indexable.) |
| 190 | 207 |
| 191 SkChunkAlloc fAlloc; | 208 SkChunkAlloc fAlloc; |
| 192 SkAutoTMalloc<Record> fRecords; | 209 SkAutoTMalloc<Record> fRecords; |
| 193 SkAutoTMalloc<Type8> fTypes; | 210 SkAutoTMalloc<Type8> fTypes; |
| 194 // fCount and fReserved measure both fRecords and fTypes, which always grow
in lock step. | 211 // fCount and fReserved measure both fRecords and fTypes, which always grow
in lock step. |
| 195 unsigned fCount; | 212 unsigned fCount; |
| 196 unsigned fReserved; | 213 unsigned fReserved; |
| 197 const unsigned kFirstReserveCount; | 214 const unsigned kFirstReserveCount; |
| 198 }; | 215 }; |
| 199 | 216 |
| 200 #endif//SkRecord_DEFINED | 217 #endif//SkRecord_DEFINED |
| OLD | NEW |