xref: /aosp_15_r20/external/skia/src/gpu/graphite/compute/DispatchGroup.cpp (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 #include "src/gpu/graphite/compute/DispatchGroup.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recorder.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/TextureInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkSpan_impl.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/BufferManager.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/CommandBuffer.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ComputePipeline.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Log.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Resource.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceProvider.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Sampler.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Texture.h"  // IWYU pragma: keep
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/TextureProxy.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UniformManager.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/ClearBuffersTask.h"
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker DispatchGroup::~DispatchGroup() = default;
37*c8dee2aaSAndroid Build Coastguard Worker 
prepareResources(ResourceProvider * resourceProvider)38*c8dee2aaSAndroid Build Coastguard Worker bool DispatchGroup::prepareResources(ResourceProvider* resourceProvider) {
39*c8dee2aaSAndroid Build Coastguard Worker     fPipelines.reserve(fPipelines.size() + fPipelineDescs.size());
40*c8dee2aaSAndroid Build Coastguard Worker     for (const ComputePipelineDesc& desc : fPipelineDescs) {
41*c8dee2aaSAndroid Build Coastguard Worker         auto pipeline = resourceProvider->findOrCreateComputePipeline(desc);
42*c8dee2aaSAndroid Build Coastguard Worker         if (!pipeline) {
43*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to create ComputePipeline for dispatch group. Dropping group!");
44*c8dee2aaSAndroid Build Coastguard Worker             return false;
45*c8dee2aaSAndroid Build Coastguard Worker         }
46*c8dee2aaSAndroid Build Coastguard Worker         fPipelines.push_back(std::move(pipeline));
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fTextures.size(); ++i) {
50*c8dee2aaSAndroid Build Coastguard Worker         if (!fTextures[i]->textureInfo().isValid()) {
51*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to validate bound texture. Dropping dispatch group!");
52*c8dee2aaSAndroid Build Coastguard Worker             return false;
53*c8dee2aaSAndroid Build Coastguard Worker         }
54*c8dee2aaSAndroid Build Coastguard Worker         if (!TextureProxy::InstantiateIfNotLazy(resourceProvider, fTextures[i].get())) {
55*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to instantiate bound texture. Dropping dispatch group!");
56*c8dee2aaSAndroid Build Coastguard Worker             return false;
57*c8dee2aaSAndroid Build Coastguard Worker         }
58*c8dee2aaSAndroid Build Coastguard Worker     }
59*c8dee2aaSAndroid Build Coastguard Worker 
60*c8dee2aaSAndroid Build Coastguard Worker     for (const SamplerDesc& desc : fSamplerDescs) {
61*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<Sampler> sampler = resourceProvider->findOrCreateCompatibleSampler(desc);
62*c8dee2aaSAndroid Build Coastguard Worker         if (!sampler) {
63*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to create sampler. Dropping dispatch group!");
64*c8dee2aaSAndroid Build Coastguard Worker             return false;
65*c8dee2aaSAndroid Build Coastguard Worker         }
66*c8dee2aaSAndroid Build Coastguard Worker         fSamplers.push_back(std::move(sampler));
67*c8dee2aaSAndroid Build Coastguard Worker     }
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker     // The DispatchGroup may be long lived on a Recording and we no longer need the descriptors
70*c8dee2aaSAndroid Build Coastguard Worker     // once we've created pipelines.
71*c8dee2aaSAndroid Build Coastguard Worker     fPipelineDescs.clear();
72*c8dee2aaSAndroid Build Coastguard Worker     fSamplerDescs.clear();
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker     return true;
75*c8dee2aaSAndroid Build Coastguard Worker }
76*c8dee2aaSAndroid Build Coastguard Worker 
addResourceRefs(CommandBuffer * commandBuffer) const77*c8dee2aaSAndroid Build Coastguard Worker void DispatchGroup::addResourceRefs(CommandBuffer* commandBuffer) const {
78*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fPipelines.size(); ++i) {
79*c8dee2aaSAndroid Build Coastguard Worker         commandBuffer->trackResource(fPipelines[i]);
80*c8dee2aaSAndroid Build Coastguard Worker     }
81*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < fTextures.size(); ++i) {
82*c8dee2aaSAndroid Build Coastguard Worker         commandBuffer->trackCommandBufferResource(fTextures[i]->refTexture());
83*c8dee2aaSAndroid Build Coastguard Worker     }
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker 
snapChildTask()86*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Task> DispatchGroup::snapChildTask() {
87*c8dee2aaSAndroid Build Coastguard Worker     if (fClearList.empty()) {
88*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
89*c8dee2aaSAndroid Build Coastguard Worker     }
90*c8dee2aaSAndroid Build Coastguard Worker     return ClearBuffersTask::Make(std::move(fClearList));
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker 
getTexture(size_t index) const93*c8dee2aaSAndroid Build Coastguard Worker const Texture* DispatchGroup::getTexture(size_t index) const {
94*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(index < SkToSizeT(fTextures.size()));
95*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fTextures[index]);
96*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fTextures[index]->texture());
97*c8dee2aaSAndroid Build Coastguard Worker     return fTextures[index]->texture();
98*c8dee2aaSAndroid Build Coastguard Worker }
99*c8dee2aaSAndroid Build Coastguard Worker 
getSampler(size_t index) const100*c8dee2aaSAndroid Build Coastguard Worker const Sampler* DispatchGroup::getSampler(size_t index) const {
101*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(index < SkToSizeT(fSamplers.size()));
102*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fSamplers[index]);
103*c8dee2aaSAndroid Build Coastguard Worker     return fSamplers[index].get();
104*c8dee2aaSAndroid Build Coastguard Worker }
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker using Builder = DispatchGroup::Builder;
107*c8dee2aaSAndroid Build Coastguard Worker 
Builder(Recorder * recorder)108*c8dee2aaSAndroid Build Coastguard Worker Builder::Builder(Recorder* recorder) : fObj(new DispatchGroup()), fRecorder(recorder) {
109*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fRecorder);
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker 
appendStep(const ComputeStep * step,std::optional<WorkgroupSize> globalSize)112*c8dee2aaSAndroid Build Coastguard Worker bool Builder::appendStep(const ComputeStep* step, std::optional<WorkgroupSize> globalSize) {
113*c8dee2aaSAndroid Build Coastguard Worker     return this->appendStepInternal(step,
114*c8dee2aaSAndroid Build Coastguard Worker                                     globalSize ? *globalSize : step->calculateGlobalDispatchSize());
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker 
appendStepIndirect(const ComputeStep * step,BindBufferInfo indirectBuffer)117*c8dee2aaSAndroid Build Coastguard Worker bool Builder::appendStepIndirect(const ComputeStep* step, BindBufferInfo indirectBuffer) {
118*c8dee2aaSAndroid Build Coastguard Worker     return this->appendStepInternal(step, indirectBuffer);
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker 
appendStepInternal(const ComputeStep * step,const std::variant<WorkgroupSize,BindBufferInfo> & globalSizeOrIndirect)121*c8dee2aaSAndroid Build Coastguard Worker bool Builder::appendStepInternal(
122*c8dee2aaSAndroid Build Coastguard Worker         const ComputeStep* step,
123*c8dee2aaSAndroid Build Coastguard Worker         const std::variant<WorkgroupSize, BindBufferInfo>& globalSizeOrIndirect) {
124*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fObj);
125*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(step);
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     Dispatch dispatch;
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker     // Process the step's resources.
130*c8dee2aaSAndroid Build Coastguard Worker     auto resources = step->resources();
131*c8dee2aaSAndroid Build Coastguard Worker     dispatch.fBindings.reserve(resources.size());
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker     // `nextIndex` matches the declaration order of resources as specified by the ComputeStep.
134*c8dee2aaSAndroid Build Coastguard Worker     int nextIndex = 0;
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker     // We assign buffer, texture, and sampler indices from separate ranges. This is compatible with
137*c8dee2aaSAndroid Build Coastguard Worker     // how Graphite assigns indices on Metal, as these map directly to the buffer/texture/sampler
138*c8dee2aaSAndroid Build Coastguard Worker     // index ranges. On Dawn/Vulkan buffers and textures/samplers are allocated from separate bind
139*c8dee2aaSAndroid Build Coastguard Worker     // groups/descriptor sets but texture and sampler indices need to not overlap.
140*c8dee2aaSAndroid Build Coastguard Worker     const auto& bindingReqs = fRecorder->priv().caps()->resourceBindingRequirements();
141*c8dee2aaSAndroid Build Coastguard Worker     bool distinctRanges = bindingReqs.fDistinctIndexRanges;
142*c8dee2aaSAndroid Build Coastguard Worker     bool separateSampler = bindingReqs.fSeparateTextureAndSamplerBinding;
143*c8dee2aaSAndroid Build Coastguard Worker     int bufferOrGlobalIndex = 0;
144*c8dee2aaSAndroid Build Coastguard Worker     int texIndex = 0;
145*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: SkSL Metal codegen always assigns the same binding index to a texture and its sampler.
146*c8dee2aaSAndroid Build Coastguard Worker     // TODO: This could cause sampler indices to not be tightly packed if the sampler2D declaration
147*c8dee2aaSAndroid Build Coastguard Worker     // comes after 1 or more storage texture declarations (which don't have samplers).
148*c8dee2aaSAndroid Build Coastguard Worker     for (const ComputeStep::ResourceDesc& r : resources) {
149*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(r.fSlot == -1 || (r.fSlot >= 0 && r.fSlot < kMaxComputeDataFlowSlots));
150*c8dee2aaSAndroid Build Coastguard Worker         const int index = nextIndex++;
151*c8dee2aaSAndroid Build Coastguard Worker 
152*c8dee2aaSAndroid Build Coastguard Worker         DispatchResourceOptional maybeResource;
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker         using DataFlow = ComputeStep::DataFlow;
155*c8dee2aaSAndroid Build Coastguard Worker         using Type = ComputeStep::ResourceType;
156*c8dee2aaSAndroid Build Coastguard Worker         switch (r.fFlow) {
157*c8dee2aaSAndroid Build Coastguard Worker             case DataFlow::kPrivate:
158*c8dee2aaSAndroid Build Coastguard Worker                 // A sampled or fetched-type readonly texture must either get assigned via
159*c8dee2aaSAndroid Build Coastguard Worker                 // `assignSharedTexture()` or internally allocated as a storage texture of a
160*c8dee2aaSAndroid Build Coastguard Worker                 // preceding step. Such a texture always has a data slot.
161*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(r.fType != Type::kReadOnlyTexture);
162*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(r.fType != Type::kSampledTexture);
163*c8dee2aaSAndroid Build Coastguard Worker                 maybeResource = this->allocateResource(step, r, index);
164*c8dee2aaSAndroid Build Coastguard Worker                 break;
165*c8dee2aaSAndroid Build Coastguard Worker             case DataFlow::kShared: {
166*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(r.fSlot >= 0);
167*c8dee2aaSAndroid Build Coastguard Worker                 // Allocate a new resource only if the shared slot is empty (except for a
168*c8dee2aaSAndroid Build Coastguard Worker                 // SampledTexture which needs its sampler to be allocated internally).
169*c8dee2aaSAndroid Build Coastguard Worker                 DispatchResourceOptional* slot = &fOutputTable.fSharedSlots[r.fSlot];
170*c8dee2aaSAndroid Build Coastguard Worker                 if (std::holds_alternative<std::monostate>(*slot)) {
171*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(r.fType != Type::kReadOnlyTexture);
172*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(r.fType != Type::kSampledTexture);
173*c8dee2aaSAndroid Build Coastguard Worker                     maybeResource = this->allocateResource(step, r, index);
174*c8dee2aaSAndroid Build Coastguard Worker                     *slot = maybeResource;
175*c8dee2aaSAndroid Build Coastguard Worker                 } else {
176*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(((r.fType == Type::kUniformBuffer ||
177*c8dee2aaSAndroid Build Coastguard Worker                                r.fType == Type::kStorageBuffer ||
178*c8dee2aaSAndroid Build Coastguard Worker                                r.fType == Type::kReadOnlyStorageBuffer ||
179*c8dee2aaSAndroid Build Coastguard Worker                                r.fType == Type::kIndirectBuffer) &&
180*c8dee2aaSAndroid Build Coastguard Worker                               std::holds_alternative<BindBufferInfo>(*slot)) ||
181*c8dee2aaSAndroid Build Coastguard Worker                              ((r.fType == Type::kReadOnlyTexture ||
182*c8dee2aaSAndroid Build Coastguard Worker                                r.fType == Type::kSampledTexture ||
183*c8dee2aaSAndroid Build Coastguard Worker                                r.fType == Type::kWriteOnlyStorageTexture) &&
184*c8dee2aaSAndroid Build Coastguard Worker                               std::holds_alternative<TextureIndex>(*slot)));
185*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
186*c8dee2aaSAndroid Build Coastguard Worker                     // Ensure that the texture has the right format if it was assigned via
187*c8dee2aaSAndroid Build Coastguard Worker                     // `assignSharedTexture()`.
188*c8dee2aaSAndroid Build Coastguard Worker                     const TextureIndex* texIdx = std::get_if<TextureIndex>(slot);
189*c8dee2aaSAndroid Build Coastguard Worker                     if (texIdx && r.fType == Type::kWriteOnlyStorageTexture) {
190*c8dee2aaSAndroid Build Coastguard Worker                         const TextureProxy* t = fObj->fTextures[texIdx->fValue].get();
191*c8dee2aaSAndroid Build Coastguard Worker                         SkASSERT(t);
192*c8dee2aaSAndroid Build Coastguard Worker                         auto [_, colorType] = step->calculateTextureParameters(index, r);
193*c8dee2aaSAndroid Build Coastguard Worker                         SkASSERT(t->textureInfo().isCompatible(
194*c8dee2aaSAndroid Build Coastguard Worker                                 fRecorder->priv().caps()->getDefaultStorageTextureInfo(colorType)));
195*c8dee2aaSAndroid Build Coastguard Worker                     }
196*c8dee2aaSAndroid Build Coastguard Worker #endif  // SK_DEBUG
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker                     maybeResource = *slot;
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker                     if (r.fType == Type::kSampledTexture) {
201*c8dee2aaSAndroid Build Coastguard Worker                         // The shared slot holds the texture part of the sampled texture but we
202*c8dee2aaSAndroid Build Coastguard Worker                         // still need to allocate the sampler.
203*c8dee2aaSAndroid Build Coastguard Worker                         SkASSERT(std::holds_alternative<TextureIndex>(*slot));
204*c8dee2aaSAndroid Build Coastguard Worker                         auto samplerResource = this->allocateResource(step, r, index);
205*c8dee2aaSAndroid Build Coastguard Worker                         const SamplerIndex* samplerIdx =
206*c8dee2aaSAndroid Build Coastguard Worker                                 std::get_if<SamplerIndex>(&samplerResource);
207*c8dee2aaSAndroid Build Coastguard Worker                         SkASSERT(samplerIdx);
208*c8dee2aaSAndroid Build Coastguard Worker                         int bindingIndex = distinctRanges    ? texIndex
209*c8dee2aaSAndroid Build Coastguard Worker                                            : separateSampler ? bufferOrGlobalIndex++
210*c8dee2aaSAndroid Build Coastguard Worker                                                              : bufferOrGlobalIndex;
211*c8dee2aaSAndroid Build Coastguard Worker                         dispatch.fBindings.push_back(
212*c8dee2aaSAndroid Build Coastguard Worker                                 {static_cast<BindingIndex>(bindingIndex), *samplerIdx});
213*c8dee2aaSAndroid Build Coastguard Worker                     }
214*c8dee2aaSAndroid Build Coastguard Worker                 }
215*c8dee2aaSAndroid Build Coastguard Worker                 break;
216*c8dee2aaSAndroid Build Coastguard Worker             }
217*c8dee2aaSAndroid Build Coastguard Worker         }
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker         int bindingIndex = 0;
220*c8dee2aaSAndroid Build Coastguard Worker         DispatchResource dispatchResource;
221*c8dee2aaSAndroid Build Coastguard Worker         if (const BindBufferInfo* buffer = std::get_if<BindBufferInfo>(&maybeResource)) {
222*c8dee2aaSAndroid Build Coastguard Worker             dispatchResource = *buffer;
223*c8dee2aaSAndroid Build Coastguard Worker             bindingIndex = bufferOrGlobalIndex++;
224*c8dee2aaSAndroid Build Coastguard Worker         } else if (const TextureIndex* texIdx = std::get_if<TextureIndex>(&maybeResource)) {
225*c8dee2aaSAndroid Build Coastguard Worker             dispatchResource = *texIdx;
226*c8dee2aaSAndroid Build Coastguard Worker             bindingIndex = distinctRanges ? texIndex++ : bufferOrGlobalIndex++;
227*c8dee2aaSAndroid Build Coastguard Worker         } else {
228*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("Failed to allocate resource for compute dispatch");
229*c8dee2aaSAndroid Build Coastguard Worker             return false;
230*c8dee2aaSAndroid Build Coastguard Worker         }
231*c8dee2aaSAndroid Build Coastguard Worker         dispatch.fBindings.push_back({static_cast<BindingIndex>(bindingIndex), dispatchResource});
232*c8dee2aaSAndroid Build Coastguard Worker     }
233*c8dee2aaSAndroid Build Coastguard Worker 
234*c8dee2aaSAndroid Build Coastguard Worker     auto wgBufferDescs = step->workgroupBuffers();
235*c8dee2aaSAndroid Build Coastguard Worker     if (!wgBufferDescs.empty()) {
236*c8dee2aaSAndroid Build Coastguard Worker         dispatch.fWorkgroupBuffers.push_back_n(wgBufferDescs.size(), wgBufferDescs.data());
237*c8dee2aaSAndroid Build Coastguard Worker     }
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker     // We need to switch pipelines if this step uses a different pipeline from the previous step.
240*c8dee2aaSAndroid Build Coastguard Worker     if (fObj->fPipelineDescs.empty() ||
241*c8dee2aaSAndroid Build Coastguard Worker         fObj->fPipelineDescs.back().uniqueID() != step->uniqueID()) {
242*c8dee2aaSAndroid Build Coastguard Worker         fObj->fPipelineDescs.push_back(ComputePipelineDesc(step));
243*c8dee2aaSAndroid Build Coastguard Worker     }
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker     dispatch.fPipelineIndex = fObj->fPipelineDescs.size() - 1;
246*c8dee2aaSAndroid Build Coastguard Worker     dispatch.fLocalSize = step->localDispatchSize();
247*c8dee2aaSAndroid Build Coastguard Worker     dispatch.fGlobalSizeOrIndirect = globalSizeOrIndirect;
248*c8dee2aaSAndroid Build Coastguard Worker 
249*c8dee2aaSAndroid Build Coastguard Worker     fObj->fDispatchList.push_back(std::move(dispatch));
250*c8dee2aaSAndroid Build Coastguard Worker 
251*c8dee2aaSAndroid Build Coastguard Worker     return true;
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker 
assignSharedBuffer(BindBufferInfo buffer,unsigned int slot,ClearBuffer cleared)254*c8dee2aaSAndroid Build Coastguard Worker void Builder::assignSharedBuffer(BindBufferInfo buffer, unsigned int slot, ClearBuffer cleared) {
255*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fObj);
256*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(buffer);
257*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(buffer.fSize);
258*c8dee2aaSAndroid Build Coastguard Worker 
259*c8dee2aaSAndroid Build Coastguard Worker     fOutputTable.fSharedSlots[slot] = buffer;
260*c8dee2aaSAndroid Build Coastguard Worker     if (cleared == ClearBuffer::kYes) {
261*c8dee2aaSAndroid Build Coastguard Worker         fObj->fClearList.push_back(buffer);
262*c8dee2aaSAndroid Build Coastguard Worker     }
263*c8dee2aaSAndroid Build Coastguard Worker }
264*c8dee2aaSAndroid Build Coastguard Worker 
assignSharedTexture(sk_sp<TextureProxy> texture,unsigned int slot)265*c8dee2aaSAndroid Build Coastguard Worker void Builder::assignSharedTexture(sk_sp<TextureProxy> texture, unsigned int slot) {
266*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fObj);
267*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(texture);
268*c8dee2aaSAndroid Build Coastguard Worker 
269*c8dee2aaSAndroid Build Coastguard Worker     fObj->fTextures.push_back(std::move(texture));
270*c8dee2aaSAndroid Build Coastguard Worker     fOutputTable.fSharedSlots[slot] = TextureIndex{fObj->fTextures.size() - 1u};
271*c8dee2aaSAndroid Build Coastguard Worker }
272*c8dee2aaSAndroid Build Coastguard Worker 
finalize()273*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<DispatchGroup> Builder::finalize() {
274*c8dee2aaSAndroid Build Coastguard Worker     auto obj = std::move(fObj);
275*c8dee2aaSAndroid Build Coastguard Worker     fOutputTable.reset();
276*c8dee2aaSAndroid Build Coastguard Worker     return obj;
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
reset()280*c8dee2aaSAndroid Build Coastguard Worker void Builder::reset() {
281*c8dee2aaSAndroid Build Coastguard Worker     fOutputTable.reset();
282*c8dee2aaSAndroid Build Coastguard Worker     fObj.reset(new DispatchGroup);
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker #endif
285*c8dee2aaSAndroid Build Coastguard Worker 
getSharedBufferResource(unsigned int slot) const286*c8dee2aaSAndroid Build Coastguard Worker BindBufferInfo Builder::getSharedBufferResource(unsigned int slot) const {
287*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fObj);
288*c8dee2aaSAndroid Build Coastguard Worker 
289*c8dee2aaSAndroid Build Coastguard Worker     BindBufferInfo info;
290*c8dee2aaSAndroid Build Coastguard Worker     if (const BindBufferInfo* slotValue =
291*c8dee2aaSAndroid Build Coastguard Worker                 std::get_if<BindBufferInfo>(&fOutputTable.fSharedSlots[slot])) {
292*c8dee2aaSAndroid Build Coastguard Worker         info = *slotValue;
293*c8dee2aaSAndroid Build Coastguard Worker     }
294*c8dee2aaSAndroid Build Coastguard Worker     return info;
295*c8dee2aaSAndroid Build Coastguard Worker }
296*c8dee2aaSAndroid Build Coastguard Worker 
getSharedTextureResource(unsigned int slot) const297*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> Builder::getSharedTextureResource(unsigned int slot) const {
298*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fObj);
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker     const TextureIndex* idx = std::get_if<TextureIndex>(&fOutputTable.fSharedSlots[slot]);
301*c8dee2aaSAndroid Build Coastguard Worker     if (!idx) {
302*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
303*c8dee2aaSAndroid Build Coastguard Worker     }
304*c8dee2aaSAndroid Build Coastguard Worker 
305*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(idx->fValue < SkToSizeT(fObj->fTextures.size()));
306*c8dee2aaSAndroid Build Coastguard Worker     return fObj->fTextures[idx->fValue];
307*c8dee2aaSAndroid Build Coastguard Worker }
308*c8dee2aaSAndroid Build Coastguard Worker 
allocateResource(const ComputeStep * step,const ComputeStep::ResourceDesc & resource,int resourceIdx)309*c8dee2aaSAndroid Build Coastguard Worker DispatchResourceOptional Builder::allocateResource(const ComputeStep* step,
310*c8dee2aaSAndroid Build Coastguard Worker                                                    const ComputeStep::ResourceDesc& resource,
311*c8dee2aaSAndroid Build Coastguard Worker                                                    int resourceIdx) {
312*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(step);
313*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fObj);
314*c8dee2aaSAndroid Build Coastguard Worker     using Type = ComputeStep::ResourceType;
315*c8dee2aaSAndroid Build Coastguard Worker     using ResourcePolicy = ComputeStep::ResourcePolicy;
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker     DrawBufferManager* bufferMgr = fRecorder->priv().drawBufferManager();
318*c8dee2aaSAndroid Build Coastguard Worker     DispatchResourceOptional result;
319*c8dee2aaSAndroid Build Coastguard Worker     switch (resource.fType) {
320*c8dee2aaSAndroid Build Coastguard Worker         case Type::kReadOnlyStorageBuffer:
321*c8dee2aaSAndroid Build Coastguard Worker         case Type::kStorageBuffer: {
322*c8dee2aaSAndroid Build Coastguard Worker             size_t bufferSize = step->calculateBufferSize(resourceIdx, resource);
323*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(bufferSize);
324*c8dee2aaSAndroid Build Coastguard Worker             if (resource.fPolicy == ResourcePolicy::kMapped) {
325*c8dee2aaSAndroid Build Coastguard Worker                 auto [ptr, bufInfo] = bufferMgr->getStoragePointer(bufferSize);
326*c8dee2aaSAndroid Build Coastguard Worker                 if (ptr) {
327*c8dee2aaSAndroid Build Coastguard Worker                     step->prepareStorageBuffer(resourceIdx, resource, ptr, bufferSize);
328*c8dee2aaSAndroid Build Coastguard Worker                     result = bufInfo;
329*c8dee2aaSAndroid Build Coastguard Worker                 }
330*c8dee2aaSAndroid Build Coastguard Worker             } else {
331*c8dee2aaSAndroid Build Coastguard Worker                 auto bufInfo = bufferMgr->getStorage(bufferSize,
332*c8dee2aaSAndroid Build Coastguard Worker                                                      resource.fPolicy == ResourcePolicy::kClear
333*c8dee2aaSAndroid Build Coastguard Worker                                                              ? ClearBuffer::kYes
334*c8dee2aaSAndroid Build Coastguard Worker                                                              : ClearBuffer::kNo);
335*c8dee2aaSAndroid Build Coastguard Worker                 if (bufInfo) {
336*c8dee2aaSAndroid Build Coastguard Worker                     result = bufInfo;
337*c8dee2aaSAndroid Build Coastguard Worker                 }
338*c8dee2aaSAndroid Build Coastguard Worker             }
339*c8dee2aaSAndroid Build Coastguard Worker             break;
340*c8dee2aaSAndroid Build Coastguard Worker         }
341*c8dee2aaSAndroid Build Coastguard Worker         case Type::kIndirectBuffer: {
342*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(resource.fPolicy != ResourcePolicy::kMapped);
343*c8dee2aaSAndroid Build Coastguard Worker 
344*c8dee2aaSAndroid Build Coastguard Worker             size_t bufferSize = step->calculateBufferSize(resourceIdx, resource);
345*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(bufferSize);
346*c8dee2aaSAndroid Build Coastguard Worker             auto bufInfo = bufferMgr->getIndirectStorage(bufferSize,
347*c8dee2aaSAndroid Build Coastguard Worker                                                          resource.fPolicy == ResourcePolicy::kClear
348*c8dee2aaSAndroid Build Coastguard Worker                                                                  ? ClearBuffer::kYes
349*c8dee2aaSAndroid Build Coastguard Worker                                                                  : ClearBuffer::kNo);
350*c8dee2aaSAndroid Build Coastguard Worker             if (bufInfo) {
351*c8dee2aaSAndroid Build Coastguard Worker                 result = bufInfo;
352*c8dee2aaSAndroid Build Coastguard Worker             }
353*c8dee2aaSAndroid Build Coastguard Worker             break;
354*c8dee2aaSAndroid Build Coastguard Worker         }
355*c8dee2aaSAndroid Build Coastguard Worker         case Type::kUniformBuffer: {
356*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(resource.fPolicy == ResourcePolicy::kMapped);
357*c8dee2aaSAndroid Build Coastguard Worker 
358*c8dee2aaSAndroid Build Coastguard Worker             const auto& resourceReqs = fRecorder->priv().caps()->resourceBindingRequirements();
359*c8dee2aaSAndroid Build Coastguard Worker             UniformManager uboMgr(resourceReqs.fUniformBufferLayout);
360*c8dee2aaSAndroid Build Coastguard Worker             step->prepareUniformBuffer(resourceIdx, resource, &uboMgr);
361*c8dee2aaSAndroid Build Coastguard Worker 
362*c8dee2aaSAndroid Build Coastguard Worker             auto dataBlock = uboMgr.finish();
363*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!dataBlock.empty());
364*c8dee2aaSAndroid Build Coastguard Worker 
365*c8dee2aaSAndroid Build Coastguard Worker             auto [writer, bufInfo] = bufferMgr->getUniformWriter(/*count=*/1, dataBlock.size());
366*c8dee2aaSAndroid Build Coastguard Worker             if (bufInfo) {
367*c8dee2aaSAndroid Build Coastguard Worker                 writer.write(dataBlock.data(), dataBlock.size());
368*c8dee2aaSAndroid Build Coastguard Worker                 result = bufInfo;
369*c8dee2aaSAndroid Build Coastguard Worker             }
370*c8dee2aaSAndroid Build Coastguard Worker             break;
371*c8dee2aaSAndroid Build Coastguard Worker         }
372*c8dee2aaSAndroid Build Coastguard Worker         case Type::kWriteOnlyStorageTexture: {
373*c8dee2aaSAndroid Build Coastguard Worker             auto [size, colorType] = step->calculateTextureParameters(resourceIdx, resource);
374*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!size.isEmpty());
375*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(colorType != kUnknown_SkColorType);
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker             auto textureInfo = fRecorder->priv().caps()->getDefaultStorageTextureInfo(colorType);
378*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<TextureProxy> texture = TextureProxy::Make(
379*c8dee2aaSAndroid Build Coastguard Worker                     fRecorder->priv().caps(), fRecorder->priv().resourceProvider(),
380*c8dee2aaSAndroid Build Coastguard Worker                     size, textureInfo, "DispatchWriteOnlyStorageTexture", skgpu::Budgeted::kYes);
381*c8dee2aaSAndroid Build Coastguard Worker             if (texture) {
382*c8dee2aaSAndroid Build Coastguard Worker                 fObj->fTextures.push_back(std::move(texture));
383*c8dee2aaSAndroid Build Coastguard Worker                 result = TextureIndex{fObj->fTextures.size() - 1u};
384*c8dee2aaSAndroid Build Coastguard Worker             }
385*c8dee2aaSAndroid Build Coastguard Worker             break;
386*c8dee2aaSAndroid Build Coastguard Worker         }
387*c8dee2aaSAndroid Build Coastguard Worker         case Type::kReadOnlyTexture:
388*c8dee2aaSAndroid Build Coastguard Worker             // This resource type is meant to be populated externally (e.g. by an upload or a render
389*c8dee2aaSAndroid Build Coastguard Worker             // pass) and only read/sampled by a ComputeStep. It's not meaningful to allocate an
390*c8dee2aaSAndroid Build Coastguard Worker             // internal texture for a DispatchGroup if none of the ComputeSteps will write to it.
391*c8dee2aaSAndroid Build Coastguard Worker             //
392*c8dee2aaSAndroid Build Coastguard Worker             // Instead of using internal allocation, this texture must be assigned explicitly to a
393*c8dee2aaSAndroid Build Coastguard Worker             // slot by calling the Builder::assignSharedTexture() method.
394*c8dee2aaSAndroid Build Coastguard Worker             //
395*c8dee2aaSAndroid Build Coastguard Worker             // Note: A ComputeStep is allowed to read/sample from a storage texture that a previous
396*c8dee2aaSAndroid Build Coastguard Worker             // ComputeStep has written to.
397*c8dee2aaSAndroid Build Coastguard Worker             SK_ABORT("a readonly texture must be externally assigned to a ComputeStep");
398*c8dee2aaSAndroid Build Coastguard Worker             break;
399*c8dee2aaSAndroid Build Coastguard Worker         case Type::kSampledTexture: {
400*c8dee2aaSAndroid Build Coastguard Worker             fObj->fSamplerDescs.push_back(step->calculateSamplerParameters(resourceIdx, resource));
401*c8dee2aaSAndroid Build Coastguard Worker             result = SamplerIndex{fObj->fSamplerDescs.size() - 1u};
402*c8dee2aaSAndroid Build Coastguard Worker             break;
403*c8dee2aaSAndroid Build Coastguard Worker         }
404*c8dee2aaSAndroid Build Coastguard Worker     }
405*c8dee2aaSAndroid Build Coastguard Worker     return result;
406*c8dee2aaSAndroid Build Coastguard Worker }
407*c8dee2aaSAndroid Build Coastguard Worker 
408*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::graphite
409