Home | History | Annotate | Download | only in ops
      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