• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 #include "src/gpu/graphite/dawn/DawnCommandBuffer.h"
9 
10 #include "src/gpu/graphite/Log.h"
11 #include "src/gpu/graphite/RenderPassDesc.h"
12 #include "src/gpu/graphite/TextureProxy.h"
13 #include "src/gpu/graphite/compute/DispatchGroup.h"
14 #include "src/gpu/graphite/dawn/DawnBuffer.h"
15 #include "src/gpu/graphite/dawn/DawnCaps.h"
16 #include "src/gpu/graphite/dawn/DawnComputePipeline.h"
17 #include "src/gpu/graphite/dawn/DawnGraphicsPipeline.h"
18 #include "src/gpu/graphite/dawn/DawnGraphiteUtilsPriv.h"
19 #include "src/gpu/graphite/dawn/DawnQueueManager.h"
20 #include "src/gpu/graphite/dawn/DawnResourceProvider.h"
21 #include "src/gpu/graphite/dawn/DawnSampler.h"
22 #include "src/gpu/graphite/dawn/DawnSharedContext.h"
23 #include "src/gpu/graphite/dawn/DawnTexture.h"
24 
25 namespace skgpu::graphite {
26 
27 namespace {
28 
29 using IntrinsicConstant = float[4];
30 
31 constexpr int kBufferBindingOffsetAlignment = 256;
32 
33 constexpr int kIntrinsicConstantAlignedSize =
34         SkAlignTo(sizeof(IntrinsicConstant), kBufferBindingOffsetAlignment);
35 
36 #if defined(__EMSCRIPTEN__)
37 // When running against WebGPU in WASM we don't have the wgpu::CommandBuffer::WriteBuffer method. We
38 // allocate a fixed size buffer to hold the intrinsics constants. If we overflow we allocate another
39 // buffer.
40 constexpr int kNumSlotsForIntrinsicConstantBuffer = 8;
41 #endif
42 
43 }  // namespace
44 
Make(const DawnSharedContext * sharedContext,DawnResourceProvider * resourceProvider)45 std::unique_ptr<DawnCommandBuffer> DawnCommandBuffer::Make(const DawnSharedContext* sharedContext,
46                                                            DawnResourceProvider* resourceProvider) {
47     std::unique_ptr<DawnCommandBuffer> cmdBuffer(
48             new DawnCommandBuffer(sharedContext, resourceProvider));
49     if (!cmdBuffer->setNewCommandBufferResources()) {
50         return {};
51     }
52     return cmdBuffer;
53 }
54 
DawnCommandBuffer(const DawnSharedContext * sharedContext,DawnResourceProvider * resourceProvider)55 DawnCommandBuffer::DawnCommandBuffer(const DawnSharedContext* sharedContext,
56                                      DawnResourceProvider* resourceProvider)
57         : fSharedContext(sharedContext)
58         , fResourceProvider(resourceProvider) {}
59 
~DawnCommandBuffer()60 DawnCommandBuffer::~DawnCommandBuffer() {}
61 
finishEncoding()62 wgpu::CommandBuffer DawnCommandBuffer::finishEncoding() {
63     SkASSERT(fCommandEncoder);
64     wgpu::CommandBuffer cmdBuffer = fCommandEncoder.Finish();
65 
66     fCommandEncoder = nullptr;
67 
68     return cmdBuffer;
69 }
70 
onResetCommandBuffer()71 void DawnCommandBuffer::onResetCommandBuffer() {
72     fIntrinsicConstantBuffer = nullptr;
73 
74     fActiveGraphicsPipeline = nullptr;
75     fActiveRenderPassEncoder = nullptr;
76     fActiveComputePassEncoder = nullptr;
77     fCommandEncoder = nullptr;
78 
79     for (auto& bufferSlot : fBoundUniformBuffers) {
80         bufferSlot = nullptr;
81     }
82     fBoundUniformBuffersDirty = true;
83 }
84 
setNewCommandBufferResources()85 bool DawnCommandBuffer::setNewCommandBufferResources() {
86     SkASSERT(!fCommandEncoder);
87     fCommandEncoder = fSharedContext->device().CreateCommandEncoder();
88     SkASSERT(fCommandEncoder);
89     return true;
90 }
91 
onAddRenderPass(const RenderPassDesc & renderPassDesc,const Texture * colorTexture,const Texture * resolveTexture,const Texture * depthStencilTexture,SkRect viewport,const DrawPassList & drawPasses)92 bool DawnCommandBuffer::onAddRenderPass(const RenderPassDesc& renderPassDesc,
93                                         const Texture* colorTexture,
94                                         const Texture* resolveTexture,
95                                         const Texture* depthStencilTexture,
96                                         SkRect viewport,
97                                         const DrawPassList& drawPasses) {
98     // Update viewport's constant buffer before starting a render pass.
99     this->preprocessViewport(viewport);
100 
101     if (!this->beginRenderPass(renderPassDesc, colorTexture, resolveTexture, depthStencilTexture)) {
102         return false;
103     }
104 
105     this->setViewport(viewport);
106 
107     for (const auto& drawPass : drawPasses) {
108         if (!this->addDrawPass(drawPass.get())) SK_UNLIKELY {
109             this->endRenderPass();
110             return false;
111         }
112     }
113 
114     this->endRenderPass();
115     return true;
116 }
117 
onAddComputePass(DispatchGroupSpan groups)118 bool DawnCommandBuffer::onAddComputePass(DispatchGroupSpan groups) {
119     this->beginComputePass();
120     for (const auto& group : groups) {
121         group->addResourceRefs(this);
122         for (const auto& dispatch : group->dispatches()) {
123             this->bindComputePipeline(group->getPipeline(dispatch.fPipelineIndex));
124             this->bindDispatchResources(*group, dispatch);
125             if (const WorkgroupSize* globalSize =
126                         std::get_if<WorkgroupSize>(&dispatch.fGlobalSizeOrIndirect)) {
127                 this->dispatchWorkgroups(*globalSize);
128             } else {
129                 SkASSERT(std::holds_alternative<BufferView>(dispatch.fGlobalSizeOrIndirect));
130                 const BufferView& indirect =
131                         *std::get_if<BufferView>(&dispatch.fGlobalSizeOrIndirect);
132                 this->dispatchWorkgroupsIndirect(indirect.fInfo.fBuffer, indirect.fInfo.fOffset);
133             }
134         }
135     }
136     this->endComputePass();
137     return true;
138 }
139 
beginRenderPass(const RenderPassDesc & renderPassDesc,const Texture * colorTexture,const Texture * resolveTexture,const Texture * depthStencilTexture)140 bool DawnCommandBuffer::beginRenderPass(const RenderPassDesc& renderPassDesc,
141                                         const Texture* colorTexture,
142                                         const Texture* resolveTexture,
143                                         const Texture* depthStencilTexture) {
144     SkASSERT(!fActiveRenderPassEncoder);
145     SkASSERT(!fActiveComputePassEncoder);
146 
147     constexpr static wgpu::LoadOp wgpuLoadActionMap[]{
148             wgpu::LoadOp::Load,
149             wgpu::LoadOp::Clear,
150             wgpu::LoadOp::Clear  // Don't care
151     };
152     static_assert((int)LoadOp::kLoad == 0);
153     static_assert((int)LoadOp::kClear == 1);
154     static_assert((int)LoadOp::kDiscard == 2);
155     static_assert(std::size(wgpuLoadActionMap) == kLoadOpCount);
156 
157     constexpr static wgpu::StoreOp wgpuStoreActionMap[]{wgpu::StoreOp::Store,
158                                                         wgpu::StoreOp::Discard};
159     static_assert((int)StoreOp::kStore == 0);
160     static_assert((int)StoreOp::kDiscard == 1);
161     static_assert(std::size(wgpuStoreActionMap) == kStoreOpCount);
162 
163     wgpu::RenderPassDescriptor wgpuRenderPass = {};
164     wgpu::RenderPassColorAttachment wgpuColorAttachment;
165     wgpu::RenderPassDepthStencilAttachment wgpuDepthStencilAttachment;
166 
167     // Set up color attachment.
168 #if !defined(__EMSCRIPTEN__)
169     wgpu::DawnRenderPassColorAttachmentRenderToSingleSampled mssaRenderToSingleSampledDesc;
170 #endif
171 
172     auto& colorInfo = renderPassDesc.fColorAttachment;
173     bool loadMSAAFromResolveExplicitly = false;
174     if (colorTexture) {
175         wgpuRenderPass.colorAttachments = &wgpuColorAttachment;
176         wgpuRenderPass.colorAttachmentCount = 1;
177 
178         // TODO: check Texture matches RenderPassDesc
179         const auto* dawnColorTexture = static_cast<const DawnTexture*>(colorTexture);
180         SkASSERT(dawnColorTexture->renderTextureView());
181         wgpuColorAttachment.view = dawnColorTexture->renderTextureView();
182 
183         const std::array<float, 4>& clearColor = renderPassDesc.fClearColor;
184         wgpuColorAttachment.clearValue = {
185                 clearColor[0], clearColor[1], clearColor[2], clearColor[3]};
186         wgpuColorAttachment.loadOp = wgpuLoadActionMap[static_cast<int>(colorInfo.fLoadOp)];
187         wgpuColorAttachment.storeOp = wgpuStoreActionMap[static_cast<int>(colorInfo.fStoreOp)];
188 
189         // Set up resolve attachment
190         if (resolveTexture) {
191             SkASSERT(renderPassDesc.fColorResolveAttachment.fStoreOp == StoreOp::kStore);
192             // TODO: check Texture matches RenderPassDesc
193             const auto* dawnResolveTexture = static_cast<const DawnTexture*>(resolveTexture);
194             SkASSERT(dawnResolveTexture->renderTextureView());
195             wgpuColorAttachment.resolveTarget = dawnResolveTexture->renderTextureView();
196 
197             // Inclusion of a resolve texture implies the client wants to finish the
198             // renderpass with a resolve.
199             SkASSERT(wgpuColorAttachment.storeOp == wgpu::StoreOp::Discard);
200 
201             // But it also means we have to load the resolve texture into the MSAA color attachment
202             if (renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad) {
203                 std::optional<wgpu::LoadOp> resolveLoadOp =
204                         fSharedContext->dawnCaps()->resolveTextureLoadOp();
205                 if (resolveLoadOp.has_value()) {
206                     wgpuColorAttachment.loadOp = *resolveLoadOp;
207                 } else {
208                     // No Dawn built-in support, we need to manually load the resolve texture.
209                     loadMSAAFromResolveExplicitly = true;
210                 }
211             }
212             // TODO: If the color resolve texture is read-only we can use a private (vs. memoryless)
213             // msaa attachment that's coupled to the framebuffer and the StoreAndMultisampleResolve
214             // action instead of loading as a draw.
215         } else {
216             [[maybe_unused]] bool isMSAAToSingleSampled = renderPassDesc.fSampleCount > 1 &&
217                                                           colorTexture->numSamples() == 1;
218 #if defined(__EMSCRIPTEN__)
219             SkASSERT(!isMSAAToSingleSampled);
220 #else
221             if (isMSAAToSingleSampled) {
222                 // If render pass is multi sampled but the color attachment is single sampled, we
223                 // need to activate multisampled render to single sampled feature for this render
224                 // pass.
225                 SkASSERT(fSharedContext->device().HasFeature(
226                         wgpu::FeatureName::MSAARenderToSingleSampled));
227 
228                 wgpuColorAttachment.nextInChain = &mssaRenderToSingleSampledDesc;
229                 mssaRenderToSingleSampledDesc.implicitSampleCount = renderPassDesc.fSampleCount;
230             }
231 #endif
232         }
233     }
234 
235     // Set up stencil/depth attachment
236     auto& depthStencilInfo = renderPassDesc.fDepthStencilAttachment;
237     if (depthStencilTexture) {
238         const auto* dawnDepthStencilTexture = static_cast<const DawnTexture*>(depthStencilTexture);
239         auto format = dawnDepthStencilTexture->textureInfo().dawnTextureSpec().getViewFormat();
240         SkASSERT(DawnFormatIsDepthOrStencil(format));
241 
242         // TODO: check Texture matches RenderPassDesc
243         SkASSERT(dawnDepthStencilTexture->renderTextureView());
244         wgpuDepthStencilAttachment.view = dawnDepthStencilTexture->renderTextureView();
245 
246         if (DawnFormatIsDepth(format)) {
247             wgpuDepthStencilAttachment.depthClearValue = renderPassDesc.fClearDepth;
248             wgpuDepthStencilAttachment.depthLoadOp =
249                     wgpuLoadActionMap[static_cast<int>(depthStencilInfo.fLoadOp)];
250             wgpuDepthStencilAttachment.depthStoreOp =
251                     wgpuStoreActionMap[static_cast<int>(depthStencilInfo.fStoreOp)];
252         }
253 
254         if (DawnFormatIsStencil(format)) {
255             wgpuDepthStencilAttachment.stencilClearValue = renderPassDesc.fClearStencil;
256             wgpuDepthStencilAttachment.stencilLoadOp =
257                     wgpuLoadActionMap[static_cast<int>(depthStencilInfo.fLoadOp)];
258             wgpuDepthStencilAttachment.stencilStoreOp =
259                     wgpuStoreActionMap[static_cast<int>(depthStencilInfo.fStoreOp)];
260         }
261 
262         wgpuRenderPass.depthStencilAttachment = &wgpuDepthStencilAttachment;
263     } else {
264         SkASSERT(!depthStencilInfo.fTextureInfo.isValid());
265     }
266 
267     if (loadMSAAFromResolveExplicitly) {
268         // Manually load the contents of the resolve texture into the MSAA attachment as a draw,
269         // so the actual load op for the MSAA attachment had better have been discard.
270 
271         if (!this->loadMSAAFromResolveAndBeginRenderPassEncoder(
272                     renderPassDesc,
273                     wgpuRenderPass,
274                     static_cast<const DawnTexture*>(colorTexture))) {
275             return false;
276         }
277     }
278     else {
279         fActiveRenderPassEncoder = fCommandEncoder.BeginRenderPass(&wgpuRenderPass);
280     }
281 
282     return true;
283 }
284 
loadMSAAFromResolveAndBeginRenderPassEncoder(const RenderPassDesc & frontendRenderPassDesc,const wgpu::RenderPassDescriptor & wgpuRenderPassDesc,const DawnTexture * msaaTexture)285 bool DawnCommandBuffer::loadMSAAFromResolveAndBeginRenderPassEncoder(
286         const RenderPassDesc& frontendRenderPassDesc,
287         const wgpu::RenderPassDescriptor& wgpuRenderPassDesc,
288         const DawnTexture* msaaTexture) {
289     SkASSERT(!fActiveRenderPassEncoder);
290 
291     // Copy from resolve texture to an intermediate texture. Using blit with draw
292     // pipeline because the resolveTexture might be created from a swapchain, and it
293     // is possible that only its texture view is available. So onCopyTextureToTexture()
294     // which operates on wgpu::Texture instead of wgpu::TextureView cannot be used in that case.
295     auto msaaLoadTexture = fResourceProvider->findOrCreateDiscardableMSAALoadTexture(
296             msaaTexture->dimensions(), msaaTexture->textureInfo());
297     if (!msaaLoadTexture) {
298         SKGPU_LOG_E("DawnCommandBuffer::loadMSAAFromResolveAndBeginRenderPassEncoder: "
299                     "Can't create MSAA Load Texture.");
300         return false;
301     }
302 
303     this->trackCommandBufferResource(msaaLoadTexture);
304 
305     // Creating intermediate render pass (copy from resolve texture -> MSAA load texture)
306     RenderPassDesc intermediateRenderPassDesc = {};
307     intermediateRenderPassDesc.fColorAttachment.fLoadOp = LoadOp::kDiscard;
308     intermediateRenderPassDesc.fColorAttachment.fStoreOp = StoreOp::kStore;
309     intermediateRenderPassDesc.fColorAttachment.fTextureInfo =
310             frontendRenderPassDesc.fColorResolveAttachment.fTextureInfo;
311 
312     wgpu::RenderPassColorAttachment wgpuIntermediateColorAttachment;
313      // Dawn doesn't support actual DontCare so use LoadOp::Clear.
314     wgpuIntermediateColorAttachment.loadOp = wgpu::LoadOp::Clear;
315     wgpuIntermediateColorAttachment.clearValue = {1, 1, 1, 1};
316     wgpuIntermediateColorAttachment.storeOp = wgpu::StoreOp::Store;
317     wgpuIntermediateColorAttachment.view = msaaLoadTexture->renderTextureView();
318 
319     wgpu::RenderPassDescriptor wgpuIntermediateRenderPassDesc;
320     wgpuIntermediateRenderPassDesc.colorAttachmentCount = 1;
321     wgpuIntermediateRenderPassDesc.colorAttachments = &wgpuIntermediateColorAttachment;
322 
323     auto renderPassEncoder = fCommandEncoder.BeginRenderPass(&wgpuIntermediateRenderPassDesc);
324 
325     bool blitSucceeded = this->doBlitWithDraw(
326             renderPassEncoder,
327             intermediateRenderPassDesc,
328             /*sourceTextureView=*/wgpuRenderPassDesc.colorAttachments[0].resolveTarget,
329             msaaTexture->dimensions().width(),
330             msaaTexture->dimensions().height());
331 
332     renderPassEncoder.End();
333 
334     if (!blitSucceeded) {
335         return false;
336     }
337 
338     // Start actual render pass (blit from MSAA load texture -> MSAA texture)
339     renderPassEncoder = fCommandEncoder.BeginRenderPass(&wgpuRenderPassDesc);
340 
341     if (!this->doBlitWithDraw(renderPassEncoder,
342                               frontendRenderPassDesc,
343                               /*sourceTextureView=*/msaaLoadTexture->renderTextureView(),
344                               msaaTexture->dimensions().width(),
345                               msaaTexture->dimensions().height())) {
346         renderPassEncoder.End();
347         return false;
348     }
349 
350     fActiveRenderPassEncoder = renderPassEncoder;
351 
352     return true;
353 }
354 
doBlitWithDraw(const wgpu::RenderPassEncoder & renderEncoder,const RenderPassDesc & frontendRenderPassDesc,const wgpu::TextureView & sourceTextureView,int width,int height)355 bool DawnCommandBuffer::doBlitWithDraw(const wgpu::RenderPassEncoder& renderEncoder,
356                                        const RenderPassDesc& frontendRenderPassDesc,
357                                        const wgpu::TextureView& sourceTextureView,
358                                        int width,
359                                        int height) {
360     auto loadPipeline = fResourceProvider->findOrCreateBlitWithDrawPipeline(frontendRenderPassDesc);
361     if (!loadPipeline) {
362         SKGPU_LOG_E("Unable to create pipeline to blit with draw");
363         return false;
364     }
365 
366     SkASSERT(renderEncoder);
367 
368     renderEncoder.SetPipeline(loadPipeline);
369 
370     // The load msaa pipeline takes no uniforms, no vertex/instance attributes and only uses
371     // one texture that does not require a sampler.
372 
373     // TODO: b/260368758
374     // cache single texture's bind group creation.
375     wgpu::BindGroupEntry entry;
376     entry.binding = 0;
377     entry.textureView = sourceTextureView;
378 
379     wgpu::BindGroupDescriptor desc;
380     desc.layout = loadPipeline.GetBindGroupLayout(0);
381     desc.entryCount = 1;
382     desc.entries = &entry;
383 
384     auto bindGroup = fSharedContext->device().CreateBindGroup(&desc);
385 
386     renderEncoder.SetBindGroup(0, bindGroup);
387 
388     renderEncoder.SetScissorRect(0, 0, width, height);
389     renderEncoder.SetViewport(0, 0, width, height, 0, 1);
390 
391     // Fullscreen triangle
392     renderEncoder.Draw(3);
393 
394     return true;
395 }
396 
endRenderPass()397 void DawnCommandBuffer::endRenderPass() {
398     SkASSERT(fActiveRenderPassEncoder);
399     fActiveRenderPassEncoder.End();
400     fActiveRenderPassEncoder = nullptr;
401 }
402 
addDrawPass(const DrawPass * drawPass)403 bool DawnCommandBuffer::addDrawPass(const DrawPass* drawPass) {
404     drawPass->addResourceRefs(this);
405     for (auto [type, cmdPtr] : drawPass->commands()) {
406         switch (type) {
407             case DrawPassCommands::Type::kBindGraphicsPipeline: {
408                 auto bgp = static_cast<DrawPassCommands::BindGraphicsPipeline*>(cmdPtr);
409                 if (!this->bindGraphicsPipeline(drawPass->getPipeline(bgp->fPipelineIndex)))
410                     SK_UNLIKELY { return false; }
411                 break;
412             }
413             case DrawPassCommands::Type::kSetBlendConstants: {
414                 auto sbc = static_cast<DrawPassCommands::SetBlendConstants*>(cmdPtr);
415                 this->setBlendConstants(sbc->fBlendConstants);
416                 break;
417             }
418             case DrawPassCommands::Type::kBindUniformBuffer: {
419                 auto bub = static_cast<DrawPassCommands::BindUniformBuffer*>(cmdPtr);
420                 this->bindUniformBuffer(bub->fInfo, bub->fSlot);
421                 break;
422             }
423             case DrawPassCommands::Type::kBindDrawBuffers: {
424                 auto bdb = static_cast<DrawPassCommands::BindDrawBuffers*>(cmdPtr);
425                 this->bindDrawBuffers(
426                         bdb->fVertices, bdb->fInstances, bdb->fIndices, bdb->fIndirect);
427                 break;
428             }
429             case DrawPassCommands::Type::kBindTexturesAndSamplers: {
430                 auto bts = static_cast<DrawPassCommands::BindTexturesAndSamplers*>(cmdPtr);
431                 bindTextureAndSamplers(*drawPass, *bts);
432                 break;
433             }
434             case DrawPassCommands::Type::kSetScissor: {
435                 auto ss = static_cast<DrawPassCommands::SetScissor*>(cmdPtr);
436                 const SkIRect& rect = ss->fScissor;
437                 this->setScissor(rect.fLeft, rect.fTop, rect.width(), rect.height());
438                 break;
439             }
440             case DrawPassCommands::Type::kDraw: {
441                 auto draw = static_cast<DrawPassCommands::Draw*>(cmdPtr);
442                 this->draw(draw->fType, draw->fBaseVertex, draw->fVertexCount);
443                 break;
444             }
445             case DrawPassCommands::Type::kDrawIndexed: {
446                 auto draw = static_cast<DrawPassCommands::DrawIndexed*>(cmdPtr);
447                 this->drawIndexed(
448                         draw->fType, draw->fBaseIndex, draw->fIndexCount, draw->fBaseVertex);
449                 break;
450             }
451             case DrawPassCommands::Type::kDrawInstanced: {
452                 auto draw = static_cast<DrawPassCommands::DrawInstanced*>(cmdPtr);
453                 this->drawInstanced(draw->fType,
454                                     draw->fBaseVertex,
455                                     draw->fVertexCount,
456                                     draw->fBaseInstance,
457                                     draw->fInstanceCount);
458                 break;
459             }
460             case DrawPassCommands::Type::kDrawIndexedInstanced: {
461                 auto draw = static_cast<DrawPassCommands::DrawIndexedInstanced*>(cmdPtr);
462                 this->drawIndexedInstanced(draw->fType,
463                                            draw->fBaseIndex,
464                                            draw->fIndexCount,
465                                            draw->fBaseVertex,
466                                            draw->fBaseInstance,
467                                            draw->fInstanceCount);
468                 break;
469             }
470             case DrawPassCommands::Type::kDrawIndirect: {
471                 auto draw = static_cast<DrawPassCommands::DrawIndirect*>(cmdPtr);
472                 this->drawIndirect(draw->fType);
473                 break;
474             }
475             case DrawPassCommands::Type::kDrawIndexedIndirect: {
476                 auto draw = static_cast<DrawPassCommands::DrawIndexedIndirect*>(cmdPtr);
477                 this->drawIndexedIndirect(draw->fType);
478                 break;
479             }
480         }
481     }
482 
483     return true;
484 }
485 
bindGraphicsPipeline(const GraphicsPipeline * graphicsPipeline)486 bool DawnCommandBuffer::bindGraphicsPipeline(const GraphicsPipeline* graphicsPipeline) {
487     SkASSERT(fActiveRenderPassEncoder);
488 
489     auto* dawnGraphicsPipeline = static_cast<const DawnGraphicsPipeline*>(graphicsPipeline);
490     auto& wgpuPipeline = dawnGraphicsPipeline->dawnRenderPipeline();
491     if (!wgpuPipeline) SK_UNLIKELY {
492         return false;
493     }
494     fActiveGraphicsPipeline = dawnGraphicsPipeline;
495     fActiveRenderPassEncoder.SetPipeline(wgpuPipeline);
496     fBoundUniformBuffersDirty = true;
497 
498     return true;
499 }
500 
bindUniformBuffer(const BindUniformBufferInfo & info,UniformSlot slot)501 void DawnCommandBuffer::bindUniformBuffer(const BindUniformBufferInfo& info, UniformSlot slot) {
502     SkASSERT(fActiveRenderPassEncoder);
503 
504     auto dawnBuffer = static_cast<const DawnBuffer*>(info.fBuffer);
505 
506     unsigned int bufferIndex = 0;
507     switch (slot) {
508         case UniformSlot::kRenderStep:
509             bufferIndex = DawnGraphicsPipeline::kRenderStepUniformBufferIndex;
510             break;
511         case UniformSlot::kPaint:
512             bufferIndex = DawnGraphicsPipeline::kPaintUniformBufferIndex;
513             break;
514         case UniformSlot::kGradient:
515             bufferIndex = DawnGraphicsPipeline::kGradientBufferIndex;
516             break;
517         default:
518             SkASSERT(false);
519     }
520 
521     fBoundUniformBuffers[bufferIndex] = dawnBuffer;
522     fBoundUniformBufferOffsets[bufferIndex] = static_cast<uint32_t>(info.fOffset);
523     fBoundUniformBufferSizes[bufferIndex] = info.fBindingSize;
524 
525     fBoundUniformBuffersDirty = true;
526 }
527 
bindDrawBuffers(const BindBufferInfo & vertices,const BindBufferInfo & instances,const BindBufferInfo & indices,const BindBufferInfo & indirect)528 void DawnCommandBuffer::bindDrawBuffers(const BindBufferInfo& vertices,
529                                         const BindBufferInfo& instances,
530                                         const BindBufferInfo& indices,
531                                         const BindBufferInfo& indirect) {
532     SkASSERT(fActiveRenderPassEncoder);
533 
534     if (vertices.fBuffer) {
535         auto dawnBuffer = static_cast<const DawnBuffer*>(vertices.fBuffer)->dawnBuffer();
536         fActiveRenderPassEncoder.SetVertexBuffer(
537                 DawnGraphicsPipeline::kVertexBufferIndex, dawnBuffer, vertices.fOffset);
538     }
539     if (instances.fBuffer) {
540         auto dawnBuffer = static_cast<const DawnBuffer*>(instances.fBuffer)->dawnBuffer();
541         fActiveRenderPassEncoder.SetVertexBuffer(
542                 DawnGraphicsPipeline::kInstanceBufferIndex, dawnBuffer, instances.fOffset);
543     }
544     if (indices.fBuffer) {
545         auto dawnBuffer = static_cast<const DawnBuffer*>(indices.fBuffer)->dawnBuffer();
546         fActiveRenderPassEncoder.SetIndexBuffer(
547                 dawnBuffer, wgpu::IndexFormat::Uint16, indices.fOffset);
548     }
549     if (indirect.fBuffer) {
550         fCurrentIndirectBuffer = static_cast<const DawnBuffer*>(indirect.fBuffer)->dawnBuffer();
551         fCurrentIndirectBufferOffset = indirect.fOffset;
552     } else {
553         fCurrentIndirectBuffer = nullptr;
554         fCurrentIndirectBufferOffset = 0;
555     }
556 }
557 
bindTextureAndSamplers(const DrawPass & drawPass,const DrawPassCommands::BindTexturesAndSamplers & command)558 void DawnCommandBuffer::bindTextureAndSamplers(
559         const DrawPass& drawPass, const DrawPassCommands::BindTexturesAndSamplers& command) {
560     SkASSERT(fActiveRenderPassEncoder);
561     SkASSERT(fActiveGraphicsPipeline);
562 
563     wgpu::BindGroup bindGroup;
564     if (command.fNumTexSamplers == 1) {
565         // Optimize for single texture.
566         SkASSERT(fActiveGraphicsPipeline->numTexturesAndSamplers() == 2);
567 
568         const auto* texture =
569                 static_cast<const DawnTexture*>(drawPass.getTexture(command.fTextureIndices[0]));
570         const auto* sampler =
571                 static_cast<const DawnSampler*>(drawPass.getSampler(command.fSamplerIndices[0]));
572 
573         bindGroup = fResourceProvider->findOrCreateSingleTextureSamplerBindGroup(sampler, texture);
574     } else {
575         std::vector<wgpu::BindGroupEntry> entries(2 * command.fNumTexSamplers);
576 
577         for (int i = 0; i < command.fNumTexSamplers; ++i) {
578             const auto* texture = static_cast<const DawnTexture*>(
579                     drawPass.getTexture(command.fTextureIndices[i]));
580             const auto* sampler = static_cast<const DawnSampler*>(
581                     drawPass.getSampler(command.fSamplerIndices[i]));
582             auto& wgpuTextureView = texture->sampleTextureView();
583             auto& wgpuSampler = sampler->dawnSampler();
584 
585             // Assuming shader generator assigns binding slot to sampler then texture,
586             // then the next sampler and texture, and so on, we need to use
587             // 2 * i as base binding index of the sampler and texture.
588             // TODO: https://b.corp.google.com/issues/259457090:
589             // Better configurable way of assigning samplers and textures' bindings.
590             entries[2 * i].binding = 2 * i;
591             entries[2 * i].sampler = wgpuSampler;
592 
593             entries[2 * i + 1].binding = 2 * i + 1;
594             entries[2 * i + 1].textureView = wgpuTextureView;
595         }
596 
597         wgpu::BindGroupDescriptor desc;
598         const auto& groupLayouts = fActiveGraphicsPipeline->dawnGroupLayouts();
599         desc.layout = groupLayouts[DawnGraphicsPipeline::kTextureBindGroupIndex];
600         desc.entryCount = entries.size();
601         desc.entries = entries.data();
602 
603         bindGroup = fSharedContext->device().CreateBindGroup(&desc);
604     }
605 
606     fActiveRenderPassEncoder.SetBindGroup(DawnGraphicsPipeline::kTextureBindGroupIndex, bindGroup);
607 }
608 
syncUniformBuffers()609 void DawnCommandBuffer::syncUniformBuffers() {
610     if (fBoundUniformBuffersDirty) {
611         fBoundUniformBuffersDirty = false;
612 
613         std::array<uint32_t, 4> dynamicOffsets;
614         std::array<std::pair<const DawnBuffer*, uint32_t>, 4> boundBuffersAndSizes;
615         boundBuffersAndSizes[0].first = fIntrinsicConstantBuffer.get();
616         boundBuffersAndSizes[0].second = sizeof(IntrinsicConstant);
617 
618         int activeIntrinsicBufferSlot = fIntrinsicConstantBufferSlotsUsed - 1;
619         dynamicOffsets[0] = activeIntrinsicBufferSlot * kIntrinsicConstantAlignedSize;
620 
621         if (fActiveGraphicsPipeline->hasStepUniforms() &&
622             fBoundUniformBuffers[DawnGraphicsPipeline::kRenderStepUniformBufferIndex]) {
623             boundBuffersAndSizes[1].first =
624                     fBoundUniformBuffers[DawnGraphicsPipeline::kRenderStepUniformBufferIndex];
625             boundBuffersAndSizes[1].second =
626                     fBoundUniformBufferSizes[DawnGraphicsPipeline::kRenderStepUniformBufferIndex];
627             dynamicOffsets[1] =
628                     fBoundUniformBufferOffsets[DawnGraphicsPipeline::kRenderStepUniformBufferIndex];
629         } else {
630             // Unused buffer entry
631             boundBuffersAndSizes[1].first = nullptr;
632             dynamicOffsets[1] = 0;
633         }
634 
635         if (fActiveGraphicsPipeline->hasPaintUniforms() &&
636             fBoundUniformBuffers[DawnGraphicsPipeline::kPaintUniformBufferIndex]) {
637             boundBuffersAndSizes[2].first =
638                     fBoundUniformBuffers[DawnGraphicsPipeline::kPaintUniformBufferIndex];
639             boundBuffersAndSizes[2].second =
640                     fBoundUniformBufferSizes[DawnGraphicsPipeline::kPaintUniformBufferIndex];
641             dynamicOffsets[2] =
642                     fBoundUniformBufferOffsets[DawnGraphicsPipeline::kPaintUniformBufferIndex];
643         } else {
644             // Unused buffer entry
645             boundBuffersAndSizes[2].first = nullptr;
646             dynamicOffsets[2] = 0;
647         }
648 
649         if (fActiveGraphicsPipeline->hasGradientBuffer() &&
650             fBoundUniformBuffers[DawnGraphicsPipeline::kGradientBufferIndex]) {
651             boundBuffersAndSizes[3].first =
652                     fBoundUniformBuffers[DawnGraphicsPipeline::kGradientBufferIndex];
653             boundBuffersAndSizes[3].second =
654                     fBoundUniformBufferSizes[DawnGraphicsPipeline::kGradientBufferIndex];
655             dynamicOffsets[3] =
656                     fBoundUniformBufferOffsets[DawnGraphicsPipeline::kGradientBufferIndex];
657         } else {
658             // Unused buffer entry
659             boundBuffersAndSizes[3].first = nullptr;
660             dynamicOffsets[3] = 0;
661         }
662 
663         auto bindGroup =
664                 fResourceProvider->findOrCreateUniformBuffersBindGroup(boundBuffersAndSizes);
665 
666         fActiveRenderPassEncoder.SetBindGroup(DawnGraphicsPipeline::kUniformBufferBindGroupIndex,
667                                               bindGroup,
668                                               dynamicOffsets.size(),
669                                               dynamicOffsets.data());
670     }
671 }
672 
setScissor(unsigned int left,unsigned int top,unsigned int width,unsigned int height)673 void DawnCommandBuffer::setScissor(unsigned int left,
674                                    unsigned int top,
675                                    unsigned int width,
676                                    unsigned int height) {
677     SkASSERT(fActiveRenderPassEncoder);
678     SkIRect scissor = SkIRect::MakeXYWH(
679             left + fReplayTranslation.x(), top + fReplayTranslation.y(), width, height);
680     if (!scissor.intersect(SkIRect::MakeSize(fRenderPassSize))) {
681         scissor.setEmpty();
682     }
683     fActiveRenderPassEncoder.SetScissorRect(
684             scissor.x(), scissor.y(), scissor.width(), scissor.height());
685 }
686 
preprocessViewport(const SkRect & viewport)687 void DawnCommandBuffer::preprocessViewport(const SkRect& viewport) {
688     // Dawn's framebuffer space has (0, 0) at the top left. This agrees with Skia's device coords.
689     // However, in NDC (-1, -1) is the bottom left. So we flip the origin here (assuming all
690     // surfaces we have are TopLeft origin).
691     const float x = viewport.x() - fReplayTranslation.x();
692     const float y = viewport.y() - fReplayTranslation.y();
693     const float invTwoW = 2.f / viewport.width();
694     const float invTwoH = 2.f / viewport.height();
695     const IntrinsicConstant rtAdjust = {invTwoW, -invTwoH, -1.f - x * invTwoW, 1.f + y * invTwoH};
696 
697     // TODO: https://b.corp.google.com/issues/259267703
698     // Make updating intrinsic constants faster. Metal has setVertexBytes method
699     // to quickly sending intrinsic constants to vertex shader without any buffer. But Dawn doesn't
700     // have similar capability. So we have to use WriteBuffer(), and this method is not allowed to
701     // be called when there is an active render pass.
702     SkASSERT(!fActiveRenderPassEncoder);
703     SkASSERT(!fActiveComputePassEncoder);
704 
705 #if !defined(__EMSCRIPTEN__)
706     if (!fIntrinsicConstantBuffer) {
707         fIntrinsicConstantBuffer = fResourceProvider->getOrCreateIntrinsicConstantBuffer();
708         SkASSERT(fIntrinsicConstantBuffer);
709         SkASSERT(fIntrinsicConstantBuffer->size() == sizeof(IntrinsicConstant));
710         this->trackResource(fIntrinsicConstantBuffer);
711     }
712     fCommandEncoder.WriteBuffer(fIntrinsicConstantBuffer->dawnBuffer(),
713                                 0,
714                                 reinterpret_cast<const uint8_t*>(rtAdjust),
715                                 sizeof(rtAdjust));
716     fIntrinsicConstantBufferSlotsUsed = 1;
717 #else   // defined(__EMSCRIPTEN__)
718     if (!fIntrinsicConstantBuffer ||
719         fIntrinsicConstantBufferSlotsUsed == kNumSlotsForIntrinsicConstantBuffer) {
720         size_t bufferSize = kIntrinsicConstantAlignedSize * kNumSlotsForIntrinsicConstantBuffer;
721         fIntrinsicConstantBuffer =
722                 fResourceProvider->findOrCreateDawnBuffer(bufferSize,
723                                                           BufferType::kUniform,
724                                                           AccessPattern::kGpuOnly,
725                                                           "IntrinsicConstantBuffer");
726 
727         fIntrinsicConstantBufferSlotsUsed = 0;
728         SkASSERT(fIntrinsicConstantBuffer);
729         this->trackResource(fIntrinsicConstantBuffer);
730     }
731     uint64_t offset = fIntrinsicConstantBufferSlotsUsed * kIntrinsicConstantAlignedSize;
732     fSharedContext->queue().WriteBuffer(
733             fIntrinsicConstantBuffer->dawnBuffer(), offset, &rtAdjust, sizeof(rtAdjust));
734     fIntrinsicConstantBufferSlotsUsed++;
735 #endif  // defined(__EMSCRIPTEN__)
736 }
737 
setViewport(const SkRect & viewport)738 void DawnCommandBuffer::setViewport(const SkRect& viewport) {
739     SkASSERT(fActiveRenderPassEncoder);
740     fActiveRenderPassEncoder.SetViewport(
741             viewport.x(), viewport.y(), viewport.width(), viewport.height(), 0, 1);
742 }
743 
setBlendConstants(float * blendConstants)744 void DawnCommandBuffer::setBlendConstants(float* blendConstants) {
745     SkASSERT(fActiveRenderPassEncoder);
746     wgpu::Color blendConst = {
747             blendConstants[0], blendConstants[1], blendConstants[2], blendConstants[3]};
748     fActiveRenderPassEncoder.SetBlendConstant(&blendConst);
749 }
750 
draw(PrimitiveType type,unsigned int baseVertex,unsigned int vertexCount)751 void DawnCommandBuffer::draw(PrimitiveType type,
752                              unsigned int baseVertex,
753                              unsigned int vertexCount) {
754     SkASSERT(fActiveRenderPassEncoder);
755     SkASSERT(fActiveGraphicsPipeline->primitiveType() == type);
756 
757     this->syncUniformBuffers();
758 
759     fActiveRenderPassEncoder.Draw(vertexCount, /*instanceCount=*/1, baseVertex);
760 }
761 
drawIndexed(PrimitiveType type,unsigned int baseIndex,unsigned int indexCount,unsigned int baseVertex)762 void DawnCommandBuffer::drawIndexed(PrimitiveType type,
763                                     unsigned int baseIndex,
764                                     unsigned int indexCount,
765                                     unsigned int baseVertex) {
766     SkASSERT(fActiveRenderPassEncoder);
767     SkASSERT(fActiveGraphicsPipeline->primitiveType() == type);
768 
769     this->syncUniformBuffers();
770 
771     fActiveRenderPassEncoder.DrawIndexed(indexCount, /*instanceCount=*/1, baseIndex, baseVertex);
772 }
773 
drawInstanced(PrimitiveType type,unsigned int baseVertex,unsigned int vertexCount,unsigned int baseInstance,unsigned int instanceCount)774 void DawnCommandBuffer::drawInstanced(PrimitiveType type,
775                                       unsigned int baseVertex,
776                                       unsigned int vertexCount,
777                                       unsigned int baseInstance,
778                                       unsigned int instanceCount) {
779     SkASSERT(fActiveRenderPassEncoder);
780     SkASSERT(fActiveGraphicsPipeline->primitiveType() == type);
781 
782     this->syncUniformBuffers();
783 
784     fActiveRenderPassEncoder.Draw(vertexCount, instanceCount, baseVertex, baseInstance);
785 }
786 
drawIndexedInstanced(PrimitiveType type,unsigned int baseIndex,unsigned int indexCount,unsigned int baseVertex,unsigned int baseInstance,unsigned int instanceCount)787 void DawnCommandBuffer::drawIndexedInstanced(PrimitiveType type,
788                                              unsigned int baseIndex,
789                                              unsigned int indexCount,
790                                              unsigned int baseVertex,
791                                              unsigned int baseInstance,
792                                              unsigned int instanceCount) {
793     SkASSERT(fActiveRenderPassEncoder);
794     SkASSERT(fActiveGraphicsPipeline->primitiveType() == type);
795 
796     this->syncUniformBuffers();
797 
798     fActiveRenderPassEncoder.DrawIndexed(
799             indexCount, instanceCount, baseIndex, baseVertex, baseInstance);
800 }
801 
drawIndirect(PrimitiveType type)802 void DawnCommandBuffer::drawIndirect(PrimitiveType type) {
803     SkASSERT(fActiveRenderPassEncoder);
804     SkASSERT(fActiveGraphicsPipeline->primitiveType() == type);
805     SkASSERT(fCurrentIndirectBuffer);
806 
807     this->syncUniformBuffers();
808 
809     fActiveRenderPassEncoder.DrawIndirect(fCurrentIndirectBuffer, fCurrentIndirectBufferOffset);
810 }
811 
drawIndexedIndirect(PrimitiveType type)812 void DawnCommandBuffer::drawIndexedIndirect(PrimitiveType type) {
813     SkASSERT(fActiveRenderPassEncoder);
814     SkASSERT(fActiveGraphicsPipeline->primitiveType() == type);
815     SkASSERT(fCurrentIndirectBuffer);
816 
817     this->syncUniformBuffers();
818 
819     fActiveRenderPassEncoder.DrawIndexedIndirect(fCurrentIndirectBuffer,
820                                                  fCurrentIndirectBufferOffset);
821 }
822 
beginComputePass()823 void DawnCommandBuffer::beginComputePass() {
824     SkASSERT(!fActiveRenderPassEncoder);
825     SkASSERT(!fActiveComputePassEncoder);
826     fActiveComputePassEncoder = fCommandEncoder.BeginComputePass();
827 }
828 
bindComputePipeline(const ComputePipeline * computePipeline)829 void DawnCommandBuffer::bindComputePipeline(const ComputePipeline* computePipeline) {
830     SkASSERT(fActiveComputePassEncoder);
831 
832     fActiveComputePipeline = static_cast<const DawnComputePipeline*>(computePipeline);
833     fActiveComputePassEncoder.SetPipeline(fActiveComputePipeline->dawnComputePipeline());
834 }
835 
bindDispatchResources(const DispatchGroup & group,const DispatchGroup::Dispatch & dispatch)836 void DawnCommandBuffer::bindDispatchResources(const DispatchGroup& group,
837                                               const DispatchGroup::Dispatch& dispatch) {
838     SkASSERT(fActiveComputePassEncoder);
839     SkASSERT(fActiveComputePipeline);
840 
841     // Bind all pipeline resources to a single new bind group at index 0.
842     // NOTE: Caching the bind groups here might be beneficial based on the layout and the bound
843     // resources (though it's questionable how often a bind group will end up getting reused since
844     // the bound objects change often).
845     skia_private::TArray<wgpu::BindGroupEntry> entries;
846     entries.reserve(dispatch.fBindings.size());
847 
848     for (const ResourceBinding& binding : dispatch.fBindings) {
849         wgpu::BindGroupEntry& entry = entries.push_back();
850         entry.binding = binding.fIndex;
851         if (const BufferView* buffer = std::get_if<BufferView>(&binding.fResource)) {
852             entry.buffer = static_cast<const DawnBuffer*>(buffer->fInfo.fBuffer)->dawnBuffer();
853             entry.offset = buffer->fInfo.fOffset;
854             entry.size = buffer->fSize;
855         } else if (const TextureIndex* texIdx = std::get_if<TextureIndex>(&binding.fResource)) {
856             const DawnTexture* texture =
857                     static_cast<const DawnTexture*>(group.getTexture(texIdx->fValue));
858             SkASSERT(texture);
859             entry.textureView = texture->sampleTextureView();
860         } else if (const SamplerIndex* samplerIdx = std::get_if<SamplerIndex>(&binding.fResource)) {
861             const DawnSampler* sampler =
862                     static_cast<const DawnSampler*>(group.getSampler(samplerIdx->fValue));
863             entry.sampler = sampler->dawnSampler();
864         } else {
865             SK_ABORT("unsupported dispatch resource type");
866         }
867     }
868 
869     wgpu::BindGroupDescriptor desc;
870     desc.layout = fActiveComputePipeline->dawnGroupLayout();
871     desc.entryCount = entries.size();
872     desc.entries = entries.data();
873 
874     auto bindGroup = fSharedContext->device().CreateBindGroup(&desc);
875     fActiveComputePassEncoder.SetBindGroup(0, bindGroup);
876 }
877 
dispatchWorkgroups(const WorkgroupSize & globalSize)878 void DawnCommandBuffer::dispatchWorkgroups(const WorkgroupSize& globalSize) {
879     SkASSERT(fActiveComputePassEncoder);
880     SkASSERT(fActiveComputePipeline);
881 
882     fActiveComputePassEncoder.DispatchWorkgroups(
883             globalSize.fWidth, globalSize.fHeight, globalSize.fDepth);
884 }
885 
dispatchWorkgroupsIndirect(const Buffer * indirectBuffer,size_t indirectBufferOffset)886 void DawnCommandBuffer::dispatchWorkgroupsIndirect(const Buffer* indirectBuffer,
887                                                    size_t indirectBufferOffset) {
888     SkASSERT(fActiveComputePassEncoder);
889     SkASSERT(fActiveComputePipeline);
890 
891     auto& wgpuIndirectBuffer = static_cast<const DawnBuffer*>(indirectBuffer)->dawnBuffer();
892     fActiveComputePassEncoder.DispatchWorkgroupsIndirect(wgpuIndirectBuffer, indirectBufferOffset);
893 }
894 
endComputePass()895 void DawnCommandBuffer::endComputePass() {
896     SkASSERT(fActiveComputePassEncoder);
897     fActiveComputePassEncoder.End();
898     fActiveComputePassEncoder = nullptr;
899 }
900 
onCopyBufferToBuffer(const Buffer * srcBuffer,size_t srcOffset,const Buffer * dstBuffer,size_t dstOffset,size_t size)901 bool DawnCommandBuffer::onCopyBufferToBuffer(const Buffer* srcBuffer,
902                                              size_t srcOffset,
903                                              const Buffer* dstBuffer,
904                                              size_t dstOffset,
905                                              size_t size) {
906     SkASSERT(!fActiveRenderPassEncoder);
907     SkASSERT(!fActiveComputePassEncoder);
908 
909     auto& wgpuBufferSrc = static_cast<const DawnBuffer*>(srcBuffer)->dawnBuffer();
910     auto& wgpuBufferDst = static_cast<const DawnBuffer*>(dstBuffer)->dawnBuffer();
911 
912     fCommandEncoder.CopyBufferToBuffer(wgpuBufferSrc, srcOffset, wgpuBufferDst, dstOffset, size);
913     return true;
914 }
915 
onCopyTextureToBuffer(const Texture * texture,SkIRect srcRect,const Buffer * buffer,size_t bufferOffset,size_t bufferRowBytes)916 bool DawnCommandBuffer::onCopyTextureToBuffer(const Texture* texture,
917                                               SkIRect srcRect,
918                                               const Buffer* buffer,
919                                               size_t bufferOffset,
920                                               size_t bufferRowBytes) {
921     SkASSERT(!fActiveRenderPassEncoder);
922     SkASSERT(!fActiveComputePassEncoder);
923 
924     const auto* wgpuTexture = static_cast<const DawnTexture*>(texture);
925     auto& wgpuBuffer = static_cast<const DawnBuffer*>(buffer)->dawnBuffer();
926 
927     wgpu::ImageCopyTexture src;
928     src.texture = wgpuTexture->dawnTexture();
929     src.origin.x = srcRect.x();
930     src.origin.y = srcRect.y();
931     src.aspect = wgpuTexture->textureInfo().dawnTextureSpec().fAspect;
932 
933     wgpu::ImageCopyBuffer dst;
934     dst.buffer = wgpuBuffer;
935     dst.layout.offset = bufferOffset;
936     // Dawn requires buffer's alignment to be multiples of 256.
937     // https://b.corp.google.com/issues/259264489
938     SkASSERT((bufferRowBytes & 0xFF) == 0);
939     dst.layout.bytesPerRow = bufferRowBytes;
940 
941     wgpu::Extent3D copySize = {
942             static_cast<uint32_t>(srcRect.width()), static_cast<uint32_t>(srcRect.height()), 1};
943     fCommandEncoder.CopyTextureToBuffer(&src, &dst, &copySize);
944 
945     return true;
946 }
947 
onCopyBufferToTexture(const Buffer * buffer,const Texture * texture,const BufferTextureCopyData * copyData,int count)948 bool DawnCommandBuffer::onCopyBufferToTexture(const Buffer* buffer,
949                                               const Texture* texture,
950                                               const BufferTextureCopyData* copyData,
951                                               int count) {
952     SkASSERT(!fActiveRenderPassEncoder);
953     SkASSERT(!fActiveComputePassEncoder);
954 
955     auto& wgpuTexture = static_cast<const DawnTexture*>(texture)->dawnTexture();
956     auto& wgpuBuffer = static_cast<const DawnBuffer*>(buffer)->dawnBuffer();
957 
958     wgpu::ImageCopyBuffer src;
959     src.buffer = wgpuBuffer;
960 
961     wgpu::ImageCopyTexture dst;
962     dst.texture = wgpuTexture;
963 
964     for (int i = 0; i < count; ++i) {
965         src.layout.offset = copyData[i].fBufferOffset;
966         // Dawn requires buffer's alignment to be multiples of 256.
967         // https://b.corp.google.com/issues/259264489
968         SkASSERT((copyData[i].fBufferRowBytes & 0xFF) == 0);
969         src.layout.bytesPerRow = copyData[i].fBufferRowBytes;
970 
971         dst.origin.x = copyData[i].fRect.x();
972         dst.origin.y = copyData[i].fRect.y();
973         dst.mipLevel = copyData[i].fMipLevel;
974 
975         wgpu::Extent3D copySize = {static_cast<uint32_t>(copyData[i].fRect.width()),
976                                    static_cast<uint32_t>(copyData[i].fRect.height()),
977                                    1};
978         fCommandEncoder.CopyBufferToTexture(&src, &dst, &copySize);
979     }
980 
981     return true;
982 }
983 
onCopyTextureToTexture(const Texture * src,SkIRect srcRect,const Texture * dst,SkIPoint dstPoint,int mipLevel)984 bool DawnCommandBuffer::onCopyTextureToTexture(const Texture* src,
985                                                SkIRect srcRect,
986                                                const Texture* dst,
987                                                SkIPoint dstPoint,
988                                                int mipLevel) {
989     SkASSERT(!fActiveRenderPassEncoder);
990     SkASSERT(!fActiveComputePassEncoder);
991 
992     auto& wgpuTextureSrc = static_cast<const DawnTexture*>(src)->dawnTexture();
993     auto& wgpuTextureDst = static_cast<const DawnTexture*>(dst)->dawnTexture();
994 
995     wgpu::ImageCopyTexture srcArgs;
996     srcArgs.texture = wgpuTextureSrc;
997     srcArgs.origin.x = srcRect.fLeft;
998     srcArgs.origin.y = srcRect.fTop;
999 
1000     wgpu::ImageCopyTexture dstArgs;
1001     dstArgs.texture = wgpuTextureDst;
1002     dstArgs.origin.x = dstPoint.fX;
1003     dstArgs.origin.y = dstPoint.fY;
1004     dstArgs.mipLevel = mipLevel;
1005 
1006     wgpu::Extent3D copySize = {
1007             static_cast<uint32_t>(srcRect.width()), static_cast<uint32_t>(srcRect.height()), 1};
1008 
1009     fCommandEncoder.CopyTextureToTexture(&srcArgs, &dstArgs, &copySize);
1010 
1011     return true;
1012 }
1013 
onSynchronizeBufferToCpu(const Buffer * buffer,bool * outDidResultInWork)1014 bool DawnCommandBuffer::onSynchronizeBufferToCpu(const Buffer* buffer, bool* outDidResultInWork) {
1015     return true;
1016 }
1017 
onClearBuffer(const Buffer * buffer,size_t offset,size_t size)1018 bool DawnCommandBuffer::onClearBuffer(const Buffer* buffer, size_t offset, size_t size) {
1019     SkASSERT(!fActiveRenderPassEncoder);
1020     SkASSERT(!fActiveComputePassEncoder);
1021 
1022     auto& wgpuBuffer = static_cast<const DawnBuffer*>(buffer)->dawnBuffer();
1023     fCommandEncoder.ClearBuffer(wgpuBuffer, offset, size);
1024 
1025     return true;
1026 }
1027 
1028 }  // namespace skgpu::graphite
1029