aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ops/GrMeshDrawOp.cpp
blob: 92571d6c709ca9f606aaa58233e79116e1865ec1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
#include "GrResourceProvider.h"

GrMeshDrawOp::GrMeshDrawOp(uint32_t classID)
    : INHERITED(classID), fBaseDrawToken(GrDrawOpUploadToken::AlreadyFlushedToken()) {}

void GrMeshDrawOp::onPrepare(GrOpFlushState* state) {
    Target target(state, this);
    this->onPrepareDraws(&target);
}

void* GrMeshDrawOp::PatternHelper::init(Target* target, GrPrimitiveType primType,
                                          size_t vertexStride, const GrBuffer* indexBuffer,
                                          int verticesPerRepetition, int indicesPerRepetition,
                                          int repeatCount) {
    SkASSERT(target);
    if (!indexBuffer) {
        return nullptr;
    }
    const GrBuffer* vertexBuffer;
    int firstVertex;
    int vertexCount = verticesPerRepetition * repeatCount;
    void* vertices =
            target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex);
    if (!vertices) {
        SkDebugf("Vertices could not be allocated for instanced rendering.");
        return nullptr;
    }
    SkASSERT(vertexBuffer);
    size_t ibSize = indexBuffer->gpuMemorySize();
    int maxRepetitions = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerRepetition));

    fMesh.fPrimitiveType = primType;
    fMesh.fIndexBuffer.reset(indexBuffer);
    fMesh.fIndexCount = indicesPerRepetition;
    fMesh.fBaseIndex = 0;
    fMesh.fVertexBuffer.reset(vertexBuffer);
    fMesh.fVertexCount = verticesPerRepetition;
    fMesh.fBaseVertex = firstVertex;
    fMesh.fPatternRepeatCount = repeatCount;
    fMesh.fMaxPatternRepetitionsInIndexBuffer = maxRepetitions;
    return vertices;
}

void GrMeshDrawOp::PatternHelper::recordDraw(Target* target, const GrGeometryProcessor* gp,
                                               const GrPipeline* pipeline) {
    target->draw(gp, pipeline, fMesh);
}

void* GrMeshDrawOp::QuadHelper::init(Target* target, size_t vertexStride, int quadsToDraw) {
    sk_sp<const GrBuffer> quadIndexBuffer(target->resourceProvider()->refQuadIndexBuffer());
    if (!quadIndexBuffer) {
        SkDebugf("Could not get quad index buffer.");
        return nullptr;
    }
    return this->INHERITED::init(target, kTriangles_GrPrimitiveType, vertexStride,
                                 quadIndexBuffer.get(), kVerticesPerQuad, kIndicesPerQuad,
                                 quadsToDraw);
}

void GrMeshDrawOp::onExecute(GrOpFlushState* state) {
    SkASSERT(!state->drawOpArgs().fAppliedClip);
    SkASSERT(!state->drawOpArgs().fDstTexture.texture());
    int currUploadIdx = 0;
    int currMeshIdx = 0;

    SkASSERT(fQueuedDraws.empty() || fBaseDrawToken == state->nextTokenToFlush());

    for (int currDrawIdx = 0; currDrawIdx < fQueuedDraws.count(); ++currDrawIdx) {
        GrDrawOpUploadToken drawToken = state->nextTokenToFlush();
        while (currUploadIdx < fInlineUploads.count() &&
               fInlineUploads[currUploadIdx].fUploadBeforeToken == drawToken) {
            state->commandBuffer()->inlineUpload(state, fInlineUploads[currUploadIdx++].fUpload,
                                                 state->drawOpArgs().fRenderTarget);
        }
        const QueuedDraw& draw = fQueuedDraws[currDrawIdx];
        SkASSERT(draw.fPipeline->getRenderTarget() == state->drawOpArgs().fRenderTarget);
        state->commandBuffer()->draw(*draw.fPipeline, *draw.fGeometryProcessor.get(),
                                     fMeshes.begin() + currMeshIdx, draw.fMeshCnt, this->bounds());
        currMeshIdx += draw.fMeshCnt;
        state->flushToken();
    }
    SkASSERT(currUploadIdx == fInlineUploads.count());
    SkASSERT(currMeshIdx == fMeshes.count());
    fQueuedDraws.reset();
    fInlineUploads.reset();
}

//////////////////////////////////////////////////////////////////////////////

void GrMeshDrawOp::Target::draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline,
                                const GrMesh& mesh) {
    GrMeshDrawOp* op = this->meshDrawOp();
    op->fMeshes.push_back(mesh);
    if (!op->fQueuedDraws.empty()) {
        // If the last draw shares a geometry processor and pipeline and there are no intervening
        // uploads, add this mesh to it.
        GrLegacyMeshDrawOp::QueuedDraw& lastDraw = op->fQueuedDraws.back();
        if (lastDraw.fGeometryProcessor == gp && lastDraw.fPipeline == pipeline &&
            (op->fInlineUploads.empty() ||
             op->fInlineUploads.back().fUploadBeforeToken != this->nextDrawToken())) {
            ++lastDraw.fMeshCnt;
            return;
        }
    }
    GrLegacyMeshDrawOp::QueuedDraw& draw = op->fQueuedDraws.push_back();
    GrDrawOpUploadToken token = this->state()->issueDrawToken();
    draw.fGeometryProcessor.reset(gp);
    draw.fPipeline = pipeline;
    draw.fMeshCnt = 1;
    if (op->fQueuedDraws.count() == 1) {
        op->fBaseDrawToken = token;
    }
}