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
GrMeshDrawOp(uint32_t classID)12 GrMeshDrawOp::GrMeshDrawOp(uint32_t classID)
13 : INHERITED(classID), fBaseDrawToken(GrDrawOpUploadToken::AlreadyFlushedToken()) {}
14
onPrepare(GrOpFlushState * state)15 void GrMeshDrawOp::onPrepare(GrOpFlushState* state) {
16 Target target(state, this);
17 this->onPrepareDraws(&target);
18 }
19
init(Target * target,GrPrimitiveType primType,size_t vertexStride,const GrBuffer * indexBuffer,int verticesPerInstance,int indicesPerInstance,int instancesToDraw)20 void* 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
recordDraw(Target * target,const GrGeometryProcessor * gp)46 void GrMeshDrawOp::InstancedHelper::recordDraw(Target* target, const GrGeometryProcessor* gp) {
47 SkASSERT(fMesh.instanceCount());
48 target->draw(gp, fMesh);
49 }
50
init(Target * target,size_t vertexStride,int quadsToDraw)51 void* 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
onExecute(GrOpFlushState * state)62 void 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
draw(const GrGeometryProcessor * gp,const GrMesh & mesh)92 void 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