• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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