Coverage Report

Created: 2024-05-20 07:14

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