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 19 GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu, 20 GrVertexBufferAllocPool* vertexPool, 21 GrIndexBufferAllocPool* indexPool) 22 : fAutoFlushTarget(NULL) 23 , fClipSet(true) 24 , fClipProxyState(kUnknown_ClipProxyState) 25 , fVertexPool(*vertexPool) 26 , fIndexPool(*indexPool) 27 , fFlushing(false) { 28 29 fGpu.reset(SkRef(gpu)); 30 fCaps = gpu->getCaps(); 31 32 GrAssert(NULL != vertexPool); 33 GrAssert(NULL != indexPool); 34 35 GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); 36 poolState.fUsedPoolVertexBytes = 0; 37 poolState.fUsedPoolIndexBytes = 0; 38 #if GR_DEBUG 39 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; 40 poolState.fPoolStartVertex = ~0; 41 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; 42 poolState.fPoolStartIndex = ~0; 43 #endif 44 this->reset(); 45 } 46 47 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() { 48 this->reset(); 49 // This must be called by before the GrDrawTarget destructor 50 this->releaseGeometry(); 51 GrSafeUnref(fAutoFlushTarget); 52 } 53 54 //////////////////////////////////////////////////////////////////////////////// 55 56 namespace { 57 void get_vertex_bounds(const void* vertices, 58 size_t vertexSize, 59 int vertexCount, 60 SkRect* bounds) { 61 GrAssert(vertexSize >= sizeof(GrPoint)); 62 GrAssert(vertexCount > 0); 63 const GrPoint* point = static_cast<const GrPoint*>(vertices); 64 bounds->fLeft = bounds->fRight = point->fX; 65 bounds->fTop = bounds->fBottom = point->fY; 66 for (int i = 1; i < vertexCount; ++i) { 67 point = reinterpret_cast<GrPoint*>(reinterpret_cast<intptr_t>(point) + vertexSize); 68 bounds->growToInclude(point->fX, point->fY); 69 } 70 } 71 } 72 73 void GrInOrderDrawBuffer::drawRect(const GrRect& rect, 74 const SkMatrix* matrix, 75 const GrRect* srcRects[], 76 const SkMatrix* srcMatrices[]) { 77 78 GrVertexLayout layout = 0; 79 GrDrawState::AutoColorRestore acr; 80 GrColor color = this->drawState()->getColor(); 81 82 // Using per-vertex colors allows batching across colors. (A lot of rects in a row differing 83 // only in color is a common occurrence in tables). However, having per-vertex colors disables 84 // blending optimizations because we don't know if the color will be solid or not. These 85 // optimizations help determine whether coverage and color can be blended correctly when 86 // dual-source blending isn't available. This comes into play when there is coverage. If colors 87 // were a stage it could take a hint that every vertex's color will be opaque. 88 if (this->getCaps().dualSourceBlendingSupport() || 89 this->getDrawState().hasSolidCoverage(this->getGeomSrc().fVertexLayout)) { 90 layout |= GrDrawState::kColor_VertexLayoutBit;; 91 // We set the draw state's color to white here. This is done so that any batching performed 92 // in our subclass's onDraw() won't get a false from GrDrawState::op== due to a color 93 // mismatch. TODO: Once vertex layout is owned by GrDrawState it should skip comparing the 94 // constant color in its op== when the kColor layout bit is set and then we can remove this. 95 acr.set(this->drawState(), 0xFFFFFFFF); 96 } 97 98 uint32_t explicitCoordMask = 0; 99 if (NULL != srcRects) { 100 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 101 int numTC = 0; 102 if (NULL != srcRects[s]) { 103 layout |= GrDrawState::StageTexCoordVertexLayoutBit(s, numTC); 104 ++numTC; 105 explicitCoordMask |= (1 << s); 106 } 107 } 108 } 109 110 AutoReleaseGeometry geo(this, layout, 4, 0); 111 if (!geo.succeeded()) { 112 GrPrintf("Failed to get space for vertices!\n"); 113 return; 114 } 115 116 // Go to device coords to allow batching across matrix changes 117 SkMatrix combinedMatrix; 118 if (NULL != matrix) { 119 combinedMatrix = *matrix; 120 } else { 121 combinedMatrix.reset(); 122 } 123 combinedMatrix.postConcat(this->drawState()->getViewMatrix()); 124 // When the caller has provided an explicit source rects for a stage then we don't want to 125 // modify that stage's matrix. Otherwise if the effect is generating its source rect from 126 // the vertex positions then we have to account for the view matrix change. 127 GrDrawState::AutoDeviceCoordDraw adcd(this->drawState(), explicitCoordMask); 128 if (!adcd.succeeded()) { 129 return; 130 } 131 132 int stageOffsets[GrDrawState::kNumStages], colorOffset; 133 int vsize = GrDrawState::VertexSizeAndOffsetsByStage(layout, stageOffsets, 134 &colorOffset, NULL, NULL); 135 136 geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize); 137 combinedMatrix.mapPointsWithStride(geo.positions(), vsize, 4); 138 139 SkRect devBounds; 140 // since we already computed the dev verts, set the bounds hint. This will help us avoid 141 // unnecessary clipping in our onDraw(). 142 get_vertex_bounds(geo.vertices(), vsize, 4, &devBounds); 143 144 for (int i = 0; i < GrDrawState::kNumStages; ++i) { 145 if (explicitCoordMask & (1 << i)) { 146 GrAssert(0 != stageOffsets[i]); 147 GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) + 148 stageOffsets[i]); 149 coords->setRectFan(srcRects[i]->fLeft, srcRects[i]->fTop, 150 srcRects[i]->fRight, srcRects[i]->fBottom, 151 vsize); 152 if (NULL != srcMatrices && NULL != srcMatrices[i]) { 153 srcMatrices[i]->mapPointsWithStride(coords, vsize, 4); 154 } 155 } else { 156 GrAssert(0 == stageOffsets[i]); 157 } 158 } 159 160 if (colorOffset >= 0) { 161 GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + colorOffset); 162 for (int i = 0; i < 4; ++i) { 163 *vertColor = color; 164 vertColor = (GrColor*) ((intptr_t) vertColor + vsize); 165 } 166 } 167 168 this->setIndexSourceToBuffer(fGpu->getQuadIndexBuffer()); 169 this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds); 170 } 171 172 bool GrInOrderDrawBuffer::quickInsideClip(const SkRect& devBounds) { 173 if (!this->getDrawState().isClipState()) { 174 return true; 175 } 176 if (kUnknown_ClipProxyState == fClipProxyState) { 177 SkIRect rect; 178 bool iior; 179 this->getClip()->getConservativeBounds(this->getDrawState().getRenderTarget(), &rect, &iior); 180 if (iior) { 181 // The clip is a rect. We will remember that in fProxyClip. It is common for an edge (or 182 // all edges) of the clip to be at the edge of the RT. However, we get that clipping for 183 // free via the viewport. We don't want to think that clipping must be enabled in this 184 // case. So we extend the clip outward from the edge to avoid these false negatives. 185 fClipProxyState = kValid_ClipProxyState; 186 fClipProxy = SkRect::MakeFromIRect(rect); 187 188 if (fClipProxy.fLeft <= 0) { 189 fClipProxy.fLeft = SK_ScalarMin; 190 } 191 if (fClipProxy.fTop <= 0) { 192 fClipProxy.fTop = SK_ScalarMin; 193 } 194 if (fClipProxy.fRight >= this->getDrawState().getRenderTarget()->width()) { 195 fClipProxy.fRight = SK_ScalarMax; 196 } 197 if (fClipProxy.fBottom >= this->getDrawState().getRenderTarget()->height()) { 198 fClipProxy.fBottom = SK_ScalarMax; 199 } 200 } else { 201 fClipProxyState = kInvalid_ClipProxyState; 202 } 203 } 204 if (kValid_ClipProxyState == fClipProxyState) { 205 return fClipProxy.contains(devBounds); 206 } 207 SkPoint originOffset = {SkIntToScalar(this->getClip()->fOrigin.fX), 208 SkIntToScalar(this->getClip()->fOrigin.fY)}; 209 SkRect clipSpaceBounds = devBounds; 210 clipSpaceBounds.offset(originOffset); 211 return this->getClip()->fClipStack->quickContains(clipSpaceBounds); 212 } 213 214 int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) { 215 GrAssert(info.isInstanced()); 216 217 const GeometrySrcState& geomSrc = this->getGeomSrc(); 218 219 // we only attempt to concat the case when reserved verts are used with a client-specified index 220 // buffer. To make this work with client-specified VBs we'd need to know if the VB was updated 221 // between draws. 222 if (kReserved_GeometrySrcType != geomSrc.fVertexSrc || 223 kBuffer_GeometrySrcType != geomSrc.fIndexSrc) { 224 return 0; 225 } 226 // Check if there is a draw info that is compatible that uses the same VB from the pool and 227 // the same IB 228 if (kDraw_Cmd != fCmds.back()) { 229 return 0; 230 } 231 232 DrawRecord* draw = &fDraws.back(); 233 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 234 const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer; 235 236 if (!draw->isInstanced() || 237 draw->verticesPerInstance() != info.verticesPerInstance() || 238 draw->indicesPerInstance() != info.indicesPerInstance() || 239 draw->fVertexBuffer != vertexBuffer || 240 draw->fIndexBuffer != geomSrc.fIndexBuffer || 241 draw->fVertexLayout != geomSrc.fVertexLayout) { 242 return 0; 243 } 244 // info does not yet account for the offset from the start of the pool's VB while the previous 245 // draw record does. 246 int adjustedStartVertex = poolState.fPoolStartVertex + info.startVertex(); 247 if (draw->startVertex() + draw->vertexCount() != adjustedStartVertex) { 248 return 0; 249 } 250 251 GrAssert(poolState.fPoolStartVertex == draw->startVertex() + draw->vertexCount()); 252 253 // how many instances can be concat'ed onto draw given the size of the index buffer 254 int instancesToConcat = this->indexCountInCurrentSource() / info.indicesPerInstance(); 255 instancesToConcat -= draw->instanceCount(); 256 instancesToConcat = GrMin(instancesToConcat, info.instanceCount()); 257 258 // update the amount of reserved vertex data actually referenced in draws 259 size_t vertexBytes = instancesToConcat * info.verticesPerInstance() * 260 GrDrawState::VertexSize(draw->fVertexLayout); 261 poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); 262 263 draw->adjustInstanceCount(instancesToConcat); 264 return instancesToConcat; 265 } 266 267 class AutoClipReenable { 268 public: 269 AutoClipReenable() : fDrawState(NULL) {} 270 ~AutoClipReenable() { 271 if (NULL != fDrawState) { 272 fDrawState->enableState(GrDrawState::kClip_StateBit); 273 } 274 } 275 void set(GrDrawState* drawState) { 276 if (drawState->isClipState()) { 277 fDrawState = drawState; 278 drawState->disableState(GrDrawState::kClip_StateBit); 279 } 280 } 281 private: 282 GrDrawState* fDrawState; 283 }; 284 285 void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) { 286 287 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 288 AutoClipReenable acr; 289 290 if (this->getDrawState().isClipState() && 291 NULL != info.getDevBounds() && 292 this->quickInsideClip(*info.getDevBounds())) { 293 acr.set(this->drawState()); 294 } 295 296 if (this->needsNewClip()) { 297 this->recordClip(); 298 } 299 if (this->needsNewState()) { 300 this->recordState(); 301 } 302 303 DrawRecord* draw; 304 if (info.isInstanced()) { 305 int instancesConcated = this->concatInstancedDraw(info); 306 if (info.instanceCount() > instancesConcated) { 307 draw = this->recordDraw(info); 308 draw->adjustInstanceCount(-instancesConcated); 309 } else { 310 return; 311 } 312 } else { 313 draw = this->recordDraw(info); 314 } 315 draw->fVertexLayout = this->getVertexLayout(); 316 317 switch (this->getGeomSrc().fVertexSrc) { 318 case kBuffer_GeometrySrcType: 319 draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer; 320 break; 321 case kReserved_GeometrySrcType: // fallthrough 322 case kArray_GeometrySrcType: { 323 size_t vertexBytes = (info.vertexCount() + info.startVertex()) * 324 GrDrawState::VertexSize(draw->fVertexLayout); 325 poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); 326 draw->fVertexBuffer = poolState.fPoolVertexBuffer; 327 draw->adjustStartVertex(poolState.fPoolStartVertex); 328 break; 329 } 330 default: 331 GrCrash("unknown geom src type"); 332 } 333 draw->fVertexBuffer->ref(); 334 335 if (info.isIndexed()) { 336 switch (this->getGeomSrc().fIndexSrc) { 337 case kBuffer_GeometrySrcType: 338 draw->fIndexBuffer = this->getGeomSrc().fIndexBuffer; 339 break; 340 case kReserved_GeometrySrcType: // fallthrough 341 case kArray_GeometrySrcType: { 342 size_t indexBytes = (info.indexCount() + info.startIndex()) * sizeof(uint16_t); 343 poolState.fUsedPoolIndexBytes = GrMax(poolState.fUsedPoolIndexBytes, indexBytes); 344 draw->fIndexBuffer = poolState.fPoolIndexBuffer; 345 draw->adjustStartIndex(poolState.fPoolStartIndex); 346 break; 347 } 348 default: 349 GrCrash("unknown geom src type"); 350 } 351 draw->fIndexBuffer->ref(); 352 } else { 353 draw->fIndexBuffer = NULL; 354 } 355 } 356 357 GrInOrderDrawBuffer::StencilPath::StencilPath() : fStroke(SkStrokeRec::kFill_InitStyle) {} 358 359 void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& stroke, 360 SkPath::FillType fill) { 361 if (this->needsNewClip()) { 362 this->recordClip(); 363 } 364 // Only compare the subset of GrDrawState relevant to path stenciling? 365 if (this->needsNewState()) { 366 this->recordState(); 367 } 368 StencilPath* sp = this->recordStencilPath(); 369 sp->fPath.reset(path); 370 path->ref(); 371 sp->fFill = fill; 372 sp->fStroke = stroke; 373 } 374 375 void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color, GrRenderTarget* renderTarget) { 376 GrIRect r; 377 if (NULL == renderTarget) { 378 renderTarget = this->drawState()->getRenderTarget(); 379 GrAssert(NULL != renderTarget); 380 } 381 if (NULL == rect) { 382 // We could do something smart and remove previous draws and clears to 383 // the current render target. If we get that smart we have to make sure 384 // those draws aren't read before this clear (render-to-texture). 385 r.setLTRB(0, 0, renderTarget->width(), renderTarget->height()); 386 rect = &r; 387 } 388 Clear* clr = this->recordClear(); 389 clr->fColor = color; 390 clr->fRect = *rect; 391 clr->fRenderTarget = renderTarget; 392 renderTarget->ref(); 393 } 394 395 void GrInOrderDrawBuffer::reset() { 396 GrAssert(1 == fGeoPoolStateStack.count()); 397 this->resetVertexSource(); 398 this->resetIndexSource(); 399 int numDraws = fDraws.count(); 400 for (int d = 0; d < numDraws; ++d) { 401 // we always have a VB, but not always an IB 402 GrAssert(NULL != fDraws[d].fVertexBuffer); 403 fDraws[d].fVertexBuffer->unref(); 404 GrSafeUnref(fDraws[d].fIndexBuffer); 405 } 406 fCmds.reset(); 407 fDraws.reset(); 408 fStencilPaths.reset(); 409 fStates.reset(); 410 fClears.reset(); 411 fVertexPool.reset(); 412 fIndexPool.reset(); 413 fClips.reset(); 414 fClipOrigins.reset(); 415 fClipSet = true; 416 } 417 418 bool GrInOrderDrawBuffer::flushTo(GrDrawTarget* target) { 419 GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc); 420 GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc); 421 422 GrAssert(NULL != target); 423 GrAssert(target != this); // not considered and why? 424 425 int numCmds = fCmds.count(); 426 if (0 == numCmds) { 427 return false; 428 } 429 430 fVertexPool.unlock(); 431 fIndexPool.unlock(); 432 433 GrDrawTarget::AutoClipRestore acr(target); 434 AutoGeometryPush agp(target); 435 436 GrDrawState playbackState; 437 GrDrawState* prevDrawState = target->drawState(); 438 prevDrawState->ref(); 439 target->setDrawState(&playbackState); 440 441 GrClipData clipData; 442 443 int currState = 0; 444 int currClip = 0; 445 int currClear = 0; 446 int currDraw = 0; 447 int currStencilPath = 0; 448 449 450 for (int c = 0; c < numCmds; ++c) { 451 switch (fCmds[c]) { 452 case kDraw_Cmd: { 453 const DrawRecord& draw = fDraws[currDraw]; 454 target->setVertexSourceToBuffer(draw.fVertexLayout, draw.fVertexBuffer); 455 if (draw.isIndexed()) { 456 target->setIndexSourceToBuffer(draw.fIndexBuffer); 457 } 458 target->executeDraw(draw); 459 460 ++currDraw; 461 break; 462 } 463 case kStencilPath_Cmd: { 464 const StencilPath& sp = fStencilPaths[currStencilPath]; 465 target->stencilPath(sp.fPath.get(), sp.fStroke, sp.fFill); 466 ++currStencilPath; 467 break; 468 } 469 case kSetState_Cmd: 470 fStates[currState].restoreTo(&playbackState); 471 ++currState; 472 break; 473 case kSetClip_Cmd: 474 clipData.fClipStack = &fClips[currClip]; 475 clipData.fOrigin = fClipOrigins[currClip]; 476 target->setClip(&clipData); 477 ++currClip; 478 break; 479 case kClear_Cmd: 480 target->clear(&fClears[currClear].fRect, 481 fClears[currClear].fColor, 482 fClears[currClear].fRenderTarget); 483 ++currClear; 484 break; 485 } 486 } 487 // we should have consumed all the states, clips, etc. 488 GrAssert(fStates.count() == currState); 489 GrAssert(fClips.count() == currClip); 490 GrAssert(fClipOrigins.count() == currClip); 491 GrAssert(fClears.count() == currClear); 492 GrAssert(fDraws.count() == currDraw); 493 494 target->setDrawState(prevDrawState); 495 prevDrawState->unref(); 496 this->reset(); 497 return true; 498 } 499 500 void GrInOrderDrawBuffer::setAutoFlushTarget(GrDrawTarget* target) { 501 GrSafeAssign(fAutoFlushTarget, target); 502 } 503 504 void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace( 505 size_t vertexSize, 506 int vertexCount, 507 int indexCount) { 508 if (NULL != fAutoFlushTarget) { 509 // We use geometryHints() to know whether to flush the draw buffer. We 510 // can't flush if we are inside an unbalanced pushGeometrySource. 511 // Moreover, flushing blows away vertex and index data that was 512 // previously reserved. So if the vertex or index data is pulled from 513 // reserved space and won't be released by this request then we can't 514 // flush. 515 bool insideGeoPush = fGeoPoolStateStack.count() > 1; 516 517 bool unreleasedVertexSpace = 518 !vertexCount && 519 kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc; 520 521 bool unreleasedIndexSpace = 522 !indexCount && 523 kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc; 524 525 // we don't want to finalize any reserved geom on the target since 526 // we don't know that the client has finished writing to it. 527 bool targetHasReservedGeom = 528 fAutoFlushTarget->hasReservedVerticesOrIndices(); 529 530 int vcount = vertexCount; 531 int icount = indexCount; 532 533 if (!insideGeoPush && 534 !unreleasedVertexSpace && 535 !unreleasedIndexSpace && 536 !targetHasReservedGeom && 537 this->geometryHints(vertexSize, &vcount, &icount)) { 538 539 this->flushTo(fAutoFlushTarget); 540 } 541 } 542 } 543 544 bool GrInOrderDrawBuffer::geometryHints(size_t vertexSize, 545 int* vertexCount, 546 int* indexCount) const { 547 // we will recommend a flush if the data could fit in a single 548 // preallocated buffer but none are left and it can't fit 549 // in the current buffer (which may not be prealloced). 550 bool flush = false; 551 if (NULL != indexCount) { 552 int32_t currIndices = fIndexPool.currentBufferIndices(); 553 if (*indexCount > currIndices && 554 (!fIndexPool.preallocatedBuffersRemaining() && 555 *indexCount <= fIndexPool.preallocatedBufferIndices())) { 556 557 flush = true; 558 } 559 *indexCount = currIndices; 560 } 561 if (NULL != vertexCount) { 562 int32_t currVertices = fVertexPool.currentBufferVertices(vertexSize); 563 if (*vertexCount > currVertices && 564 (!fVertexPool.preallocatedBuffersRemaining() && 565 *vertexCount <= fVertexPool.preallocatedBufferVertices(vertexSize))) { 566 567 flush = true; 568 } 569 *vertexCount = currVertices; 570 } 571 return flush; 572 } 573 574 bool GrInOrderDrawBuffer::onReserveVertexSpace(size_t vertexSize, 575 int vertexCount, 576 void** vertices) { 577 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 578 GrAssert(vertexCount > 0); 579 GrAssert(NULL != vertices); 580 GrAssert(0 == poolState.fUsedPoolVertexBytes); 581 582 *vertices = fVertexPool.makeSpace(vertexSize, 583 vertexCount, 584 &poolState.fPoolVertexBuffer, 585 &poolState.fPoolStartVertex); 586 return NULL != *vertices; 587 } 588 589 bool GrInOrderDrawBuffer::onReserveIndexSpace(int indexCount, void** indices) { 590 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 591 GrAssert(indexCount > 0); 592 GrAssert(NULL != indices); 593 GrAssert(0 == poolState.fUsedPoolIndexBytes); 594 595 *indices = fIndexPool.makeSpace(indexCount, 596 &poolState.fPoolIndexBuffer, 597 &poolState.fPoolStartIndex); 598 return NULL != *indices; 599 } 600 601 void GrInOrderDrawBuffer::releaseReservedVertexSpace() { 602 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 603 const GeometrySrcState& geoSrc = this->getGeomSrc(); 604 605 // If we get a release vertex space call then our current source should either be reserved 606 // or array (which we copied into reserved space). 607 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc || 608 kArray_GeometrySrcType == geoSrc.fVertexSrc); 609 610 // When the caller reserved vertex buffer space we gave it back a pointer 611 // provided by the vertex buffer pool. At each draw we tracked the largest 612 // offset into the pool's pointer that was referenced. Now we return to the 613 // pool any portion at the tail of the allocation that no draw referenced. 614 size_t reservedVertexBytes = GrDrawState::VertexSize(geoSrc.fVertexLayout) * 615 geoSrc.fVertexCount; 616 fVertexPool.putBack(reservedVertexBytes - 617 poolState.fUsedPoolVertexBytes); 618 poolState.fUsedPoolVertexBytes = 0; 619 poolState.fPoolVertexBuffer = NULL; 620 poolState.fPoolStartVertex = 0; 621 } 622 623 void GrInOrderDrawBuffer::releaseReservedIndexSpace() { 624 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 625 const GeometrySrcState& geoSrc = this->getGeomSrc(); 626 627 // If we get a release index space call then our current source should either be reserved 628 // or array (which we copied into reserved space). 629 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc || 630 kArray_GeometrySrcType == geoSrc.fIndexSrc); 631 632 // Similar to releaseReservedVertexSpace we return any unused portion at 633 // the tail 634 size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount; 635 fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes); 636 poolState.fUsedPoolIndexBytes = 0; 637 poolState.fPoolIndexBuffer = NULL; 638 poolState.fPoolStartIndex = 0; 639 } 640 641 void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray, 642 int vertexCount) { 643 644 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 645 GrAssert(0 == poolState.fUsedPoolVertexBytes); 646 #if GR_DEBUG 647 bool success = 648 #endif 649 fVertexPool.appendVertices(GrDrawState::VertexSize(this->getVertexLayout()), 650 vertexCount, 651 vertexArray, 652 &poolState.fPoolVertexBuffer, 653 &poolState.fPoolStartVertex); 654 GR_DEBUGASSERT(success); 655 } 656 657 void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray, 658 int indexCount) { 659 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 660 GrAssert(0 == poolState.fUsedPoolIndexBytes); 661 #if GR_DEBUG 662 bool success = 663 #endif 664 fIndexPool.appendIndices(indexCount, 665 indexArray, 666 &poolState.fPoolIndexBuffer, 667 &poolState.fPoolStartIndex); 668 GR_DEBUGASSERT(success); 669 } 670 671 void GrInOrderDrawBuffer::releaseVertexArray() { 672 // When the client provides an array as the vertex source we handled it 673 // by copying their array into reserved space. 674 this->GrInOrderDrawBuffer::releaseReservedVertexSpace(); 675 } 676 677 void GrInOrderDrawBuffer::releaseIndexArray() { 678 // When the client provides an array as the index source we handled it 679 // by copying their array into reserved space. 680 this->GrInOrderDrawBuffer::releaseReservedIndexSpace(); 681 } 682 683 void GrInOrderDrawBuffer::geometrySourceWillPush() { 684 GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); 685 poolState.fUsedPoolVertexBytes = 0; 686 poolState.fUsedPoolIndexBytes = 0; 687 #if GR_DEBUG 688 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; 689 poolState.fPoolStartVertex = ~0; 690 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; 691 poolState.fPoolStartIndex = ~0; 692 #endif 693 } 694 695 void GrInOrderDrawBuffer::geometrySourceWillPop( 696 const GeometrySrcState& restoredState) { 697 GrAssert(fGeoPoolStateStack.count() > 1); 698 fGeoPoolStateStack.pop_back(); 699 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 700 // we have to assume that any slack we had in our vertex/index data 701 // is now unreleasable because data may have been appended later in the 702 // pool. 703 if (kReserved_GeometrySrcType == restoredState.fVertexSrc || 704 kArray_GeometrySrcType == restoredState.fVertexSrc) { 705 poolState.fUsedPoolVertexBytes = 706 GrDrawState::VertexSize(restoredState.fVertexLayout) * 707 restoredState.fVertexCount; 708 } 709 if (kReserved_GeometrySrcType == restoredState.fIndexSrc || 710 kArray_GeometrySrcType == restoredState.fIndexSrc) { 711 poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * 712 restoredState.fIndexCount; 713 } 714 } 715 716 bool GrInOrderDrawBuffer::needsNewState() const { 717 return fStates.empty() || !fStates.back().isEqual(this->getDrawState()); 718 } 719 720 bool GrInOrderDrawBuffer::needsNewClip() const { 721 GrAssert(fClips.count() == fClipOrigins.count()); 722 if (this->getDrawState().isClipState()) { 723 if (fClipSet && 724 (fClips.empty() || 725 fClips.back() != *this->getClip()->fClipStack || 726 fClipOrigins.back() != this->getClip()->fOrigin)) { 727 return true; 728 } 729 } 730 return false; 731 } 732 733 void GrInOrderDrawBuffer::recordClip() { 734 fClips.push_back() = *this->getClip()->fClipStack; 735 fClipOrigins.push_back() = this->getClip()->fOrigin; 736 fClipSet = false; 737 fCmds.push_back(kSetClip_Cmd); 738 } 739 740 void GrInOrderDrawBuffer::recordState() { 741 fStates.push_back().saveFrom(this->getDrawState()); 742 fCmds.push_back(kSetState_Cmd); 743 } 744 745 GrInOrderDrawBuffer::DrawRecord* GrInOrderDrawBuffer::recordDraw(const DrawInfo& info) { 746 fCmds.push_back(kDraw_Cmd); 747 return &fDraws.push_back(info); 748 } 749 750 GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath() { 751 fCmds.push_back(kStencilPath_Cmd); 752 return &fStencilPaths.push_back(); 753 } 754 755 GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() { 756 fCmds.push_back(kClear_Cmd); 757 return &fClears.push_back(); 758 } 759 760 void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) { 761 INHERITED::clipWillBeSet(newClipData); 762 fClipSet = true; 763 fClipProxyState = kUnknown_ClipProxyState; 764 } 765