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