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