1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawWriter.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawCommands.h"
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
14*c8dee2aaSAndroid Build Coastguard Worker
DrawWriter(DrawPassCommands::List * commandList,DrawBufferManager * bufferManager)15*c8dee2aaSAndroid Build Coastguard Worker DrawWriter::DrawWriter(DrawPassCommands::List* commandList, DrawBufferManager* bufferManager)
16*c8dee2aaSAndroid Build Coastguard Worker : fCommandList(commandList)
17*c8dee2aaSAndroid Build Coastguard Worker , fManager(bufferManager)
18*c8dee2aaSAndroid Build Coastguard Worker , fPrimitiveType(PrimitiveType::kTriangles)
19*c8dee2aaSAndroid Build Coastguard Worker , fVertexStride(0)
20*c8dee2aaSAndroid Build Coastguard Worker , fInstanceStride(0)
21*c8dee2aaSAndroid Build Coastguard Worker , fVertices()
22*c8dee2aaSAndroid Build Coastguard Worker , fIndices()
23*c8dee2aaSAndroid Build Coastguard Worker , fInstances()
24*c8dee2aaSAndroid Build Coastguard Worker , fTemplateCount(0)
25*c8dee2aaSAndroid Build Coastguard Worker , fPendingCount(0)
26*c8dee2aaSAndroid Build Coastguard Worker , fPendingBase(0)
27*c8dee2aaSAndroid Build Coastguard Worker , fPendingBufferBinds(true) {
28*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(commandList && bufferManager);
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker
setTemplate(BindBufferInfo vertices,BindBufferInfo indices,BindBufferInfo instances,int templateCount)31*c8dee2aaSAndroid Build Coastguard Worker void DrawWriter::setTemplate(BindBufferInfo vertices,
32*c8dee2aaSAndroid Build Coastguard Worker BindBufferInfo indices,
33*c8dee2aaSAndroid Build Coastguard Worker BindBufferInfo instances,
34*c8dee2aaSAndroid Build Coastguard Worker int templateCount) {
35*c8dee2aaSAndroid Build Coastguard Worker if (vertices != fVertices || instances != fInstances || fIndices != indices) {
36*c8dee2aaSAndroid Build Coastguard Worker if (fPendingCount > 0) {
37*c8dee2aaSAndroid Build Coastguard Worker this->flush();
38*c8dee2aaSAndroid Build Coastguard Worker }
39*c8dee2aaSAndroid Build Coastguard Worker
40*c8dee2aaSAndroid Build Coastguard Worker bool willAppendVertices = templateCount == 0;
41*c8dee2aaSAndroid Build Coastguard Worker bool isAppendingVertices = fTemplateCount == 0;
42*c8dee2aaSAndroid Build Coastguard Worker if (willAppendVertices != isAppendingVertices ||
43*c8dee2aaSAndroid Build Coastguard Worker (isAppendingVertices && fVertices != vertices) ||
44*c8dee2aaSAndroid Build Coastguard Worker (!isAppendingVertices && fInstances != instances)) {
45*c8dee2aaSAndroid Build Coastguard Worker // The buffer binding target for appended data is changing, so reset the base offset
46*c8dee2aaSAndroid Build Coastguard Worker fPendingBase = 0;
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard Worker fVertices = vertices;
50*c8dee2aaSAndroid Build Coastguard Worker fInstances = instances;
51*c8dee2aaSAndroid Build Coastguard Worker fIndices = indices;
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker fTemplateCount = templateCount;
54*c8dee2aaSAndroid Build Coastguard Worker
55*c8dee2aaSAndroid Build Coastguard Worker fPendingBufferBinds = true;
56*c8dee2aaSAndroid Build Coastguard Worker } else if ((templateCount >= 0 && templateCount != fTemplateCount) || // vtx or reg. instances
57*c8dee2aaSAndroid Build Coastguard Worker (templateCount < 0 && fTemplateCount >= 0)) { // dynamic index instances
58*c8dee2aaSAndroid Build Coastguard Worker if (fPendingCount > 0) {
59*c8dee2aaSAndroid Build Coastguard Worker this->flush();
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker if ((templateCount == 0) != (fTemplateCount == 0)) {
62*c8dee2aaSAndroid Build Coastguard Worker // Switching from appending vertices to instances, or vice versa, so the pending
63*c8dee2aaSAndroid Build Coastguard Worker // base vertex for appended data is invalid
64*c8dee2aaSAndroid Build Coastguard Worker fPendingBase = 0;
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker fTemplateCount = templateCount;
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fVertices == vertices);
70*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fInstances == instances);
71*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fIndices == indices);
72*c8dee2aaSAndroid Build Coastguard Worker // NOTE: This allows 'fTemplateCount' to update across multiple DynamicInstances as long
73*c8dee2aaSAndroid Build Coastguard Worker // as they have the same vertex and index buffers.
74*c8dee2aaSAndroid Build Coastguard Worker SkASSERT((fTemplateCount < 0) == (templateCount < 0));
75*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTemplateCount < 0 || fTemplateCount == templateCount);
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker
flush()78*c8dee2aaSAndroid Build Coastguard Worker void DrawWriter::flush() {
79*c8dee2aaSAndroid Build Coastguard Worker // If nothing was appended, or the only appended data was through dynamic instances and the
80*c8dee2aaSAndroid Build Coastguard Worker // final vertex count per instance is 0 (-1 in the sign encoded field), nothing should be drawn.
81*c8dee2aaSAndroid Build Coastguard Worker if (fPendingCount == 0 || fTemplateCount == -1) {
82*c8dee2aaSAndroid Build Coastguard Worker return;
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker if (fPendingBufferBinds) {
85*c8dee2aaSAndroid Build Coastguard Worker fCommandList->bindDrawBuffers(fVertices, fInstances, fIndices, {});
86*c8dee2aaSAndroid Build Coastguard Worker fPendingBufferBinds = false;
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker if (fTemplateCount) {
90*c8dee2aaSAndroid Build Coastguard Worker // Instanced drawing
91*c8dee2aaSAndroid Build Coastguard Worker unsigned int realVertexCount;
92*c8dee2aaSAndroid Build Coastguard Worker if (fTemplateCount < 0) {
93*c8dee2aaSAndroid Build Coastguard Worker realVertexCount = -fTemplateCount - 1;
94*c8dee2aaSAndroid Build Coastguard Worker fTemplateCount = -1; // reset to re-accumulate max index account for next flush
95*c8dee2aaSAndroid Build Coastguard Worker } else {
96*c8dee2aaSAndroid Build Coastguard Worker realVertexCount = fTemplateCount;
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker SkASSERT((fPendingBase + fPendingCount)*fInstanceStride <= fInstances.fSize);
100*c8dee2aaSAndroid Build Coastguard Worker if (fIndices) {
101*c8dee2aaSAndroid Build Coastguard Worker // It's not possible to validate that the indices stored in fIndices access only valid
102*c8dee2aaSAndroid Build Coastguard Worker // data within fVertices. Simply vaidate that fIndices holds enough data for the
103*c8dee2aaSAndroid Build Coastguard Worker // vertex count that's drawn.
104*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(realVertexCount*sizeof(uint16_t) <= fIndices.fSize);
105*c8dee2aaSAndroid Build Coastguard Worker fCommandList->drawIndexedInstanced(fPrimitiveType, 0, realVertexCount, 0,
106*c8dee2aaSAndroid Build Coastguard Worker fPendingBase, fPendingCount);
107*c8dee2aaSAndroid Build Coastguard Worker } else {
108*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(realVertexCount*fVertexStride <= fVertices.fSize);
109*c8dee2aaSAndroid Build Coastguard Worker fCommandList->drawInstanced(fPrimitiveType, 0, realVertexCount,
110*c8dee2aaSAndroid Build Coastguard Worker fPendingBase, fPendingCount);
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker } else {
113*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fInstances);
114*c8dee2aaSAndroid Build Coastguard Worker if (fIndices) {
115*c8dee2aaSAndroid Build Coastguard Worker // As before, just validate there is sufficient index data
116*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPendingCount*sizeof(uint16_t) <= fIndices.fSize);
117*c8dee2aaSAndroid Build Coastguard Worker fCommandList->drawIndexed(fPrimitiveType, 0, fPendingCount, fPendingBase);
118*c8dee2aaSAndroid Build Coastguard Worker } else {
119*c8dee2aaSAndroid Build Coastguard Worker SkASSERT((fPendingBase + fPendingCount)*fVertexStride <= fVertices.fSize);
120*c8dee2aaSAndroid Build Coastguard Worker fCommandList->draw(fPrimitiveType, fPendingBase, fPendingCount);
121*c8dee2aaSAndroid Build Coastguard Worker }
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker
124*c8dee2aaSAndroid Build Coastguard Worker fPendingBase += fPendingCount;
125*c8dee2aaSAndroid Build Coastguard Worker fPendingCount = 0;
126*c8dee2aaSAndroid Build Coastguard Worker }
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
129