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 "GrMeshDrawOp.h" 9#include "GrOpFlushState.h" 10#include "GrResourceProvider.h" 11 12GrMeshDrawOp::GrMeshDrawOp(uint32_t classID) 13 : INHERITED(classID), fBaseDrawToken(GrDrawOpUploadToken::AlreadyFlushedToken()) {} 14 15void GrMeshDrawOp::onPrepare(GrOpFlushState* state) { 16 Target target(state, this); 17 this->onPrepareDraws(&target); 18} 19 20void* GrMeshDrawOp::InstancedHelper::init(Target* target, GrPrimitiveType primType, 21 size_t vertexStride, const GrBuffer* indexBuffer, 22 int verticesPerInstance, int indicesPerInstance, 23 int instancesToDraw) { 24 SkASSERT(target); 25 if (!indexBuffer) { 26 return nullptr; 27 } 28 const GrBuffer* vertexBuffer; 29 int firstVertex; 30 int vertexCount = verticesPerInstance * instancesToDraw; 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 maxInstancesPerDraw = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerInstance)); 40 41 fMesh.initInstanced(primType, vertexBuffer, indexBuffer, firstVertex, verticesPerInstance, 42 indicesPerInstance, instancesToDraw, maxInstancesPerDraw); 43 return vertices; 44} 45 46void GrMeshDrawOp::InstancedHelper::recordDraw(Target* target, const GrGeometryProcessor* gp) { 47 SkASSERT(fMesh.instanceCount()); 48 target->draw(gp, fMesh); 49} 50 51void* GrMeshDrawOp::QuadHelper::init(Target* target, size_t vertexStride, int quadsToDraw) { 52 sk_sp<const GrBuffer> quadIndexBuffer(target->resourceProvider()->refQuadIndexBuffer()); 53 if (!quadIndexBuffer) { 54 SkDebugf("Could not get quad index buffer."); 55 return nullptr; 56 } 57 return this->INHERITED::init(target, kTriangles_GrPrimitiveType, vertexStride, 58 quadIndexBuffer.get(), kVerticesPerQuad, kIndicesPerQuad, 59 quadsToDraw); 60} 61 62void GrMeshDrawOp::onExecute(GrOpFlushState* state) { 63 SkASSERT(!state->drawOpArgs().fAppliedClip); 64 SkASSERT(!state->drawOpArgs().fDstTexture.texture()); 65 SkASSERT(state->drawOpArgs().fRenderTarget == this->pipeline()->getRenderTarget()); 66 int currUploadIdx = 0; 67 int currMeshIdx = 0; 68 69 SkASSERT(fQueuedDraws.empty() || fBaseDrawToken == state->nextTokenToFlush()); 70 71 for (int currDrawIdx = 0; currDrawIdx < fQueuedDraws.count(); ++currDrawIdx) { 72 GrDrawOpUploadToken drawToken = state->nextTokenToFlush(); 73 while (currUploadIdx < fInlineUploads.count() && 74 fInlineUploads[currUploadIdx].fUploadBeforeToken == drawToken) { 75 state->commandBuffer()->inlineUpload(state, fInlineUploads[currUploadIdx++].fUpload, 76 this->pipeline()->getRenderTarget()); 77 } 78 const QueuedDraw& draw = fQueuedDraws[currDrawIdx]; 79 state->commandBuffer()->draw(*this->pipeline(), *draw.fGeometryProcessor.get(), 80 fMeshes.begin() + currMeshIdx, draw.fMeshCnt, this->bounds()); 81 currMeshIdx += draw.fMeshCnt; 82 state->flushToken(); 83 } 84 SkASSERT(currUploadIdx == fInlineUploads.count()); 85 SkASSERT(currMeshIdx == fMeshes.count()); 86 fQueuedDraws.reset(); 87 fInlineUploads.reset(); 88} 89 90////////////////////////////////////////////////////////////////////////////// 91 92void GrMeshDrawOp::Target::draw(const GrGeometryProcessor* gp, 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 there are no intervening uploads, 97 // add this mesh to it. 98 GrMeshDrawOp::QueuedDraw& lastDraw = op->fQueuedDraws.back(); 99 if (lastDraw.fGeometryProcessor == gp && 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.fMeshCnt = 1; 110 if (op->fQueuedDraws.count() == 1) { 111 op->fBaseDrawToken = token; 112 } 113} 114