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