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 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 52 GrInOrderDrawBuffer::~GrInOrderDrawBuffer() { 53 this->reset(); 54 GrSafeUnref(fQuadIndexBuffer); 55 } 56 57 void GrInOrderDrawBuffer::initializeDrawStateAndClip(const GrDrawTarget& target) { 58 this->copyDrawState(target); 59 this->setClip(target.getClip()); 60 } 61 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 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 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 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 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 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 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 408 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 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 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 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 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 521 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 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 538 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 547 void GrInOrderDrawBuffer::pushClip() { 548 fClips.push_back() = fClip; 549 fClipSet = false; 550 } 551 552 void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip) { 553 fClipSet = true; 554 } 555