1 // Copyright 2017 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/vulkan/CommandBufferVk.h"
16 
17 #include "dawn_native/BindGroupTracker.h"
18 #include "dawn_native/CommandEncoder.h"
19 #include "dawn_native/CommandValidation.h"
20 #include "dawn_native/Commands.h"
21 #include "dawn_native/DynamicUploader.h"
22 #include "dawn_native/EnumMaskIterator.h"
23 #include "dawn_native/RenderBundle.h"
24 #include "dawn_native/vulkan/BindGroupVk.h"
25 #include "dawn_native/vulkan/BufferVk.h"
26 #include "dawn_native/vulkan/CommandRecordingContext.h"
27 #include "dawn_native/vulkan/ComputePipelineVk.h"
28 #include "dawn_native/vulkan/DeviceVk.h"
29 #include "dawn_native/vulkan/FencedDeleter.h"
30 #include "dawn_native/vulkan/PipelineLayoutVk.h"
31 #include "dawn_native/vulkan/QuerySetVk.h"
32 #include "dawn_native/vulkan/RenderPassCache.h"
33 #include "dawn_native/vulkan/RenderPipelineVk.h"
34 #include "dawn_native/vulkan/StagingBufferVk.h"
35 #include "dawn_native/vulkan/TextureVk.h"
36 #include "dawn_native/vulkan/UtilsVulkan.h"
37 #include "dawn_native/vulkan/VulkanError.h"
38 
39 #include <algorithm>
40 
41 namespace dawn_native { namespace vulkan {
42 
43     namespace {
44 
VulkanIndexType(wgpu::IndexFormat format)45         VkIndexType VulkanIndexType(wgpu::IndexFormat format) {
46             switch (format) {
47                 case wgpu::IndexFormat::Uint16:
48                     return VK_INDEX_TYPE_UINT16;
49                 case wgpu::IndexFormat::Uint32:
50                     return VK_INDEX_TYPE_UINT32;
51                 case wgpu::IndexFormat::Undefined:
52                     break;
53             }
54             UNREACHABLE();
55         }
56 
HasSameTextureCopyExtent(const TextureCopy& srcCopy, const TextureCopy& dstCopy, const Extent3D& copySize)57         bool HasSameTextureCopyExtent(const TextureCopy& srcCopy,
58                                       const TextureCopy& dstCopy,
59                                       const Extent3D& copySize) {
60             Extent3D imageExtentSrc = ComputeTextureCopyExtent(srcCopy, copySize);
61             Extent3D imageExtentDst = ComputeTextureCopyExtent(dstCopy, copySize);
62             return imageExtentSrc.width == imageExtentDst.width &&
63                    imageExtentSrc.height == imageExtentDst.height &&
64                    imageExtentSrc.depthOrArrayLayers == imageExtentDst.depthOrArrayLayers;
65         }
66 
ComputeImageCopyRegion(const TextureCopy& srcCopy, const TextureCopy& dstCopy, const Extent3D& copySize, Aspect aspect)67         VkImageCopy ComputeImageCopyRegion(const TextureCopy& srcCopy,
68                                            const TextureCopy& dstCopy,
69                                            const Extent3D& copySize,
70                                            Aspect aspect) {
71             const Texture* srcTexture = ToBackend(srcCopy.texture.Get());
72             const Texture* dstTexture = ToBackend(dstCopy.texture.Get());
73 
74             VkImageCopy region;
75             region.srcSubresource.aspectMask = VulkanAspectMask(aspect);
76             region.srcSubresource.mipLevel = srcCopy.mipLevel;
77             region.dstSubresource.aspectMask = VulkanAspectMask(aspect);
78             region.dstSubresource.mipLevel = dstCopy.mipLevel;
79 
80             bool has3DTextureInCopy = false;
81 
82             region.srcOffset.x = srcCopy.origin.x;
83             region.srcOffset.y = srcCopy.origin.y;
84             switch (srcTexture->GetDimension()) {
85                 case wgpu::TextureDimension::e2D:
86                     region.srcSubresource.baseArrayLayer = srcCopy.origin.z;
87                     region.srcSubresource.layerCount = copySize.depthOrArrayLayers;
88                     region.srcOffset.z = 0;
89                     break;
90                 case wgpu::TextureDimension::e3D:
91                     has3DTextureInCopy = true;
92                     region.srcSubresource.baseArrayLayer = 0;
93                     region.srcSubresource.layerCount = 1;
94                     region.srcOffset.z = srcCopy.origin.z;
95                     break;
96                 case wgpu::TextureDimension::e1D:
97                     // TODO(crbug.com/dawn/814): support 1D textures
98                     UNREACHABLE();
99             }
100 
101             region.dstOffset.x = dstCopy.origin.x;
102             region.dstOffset.y = dstCopy.origin.y;
103             switch (dstTexture->GetDimension()) {
104                 case wgpu::TextureDimension::e2D:
105                     region.dstSubresource.baseArrayLayer = dstCopy.origin.z;
106                     region.dstSubresource.layerCount = copySize.depthOrArrayLayers;
107                     region.dstOffset.z = 0;
108                     break;
109                 case wgpu::TextureDimension::e3D:
110                     has3DTextureInCopy = true;
111                     region.dstSubresource.baseArrayLayer = 0;
112                     region.dstSubresource.layerCount = 1;
113                     region.dstOffset.z = dstCopy.origin.z;
114                     break;
115                 case wgpu::TextureDimension::e1D:
116                     // TODO(crbug.com/dawn/814): support 1D textures
117                     UNREACHABLE();
118             }
119 
120             ASSERT(HasSameTextureCopyExtent(srcCopy, dstCopy, copySize));
121             Extent3D imageExtent = ComputeTextureCopyExtent(dstCopy, copySize);
122             region.extent.width = imageExtent.width;
123             region.extent.height = imageExtent.height;
124             region.extent.depth = has3DTextureInCopy ? copySize.depthOrArrayLayers : 1;
125 
126             return region;
127         }
128 
129         class DescriptorSetTracker : public BindGroupTrackerBase<true, uint32_t> {
130           public:
131             DescriptorSetTracker() = default;
132 
Apply(Device* device, CommandRecordingContext* recordingContext, VkPipelineBindPoint bindPoint)133             void Apply(Device* device,
134                        CommandRecordingContext* recordingContext,
135                        VkPipelineBindPoint bindPoint) {
136                 BeforeApply();
137                 for (BindGroupIndex dirtyIndex :
138                      IterateBitSet(mDirtyBindGroupsObjectChangedOrIsDynamic)) {
139                     VkDescriptorSet set = ToBackend(mBindGroups[dirtyIndex])->GetHandle();
140                     const uint32_t* dynamicOffset = mDynamicOffsetCounts[dirtyIndex] > 0
141                                                         ? mDynamicOffsets[dirtyIndex].data()
142                                                         : nullptr;
143                     device->fn.CmdBindDescriptorSets(
144                         recordingContext->commandBuffer, bindPoint,
145                         ToBackend(mPipelineLayout)->GetHandle(), static_cast<uint32_t>(dirtyIndex),
146                         1, &*set, mDynamicOffsetCounts[dirtyIndex], dynamicOffset);
147                 }
148                 AfterApply();
149             }
150         };
151 
152         // Records the necessary barriers for a synchronization scope using the resource usage
153         // data pre-computed in the frontend. Also performs lazy initialization if required.
TransitionAndClearForSyncScope(Device* device, CommandRecordingContext* recordingContext, const SyncScopeResourceUsage& scope)154         void TransitionAndClearForSyncScope(Device* device,
155                                             CommandRecordingContext* recordingContext,
156                                             const SyncScopeResourceUsage& scope) {
157             std::vector<VkBufferMemoryBarrier> bufferBarriers;
158             std::vector<VkImageMemoryBarrier> imageBarriers;
159             VkPipelineStageFlags srcStages = 0;
160             VkPipelineStageFlags dstStages = 0;
161 
162             for (size_t i = 0; i < scope.buffers.size(); ++i) {
163                 Buffer* buffer = ToBackend(scope.buffers[i]);
164                 buffer->EnsureDataInitialized(recordingContext);
165 
166                 VkBufferMemoryBarrier bufferBarrier;
167                 if (buffer->TransitionUsageAndGetResourceBarrier(
168                         scope.bufferUsages[i], &bufferBarrier, &srcStages, &dstStages)) {
169                     bufferBarriers.push_back(bufferBarrier);
170                 }
171             }
172 
173             for (size_t i = 0; i < scope.textures.size(); ++i) {
174                 Texture* texture = ToBackend(scope.textures[i]);
175 
176                 // Clear subresources that are not render attachments. Render attachments will be
177                 // cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
178                 // subresource has not been initialized before the render pass.
179                 scope.textureUsages[i].Iterate(
180                     [&](const SubresourceRange& range, wgpu::TextureUsage usage) {
181                         if (usage & ~wgpu::TextureUsage::RenderAttachment) {
182                             texture->EnsureSubresourceContentInitialized(recordingContext, range);
183                         }
184                     });
185                 texture->TransitionUsageForPass(recordingContext, scope.textureUsages[i],
186                                                 &imageBarriers, &srcStages, &dstStages);
187             }
188 
189             if (bufferBarriers.size() || imageBarriers.size()) {
190                 device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages,
191                                               0, 0, nullptr, bufferBarriers.size(),
192                                               bufferBarriers.data(), imageBarriers.size(),
193                                               imageBarriers.data());
194             }
195         }
196 
RecordBeginRenderPass(CommandRecordingContext* recordingContext, Device* device, BeginRenderPassCmd* renderPass)197         MaybeError RecordBeginRenderPass(CommandRecordingContext* recordingContext,
198                                          Device* device,
199                                          BeginRenderPassCmd* renderPass) {
200             VkCommandBuffer commands = recordingContext->commandBuffer;
201 
202             // Query a VkRenderPass from the cache
203             VkRenderPass renderPassVK = VK_NULL_HANDLE;
204             {
205                 RenderPassCacheQuery query;
206 
207                 for (ColorAttachmentIndex i :
208                      IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
209                     const auto& attachmentInfo = renderPass->colorAttachments[i];
210 
211                     bool hasResolveTarget = attachmentInfo.resolveTarget != nullptr;
212 
213                     query.SetColor(i, attachmentInfo.view->GetFormat().format,
214                                    attachmentInfo.loadOp, attachmentInfo.storeOp, hasResolveTarget);
215                 }
216 
217                 if (renderPass->attachmentState->HasDepthStencilAttachment()) {
218                     const auto& attachmentInfo = renderPass->depthStencilAttachment;
219 
220                     query.SetDepthStencil(
221                         attachmentInfo.view->GetTexture()->GetFormat().format,
222                         attachmentInfo.depthLoadOp, attachmentInfo.depthStoreOp,
223                         attachmentInfo.stencilLoadOp, attachmentInfo.stencilStoreOp,
224                         attachmentInfo.depthReadOnly || attachmentInfo.stencilReadOnly);
225                 }
226 
227                 query.SetSampleCount(renderPass->attachmentState->GetSampleCount());
228 
229                 DAWN_TRY_ASSIGN(renderPassVK, device->GetRenderPassCache()->GetRenderPass(query));
230             }
231 
232             // Create a framebuffer that will be used once for the render pass and gather the clear
233             // values for the attachments at the same time.
234             std::array<VkClearValue, kMaxColorAttachments + 1> clearValues;
235             VkFramebuffer framebuffer = VK_NULL_HANDLE;
236             uint32_t attachmentCount = 0;
237             {
238                 // Fill in the attachment info that will be chained in the framebuffer create info.
239                 std::array<VkImageView, kMaxColorAttachments * 2 + 1> attachments;
240 
241                 for (ColorAttachmentIndex i :
242                      IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
243                     auto& attachmentInfo = renderPass->colorAttachments[i];
244                     TextureView* view = ToBackend(attachmentInfo.view.Get());
245 
246                     attachments[attachmentCount] = view->GetHandle();
247 
248                     switch (view->GetFormat().GetAspectInfo(Aspect::Color).baseType) {
249                         case wgpu::TextureComponentType::Float: {
250                             const std::array<float, 4> appliedClearColor =
251                                 ConvertToFloatColor(attachmentInfo.clearColor);
252                             for (uint32_t i = 0; i < 4; ++i) {
253                                 clearValues[attachmentCount].color.float32[i] =
254                                     appliedClearColor[i];
255                             }
256                             break;
257                         }
258                         case wgpu::TextureComponentType::Uint: {
259                             const std::array<uint32_t, 4> appliedClearColor =
260                                 ConvertToUnsignedIntegerColor(attachmentInfo.clearColor);
261                             for (uint32_t i = 0; i < 4; ++i) {
262                                 clearValues[attachmentCount].color.uint32[i] = appliedClearColor[i];
263                             }
264                             break;
265                         }
266                         case wgpu::TextureComponentType::Sint: {
267                             const std::array<int32_t, 4> appliedClearColor =
268                                 ConvertToSignedIntegerColor(attachmentInfo.clearColor);
269                             for (uint32_t i = 0; i < 4; ++i) {
270                                 clearValues[attachmentCount].color.int32[i] = appliedClearColor[i];
271                             }
272                             break;
273                         }
274 
275                         case wgpu::TextureComponentType::DepthComparison:
276                             UNREACHABLE();
277                     }
278                     attachmentCount++;
279                 }
280 
281                 if (renderPass->attachmentState->HasDepthStencilAttachment()) {
282                     auto& attachmentInfo = renderPass->depthStencilAttachment;
283                     TextureView* view = ToBackend(attachmentInfo.view.Get());
284 
285                     attachments[attachmentCount] = view->GetHandle();
286 
287                     clearValues[attachmentCount].depthStencil.depth = attachmentInfo.clearDepth;
288                     clearValues[attachmentCount].depthStencil.stencil = attachmentInfo.clearStencil;
289 
290                     attachmentCount++;
291                 }
292 
293                 for (ColorAttachmentIndex i :
294                      IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
295                     if (renderPass->colorAttachments[i].resolveTarget != nullptr) {
296                         TextureView* view =
297                             ToBackend(renderPass->colorAttachments[i].resolveTarget.Get());
298 
299                         attachments[attachmentCount] = view->GetHandle();
300 
301                         attachmentCount++;
302                     }
303                 }
304 
305                 // Chain attachments and create the framebuffer
306                 VkFramebufferCreateInfo createInfo;
307                 createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
308                 createInfo.pNext = nullptr;
309                 createInfo.flags = 0;
310                 createInfo.renderPass = renderPassVK;
311                 createInfo.attachmentCount = attachmentCount;
312                 createInfo.pAttachments = AsVkArray(attachments.data());
313                 createInfo.width = renderPass->width;
314                 createInfo.height = renderPass->height;
315                 createInfo.layers = 1;
316 
317                 DAWN_TRY(
318                     CheckVkSuccess(device->fn.CreateFramebuffer(device->GetVkDevice(), &createInfo,
319                                                                 nullptr, &*framebuffer),
320                                    "CreateFramebuffer"));
321 
322                 // We don't reuse VkFramebuffers so mark the framebuffer for deletion as soon as the
323                 // commands currently being recorded are finished.
324                 device->GetFencedDeleter()->DeleteWhenUnused(framebuffer);
325             }
326 
327             VkRenderPassBeginInfo beginInfo;
328             beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
329             beginInfo.pNext = nullptr;
330             beginInfo.renderPass = renderPassVK;
331             beginInfo.framebuffer = framebuffer;
332             beginInfo.renderArea.offset.x = 0;
333             beginInfo.renderArea.offset.y = 0;
334             beginInfo.renderArea.extent.width = renderPass->width;
335             beginInfo.renderArea.extent.height = renderPass->height;
336             beginInfo.clearValueCount = attachmentCount;
337             beginInfo.pClearValues = clearValues.data();
338 
339             device->fn.CmdBeginRenderPass(commands, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
340 
341             return {};
342         }
343 
344         // Reset the query sets used on render pass because the reset command must be called outside
345         // render pass.
ResetUsedQuerySetsOnRenderPass(Device* device, VkCommandBuffer commands, QuerySetBase* querySet, const std::vector<bool>& availability)346         void ResetUsedQuerySetsOnRenderPass(Device* device,
347                                             VkCommandBuffer commands,
348                                             QuerySetBase* querySet,
349                                             const std::vector<bool>& availability) {
350             ASSERT(availability.size() == querySet->GetQueryAvailability().size());
351 
352             auto currentIt = availability.begin();
353             auto lastIt = availability.end();
354             // Traverse the used queries which availability are true.
355             while (currentIt != lastIt) {
356                 auto firstTrueIt = std::find(currentIt, lastIt, true);
357                 // No used queries need to be reset
358                 if (firstTrueIt == lastIt) {
359                     break;
360                 }
361 
362                 auto nextFalseIt = std::find(firstTrueIt, lastIt, false);
363 
364                 uint32_t queryIndex = std::distance(availability.begin(), firstTrueIt);
365                 uint32_t queryCount = std::distance(firstTrueIt, nextFalseIt);
366 
367                 // Reset the queries between firstTrueIt and nextFalseIt (which is at most
368                 // lastIt)
369                 device->fn.CmdResetQueryPool(commands, ToBackend(querySet)->GetHandle(), queryIndex,
370                                              queryCount);
371 
372                 // Set current iterator to next false
373                 currentIt = nextFalseIt;
374             }
375         }
376 
RecordWriteTimestampCmd(CommandRecordingContext* recordingContext, Device* device, WriteTimestampCmd* cmd)377         void RecordWriteTimestampCmd(CommandRecordingContext* recordingContext,
378                                      Device* device,
379                                      WriteTimestampCmd* cmd) {
380             VkCommandBuffer commands = recordingContext->commandBuffer;
381             QuerySet* querySet = ToBackend(cmd->querySet.Get());
382 
383             device->fn.CmdWriteTimestamp(commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
384                                          querySet->GetHandle(), cmd->queryIndex);
385         }
386 
RecordResolveQuerySetCmd(VkCommandBuffer commands, Device* device, QuerySet* querySet, uint32_t firstQuery, uint32_t queryCount, Buffer* destination, uint64_t destinationOffset)387         void RecordResolveQuerySetCmd(VkCommandBuffer commands,
388                                       Device* device,
389                                       QuerySet* querySet,
390                                       uint32_t firstQuery,
391                                       uint32_t queryCount,
392                                       Buffer* destination,
393                                       uint64_t destinationOffset) {
394             const std::vector<bool>& availability = querySet->GetQueryAvailability();
395 
396             auto currentIt = availability.begin() + firstQuery;
397             auto lastIt = availability.begin() + firstQuery + queryCount;
398 
399             // Traverse available queries in the range of [firstQuery, firstQuery +  queryCount - 1]
400             while (currentIt != lastIt) {
401                 auto firstTrueIt = std::find(currentIt, lastIt, true);
402                 // No available query found for resolving
403                 if (firstTrueIt == lastIt) {
404                     break;
405                 }
406                 auto nextFalseIt = std::find(firstTrueIt, lastIt, false);
407 
408                 // The query index of firstTrueIt where the resolving starts
409                 uint32_t resolveQueryIndex = std::distance(availability.begin(), firstTrueIt);
410                 // The queries count between firstTrueIt and nextFalseIt need to be resolved
411                 uint32_t resolveQueryCount = std::distance(firstTrueIt, nextFalseIt);
412 
413                 // Calculate destinationOffset based on the current resolveQueryIndex and firstQuery
414                 uint32_t resolveDestinationOffset =
415                     destinationOffset + (resolveQueryIndex - firstQuery) * sizeof(uint64_t);
416 
417                 // Resolve the queries between firstTrueIt and nextFalseIt (which is at most lastIt)
418                 device->fn.CmdCopyQueryPoolResults(
419                     commands, querySet->GetHandle(), resolveQueryIndex, resolveQueryCount,
420                     destination->GetHandle(), resolveDestinationOffset, sizeof(uint64_t),
421                     VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
422 
423                 // Set current iterator to next false
424                 currentIt = nextFalseIt;
425             }
426         }
427 
428     }  // anonymous namespace
429 
430     // static
Create(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor)431     Ref<CommandBuffer> CommandBuffer::Create(CommandEncoder* encoder,
432                                              const CommandBufferDescriptor* descriptor) {
433         return AcquireRef(new CommandBuffer(encoder, descriptor));
434     }
435 
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor)436     CommandBuffer::CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor)
437         : CommandBufferBase(encoder, descriptor) {
438     }
439 
RecordCopyImageWithTemporaryBuffer( CommandRecordingContext* recordingContext, const TextureCopy& srcCopy, const TextureCopy& dstCopy, const Extent3D& copySize)440     void CommandBuffer::RecordCopyImageWithTemporaryBuffer(
441         CommandRecordingContext* recordingContext,
442         const TextureCopy& srcCopy,
443         const TextureCopy& dstCopy,
444         const Extent3D& copySize) {
445         ASSERT(srcCopy.texture->GetFormat().format == dstCopy.texture->GetFormat().format);
446         ASSERT(srcCopy.aspect == dstCopy.aspect);
447         dawn_native::Format format = srcCopy.texture->GetFormat();
448         const TexelBlockInfo& blockInfo = format.GetAspectInfo(srcCopy.aspect).block;
449         ASSERT(copySize.width % blockInfo.width == 0);
450         uint32_t widthInBlocks = copySize.width / blockInfo.width;
451         ASSERT(copySize.height % blockInfo.height == 0);
452         uint32_t heightInBlocks = copySize.height / blockInfo.height;
453 
454         // Create the temporary buffer. Note that We don't need to respect WebGPU's 256 alignment
455         // because it isn't a hard constraint in Vulkan.
456         uint64_t tempBufferSize =
457             widthInBlocks * heightInBlocks * copySize.depthOrArrayLayers * blockInfo.byteSize;
458         BufferDescriptor tempBufferDescriptor;
459         tempBufferDescriptor.size = tempBufferSize;
460         tempBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
461 
462         Device* device = ToBackend(GetDevice());
463         // TODO(dawn:723): change to not use AcquireRef for reentrant object creation.
464         Ref<Buffer> tempBuffer =
465             AcquireRef(ToBackend(device->APICreateBuffer(&tempBufferDescriptor)));
466 
467         BufferCopy tempBufferCopy;
468         tempBufferCopy.buffer = tempBuffer.Get();
469         tempBufferCopy.rowsPerImage = heightInBlocks;
470         tempBufferCopy.offset = 0;
471         tempBufferCopy.bytesPerRow = copySize.width / blockInfo.width * blockInfo.byteSize;
472 
473         VkCommandBuffer commands = recordingContext->commandBuffer;
474         VkImage srcImage = ToBackend(srcCopy.texture)->GetHandle();
475         VkImage dstImage = ToBackend(dstCopy.texture)->GetHandle();
476 
477         tempBuffer->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopyDst);
478         VkBufferImageCopy srcToTempBufferRegion =
479             ComputeBufferImageCopyRegion(tempBufferCopy, srcCopy, copySize);
480 
481         // The Dawn CopySrc usage is always mapped to GENERAL
482         device->fn.CmdCopyImageToBuffer(commands, srcImage, VK_IMAGE_LAYOUT_GENERAL,
483                                         tempBuffer->GetHandle(), 1, &srcToTempBufferRegion);
484 
485         tempBuffer->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopySrc);
486         VkBufferImageCopy tempBufferToDstRegion =
487             ComputeBufferImageCopyRegion(tempBufferCopy, dstCopy, copySize);
488 
489         // Dawn guarantees dstImage be in the TRANSFER_DST_OPTIMAL layout after the
490         // copy command.
491         device->fn.CmdCopyBufferToImage(commands, tempBuffer->GetHandle(), dstImage,
492                                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
493                                         &tempBufferToDstRegion);
494 
495         recordingContext->tempBuffers.emplace_back(tempBuffer);
496     }
497 
RecordCommands(CommandRecordingContext* recordingContext)498     MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* recordingContext) {
499         Device* device = ToBackend(GetDevice());
500         VkCommandBuffer commands = recordingContext->commandBuffer;
501 
502         // Records the necessary barriers for the resource usage pre-computed by the frontend.
503         // And resets the used query sets which are rewritten on the render pass.
504         auto PrepareResourcesForRenderPass = [](Device* device,
505                                                 CommandRecordingContext* recordingContext,
506                                                 const RenderPassResourceUsage& usages) {
507             TransitionAndClearForSyncScope(device, recordingContext, usages);
508 
509             // Reset all query set used on current render pass together before beginning render pass
510             // because the reset command must be called outside render pass
511             for (size_t i = 0; i < usages.querySets.size(); ++i) {
512                 ResetUsedQuerySetsOnRenderPass(device, recordingContext->commandBuffer,
513                                                usages.querySets[i], usages.queryAvailabilities[i]);
514             }
515         };
516 
517         size_t nextComputePassNumber = 0;
518         size_t nextRenderPassNumber = 0;
519 
520         Command type;
521         while (mCommands.NextCommandId(&type)) {
522             switch (type) {
523                 case Command::CopyBufferToBuffer: {
524                     CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
525                     if (copy->size == 0) {
526                         // Skip no-op copies.
527                         break;
528                     }
529 
530                     Buffer* srcBuffer = ToBackend(copy->source.Get());
531                     Buffer* dstBuffer = ToBackend(copy->destination.Get());
532 
533                     srcBuffer->EnsureDataInitialized(recordingContext);
534                     dstBuffer->EnsureDataInitializedAsDestination(
535                         recordingContext, copy->destinationOffset, copy->size);
536 
537                     srcBuffer->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopySrc);
538                     dstBuffer->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopyDst);
539 
540                     VkBufferCopy region;
541                     region.srcOffset = copy->sourceOffset;
542                     region.dstOffset = copy->destinationOffset;
543                     region.size = copy->size;
544 
545                     VkBuffer srcHandle = srcBuffer->GetHandle();
546                     VkBuffer dstHandle = dstBuffer->GetHandle();
547                     device->fn.CmdCopyBuffer(commands, srcHandle, dstHandle, 1, &region);
548                     break;
549                 }
550 
551                 case Command::CopyBufferToTexture: {
552                     CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>();
553                     if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
554                         copy->copySize.depthOrArrayLayers == 0) {
555                         // Skip no-op copies.
556                         continue;
557                     }
558                     auto& src = copy->source;
559                     auto& dst = copy->destination;
560 
561                     ToBackend(src.buffer)->EnsureDataInitialized(recordingContext);
562 
563                     VkBufferImageCopy region =
564                         ComputeBufferImageCopyRegion(src, dst, copy->copySize);
565                     VkImageSubresourceLayers subresource = region.imageSubresource;
566 
567                     ASSERT(dst.texture->GetDimension() != wgpu::TextureDimension::e1D);
568                     SubresourceRange range =
569                         GetSubresourcesAffectedByCopy(copy->destination, copy->copySize);
570 
571                     if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize,
572                                                       subresource.mipLevel)) {
573                         // Since texture has been overwritten, it has been "initialized"
574                         dst.texture->SetIsSubresourceContentInitialized(true, range);
575                     } else {
576                         ToBackend(dst.texture)
577                             ->EnsureSubresourceContentInitialized(recordingContext, range);
578                     }
579                     ToBackend(src.buffer)
580                         ->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopySrc);
581                     ToBackend(dst.texture)
582                         ->TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopyDst, range);
583                     VkBuffer srcBuffer = ToBackend(src.buffer)->GetHandle();
584                     VkImage dstImage = ToBackend(dst.texture)->GetHandle();
585 
586                     // Dawn guarantees dstImage be in the TRANSFER_DST_OPTIMAL layout after the
587                     // copy command.
588                     device->fn.CmdCopyBufferToImage(commands, srcBuffer, dstImage,
589                                                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
590                                                     &region);
591                     break;
592                 }
593 
594                 case Command::CopyTextureToBuffer: {
595                     CopyTextureToBufferCmd* copy = mCommands.NextCommand<CopyTextureToBufferCmd>();
596                     if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
597                         copy->copySize.depthOrArrayLayers == 0) {
598                         // Skip no-op copies.
599                         continue;
600                     }
601                     auto& src = copy->source;
602                     auto& dst = copy->destination;
603 
604                     ToBackend(dst.buffer)
605                         ->EnsureDataInitializedAsDestination(recordingContext, copy);
606 
607                     VkBufferImageCopy region =
608                         ComputeBufferImageCopyRegion(dst, src, copy->copySize);
609 
610                     ASSERT(src.texture->GetDimension() != wgpu::TextureDimension::e1D);
611                     SubresourceRange range =
612                         GetSubresourcesAffectedByCopy(copy->source, copy->copySize);
613 
614                     ToBackend(src.texture)
615                         ->EnsureSubresourceContentInitialized(recordingContext, range);
616 
617                     ToBackend(src.texture)
618                         ->TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopySrc, range);
619                     ToBackend(dst.buffer)
620                         ->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopyDst);
621 
622                     VkImage srcImage = ToBackend(src.texture)->GetHandle();
623                     VkBuffer dstBuffer = ToBackend(dst.buffer)->GetHandle();
624                     // The Dawn CopySrc usage is always mapped to GENERAL
625                     device->fn.CmdCopyImageToBuffer(commands, srcImage, VK_IMAGE_LAYOUT_GENERAL,
626                                                     dstBuffer, 1, &region);
627                     break;
628                 }
629 
630                 case Command::CopyTextureToTexture: {
631                     CopyTextureToTextureCmd* copy =
632                         mCommands.NextCommand<CopyTextureToTextureCmd>();
633                     if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
634                         copy->copySize.depthOrArrayLayers == 0) {
635                         // Skip no-op copies.
636                         continue;
637                     }
638                     TextureCopy& src = copy->source;
639                     TextureCopy& dst = copy->destination;
640                     SubresourceRange srcRange = GetSubresourcesAffectedByCopy(src, copy->copySize);
641                     SubresourceRange dstRange = GetSubresourcesAffectedByCopy(dst, copy->copySize);
642 
643                     ToBackend(src.texture)
644                         ->EnsureSubresourceContentInitialized(recordingContext, srcRange);
645                     if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize,
646                                                       dst.mipLevel)) {
647                         // Since destination texture has been overwritten, it has been "initialized"
648                         dst.texture->SetIsSubresourceContentInitialized(true, dstRange);
649                     } else {
650                         ToBackend(dst.texture)
651                             ->EnsureSubresourceContentInitialized(recordingContext, dstRange);
652                     }
653 
654                     if (src.texture.Get() == dst.texture.Get() && src.mipLevel == dst.mipLevel) {
655                         // When there are overlapped subresources, the layout of the overlapped
656                         // subresources should all be GENERAL instead of what we set now. Currently
657                         // it is not allowed to copy with overlapped subresources, but we still
658                         // add the ASSERT here as a reminder for this possible misuse.
659                         ASSERT(!IsRangeOverlapped(src.origin.z, dst.origin.z,
660                                                   copy->copySize.depthOrArrayLayers));
661                     }
662 
663                     // TODO after Yunchao's CL
664                     ToBackend(src.texture)
665                         ->TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopySrc,
666                                              srcRange);
667                     ToBackend(dst.texture)
668                         ->TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopyDst,
669                                              dstRange);
670 
671                     // In some situations we cannot do texture-to-texture copies with vkCmdCopyImage
672                     // because as Vulkan SPEC always validates image copies with the virtual size of
673                     // the image subresource, when the extent that fits in the copy region of one
674                     // subresource but does not fit in the one of another subresource, we will fail
675                     // to find a valid extent to satisfy the requirements on both source and
676                     // destination image subresource. For example, when the source is the first
677                     // level of a 16x16 texture in BC format, and the destination is the third level
678                     // of a 60x60 texture in the same format, neither 16x16 nor 15x15 is valid as
679                     // the extent of vkCmdCopyImage.
680                     // Our workaround for this issue is replacing the texture-to-texture copy with
681                     // one texture-to-buffer copy and one buffer-to-texture copy.
682                     bool copyUsingTemporaryBuffer =
683                         device->IsToggleEnabled(
684                             Toggle::UseTemporaryBufferInCompressedTextureToTextureCopy) &&
685                         src.texture->GetFormat().isCompressed &&
686                         !HasSameTextureCopyExtent(src, dst, copy->copySize);
687 
688                     if (!copyUsingTemporaryBuffer) {
689                         VkImage srcImage = ToBackend(src.texture)->GetHandle();
690                         VkImage dstImage = ToBackend(dst.texture)->GetHandle();
691 
692                         for (Aspect aspect : IterateEnumMask(src.texture->GetFormat().aspects)) {
693                             ASSERT(dst.texture->GetFormat().aspects & aspect);
694                             VkImageCopy region =
695                                 ComputeImageCopyRegion(src, dst, copy->copySize, aspect);
696 
697                             // Dawn guarantees dstImage be in the TRANSFER_DST_OPTIMAL layout after
698                             // the copy command.
699                             device->fn.CmdCopyImage(commands, srcImage, VK_IMAGE_LAYOUT_GENERAL,
700                                                     dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
701                                                     1, &region);
702                         }
703                     } else {
704                         RecordCopyImageWithTemporaryBuffer(recordingContext, src, dst,
705                                                            copy->copySize);
706                     }
707 
708                     break;
709                 }
710 
711                 case Command::ClearBuffer: {
712                     ClearBufferCmd* cmd = mCommands.NextCommand<ClearBufferCmd>();
713                     if (cmd->size == 0) {
714                         // Skip no-op fills.
715                         break;
716                     }
717 
718                     Buffer* dstBuffer = ToBackend(cmd->buffer.Get());
719                     bool clearedToZero = dstBuffer->EnsureDataInitializedAsDestination(
720                         recordingContext, cmd->offset, cmd->size);
721 
722                     if (!clearedToZero) {
723                         dstBuffer->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopyDst);
724                         device->fn.CmdFillBuffer(recordingContext->commandBuffer,
725                                                  dstBuffer->GetHandle(), cmd->offset, cmd->size,
726                                                  0u);
727                     }
728 
729                     break;
730                 }
731 
732                 case Command::BeginRenderPass: {
733                     BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
734 
735                     PrepareResourcesForRenderPass(
736                         device, recordingContext,
737                         GetResourceUsages().renderPasses[nextRenderPassNumber]);
738 
739                     LazyClearRenderPassAttachments(cmd);
740                     DAWN_TRY(RecordRenderPass(recordingContext, cmd));
741 
742                     nextRenderPassNumber++;
743                     break;
744                 }
745 
746                 case Command::BeginComputePass: {
747                     mCommands.NextCommand<BeginComputePassCmd>();
748 
749                     DAWN_TRY(RecordComputePass(
750                         recordingContext,
751                         GetResourceUsages().computePasses[nextComputePassNumber]));
752 
753                     nextComputePassNumber++;
754                     break;
755                 }
756 
757                 case Command::ResolveQuerySet: {
758                     ResolveQuerySetCmd* cmd = mCommands.NextCommand<ResolveQuerySetCmd>();
759                     QuerySet* querySet = ToBackend(cmd->querySet.Get());
760                     Buffer* destination = ToBackend(cmd->destination.Get());
761 
762                     destination->EnsureDataInitializedAsDestination(
763                         recordingContext, cmd->destinationOffset,
764                         cmd->queryCount * sizeof(uint64_t));
765 
766                     // vkCmdCopyQueryPoolResults only can retrieve available queries because
767                     // VK_QUERY_RESULT_WAIT_BIT is set. In order to resolve the unavailable queries
768                     // as 0s, we need to clear the resolving region of the destination buffer to 0s.
769                     auto startIt = querySet->GetQueryAvailability().begin() + cmd->firstQuery;
770                     auto endIt = querySet->GetQueryAvailability().begin() + cmd->firstQuery +
771                                  cmd->queryCount;
772                     bool hasUnavailableQueries = std::find(startIt, endIt, false) != endIt;
773                     if (hasUnavailableQueries) {
774                         destination->TransitionUsageNow(recordingContext,
775                                                         wgpu::BufferUsage::CopyDst);
776                         device->fn.CmdFillBuffer(commands, destination->GetHandle(),
777                                                  cmd->destinationOffset,
778                                                  cmd->queryCount * sizeof(uint64_t), 0u);
779                     }
780 
781                     destination->TransitionUsageNow(recordingContext,
782                                                     wgpu::BufferUsage::QueryResolve);
783 
784                     RecordResolveQuerySetCmd(commands, device, querySet, cmd->firstQuery,
785                                              cmd->queryCount, destination, cmd->destinationOffset);
786 
787                     break;
788                 }
789 
790                 case Command::WriteTimestamp: {
791                     WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
792 
793                     // The query must be reset between uses.
794                     device->fn.CmdResetQueryPool(commands, ToBackend(cmd->querySet)->GetHandle(),
795                                                  cmd->queryIndex, 1);
796 
797                     RecordWriteTimestampCmd(recordingContext, device, cmd);
798                     break;
799                 }
800 
801                 case Command::InsertDebugMarker: {
802                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
803                         InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
804                         const char* label = mCommands.NextData<char>(cmd->length + 1);
805                         VkDebugUtilsLabelEXT utilsLabel;
806                         utilsLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
807                         utilsLabel.pNext = nullptr;
808                         utilsLabel.pLabelName = label;
809                         // Default color to black
810                         utilsLabel.color[0] = 0.0;
811                         utilsLabel.color[1] = 0.0;
812                         utilsLabel.color[2] = 0.0;
813                         utilsLabel.color[3] = 1.0;
814                         device->fn.CmdInsertDebugUtilsLabelEXT(commands, &utilsLabel);
815                     } else {
816                         SkipCommand(&mCommands, Command::InsertDebugMarker);
817                     }
818                     break;
819                 }
820 
821                 case Command::PopDebugGroup: {
822                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
823                         mCommands.NextCommand<PopDebugGroupCmd>();
824                         device->fn.CmdEndDebugUtilsLabelEXT(commands);
825                     } else {
826                         SkipCommand(&mCommands, Command::PopDebugGroup);
827                     }
828                     break;
829                 }
830 
831                 case Command::PushDebugGroup: {
832                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
833                         PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
834                         const char* label = mCommands.NextData<char>(cmd->length + 1);
835                         VkDebugUtilsLabelEXT utilsLabel;
836                         utilsLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
837                         utilsLabel.pNext = nullptr;
838                         utilsLabel.pLabelName = label;
839                         // Default color to black
840                         utilsLabel.color[0] = 0.0;
841                         utilsLabel.color[1] = 0.0;
842                         utilsLabel.color[2] = 0.0;
843                         utilsLabel.color[3] = 1.0;
844                         device->fn.CmdBeginDebugUtilsLabelEXT(commands, &utilsLabel);
845                     } else {
846                         SkipCommand(&mCommands, Command::PushDebugGroup);
847                     }
848                     break;
849                 }
850 
851                 case Command::WriteBuffer: {
852                     WriteBufferCmd* write = mCommands.NextCommand<WriteBufferCmd>();
853                     const uint64_t offset = write->offset;
854                     const uint64_t size = write->size;
855                     if (size == 0) {
856                         continue;
857                     }
858 
859                     Buffer* dstBuffer = ToBackend(write->buffer.Get());
860                     uint8_t* data = mCommands.NextData<uint8_t>(size);
861                     Device* device = ToBackend(GetDevice());
862 
863                     UploadHandle uploadHandle;
864                     DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate(
865                                                       size, device->GetPendingCommandSerial(),
866                                                       kCopyBufferToBufferOffsetAlignment));
867                     ASSERT(uploadHandle.mappedBuffer != nullptr);
868                     memcpy(uploadHandle.mappedBuffer, data, size);
869 
870                     dstBuffer->EnsureDataInitializedAsDestination(recordingContext, offset, size);
871 
872                     dstBuffer->TransitionUsageNow(recordingContext, wgpu::BufferUsage::CopyDst);
873 
874                     VkBufferCopy copy;
875                     copy.srcOffset = uploadHandle.startOffset;
876                     copy.dstOffset = offset;
877                     copy.size = size;
878 
879                     device->fn.CmdCopyBuffer(
880                         commands, ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(),
881                         dstBuffer->GetHandle(), 1, &copy);
882                     break;
883                 }
884 
885                 default:
886                     break;
887             }
888         }
889 
890         return {};
891     }
892 
RecordComputePass(CommandRecordingContext* recordingContext, const ComputePassResourceUsage& resourceUsages)893     MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext,
894                                                 const ComputePassResourceUsage& resourceUsages) {
895         Device* device = ToBackend(GetDevice());
896         VkCommandBuffer commands = recordingContext->commandBuffer;
897 
898         uint64_t currentDispatch = 0;
899         DescriptorSetTracker descriptorSets = {};
900 
901         Command type;
902         while (mCommands.NextCommandId(&type)) {
903             switch (type) {
904                 case Command::EndComputePass: {
905                     mCommands.NextCommand<EndComputePassCmd>();
906                     return {};
907                 }
908 
909                 case Command::Dispatch: {
910                     DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
911 
912                     TransitionAndClearForSyncScope(device, recordingContext,
913                                                    resourceUsages.dispatchUsages[currentDispatch]);
914                     descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_COMPUTE);
915 
916                     device->fn.CmdDispatch(commands, dispatch->x, dispatch->y, dispatch->z);
917                     currentDispatch++;
918                     break;
919                 }
920 
921                 case Command::DispatchIndirect: {
922                     DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>();
923                     VkBuffer indirectBuffer = ToBackend(dispatch->indirectBuffer)->GetHandle();
924 
925                     TransitionAndClearForSyncScope(device, recordingContext,
926                                                    resourceUsages.dispatchUsages[currentDispatch]);
927                     descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_COMPUTE);
928 
929                     device->fn.CmdDispatchIndirect(
930                         commands, indirectBuffer,
931                         static_cast<VkDeviceSize>(dispatch->indirectOffset));
932                     currentDispatch++;
933                     break;
934                 }
935 
936                 case Command::SetBindGroup: {
937                     SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
938 
939                     BindGroup* bindGroup = ToBackend(cmd->group.Get());
940                     uint32_t* dynamicOffsets = nullptr;
941                     if (cmd->dynamicOffsetCount > 0) {
942                         dynamicOffsets = mCommands.NextData<uint32_t>(cmd->dynamicOffsetCount);
943                     }
944 
945                     descriptorSets.OnSetBindGroup(cmd->index, bindGroup, cmd->dynamicOffsetCount,
946                                                   dynamicOffsets);
947                     break;
948                 }
949 
950                 case Command::SetComputePipeline: {
951                     SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
952                     ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get();
953 
954                     device->fn.CmdBindPipeline(commands, VK_PIPELINE_BIND_POINT_COMPUTE,
955                                                pipeline->GetHandle());
956                     descriptorSets.OnSetPipeline(pipeline);
957                     break;
958                 }
959 
960                 case Command::InsertDebugMarker: {
961                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
962                         InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
963                         const char* label = mCommands.NextData<char>(cmd->length + 1);
964                         VkDebugUtilsLabelEXT utilsLabel;
965                         utilsLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
966                         utilsLabel.pNext = nullptr;
967                         utilsLabel.pLabelName = label;
968                         // Default color to black
969                         utilsLabel.color[0] = 0.0;
970                         utilsLabel.color[1] = 0.0;
971                         utilsLabel.color[2] = 0.0;
972                         utilsLabel.color[3] = 1.0;
973                         device->fn.CmdInsertDebugUtilsLabelEXT(commands, &utilsLabel);
974                     } else {
975                         SkipCommand(&mCommands, Command::InsertDebugMarker);
976                     }
977                     break;
978                 }
979 
980                 case Command::PopDebugGroup: {
981                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
982                         mCommands.NextCommand<PopDebugGroupCmd>();
983                         device->fn.CmdEndDebugUtilsLabelEXT(commands);
984                     } else {
985                         SkipCommand(&mCommands, Command::PopDebugGroup);
986                     }
987                     break;
988                 }
989 
990                 case Command::PushDebugGroup: {
991                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
992                         PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
993                         const char* label = mCommands.NextData<char>(cmd->length + 1);
994                         VkDebugUtilsLabelEXT utilsLabel;
995                         utilsLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
996                         utilsLabel.pNext = nullptr;
997                         utilsLabel.pLabelName = label;
998                         // Default color to black
999                         utilsLabel.color[0] = 0.0;
1000                         utilsLabel.color[1] = 0.0;
1001                         utilsLabel.color[2] = 0.0;
1002                         utilsLabel.color[3] = 1.0;
1003                         device->fn.CmdBeginDebugUtilsLabelEXT(commands, &utilsLabel);
1004                     } else {
1005                         SkipCommand(&mCommands, Command::PushDebugGroup);
1006                     }
1007                     break;
1008                 }
1009 
1010                 case Command::WriteTimestamp: {
1011                     WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
1012 
1013                     // The query must be reset between uses.
1014                     device->fn.CmdResetQueryPool(commands, ToBackend(cmd->querySet)->GetHandle(),
1015                                                  cmd->queryIndex, 1);
1016 
1017                     RecordWriteTimestampCmd(recordingContext, device, cmd);
1018                     break;
1019                 }
1020 
1021                 default:
1022                     UNREACHABLE();
1023             }
1024         }
1025 
1026         // EndComputePass should have been called
1027         UNREACHABLE();
1028     }
1029 
RecordRenderPass(CommandRecordingContext* recordingContext, BeginRenderPassCmd* renderPassCmd)1030     MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingContext,
1031                                                BeginRenderPassCmd* renderPassCmd) {
1032         Device* device = ToBackend(GetDevice());
1033         VkCommandBuffer commands = recordingContext->commandBuffer;
1034 
1035         DAWN_TRY(RecordBeginRenderPass(recordingContext, device, renderPassCmd));
1036 
1037         // Set the default value for the dynamic state
1038         {
1039             device->fn.CmdSetLineWidth(commands, 1.0f);
1040             device->fn.CmdSetDepthBounds(commands, 0.0f, 1.0f);
1041 
1042             device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK, 0);
1043 
1044             float blendConstants[4] = {
1045                 0.0f,
1046                 0.0f,
1047                 0.0f,
1048                 0.0f,
1049             };
1050             device->fn.CmdSetBlendConstants(commands, blendConstants);
1051 
1052             // The viewport and scissor default to cover all of the attachments
1053             VkViewport viewport;
1054             viewport.x = 0.0f;
1055             viewport.y = static_cast<float>(renderPassCmd->height);
1056             viewport.width = static_cast<float>(renderPassCmd->width);
1057             viewport.height = -static_cast<float>(renderPassCmd->height);
1058             viewport.minDepth = 0.0f;
1059             viewport.maxDepth = 1.0f;
1060             device->fn.CmdSetViewport(commands, 0, 1, &viewport);
1061 
1062             VkRect2D scissorRect;
1063             scissorRect.offset.x = 0;
1064             scissorRect.offset.y = 0;
1065             scissorRect.extent.width = renderPassCmd->width;
1066             scissorRect.extent.height = renderPassCmd->height;
1067             device->fn.CmdSetScissor(commands, 0, 1, &scissorRect);
1068         }
1069 
1070         DescriptorSetTracker descriptorSets = {};
1071         RenderPipeline* lastPipeline = nullptr;
1072 
1073         auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
1074             switch (type) {
1075                 case Command::Draw: {
1076                     DrawCmd* draw = iter->NextCommand<DrawCmd>();
1077 
1078                     descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_GRAPHICS);
1079                     device->fn.CmdDraw(commands, draw->vertexCount, draw->instanceCount,
1080                                        draw->firstVertex, draw->firstInstance);
1081                     break;
1082                 }
1083 
1084                 case Command::DrawIndexed: {
1085                     DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
1086 
1087                     descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_GRAPHICS);
1088                     device->fn.CmdDrawIndexed(commands, draw->indexCount, draw->instanceCount,
1089                                               draw->firstIndex, draw->baseVertex,
1090                                               draw->firstInstance);
1091                     break;
1092                 }
1093 
1094                 case Command::DrawIndirect: {
1095                     DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
1096                     Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
1097 
1098                     descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_GRAPHICS);
1099                     device->fn.CmdDrawIndirect(commands, buffer->GetHandle(),
1100                                                static_cast<VkDeviceSize>(draw->indirectOffset), 1,
1101                                                0);
1102                     break;
1103                 }
1104 
1105                 case Command::DrawIndexedIndirect: {
1106                     DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
1107                     Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
1108                     ASSERT(buffer != nullptr);
1109 
1110                     descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_GRAPHICS);
1111                     device->fn.CmdDrawIndexedIndirect(
1112                         commands, buffer->GetHandle(),
1113                         static_cast<VkDeviceSize>(draw->indirectOffset), 1, 0);
1114                     break;
1115                 }
1116 
1117                 case Command::InsertDebugMarker: {
1118                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
1119                         InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>();
1120                         const char* label = iter->NextData<char>(cmd->length + 1);
1121                         VkDebugUtilsLabelEXT utilsLabel;
1122                         utilsLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
1123                         utilsLabel.pNext = nullptr;
1124                         utilsLabel.pLabelName = label;
1125                         // Default color to black
1126                         utilsLabel.color[0] = 0.0;
1127                         utilsLabel.color[1] = 0.0;
1128                         utilsLabel.color[2] = 0.0;
1129                         utilsLabel.color[3] = 1.0;
1130                         device->fn.CmdInsertDebugUtilsLabelEXT(commands, &utilsLabel);
1131                     } else {
1132                         SkipCommand(iter, Command::InsertDebugMarker);
1133                     }
1134                     break;
1135                 }
1136 
1137                 case Command::PopDebugGroup: {
1138                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
1139                         iter->NextCommand<PopDebugGroupCmd>();
1140                         device->fn.CmdEndDebugUtilsLabelEXT(commands);
1141                     } else {
1142                         SkipCommand(iter, Command::PopDebugGroup);
1143                     }
1144                     break;
1145                 }
1146 
1147                 case Command::PushDebugGroup: {
1148                     if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
1149                         PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>();
1150                         const char* label = iter->NextData<char>(cmd->length + 1);
1151                         VkDebugUtilsLabelEXT utilsLabel;
1152                         utilsLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
1153                         utilsLabel.pNext = nullptr;
1154                         utilsLabel.pLabelName = label;
1155                         // Default color to black
1156                         utilsLabel.color[0] = 0.0;
1157                         utilsLabel.color[1] = 0.0;
1158                         utilsLabel.color[2] = 0.0;
1159                         utilsLabel.color[3] = 1.0;
1160                         device->fn.CmdBeginDebugUtilsLabelEXT(commands, &utilsLabel);
1161                     } else {
1162                         SkipCommand(iter, Command::PushDebugGroup);
1163                     }
1164                     break;
1165                 }
1166 
1167                 case Command::SetBindGroup: {
1168                     SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
1169                     BindGroup* bindGroup = ToBackend(cmd->group.Get());
1170                     uint32_t* dynamicOffsets = nullptr;
1171                     if (cmd->dynamicOffsetCount > 0) {
1172                         dynamicOffsets = iter->NextData<uint32_t>(cmd->dynamicOffsetCount);
1173                     }
1174 
1175                     descriptorSets.OnSetBindGroup(cmd->index, bindGroup, cmd->dynamicOffsetCount,
1176                                                   dynamicOffsets);
1177                     break;
1178                 }
1179 
1180                 case Command::SetIndexBuffer: {
1181                     SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
1182                     VkBuffer indexBuffer = ToBackend(cmd->buffer)->GetHandle();
1183 
1184                     device->fn.CmdBindIndexBuffer(commands, indexBuffer, cmd->offset,
1185                                                   VulkanIndexType(cmd->format));
1186                     break;
1187                 }
1188 
1189                 case Command::SetRenderPipeline: {
1190                     SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>();
1191                     RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get();
1192 
1193                     device->fn.CmdBindPipeline(commands, VK_PIPELINE_BIND_POINT_GRAPHICS,
1194                                                pipeline->GetHandle());
1195                     lastPipeline = pipeline;
1196 
1197                     descriptorSets.OnSetPipeline(pipeline);
1198                     break;
1199                 }
1200 
1201                 case Command::SetVertexBuffer: {
1202                     SetVertexBufferCmd* cmd = iter->NextCommand<SetVertexBufferCmd>();
1203                     VkBuffer buffer = ToBackend(cmd->buffer)->GetHandle();
1204                     VkDeviceSize offset = static_cast<VkDeviceSize>(cmd->offset);
1205 
1206                     device->fn.CmdBindVertexBuffers(commands, static_cast<uint8_t>(cmd->slot), 1,
1207                                                     &*buffer, &offset);
1208                     break;
1209                 }
1210 
1211                 default:
1212                     UNREACHABLE();
1213                     break;
1214             }
1215         };
1216 
1217         Command type;
1218         while (mCommands.NextCommandId(&type)) {
1219             switch (type) {
1220                 case Command::EndRenderPass: {
1221                     mCommands.NextCommand<EndRenderPassCmd>();
1222                     device->fn.CmdEndRenderPass(commands);
1223                     return {};
1224                 }
1225 
1226                 case Command::SetBlendConstant: {
1227                     SetBlendConstantCmd* cmd = mCommands.NextCommand<SetBlendConstantCmd>();
1228                     const std::array<float, 4> blendConstants = ConvertToFloatColor(cmd->color);
1229                     device->fn.CmdSetBlendConstants(commands, blendConstants.data());
1230                     break;
1231                 }
1232 
1233                 case Command::SetStencilReference: {
1234                     SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
1235                     device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK,
1236                                                       cmd->reference);
1237                     break;
1238                 }
1239 
1240                 case Command::SetViewport: {
1241                     SetViewportCmd* cmd = mCommands.NextCommand<SetViewportCmd>();
1242                     VkViewport viewport;
1243                     viewport.x = cmd->x;
1244                     viewport.y = cmd->y + cmd->height;
1245                     viewport.width = cmd->width;
1246                     viewport.height = -cmd->height;
1247                     viewport.minDepth = cmd->minDepth;
1248                     viewport.maxDepth = cmd->maxDepth;
1249 
1250                     // Vulkan disallows width = 0, but VK_KHR_maintenance1 which we require allows
1251                     // height = 0 so use that to do an empty viewport.
1252                     if (viewport.width == 0) {
1253                         viewport.height = 0;
1254 
1255                         // Set the viewport x range to a range that's always valid.
1256                         viewport.x = 0;
1257                         viewport.width = 1;
1258                     }
1259 
1260                     device->fn.CmdSetViewport(commands, 0, 1, &viewport);
1261                     break;
1262                 }
1263 
1264                 case Command::SetScissorRect: {
1265                     SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
1266                     VkRect2D rect;
1267                     rect.offset.x = cmd->x;
1268                     rect.offset.y = cmd->y;
1269                     rect.extent.width = cmd->width;
1270                     rect.extent.height = cmd->height;
1271 
1272                     device->fn.CmdSetScissor(commands, 0, 1, &rect);
1273                     break;
1274                 }
1275 
1276                 case Command::ExecuteBundles: {
1277                     ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>();
1278                     auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count);
1279 
1280                     for (uint32_t i = 0; i < cmd->count; ++i) {
1281                         CommandIterator* iter = bundles[i]->GetCommands();
1282                         iter->Reset();
1283                         while (iter->NextCommandId(&type)) {
1284                             EncodeRenderBundleCommand(iter, type);
1285                         }
1286                     }
1287                     break;
1288                 }
1289 
1290                 case Command::BeginOcclusionQuery: {
1291                     BeginOcclusionQueryCmd* cmd = mCommands.NextCommand<BeginOcclusionQueryCmd>();
1292 
1293                     device->fn.CmdBeginQuery(commands, ToBackend(cmd->querySet.Get())->GetHandle(),
1294                                              cmd->queryIndex, 0);
1295                     break;
1296                 }
1297 
1298                 case Command::EndOcclusionQuery: {
1299                     EndOcclusionQueryCmd* cmd = mCommands.NextCommand<EndOcclusionQueryCmd>();
1300 
1301                     device->fn.CmdEndQuery(commands, ToBackend(cmd->querySet.Get())->GetHandle(),
1302                                            cmd->queryIndex);
1303                     break;
1304                 }
1305 
1306                 case Command::WriteTimestamp: {
1307                     WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
1308 
1309                     RecordWriteTimestampCmd(recordingContext, device, cmd);
1310                     break;
1311                 }
1312 
1313                 default: {
1314                     EncodeRenderBundleCommand(&mCommands, type);
1315                     break;
1316                 }
1317             }
1318         }
1319 
1320         // EndRenderPass should have been called
1321         UNREACHABLE();
1322     }
1323 
1324 }}  // namespace dawn_native::vulkan
1325