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 |