1 /* 2 * Copyright 2011 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 #include "GrInOrderDrawBuffer.h" 9 10 #include "GrBufferAllocPool.h" 11 #include "GrDrawTargetCaps.h" 12 #include "GrTextStrike.h" 13 #include "GrGpu.h" 14 #include "GrIndexBuffer.h" 15 #include "GrPath.h" 16 #include "GrRenderTarget.h" 17 #include "GrTemplates.h" 18 #include "GrTexture.h" 19 #include "GrVertexBuffer.h" 20 21 GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrGpu* gpu, 22 GrVertexBufferAllocPool* vertexPool, 23 GrIndexBufferAllocPool* indexPool) 24 : GrDrawTarget(gpu->getContext()) 25 , fDstGpu(gpu) 26 , fClipSet(true) 27 , fClipProxyState(kUnknown_ClipProxyState) 28 , fVertexPool(*vertexPool) 29 , fIndexPool(*indexPool) 30 , fFlushing(false) 31 , fDrawID(0) { 32 33 fDstGpu->ref(); 34 fCaps.reset(SkRef(fDstGpu->caps())); 35 36 SkASSERT(NULL != vertexPool); 37 SkASSERT(NULL != indexPool); 38 39 GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); 40 poolState.fUsedPoolVertexBytes = 0; 41 poolState.fUsedPoolIndexBytes = 0; 42 #ifdef SK_DEBUG 43 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; 44 poolState.fPoolStartVertex = ~0; 45 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; 46 poolState.fPoolStartIndex = ~0; 47 #endif 48 this->reset(); 49 } 50 51 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() { 52 this->reset(); 53 // This must be called by before the GrDrawTarget destructor 54 this->releaseGeometry(); 55 fDstGpu->unref(); 56 } 57 58 //////////////////////////////////////////////////////////////////////////////// 59 60 namespace { 61 void get_vertex_bounds(const void* vertices, 62 size_t vertexSize, 63 int vertexCount, 64 SkRect* bounds) { 65 SkASSERT(vertexSize >= sizeof(SkPoint)); 66 SkASSERT(vertexCount > 0); 67 const SkPoint* point = static_cast<const SkPoint*>(vertices); 68 bounds->fLeft = bounds->fRight = point->fX; 69 bounds->fTop = bounds->fBottom = point->fY; 70 for (int i = 1; i < vertexCount; ++i) { 71 point = reinterpret_cast<SkPoint*>(reinterpret_cast<intptr_t>(point) + vertexSize); 72 bounds->growToInclude(point->fX, point->fY); 73 } 74 } 75 } 76 77 78 namespace { 79 80 extern const GrVertexAttrib kRectPosColorUVAttribs[] = { 81 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 82 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding}, 83 {kVec2f_GrVertexAttribType, sizeof(SkPoint)+sizeof(GrColor), 84 kLocalCoord_GrVertexAttribBinding}, 85 }; 86 87 extern const GrVertexAttrib kRectPosUVAttribs[] = { 88 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 89 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding}, 90 }; 91 92 static void set_vertex_attributes(GrDrawState* drawState, 93 bool hasColor, bool hasUVs, 94 int* colorOffset, int* localOffset) { 95 *colorOffset = -1; 96 *localOffset = -1; 97 98 // Using per-vertex colors allows batching across colors. (A lot of rects in a row differing 99 // only in color is a common occurrence in tables). However, having per-vertex colors disables 100 // blending optimizations because we don't know if the color will be solid or not. These 101 // optimizations help determine whether coverage and color can be blended correctly when 102 // dual-source blending isn't available. This comes into play when there is coverage. If colors 103 // were a stage it could take a hint that every vertex's color will be opaque. 104 if (hasColor && hasUVs) { 105 *colorOffset = sizeof(SkPoint); 106 *localOffset = sizeof(SkPoint) + sizeof(GrColor); 107 drawState->setVertexAttribs<kRectPosColorUVAttribs>(3); 108 } else if (hasColor) { 109 *colorOffset = sizeof(SkPoint); 110 drawState->setVertexAttribs<kRectPosColorUVAttribs>(2); 111 } else if (hasUVs) { 112 *localOffset = sizeof(SkPoint); 113 drawState->setVertexAttribs<kRectPosUVAttribs>(2); 114 } else { 115 drawState->setVertexAttribs<kRectPosUVAttribs>(1); 116 } 117 } 118 119 }; 120 121 enum { 122 kTraceCmdBit = 0x80, 123 kCmdMask = 0x7f, 124 }; 125 126 static uint8_t add_trace_bit(uint8_t cmd) { 127 return cmd | kTraceCmdBit; 128 } 129 130 static uint8_t strip_trace_bit(uint8_t cmd) { 131 return cmd & kCmdMask; 132 } 133 134 static bool cmd_has_trace_marker(uint8_t cmd) { 135 return SkToBool(cmd & kTraceCmdBit); 136 } 137 138 void GrInOrderDrawBuffer::onDrawRect(const SkRect& rect, 139 const SkMatrix* matrix, 140 const SkRect* localRect, 141 const SkMatrix* localMatrix) { 142 GrDrawState::AutoColorRestore acr; 143 144 GrDrawState* drawState = this->drawState(); 145 146 GrColor color = drawState->getColor(); 147 148 int colorOffset, localOffset; 149 set_vertex_attributes(drawState, 150 this->caps()->dualSourceBlendingSupport() || drawState->hasSolidCoverage(), 151 NULL != localRect, 152 &colorOffset, &localOffset); 153 if (colorOffset >= 0) { 154 // We set the draw state's color to white here. This is done so that any batching performed 155 // in our subclass's onDraw() won't get a false from GrDrawState::op== due to a color 156 // mismatch. TODO: Once vertex layout is owned by GrDrawState it should skip comparing the 157 // constant color in its op== when the kColor layout bit is set and then we can remove 158 // this. 159 acr.set(drawState, 0xFFFFFFFF); 160 } 161 162 AutoReleaseGeometry geo(this, 4, 0); 163 if (!geo.succeeded()) { 164 GrPrintf("Failed to get space for vertices!\n"); 165 return; 166 } 167 168 // Go to device coords to allow batching across matrix changes 169 SkMatrix combinedMatrix; 170 if (NULL != matrix) { 171 combinedMatrix = *matrix; 172 } else { 173 combinedMatrix.reset(); 174 } 175 combinedMatrix.postConcat(drawState->getViewMatrix()); 176 // When the caller has provided an explicit source rect for a stage then we don't want to 177 // modify that stage's matrix. Otherwise if the effect is generating its source rect from 178 // the vertex positions then we have to account for the view matrix change. 179 GrDrawState::AutoViewMatrixRestore avmr; 180 if (!avmr.setIdentity(drawState)) { 181 return; 182 } 183 184 size_t vsize = drawState->getVertexSize(); 185 186 geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize); 187 combinedMatrix.mapPointsWithStride(geo.positions(), vsize, 4); 188 189 SkRect devBounds; 190 // since we already computed the dev verts, set the bounds hint. This will help us avoid 191 // unnecessary clipping in our onDraw(). 192 get_vertex_bounds(geo.vertices(), vsize, 4, &devBounds); 193 194 if (localOffset >= 0) { 195 SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + localOffset); 196 coords->setRectFan(localRect->fLeft, localRect->fTop, 197 localRect->fRight, localRect->fBottom, 198 vsize); 199 if (NULL != localMatrix) { 200 localMatrix->mapPointsWithStride(coords, vsize, 4); 201 } 202 } 203 204 if (colorOffset >= 0) { 205 GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + colorOffset); 206 for (int i = 0; i < 4; ++i) { 207 *vertColor = color; 208 vertColor = (GrColor*) ((intptr_t) vertColor + vsize); 209 } 210 } 211 212 this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer()); 213 this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds); 214 215 // to ensure that stashing the drawState ptr is valid 216 SkASSERT(this->drawState() == drawState); 217 } 218 219 bool GrInOrderDrawBuffer::quickInsideClip(const SkRect& devBounds) { 220 if (!this->getDrawState().isClipState()) { 221 return true; 222 } 223 if (kUnknown_ClipProxyState == fClipProxyState) { 224 SkIRect rect; 225 bool iior; 226 this->getClip()->getConservativeBounds(this->getDrawState().getRenderTarget(), &rect, &iior); 227 if (iior) { 228 // The clip is a rect. We will remember that in fProxyClip. It is common for an edge (or 229 // all edges) of the clip to be at the edge of the RT. However, we get that clipping for 230 // free via the viewport. We don't want to think that clipping must be enabled in this 231 // case. So we extend the clip outward from the edge to avoid these false negatives. 232 fClipProxyState = kValid_ClipProxyState; 233 fClipProxy = SkRect::Make(rect); 234 235 if (fClipProxy.fLeft <= 0) { 236 fClipProxy.fLeft = SK_ScalarMin; 237 } 238 if (fClipProxy.fTop <= 0) { 239 fClipProxy.fTop = SK_ScalarMin; 240 } 241 if (fClipProxy.fRight >= this->getDrawState().getRenderTarget()->width()) { 242 fClipProxy.fRight = SK_ScalarMax; 243 } 244 if (fClipProxy.fBottom >= this->getDrawState().getRenderTarget()->height()) { 245 fClipProxy.fBottom = SK_ScalarMax; 246 } 247 } else { 248 fClipProxyState = kInvalid_ClipProxyState; 249 } 250 } 251 if (kValid_ClipProxyState == fClipProxyState) { 252 return fClipProxy.contains(devBounds); 253 } 254 SkPoint originOffset = {SkIntToScalar(this->getClip()->fOrigin.fX), 255 SkIntToScalar(this->getClip()->fOrigin.fY)}; 256 SkRect clipSpaceBounds = devBounds; 257 clipSpaceBounds.offset(originOffset); 258 return this->getClip()->fClipStack->quickContains(clipSpaceBounds); 259 } 260 261 int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) { 262 SkASSERT(info.isInstanced()); 263 264 const GeometrySrcState& geomSrc = this->getGeomSrc(); 265 const GrDrawState& drawState = this->getDrawState(); 266 267 // we only attempt to concat the case when reserved verts are used with a client-specified index 268 // buffer. To make this work with client-specified VBs we'd need to know if the VB was updated 269 // between draws. 270 if (kReserved_GeometrySrcType != geomSrc.fVertexSrc || 271 kBuffer_GeometrySrcType != geomSrc.fIndexSrc) { 272 return 0; 273 } 274 // Check if there is a draw info that is compatible that uses the same VB from the pool and 275 // the same IB 276 if (kDraw_Cmd != strip_trace_bit(fCmds.back())) { 277 return 0; 278 } 279 280 DrawRecord* draw = &fDraws.back(); 281 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 282 const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer; 283 284 if (!draw->isInstanced() || 285 draw->verticesPerInstance() != info.verticesPerInstance() || 286 draw->indicesPerInstance() != info.indicesPerInstance() || 287 draw->fVertexBuffer != vertexBuffer || 288 draw->fIndexBuffer != geomSrc.fIndexBuffer) { 289 return 0; 290 } 291 // info does not yet account for the offset from the start of the pool's VB while the previous 292 // draw record does. 293 int adjustedStartVertex = poolState.fPoolStartVertex + info.startVertex(); 294 if (draw->startVertex() + draw->vertexCount() != adjustedStartVertex) { 295 return 0; 296 } 297 298 SkASSERT(poolState.fPoolStartVertex == draw->startVertex() + draw->vertexCount()); 299 300 // how many instances can be concat'ed onto draw given the size of the index buffer 301 int instancesToConcat = this->indexCountInCurrentSource() / info.indicesPerInstance(); 302 instancesToConcat -= draw->instanceCount(); 303 instancesToConcat = SkTMin(instancesToConcat, info.instanceCount()); 304 305 // update the amount of reserved vertex data actually referenced in draws 306 size_t vertexBytes = instancesToConcat * info.verticesPerInstance() * 307 drawState.getVertexSize(); 308 poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, vertexBytes); 309 310 draw->adjustInstanceCount(instancesToConcat); 311 312 // update last fGpuCmdMarkers to include any additional trace markers that have been added 313 if (this->getActiveTraceMarkers().count() > 0) { 314 if (cmd_has_trace_marker(fCmds.back())) { 315 fGpuCmdMarkers.back().addSet(this->getActiveTraceMarkers()); 316 } else { 317 fGpuCmdMarkers.push_back(this->getActiveTraceMarkers()); 318 fCmds.back() = add_trace_bit(fCmds.back()); 319 } 320 } 321 322 return instancesToConcat; 323 } 324 325 class AutoClipReenable { 326 public: 327 AutoClipReenable() : fDrawState(NULL) {} 328 ~AutoClipReenable() { 329 if (NULL != fDrawState) { 330 fDrawState->enableState(GrDrawState::kClip_StateBit); 331 } 332 } 333 void set(GrDrawState* drawState) { 334 if (drawState->isClipState()) { 335 fDrawState = drawState; 336 drawState->disableState(GrDrawState::kClip_StateBit); 337 } 338 } 339 private: 340 GrDrawState* fDrawState; 341 }; 342 343 void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) { 344 345 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 346 const GrDrawState& drawState = this->getDrawState(); 347 AutoClipReenable acr; 348 349 if (drawState.isClipState() && 350 NULL != info.getDevBounds() && 351 this->quickInsideClip(*info.getDevBounds())) { 352 acr.set(this->drawState()); 353 } 354 355 if (this->needsNewClip()) { 356 this->recordClip(); 357 } 358 if (this->needsNewState()) { 359 this->recordState(); 360 } 361 362 DrawRecord* draw; 363 if (info.isInstanced()) { 364 int instancesConcated = this->concatInstancedDraw(info); 365 if (info.instanceCount() > instancesConcated) { 366 draw = this->recordDraw(info); 367 draw->adjustInstanceCount(-instancesConcated); 368 } else { 369 return; 370 } 371 } else { 372 draw = this->recordDraw(info); 373 } 374 375 switch (this->getGeomSrc().fVertexSrc) { 376 case kBuffer_GeometrySrcType: 377 draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer; 378 break; 379 case kReserved_GeometrySrcType: // fallthrough 380 case kArray_GeometrySrcType: { 381 size_t vertexBytes = (info.vertexCount() + info.startVertex()) * 382 drawState.getVertexSize(); 383 poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, vertexBytes); 384 draw->fVertexBuffer = poolState.fPoolVertexBuffer; 385 draw->adjustStartVertex(poolState.fPoolStartVertex); 386 break; 387 } 388 default: 389 SkFAIL("unknown geom src type"); 390 } 391 draw->fVertexBuffer->ref(); 392 393 if (info.isIndexed()) { 394 switch (this->getGeomSrc().fIndexSrc) { 395 case kBuffer_GeometrySrcType: 396 draw->fIndexBuffer = this->getGeomSrc().fIndexBuffer; 397 break; 398 case kReserved_GeometrySrcType: // fallthrough 399 case kArray_GeometrySrcType: { 400 size_t indexBytes = (info.indexCount() + info.startIndex()) * sizeof(uint16_t); 401 poolState.fUsedPoolIndexBytes = SkTMax(poolState.fUsedPoolIndexBytes, indexBytes); 402 draw->fIndexBuffer = poolState.fPoolIndexBuffer; 403 draw->adjustStartIndex(poolState.fPoolStartIndex); 404 break; 405 } 406 default: 407 SkFAIL("unknown geom src type"); 408 } 409 draw->fIndexBuffer->ref(); 410 } else { 411 draw->fIndexBuffer = NULL; 412 } 413 } 414 415 GrInOrderDrawBuffer::StencilPath::StencilPath() {} 416 GrInOrderDrawBuffer::DrawPath::DrawPath() {} 417 GrInOrderDrawBuffer::DrawPaths::DrawPaths() {} 418 GrInOrderDrawBuffer::DrawPaths::~DrawPaths() { 419 if (fTransforms) { 420 SkDELETE_ARRAY(fTransforms); 421 } 422 for (int i = 0; i < fPathCount; ++i) { 423 fPaths[i]->unref(); 424 } 425 SkDELETE_ARRAY(fPaths); 426 } 427 428 void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, SkPath::FillType fill) { 429 if (this->needsNewClip()) { 430 this->recordClip(); 431 } 432 // Only compare the subset of GrDrawState relevant to path stenciling? 433 if (this->needsNewState()) { 434 this->recordState(); 435 } 436 StencilPath* sp = this->recordStencilPath(); 437 sp->fPath.reset(path); 438 path->ref(); 439 sp->fFill = fill; 440 } 441 442 void GrInOrderDrawBuffer::onDrawPath(const GrPath* path, 443 SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) { 444 if (this->needsNewClip()) { 445 this->recordClip(); 446 } 447 // TODO: Only compare the subset of GrDrawState relevant to path covering? 448 if (this->needsNewState()) { 449 this->recordState(); 450 } 451 DrawPath* cp = this->recordDrawPath(); 452 cp->fPath.reset(path); 453 path->ref(); 454 cp->fFill = fill; 455 if (NULL != dstCopy) { 456 cp->fDstCopy = *dstCopy; 457 } 458 } 459 460 void GrInOrderDrawBuffer::onDrawPaths(int pathCount, const GrPath** paths, 461 const SkMatrix* transforms, 462 SkPath::FillType fill, 463 SkStrokeRec::Style stroke, 464 const GrDeviceCoordTexture* dstCopy) { 465 SkASSERT(pathCount); 466 467 if (this->needsNewClip()) { 468 this->recordClip(); 469 } 470 if (this->needsNewState()) { 471 this->recordState(); 472 } 473 DrawPaths* dp = this->recordDrawPaths(); 474 dp->fPathCount = pathCount; 475 dp->fPaths = SkNEW_ARRAY(const GrPath*, pathCount); 476 memcpy(dp->fPaths, paths, sizeof(GrPath*) * pathCount); 477 for (int i = 0; i < pathCount; ++i) { 478 dp->fPaths[i]->ref(); 479 } 480 481 dp->fTransforms = SkNEW_ARRAY(SkMatrix, pathCount); 482 memcpy(dp->fTransforms, transforms, sizeof(SkMatrix) * pathCount); 483 484 dp->fFill = fill; 485 dp->fStroke = stroke; 486 487 if (NULL != dstCopy) { 488 dp->fDstCopy = *dstCopy; 489 } 490 } 491 492 void GrInOrderDrawBuffer::clear(const SkIRect* rect, GrColor color, 493 bool canIgnoreRect, GrRenderTarget* renderTarget) { 494 SkIRect r; 495 if (NULL == renderTarget) { 496 renderTarget = this->drawState()->getRenderTarget(); 497 SkASSERT(NULL != renderTarget); 498 } 499 if (NULL == rect) { 500 // We could do something smart and remove previous draws and clears to 501 // the current render target. If we get that smart we have to make sure 502 // those draws aren't read before this clear (render-to-texture). 503 r.setLTRB(0, 0, renderTarget->width(), renderTarget->height()); 504 rect = &r; 505 } 506 Clear* clr = this->recordClear(); 507 GrColorIsPMAssert(color); 508 clr->fColor = color; 509 clr->fRect = *rect; 510 clr->fCanIgnoreRect = canIgnoreRect; 511 clr->fRenderTarget = renderTarget; 512 renderTarget->ref(); 513 } 514 515 void GrInOrderDrawBuffer::discard(GrRenderTarget* renderTarget) { 516 if (!this->caps()->discardRenderTargetSupport()) { 517 return; 518 } 519 if (NULL == renderTarget) { 520 renderTarget = this->drawState()->getRenderTarget(); 521 SkASSERT(NULL != renderTarget); 522 } 523 Clear* clr = this->recordClear(); 524 clr->fColor = GrColor_ILLEGAL; 525 clr->fRenderTarget = renderTarget; 526 renderTarget->ref(); 527 } 528 529 void GrInOrderDrawBuffer::reset() { 530 SkASSERT(1 == fGeoPoolStateStack.count()); 531 this->resetVertexSource(); 532 this->resetIndexSource(); 533 int numDraws = fDraws.count(); 534 for (int d = 0; d < numDraws; ++d) { 535 // we always have a VB, but not always an IB 536 SkASSERT(NULL != fDraws[d].fVertexBuffer); 537 fDraws[d].fVertexBuffer->unref(); 538 SkSafeUnref(fDraws[d].fIndexBuffer); 539 } 540 fCmds.reset(); 541 fDraws.reset(); 542 fStencilPaths.reset(); 543 fDrawPath.reset(); 544 fDrawPaths.reset(); 545 fStates.reset(); 546 fClears.reset(); 547 fVertexPool.reset(); 548 fIndexPool.reset(); 549 fClips.reset(); 550 fClipOrigins.reset(); 551 fCopySurfaces.reset(); 552 fGpuCmdMarkers.reset(); 553 fClipSet = true; 554 } 555 556 void GrInOrderDrawBuffer::flush() { 557 if (fFlushing) { 558 return; 559 } 560 561 this->getContext()->getFontCache()->updateTextures(); 562 563 SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc); 564 SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc); 565 566 int numCmds = fCmds.count(); 567 if (0 == numCmds) { 568 return; 569 } 570 571 GrAutoTRestore<bool> flushRestore(&fFlushing); 572 fFlushing = true; 573 574 fVertexPool.unmap(); 575 fIndexPool.unmap(); 576 577 GrDrawTarget::AutoClipRestore acr(fDstGpu); 578 AutoGeometryAndStatePush agasp(fDstGpu, kPreserve_ASRInit); 579 580 GrDrawState playbackState; 581 GrDrawState* prevDrawState = fDstGpu->drawState(); 582 prevDrawState->ref(); 583 fDstGpu->setDrawState(&playbackState); 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 int currDrawPath = 0; 593 int currDrawPaths = 0; 594 int currCopySurface = 0; 595 int currCmdMarker = 0; 596 597 fDstGpu->saveActiveTraceMarkers(); 598 for (int c = 0; c < numCmds; ++c) { 599 GrGpuTraceMarker newMarker("", -1); 600 if (cmd_has_trace_marker(fCmds[c])) { 601 SkString traceString = fGpuCmdMarkers[currCmdMarker].toString(); 602 newMarker.fMarker = traceString.c_str(); 603 fDstGpu->addGpuTraceMarker(&newMarker); 604 ++currCmdMarker; 605 } 606 switch (strip_trace_bit(fCmds[c])) { 607 case kDraw_Cmd: { 608 const DrawRecord& draw = fDraws[currDraw]; 609 fDstGpu->setVertexSourceToBuffer(draw.fVertexBuffer); 610 if (draw.isIndexed()) { 611 fDstGpu->setIndexSourceToBuffer(draw.fIndexBuffer); 612 } 613 fDstGpu->executeDraw(draw); 614 ++currDraw; 615 break; 616 } 617 case kStencilPath_Cmd: { 618 const StencilPath& sp = fStencilPaths[currStencilPath]; 619 fDstGpu->stencilPath(sp.fPath.get(), sp.fFill); 620 ++currStencilPath; 621 break; 622 } 623 case kDrawPath_Cmd: { 624 const DrawPath& cp = fDrawPath[currDrawPath]; 625 fDstGpu->executeDrawPath(cp.fPath.get(), cp.fFill, 626 NULL != cp.fDstCopy.texture() ? &cp.fDstCopy : NULL); 627 ++currDrawPath; 628 break; 629 } 630 case kDrawPaths_Cmd: { 631 DrawPaths& dp = fDrawPaths[currDrawPaths]; 632 const GrDeviceCoordTexture* dstCopy = 633 NULL != dp.fDstCopy.texture() ? &dp.fDstCopy : NULL; 634 fDstGpu->executeDrawPaths(dp.fPathCount, dp.fPaths, 635 dp.fTransforms, dp.fFill, dp.fStroke, 636 dstCopy); 637 ++currDrawPaths; 638 break; 639 } 640 case kSetState_Cmd: 641 fStates[currState].restoreTo(&playbackState); 642 ++currState; 643 break; 644 case kSetClip_Cmd: 645 clipData.fClipStack = &fClips[currClip]; 646 clipData.fOrigin = fClipOrigins[currClip]; 647 fDstGpu->setClip(&clipData); 648 ++currClip; 649 break; 650 case kClear_Cmd: 651 if (GrColor_ILLEGAL == fClears[currClear].fColor) { 652 fDstGpu->discard(fClears[currClear].fRenderTarget); 653 } else { 654 fDstGpu->clear(&fClears[currClear].fRect, 655 fClears[currClear].fColor, 656 fClears[currClear].fCanIgnoreRect, 657 fClears[currClear].fRenderTarget); 658 } 659 ++currClear; 660 break; 661 case kCopySurface_Cmd: 662 fDstGpu->copySurface(fCopySurfaces[currCopySurface].fDst.get(), 663 fCopySurfaces[currCopySurface].fSrc.get(), 664 fCopySurfaces[currCopySurface].fSrcRect, 665 fCopySurfaces[currCopySurface].fDstPoint); 666 ++currCopySurface; 667 break; 668 } 669 if (cmd_has_trace_marker(fCmds[c])) { 670 fDstGpu->removeGpuTraceMarker(&newMarker); 671 } 672 } 673 fDstGpu->restoreActiveTraceMarkers(); 674 // we should have consumed all the states, clips, etc. 675 SkASSERT(fStates.count() == currState); 676 SkASSERT(fClips.count() == currClip); 677 SkASSERT(fClipOrigins.count() == currClip); 678 SkASSERT(fClears.count() == currClear); 679 SkASSERT(fDraws.count() == currDraw); 680 SkASSERT(fCopySurfaces.count() == currCopySurface); 681 SkASSERT(fGpuCmdMarkers.count() == currCmdMarker); 682 683 fDstGpu->setDrawState(prevDrawState); 684 prevDrawState->unref(); 685 this->reset(); 686 ++fDrawID; 687 } 688 689 bool GrInOrderDrawBuffer::onCopySurface(GrSurface* dst, 690 GrSurface* src, 691 const SkIRect& srcRect, 692 const SkIPoint& dstPoint) { 693 if (fDstGpu->canCopySurface(dst, src, srcRect, dstPoint)) { 694 CopySurface* cs = this->recordCopySurface(); 695 cs->fDst.reset(SkRef(dst)); 696 cs->fSrc.reset(SkRef(src)); 697 cs->fSrcRect = srcRect; 698 cs->fDstPoint = dstPoint; 699 return true; 700 } else { 701 return false; 702 } 703 } 704 705 bool GrInOrderDrawBuffer::onCanCopySurface(GrSurface* dst, 706 GrSurface* src, 707 const SkIRect& srcRect, 708 const SkIPoint& dstPoint) { 709 return fDstGpu->canCopySurface(dst, src, srcRect, dstPoint); 710 } 711 712 void GrInOrderDrawBuffer::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) { 713 fDstGpu->initCopySurfaceDstDesc(src, desc); 714 } 715 716 void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace(int vertexCount, 717 int indexCount) { 718 // We use geometryHints() to know whether to flush the draw buffer. We 719 // can't flush if we are inside an unbalanced pushGeometrySource. 720 // Moreover, flushing blows away vertex and index data that was 721 // previously reserved. So if the vertex or index data is pulled from 722 // reserved space and won't be released by this request then we can't 723 // flush. 724 bool insideGeoPush = fGeoPoolStateStack.count() > 1; 725 726 bool unreleasedVertexSpace = 727 !vertexCount && 728 kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc; 729 730 bool unreleasedIndexSpace = 731 !indexCount && 732 kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc; 733 734 // we don't want to finalize any reserved geom on the target since 735 // we don't know that the client has finished writing to it. 736 bool targetHasReservedGeom = fDstGpu->hasReservedVerticesOrIndices(); 737 738 int vcount = vertexCount; 739 int icount = indexCount; 740 741 if (!insideGeoPush && 742 !unreleasedVertexSpace && 743 !unreleasedIndexSpace && 744 !targetHasReservedGeom && 745 this->geometryHints(&vcount, &icount)) { 746 747 this->flush(); 748 } 749 } 750 751 bool GrInOrderDrawBuffer::geometryHints(int* vertexCount, 752 int* indexCount) const { 753 // we will recommend a flush if the data could fit in a single 754 // preallocated buffer but none are left and it can't fit 755 // in the current buffer (which may not be prealloced). 756 bool flush = false; 757 if (NULL != indexCount) { 758 int32_t currIndices = fIndexPool.currentBufferIndices(); 759 if (*indexCount > currIndices && 760 (!fIndexPool.preallocatedBuffersRemaining() && 761 *indexCount <= fIndexPool.preallocatedBufferIndices())) { 762 763 flush = true; 764 } 765 *indexCount = currIndices; 766 } 767 if (NULL != vertexCount) { 768 size_t vertexSize = this->getDrawState().getVertexSize(); 769 int32_t currVertices = fVertexPool.currentBufferVertices(vertexSize); 770 if (*vertexCount > currVertices && 771 (!fVertexPool.preallocatedBuffersRemaining() && 772 *vertexCount <= fVertexPool.preallocatedBufferVertices(vertexSize))) { 773 774 flush = true; 775 } 776 *vertexCount = currVertices; 777 } 778 return flush; 779 } 780 781 bool GrInOrderDrawBuffer::onReserveVertexSpace(size_t vertexSize, 782 int vertexCount, 783 void** vertices) { 784 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 785 SkASSERT(vertexCount > 0); 786 SkASSERT(NULL != vertices); 787 SkASSERT(0 == poolState.fUsedPoolVertexBytes); 788 789 *vertices = fVertexPool.makeSpace(vertexSize, 790 vertexCount, 791 &poolState.fPoolVertexBuffer, 792 &poolState.fPoolStartVertex); 793 return NULL != *vertices; 794 } 795 796 bool GrInOrderDrawBuffer::onReserveIndexSpace(int indexCount, void** indices) { 797 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 798 SkASSERT(indexCount > 0); 799 SkASSERT(NULL != indices); 800 SkASSERT(0 == poolState.fUsedPoolIndexBytes); 801 802 *indices = fIndexPool.makeSpace(indexCount, 803 &poolState.fPoolIndexBuffer, 804 &poolState.fPoolStartIndex); 805 return NULL != *indices; 806 } 807 808 void GrInOrderDrawBuffer::releaseReservedVertexSpace() { 809 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 810 const GeometrySrcState& geoSrc = this->getGeomSrc(); 811 812 // If we get a release vertex space call then our current source should either be reserved 813 // or array (which we copied into reserved space). 814 SkASSERT(kReserved_GeometrySrcType == geoSrc.fVertexSrc || 815 kArray_GeometrySrcType == geoSrc.fVertexSrc); 816 817 // When the caller reserved vertex buffer space we gave it back a pointer 818 // provided by the vertex buffer pool. At each draw we tracked the largest 819 // offset into the pool's pointer that was referenced. Now we return to the 820 // pool any portion at the tail of the allocation that no draw referenced. 821 size_t reservedVertexBytes = geoSrc.fVertexSize * geoSrc.fVertexCount; 822 fVertexPool.putBack(reservedVertexBytes - 823 poolState.fUsedPoolVertexBytes); 824 poolState.fUsedPoolVertexBytes = 0; 825 poolState.fPoolVertexBuffer = NULL; 826 poolState.fPoolStartVertex = 0; 827 } 828 829 void GrInOrderDrawBuffer::releaseReservedIndexSpace() { 830 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 831 const GeometrySrcState& geoSrc = this->getGeomSrc(); 832 833 // If we get a release index space call then our current source should either be reserved 834 // or array (which we copied into reserved space). 835 SkASSERT(kReserved_GeometrySrcType == geoSrc.fIndexSrc || 836 kArray_GeometrySrcType == geoSrc.fIndexSrc); 837 838 // Similar to releaseReservedVertexSpace we return any unused portion at 839 // the tail 840 size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount; 841 fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes); 842 poolState.fUsedPoolIndexBytes = 0; 843 poolState.fPoolIndexBuffer = NULL; 844 poolState.fPoolStartIndex = 0; 845 } 846 847 void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray, 848 int vertexCount) { 849 850 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 851 SkASSERT(0 == poolState.fUsedPoolVertexBytes); 852 #ifdef SK_DEBUG 853 bool success = 854 #endif 855 fVertexPool.appendVertices(this->getVertexSize(), 856 vertexCount, 857 vertexArray, 858 &poolState.fPoolVertexBuffer, 859 &poolState.fPoolStartVertex); 860 GR_DEBUGASSERT(success); 861 } 862 863 void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray, 864 int indexCount) { 865 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 866 SkASSERT(0 == poolState.fUsedPoolIndexBytes); 867 #ifdef SK_DEBUG 868 bool success = 869 #endif 870 fIndexPool.appendIndices(indexCount, 871 indexArray, 872 &poolState.fPoolIndexBuffer, 873 &poolState.fPoolStartIndex); 874 GR_DEBUGASSERT(success); 875 } 876 877 void GrInOrderDrawBuffer::releaseVertexArray() { 878 // When the client provides an array as the vertex source we handled it 879 // by copying their array into reserved space. 880 this->GrInOrderDrawBuffer::releaseReservedVertexSpace(); 881 } 882 883 void GrInOrderDrawBuffer::releaseIndexArray() { 884 // When the client provides an array as the index source we handled it 885 // by copying their array into reserved space. 886 this->GrInOrderDrawBuffer::releaseReservedIndexSpace(); 887 } 888 889 void GrInOrderDrawBuffer::geometrySourceWillPush() { 890 GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); 891 poolState.fUsedPoolVertexBytes = 0; 892 poolState.fUsedPoolIndexBytes = 0; 893 #ifdef SK_DEBUG 894 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0; 895 poolState.fPoolStartVertex = ~0; 896 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0; 897 poolState.fPoolStartIndex = ~0; 898 #endif 899 } 900 901 void GrInOrderDrawBuffer::geometrySourceWillPop( 902 const GeometrySrcState& restoredState) { 903 SkASSERT(fGeoPoolStateStack.count() > 1); 904 fGeoPoolStateStack.pop_back(); 905 GeometryPoolState& poolState = fGeoPoolStateStack.back(); 906 // we have to assume that any slack we had in our vertex/index data 907 // is now unreleasable because data may have been appended later in the 908 // pool. 909 if (kReserved_GeometrySrcType == restoredState.fVertexSrc || 910 kArray_GeometrySrcType == restoredState.fVertexSrc) { 911 poolState.fUsedPoolVertexBytes = restoredState.fVertexSize * restoredState.fVertexCount; 912 } 913 if (kReserved_GeometrySrcType == restoredState.fIndexSrc || 914 kArray_GeometrySrcType == restoredState.fIndexSrc) { 915 poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * 916 restoredState.fIndexCount; 917 } 918 } 919 920 bool GrInOrderDrawBuffer::needsNewState() const { 921 return fStates.empty() || !fStates.back().isEqual(this->getDrawState()); 922 } 923 924 bool GrInOrderDrawBuffer::needsNewClip() const { 925 SkASSERT(fClips.count() == fClipOrigins.count()); 926 if (this->getDrawState().isClipState()) { 927 if (fClipSet && 928 (fClips.empty() || 929 fClips.back() != *this->getClip()->fClipStack || 930 fClipOrigins.back() != this->getClip()->fOrigin)) { 931 return true; 932 } 933 } 934 return false; 935 } 936 937 void GrInOrderDrawBuffer::addToCmdBuffer(uint8_t cmd) { 938 SkASSERT(!cmd_has_trace_marker(cmd)); 939 const GrTraceMarkerSet& activeTraceMarkers = this->getActiveTraceMarkers(); 940 if (activeTraceMarkers.count() > 0) { 941 fCmds.push_back(add_trace_bit(cmd)); 942 fGpuCmdMarkers.push_back(activeTraceMarkers); 943 } else { 944 fCmds.push_back(cmd); 945 } 946 } 947 948 void GrInOrderDrawBuffer::recordClip() { 949 fClips.push_back(*this->getClip()->fClipStack); 950 fClipOrigins.push_back() = this->getClip()->fOrigin; 951 fClipSet = false; 952 this->addToCmdBuffer(kSetClip_Cmd); 953 } 954 955 void GrInOrderDrawBuffer::recordState() { 956 fStates.push_back().saveFrom(this->getDrawState()); 957 this->addToCmdBuffer(kSetState_Cmd); 958 } 959 960 GrInOrderDrawBuffer::DrawRecord* GrInOrderDrawBuffer::recordDraw(const DrawInfo& info) { 961 this->addToCmdBuffer(kDraw_Cmd); 962 return &fDraws.push_back(info); 963 } 964 965 GrInOrderDrawBuffer::StencilPath* GrInOrderDrawBuffer::recordStencilPath() { 966 this->addToCmdBuffer(kStencilPath_Cmd); 967 return &fStencilPaths.push_back(); 968 } 969 970 GrInOrderDrawBuffer::DrawPath* GrInOrderDrawBuffer::recordDrawPath() { 971 this->addToCmdBuffer(kDrawPath_Cmd); 972 return &fDrawPath.push_back(); 973 } 974 975 GrInOrderDrawBuffer::DrawPaths* GrInOrderDrawBuffer::recordDrawPaths() { 976 this->addToCmdBuffer(kDrawPaths_Cmd); 977 return &fDrawPaths.push_back(); 978 } 979 980 GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() { 981 this->addToCmdBuffer(kClear_Cmd); 982 return &fClears.push_back(); 983 } 984 985 GrInOrderDrawBuffer::CopySurface* GrInOrderDrawBuffer::recordCopySurface() { 986 this->addToCmdBuffer(kCopySurface_Cmd); 987 return &fCopySurfaces.push_back(); 988 } 989 990 991 void GrInOrderDrawBuffer::clipWillBeSet(const GrClipData* newClipData) { 992 INHERITED::clipWillBeSet(newClipData); 993 fClipSet = true; 994 fClipProxyState = kUnknown_ClipProxyState; 995 } 996