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