GrInOrderDrawBuffer.cpp revision 363e546ed626b6dbbc42f5db87b3594bc0b5944b
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "GrInOrderDrawBuffer.h" 11#include "GrBufferAllocPool.h" 12#include "GrGpu.h" 13#include "GrIndexBuffer.h" 14#include "GrPath.h" 15#include "GrRenderTarget.h" 16#include "GrTexture.h" 17#include "GrVertexBuffer.h" 18 19GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu, 20 GrVertexBufferAllocPool* vertexPool, 21 GrIndexBufferAllocPool* indexPool) 22 : fAutoFlushTarget(NULL) 23 , fClipSet(true) 24 , fVertexPool(*vertexPool) 25 , fIndexPool(*indexPool) 26 , fLastRectVertexLayout(0) 27 , fQuadIndexBuffer(NULL) 28 , fMaxQuads(0) 29 , fFlushing(false) { 30 31 fCaps = gpu->getCaps(); 32 33 GrAssert(NULL != vertexPool); 34 GrAssert(NULL != indexPool); 35 36 GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); 37 poolState.fUsedPoolVertexBytes = 0; 38 poolState.fUsedPoolIndexBytes = 0; 39#if GR_DEBUG 40 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; 41 poolState.fPoolStartVertex = ~0; 42 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; 43 poolState.fPoolStartIndex = ~0; 44#endif 45 this->reset(); 46} 47 48GrInOrderDrawBuffer::~GrInOrderDrawBuffer() { 49 this->reset(); 50 // This must be called by before the GrDrawTarget destructor 51 this->releaseGeometry(); 52 GrSafeUnref(fQuadIndexBuffer); 53 GrSafeUnref(fAutoFlushTarget); 54} 55 56void GrInOrderDrawBuffer::setQuadIndexBuffer(const GrIndexBuffer* indexBuffer) { 57 bool newIdxBuffer = fQuadIndexBuffer != indexBuffer; 58 if (newIdxBuffer) { 59 GrSafeUnref(fQuadIndexBuffer); 60 fQuadIndexBuffer = indexBuffer; 61 GrSafeRef(fQuadIndexBuffer); 62 fCurrQuad = 0; 63 fMaxQuads = (NULL == indexBuffer) ? 0 : indexBuffer->maxQuads(); 64 } else { 65 GrAssert((NULL == indexBuffer && 0 == fMaxQuads) || 66 (indexBuffer->maxQuads() == fMaxQuads)); 67 } 68} 69 70//////////////////////////////////////////////////////////////////////////////// 71 72void GrInOrderDrawBuffer::resetDrawTracking() { 73 fCurrQuad = 0; 74 fInstancedDrawTracker.reset(); 75} 76 77void GrInOrderDrawBuffer::drawRect(const GrRect& rect, 78 const SkMatrix* matrix, 79 const GrRect* srcRects[], 80 const SkMatrix* srcMatrices[]) { 81 82 GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad)); 83 GrAssert(!(fDraws.empty() && fCurrQuad)); 84 GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer)); 85 86 GrDrawState* drawState = this->drawState(); 87 88 // if we have a quad IB then either append to the previous run of 89 // rects or start a new run 90 if (fMaxQuads) { 91 92 bool appendToPreviousDraw = false; 93 GrVertexLayout layout = GetRectVertexLayout(srcRects); 94 95 // Batching across colors means we move the draw color into the 96 // rect's vertex colors to allow greater batching (a lot of rects 97 // in a row differing only in color is a common occurence in tables). 98 bool batchAcrossColors = true; 99 if (!this->getCaps().dualSourceBlendingSupport()) { 100 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 101 if (this->getDrawState().isStageEnabled(s)) { 102 // We disable batching across colors when there is a texture 103 // present because (by pushing the the color to the vertices) 104 // Ganesh loses track of the rect's opacity. This, in turn, can 105 // cause some of the blending optimizations to be disabled. This 106 // becomes a huge problem on some of the smaller devices where 107 // shader derivatives and dual source blending aren't supported. 108 // In those cases paths are often drawn to a texture and then 109 // drawn as a texture (using this method). Because dual source 110 // blending is disabled (and the blend optimizations are short 111 // circuited) some of the more esoteric blend modes can no longer 112 // be supported. 113 // TODO: add tracking of batchAcrossColors's opacity 114 batchAcrossColors = false; 115 break; 116 } 117 } 118 } 119 120 if (batchAcrossColors) { 121 layout |= kColor_VertexLayoutBit; 122 } 123 124 AutoReleaseGeometry geo(this, layout, 4, 0); 125 if (!geo.succeeded()) { 126 GrPrintf("Failed to get space for vertices!\n"); 127 return; 128 } 129 SkMatrix combinedMatrix = drawState->getViewMatrix(); 130 // We go to device space so that matrix changes allow us to concat 131 // rect draws. When the caller has provided explicit source rects 132 // then we don't want to modify the stages' matrices. Otherwise 133 // we have to account for the view matrix change in the stage 134 // matrices. 135 uint32_t explicitCoordMask = 0; 136 if (srcRects) { 137 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 138 if (srcRects[s]) { 139 explicitCoordMask |= (1 << s); 140 } 141 } 142 } 143 GrDrawState::AutoDeviceCoordDraw adcd(this->drawState(), explicitCoordMask); 144 if (!adcd.succeeded()) { 145 return; 146 } 147 if (NULL != matrix) { 148 combinedMatrix.preConcat(*matrix); 149 } 150 151 SetRectVertices(rect, &combinedMatrix, srcRects, srcMatrices, 152 this->getDrawState().getColor(), layout, geo.vertices()); 153 154 // Now that the paint's color is stored in the vertices set it to 155 // white so that the following code can batch all the rects regardless 156 // of paint color 157 GrDrawState::AutoColorRestore acr(this->drawState(), 158 batchAcrossColors ? SK_ColorWHITE 159 : this->getDrawState().getColor()); 160 161 // we don't want to miss an opportunity to batch rects together 162 // simply because the clip has changed if the clip doesn't affect 163 // the rect. 164 bool disabledClip = false; 165 166 if (drawState->isClipState()) { 167 168 GrRect devClipRect; 169 bool isIntersectionOfRects = false; 170 171 fClip->fClipStack->getConservativeBounds(-fClip->fOrigin.fX, 172 -fClip->fOrigin.fY, 173 drawState->getRenderTarget()->width(), 174 drawState->getRenderTarget()->height(), 175 &devClipRect, 176 &isIntersectionOfRects); 177 178 if (isIntersectionOfRects) { 179 // If the clip rect touches the edge of the viewport, extended it 180 // out (close) to infinity to avoid bogus intersections. 181 // We might consider a more exact clip to viewport if this 182 // conservative test fails. 183 const GrRenderTarget* target = drawState->getRenderTarget(); 184 if (0 >= devClipRect.fLeft) { 185 devClipRect.fLeft = SK_ScalarMin; 186 } 187 if (target->width() <= devClipRect.fRight) { 188 devClipRect.fRight = SK_ScalarMax; 189 } 190 if (0 >= devClipRect.top()) { 191 devClipRect.fTop = SK_ScalarMin; 192 } 193 if (target->height() <= devClipRect.fBottom) { 194 devClipRect.fBottom = SK_ScalarMax; 195 } 196 int stride = VertexSize(layout); 197 bool insideClip = true; 198 for (int v = 0; v < 4; ++v) { 199 const GrPoint& p = *GetVertexPoint(geo.vertices(), v, stride); 200 if (!devClipRect.contains(p)) { 201 insideClip = false; 202 break; 203 } 204 } 205 if (insideClip) { 206 drawState->disableState(GrDrawState::kClip_StateBit); 207 disabledClip = true; 208 } 209 } 210 } 211 212 if (!this->needsNewClip() && 213 !this->needsNewState() && 214 fCurrQuad > 0 && 215 fCurrQuad < fMaxQuads && 216 layout == fLastRectVertexLayout) { 217 218 int vsize = VertexSize(layout); 219 220 Draw& lastDraw = fDraws.back(); 221 222 GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer); 223 GrAssert(kTriangles_GrPrimitiveType == lastDraw.fPrimitiveType); 224 GrAssert(0 == lastDraw.fVertexCount % 4); 225 GrAssert(0 == lastDraw.fIndexCount % 6); 226 GrAssert(0 == lastDraw.fStartIndex); 227 228 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 229 230 appendToPreviousDraw = 231 kDraw_Cmd == fCmds.back() && 232 lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer && 233 (fCurrQuad * 4 + lastDraw.fStartVertex) == poolState.fPoolStartVertex; 234 235 if (appendToPreviousDraw) { 236 lastDraw.fVertexCount += 4; 237 lastDraw.fIndexCount += 6; 238 fCurrQuad += 1; 239 // we reserved above, so we should be the first 240 // use of this vertex reservation. 241 GrAssert(0 == poolState.fUsedPoolVertexBytes); 242 poolState.fUsedPoolVertexBytes = 4 * vsize; 243 } 244 } 245 if (!appendToPreviousDraw) { 246 this->setIndexSourceToBuffer(fQuadIndexBuffer); 247 this->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 4, 6); 248 fCurrQuad = 1; 249 fLastRectVertexLayout = layout; 250 } 251 if (disabledClip) { 252 drawState->enableState(GrDrawState::kClip_StateBit); 253 } 254 fInstancedDrawTracker.reset(); 255 } else { 256 INHERITED::drawRect(rect, matrix, srcRects, srcMatrices); 257 } 258} 259 260void GrInOrderDrawBuffer::drawIndexedInstances(GrPrimitiveType type, 261 int instanceCount, 262 int verticesPerInstance, 263 int indicesPerInstance) { 264 if (!verticesPerInstance || !indicesPerInstance) { 265 return; 266 } 267 268 const GeometrySrcState& geomSrc = this->getGeomSrc(); 269 270 // we only attempt to concat the case when reserved verts are used with 271 // an index buffer. 272 if (kReserved_GeometrySrcType == geomSrc.fVertexSrc && 273 kBuffer_GeometrySrcType == geomSrc.fIndexSrc) { 274 275 if (this->needsNewClip()) { 276 this->recordClip(); 277 } 278 if (this->needsNewState()) { 279 this->recordState(); 280 } 281 282 Draw* draw = NULL; 283 // if the last draw used the same indices/vertices per shape then we 284 // may be able to append to it. 285 if (kDraw_Cmd == fCmds.back() && 286 verticesPerInstance == fInstancedDrawTracker.fVerticesPerInstance && 287 indicesPerInstance == fInstancedDrawTracker.fIndicesPerInstance) { 288 GrAssert(fDraws.count()); 289 draw = &fDraws.back(); 290 } 291 292 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 293 const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer; 294 295 // Check whether the draw is compatible with this draw in order to 296 // append 297 if (NULL == draw || 298 draw->fIndexBuffer != geomSrc.fIndexBuffer || 299 draw->fPrimitiveType != type || 300 draw->fVertexBuffer != vertexBuffer) { 301 302 draw = this->recordDraw(); 303 draw->fPrimitiveType = type; 304 draw->fStartVertex = poolState.fPoolStartVertex; 305 draw->fStartIndex = 0; 306 draw->fVertexCount = 0; 307 draw->fIndexCount = 0; 308 draw->fVertexLayout = geomSrc.fVertexLayout; 309 draw->fVertexBuffer = vertexBuffer; 310 vertexBuffer->ref(); 311 draw->fIndexBuffer = geomSrc.fIndexBuffer; 312 geomSrc.fIndexBuffer->ref(); 313 } else { 314 GrAssert(!(draw->fIndexCount % indicesPerInstance)); 315 GrAssert(!(draw->fVertexCount % verticesPerInstance)); 316 GrAssert(poolState.fPoolStartVertex == draw->fStartVertex + 317 draw->fVertexCount); 318 } 319 320 // how many instances can be in a single draw 321 int maxInstancesPerDraw = this->indexCountInCurrentSource() / 322 indicesPerInstance; 323 if (!maxInstancesPerDraw) { 324 return; 325 } 326 // how many instances should be concat'ed onto draw 327 int instancesToConcat = maxInstancesPerDraw - draw->fVertexCount / 328 verticesPerInstance; 329 if (maxInstancesPerDraw > instanceCount) { 330 maxInstancesPerDraw = instanceCount; 331 if (instancesToConcat > instanceCount) { 332 instancesToConcat = instanceCount; 333 } 334 } 335 336 // update the amount of reserved data actually referenced in draws 337 size_t vertexBytes = instanceCount * verticesPerInstance * 338 VertexSize(draw->fVertexLayout); 339 poolState.fUsedPoolVertexBytes = 340 GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); 341 342 while (instanceCount) { 343 if (!instancesToConcat) { 344 int startVertex = draw->fStartVertex + draw->fVertexCount; 345 draw = this->recordDraw(); 346 draw->fPrimitiveType = type; 347 draw->fStartVertex = startVertex; 348 draw->fStartIndex = 0; 349 draw->fVertexCount = 0; 350 draw->fIndexCount = 0; 351 draw->fVertexLayout = geomSrc.fVertexLayout; 352 draw->fVertexBuffer = vertexBuffer; 353 vertexBuffer->ref(); 354 draw->fIndexBuffer = geomSrc.fIndexBuffer; 355 geomSrc.fIndexBuffer->ref(); 356 instancesToConcat = maxInstancesPerDraw; 357 } 358 draw->fVertexCount += instancesToConcat * verticesPerInstance; 359 draw->fIndexCount += instancesToConcat * indicesPerInstance; 360 instanceCount -= instancesToConcat; 361 instancesToConcat = 0; 362 } 363 364 // update draw tracking for next draw 365 fCurrQuad = 0; 366 fInstancedDrawTracker.fVerticesPerInstance = verticesPerInstance; 367 fInstancedDrawTracker.fIndicesPerInstance = indicesPerInstance; 368 } else { 369 this->INHERITED::drawIndexedInstances(type, 370 instanceCount, 371 verticesPerInstance, 372 indicesPerInstance); 373 } 374 375} 376 377void GrInOrderDrawBuffer::onDrawIndexed(GrPrimitiveType primitiveType, 378 int startVertex, 379 int startIndex, 380 int vertexCount, 381 int indexCount) { 382 383 if (!vertexCount || !indexCount) { 384 return; 385 } 386 387 this->resetDrawTracking(); 388 389 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 390 391 if (this->needsNewClip()) { 392 this->recordClip(); 393 } 394 if (this->needsNewState()) { 395 this->recordState(); 396 } 397 398 Draw* draw = this->recordDraw(); 399 400 draw->fPrimitiveType = primitiveType; 401 draw->fStartVertex = startVertex; 402 draw->fStartIndex = startIndex; 403 draw->fVertexCount = vertexCount; 404 draw->fIndexCount = indexCount; 405 406 draw->fVertexLayout = this->getVertexLayout(); 407 switch (this->getGeomSrc().fVertexSrc) { 408 case kBuffer_GeometrySrcType: 409 draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer; 410 break; 411 case kReserved_GeometrySrcType: // fallthrough 412 case kArray_GeometrySrcType: { 413 size_t vertexBytes = (vertexCount + startVertex) * 414 VertexSize(draw->fVertexLayout); 415 poolState.fUsedPoolVertexBytes = 416 GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); 417 draw->fVertexBuffer = poolState.fPoolVertexBuffer; 418 draw->fStartVertex += poolState.fPoolStartVertex; 419 break; 420 } 421 default: 422 GrCrash("unknown geom src type"); 423 } 424 draw->fVertexBuffer->ref(); 425 426 switch (this->getGeomSrc().fIndexSrc) { 427 case kBuffer_GeometrySrcType: 428 draw->fIndexBuffer = this->getGeomSrc().fIndexBuffer; 429 break; 430 case kReserved_GeometrySrcType: // fallthrough 431 case kArray_GeometrySrcType: { 432 size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t); 433 poolState.fUsedPoolIndexBytes = 434 GrMax(poolState.fUsedPoolIndexBytes, indexBytes); 435 draw->fIndexBuffer = poolState.fPoolIndexBuffer; 436 draw->fStartIndex += poolState.fPoolStartIndex; 437 break; 438 } 439 default: 440 GrCrash("unknown geom src type"); 441 } 442 draw->fIndexBuffer->ref(); 443} 444 445void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType, 446 int startVertex, 447 int vertexCount) { 448 if (!vertexCount) { 449 return; 450 } 451 452 this->resetDrawTracking(); 453 454 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 455 if (this->needsNewClip()) { 456 this->recordClip(); 457 } 458 if (this->needsNewState()) { 459 this->recordState(); 460 } 461 462 Draw* draw = this->recordDraw(); 463 draw->fPrimitiveType = primitiveType; 464 draw->fStartVertex = startVertex; 465 draw->fStartIndex = 0; 466 draw->fVertexCount = vertexCount; 467 draw->fIndexCount = 0; 468 469 draw->fVertexLayout = this->getVertexLayout(); 470 switch (this->getGeomSrc().fVertexSrc) { 471 case kBuffer_GeometrySrcType: 472 draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer; 473 break; 474 case kReserved_GeometrySrcType: // fallthrough 475 case kArray_GeometrySrcType: { 476 size_t vertexBytes = (vertexCount + startVertex) * 477 VertexSize(draw->fVertexLayout); 478 poolState.fUsedPoolVertexBytes = 479 GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); 480 draw->fVertexBuffer = poolState.fPoolVertexBuffer; 481 draw->fStartVertex += poolState.fPoolStartVertex; 482 break; 483 } 484 default: 485 GrCrash("unknown geom src type"); 486 } 487 draw->fVertexBuffer->ref(); 488 draw->fIndexBuffer = NULL; 489} 490 491GrInOrderDrawBuffer::StencilPath::StencilPath() : fStroke(SkStrokeRec::kFill_InitStyle) {} 492 493void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& stroke, 494 SkPath::FillType fill) { 495 if (this->needsNewClip()) { 496 this->recordClip(); 497 } 498 // Only compare the subset of GrDrawState relevant to path stenciling? 499 if (this->needsNewState()) { 500 this->recordState(); 501 } 502 StencilPath* sp = this->recordStencilPath(); 503 sp->fPath.reset(path); 504 path->ref(); 505 sp->fFill = fill; 506 sp->fStroke = stroke; 507} 508 509void GrInOrderDrawBuffer::clear(const GrIRect* rect, 510 GrColor color, 511 GrRenderTarget* renderTarget) { 512 GrIRect r; 513 if (NULL == renderTarget) { 514 renderTarget = this->drawState()->getRenderTarget(); 515 GrAssert(NULL != renderTarget); 516 } 517 if (NULL == rect) { 518 // We could do something smart and remove previous draws and clears to 519 // the current render target. If we get that smart we have to make sure 520 // those draws aren't read before this clear (render-to-texture). 521 r.setLTRB(0, 0, renderTarget->width(), renderTarget->height()); 522 rect = &r; 523 } 524 Clear* clr = this->recordClear(); 525 clr->fColor = color; 526 clr->fRect = *rect; 527 clr->fRenderTarget = renderTarget; 528 renderTarget->ref(); 529} 530 531void GrInOrderDrawBuffer::reset() { 532 GrAssert(1 == fGeoPoolStateStack.count()); 533 this->resetVertexSource(); 534 this->resetIndexSource(); 535 int numDraws = fDraws.count(); 536 for (int d = 0; d < numDraws; ++d) { 537 // we always have a VB, but not always an IB 538 GrAssert(NULL != fDraws[d].fVertexBuffer); 539 fDraws[d].fVertexBuffer->unref(); 540 GrSafeUnref(fDraws[d].fIndexBuffer); 541 } 542 fCmds.reset(); 543 fDraws.reset(); 544 fStencilPaths.reset(); 545 fStates.reset(); 546 fClears.reset(); 547 fVertexPool.reset(); 548 fIndexPool.reset(); 549 fClips.reset(); 550 fClipOrigins.reset(); 551 fClipSet = true; 552 553 this->resetDrawTracking(); 554 555 // we start off with a default clip and state so that we don't have 556 // to do count checks on fClips, fStates, or fCmds before checking their 557 // last entry. 558 this->recordDefaultState(); 559 this->recordDefaultClip(); 560} 561 562bool GrInOrderDrawBuffer::playback(GrDrawTarget* target) { 563 GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc); 564 GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc); 565 566 GrAssert(NULL != target); 567 GrAssert(target != this); // not considered and why? 568 569 int numCmds = fCmds.count(); 570 GrAssert(numCmds >= 2); 571 if (2 == numCmds) { 572 GrAssert(kSetState_Cmd == fCmds[0]); 573 GrAssert(kSetClip_Cmd == fCmds[1]); 574 return false; 575 } 576 577 fVertexPool.unlock(); 578 fIndexPool.unlock(); 579 580 GrDrawTarget::AutoClipRestore acr(target); 581 AutoGeometryPush agp(target); 582 GrDrawState* prevDrawState = target->drawState(); 583 prevDrawState->ref(); 584 585 GrClipData clipData; 586 587 int currState = 0; 588 int currClip = 0; 589 int currClear = 0; 590 int currDraw = 0; 591 int currStencilPath = 0; 592 593 for (int c = 0; c < numCmds; ++c) { 594 switch (fCmds[c]) { 595 case kDraw_Cmd: { 596 const Draw& draw = fDraws[currDraw]; 597 target->setVertexSourceToBuffer(draw.fVertexLayout, draw.fVertexBuffer); 598 if (draw.fIndexCount) { 599 target->setIndexSourceToBuffer(draw.fIndexBuffer); 600 } 601 602 if (draw.fIndexCount) { 603 target->drawIndexed(draw.fPrimitiveType, 604 draw.fStartVertex, 605 draw.fStartIndex, 606 draw.fVertexCount, 607 draw.fIndexCount); 608 } else { 609 target->drawNonIndexed(draw.fPrimitiveType, 610 draw.fStartVertex, 611 draw.fVertexCount); 612 } 613 ++currDraw; 614 break; 615 } 616 case kStencilPath_Cmd: { 617 const StencilPath& sp = fStencilPaths[currStencilPath]; 618 target->stencilPath(sp.fPath.get(), sp.fStroke, sp.fFill); 619 ++currStencilPath; 620 break; 621 } 622 case kSetState_Cmd: 623 target->setDrawState(&fStates[currState]); 624 ++currState; 625 break; 626 case kSetClip_Cmd: 627 clipData.fClipStack = &fClips[currClip]; 628 clipData.fOrigin = fClipOrigins[currClip]; 629 target->setClip(&clipData); 630 ++currClip; 631 break; 632 case kClear_Cmd: 633 target->clear(&fClears[currClear].fRect, 634 fClears[currClear].fColor, 635 fClears[currClear].fRenderTarget); 636 ++currClear; 637 break; 638 } 639 } 640 // we should have consumed all the states, clips, etc. 641 GrAssert(fStates.count() == currState); 642 GrAssert(fClips.count() == currClip); 643 GrAssert(fClipOrigins.count() == currClip); 644 GrAssert(fClears.count() == currClear); 645 GrAssert(fDraws.count() == currDraw); 646 647 target->setDrawState(prevDrawState); 648 prevDrawState->unref(); 649 return true; 650} 651 652void GrInOrderDrawBuffer::setAutoFlushTarget(GrDrawTarget* target) { 653 GrSafeAssign(fAutoFlushTarget, target); 654} 655 656void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace( 657 GrVertexLayout vertexLayout, 658 int vertexCount, 659 int indexCount) { 660 if (NULL != fAutoFlushTarget) { 661 // We use geometryHints() to know whether to flush the draw buffer. We 662 // can't flush if we are inside an unbalanced pushGeometrySource. 663 // Moreover, flushing blows away vertex and index data that was 664 // previously reserved. So if the vertex or index data is pulled from 665 // reserved space and won't be released by this request then we can't 666 // flush. 667 bool insideGeoPush = fGeoPoolStateStack.count() > 1; 668 669 bool unreleasedVertexSpace = 670 !vertexCount && 671 kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc; 672 673 bool unreleasedIndexSpace = 674 !indexCount && 675 kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc; 676 677 // we don't want to finalize any reserved geom on the target since 678 // we don't know that the client has finished writing to it. 679 bool targetHasReservedGeom = 680 fAutoFlushTarget->hasReservedVerticesOrIndices(); 681 682 int vcount = vertexCount; 683 int icount = indexCount; 684 685 if (!insideGeoPush && 686 !unreleasedVertexSpace && 687 !unreleasedIndexSpace && 688 !targetHasReservedGeom && 689 this->geometryHints(vertexLayout, &vcount, &icount)) { 690 691 this->flushTo(fAutoFlushTarget); 692 } 693 } 694} 695 696bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout, 697 int* vertexCount, 698 int* indexCount) const { 699 // we will recommend a flush if the data could fit in a single 700 // preallocated buffer but none are left and it can't fit 701 // in the current buffer (which may not be prealloced). 702 bool flush = false; 703 if (NULL != indexCount) { 704 int32_t currIndices = fIndexPool.currentBufferIndices(); 705 if (*indexCount > currIndices && 706 (!fIndexPool.preallocatedBuffersRemaining() && 707 *indexCount <= fIndexPool.preallocatedBufferIndices())) { 708 709 flush = true; 710 } 711 *indexCount = currIndices; 712 } 713 if (NULL != vertexCount) { 714 int32_t currVertices = fVertexPool.currentBufferVertices(vertexLayout); 715 if (*vertexCount > currVertices && 716 (!fVertexPool.preallocatedBuffersRemaining() && 717 *vertexCount <= fVertexPool.preallocatedBufferVertices(vertexLayout))) { 718 719 flush = true; 720 } 721 *vertexCount = currVertices; 722 } 723 return flush; 724} 725 726bool GrInOrderDrawBuffer::onReserveVertexSpace(GrVertexLayout vertexLayout, 727 int vertexCount, 728 void** vertices) { 729 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 730 GrAssert(vertexCount > 0); 731 GrAssert(NULL != vertices); 732 GrAssert(0 == poolState.fUsedPoolVertexBytes); 733 734 *vertices = fVertexPool.makeSpace(vertexLayout, 735 vertexCount, 736 &poolState.fPoolVertexBuffer, 737 &poolState.fPoolStartVertex); 738 return NULL != *vertices; 739} 740 741bool GrInOrderDrawBuffer::onReserveIndexSpace(int indexCount, void** indices) { 742 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 743 GrAssert(indexCount > 0); 744 GrAssert(NULL != indices); 745 GrAssert(0 == poolState.fUsedPoolIndexBytes); 746 747 *indices = fIndexPool.makeSpace(indexCount, 748 &poolState.fPoolIndexBuffer, 749 &poolState.fPoolStartIndex); 750 return NULL != *indices; 751} 752 753void GrInOrderDrawBuffer::releaseReservedVertexSpace() { 754 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 755 const GeometrySrcState& geoSrc = this->getGeomSrc(); 756 757 // If we get a release vertex space call then our current source should either be reserved 758 // or array (which we copied into reserved space). 759 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc || 760 kArray_GeometrySrcType == geoSrc.fVertexSrc); 761 762 // When the caller reserved vertex buffer space we gave it back a pointer 763 // provided by the vertex buffer pool. At each draw we tracked the largest 764 // offset into the pool's pointer that was referenced. Now we return to the 765 // pool any portion at the tail of the allocation that no draw referenced. 766 size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) * 767 geoSrc.fVertexCount; 768 fVertexPool.putBack(reservedVertexBytes - 769 poolState.fUsedPoolVertexBytes); 770 poolState.fUsedPoolVertexBytes = 0; 771 poolState.fPoolVertexBuffer = NULL; 772 poolState.fPoolStartVertex = 0; 773} 774 775void GrInOrderDrawBuffer::releaseReservedIndexSpace() { 776 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 777 const GeometrySrcState& geoSrc = this->getGeomSrc(); 778 779 // If we get a release index space call then our current source should either be reserved 780 // or array (which we copied into reserved space). 781 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc || 782 kArray_GeometrySrcType == geoSrc.fIndexSrc); 783 784 // Similar to releaseReservedVertexSpace we return any unused portion at 785 // the tail 786 size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount; 787 fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes); 788 poolState.fUsedPoolIndexBytes = 0; 789 poolState.fPoolIndexBuffer = NULL; 790 poolState.fPoolStartIndex = 0; 791} 792 793void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray, 794 int vertexCount) { 795 796 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 797 GrAssert(0 == poolState.fUsedPoolVertexBytes); 798#if GR_DEBUG 799 bool success = 800#endif 801 fVertexPool.appendVertices(this->getVertexLayout(), 802 vertexCount, 803 vertexArray, 804 &poolState.fPoolVertexBuffer, 805 &poolState.fPoolStartVertex); 806 GR_DEBUGASSERT(success); 807} 808 809void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray, 810 int indexCount) { 811 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 812 GrAssert(0 == poolState.fUsedPoolIndexBytes); 813#if GR_DEBUG 814 bool success = 815#endif 816 fIndexPool.appendIndices(indexCount, 817 indexArray, 818 &poolState.fPoolIndexBuffer, 819 &poolState.fPoolStartIndex); 820 GR_DEBUGASSERT(success); 821} 822 823void GrInOrderDrawBuffer::releaseVertexArray() { 824 // When the client provides an array as the vertex source we handled it 825 // by copying their array into reserved space. 826 this->GrInOrderDrawBuffer::releaseReservedVertexSpace(); 827} 828 829void GrInOrderDrawBuffer::releaseIndexArray() { 830 // When the client provides an array as the index source we handled it 831 // by copying their array into reserved space. 832 this->GrInOrderDrawBuffer::releaseReservedIndexSpace(); 833} 834 835void GrInOrderDrawBuffer::geometrySourceWillPush() { 836 GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); 837 poolState.fUsedPoolVertexBytes = 0; 838 poolState.fUsedPoolIndexBytes = 0; 839 this->resetDrawTracking(); 840#if GR_DEBUG 841 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; 842 poolState.fPoolStartVertex = ~0; 843 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; 844 poolState.fPoolStartIndex = ~0; 845#endif 846} 847 848void GrInOrderDrawBuffer::geometrySourceWillPop( 849 const GeometrySrcState& restoredState) { 850 GrAssert(fGeoPoolStateStack.count() > 1); 851 fGeoPoolStateStack.pop_back(); 852 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 853 // we have to assume that any slack we had in our vertex/index data 854 // is now unreleasable because data may have been appended later in the 855 // pool. 856 if (kReserved_GeometrySrcType == restoredState.fVertexSrc || 857 kArray_GeometrySrcType == restoredState.fVertexSrc) { 858 poolState.fUsedPoolVertexBytes = 859 VertexSize(restoredState.fVertexLayout) * 860 restoredState.fVertexCount; 861 } 862 if (kReserved_GeometrySrcType == restoredState.fIndexSrc || 863 kArray_GeometrySrcType == restoredState.fIndexSrc) { 864 poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * 865 restoredState.fIndexCount; 866 } 867 this->resetDrawTracking(); 868} 869 870bool GrInOrderDrawBuffer::needsNewState() const { 871 // we should have recorded a default state in reset() 872 GrAssert(!fStates.empty()); 873 return fStates.back() != this->getDrawState(); 874} 875 876bool GrInOrderDrawBuffer::needsNewClip() const { 877 if (this->getDrawState().isClipState()) { 878 if (fClipSet && 879 (fClips.back() != *fClip->fClipStack || 880 fClipOrigins.back() != fClip->fOrigin)) { 881 return true; 882 } 883 } 884 return false; 885} 886 887void GrInOrderDrawBuffer::recordClip() { 888 fClips.push_back() = *fClip->fClipStack; 889 fClipOrigins.push_back() = fClip->fOrigin; 890 fClipSet = false; 891 fCmds.push_back(kSetClip_Cmd); 892} 893 894void GrInOrderDrawBuffer::recordDefaultClip() { 895 fClips.push_back() = SkClipStack(); 896 fClipOrigins.push_back() = SkIPoint::Make(0, 0); 897 fCmds.push_back(kSetClip_Cmd); 898} 899 900void GrInOrderDrawBuffer::recordState() { 901 fStates.push_back(this->getDrawState()); 902 fCmds.push_back(kSetState_Cmd); 903} 904 905void GrInOrderDrawBuffer::recordDefaultState() { 906 fStates.push_back(GrDrawState()); 907 fCmds.push_back(kSetState_Cmd); 908} 909 910GrInOrderDrawBuffer::Draw* GrInOrderDrawBuffer::recordDraw() { 911 fCmds.push_back(kDraw_Cmd); 912 return &fDraws.push_back(); 913} 914 915GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath() { 916 fCmds.push_back(kStencilPath_Cmd); 917 return &fStencilPaths.push_back(); 918} 919 920GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() { 921 fCmds.push_back(kClear_Cmd); 922 return &fClears.push_back(); 923} 924 925void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) { 926 INHERITED::clipWillBeSet(newClipData); 927 fClipSet = true; 928} 929