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 "GrMeshDrawOp.h"
      9 #include "GrOpFlushState.h"
     10 #include "GrResourceProvider.h"
     11 
     12 GrMeshDrawOp::GrMeshDrawOp(uint32_t classID)
     13     : INHERITED(classID), fBaseDrawToken(GrDrawOpUploadToken::AlreadyFlushedToken()) {}
     14 
     15 void GrMeshDrawOp::onPrepare(GrOpFlushState* state) {
     16     Target target(state, this);
     17     this->onPrepareDraws(&target);
     18 }
     19 
     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 
     46 void GrMeshDrawOp::InstancedHelper::recordDraw(Target* target, const GrGeometryProcessor* gp) {
     47     SkASSERT(fMesh.instanceCount());
     48     target->draw(gp, fMesh);
     49 }
     50 
     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 
     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 
     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