• 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_Renderer_DEFINED
9 #define skgpu_Renderer_DEFINED
10 
11 #include "include/core/SkSpan.h"
12 #include "include/core/SkString.h"
13 #include "include/core/SkTypes.h"
14 
15 #include <array>
16 
17 namespace skgpu {
18 
19 struct IndexWriter;
20 class Shape;
21 struct VertexWriter;
22 
23 class RenderStep {
24 public:
~RenderStep()25     virtual ~RenderStep() {}
26 
27     virtual const char* name()            const = 0;
28     virtual bool        requiresStencil() const = 0;
29     virtual bool        requiresMSAA()    const = 0;
30     virtual bool        performsShading() const = 0;
31 
32     virtual size_t requiredVertexSpace(const Shape&) const = 0;
33     virtual size_t requiredIndexSpace(const Shape&) const = 0;
34     virtual void writeVertices(VertexWriter, IndexWriter, const Shape&) const = 0;
35 
36     // TODO: Actual API to do things
37     // 1. Provide stencil settings
38     // 2. Provide shader key or MSL(?) for the vertex stage
39     // 3. Write vertex data given a Shape/Transform/Stroke info
40     // 4. Write uniform data given a Shape/Transform/Stroke info
41     // 5. Somehow specify the draw call that needs to be made, although this can't just be "record"
42     //    the draw call, since we want multiple draws to accumulate into the same vertex buffer,
43     //    and the final draw totals aren't known until we have done #3 for another draw and it
44     //    requires binding a new vertex buffer/offset.
45     //    - maybe if it just says what it's primitive type is and instanced/indexed/etc. and then
46     //      the DrawPass building is able to track the total number of vertices/indices written for
47     //      the draws in the batch and can handle recording the draw command itself.
48     // 6. Some Renderers benefit from being able to share vertices between RenderSteps. Must find a
49     //    way to support that. It may mean that RenderSteps get state per draw.
50     //    - Does Renderer make RenderStepFactories that create steps for each DrawList::Draw?
51     //    - Does DrawList->DrawPass conversion build a separate array of blind data that the
52     //      stateless Renderstep can refer to for {draw,step} pairs?
53     //    - Does each DrawList::Draw have extra space (e.g. 8 bytes) that steps can cache data in?
54 protected:
RenderStep()55     RenderStep() {}
56 
57 private:
58     // Cannot copy or move
59     RenderStep(const RenderStep&) = delete;
60     RenderStep(RenderStep&&)      = delete;
61 };
62 
63 /**
64  * The actual technique for rasterizing a high-level draw recorded in a DrawList is handled by a
65  * specific Renderer. Each technique has an associated singleton Renderer that decomposes the
66  * technique into a series of RenderSteps that must be executed in the specified order for the draw.
67  * However, the RenderStep executions for multiple draws can be re-arranged so batches of each
68  * step can be performed in a larger GPU operation. This re-arranging relies on accurate
69  * determination of the DisjointStencilIndex for each draw so that stencil steps are not corrupted
70  * by another draw before its cover step is executed. It also relies on the CompressedPaintersOrder
71  * for each draw to ensure steps are not re-arranged in a way that violates the original draw order.
72  *
73  * Renderer itself is non-virtual since it simply has to point to a list of RenderSteps. RenderSteps
74  * on the other hand are virtual implement the technique specific functionality. It is entirely
75  * possible for certain types of steps, e.g. a bounding box cover, to be re-used across different
76  * Renderers even if the preceeding steps were different.
77  */
78 class Renderer {
79 public:
80     // Graphite defines a limited set of renderers in order to increase likelihood of batching
81     // across draw calls, and reduce the number of shader permutations required. These Renderers
82     // are stateless singletons and remain alive for the entire program. Each Renderer corresponds
83     // to a specific recording function on DrawList.
84     static const Renderer& StencilAndFillPath();
85     // TODO: Not on the immediate sprint target, but show what needs to be added for DrawList's API
86     // static const Renderer& FillConvexPath();
87     // static const Renderer& StrokePath();
88     // TODO: Will add more of these as primitive rendering etc. is fleshed out
89 
90     // The maximum number of render steps that any Renderer is allowed to have.
91     static constexpr int kMaxRenderSteps = 4;
92 
steps()93     SkSpan<const RenderStep* const> steps() const {
94         return {&fSteps.front(), static_cast<size_t>(fStepCount) };
95     }
96 
name()97     const char* name()            const { return fName.c_str();    }
numRenderSteps()98     int         numRenderSteps()  const { return fStepCount;       }
requiresStencil()99     bool        requiresStencil() const { return fRequiresStencil; }
requiresMSAA()100     bool        requiresMSAA()    const { return fRequiresMSAA;    }
101 
102 private:
103     // max render steps is 4, so just spell the options out for now...
Renderer(const char * name,const RenderStep * s1)104     Renderer(const char* name, const RenderStep* s1)
105             : Renderer(name, std::array<const RenderStep*, 1>{s1}) {}
106 
Renderer(const char * name,const RenderStep * s1,const RenderStep * s2)107     Renderer(const char* name, const RenderStep* s1, const RenderStep* s2)
108             : Renderer(name, std::array<const RenderStep*, 2>{s1, s2}) {}
109 
Renderer(const char * name,const RenderStep * s1,const RenderStep * s2,const RenderStep * s3)110     Renderer(const char* name, const RenderStep* s1, const RenderStep* s2, const RenderStep* s3)
111             : Renderer(name, std::array<const RenderStep*, 3>{s1, s2, s3}) {}
112 
Renderer(const char * name,const RenderStep * s1,const RenderStep * s2,const RenderStep * s3,const RenderStep * s4)113     Renderer(const char* name, const RenderStep* s1, const RenderStep* s2,
114              const RenderStep* s3, const RenderStep* s4)
115             : Renderer(name, std::array<const RenderStep*, 4>{s1, s2, s3, s4}) {}
116 
117     template<size_t N>
Renderer(const char * name,std::array<const RenderStep *,N> steps)118     Renderer(const char* name, std::array<const RenderStep*, N> steps)
119             : fName(name)
120             , fStepCount(SkTo<int>(N))
121             , fRequiresStencil(false)
122             , fRequiresMSAA(false) {
123         static_assert(N <= kMaxRenderSteps);
124         SkDEBUGCODE(bool performsShading = false;)
125         for (int i = 0 ; i < fStepCount; ++i) {
126             fSteps[i] = steps[i];
127             fRequiresStencil |= fSteps[i]->requiresStencil();
128             fRequiresMSAA |= fSteps[i]->requiresMSAA();
129             SkDEBUGCODE(performsShading |= fSteps[i]->performsShading());
130         }
131         SkASSERT(performsShading); // at least one step needs to actually shade
132     }
133 
134     // Cannot move or copy
135     Renderer(const Renderer&) = delete;
136     Renderer(Renderer&&)      = delete;
137 
138     std::array<const RenderStep*, kMaxRenderSteps> fSteps;
139 
140     SkString fName;
141     int      fStepCount;
142     bool     fRequiresStencil;
143     bool     fRequiresMSAA;
144 };
145 
146 } // skgpu namespace
147 
148 #endif // skgpu_Renderer_DEFINED
149