1 /*
2 * Copyright 2022 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/render/VerticesRenderStep.h"
9
10 #include "include/core/SkColor.h"
11 #include "include/core/SkVertices.h"
12 #include "include/private/base/SkAssert.h"
13 #include "include/private/base/SkDebug.h"
14 #include "include/private/base/SkPoint_impl.h"
15 #include "include/private/base/SkSpan_impl.h"
16 #include "include/private/base/SkTo.h"
17 #include "src/base/SkEnumBitMask.h"
18 #include "src/core/SkSLTypeShared.h"
19 #include "src/core/SkVertState.h"
20 #include "src/core/SkVerticesPriv.h"
21 #include "src/gpu/BufferWriter.h"
22 #include "src/gpu/graphite/Attribute.h"
23 #include "src/gpu/graphite/DrawOrder.h"
24 #include "src/gpu/graphite/DrawParams.h"
25 #include "src/gpu/graphite/DrawTypes.h"
26 #include "src/gpu/graphite/DrawWriter.h"
27 #include "src/gpu/graphite/PipelineData.h"
28 #include "src/gpu/graphite/geom/Geometry.h"
29 #include "src/gpu/graphite/geom/Transform.h"
30 #include "src/gpu/graphite/render/CommonDepthStencilSettings.h"
31
32 #include <cstdint>
33
34 namespace skgpu::graphite {
35
36 namespace {
37
38 static constexpr Attribute kPositionAttr =
39 {"position", VertexAttribType::kFloat2, SkSLType::kFloat2};
40 static constexpr Attribute kTexCoordAttr =
41 {"texCoords", VertexAttribType::kFloat2, SkSLType::kFloat2};
42 static constexpr Attribute kColorAttr =
43 {"vertColor", VertexAttribType::kUByte4_norm, SkSLType::kHalf4};
44 static constexpr Attribute kSsboIndexAttr =
45 {"ssboIndices", VertexAttribType::kUInt2, SkSLType::kUInt2};
46
47 static constexpr Attribute kAttributePositionOnly[] =
48 {kPositionAttr, kSsboIndexAttr};
49 static constexpr Attribute kAttributeColor[] =
50 {kPositionAttr, kColorAttr, kSsboIndexAttr};
51 static constexpr Attribute kAttributeTexCoords[] =
52 {kPositionAttr, kTexCoordAttr, kSsboIndexAttr};
53 static constexpr Attribute kAttributeColorAndTexCoords[] =
54 {kPositionAttr, kColorAttr, kTexCoordAttr, kSsboIndexAttr};
55
56 static constexpr SkSpan<const Attribute> kAttributes[4] = {
57 kAttributePositionOnly,
58 kAttributeColor,
59 kAttributeTexCoords,
60 kAttributeColorAndTexCoords,
61 };
62
63 static constexpr Varying kVaryingColor[] =
64 {{"color", SkSLType::kHalf4}};
65
66 static constexpr SkSpan<const Varying> kVaryings[2] = {
67 /*none*/ {},
68 /*color*/ kVaryingColor
69 };
70
variant_id(PrimitiveType type,bool hasColor,bool hasTexCoords)71 RenderStep::RenderStepID variant_id(PrimitiveType type, bool hasColor, bool hasTexCoords) {
72 if (type == PrimitiveType::kTriangles) {
73 if (hasColor) {
74 if (hasTexCoords) {
75 return RenderStep::RenderStepID::kVertices_TrisColorTexCoords;
76 } else {
77 return RenderStep::RenderStepID::kVertices_TrisColor;
78 }
79 } else {
80 if (hasTexCoords) {
81 return RenderStep::RenderStepID::kVertices_TrisTexCoords;
82 } else {
83 return RenderStep::RenderStepID::kVertices_Tris;
84 }
85 }
86 } else {
87 SkASSERT(type == PrimitiveType::kTriangleStrip);
88
89 if (hasColor) {
90 if (hasTexCoords) {
91 return RenderStep::RenderStepID::kVertices_TristripsColorTexCoords;
92 } else {
93 return RenderStep::RenderStepID::kVertices_TristripsColor;
94 }
95 } else {
96 if (hasTexCoords) {
97 return RenderStep::RenderStepID::kVertices_TristripsTexCoords;
98 } else {
99 return RenderStep::RenderStepID::kVertices_Tristrips;
100 }
101 }
102 }
103 }
104
105 } // namespace
106
VerticesRenderStep(PrimitiveType type,bool hasColor,bool hasTexCoords)107 VerticesRenderStep::VerticesRenderStep(PrimitiveType type, bool hasColor, bool hasTexCoords)
108 : RenderStep(variant_id(type, hasColor, hasTexCoords),
109 hasColor ? Flags::kEmitsPrimitiveColor | Flags::kPerformsShading
110 : Flags::kPerformsShading,
111 /*uniforms=*/{{"localToDevice", SkSLType::kFloat4x4},
112 {"depth", SkSLType::kFloat}},
113 type,
114 kDirectDepthGEqualPass,
115 /*vertexAttrs=*/ kAttributes[2*hasTexCoords + hasColor],
116 /*instanceAttrs=*/{},
117 /*varyings=*/ kVaryings[hasColor])
118 , fHasColor(hasColor)
119 , fHasTexCoords(hasTexCoords) {}
120
~VerticesRenderStep()121 VerticesRenderStep::~VerticesRenderStep() {}
122
vertexSkSL() const123 std::string VerticesRenderStep::vertexSkSL() const {
124 if (fHasColor && fHasTexCoords) {
125 return
126 "color = half4(vertColor.bgr * vertColor.a, vertColor.a);\n"
127 "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n"
128 "devPosition.z = depth;\n"
129 "stepLocalCoords = texCoords;\n";
130 } else if (fHasTexCoords) {
131 return
132 "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n"
133 "devPosition.z = depth;\n"
134 "stepLocalCoords = texCoords;\n";
135 } else if (fHasColor) {
136 return
137 "color = half4(vertColor.bgr * vertColor.a, vertColor.a);\n"
138 "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n"
139 "devPosition.z = depth;\n"
140 "stepLocalCoords = position;\n";
141 } else {
142 return
143 "float4 devPosition = localToDevice * float4(position, 0.0, 1.0);\n"
144 "devPosition.z = depth;\n"
145 "stepLocalCoords = position;\n";
146 }
147 }
148
fragmentColorSkSL() const149 const char* VerticesRenderStep::fragmentColorSkSL() const {
150 if (fHasColor) {
151 return "primitiveColor = color;\n";
152 } else {
153 return "";
154 }
155 }
156
writeVertices(DrawWriter * writer,const DrawParams & params,skvx::uint2 ssboIndices) const157 void VerticesRenderStep::writeVertices(DrawWriter* writer,
158 const DrawParams& params,
159 skvx::uint2 ssboIndices) const {
160 SkVerticesPriv info(params.geometry().vertices()->priv());
161 const int vertexCount = info.vertexCount();
162 const int indexCount = info.indexCount();
163 const SkPoint* positions = info.positions();
164 const uint16_t* indices = info.indices();
165 const SkColor* colors = info.colors();
166 const SkPoint* texCoords = info.texCoords();
167
168 // This should always be the case if the Renderer was chosen appropriately, but the vertex
169 // writing loop is set up in such a way that if the shader expects color or tex coords and they
170 // are missing, it will just read 0s, so release builds are safe.
171 SkASSERT(fHasColor == SkToBool(colors));
172 SkASSERT(fHasTexCoords == SkToBool(texCoords));
173
174 // TODO: We could access the writer's DrawBufferManager and upload the SkVertices index buffer
175 // but that would require we manually manage the VertexWriter for interleaving the position,
176 // color, and tex coord arrays together. This wouldn't be so bad if we let ::Vertices() take
177 // a CPU index buffer that indexes into the accumulated vertex data (and handles offsetting for
178 // merged drawIndexed calls), or if we could bind multiple attribute sources and copy the
179 // position/color/texCoord data separately in bulk w/o using an Appender.
180 DrawWriter::Vertices verts{*writer};
181 verts.reserve(indices ? indexCount : vertexCount);
182
183 VertState state(vertexCount, indices, indexCount);
184 VertState::Proc vertProc = state.chooseProc(info.mode());
185 while (vertProc(&state)) {
186 verts.append(3) << positions[state.f0]
187 << VertexWriter::If(fHasColor, colors ? colors[state.f0]
188 : SK_ColorTRANSPARENT)
189 << VertexWriter::If(fHasTexCoords, texCoords ? texCoords[state.f0]
190 : SkPoint{0.f, 0.f})
191 << ssboIndices
192 << positions[state.f1]
193 << VertexWriter::If(fHasColor, colors ? colors[state.f1]
194 : SK_ColorTRANSPARENT)
195 << VertexWriter::If(fHasTexCoords, texCoords ? texCoords[state.f1]
196 : SkPoint{0.f, 0.f})
197 << ssboIndices
198 << positions[state.f2]
199 << VertexWriter::If(fHasColor, colors ? colors[state.f2]
200 : SK_ColorTRANSPARENT)
201 << VertexWriter::If(fHasTexCoords, texCoords ? texCoords[state.f2]
202 : SkPoint{0.f, 0.f})
203 << ssboIndices;
204 }
205 }
206
writeUniformsAndTextures(const DrawParams & params,PipelineDataGatherer * gatherer) const207 void VerticesRenderStep::writeUniformsAndTextures(const DrawParams& params,
208 PipelineDataGatherer* gatherer) const {
209 // Vertices are transformed on the GPU. Store PaintDepth as a uniform to avoid copying the
210 // same depth for each vertex.
211 SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, this->uniforms());)
212 gatherer->write(params.transform().matrix());
213 gatherer->write(params.order().depthAsFloat());
214 }
215
216 } // namespace skgpu::graphite
217