Flutter Engine
The Flutter Engine
ComputeStep.h
Go to the documentation of this file.
1/*
2 * Copyright 2023 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_compute_ComputeStep_DEFINED
9#define skgpu_graphite_compute_ComputeStep_DEFINED
10
12#include "include/core/SkSize.h"
13#include "include/core/SkSpan.h"
18
19#include <optional>
20#include <string>
21#include <string_view>
22#include <tuple>
23#include <vector>
24
25namespace skgpu::graphite {
26
27class UniformManager;
28
29/**
30 * A `ComputeStep` represents a compute pass within a wider draw operation. A `ComputeStep`
31 * implementation describes an invocation of a compute program and its data binding layout.
32 *
33 * A `ComputeStep` can perform arbitrary operations on the GPU over various types of data, including
34 * geometry and image processing. The data processed by a `ComputeStep` can be inputs (textures or
35 * buffers) populated on the CPU, data forwarded to and from other `ComputeStep` invocations (via
36 * "slots"), transient storage buffers/textures that are only used within an individual dispatch,
37 * geometry attribute (vertex/index/instance) and indirect draw parameters of a subsequent raster
38 * pipeline stage, as well as texture outputs.
39 *
40 * The data flow between sequential `ComputeStep` invocations within a DispatchGroup is achieved by
41 * operating over a shared "resource table". `ComputeStep`s can declare a resource with a slot
42 * number. Multiple `ComputeStep`s in a group that declare a resource with the same slot number will
43 * have access to the same backing resource object through that slot:
44 *
45 * _______________ _______________
46 * | | | |
47 * | ---[Slot 0]--- |
48 * | | | |
49 * | ---[Slot 1]--- |
50 * | ComputeStep 1 | | ComputeStep 2 |
51 * | ---[Slot 2] | |
52 * | | | |
53 * | | [Slot 3]--- |
54 * | | | |
55 * --------------- ---------------
56 *
57 * In the example above, slots 0 and 1 are accessed by both ComputeSteps, while slots 2 and 3 are
58 * exclusively accessed by ComputeStep 1 and 2 respectively. Alternately, slots 2 and 3 could be
59 * declared as "private" resources which are visible to a single ComputeStep.
60 *
61 * Similarly, raster stage geometry buffers that are specified as the output of a ComputeStep can be
62 * used to assign the draw buffers of a RenderStep.
63 *
64 * It is the responsibility of the owning entity (e.g. a RendererProvider) to ensure that a chain of
65 * ComputeStep and RenderStep invocations have a compatible resource and data-flow layout.
66 */
68public:
69 enum class DataFlow {
70 // A private binding is a resource that is only visible to a single ComputeStep invocation.
71 kPrivate,
72
73 // Bindings with a slot number that can be used to forward data between a series of
74 // `ComputeStep`s. This DataFlow type is accompanied with a "slot number" that can be
75 // shared by multiple `ComputeStep`s in a group.
76 kShared,
77 };
78
79 enum class ResourceType {
80 kUniformBuffer,
81 kStorageBuffer,
82 kReadOnlyStorageBuffer,
83
84 // An indirect buffer is a storage buffer populated by this ComputeStep to determine the
85 // global dispatch size of a subsequent ComputeStep within the same DispatchGroup. The
86 // contents of the buffer must be laid out according to the `IndirectDispatchArgs` struct
87 // definition declared in ComputeTypes.h.
88 kIndirectBuffer,
89
90 kWriteOnlyStorageTexture,
91 kReadOnlyTexture,
92 kSampledTexture,
93 };
94
95 enum class ResourcePolicy {
96 kNone,
97
98 // The memory of the resource will be initialized to 0
99 kClear,
100
101 // The ComputeStep will be asked to initialize the memory on the CPU via
102 // `ComputeStep::prepareStorageBuffer` or `ComputeStep::prepareUniformBuffer` prior to
103 // pipeline execution. This may incur a transfer cost on platforms that do not allow buffers
104 // to be mapped in shared memory.
105 //
106 // If multiple ComputeSteps in a DispatchGroup declare a mapped resource with the same
107 // shared slot number, only the first ComputeStep in the group will receive a call to
108 // prepare the buffer.
109 //
110 // This only has meaning for buffer resources. A resource with the `kUniformBuffer` resource
111 // type must specify the `kMapped` resource policy.
112 kMapped,
113 };
114
115 struct ResourceDesc final {
119
120 // This field only has meaning (and must have a non-negative value) if `fFlow` is
121 // `DataFlow::kShared`.
122 int fSlot;
123
124 // The SkSL variable declaration code excluding the layout and type definitions. This field
125 // is ignored for a ComputeStep that supports native shader source.
126 const char* fSkSL = "";
127
129 DataFlow flow,
131 int slot = -1)
132 : fType(type), fFlow(flow), fPolicy(policy), fSlot(slot) {}
133
135 DataFlow flow,
137 int slot,
138 const char* sksl)
139 : fType(type), fFlow(flow), fPolicy(policy), fSlot(slot), fSkSL(sksl) {}
140
142 DataFlow flow,
144 const char* sksl)
145 : fType(type), fFlow(flow), fPolicy(policy), fSlot(-1), fSkSL(sksl) {}
146 };
147
148 // On platforms that support late bound workgroup shared resources (e.g. Metal) a ComputeStep
149 // can optionally provide a list of memory sizes and binding indices.
151 // The buffer size in bytes.
152 size_t size;
153 size_t index;
154 };
155
156 virtual ~ComputeStep() = default;
157
158 // Returns a complete SkSL compute program. The returned SkSL must constitute a complete compute
159 // program and declare all resource bindings starting at `nextBindingIndex` in the order in
160 // which they are enumerated by `ComputeStep::resources()`.
161 //
162 // If this ComputeStep supports native shader source then it must override
163 // `nativeShaderSource()` instead.
164 virtual std::string computeSkSL() const;
165
166 // A ComputeStep that supports native shader source then then it must implement
167 // `nativeShaderSource()` and return the shader source in the requested format. This is intended
168 // to instantiate a compute pipeline from a pre-compiled shader module. The returned source must
169 // constitute a shader module that contains at least one compute entry-point function that
170 // matches the specified name.
172 kWGSL,
173 kMSL,
174 };
176 std::string_view fSource;
177 std::string fEntryPoint;
178 };
180
181 // This method will be called for buffer entries in the ComputeStep's resource list to
182 // determine the required allocation size. The ComputeStep must return a non-zero value.
183 //
184 // TODO(b/279955342): Provide a context object, e.g. a type a associated with
185 // DispatchGroup::Builder, to aid the ComputeStep in its buffer size calculations.
186 virtual size_t calculateBufferSize(int resourceIndex, const ResourceDesc&) const;
187
188 // This method will be called for storage texture entries in the ComputeStep's resource list to
189 // determine the required dimensions and color type. The ComputeStep must return a non-zero
190 // value for the size and a valid color type.
191 virtual std::tuple<SkISize, SkColorType> calculateTextureParameters(int resourceIndex,
192 const ResourceDesc&) const;
193
194 // This method will be called for sampler entries in the ComputeStep's resource list to
195 // determine the sampling and tile mode options.
196 virtual SamplerDesc calculateSamplerParameters(int resourceIndex, const ResourceDesc&) const;
197
198 // Return the global dispatch size (aka "workgroup count") for this step based on the draw
199 // parameters. The default value is a workgroup count of (1, 1, 1)
200 //
201 // TODO(b/279955342): Provide a context object, e.g. a type a associated with
202 // DispatchGroup::Builder, to aid the ComputeStep in its buffer size calculations.
204
205 // Populates a storage buffer resource which was specified as "mapped". This method will only be
206 // called once for a resource right after its allocation and before pipeline execution. For
207 // shared resources, only the first ComputeStep in a DispatchGroup will be asked to prepare the
208 // buffer.
209 //
210 // `resourceIndex` matches the order in which `resource` was enumerated by
211 // `ComputeStep::resources()`.
212 virtual void prepareStorageBuffer(int resourceIndex,
213 const ResourceDesc& resource,
214 void* buffer,
215 size_t bufferSize) const;
216
217 // Populates a uniform buffer resource. This method will be called once for a resource right
218 // after its allocation and before pipeline execution. For shared resources, only the first
219 // ComputeStep in a DispatchGroup will be asked to prepare the buffer.
220 //
221 // `resourceIndex` matches the order in which `resource` was enumerated by
222 // `ComputeStep::resources()`.
223 //
224 // The implementation must use the provided `UniformManager` to populate the buffer. On debug
225 // builds, the implementation must validate the buffer layout by setting up an expectation, for
226 // example:
227 //
228 // SkDEBUGCODE(mgr->setExpectedUniforms({{"foo", SkSLType::kFloat}}));
229 //
230 // TODO(b/279955342): Provide a context object, e.g. a type a associated with
231 // DispatchGroup::Builder, to aid the ComputeStep in its buffer size calculations.
232 virtual void prepareUniformBuffer(int resourceIndex,
233 const ResourceDesc&,
234 UniformManager*) const;
235
236 SkSpan<const ResourceDesc> resources() const { return SkSpan(fResources); }
237 SkSpan<const WorkgroupBufferDesc> workgroupBuffers() const { return SkSpan(fWorkgroupBuffers); }
238
239 // Identifier that can be used as part of a unique key for a compute pipeline state object
240 // associated with this `ComputeStep`.
241 uint32_t uniqueID() const { return fUniqueID; }
242
243 // Returns a debug name for the subclass implementation.
244 const char* name() const { return fName.c_str(); }
245
246 // The size of the workgroup for this ComputeStep's entry point function. This value is hardware
247 // dependent. On Metal, this value should be used when invoking the dispatch API call. On all
248 // other backends, this value will be baked into the pipeline.
249 WorkgroupSize localDispatchSize() const { return fLocalDispatchSize; }
250
252
253protected:
254 enum class Flags : uint8_t {
255 kNone = 0b00000,
256 kSupportsNativeShader = 0b00010,
257 };
259
260 ComputeStep(std::string_view name,
264 Flags baseFlags = Flags::kNone);
265
266private:
267 // Disallow copy and move
268 ComputeStep(const ComputeStep&) = delete;
269 ComputeStep(ComputeStep&&) = delete;
270
271 uint32_t fUniqueID;
273 std::string fName;
276
277 // TODO(b/240615224): Subclasses should simply specify the workgroup size that they need.
278 // The ComputeStep constructor should check and reduce that number based on the maximum
279 // supported workgroup size stored in Caps. In Metal, we'll pass this number directly to the
280 // dispatch API call. On other backends, we'll use this value to generate the right SkSL
281 // workgroup size declaration to avoid any validation failures.
282 WorkgroupSize fLocalDispatchSize;
283};
285
286} // namespace skgpu::graphite
287
288#endif // skgpu_graphite_compute_ComputeStep_DEFINED
#define SK_DECL_BITMASK_OPS_FRIENDS(E)
Definition: SkEnumBitMask.h:82
static SkString resource(SkPDFResourceType type, int index)
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
GLenum type
virtual SamplerDesc calculateSamplerParameters(int resourceIndex, const ResourceDesc &) const
Definition: ComputeStep.cpp:83
virtual ~ComputeStep()=default
virtual std::string computeSkSL() const
Definition: ComputeStep.cpp:62
bool supportsNativeShader() const
Definition: ComputeStep.h:251
virtual WorkgroupSize calculateGlobalDispatchSize() const
Definition: ComputeStep.cpp:89
WorkgroupSize localDispatchSize() const
Definition: ComputeStep.h:249
virtual void prepareStorageBuffer(int resourceIndex, const ResourceDesc &resource, void *buffer, size_t bufferSize) const
Definition: ComputeStep.cpp:53
SkSpan< const ResourceDesc > resources() const
Definition: ComputeStep.h:236
virtual std::tuple< SkISize, SkColorType > calculateTextureParameters(int resourceIndex, const ResourceDesc &) const
Definition: ComputeStep.cpp:77
ComputeStep(std::string_view name, WorkgroupSize localDispatchSize, SkSpan< const ResourceDesc > resources, SkSpan< const WorkgroupBufferDesc > workgroupBuffers={}, Flags baseFlags=Flags::kNone)
Definition: ComputeStep.cpp:28
virtual NativeShaderSource nativeShaderSource(NativeShaderFormat) const
Definition: ComputeStep.cpp:67
SkSpan< const WorkgroupBufferDesc > workgroupBuffers() const
Definition: ComputeStep.h:237
const char * name() const
Definition: ComputeStep.h:244
uint32_t uniqueID() const
Definition: ComputeStep.h:241
virtual void prepareUniformBuffer(int resourceIndex, const ResourceDesc &, UniformManager *) const
Definition: ComputeStep.cpp:58
virtual size_t calculateBufferSize(int resourceIndex, const ResourceDesc &) const
Definition: ComputeStep.cpp:72
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition: switches.h:248
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
SK_MAKE_BITMASK_OPS(DawnErrorType)
constexpr ResourceDesc(ResourceType type, DataFlow flow, ResourcePolicy policy, int slot, const char *sksl)
Definition: ComputeStep.h:134
constexpr ResourceDesc(ResourceType type, DataFlow flow, ResourcePolicy policy, const char *sksl)
Definition: ComputeStep.h:141
constexpr ResourceDesc(ResourceType type, DataFlow flow, ResourcePolicy policy, int slot=-1)
Definition: ComputeStep.h:128