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