1 /*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18 #include "GrInOrderDrawBuffer.h"
19 #include "GrTexture.h"
20 #include "GrBufferAllocPool.h"
21 #include "GrIndexBuffer.h"
22 #include "GrVertexBuffer.h"
23 #include "GrGpu.h"
24
GrInOrderDrawBuffer(GrVertexBufferAllocPool * vertexPool,GrIndexBufferAllocPool * indexPool)25 GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool,
26 GrIndexBufferAllocPool* indexPool) :
27 fDraws(&fDrawStorage),
28 fStates(&fStateStorage),
29 fClears(&fClearStorage),
30 fClips(&fClipStorage),
31 fClipSet(true),
32
33 fLastRectVertexLayout(0),
34 fQuadIndexBuffer(NULL),
35 fMaxQuads(0),
36 fCurrQuad(0),
37
38 fVertexPool(*vertexPool),
39 fCurrPoolVertexBuffer(NULL),
40 fCurrPoolStartVertex(0),
41 fIndexPool(*indexPool),
42 fCurrPoolIndexBuffer(NULL),
43 fCurrPoolStartIndex(0),
44 fReservedVertexBytes(0),
45 fReservedIndexBytes(0),
46 fUsedReservedVertexBytes(0),
47 fUsedReservedIndexBytes(0) {
48 GrAssert(NULL != vertexPool);
49 GrAssert(NULL != indexPool);
50 }
51
~GrInOrderDrawBuffer()52 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
53 this->reset();
54 GrSafeUnref(fQuadIndexBuffer);
55 }
56
initializeDrawStateAndClip(const GrDrawTarget & target)57 void GrInOrderDrawBuffer::initializeDrawStateAndClip(const GrDrawTarget& target) {
58 this->copyDrawState(target);
59 this->setClip(target.getClip());
60 }
61
setQuadIndexBuffer(const GrIndexBuffer * indexBuffer)62 void GrInOrderDrawBuffer::setQuadIndexBuffer(const GrIndexBuffer* indexBuffer) {
63 bool newIdxBuffer = fQuadIndexBuffer != indexBuffer;
64 if (newIdxBuffer) {
65 GrSafeUnref(fQuadIndexBuffer);
66 fQuadIndexBuffer = indexBuffer;
67 GrSafeRef(fQuadIndexBuffer);
68 fCurrQuad = 0;
69 fMaxQuads = (NULL == indexBuffer) ? 0 : indexBuffer->maxQuads();
70 } else {
71 GrAssert((NULL == indexBuffer && 0 == fMaxQuads) ||
72 (indexBuffer->maxQuads() == fMaxQuads));
73 }
74 }
75
drawRect(const GrRect & rect,const GrMatrix * matrix,StageBitfield stageEnableBitfield,const GrRect * srcRects[],const GrMatrix * srcMatrices[])76 void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
77 const GrMatrix* matrix,
78 StageBitfield stageEnableBitfield,
79 const GrRect* srcRects[],
80 const GrMatrix* srcMatrices[]) {
81
82 GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad));
83 GrAssert(!(fDraws.empty() && fCurrQuad));
84 GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer));
85
86 // if we have a quad IB then either append to the previous run of
87 // rects or start a new run
88 if (fMaxQuads) {
89
90 bool appendToPreviousDraw = false;
91 GrVertexLayout layout = GetRectVertexLayout(stageEnableBitfield, srcRects);
92 AutoReleaseGeometry geo(this, layout, 4, 0);
93 AutoViewMatrixRestore avmr(this);
94 GrMatrix combinedMatrix = this->getViewMatrix();
95 this->setViewMatrix(GrMatrix::I());
96 if (NULL != matrix) {
97 combinedMatrix.preConcat(*matrix);
98 }
99
100 SetRectVertices(rect, &combinedMatrix, srcRects, srcMatrices, layout, geo.vertices());
101
102 // we don't want to miss an opportunity to batch rects together
103 // simply because the clip has changed if the clip doesn't affect
104 // the rect.
105 bool disabledClip = false;
106 if (this->isClipState() && fClip.isRect()) {
107
108 GrRect clipRect = fClip.getRect(0);
109 // If the clip rect touches the edge of the viewport, extended it
110 // out (close) to infinity to avoid bogus intersections.
111 // We might consider a more exact clip to viewport if this
112 // conservative test fails.
113 const GrRenderTarget* target = this->getRenderTarget();
114 if (0 >= clipRect.fLeft) {
115 clipRect.fLeft = GR_ScalarMin;
116 }
117 if (target->width() <= clipRect.fRight) {
118 clipRect.fRight = GR_ScalarMax;
119 }
120 if (0 >= clipRect.top()) {
121 clipRect.fTop = GR_ScalarMin;
122 }
123 if (target->height() <= clipRect.fBottom) {
124 clipRect.fBottom = GR_ScalarMax;
125 }
126 int stride = VertexSize(layout);
127 bool insideClip = true;
128 for (int v = 0; v < 4; ++v) {
129 const GrPoint& p = *GetVertexPoint(geo.vertices(), v, stride);
130 if (!clipRect.contains(p)) {
131 insideClip = false;
132 break;
133 }
134 }
135 if (insideClip) {
136 this->disableState(kClip_StateBit);
137 disabledClip = true;
138 }
139 }
140 if (!needsNewClip() && !needsNewState() && fCurrQuad > 0 &&
141 fCurrQuad < fMaxQuads && layout == fLastRectVertexLayout) {
142
143 int vsize = VertexSize(layout);
144
145 Draw& lastDraw = fDraws.back();
146
147 GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer);
148 GrAssert(kTriangles_PrimitiveType == lastDraw.fPrimitiveType);
149 GrAssert(0 == lastDraw.fVertexCount % 4);
150 GrAssert(0 == lastDraw.fIndexCount % 6);
151 GrAssert(0 == lastDraw.fStartIndex);
152
153 bool clearSinceLastDraw =
154 fClears.count() &&
155 fClears.back().fBeforeDrawIdx == fDraws.count();
156
157 appendToPreviousDraw = !clearSinceLastDraw &&
158 lastDraw.fVertexBuffer == fCurrPoolVertexBuffer &&
159 (fCurrQuad * 4 + lastDraw.fStartVertex) == fCurrPoolStartVertex;
160 if (appendToPreviousDraw) {
161 lastDraw.fVertexCount += 4;
162 lastDraw.fIndexCount += 6;
163 fCurrQuad += 1;
164 GrAssert(0 == fUsedReservedVertexBytes);
165 fUsedReservedVertexBytes = 4 * vsize;
166 }
167 }
168 if (!appendToPreviousDraw) {
169 this->setIndexSourceToBuffer(fQuadIndexBuffer);
170 drawIndexed(kTriangles_PrimitiveType, 0, 0, 4, 6);
171 fCurrQuad = 1;
172 fLastRectVertexLayout = layout;
173 }
174 if (disabledClip) {
175 this->enableState(kClip_StateBit);
176 }
177 } else {
178 INHERITED::drawRect(rect, matrix, stageEnableBitfield, srcRects, srcMatrices);
179 }
180 }
181
drawIndexed(GrPrimitiveType primitiveType,int startVertex,int startIndex,int vertexCount,int indexCount)182 void GrInOrderDrawBuffer::drawIndexed(GrPrimitiveType primitiveType,
183 int startVertex,
184 int startIndex,
185 int vertexCount,
186 int indexCount) {
187
188 if (!vertexCount || !indexCount) {
189 return;
190 }
191
192 fCurrQuad = 0;
193
194 Draw& draw = fDraws.push_back();
195 draw.fPrimitiveType = primitiveType;
196 draw.fStartVertex = startVertex;
197 draw.fStartIndex = startIndex;
198 draw.fVertexCount = vertexCount;
199 draw.fIndexCount = indexCount;
200
201 draw.fClipChanged = this->needsNewClip();
202 if (draw.fClipChanged) {
203 this->pushClip();
204 }
205
206 draw.fStateChanged = this->needsNewState();
207 if (draw.fStateChanged) {
208 this->pushState();
209 }
210
211 draw.fVertexLayout = fGeometrySrc.fVertexLayout;
212 switch (fGeometrySrc.fVertexSrc) {
213 case kBuffer_GeometrySrcType:
214 draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
215 break;
216 case kReserved_GeometrySrcType: {
217 size_t vertexBytes = (vertexCount + startVertex) *
218 VertexSize(fGeometrySrc.fVertexLayout);
219 fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes, vertexBytes);
220 } // fallthrough
221 case kArray_GeometrySrcType:
222 draw.fVertexBuffer = fCurrPoolVertexBuffer;
223 draw.fStartVertex += fCurrPoolStartVertex;
224 break;
225 default:
226 GrCrash("unknown geom src type");
227 }
228 draw.fVertexBuffer->ref();
229
230 switch (fGeometrySrc.fIndexSrc) {
231 case kBuffer_GeometrySrcType:
232 draw.fIndexBuffer = fGeometrySrc.fIndexBuffer;
233 break;
234 case kReserved_GeometrySrcType: {
235 size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t);
236 fUsedReservedIndexBytes = GrMax(fUsedReservedIndexBytes, indexBytes);
237 } // fallthrough
238 case kArray_GeometrySrcType:
239 draw.fIndexBuffer = fCurrPoolIndexBuffer;
240 draw.fStartIndex += fCurrPoolStartVertex;
241 break;
242 default:
243 GrCrash("unknown geom src type");
244 }
245 draw.fIndexBuffer->ref();
246 }
247
drawNonIndexed(GrPrimitiveType primitiveType,int startVertex,int vertexCount)248 void GrInOrderDrawBuffer::drawNonIndexed(GrPrimitiveType primitiveType,
249 int startVertex,
250 int vertexCount) {
251 if (!vertexCount) {
252 return;
253 }
254
255 fCurrQuad = 0;
256
257 Draw& draw = fDraws.push_back();
258 draw.fPrimitiveType = primitiveType;
259 draw.fStartVertex = startVertex;
260 draw.fStartIndex = 0;
261 draw.fVertexCount = vertexCount;
262 draw.fIndexCount = 0;
263
264 draw.fClipChanged = this->needsNewClip();
265 if (draw.fClipChanged) {
266 this->pushClip();
267 }
268
269 draw.fStateChanged = this->needsNewState();
270 if (draw.fStateChanged) {
271 this->pushState();
272 }
273
274 draw.fVertexLayout = fGeometrySrc.fVertexLayout;
275 switch (fGeometrySrc.fVertexSrc) {
276 case kBuffer_GeometrySrcType:
277 draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
278 break;
279 case kReserved_GeometrySrcType: {
280 size_t vertexBytes = (vertexCount + startVertex) *
281 VertexSize(fGeometrySrc.fVertexLayout);
282 fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes,
283 vertexBytes);
284 } // fallthrough
285 case kArray_GeometrySrcType:
286 draw.fVertexBuffer = fCurrPoolVertexBuffer;
287 draw.fStartVertex += fCurrPoolStartVertex;
288 break;
289 default:
290 GrCrash("unknown geom src type");
291 }
292 draw.fVertexBuffer->ref();
293 draw.fIndexBuffer = NULL;
294 }
295
clear(const GrIRect * rect,GrColor color)296 void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color) {
297 GrIRect r;
298 if (NULL == rect) {
299 // We could do something smart and remove previous draws and clears to
300 // the current render target. If we get that smart we have to make sure
301 // those draws aren't read before this clear (render-to-texture).
302 r.setLTRB(0, 0,
303 this->getRenderTarget()->width(),
304 this->getRenderTarget()->height());
305 rect = &r;
306 }
307 Clear& clr = fClears.push_back();
308 clr.fColor = color;
309 clr.fBeforeDrawIdx = fDraws.count();
310 clr.fRect = *rect;
311 }
312
reset()313 void GrInOrderDrawBuffer::reset() {
314 GrAssert(!fReservedGeometry.fLocked);
315 uint32_t numStates = fStates.count();
316 for (uint32_t i = 0; i < numStates; ++i) {
317 const DrState& dstate = this->accessSavedDrawState(fStates[i]);
318 for (int s = 0; s < kNumStages; ++s) {
319 GrSafeUnref(dstate.fTextures[s]);
320 }
321 GrSafeUnref(dstate.fRenderTarget);
322 }
323 int numDraws = fDraws.count();
324 for (int d = 0; d < numDraws; ++d) {
325 // we always have a VB, but not always an IB
326 GrAssert(NULL != fDraws[d].fVertexBuffer);
327 fDraws[d].fVertexBuffer->unref();
328 GrSafeUnref(fDraws[d].fIndexBuffer);
329 }
330 fDraws.reset();
331 fStates.reset();
332
333 fClears.reset();
334
335 fVertexPool.reset();
336 fIndexPool.reset();
337
338 fClips.reset();
339
340 fCurrQuad = 0;
341 }
342
playback(GrDrawTarget * target)343 void GrInOrderDrawBuffer::playback(GrDrawTarget* target) {
344 GrAssert(!fReservedGeometry.fLocked);
345 GrAssert(NULL != target);
346 GrAssert(target != this); // not considered and why?
347
348 int numDraws = fDraws.count();
349 if (!numDraws) {
350 return;
351 }
352
353 fVertexPool.unlock();
354 fIndexPool.unlock();
355
356 GrDrawTarget::AutoStateRestore asr(target);
357 GrDrawTarget::AutoClipRestore acr(target);
358 // important to not mess with reserve/lock geometry in the target with this
359 // on the stack.
360 GrDrawTarget::AutoGeometrySrcRestore agsr(target);
361
362 int currState = ~0;
363 int currClip = ~0;
364 int currClear = 0;
365
366 for (int i = 0; i < numDraws; ++i) {
367 while (currClear < fClears.count() &&
368 i == fClears[currClear].fBeforeDrawIdx) {
369 target->clear(&fClears[currClear].fRect, fClears[currClear].fColor);
370 ++currClear;
371 }
372
373 const Draw& draw = fDraws[i];
374 if (draw.fStateChanged) {
375 ++currState;
376 target->restoreDrawState(fStates[currState]);
377 }
378 if (draw.fClipChanged) {
379 ++currClip;
380 target->setClip(fClips[currClip]);
381 }
382
383 target->setVertexSourceToBuffer(draw.fVertexLayout, draw.fVertexBuffer);
384
385 if (draw.fIndexCount) {
386 target->setIndexSourceToBuffer(draw.fIndexBuffer);
387 }
388
389 if (draw.fIndexCount) {
390 target->drawIndexed(draw.fPrimitiveType,
391 draw.fStartVertex,
392 draw.fStartIndex,
393 draw.fVertexCount,
394 draw.fIndexCount);
395 } else {
396 target->drawNonIndexed(draw.fPrimitiveType,
397 draw.fStartVertex,
398 draw.fVertexCount);
399 }
400 }
401 while (currClear < fClears.count()) {
402 GrAssert(fDraws.count() == fClears[currClear].fBeforeDrawIdx);
403 target->clear(&fClears[currClear].fRect, fClears[currClear].fColor);
404 ++currClear;
405 }
406 }
407
geometryHints(GrVertexLayout vertexLayout,int * vertexCount,int * indexCount) const408 bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout,
409 int* vertexCount,
410 int* indexCount) const {
411 // we will recommend a flush if the data could fit in a single
412 // preallocated buffer but none are left and it can't fit
413 // in the current buffer (which may not be prealloced).
414 bool flush = false;
415 if (NULL != indexCount) {
416 int32_t currIndices = fIndexPool.currentBufferIndices();
417 if (*indexCount > currIndices &&
418 (!fIndexPool.preallocatedBuffersRemaining() &&
419 *indexCount <= fIndexPool.preallocatedBufferIndices())) {
420
421 flush = true;
422 }
423 *indexCount = currIndices;
424 }
425 if (NULL != vertexCount) {
426 int32_t currVertices = fVertexPool.currentBufferVertices(vertexLayout);
427 if (*vertexCount > currVertices &&
428 (!fVertexPool.preallocatedBuffersRemaining() &&
429 *vertexCount <= fVertexPool.preallocatedBufferVertices(vertexLayout))) {
430
431 flush = true;
432 }
433 *vertexCount = currVertices;
434 }
435 return flush;
436 }
437
onAcquireGeometry(GrVertexLayout vertexLayout,void ** vertices,void ** indices)438 bool GrInOrderDrawBuffer::onAcquireGeometry(GrVertexLayout vertexLayout,
439 void** vertices,
440 void** indices) {
441 GrAssert(!fReservedGeometry.fLocked);
442 if (fReservedGeometry.fVertexCount) {
443 GrAssert(NULL != vertices);
444 GrAssert(0 == fReservedVertexBytes);
445 GrAssert(0 == fUsedReservedVertexBytes);
446
447 fReservedVertexBytes = VertexSize(vertexLayout) *
448 fReservedGeometry.fVertexCount;
449 *vertices = fVertexPool.makeSpace(vertexLayout,
450 fReservedGeometry.fVertexCount,
451 &fCurrPoolVertexBuffer,
452 &fCurrPoolStartVertex);
453 if (NULL == *vertices) {
454 return false;
455 }
456 }
457 if (fReservedGeometry.fIndexCount) {
458 GrAssert(NULL != indices);
459 GrAssert(0 == fReservedIndexBytes);
460 GrAssert(0 == fUsedReservedIndexBytes);
461
462 *indices = fIndexPool.makeSpace(fReservedGeometry.fIndexCount,
463 &fCurrPoolIndexBuffer,
464 &fCurrPoolStartIndex);
465 if (NULL == *indices) {
466 fVertexPool.putBack(fReservedVertexBytes);
467 fReservedVertexBytes = 0;
468 fCurrPoolVertexBuffer = NULL;
469 return false;
470 }
471 }
472 return true;
473 }
474
onReleaseGeometry()475 void GrInOrderDrawBuffer::onReleaseGeometry() {
476 GrAssert(fUsedReservedVertexBytes <= fReservedVertexBytes);
477 GrAssert(fUsedReservedIndexBytes <= fReservedIndexBytes);
478
479 size_t vertexSlack = fReservedVertexBytes - fUsedReservedVertexBytes;
480 fVertexPool.putBack(vertexSlack);
481
482 size_t indexSlack = fReservedIndexBytes - fUsedReservedIndexBytes;
483 fIndexPool.putBack(indexSlack);
484
485 fReservedVertexBytes = 0;
486 fReservedIndexBytes = 0;
487 fUsedReservedVertexBytes = 0;
488 fUsedReservedIndexBytes = 0;
489 fCurrPoolVertexBuffer = 0;
490 fCurrPoolStartVertex = 0;
491
492 }
493
onSetVertexSourceToArray(const void * vertexArray,int vertexCount)494 void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray,
495 int vertexCount) {
496 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
497 #if GR_DEBUG
498 bool success =
499 #endif
500 fVertexPool.appendVertices(fGeometrySrc.fVertexLayout,
501 vertexCount,
502 vertexArray,
503 &fCurrPoolVertexBuffer,
504 &fCurrPoolStartVertex);
505 GR_DEBUGASSERT(success);
506 }
507
onSetIndexSourceToArray(const void * indexArray,int indexCount)508 void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray,
509 int indexCount) {
510 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
511 #if GR_DEBUG
512 bool success =
513 #endif
514 fIndexPool.appendIndices(indexCount,
515 indexArray,
516 &fCurrPoolIndexBuffer,
517 &fCurrPoolStartIndex);
518 GR_DEBUGASSERT(success);
519 }
520
needsNewState() const521 bool GrInOrderDrawBuffer::needsNewState() const {
522 if (fStates.empty()) {
523 return true;
524 } else {
525 const DrState& old = this->accessSavedDrawState(fStates.back());
526 return old != fCurrDrawState;
527 }
528 }
529
pushState()530 void GrInOrderDrawBuffer::pushState() {
531 for (int s = 0; s < kNumStages; ++s) {
532 GrSafeRef(fCurrDrawState.fTextures[s]);
533 }
534 GrSafeRef(fCurrDrawState.fRenderTarget);
535 this->saveCurrentDrawState(&fStates.push_back());
536 }
537
needsNewClip() const538 bool GrInOrderDrawBuffer::needsNewClip() const {
539 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
540 if (fClips.empty() || (fClipSet && fClips.back() != fClip)) {
541 return true;
542 }
543 }
544 return false;
545 }
546
pushClip()547 void GrInOrderDrawBuffer::pushClip() {
548 fClips.push_back() = fClip;
549 fClipSet = false;
550 }
551
clipWillBeSet(const GrClip & newClip)552 void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip) {
553 fClipSet = true;
554 }
555