• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GrMeshDrawOp(uint32_t classID)13 GrMeshDrawOp::GrMeshDrawOp(uint32_t classID)
14     : INHERITED(classID), fBaseDrawToken(GrDrawOpUploadToken::AlreadyFlushedToken()) {}
15 
onPrepare(GrOpFlushState * state)16 void GrMeshDrawOp::onPrepare(GrOpFlushState* state) {
17     Target target(state, this);
18     this->onPrepareDraws(&target);
19 }
20 
init(Target * target,size_t vertexStride,const GrBuffer * indexBuffer,int verticesPerRepetition,int indicesPerRepetition,int repeatCount)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 
recordDraw(Target * target,const GrGeometryProcessor * gp,const GrPipeline * pipeline)47 void GrMeshDrawOp::PatternHelper::recordDraw(Target* target, const GrGeometryProcessor* gp,
48                                              const GrPipeline* pipeline) {
49     target->draw(gp, pipeline, fMesh);
50 }
51 
init(Target * target,size_t vertexStride,int quadsToDraw)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 
onExecute(GrOpFlushState * state)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 
draw(const GrGeometryProcessor * gp,const GrPipeline * pipeline,const GrMesh & mesh)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