xref: /aosp_15_r20/external/skia/src/gpu/graphite/DrawWriter.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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