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 "experimental/graphite/src/Attribute.h" 12 #include "experimental/graphite/src/DrawTypes.h" 13 #include "experimental/graphite/src/EnumBitMask.h" 14 #include "experimental/graphite/src/ResourceTypes.h" 15 16 #include "include/core/SkSpan.h" 17 #include "include/core/SkString.h" 18 #include "include/core/SkTypes.h" 19 #include "src/core/SkUniform.h" 20 21 #include <array> 22 #include <initializer_list> 23 #include <vector> 24 25 struct SkIRect; 26 enum class SkPathFillType; 27 class SkUniformData; 28 29 namespace skgpu { 30 31 class DrawWriter; 32 class ResourceProvider; 33 class Shape; 34 class Transform; 35 36 enum class Layout; 37 38 class RenderStep { 39 public: 40 virtual ~RenderStep() = default; 41 42 // The DrawWriter is configured with the vertex and instance strides of the RenderStep, and its 43 // primitive type. The recorded draws will be executed with a graphics pipeline compatible with 44 // this RenderStep. 45 virtual void writeVertices(DrawWriter*, 46 const SkIRect& bounds, 47 const Transform&, 48 const Shape&) const = 0; 49 50 // Write out the uniform values (aligned for the layout). These values will be de-duplicated 51 // across all draws using the RenderStep before uploading to the GPU, but it can be assumed the 52 // uniforms will be bound before the draws recorded in 'writeVertices' are executed. 53 // TODO: We definitely want this to return CPU memory since it's better for the caller to handle 54 // the de-duplication and GPU upload/binding (DrawPass tracks all this). However, a RenderStep's 55 // uniforms aren't going to change, and the Layout won't change during a process, so it would be 56 // nice if we could remember the offsets for the layout/gpu and reuse them across draws. 57 // Similarly, it would be nice if this could write into reusable storage and then DrawPass or 58 // UniformCache handles making an sk_sp if we need to assign a new unique ID to the uniform data 59 virtual sk_sp<SkUniformData> writeUniforms(Layout layout, 60 const SkIRect& bounds, 61 const Transform&, 62 const Shape&) const = 0; 63 64 virtual const char* name() const = 0; 65 66 // TODO: This is only temporary. Eventually the RenderStep will define its logic in SkSL and 67 // be able to have code operate in both the vertex and fragment shaders. Ideally the RenderStep 68 // will provide two functions that fit some ABI for integrating with the common and paint SkSL, 69 // although we could go as far as allowing RenderStep to handle composing the final SkSL if 70 // given the paint combination's SkSL. 71 72 // Returns the body of a vertex function, which must define a float4 devPosition variable. 73 // It has access to the variables declared by vertexAttributes(), instanceAttributes(), 74 // and uniforms(). 75 // 76 // NOTE: The above contract is mainly so that the entire SkSL program can be created by just str 77 // concatenating struct definitions generated from the RenderStep and paint Combination 78 // and then including the function bodies returned here. 79 virtual const char* vertexSkSL() const = 0; 80 requiresMSAA()81 bool requiresMSAA() const { return fFlags & Flags::kRequiresMSAA; } performsShading()82 bool performsShading() const { return fFlags & Flags::kPerformsShading; } 83 primitiveType()84 PrimitiveType primitiveType() const { return fPrimitiveType; } vertexStride()85 size_t vertexStride() const { return fVertexStride; } instanceStride()86 size_t instanceStride() const { return fInstanceStride; } 87 depthStencilSettings()88 const DepthStencilSettings& depthStencilSettings() const { return fDepthStencilSettings; } 89 depthStencilFlags()90 Mask<DepthStencilFlags> depthStencilFlags() const { 91 return (fDepthStencilSettings.fStencilTestEnabled 92 ? DepthStencilFlags::kStencil : DepthStencilFlags::kNone) | 93 (fDepthStencilSettings.fDepthTestEnabled || fDepthStencilSettings.fDepthWriteEnabled 94 ? DepthStencilFlags::kDepth : DepthStencilFlags::kNone); 95 } 96 numUniforms()97 size_t numUniforms() const { return fUniforms.size(); } numVertexAttributes()98 size_t numVertexAttributes() const { return fVertexAttrs.size(); } numInstanceAttributes()99 size_t numInstanceAttributes() const { return fInstanceAttrs.size(); } 100 101 // The uniforms of a RenderStep are bound to the kRenderStep slot, the rest of the pipeline 102 // may still use uniforms bound to other slots. uniforms()103 SkSpan<const SkUniform> uniforms() const { return SkMakeSpan(fUniforms); } vertexAttributes()104 SkSpan<const Attribute> vertexAttributes() const { return SkMakeSpan(fVertexAttrs); } instanceAttributes()105 SkSpan<const Attribute> instanceAttributes() const { return SkMakeSpan(fInstanceAttrs); } 106 107 108 // TODO: Actual API to do things 109 // 1. Provide stencil settings 110 // 6. Some Renderers benefit from being able to share vertices between RenderSteps. Must find a 111 // way to support that. It may mean that RenderSteps get state per draw. 112 // - Does Renderer make RenderStepFactories that create steps for each DrawList::Draw? 113 // - Does DrawList->DrawPass conversion build a separate array of blind data that the 114 // stateless Renderstep can refer to for {draw,step} pairs? 115 // - Does each DrawList::Draw have extra space (e.g. 8 bytes) that steps can cache data in? 116 protected: 117 enum class Flags : unsigned { 118 kNone = 0b000, 119 kRequiresMSAA = 0b001, 120 kPerformsShading = 0b010, 121 }; 122 SKGPU_DECL_MASK_OPS_FRIENDS(Flags); 123 124 // While RenderStep does not define the full program that's run for a draw, it defines the 125 // entire vertex layout of the pipeline. This is not allowed to change, so can be provided to 126 // the RenderStep constructor by subclasses. RenderStep(Mask<Flags> flags,std::initializer_list<SkUniform> uniforms,PrimitiveType primitiveType,DepthStencilSettings depthStencilSettings,std::initializer_list<Attribute> vertexAttrs,std::initializer_list<Attribute> instanceAttrs)127 RenderStep(Mask<Flags> flags, 128 std::initializer_list<SkUniform> uniforms, 129 PrimitiveType primitiveType, 130 DepthStencilSettings depthStencilSettings, 131 std::initializer_list<Attribute> vertexAttrs, 132 std::initializer_list<Attribute> instanceAttrs) 133 : fFlags(flags) 134 , fPrimitiveType(primitiveType) 135 , fDepthStencilSettings(depthStencilSettings) 136 , fUniforms(uniforms) 137 , fVertexAttrs(vertexAttrs) 138 , fInstanceAttrs(instanceAttrs) 139 , fVertexStride(0) 140 , fInstanceStride(0) { 141 for (auto v : this->vertexAttributes()) { 142 fVertexStride += v.sizeAlign4(); 143 } 144 for (auto i : this->instanceAttributes()) { 145 fInstanceStride += i.sizeAlign4(); 146 } 147 } 148 149 private: 150 // Cannot copy or move 151 RenderStep(const RenderStep&) = delete; 152 RenderStep(RenderStep&&) = delete; 153 154 Mask<Flags> fFlags; 155 PrimitiveType fPrimitiveType; 156 157 DepthStencilSettings fDepthStencilSettings; 158 159 // TODO: When we always use C++17 for builds, we should be able to just let subclasses declare 160 // constexpr arrays and point to those, but we need explicit storage for C++14. 161 // Alternatively, if we imposed a max attr count, similar to Renderer's num render steps, we 162 // could just have this be std::array and keep all attributes inline with the RenderStep memory. 163 // On the other hand, the attributes are only needed when creating a new pipeline so it's not 164 // that performance sensitive. 165 std::vector<SkUniform> fUniforms; 166 std::vector<Attribute> fVertexAttrs; 167 std::vector<Attribute> fInstanceAttrs; 168 169 size_t fVertexStride; // derived from vertex attribute set 170 size_t fInstanceStride; // derived from instance attribute set 171 }; 172 SKGPU_MAKE_MASK_OPS(RenderStep::Flags); 173 174 /** 175 * The actual technique for rasterizing a high-level draw recorded in a DrawList is handled by a 176 * specific Renderer. Each technique has an associated singleton Renderer that decomposes the 177 * technique into a series of RenderSteps that must be executed in the specified order for the draw. 178 * However, the RenderStep executions for multiple draws can be re-arranged so batches of each 179 * step can be performed in a larger GPU operation. This re-arranging relies on accurate 180 * determination of the DisjointStencilIndex for each draw so that stencil steps are not corrupted 181 * by another draw before its cover step is executed. It also relies on the CompressedPaintersOrder 182 * for each draw to ensure steps are not re-arranged in a way that violates the original draw order. 183 * 184 * Renderer itself is non-virtual since it simply has to point to a list of RenderSteps. RenderSteps 185 * on the other hand are virtual implement the technique specific functionality. It is entirely 186 * possible for certain types of steps, e.g. a bounding box cover, to be re-used across different 187 * Renderers even if the preceeding steps were different. 188 */ 189 class Renderer { 190 public: 191 // Graphite defines a limited set of renderers in order to increase likelihood of batching 192 // across draw calls, and reduce the number of shader permutations required. These Renderers 193 // are stateless singletons and remain alive for the entire program. Each Renderer corresponds 194 // to a specific recording function on DrawList and fill type. 195 static const Renderer& StencilAndFillPath(SkPathFillType); 196 // TODO: Not on the immediate sprint target, but show what needs to be added for DrawList's API 197 // static const Renderer& FillConvexPath(); 198 // static const Renderer& StrokePath(); 199 // TODO: Will add more of these as primitive rendering etc. is fleshed out 200 201 // The maximum number of render steps that any Renderer is allowed to have. 202 static constexpr int kMaxRenderSteps = 4; 203 steps()204 SkSpan<const RenderStep* const> steps() const { 205 return {&fSteps.front(), static_cast<size_t>(fStepCount) }; 206 } 207 name()208 const char* name() const { return fName.c_str(); } numRenderSteps()209 int numRenderSteps() const { return fStepCount; } requiresMSAA()210 bool requiresMSAA() const { return fRequiresMSAA; } 211 depthStencilFlags()212 Mask<DepthStencilFlags> depthStencilFlags() const { return fDepthStencilFlags; } 213 214 private: 215 // max render steps is 4, so just spell the options out for now... Renderer(const char * name,const RenderStep * s1)216 Renderer(const char* name, const RenderStep* s1) 217 : Renderer(name, std::array<const RenderStep*, 1>{s1}) {} 218 Renderer(const char * name,const RenderStep * s1,const RenderStep * s2)219 Renderer(const char* name, const RenderStep* s1, const RenderStep* s2) 220 : Renderer(name, std::array<const RenderStep*, 2>{s1, s2}) {} 221 Renderer(const char * name,const RenderStep * s1,const RenderStep * s2,const RenderStep * s3)222 Renderer(const char* name, const RenderStep* s1, const RenderStep* s2, const RenderStep* s3) 223 : Renderer(name, std::array<const RenderStep*, 3>{s1, s2, s3}) {} 224 Renderer(const char * name,const RenderStep * s1,const RenderStep * s2,const RenderStep * s3,const RenderStep * s4)225 Renderer(const char* name, const RenderStep* s1, const RenderStep* s2, 226 const RenderStep* s3, const RenderStep* s4) 227 : Renderer(name, std::array<const RenderStep*, 4>{s1, s2, s3, s4}) {} 228 229 template<size_t N> Renderer(const char * name,std::array<const RenderStep *,N> steps)230 Renderer(const char* name, std::array<const RenderStep*, N> steps) 231 : fName(name) 232 , fStepCount(SkTo<int>(N)) { 233 static_assert(N <= kMaxRenderSteps); 234 SkDEBUGCODE(bool performsShading = false;) 235 for (int i = 0 ; i < fStepCount; ++i) { 236 fSteps[i] = steps[i]; 237 fDepthStencilFlags |= fSteps[i]->depthStencilFlags(); 238 SkDEBUGCODE(performsShading |= fSteps[i]->performsShading()); 239 } 240 SkASSERT(performsShading); // at least one step needs to actually shade 241 } 242 243 // Cannot move or copy 244 Renderer(const Renderer&) = delete; 245 Renderer(Renderer&&) = delete; 246 247 std::array<const RenderStep*, kMaxRenderSteps> fSteps; 248 249 SkString fName; 250 int fStepCount; 251 bool fRequiresMSAA = false; 252 253 Mask<DepthStencilFlags> fDepthStencilFlags = DepthStencilFlags::kNone; 254 }; 255 256 } // skgpu namespace 257 258 #endif // skgpu_Renderer_DEFINED 259