Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2014 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #ifndef GrCmdBuffer_DEFINED | |
| 9 #define GrCmdBuffer_DEFINED | |
| 10 | |
| 11 #include "SkTemplates.h" | |
| 12 #include "SkTypes.h" | |
| 13 | |
| 14 class GrDrawTarget; | |
| 15 | |
| 16 /** | |
| 17 * Ordered list of commands for a GrDrawTarget. | |
| 18 * | |
| 19 * The commands are stored contiguously within large blocks of memory, in order avoid | |
| 20 * excessive calls to malloc(). | |
| 21 * | |
| 22 * @param TAlign A type whose size is the desired alignment for command allocat ions. | |
| 23 * Using long double will always meet alignment requirements, but this may | |
| 24 * be smaller if the largest alignment requirement is know ahead of time. | |
| 25 */ | |
| 26 template<typename TAlign = long double> class GrCmdBuffer : SkNoncopyable { | |
|
bsalomon
2014/10/03 15:04:45
Do long doubles require alignment? Wondering if vo
Chris Dalton
2014/10/03 16:16:24
According to this, long double gets aligned at 16
bsalomon
2014/10/03 18:43:03
Interesting. Maybe just have no default?
Chris Dalton
2014/10/03 19:38:40
Sure
Chris Dalton
2014/10/08 19:29:02
Done.
| |
| 27 public: | |
| 28 class Cmd; | |
| 29 class Iter; | |
| 30 | |
| 31 /** | |
| 32 * Create a command buffer | |
| 33 * | |
| 34 * @param initialSizeInBytes The amount of memory reserved by the command b uffer | |
| 35 * initially, and after calls to reset(). | |
| 36 */ | |
| 37 GrCmdBuffer(int initialSizeInBytes) | |
| 38 : fHeadBlock(bytes_to_length(initialSizeInBytes)), | |
| 39 fTailBlock(&fHeadBlock), | |
| 40 fBack(0), | |
| 41 fFirstCmd(NULL), | |
| 42 fLastCmd(NULL) {} | |
| 43 | |
| 44 ~GrCmdBuffer() { this->reset(); } | |
| 45 | |
| 46 bool empty() { | |
| 47 SkASSERT((NULL == fFirstCmd) == (NULL == fLastCmd)); | |
| 48 return NULL == fFirstCmd; | |
| 49 } | |
| 50 | |
| 51 Cmd& front() { | |
| 52 SkASSERT(!this->empty()); | |
| 53 return *fFirstCmd; | |
| 54 } | |
| 55 | |
| 56 Cmd& back() { | |
| 57 SkASSERT(!this->empty()); | |
| 58 return *fLastCmd; | |
| 59 } | |
| 60 | |
| 61 /** | |
| 62 * Destruct all commands in the command buffer and reset to empty. | |
| 63 */ | |
| 64 void reset(); | |
| 65 | |
| 66 /** | |
| 67 * Push a command to the back of the buffer, with optional arguments to for its | |
| 68 * constructor. TCmd must be a subclass of GrCmdBuffer::Cmd. | |
| 69 */ | |
| 70 template<typename TCmd> | |
| 71 TCmd& push_back() { return this->push_back_size<TCmd>(sizeof(TCmd)); } | |
|
bsalomon
2014/10/03 15:04:45
Instead of all these could we use something like a
Chris Dalton
2014/10/03 16:16:24
I did consider that approach. The only problem is
bsalomon
2014/10/03 18:43:03
In the other instances where we've done this we ju
Chris Dalton
2014/10/03 19:38:40
Ok, this will work now. (The issue used to be that
Chris Dalton
2014/10/08 19:29:02
Done.
| |
| 72 template<typename TCmd, typename TArg1> | |
| 73 TCmd& push_back(const TArg1& a) { return this->push_back_size<TCmd>(sizeof(T Cmd), a); } | |
| 74 template<typename TCmd, typename TArg1, typename TArg2> | |
| 75 TCmd& push_back(const TArg1& a, const TArg2& b) { return this->push_back_siz e<TCmd>(sizeof(TCmd), a, b); } | |
| 76 template<typename TCmd, typename TArg1, typename TArg2, typename TArg3> | |
| 77 TCmd& push_back(const TArg1& a, const TArg2& b, const TArg3& c) { return thi s->push_back_size<TCmd>(sizeof(TCmd), a, b, c); } | |
| 78 | |
| 79 /** | |
| 80 * Push a variable-size command to the back of the buffer, with optional arg uments for | |
| 81 * its constructor. TCmd must be a subclass of GrCmdBuffer::Cmd. | |
| 82 * | |
| 83 * @param sizeInBytes The amount of memory to allocate for the command. Thi s may be | |
|
bsalomon
2014/10/03 15:04:45
Wonder whether we should only take the extra paylo
Chris Dalton
2014/10/03 16:16:24
The Cmd base class could also maybe know where to
bsalomon
2014/10/03 18:43:03
Sure but then we need to store ptr. If it's a para
Chris Dalton
2014/10/03 19:38:40
So at execute time, the client code doesn't know w
Chris Dalton
2014/10/08 19:29:02
Left as-is for now, to resemble the way this would
| |
| 84 * larger than sizeof(TCmd) to accomodate variable-lengt h arrays. | |
| 85 */ | |
| 86 template<typename TCmd> | |
| 87 TCmd& push_back_size(int sizeInBytes); | |
| 88 template<typename TCmd, typename TArg1> | |
| 89 TCmd& push_back_size(int sizeInBytes, const TArg1&); | |
| 90 template<typename TCmd, typename TArg1, typename TArg2> | |
| 91 TCmd& push_back_size(int sizeInBytes, const TArg1&, const TArg2&); | |
| 92 template<typename TCmd, typename TArg1, typename TArg2, typename TArg3> | |
| 93 TCmd& push_back_size(int sizeInBytes, const TArg1&, const TArg2&, const TArg 3&); | |
| 94 | |
| 95 private: | |
| 96 static int bytes_to_length(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeof(TAlign); } | |
| 97 | |
| 98 void* push_back_raw(int sizeInBytes); | |
| 99 template<typename T> T& init_back(T* cmd); | |
| 100 | |
| 101 struct Block { | |
| 102 Block(int length) : fLength(length), fBuffer(fLength) {} | |
| 103 const int fLength; | |
| 104 SkAutoTMalloc<TAlign> fBuffer; | |
| 105 SkAutoTDelete<Block> fNext; | |
| 106 }; | |
| 107 Block fHeadBlock; | |
| 108 Block* fTailBlock; | |
| 109 int fBack; | |
| 110 | |
| 111 Cmd* fFirstCmd; | |
| 112 Cmd* fLastCmd; | |
| 113 | |
| 114 friend class Iter; | |
| 115 }; | |
| 116 | |
| 117 //////////////////////////////////////////////////////////////////////////////// | |
| 118 | |
| 119 template<typename TAlign> | |
| 120 class GrCmdBuffer<TAlign>::Cmd : SkNoncopyable { | |
| 121 public: | |
| 122 Cmd() : fNext(NULL) {} | |
| 123 virtual ~Cmd() {} | |
| 124 virtual void execute(GrDrawTarget*) = 0; | |
| 125 | |
| 126 uint8_t type() const { return fType; } | |
| 127 void resetType(uint8_t type) { fType = type; } | |
| 128 | |
| 129 private: | |
| 130 Cmd* fNext; | |
| 131 uint8_t fType; | |
|
bsalomon
2014/10/03 15:04:45
Is the type really just just used to hang the debu
Chris Dalton
2014/10/03 16:16:24
At least for now, concatInstancedDraw() also check
bsalomon
2014/10/03 18:43:03
The GrIODB could just have a bool, fLastCmdWasDraw
Chris Dalton
2014/10/03 19:38:40
Oh, fLastCmdWasDraw, I like that
Chris Dalton
2014/10/08 19:29:02
I ended up leaving fType in the base Cmd class. It
| |
| 132 | |
| 133 friend class GrCmdBuffer; | |
| 134 }; | |
| 135 | |
| 136 template<typename TAlign> | |
| 137 class GrCmdBuffer<TAlign>::Iter { | |
| 138 public: | |
| 139 Iter(GrCmdBuffer& cmdBuffer) : fCmd(NULL), fNext(cmdBuffer.fFirstCmd) {} | |
| 140 | |
| 141 bool next() { | |
| 142 if (NULL == fNext) { | |
| 143 return false; | |
| 144 } | |
| 145 fCmd = fNext; | |
| 146 fNext = fCmd->fNext; | |
| 147 return true; | |
| 148 } | |
| 149 | |
| 150 Cmd* operator->() { | |
| 151 SkASSERT(fCmd); | |
| 152 return fCmd; | |
| 153 } | |
| 154 | |
| 155 private: | |
| 156 Cmd* fCmd; | |
| 157 Cmd* fNext; | |
| 158 }; | |
| 159 | |
| 160 template<typename TAlign> | |
| 161 void GrCmdBuffer<TAlign>::reset() { | |
| 162 Iter iter(*this); | |
| 163 while (iter.next()) { | |
| 164 iter->~Cmd(); | |
| 165 } | |
| 166 fHeadBlock.fNext.free(); | |
| 167 fTailBlock = &fHeadBlock; | |
| 168 fBack = 0; | |
| 169 fFirstCmd = fLastCmd = NULL; | |
| 170 } | |
| 171 | |
| 172 template<typename TAlign> | |
| 173 void* GrCmdBuffer<TAlign>::push_back_raw(int sizeInBytes) { | |
| 174 const int cmdLength = bytes_to_length(sizeInBytes); | |
| 175 | |
| 176 if (fBack + cmdLength > fTailBlock->fLength) { | |
| 177 SkASSERT(NULL == fTailBlock->fNext.get()); | |
| 178 Block* next = SkNEW_ARGS(Block, (SkTMax(2 * fTailBlock->fLength, cmdLeng th))); | |
| 179 fTailBlock->fNext.reset(next); | |
| 180 fTailBlock = next; | |
| 181 fBack = 0; | |
| 182 } | |
| 183 | |
| 184 void* data = &fTailBlock->fBuffer[fBack]; | |
| 185 fBack += cmdLength; | |
| 186 return data; | |
| 187 } | |
| 188 | |
| 189 template<typename TAlign> | |
| 190 template<typename T> | |
| 191 T& GrCmdBuffer<TAlign>::init_back(T* cmd) { | |
| 192 cmd->fType = T::kCmdType; | |
| 193 if (NULL == fFirstCmd) { | |
| 194 SkASSERT(NULL == fLastCmd); | |
| 195 fFirstCmd = fLastCmd = cmd; | |
| 196 } else { | |
| 197 SkASSERT(NULL != fLastCmd); | |
| 198 fLastCmd->fNext = cmd; | |
| 199 fLastCmd = cmd; | |
| 200 } | |
| 201 return *cmd; | |
| 202 } | |
| 203 | |
| 204 template<typename TAlign> | |
| 205 template<typename TCmd> | |
| 206 TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes) { | |
| 207 SkASSERT(sizeInBytes >= (int)sizeof(TCmd)); | |
| 208 TCmd* cmd = SkNEW_PLACEMENT(this->push_back_raw(sizeInBytes), TCmd); | |
| 209 return this->init_back(cmd); | |
| 210 } | |
| 211 | |
| 212 template<typename TAlign> | |
| 213 template<typename TCmd, typename TArg1> | |
| 214 TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes, const TArg1& a) { | |
| 215 SkASSERT(sizeInBytes >= (int)sizeof(TCmd)); | |
| 216 TCmd* cmd = SkNEW_PLACEMENT_ARGS(this->push_back_raw(sizeInBytes), TCmd, (a) ); | |
| 217 return this->init_back(cmd); | |
| 218 } | |
| 219 | |
| 220 template<typename TAlign> | |
| 221 template<typename TCmd, typename TArg1, typename TArg2> | |
| 222 TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes, const TArg1& a, const TArg2& b) { | |
| 223 SkASSERT(sizeInBytes >= (int)sizeof(TCmd)); | |
| 224 TCmd* cmd = SkNEW_PLACEMENT_ARGS(this->push_back_raw(sizeInBytes), TCmd, (a, b)); | |
| 225 return this->init_back(cmd); | |
| 226 } | |
| 227 | |
| 228 template<typename TAlign> | |
| 229 template<typename TCmd, typename TArg1, typename TArg2, typename TArg3> | |
| 230 TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes, const TArg1& a, const TArg2& b, const TArg3& c) { | |
| 231 SkASSERT(sizeInBytes >= (int)sizeof(TCmd)); | |
| 232 TCmd* cmd = SkNEW_PLACEMENT_ARGS(this->push_back_raw(sizeInBytes), TCmd, (a, b, c)); | |
| 233 return this->init_back(cmd); | |
| 234 } | |
| 235 | |
| 236 #endif | |
| OLD | NEW |