xref: /aosp_15_r20/external/skia/src/gpu/graphite/compute/DispatchGroup.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2023 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_graphite_compute_DispatchGroup_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_graphite_compute_DispatchGroup_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ComputePipelineDesc.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ComputeTypes.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceTypes.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/compute/ComputeStep.h"
17*c8dee2aaSAndroid Build Coastguard Worker 
18*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
19*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
20*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
21*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
22*c8dee2aaSAndroid Build Coastguard Worker #include <variant>
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker class CommandBuffer;
27*c8dee2aaSAndroid Build Coastguard Worker class ComputePipeline;
28*c8dee2aaSAndroid Build Coastguard Worker class Recorder;
29*c8dee2aaSAndroid Build Coastguard Worker class ResourceProvider;
30*c8dee2aaSAndroid Build Coastguard Worker class Sampler;
31*c8dee2aaSAndroid Build Coastguard Worker class Task;
32*c8dee2aaSAndroid Build Coastguard Worker class Texture;
33*c8dee2aaSAndroid Build Coastguard Worker class TextureProxy;
34*c8dee2aaSAndroid Build Coastguard Worker 
35*c8dee2aaSAndroid Build Coastguard Worker using BindingIndex = uint32_t;
36*c8dee2aaSAndroid Build Coastguard Worker struct TextureIndex { uint32_t fValue; };
37*c8dee2aaSAndroid Build Coastguard Worker struct SamplerIndex { uint32_t fValue; };
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker using DispatchResource = std::variant<BindBufferInfo, TextureIndex, SamplerIndex>;
40*c8dee2aaSAndroid Build Coastguard Worker using DispatchResourceOptional =
41*c8dee2aaSAndroid Build Coastguard Worker         std::variant<std::monostate, BindBufferInfo, TextureIndex, SamplerIndex>;
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker struct ResourceBinding {
44*c8dee2aaSAndroid Build Coastguard Worker     BindingIndex fIndex;
45*c8dee2aaSAndroid Build Coastguard Worker     DispatchResource fResource;
46*c8dee2aaSAndroid Build Coastguard Worker };
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker /**
49*c8dee2aaSAndroid Build Coastguard Worker  * DispatchGroup groups a series of compute pipeline dispatches that need to execute sequentially
50*c8dee2aaSAndroid Build Coastguard Worker  * (i.e. with a barrier). Dispatches are stored in the order that they will be encoded
51*c8dee2aaSAndroid Build Coastguard Worker  * in the eventual command buffer.
52*c8dee2aaSAndroid Build Coastguard Worker  *
53*c8dee2aaSAndroid Build Coastguard Worker  * A DispatchGroup can be constructed from a series of ComputeSteps using a Builder. The Builder
54*c8dee2aaSAndroid Build Coastguard Worker  * verifies that the data flow specification between successive ComputeSteps are compatible.
55*c8dee2aaSAndroid Build Coastguard Worker  * The resources required by a ComputeStep (such as Buffers and TextureProxies) are created by
56*c8dee2aaSAndroid Build Coastguard Worker  * the Builder as they get added.
57*c8dee2aaSAndroid Build Coastguard Worker  *
58*c8dee2aaSAndroid Build Coastguard Worker  * Once a DispatchGroup is finalized, it is immutable. It contains the complete ResourceBinding list
59*c8dee2aaSAndroid Build Coastguard Worker  * for each dispatch. A list of finalized DispatchGroups can be submitted to the command buffer in a
60*c8dee2aaSAndroid Build Coastguard Worker  * ComputeTask.
61*c8dee2aaSAndroid Build Coastguard Worker  */
62*c8dee2aaSAndroid Build Coastguard Worker class DispatchGroup final {
63*c8dee2aaSAndroid Build Coastguard Worker public:
64*c8dee2aaSAndroid Build Coastguard Worker     class Builder;
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker     struct Dispatch {
67*c8dee2aaSAndroid Build Coastguard Worker         WorkgroupSize fLocalSize;
68*c8dee2aaSAndroid Build Coastguard Worker         std::variant<WorkgroupSize, BindBufferInfo> fGlobalSizeOrIndirect;
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker         std::optional<WorkgroupSize> fGlobalDispatchSize;
71*c8dee2aaSAndroid Build Coastguard Worker         skia_private::TArray<ResourceBinding> fBindings;
72*c8dee2aaSAndroid Build Coastguard Worker         skia_private::TArray<ComputeStep::WorkgroupBufferDesc> fWorkgroupBuffers;
73*c8dee2aaSAndroid Build Coastguard Worker         int fPipelineIndex = 0;
74*c8dee2aaSAndroid Build Coastguard Worker     };
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     ~DispatchGroup();
77*c8dee2aaSAndroid Build Coastguard Worker 
dispatches()78*c8dee2aaSAndroid Build Coastguard Worker     const skia_private::TArray<Dispatch>& dispatches() const { return fDispatchList; }
79*c8dee2aaSAndroid Build Coastguard Worker 
getPipeline(size_t index)80*c8dee2aaSAndroid Build Coastguard Worker     const ComputePipeline* getPipeline(size_t index) const { return fPipelines[index].get(); }
81*c8dee2aaSAndroid Build Coastguard Worker     const Texture* getTexture(size_t index) const;
82*c8dee2aaSAndroid Build Coastguard Worker     const Sampler* getSampler(size_t index) const;
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker     bool prepareResources(ResourceProvider*);
85*c8dee2aaSAndroid Build Coastguard Worker     void addResourceRefs(CommandBuffer*) const;
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker     // Returns a single tasks that must execute before this DispatchGroup or nullptr if the group
88*c8dee2aaSAndroid Build Coastguard Worker     // has no task dependencies.
89*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<Task> snapChildTask();
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker private:
92*c8dee2aaSAndroid Build Coastguard Worker     friend class DispatchGroupBuilder;
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker     DispatchGroup() = default;
95*c8dee2aaSAndroid Build Coastguard Worker 
96*c8dee2aaSAndroid Build Coastguard Worker     // Disallow copy and move.
97*c8dee2aaSAndroid Build Coastguard Worker     DispatchGroup(const DispatchGroup&) = delete;
98*c8dee2aaSAndroid Build Coastguard Worker     DispatchGroup(DispatchGroup&&) = delete;
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<Dispatch> fDispatchList;
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     // The list of all buffers that must be cleared before the dispatches.
103*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<BindBufferInfo> fClearList;
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker     // Pipelines are referenced by index by each Dispatch in `fDispatchList`. They are stored as a
106*c8dee2aaSAndroid Build Coastguard Worker     // pipeline description until instantiated in `prepareResources()`.
107*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<ComputePipelineDesc> fPipelineDescs;
108*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<SamplerDesc> fSamplerDescs;
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     // Resources instantiated by `prepareResources()`
111*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<sk_sp<ComputePipeline>> fPipelines;
112*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<sk_sp<TextureProxy>> fTextures;
113*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<sk_sp<Sampler>> fSamplers;
114*c8dee2aaSAndroid Build Coastguard Worker };
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker class DispatchGroup::Builder final {
117*c8dee2aaSAndroid Build Coastguard Worker public:
118*c8dee2aaSAndroid Build Coastguard Worker     // Contains the resource handles assigned to the outputs of the most recently inserted
119*c8dee2aaSAndroid Build Coastguard Worker     // ComputeStep.
120*c8dee2aaSAndroid Build Coastguard Worker     struct OutputTable {
121*c8dee2aaSAndroid Build Coastguard Worker         // Contains the std::monostate variant if the slot is uninitialized
122*c8dee2aaSAndroid Build Coastguard Worker         DispatchResourceOptional fSharedSlots[kMaxComputeDataFlowSlots];
123*c8dee2aaSAndroid Build Coastguard Worker 
124*c8dee2aaSAndroid Build Coastguard Worker         OutputTable() = default;
125*c8dee2aaSAndroid Build Coastguard Worker 
resetOutputTable126*c8dee2aaSAndroid Build Coastguard Worker         void reset() { *this = {}; }
127*c8dee2aaSAndroid Build Coastguard Worker     };
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker     explicit Builder(Recorder*);
130*c8dee2aaSAndroid Build Coastguard Worker 
outputTable()131*c8dee2aaSAndroid Build Coastguard Worker     const OutputTable& outputTable() const { return fOutputTable; }
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker     // Add a new compute step to the dispatch group and initialize its required resources if
134*c8dee2aaSAndroid Build Coastguard Worker     // necessary.
135*c8dee2aaSAndroid Build Coastguard Worker     //
136*c8dee2aaSAndroid Build Coastguard Worker     // If the global dispatch size (i.e. workgroup count) is known ahead of time it can be
137*c8dee2aaSAndroid Build Coastguard Worker     // optionally provided here while appending a step. If provided, the ComputeStep will not
138*c8dee2aaSAndroid Build Coastguard Worker     // receive a call to `calculateGlobalDispatchSize`.
139*c8dee2aaSAndroid Build Coastguard Worker     bool appendStep(const ComputeStep*, std::optional<WorkgroupSize> globalSize = std::nullopt);
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker     // Add a new compute step to the dispatch group with an indirectly specified global dispatch
142*c8dee2aaSAndroid Build Coastguard Worker     // size. Initialize the required resources if necessary.
143*c8dee2aaSAndroid Build Coastguard Worker     //
144*c8dee2aaSAndroid Build Coastguard Worker     // The global dispatch size is determined by the GPU by reading the entries in `indirectBuffer`.
145*c8dee2aaSAndroid Build Coastguard Worker     // The contents of this buffer must conform to the layout of the `IndirectDispatchArgs`
146*c8dee2aaSAndroid Build Coastguard Worker     // structure declared in ComputeTypes.h.
147*c8dee2aaSAndroid Build Coastguard Worker     //
148*c8dee2aaSAndroid Build Coastguard Worker     // The ComputeStep will not receive a call to `calculateGlobalDispatchSize`.
149*c8dee2aaSAndroid Build Coastguard Worker     bool appendStepIndirect(const ComputeStep*, BindBufferInfo indirectBuffer);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     // Directly assign a buffer range to a shared slot. ComputeSteps that are appended after this
152*c8dee2aaSAndroid Build Coastguard Worker     // call will use this resouce if they reference the given `slot` index. Builder will not
153*c8dee2aaSAndroid Build Coastguard Worker     // allocate the resource internally and ComputeSteps will not receive calls to
154*c8dee2aaSAndroid Build Coastguard Worker     // `calculateBufferSize`.
155*c8dee2aaSAndroid Build Coastguard Worker     //
156*c8dee2aaSAndroid Build Coastguard Worker     // If the slot is already assigned a buffer, it will be overwritten. Calling this method does
157*c8dee2aaSAndroid Build Coastguard Worker     // not have any effect on previously appended ComputeSteps that were already bound that
158*c8dee2aaSAndroid Build Coastguard Worker     // resource.
159*c8dee2aaSAndroid Build Coastguard Worker     //
160*c8dee2aaSAndroid Build Coastguard Worker     // If `cleared` is kYes, the contents of the given view will be cleared to 0 before the current
161*c8dee2aaSAndroid Build Coastguard Worker     // DispatchGroup gets submitted.
162*c8dee2aaSAndroid Build Coastguard Worker     void assignSharedBuffer(BindBufferInfo buffer,
163*c8dee2aaSAndroid Build Coastguard Worker                             unsigned int slot,
164*c8dee2aaSAndroid Build Coastguard Worker                             ClearBuffer cleared = ClearBuffer::kNo);
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker     // Directly assign a texture to a shared slot. ComputeSteps that are appended after this call
167*c8dee2aaSAndroid Build Coastguard Worker     // will use this resource if they reference the given `slot` index. Builder will not allocate
168*c8dee2aaSAndroid Build Coastguard Worker     // the resource internally and ComputeSteps will not receive calls to
169*c8dee2aaSAndroid Build Coastguard Worker     // `calculateTextureParameters`.
170*c8dee2aaSAndroid Build Coastguard Worker     //
171*c8dee2aaSAndroid Build Coastguard Worker     // If the slot is already assigned a texture, it will be overwritten. Calling this method does
172*c8dee2aaSAndroid Build Coastguard Worker     // not have any effect on previously appended ComputeSteps that were already bound that
173*c8dee2aaSAndroid Build Coastguard Worker     // resource.
174*c8dee2aaSAndroid Build Coastguard Worker     void assignSharedTexture(sk_sp<TextureProxy> texture, unsigned int slot);
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker     // Finalize and return the constructed DispatchGroup.
177*c8dee2aaSAndroid Build Coastguard Worker     //
178*c8dee2aaSAndroid Build Coastguard Worker     // The Builder can be used to construct a new DispatchGroup by calling "reset()" after this
179*c8dee2aaSAndroid Build Coastguard Worker     // method returns.
180*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<DispatchGroup> finalize();
181*c8dee2aaSAndroid Build Coastguard Worker 
182*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
183*c8dee2aaSAndroid Build Coastguard Worker     // Clear old state and start a new DispatchGroup.
184*c8dee2aaSAndroid Build Coastguard Worker     void reset();
185*c8dee2aaSAndroid Build Coastguard Worker #endif
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker     // Returns the buffer resource assigned to the shared slot with the given index, if any.
188*c8dee2aaSAndroid Build Coastguard Worker     BindBufferInfo getSharedBufferResource(unsigned int slot) const;
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker     // Returns the texture resource assigned to the shared slot with the given index, if any.
191*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<TextureProxy> getSharedTextureResource(unsigned int slot) const;
192*c8dee2aaSAndroid Build Coastguard Worker 
193*c8dee2aaSAndroid Build Coastguard Worker private:
194*c8dee2aaSAndroid Build Coastguard Worker     bool appendStepInternal(const ComputeStep*, const std::variant<WorkgroupSize, BindBufferInfo>&);
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker     // Allocate a resource that can be assigned to the shared or private data flow slots. Returns a
197*c8dee2aaSAndroid Build Coastguard Worker     // std::monostate if allocation fails.
198*c8dee2aaSAndroid Build Coastguard Worker     DispatchResourceOptional allocateResource(const ComputeStep* step,
199*c8dee2aaSAndroid Build Coastguard Worker                                               const ComputeStep::ResourceDesc& resource,
200*c8dee2aaSAndroid Build Coastguard Worker                                               int resourceIdx);
201*c8dee2aaSAndroid Build Coastguard Worker 
202*c8dee2aaSAndroid Build Coastguard Worker     // The object under construction.
203*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<DispatchGroup> fObj;
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker     Recorder* fRecorder;
206*c8dee2aaSAndroid Build Coastguard Worker     OutputTable fOutputTable;
207*c8dee2aaSAndroid Build Coastguard Worker };
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::graphite
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker #endif  // skgpu_graphite_compute_DispatchGroup_DEFINED
212