Flutter Engine
The Flutter Engine
Renderer.h
Go to the documentation of this file.
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"
15#include "src/base/SkVx.h"
20
21#include <array>
22#include <initializer_list>
23#include <string>
24#include <string_view>
25#include <vector>
26
27enum class SkPathFillType;
28
29namespace skgpu { enum class MaskFormat; }
30
31namespace skgpu::graphite {
32
33class DrawWriter;
34class DrawParams;
35class PipelineDataGatherer;
36class Rect;
38class TextureDataBlock;
39class Transform;
40
41struct ResourceBindingRequirements;
42
44
45struct Varying {
46 const char* fName;
48 // TODO: add modifier (e.g., flat and noperspective) support
49};
50
51/**
52 * The actual technique for rasterizing a high-level draw recorded in a DrawList is handled by a
53 * specific Renderer. Each technique has an associated singleton Renderer that decomposes the
54 * technique into a series of RenderSteps that must be executed in the specified order for the draw.
55 * However, the RenderStep executions for multiple draws can be re-arranged so batches of each
56 * step can be performed in a larger GPU operation. This re-arranging relies on accurate
57 * determination of the DisjointStencilIndex for each draw so that stencil steps are not corrupted
58 * by another draw before its cover step is executed. It also relies on the CompressedPaintersOrder
59 * for each draw to ensure steps are not re-arranged in a way that violates the original draw order.
60 *
61 * Renderer itself is non-virtual since it simply has to point to a list of RenderSteps. RenderSteps
62 * on the other hand are virtual implement the technique specific functionality. It is entirely
63 * possible for certain types of steps, e.g. a bounding box cover, to be re-used across different
64 * Renderers even if the preceeding steps were different.
65 *
66 * All Renderers are accessed through the SharedContext's RendererProvider.
67 */
69public:
70 virtual ~RenderStep() = default;
71
72 // The DrawWriter is configured with the vertex and instance strides of the RenderStep, and its
73 // primitive type. The recorded draws will be executed with a graphics pipeline compatible with
74 // this RenderStep.
75 virtual void writeVertices(DrawWriter*, const DrawParams&, skvx::ushort2 ssboIndices) const = 0;
76
77 // Write out the uniform values (aligned for the layout), textures, and samplers. The uniform
78 // values will be de-duplicated across all draws using the RenderStep before uploading to the
79 // GPU, but it can be assumed the uniforms will be bound before the draws recorded in
80 // 'writeVertices' are executed.
82
83 // Returns the body of a vertex function, which must define a float4 devPosition variable and
84 // must write to an already-defined float2 stepLocalCoords variable. This will be automatically
85 // set to a varying for the fragment shader if the paint requires local coords. This SkSL has
86 // access to the variables declared by vertexAttributes(), instanceAttributes(), and uniforms().
87 // The 'devPosition' variable's z must store the PaintDepth normalized to a float from [0, 1],
88 // for each processed draw although the RenderStep can choose to upload it in any manner.
89 //
90 // NOTE: The above contract is mainly so that the entire SkSL program can be created by just str
91 // concatenating struct definitions generated from the RenderStep and paint Combination
92 // and then including the function bodies returned here.
93 virtual std::string vertexSkSL() const = 0;
94
95 // Emits code to set up textures and samplers. Should only be defined if hasTextures is true.
97 int* nextBindingIndex) const {
98 return R"()";
99 }
100
101 // Emits code to set up coverage value. Should only be defined if overridesCoverage is true.
102 // When implemented the returned SkSL fragment should write its coverage into a
103 // 'half4 outputCoverage' variable (defined in the calling code) with the actual
104 // coverage splatted out into all four channels.
105 virtual const char* fragmentCoverageSkSL() const { return R"()"; }
106
107 // Emits code to set up a primitive color value. Should only be defined if emitsPrimitiveColor
108 // is true. When implemented, the returned SkSL fragment should write its color into a
109 // 'half4 primitiveColor' variable (defined in the calling code).
110 virtual const char* fragmentColorSkSL() const { return R"()"; }
111
112 uint32_t uniqueID() const { return fUniqueID; }
113
114 // Returns a name formatted as "Subclass[variant]", where "Subclass" matches the C++ class name
115 // and variant is a unique term describing instance's specific configuration.
116 const char* name() const { return fName.c_str(); }
117
118 bool requiresMSAA() const { return SkToBool(fFlags & Flags::kRequiresMSAA); }
119 bool performsShading() const { return SkToBool(fFlags & Flags::kPerformsShading); }
120 bool hasTextures() const { return SkToBool(fFlags & Flags::kHasTextures); }
122 bool outsetBoundsForAA() const { return SkToBool(fFlags & Flags::kOutsetBoundsForAA); }
123
124 Coverage coverage() const { return RenderStep::GetCoverage(fFlags); }
125
126 PrimitiveType primitiveType() const { return fPrimitiveType; }
127 size_t vertexStride() const { return fVertexStride; }
128 size_t instanceStride() const { return fInstanceStride; }
129
130 size_t numUniforms() const { return fUniforms.size(); }
131 size_t numVertexAttributes() const { return fVertexAttrs.size(); }
132 size_t numInstanceAttributes() const { return fInstanceAttrs.size(); }
133
134 // Name of an attribute containing both render step and shading SSBO indices, if used.
135 static const char* ssboIndicesAttribute() { return "ssboIndices"; }
136
137 // Name of a varying to pass SSBO indices to fragment shader. Both render step and shading
138 // indices are passed, because render step uniforms are sometimes used for coverage.
139 static const char* ssboIndicesVarying() { return "ssboIndicesVar"; }
140
141 // The uniforms of a RenderStep are bound to the kRenderStep slot, the rest of the pipeline
142 // may still use uniforms bound to other slots.
143 SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); }
144 SkSpan<const Attribute> vertexAttributes() const { return SkSpan(fVertexAttrs); }
145 SkSpan<const Attribute> instanceAttributes() const { return SkSpan(fInstanceAttrs); }
146 SkSpan<const Varying> varyings() const { return SkSpan(fVaryings); }
147
148 const DepthStencilSettings& depthStencilSettings() const { return fDepthStencilSettings; }
149
151 return (fDepthStencilSettings.fStencilTestEnabled
153 (fDepthStencilSettings.fDepthTestEnabled || fDepthStencilSettings.fDepthWriteEnabled
155 }
156
157 // TODO: Actual API to do things
158 // 6. Some Renderers benefit from being able to share vertices between RenderSteps. Must find a
159 // way to support that. It may mean that RenderSteps get state per draw.
160 // - Does Renderer make RenderStepFactories that create steps for each DrawList::Draw?
161 // - Does DrawList->DrawPass conversion build a separate array of blind data that the
162 // stateless Renderstep can refer to for {draw,step} pairs?
163 // - Does each DrawList::Draw have extra space (e.g. 8 bytes) that steps can cache data in?
164protected:
165 enum class Flags : unsigned {
166 kNone = 0b0000000,
167 kRequiresMSAA = 0b0000001,
168 kPerformsShading = 0b0000010,
169 kHasTextures = 0b0000100,
170 kEmitsCoverage = 0b0001000,
171 kLCDCoverage = 0b0010000,
172 kEmitsPrimitiveColor = 0b0100000,
173 kOutsetBoundsForAA = 0b1000000,
174 };
176
177 // While RenderStep does not define the full program that's run for a draw, it defines the
178 // entire vertex layout of the pipeline. This is not allowed to change, so can be provided to
179 // the RenderStep constructor by subclasses.
180 RenderStep(std::string_view className,
181 std::string_view variantName,
183 std::initializer_list<Uniform> uniforms,
186 SkSpan<const Attribute> vertexAttrs,
187 SkSpan<const Attribute> instanceAttrs,
189
190private:
191 friend class Renderer; // for Flags
192
193 // Cannot copy or move
194 RenderStep(const RenderStep&) = delete;
195 RenderStep(RenderStep&&) = delete;
196
197 static Coverage GetCoverage(SkEnumBitMask<Flags>);
198
199 uint32_t fUniqueID;
201 PrimitiveType fPrimitiveType;
202
203 DepthStencilSettings fDepthStencilSettings;
204
205 // TODO: When we always use C++17 for builds, we should be able to just let subclasses declare
206 // constexpr arrays and point to those, but we need explicit storage for C++14.
207 // Alternatively, if we imposed a max attr count, similar to Renderer's num render steps, we
208 // could just have this be std::array and keep all attributes inline with the RenderStep memory.
209 // On the other hand, the attributes are only needed when creating a new pipeline so it's not
210 // that performance sensitive.
211 std::vector<Uniform> fUniforms;
212 std::vector<Attribute> fVertexAttrs;
213 std::vector<Attribute> fInstanceAttrs;
214 std::vector<Varying> fVaryings;
215
216 size_t fVertexStride; // derived from vertex attribute set
217 size_t fInstanceStride; // derived from instance attribute set
218
219 std::string fName;
220};
222
223class Renderer {
225public:
226 // The maximum number of render steps that any Renderer is allowed to have.
227 static constexpr int kMaxRenderSteps = 4;
228
229 const RenderStep& step(int i) const {
230 SkASSERT(i >= 0 && i < fStepCount);
231 return *fSteps[i];
232 }
234 SkASSERT(fStepCount > 0); // steps() should only be called on valid Renderers.
235 return {fSteps.data(), static_cast<size_t>(fStepCount) };
236 }
237
238 const char* name() const { return fName.c_str(); }
239 DrawTypeFlags drawTypes() const { return fDrawTypes; }
240 int numRenderSteps() const { return fStepCount; }
241
242 bool requiresMSAA() const {
243 return SkToBool(fStepFlags & StepFlags::kRequiresMSAA);
244 }
245 bool emitsPrimitiveColor() const {
246 return SkToBool(fStepFlags & StepFlags::kEmitsPrimitiveColor);
247 }
248 bool outsetBoundsForAA() const {
249 return SkToBool(fStepFlags & StepFlags::kOutsetBoundsForAA);
250 }
251
252 SkEnumBitMask<DepthStencilFlags> depthStencilFlags() const { return fDepthStencilFlags; }
253
254 Coverage coverage() const { return RenderStep::GetCoverage(fStepFlags); }
255
256private:
257 friend class RendererProvider; // for ctors
258
259 // Max render steps is 4, so just spell the options out for now...
260 Renderer(std::string_view name, DrawTypeFlags drawTypes, const RenderStep* s1)
261 : Renderer(name, drawTypes, std::array<const RenderStep*, 1>{s1}) {}
262
263 Renderer(std::string_view name, DrawTypeFlags drawTypes,
264 const RenderStep* s1, const RenderStep* s2)
265 : Renderer(name, drawTypes, std::array<const RenderStep*, 2>{s1, s2}) {}
266
267 Renderer(std::string_view name, DrawTypeFlags drawTypes,
268 const RenderStep* s1, const RenderStep* s2, const RenderStep* s3)
269 : Renderer(name, drawTypes, std::array<const RenderStep*, 3>{s1, s2, s3}) {}
270
271 Renderer(std::string_view name, DrawTypeFlags drawTypes,
272 const RenderStep* s1, const RenderStep* s2, const RenderStep* s3, const RenderStep* s4)
273 : Renderer(name, drawTypes, std::array<const RenderStep*, 4>{s1, s2, s3, s4}) {}
274
275 template<size_t N>
276 Renderer(std::string_view name, DrawTypeFlags drawTypes, std::array<const RenderStep*, N> steps)
277 : fName(name)
278 , fDrawTypes(drawTypes)
279 , fStepCount(SkTo<int>(N)) {
280 static_assert(N <= kMaxRenderSteps);
281 for (int i = 0 ; i < fStepCount; ++i) {
282 fSteps[i] = steps[i];
283 fStepFlags |= fSteps[i]->fFlags;
284 fDepthStencilFlags |= fSteps[i]->depthStencilFlags();
285 }
286 // At least one step needs to actually shade.
288 }
289
290 // For RendererProvider to manage initialization; it will never expose a Renderer that is only
291 // default-initialized and not replaced because it's algorithm is disabled by caps/options.
292 Renderer() : fSteps(), fName(""), fStepCount(0) {}
293 Renderer& operator=(Renderer&&) = default;
294
295 std::array<const RenderStep*, kMaxRenderSteps> fSteps;
296 std::string fName;
298 int fStepCount;
299
302};
303
304} // namespace skgpu::graphite
305
306#endif // skgpu_graphite_Renderer_DEFINED
const char * fName
uint16_t fFlags
Definition: ShapeLayer.cpp:106
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SK_DECL_BITMASK_OPS_FRIENDS(E)
Definition: SkEnumBitMask.h:82
SkPathFillType
Definition: SkPathTypes.h:11
SkSLType
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr D SkTo(S s)
Definition: SkTo.h:16
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define N
Definition: beziers.cpp:19
size_t vertexStride() const
Definition: Renderer.h:127
virtual ~RenderStep()=default
SkSpan< const Attribute > instanceAttributes() const
Definition: Renderer.h:145
PrimitiveType primitiveType() const
Definition: Renderer.h:126
bool emitsPrimitiveColor() const
Definition: Renderer.h:121
static const char * ssboIndicesAttribute()
Definition: Renderer.h:135
virtual const char * fragmentColorSkSL() const
Definition: Renderer.h:110
virtual std::string vertexSkSL() const =0
size_t numUniforms() const
Definition: Renderer.h:130
SkSpan< const Attribute > vertexAttributes() const
Definition: Renderer.h:144
virtual std::string texturesAndSamplersSkSL(const ResourceBindingRequirements &, int *nextBindingIndex) const
Definition: Renderer.h:96
virtual void writeVertices(DrawWriter *, const DrawParams &, skvx::ushort2 ssboIndices) const =0
Coverage coverage() const
Definition: Renderer.h:124
const char * name() const
Definition: Renderer.h:116
size_t numInstanceAttributes() const
Definition: Renderer.h:132
bool outsetBoundsForAA() const
Definition: Renderer.h:122
SkEnumBitMask< DepthStencilFlags > depthStencilFlags() const
Definition: Renderer.h:150
static const char * ssboIndicesVarying()
Definition: Renderer.h:139
size_t instanceStride() const
Definition: Renderer.h:128
uint32_t uniqueID() const
Definition: Renderer.h:112
virtual void writeUniformsAndTextures(const DrawParams &, PipelineDataGatherer *) const =0
SkSpan< const Varying > varyings() const
Definition: Renderer.h:146
bool performsShading() const
Definition: Renderer.h:119
SkSpan< const Uniform > uniforms() const
Definition: Renderer.h:143
size_t numVertexAttributes() const
Definition: Renderer.h:131
RenderStep(std::string_view className, std::string_view variantName, SkEnumBitMask< Flags > flags, std::initializer_list< Uniform > uniforms, PrimitiveType primitiveType, DepthStencilSettings depthStencilSettings, SkSpan< const Attribute > vertexAttrs, SkSpan< const Attribute > instanceAttrs, SkSpan< const Varying > varyings={})
Definition: Renderer.cpp:19
bool requiresMSAA() const
Definition: Renderer.h:118
virtual const char * fragmentCoverageSkSL() const
Definition: Renderer.h:105
bool hasTextures() const
Definition: Renderer.h:120
const DepthStencilSettings & depthStencilSettings() const
Definition: Renderer.h:148
SkEnumBitMask< DepthStencilFlags > depthStencilFlags() const
Definition: Renderer.h:252
bool requiresMSAA() const
Definition: Renderer.h:242
const RenderStep & step(int i) const
Definition: Renderer.h:229
Coverage coverage() const
Definition: Renderer.h:254
int numRenderSteps() const
Definition: Renderer.h:240
SkSpan< const RenderStep *const > steps() const
Definition: Renderer.h:233
const char * name() const
Definition: Renderer.h:238
bool emitsPrimitiveColor() const
Definition: Renderer.h:245
DrawTypeFlags drawTypes() const
Definition: Renderer.h:239
bool outsetBoundsForAA() const
Definition: Renderer.h:248
FlutterSemanticsFlag flags
@ kNone
Definition: layer.h:53
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
TRect< Scalar > Rect
Definition: rect.h:769
SK_MAKE_BITMASK_OPS(DawnErrorType)
Definition: GpuTools.h:21
MaskFormat
Definition: AtlasTypes.h:98
skgpu::graphite::Transform Transform
Definition: ref_ptr.h:256
const char * fName
Definition: Renderer.h:46
Definition: SkVx.h:83