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