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 #ifndef skgpu_graphite_Renderer_DEFINED
9 #define skgpu_graphite_Renderer_DEFINED
10
11 #include "include/core/SkSpan.h"
12 #include "include/core/SkString.h"
13 #include "include/core/SkTypes.h"
14 #include "include/gpu/graphite/GraphiteTypes.h"
15 #include "src/base/SkEnumBitMask.h"
16 #include "src/base/SkVx.h"
17 #include "src/gpu/graphite/Attribute.h"
18 #include "src/gpu/graphite/DrawTypes.h"
19 #include "src/gpu/graphite/ResourceTypes.h"
20 #include "src/gpu/graphite/Uniform.h"
21
22 #include <array>
23 #include <initializer_list>
24 #include <string>
25 #include <string_view>
26 #include <vector>
27
28 enum class SkPathFillType;
29
30 namespace skgpu { enum class MaskFormat; }
31
32 namespace skgpu::graphite {
33
34 class DrawWriter;
35 class DrawParams;
36 class PipelineDataGatherer;
37 class Rect;
38 class ResourceProvider;
39 class TextureDataBlock;
40 class Transform;
41
42 struct ResourceBindingRequirements;
43
44 enum class Coverage { kNone, kSingleChannel, kLCD };
45
46 // If this list is modified in any way, please increment the
47 // RenderStep::kRenderStepIDVersion value. The enum values generated from this
48 // list are serialized and the kRenderStepIDVersion value is the signal to
49 // abandon older serialized data.
50 #define SKGPU_RENDERSTEP_TYPES(M1, M2) \
51 M1(Invalid) \
52 M1(CircularArc) \
53 M1(AnalyticRRect) \
54 M1(AnalyticBlur) \
55 M1(PerEdgeAAQuad) \
56 M2(CoverBounds, NonAAFill) \
57 M2(CoverBounds, RegularCover) \
58 M2(CoverBounds, InverseCover) \
59 M1(CoverageMask) \
60 M2(BitmapText, Mask) \
61 M2(BitmapText, LCD) \
62 M2(BitmapText, Color) \
63 M2(MiddleOutFan, EvenOdd) \
64 M2(MiddleOutFan, Winding) \
65 M1(SDFTextLCD) \
66 M1(SDFText) \
67 M2(TessellateCurves, EvenOdd) \
68 M2(TessellateCurves, Winding) \
69 M1(TessellateStrokes) \
70 M2(TessellateWedges, Convex) \
71 M2(TessellateWedges, EvenOdd) \
72 M2(TessellateWedges, Winding) \
73 M2(Vertices, Tris) \
74 M2(Vertices, TrisColor) \
75 M2(Vertices, TrisTexCoords) \
76 M2(Vertices, TrisColorTexCoords) \
77 M2(Vertices, Tristrips) \
78 M2(Vertices, TristripsColor) \
79 M2(Vertices, TristripsTexCoords) \
80 M2(Vertices, TristripsColorTexCoords)
81
82 /**
83 * The actual technique for rasterizing a high-level draw recorded in a DrawList is handled by a
84 * specific Renderer. Each technique has an associated singleton Renderer that decomposes the
85 * technique into a series of RenderSteps that must be executed in the specified order for the draw.
86 * However, the RenderStep executions for multiple draws can be re-arranged so batches of each
87 * step can be performed in a larger GPU operation. This re-arranging relies on accurate
88 * determination of the DisjointStencilIndex for each draw so that stencil steps are not corrupted
89 * by another draw before its cover step is executed. It also relies on the CompressedPaintersOrder
90 * for each draw to ensure steps are not re-arranged in a way that violates the original draw order.
91 *
92 * Renderer itself is non-virtual since it simply has to point to a list of RenderSteps. RenderSteps
93 * on the other hand are virtual implement the technique specific functionality. It is entirely
94 * possible for certain types of steps, e.g. a bounding box cover, to be re-used across different
95 * Renderers even if the preceeding steps were different.
96 *
97 * All Renderers are accessed through the SharedContext's RendererProvider.
98 */
99 class RenderStep {
100 public:
101 virtual ~RenderStep() = default;
102
103 // The DrawWriter is configured with the vertex and instance strides of the RenderStep, and its
104 // primitive type. The recorded draws will be executed with a graphics pipeline compatible with
105 // this RenderStep.
106 virtual void writeVertices(DrawWriter*, const DrawParams&, skvx::uint2 ssboIndices) const = 0;
107
108 // Write out the uniform values (aligned for the layout), textures, and samplers. The uniform
109 // values will be de-duplicated across all draws using the RenderStep before uploading to the
110 // GPU, but it can be assumed the uniforms will be bound before the draws recorded in
111 // 'writeVertices' are executed.
112 virtual void writeUniformsAndTextures(const DrawParams&, PipelineDataGatherer*) const = 0;
113
114 // Returns the body of a vertex function, which must define a float4 devPosition variable and
115 // must write to an already-defined float2 stepLocalCoords variable. This will be automatically
116 // set to a varying for the fragment shader if the paint requires local coords. This SkSL has
117 // access to the variables declared by vertexAttributes(), instanceAttributes(), and uniforms().
118 // The 'devPosition' variable's z must store the PaintDepth normalized to a float from [0, 1],
119 // for each processed draw although the RenderStep can choose to upload it in any manner.
120 //
121 // NOTE: The above contract is mainly so that the entire SkSL program can be created by just str
122 // concatenating struct definitions generated from the RenderStep and paint Combination
123 // and then including the function bodies returned here.
124 virtual std::string vertexSkSL() const = 0;
125
126 // Emits code to set up textures and samplers. Should only be defined if hasTextures is true.
texturesAndSamplersSkSL(const ResourceBindingRequirements &,int * nextBindingIndex)127 virtual std::string texturesAndSamplersSkSL(const ResourceBindingRequirements&,
128 int* nextBindingIndex) const {
129 return "";
130 }
131
132 // Emits code to set up coverage value. Should only be defined if overridesCoverage is true.
133 // When implemented the returned SkSL fragment should write its coverage into a
134 // 'half4 outputCoverage' variable (defined in the calling code) with the actual
135 // coverage splatted out into all four channels.
fragmentCoverageSkSL()136 virtual const char* fragmentCoverageSkSL() const { return ""; }
137
138 // Emits code to set up a primitive color value. Should only be defined if emitsPrimitiveColor
139 // is true. When implemented, the returned SkSL fragment should write its color into a
140 // 'half4 primitiveColor' variable (defined in the calling code).
fragmentColorSkSL()141 virtual const char* fragmentColorSkSL() const { return ""; }
142
143 // Returns a name formatted as "Subclass[variant]", where "Subclass" matches the C++ class name
144 // and variant is a unique term describing instance's specific configuration.
name()145 const char* name() const { return RenderStepName(fRenderStepID); }
146
requiresMSAA()147 bool requiresMSAA() const { return SkToBool(fFlags & Flags::kRequiresMSAA); }
performsShading()148 bool performsShading() const { return SkToBool(fFlags & Flags::kPerformsShading); }
hasTextures()149 bool hasTextures() const { return SkToBool(fFlags & Flags::kHasTextures); }
emitsPrimitiveColor()150 bool emitsPrimitiveColor() const { return SkToBool(fFlags & Flags::kEmitsPrimitiveColor); }
outsetBoundsForAA()151 bool outsetBoundsForAA() const { return SkToBool(fFlags & Flags::kOutsetBoundsForAA); }
useNonAAInnerFill()152 bool useNonAAInnerFill() const { return SkToBool(fFlags & Flags::kUseNonAAInnerFill); }
153
coverage()154 Coverage coverage() const { return RenderStep::GetCoverage(fFlags); }
155
primitiveType()156 PrimitiveType primitiveType() const { return fPrimitiveType; }
vertexStride()157 size_t vertexStride() const { return fVertexStride; }
instanceStride()158 size_t instanceStride() const { return fInstanceStride; }
159
numUniforms()160 size_t numUniforms() const { return fUniforms.size(); }
numVertexAttributes()161 size_t numVertexAttributes() const { return fVertexAttrs.size(); }
numInstanceAttributes()162 size_t numInstanceAttributes() const { return fInstanceAttrs.size(); }
163
164 // Name of an attribute containing both render step and shading SSBO indices, if used.
ssboIndicesAttribute()165 static const char* ssboIndicesAttribute() { return "ssboIndices"; }
166
167 // Name of a varying to pass SSBO indices to fragment shader. Both render step and shading
168 // indices are passed, because render step uniforms are sometimes used for coverage.
ssboIndicesVarying()169 static const char* ssboIndicesVarying() { return "ssboIndicesVar"; }
170
171 // The uniforms of a RenderStep are bound to the kRenderStep slot, the rest of the pipeline
172 // may still use uniforms bound to other slots.
uniforms()173 SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); }
vertexAttributes()174 SkSpan<const Attribute> vertexAttributes() const { return SkSpan(fVertexAttrs); }
instanceAttributes()175 SkSpan<const Attribute> instanceAttributes() const { return SkSpan(fInstanceAttrs); }
varyings()176 SkSpan<const Varying> varyings() const { return SkSpan(fVaryings); }
177
depthStencilSettings()178 const DepthStencilSettings& depthStencilSettings() const { return fDepthStencilSettings; }
179
depthStencilFlags()180 SkEnumBitMask<DepthStencilFlags> depthStencilFlags() const {
181 return (fDepthStencilSettings.fStencilTestEnabled
182 ? DepthStencilFlags::kStencil : DepthStencilFlags::kNone) |
183 (fDepthStencilSettings.fDepthTestEnabled || fDepthStencilSettings.fDepthWriteEnabled
184 ? DepthStencilFlags::kDepth : DepthStencilFlags::kNone);
185 }
186
187 static const int kRenderStepIDVersion = 1;
188
189 #define ENUM1(BaseName) k##BaseName,
190 #define ENUM2(BaseName, VariantName) k##BaseName##_##VariantName,
191 enum class RenderStepID : uint32_t {
192 SKGPU_RENDERSTEP_TYPES(ENUM1, ENUM2)
193
194 kLast = kVertices_TristripsColorTexCoords,
195 };
196 #undef ENUM1
197 #undef ENUM2
198 static const int kNumRenderSteps = static_cast<int>(RenderStepID::kLast) + 1;
199
renderStepID()200 RenderStepID renderStepID() const { return fRenderStepID; }
201
202 static const char* RenderStepName(RenderStepID);
203 static bool IsValidRenderStepID(uint32_t);
204
205 // TODO: Actual API to do things
206 // 6. Some Renderers benefit from being able to share vertices between RenderSteps. Must find a
207 // way to support that. It may mean that RenderSteps get state per draw.
208 // - Does Renderer make RenderStepFactories that create steps for each DrawList::Draw?
209 // - Does DrawList->DrawPass conversion build a separate array of blind data that the
210 // stateless Renderstep can refer to for {draw,step} pairs?
211 // - Does each DrawList::Draw have extra space (e.g. 8 bytes) that steps can cache data in?
212 protected:
213 enum class Flags : unsigned {
214 kNone = 0b00000000,
215 kRequiresMSAA = 0b00000001,
216 kPerformsShading = 0b00000010,
217 kHasTextures = 0b00000100,
218 kEmitsCoverage = 0b00001000,
219 kLCDCoverage = 0b00010000,
220 kEmitsPrimitiveColor = 0b00100000,
221 kOutsetBoundsForAA = 0b01000000,
222 kUseNonAAInnerFill = 0b10000000,
223 };
224 SK_DECL_BITMASK_OPS_FRIENDS(Flags)
225
226 // While RenderStep does not define the full program that's run for a draw, it defines the
227 // entire vertex layout of the pipeline. This is not allowed to change, so can be provided to
228 // the RenderStep constructor by subclasses.
229 RenderStep(RenderStepID renderStepID,
230 SkEnumBitMask<Flags> flags,
231 std::initializer_list<Uniform> uniforms,
232 PrimitiveType primitiveType,
233 DepthStencilSettings depthStencilSettings,
234 SkSpan<const Attribute> vertexAttrs,
235 SkSpan<const Attribute> instanceAttrs,
236 SkSpan<const Varying> varyings = {});
237
238 private:
239 friend class Renderer; // for Flags
240
241 // Cannot copy or move
242 RenderStep(const RenderStep&) = delete;
243 RenderStep(RenderStep&&) = delete;
244
245 static Coverage GetCoverage(SkEnumBitMask<Flags>);
246
247 RenderStepID fRenderStepID;
248 SkEnumBitMask<Flags> fFlags;
249 PrimitiveType fPrimitiveType;
250
251 DepthStencilSettings fDepthStencilSettings;
252
253 // TODO: When we always use C++17 for builds, we should be able to just let subclasses declare
254 // constexpr arrays and point to those, but we need explicit storage for C++14.
255 // Alternatively, if we imposed a max attr count, similar to Renderer's num render steps, we
256 // could just have this be std::array and keep all attributes inline with the RenderStep memory.
257 // On the other hand, the attributes are only needed when creating a new pipeline so it's not
258 // that performance sensitive.
259 std::vector<Uniform> fUniforms;
260 std::vector<Attribute> fVertexAttrs;
261 std::vector<Attribute> fInstanceAttrs;
262 std::vector<Varying> fVaryings;
263
264 size_t fVertexStride; // derived from vertex attribute set
265 size_t fInstanceStride; // derived from instance attribute set
266 };
SK_MAKE_BITMASK_OPS(RenderStep::Flags)267 SK_MAKE_BITMASK_OPS(RenderStep::Flags)
268
269 class Renderer {
270 using StepFlags = RenderStep::Flags;
271 public:
272 // The maximum number of render steps that any Renderer is allowed to have.
273 static constexpr int kMaxRenderSteps = 4;
274
275 const RenderStep& step(int i) const {
276 SkASSERT(i >= 0 && i < fStepCount);
277 return *fSteps[i];
278 }
279 SkSpan<const RenderStep* const> steps() const {
280 SkASSERT(fStepCount > 0); // steps() should only be called on valid Renderers.
281 return {fSteps.data(), static_cast<size_t>(fStepCount) };
282 }
283
284 const char* name() const { return fName.c_str(); }
285 DrawTypeFlags drawTypes() const { return fDrawTypes; }
286 int numRenderSteps() const { return fStepCount; }
287
288 bool requiresMSAA() const {
289 return SkToBool(fStepFlags & StepFlags::kRequiresMSAA);
290 }
291 bool emitsPrimitiveColor() const {
292 return SkToBool(fStepFlags & StepFlags::kEmitsPrimitiveColor);
293 }
294 bool outsetBoundsForAA() const {
295 return SkToBool(fStepFlags & StepFlags::kOutsetBoundsForAA);
296 }
297 bool useNonAAInnerFill() const {
298 return SkToBool(fStepFlags & StepFlags::kUseNonAAInnerFill);
299 }
300
301 SkEnumBitMask<DepthStencilFlags> depthStencilFlags() const { return fDepthStencilFlags; }
302
303 Coverage coverage() const { return RenderStep::GetCoverage(fStepFlags); }
304
305 private:
306 friend class RendererProvider; // for ctors
307
308 // Max render steps is 4, so just spell the options out for now...
309 Renderer(std::string_view name, DrawTypeFlags drawTypes, const RenderStep* s1)
310 : Renderer(name, drawTypes, std::array<const RenderStep*, 1>{s1}) {}
311
312 Renderer(std::string_view name, DrawTypeFlags drawTypes,
313 const RenderStep* s1, const RenderStep* s2)
314 : Renderer(name, drawTypes, std::array<const RenderStep*, 2>{s1, s2}) {}
315
316 Renderer(std::string_view name, DrawTypeFlags drawTypes,
317 const RenderStep* s1, const RenderStep* s2, const RenderStep* s3)
318 : Renderer(name, drawTypes, std::array<const RenderStep*, 3>{s1, s2, s3}) {}
319
320 Renderer(std::string_view name, DrawTypeFlags drawTypes,
321 const RenderStep* s1, const RenderStep* s2, const RenderStep* s3, const RenderStep* s4)
322 : Renderer(name, drawTypes, std::array<const RenderStep*, 4>{s1, s2, s3, s4}) {}
323
324 template<size_t N>
325 Renderer(std::string_view name, DrawTypeFlags drawTypes, std::array<const RenderStep*, N> steps)
326 : fName(name)
327 , fDrawTypes(drawTypes)
328 , fStepCount(SkTo<int>(N)) {
329 static_assert(N <= kMaxRenderSteps);
330 for (int i = 0 ; i < fStepCount; ++i) {
331 fSteps[i] = steps[i];
332 fStepFlags |= fSteps[i]->fFlags;
333 fDepthStencilFlags |= fSteps[i]->depthStencilFlags();
334 }
335 // At least one step needs to actually shade.
336 SkASSERT(fStepFlags & RenderStep::Flags::kPerformsShading);
337 // A render step using non-AA inner fills with a second draw should not also be part of a
338 // multi-step renderer (to keep reasoning simple) and must use the GREATER depth test.
339 SkASSERT(!this->useNonAAInnerFill() ||
340 (fStepCount == 1 && fSteps[0]->depthStencilSettings().fDepthTestEnabled &&
341 fSteps[0]->depthStencilSettings().fDepthCompareOp == CompareOp::kGreater));
342 }
343
344 // For RendererProvider to manage initialization; it will never expose a Renderer that is only
345 // default-initialized and not replaced because it's algorithm is disabled by caps/options.
346 Renderer() : fSteps(), fName(""), fStepCount(0) {}
347 Renderer& operator=(Renderer&&) = default;
348
349 std::array<const RenderStep*, kMaxRenderSteps> fSteps;
350 std::string fName;
351 DrawTypeFlags fDrawTypes = DrawTypeFlags::kNone;
352 int fStepCount;
353
354 SkEnumBitMask<StepFlags> fStepFlags = StepFlags::kNone;
355 SkEnumBitMask<DepthStencilFlags> fDepthStencilFlags = DepthStencilFlags::kNone;
356 };
357
358 } // namespace skgpu::graphite
359
360 #endif // skgpu_graphite_Renderer_DEFINED
361