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