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