1 /* 2 * Copyright 2015 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 "GrGpuCommandBuffer.h" 9 #include "GrMeshDrawOp.h" 10 #include "GrOpFlushState.h" 11 #include "GrResourceProvider.h" 12 13 GrMeshDrawOp::GrMeshDrawOp(uint32_t classID) 14 : INHERITED(classID), fBaseDrawToken(GrDrawOpUploadToken::AlreadyFlushedToken()) {} 15 16 void GrMeshDrawOp::onPrepare(GrOpFlushState* state) { 17 Target target(state, this); 18 this->onPrepareDraws(&target); 19 } 20 21 void* GrMeshDrawOp::PatternHelper::init(Target* target, size_t vertexStride, 22 const GrBuffer* indexBuffer, int verticesPerRepetition, 23 int indicesPerRepetition, int repeatCount) { 24 SkASSERT(target); 25 if (!indexBuffer) { 26 return nullptr; 27 } 28 const GrBuffer* vertexBuffer; 29 int firstVertex; 30 int vertexCount = verticesPerRepetition * repeatCount; 31 void* vertices = 32 target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); 33 if (!vertices) { 34 SkDebugf("Vertices could not be allocated for instanced rendering."); 35 return nullptr; 36 } 37 SkASSERT(vertexBuffer); 38 size_t ibSize = indexBuffer->gpuMemorySize(); 39 int maxRepetitions = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerRepetition)); 40 41 fMesh.setIndexedPatterned(indexBuffer, indicesPerRepetition, verticesPerRepetition, 42 repeatCount, maxRepetitions); 43 fMesh.setVertexData(vertexBuffer, firstVertex); 44 return vertices; 45 } 46 47 void GrMeshDrawOp::PatternHelper::recordDraw(Target* target, const GrGeometryProcessor* gp, 48 const GrPipeline* pipeline) { 49 target->draw(gp, pipeline, fMesh); 50 } 51 52 void* GrMeshDrawOp::QuadHelper::init(Target* target, size_t vertexStride, int quadsToDraw) { 53 sk_sp<const GrBuffer> quadIndexBuffer(target->resourceProvider()->refQuadIndexBuffer()); 54 if (!quadIndexBuffer) { 55 SkDebugf("Could not get quad index buffer."); 56 return nullptr; 57 } 58 return this->INHERITED::init(target, vertexStride, quadIndexBuffer.get(), kVerticesPerQuad, 59 kIndicesPerQuad, quadsToDraw); 60 } 61 62 void GrMeshDrawOp::onExecute(GrOpFlushState* state) { 63 int currUploadIdx = 0; 64 int currMeshIdx = 0; 65 66 SkASSERT(fQueuedDraws.empty() || fBaseDrawToken == state->nextTokenToFlush()); 67 68 for (int currDrawIdx = 0; currDrawIdx < fQueuedDraws.count(); ++currDrawIdx) { 69 GrDrawOpUploadToken drawToken = state->nextTokenToFlush(); 70 while (currUploadIdx < fInlineUploads.count() && 71 fInlineUploads[currUploadIdx].fUploadBeforeToken == drawToken) { 72 state->commandBuffer()->inlineUpload(state, fInlineUploads[currUploadIdx++].fUpload, 73 state->drawOpArgs().fRenderTarget); 74 } 75 const QueuedDraw& draw = fQueuedDraws[currDrawIdx]; 76 SkASSERT(draw.fPipeline->getRenderTarget() == state->drawOpArgs().fRenderTarget); 77 state->commandBuffer()->draw(*draw.fPipeline, *draw.fGeometryProcessor.get(), 78 fMeshes.begin() + currMeshIdx, nullptr, draw.fMeshCnt, 79 this->bounds()); 80 currMeshIdx += draw.fMeshCnt; 81 state->flushToken(); 82 } 83 SkASSERT(currUploadIdx == fInlineUploads.count()); 84 SkASSERT(currMeshIdx == fMeshes.count()); 85 fQueuedDraws.reset(); 86 fInlineUploads.reset(); 87 } 88 89 ////////////////////////////////////////////////////////////////////////////// 90 91 void GrMeshDrawOp::Target::draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline, 92 const GrMesh& mesh) { 93 GrMeshDrawOp* op = this->meshDrawOp(); 94 op->fMeshes.push_back(mesh); 95 if (!op->fQueuedDraws.empty()) { 96 // If the last draw shares a geometry processor and pipeline and there are no intervening 97 // uploads, add this mesh to it. 98 GrMeshDrawOp::QueuedDraw& lastDraw = op->fQueuedDraws.back(); 99 if (lastDraw.fGeometryProcessor == gp && lastDraw.fPipeline == pipeline && 100 (op->fInlineUploads.empty() || 101 op->fInlineUploads.back().fUploadBeforeToken != this->nextDrawToken())) { 102 ++lastDraw.fMeshCnt; 103 return; 104 } 105 } 106 GrMeshDrawOp::QueuedDraw& draw = op->fQueuedDraws.push_back(); 107 GrDrawOpUploadToken token = this->state()->issueDrawToken(); 108 draw.fGeometryProcessor.reset(gp); 109 draw.fPipeline = pipeline; 110 draw.fMeshCnt = 1; 111 if (op->fQueuedDraws.count() == 1) { 112 op->fBaseDrawToken = token; 113 } 114 } 115