• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/d3d12/CommandBufferD3D12.h"
16 
17 #include "dawn_native/BindGroupTracker.h"
18 #include "dawn_native/CommandValidation.h"
19 #include "dawn_native/DynamicUploader.h"
20 #include "dawn_native/Error.h"
21 #include "dawn_native/RenderBundle.h"
22 #include "dawn_native/d3d12/BindGroupD3D12.h"
23 #include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
24 #include "dawn_native/d3d12/ComputePipelineD3D12.h"
25 #include "dawn_native/d3d12/DeviceD3D12.h"
26 #include "dawn_native/d3d12/PipelineLayoutD3D12.h"
27 #include "dawn_native/d3d12/PlatformFunctions.h"
28 #include "dawn_native/d3d12/QuerySetD3D12.h"
29 #include "dawn_native/d3d12/RenderPassBuilderD3D12.h"
30 #include "dawn_native/d3d12/RenderPipelineD3D12.h"
31 #include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
32 #include "dawn_native/d3d12/StagingBufferD3D12.h"
33 #include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h"
34 #include "dawn_native/d3d12/UtilsD3D12.h"
35 
36 namespace dawn_native { namespace d3d12 {
37 
38     namespace {
39 
DXGIIndexFormat(wgpu::IndexFormat format)40         DXGI_FORMAT DXGIIndexFormat(wgpu::IndexFormat format) {
41             switch (format) {
42                 case wgpu::IndexFormat::Undefined:
43                     return DXGI_FORMAT_UNKNOWN;
44                 case wgpu::IndexFormat::Uint16:
45                     return DXGI_FORMAT_R16_UINT;
46                 case wgpu::IndexFormat::Uint32:
47                     return DXGI_FORMAT_R32_UINT;
48             }
49         }
50 
D3D12QueryType(wgpu::QueryType type)51         D3D12_QUERY_TYPE D3D12QueryType(wgpu::QueryType type) {
52             switch (type) {
53                 case wgpu::QueryType::Occlusion:
54                     return D3D12_QUERY_TYPE_BINARY_OCCLUSION;
55                 case wgpu::QueryType::PipelineStatistics:
56                     return D3D12_QUERY_TYPE_PIPELINE_STATISTICS;
57                 case wgpu::QueryType::Timestamp:
58                     return D3D12_QUERY_TYPE_TIMESTAMP;
59             }
60         }
61 
CanUseCopyResource(const TextureCopy & src,const TextureCopy & dst,const Extent3D & copySize)62         bool CanUseCopyResource(const TextureCopy& src,
63                                 const TextureCopy& dst,
64                                 const Extent3D& copySize) {
65             // Checked by validation
66             ASSERT(src.texture->GetSampleCount() == dst.texture->GetSampleCount());
67             ASSERT(src.texture->GetFormat().format == dst.texture->GetFormat().format);
68             ASSERT(src.aspect == dst.aspect);
69 
70             const Extent3D& srcSize = src.texture->GetSize();
71             const Extent3D& dstSize = dst.texture->GetSize();
72 
73             // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-copyresource
74             // In order to use D3D12's copy resource, the textures must be the same dimensions, and
75             // the copy must be of the entire resource.
76             // TODO(dawn:129): Support 1D textures.
77             return src.aspect == src.texture->GetFormat().aspects &&
78                    src.texture->GetDimension() == dst.texture->GetDimension() &&  //
79                    dst.texture->GetNumMipLevels() == 1 &&                         //
80                    src.texture->GetNumMipLevels() == 1 &&  // A copy command is of a single mip, so
81                                                            // if a resource has more than one, we
82                                                            // definitely cannot use CopyResource.
83                    copySize.width == dstSize.width &&      //
84                    copySize.width == srcSize.width &&      //
85                    copySize.height == dstSize.height &&    //
86                    copySize.height == srcSize.height &&    //
87                    copySize.depthOrArrayLayers == dstSize.depthOrArrayLayers &&  //
88                    copySize.depthOrArrayLayers == srcSize.depthOrArrayLayers;
89         }
90 
RecordWriteTimestampCmd(ID3D12GraphicsCommandList * commandList,WriteTimestampCmd * cmd)91         void RecordWriteTimestampCmd(ID3D12GraphicsCommandList* commandList,
92                                      WriteTimestampCmd* cmd) {
93             QuerySet* querySet = ToBackend(cmd->querySet.Get());
94             ASSERT(D3D12QueryType(querySet->GetQueryType()) == D3D12_QUERY_TYPE_TIMESTAMP);
95             commandList->EndQuery(querySet->GetQueryHeap(), D3D12_QUERY_TYPE_TIMESTAMP,
96                                   cmd->queryIndex);
97         }
98 
RecordResolveQuerySetCmd(ID3D12GraphicsCommandList * commandList,Device * device,QuerySet * querySet,uint32_t firstQuery,uint32_t queryCount,Buffer * destination,uint64_t destinationOffset)99         void RecordResolveQuerySetCmd(ID3D12GraphicsCommandList* commandList,
100                                       Device* device,
101                                       QuerySet* querySet,
102                                       uint32_t firstQuery,
103                                       uint32_t queryCount,
104                                       Buffer* destination,
105                                       uint64_t destinationOffset) {
106             const std::vector<bool>& availability = querySet->GetQueryAvailability();
107 
108             auto currentIt = availability.begin() + firstQuery;
109             auto lastIt = availability.begin() + firstQuery + queryCount;
110 
111             // Traverse available queries in the range of [firstQuery, firstQuery +  queryCount - 1]
112             while (currentIt != lastIt) {
113                 auto firstTrueIt = std::find(currentIt, lastIt, true);
114                 // No available query found for resolving
115                 if (firstTrueIt == lastIt) {
116                     break;
117                 }
118                 auto nextFalseIt = std::find(firstTrueIt, lastIt, false);
119 
120                 // The query index of firstTrueIt where the resolving starts
121                 uint32_t resolveQueryIndex = std::distance(availability.begin(), firstTrueIt);
122                 // The queries count between firstTrueIt and nextFalseIt need to be resolved
123                 uint32_t resolveQueryCount = std::distance(firstTrueIt, nextFalseIt);
124 
125                 // Calculate destinationOffset based on the current resolveQueryIndex and firstQuery
126                 uint32_t resolveDestinationOffset =
127                     destinationOffset + (resolveQueryIndex - firstQuery) * sizeof(uint64_t);
128 
129                 // Resolve the queries between firstTrueIt and nextFalseIt (which is at most lastIt)
130                 commandList->ResolveQueryData(
131                     querySet->GetQueryHeap(), D3D12QueryType(querySet->GetQueryType()),
132                     resolveQueryIndex, resolveQueryCount, destination->GetD3D12Resource(),
133                     resolveDestinationOffset);
134 
135                 // Set current iterator to next false
136                 currentIt = nextFalseIt;
137             }
138         }
139 
RecordFirstIndexOffset(ID3D12GraphicsCommandList * commandList,RenderPipeline * pipeline,uint32_t firstVertex,uint32_t firstInstance)140         void RecordFirstIndexOffset(ID3D12GraphicsCommandList* commandList,
141                                     RenderPipeline* pipeline,
142                                     uint32_t firstVertex,
143                                     uint32_t firstInstance) {
144             const FirstOffsetInfo& firstOffsetInfo = pipeline->GetFirstOffsetInfo();
145             if (!firstOffsetInfo.usesVertexIndex && !firstOffsetInfo.usesInstanceIndex) {
146                 return;
147             }
148             std::array<uint32_t, 2> offsets{};
149             uint32_t count = 0;
150             if (firstOffsetInfo.usesVertexIndex) {
151                 offsets[firstOffsetInfo.vertexIndexOffset / sizeof(uint32_t)] = firstVertex;
152                 ++count;
153             }
154             if (firstOffsetInfo.usesInstanceIndex) {
155                 offsets[firstOffsetInfo.instanceIndexOffset / sizeof(uint32_t)] = firstInstance;
156                 ++count;
157             }
158             PipelineLayout* layout = ToBackend(pipeline->GetLayout());
159             commandList->SetGraphicsRoot32BitConstants(layout->GetFirstIndexOffsetParameterIndex(),
160                                                        count, offsets.data(), 0);
161         }
162 
ShouldCopyUsingTemporaryBuffer(DeviceBase * device,const TextureCopy & srcCopy,const TextureCopy & dstCopy)163         bool ShouldCopyUsingTemporaryBuffer(DeviceBase* device,
164                                             const TextureCopy& srcCopy,
165                                             const TextureCopy& dstCopy) {
166             // Currently we only need the workaround for an Intel D3D12 driver issue.
167             if (device->IsToggleEnabled(
168                     Toggle::
169                         UseTempBufferInSmallFormatTextureToTextureCopyFromGreaterToLessMipLevel)) {
170                 bool copyToLesserLevel = srcCopy.mipLevel > dstCopy.mipLevel;
171                 ASSERT(srcCopy.texture->GetFormat().format == dstCopy.texture->GetFormat().format);
172 
173                 // GetAspectInfo(aspect) requires HasOneBit(aspect) == true, plus the texel block
174                 // sizes of depth stencil formats are always no less than 4 bytes.
175                 bool isSmallColorFormat =
176                     HasOneBit(srcCopy.aspect) &&
177                     srcCopy.texture->GetFormat().GetAspectInfo(srcCopy.aspect).block.byteSize < 4u;
178                 if (copyToLesserLevel && isSmallColorFormat) {
179                     return true;
180                 }
181             }
182 
183             return false;
184         }
185 
RecordCopyTextureWithTemporaryBuffer(CommandRecordingContext * recordingContext,const TextureCopy & srcCopy,const TextureCopy & dstCopy,const Extent3D & copySize)186         MaybeError RecordCopyTextureWithTemporaryBuffer(CommandRecordingContext* recordingContext,
187                                                         const TextureCopy& srcCopy,
188                                                         const TextureCopy& dstCopy,
189                                                         const Extent3D& copySize) {
190             ASSERT(srcCopy.texture->GetFormat().format == dstCopy.texture->GetFormat().format);
191             ASSERT(srcCopy.aspect == dstCopy.aspect);
192             dawn_native::Format format = srcCopy.texture->GetFormat();
193             const TexelBlockInfo& blockInfo = format.GetAspectInfo(srcCopy.aspect).block;
194             ASSERT(copySize.width % blockInfo.width == 0);
195             uint32_t widthInBlocks = copySize.width / blockInfo.width;
196             ASSERT(copySize.height % blockInfo.height == 0);
197             uint32_t heightInBlocks = copySize.height / blockInfo.height;
198 
199             // Create tempBuffer
200             uint32_t bytesPerRow =
201                 Align(blockInfo.byteSize * widthInBlocks, kTextureBytesPerRowAlignment);
202             uint32_t rowsPerImage = heightInBlocks;
203 
204             // The size of temporary buffer isn't needed to be a multiple of 4 because we don't
205             // need to set mappedAtCreation to be true.
206             auto tempBufferSize =
207                 ComputeRequiredBytesInCopy(blockInfo, copySize, bytesPerRow, rowsPerImage);
208 
209             BufferDescriptor tempBufferDescriptor;
210             tempBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
211             tempBufferDescriptor.size = tempBufferSize.AcquireSuccess();
212             Device* device = ToBackend(srcCopy.texture->GetDevice());
213             Ref<BufferBase> tempBufferBase;
214             DAWN_TRY_ASSIGN(tempBufferBase, device->CreateBuffer(&tempBufferDescriptor));
215             Ref<Buffer> tempBuffer = ToBackend(std::move(tempBufferBase));
216 
217             // Copy from source texture into tempBuffer
218             Texture* srcTexture = ToBackend(srcCopy.texture).Get();
219             tempBuffer->TrackUsageAndTransitionNow(recordingContext, wgpu::BufferUsage::CopyDst);
220             BufferCopy bufferCopy;
221             bufferCopy.buffer = tempBuffer;
222             bufferCopy.offset = 0;
223             bufferCopy.bytesPerRow = bytesPerRow;
224             bufferCopy.rowsPerImage = rowsPerImage;
225             RecordCopyTextureToBuffer(recordingContext->GetCommandList(), srcCopy, bufferCopy,
226                                       srcTexture, tempBuffer.Get(), copySize);
227 
228             // Copy from tempBuffer into destination texture
229             tempBuffer->TrackUsageAndTransitionNow(recordingContext, wgpu::BufferUsage::CopySrc);
230             Texture* dstTexture = ToBackend(dstCopy.texture).Get();
231             RecordCopyBufferToTexture(recordingContext, dstCopy, tempBuffer->GetD3D12Resource(), 0,
232                                       bytesPerRow, rowsPerImage, copySize, dstTexture,
233                                       dstCopy.aspect);
234 
235             // Save tempBuffer into recordingContext
236             recordingContext->AddToTempBuffers(std::move(tempBuffer));
237 
238             return {};
239         }
240 
RecordNumWorkgroupsForDispatch(ID3D12GraphicsCommandList * commandList,ComputePipeline * pipeline,DispatchCmd * dispatch)241         void RecordNumWorkgroupsForDispatch(ID3D12GraphicsCommandList* commandList,
242                                             ComputePipeline* pipeline,
243                                             DispatchCmd* dispatch) {
244             if (!pipeline->UsesNumWorkgroups()) {
245                 return;
246             }
247 
248             PipelineLayout* layout = ToBackend(pipeline->GetLayout());
249             commandList->SetComputeRoot32BitConstants(layout->GetNumWorkgroupsParameterIndex(), 3,
250                                                       dispatch, 0);
251         }
252 
253         // Records the necessary barriers for a synchronization scope using the resource usage
254         // data pre-computed in the frontend. Also performs lazy initialization if required.
255         // Returns whether any UAV are used in the synchronization scope.
TransitionAndClearForSyncScope(CommandRecordingContext * commandContext,const SyncScopeResourceUsage & usages)256         bool TransitionAndClearForSyncScope(CommandRecordingContext* commandContext,
257                                             const SyncScopeResourceUsage& usages) {
258             std::vector<D3D12_RESOURCE_BARRIER> barriers;
259 
260             ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
261 
262             wgpu::BufferUsage bufferUsages = wgpu::BufferUsage::None;
263 
264             for (size_t i = 0; i < usages.buffers.size(); ++i) {
265                 Buffer* buffer = ToBackend(usages.buffers[i]);
266 
267                 // TODO(crbug.com/dawn/852): clear storage buffers with
268                 // ClearUnorderedAccessView*().
269                 buffer->GetDevice()->ConsumedError(buffer->EnsureDataInitialized(commandContext));
270 
271                 D3D12_RESOURCE_BARRIER barrier;
272                 if (buffer->TrackUsageAndGetResourceBarrier(commandContext, &barrier,
273                                                             usages.bufferUsages[i])) {
274                     barriers.push_back(barrier);
275                 }
276                 bufferUsages |= usages.bufferUsages[i];
277             }
278 
279             wgpu::TextureUsage textureUsages = wgpu::TextureUsage::None;
280 
281             for (size_t i = 0; i < usages.textures.size(); ++i) {
282                 Texture* texture = ToBackend(usages.textures[i]);
283 
284                 // Clear subresources that are not render attachments. Render attachments will be
285                 // cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
286                 // subresource has not been initialized before the render pass.
287                 usages.textureUsages[i].Iterate(
288                     [&](const SubresourceRange& range, wgpu::TextureUsage usage) {
289                         if (usage & ~wgpu::TextureUsage::RenderAttachment) {
290                             texture->EnsureSubresourceContentInitialized(commandContext, range);
291                         }
292                         textureUsages |= usage;
293                     });
294 
295                 ToBackend(usages.textures[i])
296                     ->TrackUsageAndGetResourceBarrierForPass(commandContext, &barriers,
297                                                              usages.textureUsages[i]);
298             }
299 
300             if (barriers.size()) {
301                 commandList->ResourceBarrier(barriers.size(), barriers.data());
302             }
303 
304             return (bufferUsages & wgpu::BufferUsage::Storage ||
305                     textureUsages & wgpu::TextureUsage::StorageBinding);
306         }
307 
308     }  // anonymous namespace
309 
310     class BindGroupStateTracker : public BindGroupTrackerBase<false, uint64_t> {
311         using Base = BindGroupTrackerBase;
312 
313       public:
BindGroupStateTracker(Device * device)314         BindGroupStateTracker(Device* device)
315             : BindGroupTrackerBase(),
316               mDevice(device),
317               mViewAllocator(device->GetViewShaderVisibleDescriptorAllocator()),
318               mSamplerAllocator(device->GetSamplerShaderVisibleDescriptorAllocator()) {
319         }
320 
SetInComputePass(bool inCompute_)321         void SetInComputePass(bool inCompute_) {
322             mInCompute = inCompute_;
323         }
324 
Apply(CommandRecordingContext * commandContext)325         MaybeError Apply(CommandRecordingContext* commandContext) {
326             BeforeApply();
327 
328             ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
329             UpdateRootSignatureIfNecessary(commandList);
330 
331             // Bindgroups are allocated in shader-visible descriptor heaps which are managed by a
332             // ringbuffer. There can be a single shader-visible descriptor heap of each type bound
333             // at any given time. This means that when we switch heaps, all other currently bound
334             // bindgroups must be re-populated. Bindgroups can fail allocation gracefully which is
335             // the signal to change the bounded heaps.
336             // Re-populating all bindgroups after the last one fails causes duplicated allocations
337             // to occur on overflow.
338             bool didCreateBindGroupViews = true;
339             bool didCreateBindGroupSamplers = true;
340             for (BindGroupIndex index : IterateBitSet(mDirtyBindGroups)) {
341                 BindGroup* group = ToBackend(mBindGroups[index]);
342                 didCreateBindGroupViews = group->PopulateViews(mViewAllocator);
343                 didCreateBindGroupSamplers = group->PopulateSamplers(mDevice, mSamplerAllocator);
344                 if (!didCreateBindGroupViews && !didCreateBindGroupSamplers) {
345                     break;
346                 }
347             }
348 
349             if (!didCreateBindGroupViews || !didCreateBindGroupSamplers) {
350                 if (!didCreateBindGroupViews) {
351                     DAWN_TRY(mViewAllocator->AllocateAndSwitchShaderVisibleHeap());
352                 }
353 
354                 if (!didCreateBindGroupSamplers) {
355                     DAWN_TRY(mSamplerAllocator->AllocateAndSwitchShaderVisibleHeap());
356                 }
357 
358                 mDirtyBindGroupsObjectChangedOrIsDynamic |= mBindGroupLayoutsMask;
359                 mDirtyBindGroups |= mBindGroupLayoutsMask;
360 
361                 // Must be called before applying the bindgroups.
362                 SetID3D12DescriptorHeaps(commandList);
363 
364                 for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) {
365                     BindGroup* group = ToBackend(mBindGroups[index]);
366                     didCreateBindGroupViews = group->PopulateViews(mViewAllocator);
367                     didCreateBindGroupSamplers =
368                         group->PopulateSamplers(mDevice, mSamplerAllocator);
369                     ASSERT(didCreateBindGroupViews);
370                     ASSERT(didCreateBindGroupSamplers);
371                 }
372             }
373 
374             for (BindGroupIndex index : IterateBitSet(mDirtyBindGroupsObjectChangedOrIsDynamic)) {
375                 BindGroup* group = ToBackend(mBindGroups[index]);
376                 ApplyBindGroup(commandList, ToBackend(mPipelineLayout), index, group,
377                                mDynamicOffsetCounts[index], mDynamicOffsets[index].data());
378             }
379 
380             AfterApply();
381 
382             return {};
383         }
384 
SetID3D12DescriptorHeaps(ID3D12GraphicsCommandList * commandList)385         void SetID3D12DescriptorHeaps(ID3D12GraphicsCommandList* commandList) {
386             ASSERT(commandList != nullptr);
387             std::array<ID3D12DescriptorHeap*, 2> descriptorHeaps = {
388                 mViewAllocator->GetShaderVisibleHeap(), mSamplerAllocator->GetShaderVisibleHeap()};
389             ASSERT(descriptorHeaps[0] != nullptr);
390             ASSERT(descriptorHeaps[1] != nullptr);
391             commandList->SetDescriptorHeaps(descriptorHeaps.size(), descriptorHeaps.data());
392         }
393 
394       private:
UpdateRootSignatureIfNecessary(ID3D12GraphicsCommandList * commandList)395         void UpdateRootSignatureIfNecessary(ID3D12GraphicsCommandList* commandList) {
396             if (mLastAppliedPipelineLayout != mPipelineLayout) {
397                 if (mInCompute) {
398                     commandList->SetComputeRootSignature(
399                         ToBackend(mPipelineLayout)->GetRootSignature());
400                 } else {
401                     commandList->SetGraphicsRootSignature(
402                         ToBackend(mPipelineLayout)->GetRootSignature());
403                 }
404                 // Invalidate the root sampler tables previously set in the root signature.
405                 mBoundRootSamplerTables = {};
406             }
407         }
408 
ApplyBindGroup(ID3D12GraphicsCommandList * commandList,const PipelineLayout * pipelineLayout,BindGroupIndex index,BindGroup * group,uint32_t dynamicOffsetCountIn,const uint64_t * dynamicOffsetsIn)409         void ApplyBindGroup(ID3D12GraphicsCommandList* commandList,
410                             const PipelineLayout* pipelineLayout,
411                             BindGroupIndex index,
412                             BindGroup* group,
413                             uint32_t dynamicOffsetCountIn,
414                             const uint64_t* dynamicOffsetsIn) {
415             ityp::span<BindingIndex, const uint64_t> dynamicOffsets(
416                 dynamicOffsetsIn, BindingIndex(dynamicOffsetCountIn));
417             ASSERT(dynamicOffsets.size() == group->GetLayout()->GetDynamicBufferCount());
418 
419             // Usually, the application won't set the same offsets many times,
420             // so always try to apply dynamic offsets even if the offsets stay the same
421             if (dynamicOffsets.size() != BindingIndex(0)) {
422                 // Update dynamic offsets.
423                 // Dynamic buffer bindings are packed at the beginning of the layout.
424                 for (BindingIndex bindingIndex{0}; bindingIndex < dynamicOffsets.size();
425                      ++bindingIndex) {
426                     const BindingInfo& bindingInfo =
427                         group->GetLayout()->GetBindingInfo(bindingIndex);
428                     if (bindingInfo.visibility == wgpu::ShaderStage::None) {
429                         // Skip dynamic buffers that are not visible. D3D12 does not have None
430                         // visibility.
431                         continue;
432                     }
433 
434                     uint32_t parameterIndex =
435                         pipelineLayout->GetDynamicRootParameterIndex(index, bindingIndex);
436                     BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
437 
438                     // Calculate buffer locations that root descriptors links to. The location
439                     // is (base buffer location + initial offset + dynamic offset)
440                     uint64_t dynamicOffset = dynamicOffsets[bindingIndex];
441                     uint64_t offset = binding.offset + dynamicOffset;
442                     D3D12_GPU_VIRTUAL_ADDRESS bufferLocation =
443                         ToBackend(binding.buffer)->GetVA() + offset;
444 
445                     ASSERT(bindingInfo.bindingType == BindingInfoType::Buffer);
446                     switch (bindingInfo.buffer.type) {
447                         case wgpu::BufferBindingType::Uniform:
448                             if (mInCompute) {
449                                 commandList->SetComputeRootConstantBufferView(parameterIndex,
450                                                                               bufferLocation);
451                             } else {
452                                 commandList->SetGraphicsRootConstantBufferView(parameterIndex,
453                                                                                bufferLocation);
454                             }
455                             break;
456                         case wgpu::BufferBindingType::Storage:
457                         case kInternalStorageBufferBinding:
458                             if (mInCompute) {
459                                 commandList->SetComputeRootUnorderedAccessView(parameterIndex,
460                                                                                bufferLocation);
461                             } else {
462                                 commandList->SetGraphicsRootUnorderedAccessView(parameterIndex,
463                                                                                 bufferLocation);
464                             }
465                             break;
466                         case wgpu::BufferBindingType::ReadOnlyStorage:
467                             if (mInCompute) {
468                                 commandList->SetComputeRootShaderResourceView(parameterIndex,
469                                                                               bufferLocation);
470                             } else {
471                                 commandList->SetGraphicsRootShaderResourceView(parameterIndex,
472                                                                                bufferLocation);
473                             }
474                             break;
475                         case wgpu::BufferBindingType::Undefined:
476                             UNREACHABLE();
477                     }
478                 }
479             }
480 
481             // It's not necessary to update descriptor tables if only the dynamic offset changed.
482             if (!mDirtyBindGroups[index]) {
483                 return;
484             }
485 
486             const uint32_t cbvUavSrvCount =
487                 ToBackend(group->GetLayout())->GetCbvUavSrvDescriptorCount();
488             const uint32_t samplerCount =
489                 ToBackend(group->GetLayout())->GetSamplerDescriptorCount();
490 
491             if (cbvUavSrvCount > 0) {
492                 uint32_t parameterIndex = pipelineLayout->GetCbvUavSrvRootParameterIndex(index);
493                 const D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor = group->GetBaseViewDescriptor();
494                 if (mInCompute) {
495                     commandList->SetComputeRootDescriptorTable(parameterIndex, baseDescriptor);
496                 } else {
497                     commandList->SetGraphicsRootDescriptorTable(parameterIndex, baseDescriptor);
498                 }
499             }
500 
501             if (samplerCount > 0) {
502                 uint32_t parameterIndex = pipelineLayout->GetSamplerRootParameterIndex(index);
503                 const D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor =
504                     group->GetBaseSamplerDescriptor();
505                 // Check if the group requires its sampler table to be set in the pipeline.
506                 // This because sampler heap allocations could be cached and use the same table.
507                 if (mBoundRootSamplerTables[index].ptr != baseDescriptor.ptr) {
508                     if (mInCompute) {
509                         commandList->SetComputeRootDescriptorTable(parameterIndex, baseDescriptor);
510                     } else {
511                         commandList->SetGraphicsRootDescriptorTable(parameterIndex, baseDescriptor);
512                     }
513 
514                     mBoundRootSamplerTables[index] = baseDescriptor;
515                 }
516             }
517 
518             const auto& dynamicStorageBufferLengths = group->GetDynamicStorageBufferLengths();
519             if (dynamicStorageBufferLengths.size() != 0) {
520                 uint32_t parameterIndex =
521                     pipelineLayout->GetDynamicStorageBufferLengthsParameterIndex();
522                 uint32_t firstRegisterOffset =
523                     pipelineLayout->GetDynamicStorageBufferLengthInfo()[index].firstRegisterOffset;
524 
525                 if (mInCompute) {
526                     commandList->SetComputeRoot32BitConstants(
527                         parameterIndex, dynamicStorageBufferLengths.size(),
528                         dynamicStorageBufferLengths.data(), firstRegisterOffset);
529                 } else {
530                     commandList->SetGraphicsRoot32BitConstants(
531                         parameterIndex, dynamicStorageBufferLengths.size(),
532                         dynamicStorageBufferLengths.data(), firstRegisterOffset);
533                 }
534             }
535         }
536 
537         Device* mDevice;
538 
539         bool mInCompute = false;
540 
541         ityp::array<BindGroupIndex, D3D12_GPU_DESCRIPTOR_HANDLE, kMaxBindGroups>
542             mBoundRootSamplerTables = {};
543 
544         ShaderVisibleDescriptorAllocator* mViewAllocator;
545         ShaderVisibleDescriptorAllocator* mSamplerAllocator;
546     };
547 
548     namespace {
549         class VertexBufferTracker {
550           public:
OnSetVertexBuffer(VertexBufferSlot slot,Buffer * buffer,uint64_t offset,uint64_t size)551             void OnSetVertexBuffer(VertexBufferSlot slot,
552                                    Buffer* buffer,
553                                    uint64_t offset,
554                                    uint64_t size) {
555                 mStartSlot = std::min(mStartSlot, slot);
556                 mEndSlot = std::max(mEndSlot, ityp::Add(slot, VertexBufferSlot(uint8_t(1))));
557 
558                 auto* d3d12BufferView = &mD3D12BufferViews[slot];
559                 d3d12BufferView->BufferLocation = buffer->GetVA() + offset;
560                 d3d12BufferView->SizeInBytes = size;
561                 // The bufferView stride is set based on the vertex state before a draw.
562             }
563 
Apply(ID3D12GraphicsCommandList * commandList,const RenderPipeline * renderPipeline)564             void Apply(ID3D12GraphicsCommandList* commandList,
565                        const RenderPipeline* renderPipeline) {
566                 ASSERT(renderPipeline != nullptr);
567 
568                 VertexBufferSlot startSlot = mStartSlot;
569                 VertexBufferSlot endSlot = mEndSlot;
570 
571                 // If the vertex state has changed, we need to update the StrideInBytes
572                 // for the D3D12 buffer views. We also need to extend the dirty range to
573                 // touch all these slots because the stride may have changed.
574                 if (mLastAppliedRenderPipeline != renderPipeline) {
575                     mLastAppliedRenderPipeline = renderPipeline;
576 
577                     for (VertexBufferSlot slot :
578                          IterateBitSet(renderPipeline->GetVertexBufferSlotsUsed())) {
579                         startSlot = std::min(startSlot, slot);
580                         endSlot =
581                             std::max(endSlot, ityp::Add(slot, VertexBufferSlot(uint8_t(1))));
582                         mD3D12BufferViews[slot].StrideInBytes =
583                             renderPipeline->GetVertexBuffer(slot).arrayStride;
584                     }
585                 }
586 
587                 if (endSlot <= startSlot) {
588                     return;
589                 }
590 
591                 // mD3D12BufferViews is kept up to date with the most recent data passed
592                 // to SetVertexBuffer. This makes it correct to only track the start
593                 // and end of the dirty range. When Apply is called,
594                 // we will at worst set non-dirty vertex buffers in duplicate.
595                 commandList->IASetVertexBuffers(static_cast<uint8_t>(startSlot),
596                                                 static_cast<uint8_t>(ityp::Sub(endSlot, startSlot)),
597                                                 &mD3D12BufferViews[startSlot]);
598 
599                 mStartSlot = VertexBufferSlot(kMaxVertexBuffers);
600                 mEndSlot = VertexBufferSlot(uint8_t(0));
601             }
602 
603           private:
604             // startSlot and endSlot indicate the range of dirty vertex buffers.
605             // If there are multiple calls to SetVertexBuffer, the start and end
606             // represent the union of the dirty ranges (the union may have non-dirty
607             // data in the middle of the range).
608             const RenderPipeline* mLastAppliedRenderPipeline = nullptr;
609             VertexBufferSlot mStartSlot{kMaxVertexBuffers};
610             VertexBufferSlot mEndSlot{uint8_t(0)};
611             ityp::array<VertexBufferSlot, D3D12_VERTEX_BUFFER_VIEW, kMaxVertexBuffers>
612                 mD3D12BufferViews = {};
613         };
614 
ResolveMultisampledRenderPass(CommandRecordingContext * commandContext,BeginRenderPassCmd * renderPass)615         void ResolveMultisampledRenderPass(CommandRecordingContext* commandContext,
616                                            BeginRenderPassCmd* renderPass) {
617             ASSERT(renderPass != nullptr);
618 
619             for (ColorAttachmentIndex i :
620                  IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
621                 TextureViewBase* resolveTarget =
622                     renderPass->colorAttachments[i].resolveTarget.Get();
623                 if (resolveTarget == nullptr) {
624                     continue;
625                 }
626 
627                 TextureViewBase* colorView = renderPass->colorAttachments[i].view.Get();
628                 Texture* colorTexture = ToBackend(colorView->GetTexture());
629                 Texture* resolveTexture = ToBackend(resolveTarget->GetTexture());
630 
631                 // Transition the usages of the color attachment and resolve target.
632                 colorTexture->TrackUsageAndTransitionNow(commandContext,
633                                                          D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
634                                                          colorView->GetSubresourceRange());
635                 resolveTexture->TrackUsageAndTransitionNow(commandContext,
636                                                            D3D12_RESOURCE_STATE_RESOLVE_DEST,
637                                                            resolveTarget->GetSubresourceRange());
638 
639                 // Do MSAA resolve with ResolveSubResource().
640                 ID3D12Resource* colorTextureHandle = colorTexture->GetD3D12Resource();
641                 ID3D12Resource* resolveTextureHandle = resolveTexture->GetD3D12Resource();
642                 const uint32_t resolveTextureSubresourceIndex = resolveTexture->GetSubresourceIndex(
643                     resolveTarget->GetBaseMipLevel(), resolveTarget->GetBaseArrayLayer(),
644                     Aspect::Color);
645                 constexpr uint32_t kColorTextureSubresourceIndex = 0;
646                 commandContext->GetCommandList()->ResolveSubresource(
647                     resolveTextureHandle, resolveTextureSubresourceIndex, colorTextureHandle,
648                     kColorTextureSubresourceIndex, colorTexture->GetD3D12Format());
649             }
650         }
651 
652     }  // anonymous namespace
653 
654     // static
Create(CommandEncoder * encoder,const CommandBufferDescriptor * descriptor)655     Ref<CommandBuffer> CommandBuffer::Create(CommandEncoder* encoder,
656                                              const CommandBufferDescriptor* descriptor) {
657         return AcquireRef(new CommandBuffer(encoder, descriptor));
658     }
659 
CommandBuffer(CommandEncoder * encoder,const CommandBufferDescriptor * descriptor)660     CommandBuffer::CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor)
661         : CommandBufferBase(encoder, descriptor) {
662     }
663 
RecordCommands(CommandRecordingContext * commandContext)664     MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext) {
665         Device* device = ToBackend(GetDevice());
666         BindGroupStateTracker bindingTracker(device);
667 
668         ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
669 
670         // Make sure we use the correct descriptors for this command list. Could be done once per
671         // actual command list but here is ok because there should be few command buffers.
672         bindingTracker.SetID3D12DescriptorHeaps(commandList);
673 
674         size_t nextComputePassNumber = 0;
675         size_t nextRenderPassNumber = 0;
676 
677         Command type;
678         while (mCommands.NextCommandId(&type)) {
679             switch (type) {
680                 case Command::BeginComputePass: {
681                     mCommands.NextCommand<BeginComputePassCmd>();
682 
683                     bindingTracker.SetInComputePass(true);
684                     DAWN_TRY(RecordComputePass(
685                         commandContext, &bindingTracker,
686                         GetResourceUsages().computePasses[nextComputePassNumber]));
687 
688                     nextComputePassNumber++;
689                     break;
690                 }
691 
692                 case Command::BeginRenderPass: {
693                     BeginRenderPassCmd* beginRenderPassCmd =
694                         mCommands.NextCommand<BeginRenderPassCmd>();
695 
696                     const bool passHasUAV = TransitionAndClearForSyncScope(
697                         commandContext, GetResourceUsages().renderPasses[nextRenderPassNumber]);
698                     bindingTracker.SetInComputePass(false);
699 
700                     LazyClearRenderPassAttachments(beginRenderPassCmd);
701                     DAWN_TRY(RecordRenderPass(commandContext, &bindingTracker, beginRenderPassCmd,
702                                               passHasUAV));
703 
704                     nextRenderPassNumber++;
705                     break;
706                 }
707 
708                 case Command::CopyBufferToBuffer: {
709                     CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
710                     if (copy->size == 0) {
711                         // Skip no-op copies.
712                         break;
713                     }
714                     Buffer* srcBuffer = ToBackend(copy->source.Get());
715                     Buffer* dstBuffer = ToBackend(copy->destination.Get());
716 
717                     DAWN_TRY(srcBuffer->EnsureDataInitialized(commandContext));
718                     bool cleared;
719                     DAWN_TRY_ASSIGN(cleared,
720                                     dstBuffer->EnsureDataInitializedAsDestination(
721                                         commandContext, copy->destinationOffset, copy->size));
722                     DAWN_UNUSED(cleared);
723 
724                     srcBuffer->TrackUsageAndTransitionNow(commandContext,
725                                                           wgpu::BufferUsage::CopySrc);
726                     dstBuffer->TrackUsageAndTransitionNow(commandContext,
727                                                           wgpu::BufferUsage::CopyDst);
728 
729                     commandList->CopyBufferRegion(
730                         dstBuffer->GetD3D12Resource(), copy->destinationOffset,
731                         srcBuffer->GetD3D12Resource(), copy->sourceOffset, copy->size);
732                     break;
733                 }
734 
735                 case Command::CopyBufferToTexture: {
736                     CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>();
737                     if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
738                         copy->copySize.depthOrArrayLayers == 0) {
739                         // Skip no-op copies.
740                         continue;
741                     }
742                     Buffer* buffer = ToBackend(copy->source.buffer.Get());
743                     Texture* texture = ToBackend(copy->destination.texture.Get());
744 
745                     DAWN_TRY(buffer->EnsureDataInitialized(commandContext));
746 
747                     ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D);
748                     SubresourceRange subresources =
749                         GetSubresourcesAffectedByCopy(copy->destination, copy->copySize);
750 
751                     if (IsCompleteSubresourceCopiedTo(texture, copy->copySize,
752                                                       copy->destination.mipLevel)) {
753                         texture->SetIsSubresourceContentInitialized(true, subresources);
754                     } else {
755                         texture->EnsureSubresourceContentInitialized(commandContext, subresources);
756                     }
757 
758                     buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopySrc);
759                     texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopyDst,
760                                                         subresources);
761 
762                     RecordCopyBufferToTexture(commandContext, copy->destination,
763                                               buffer->GetD3D12Resource(), copy->source.offset,
764                                               copy->source.bytesPerRow, copy->source.rowsPerImage,
765                                               copy->copySize, texture, subresources.aspects);
766 
767                     break;
768                 }
769 
770                 case Command::CopyTextureToBuffer: {
771                     CopyTextureToBufferCmd* copy = mCommands.NextCommand<CopyTextureToBufferCmd>();
772                     if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
773                         copy->copySize.depthOrArrayLayers == 0) {
774                         // Skip no-op copies.
775                         continue;
776                     }
777                     Texture* texture = ToBackend(copy->source.texture.Get());
778                     Buffer* buffer = ToBackend(copy->destination.buffer.Get());
779 
780                     DAWN_TRY(buffer->EnsureDataInitializedAsDestination(commandContext, copy));
781 
782                     ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D);
783                     SubresourceRange subresources =
784                         GetSubresourcesAffectedByCopy(copy->source, copy->copySize);
785 
786                     texture->EnsureSubresourceContentInitialized(commandContext, subresources);
787 
788                     texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopySrc,
789                                                         subresources);
790                     buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopyDst);
791 
792                     RecordCopyTextureToBuffer(commandList, copy->source, copy->destination, texture,
793                                               buffer, copy->copySize);
794 
795                     break;
796                 }
797 
798                 case Command::CopyTextureToTexture: {
799                     CopyTextureToTextureCmd* copy =
800                         mCommands.NextCommand<CopyTextureToTextureCmd>();
801                     if (copy->copySize.width == 0 || copy->copySize.height == 0 ||
802                         copy->copySize.depthOrArrayLayers == 0) {
803                         // Skip no-op copies.
804                         continue;
805                     }
806                     Texture* source = ToBackend(copy->source.texture.Get());
807                     Texture* destination = ToBackend(copy->destination.texture.Get());
808 
809                     SubresourceRange srcRange =
810                         GetSubresourcesAffectedByCopy(copy->source, copy->copySize);
811                     SubresourceRange dstRange =
812                         GetSubresourcesAffectedByCopy(copy->destination, copy->copySize);
813 
814                     source->EnsureSubresourceContentInitialized(commandContext, srcRange);
815                     if (IsCompleteSubresourceCopiedTo(destination, copy->copySize,
816                                                       copy->destination.mipLevel)) {
817                         destination->SetIsSubresourceContentInitialized(true, dstRange);
818                     } else {
819                         destination->EnsureSubresourceContentInitialized(commandContext, dstRange);
820                     }
821 
822                     if (copy->source.texture.Get() == copy->destination.texture.Get() &&
823                         copy->source.mipLevel == copy->destination.mipLevel) {
824                         // When there are overlapped subresources, the layout of the overlapped
825                         // subresources should all be COMMON instead of what we set now. Currently
826                         // it is not allowed to copy with overlapped subresources, but we still
827                         // add the ASSERT here as a reminder for this possible misuse.
828                         ASSERT(!IsRangeOverlapped(copy->source.origin.z, copy->destination.origin.z,
829                                                   copy->copySize.depthOrArrayLayers));
830                     }
831                     source->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopySrc,
832                                                        srcRange);
833                     destination->TrackUsageAndTransitionNow(commandContext,
834                                                             wgpu::TextureUsage::CopyDst, dstRange);
835 
836                     ASSERT(srcRange.aspects == dstRange.aspects);
837                     if (ShouldCopyUsingTemporaryBuffer(GetDevice(), copy->source,
838                                                        copy->destination)) {
839                         DAWN_TRY(RecordCopyTextureWithTemporaryBuffer(
840                             commandContext, copy->source, copy->destination, copy->copySize));
841                         break;
842                     }
843 
844                     if (CanUseCopyResource(copy->source, copy->destination, copy->copySize)) {
845                         commandList->CopyResource(destination->GetD3D12Resource(),
846                                                   source->GetD3D12Resource());
847                     } else if (source->GetDimension() == wgpu::TextureDimension::e3D &&
848                                destination->GetDimension() == wgpu::TextureDimension::e3D) {
849                         for (Aspect aspect : IterateEnumMask(srcRange.aspects)) {
850                             D3D12_TEXTURE_COPY_LOCATION srcLocation =
851                                 ComputeTextureCopyLocationForTexture(source, copy->source.mipLevel,
852                                                                      0, aspect);
853                             D3D12_TEXTURE_COPY_LOCATION dstLocation =
854                                 ComputeTextureCopyLocationForTexture(
855                                     destination, copy->destination.mipLevel, 0, aspect);
856 
857                             D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize(
858                                 copy->source.origin, copy->copySize);
859 
860                             commandList->CopyTextureRegion(&dstLocation, copy->destination.origin.x,
861                                                            copy->destination.origin.y,
862                                                            copy->destination.origin.z, &srcLocation,
863                                                            &sourceRegion);
864                         }
865                     } else {
866                         // TODO(crbug.com/dawn/814): support copying with 1D.
867                         ASSERT(source->GetDimension() != wgpu::TextureDimension::e1D &&
868                                destination->GetDimension() != wgpu::TextureDimension::e1D);
869                         const dawn_native::Extent3D copyExtentOneSlice = {
870                             copy->copySize.width, copy->copySize.height, 1u};
871 
872                         for (Aspect aspect : IterateEnumMask(srcRange.aspects)) {
873                             for (uint32_t z = 0; z < copy->copySize.depthOrArrayLayers; ++z) {
874                                 uint32_t sourceLayer = 0;
875                                 uint32_t sourceZ = 0;
876                                 switch (source->GetDimension()) {
877                                     case wgpu::TextureDimension::e2D:
878                                         sourceLayer = copy->source.origin.z + z;
879                                         break;
880                                     case wgpu::TextureDimension::e3D:
881                                         sourceZ = copy->source.origin.z + z;
882                                         break;
883                                     case wgpu::TextureDimension::e1D:
884                                         UNREACHABLE();
885                                 }
886 
887                                 uint32_t destinationLayer = 0;
888                                 uint32_t destinationZ = 0;
889                                 switch (destination->GetDimension()) {
890                                     case wgpu::TextureDimension::e2D:
891                                         destinationLayer = copy->destination.origin.z + z;
892                                         break;
893                                     case wgpu::TextureDimension::e3D:
894                                         destinationZ = copy->destination.origin.z + z;
895                                         break;
896                                     case wgpu::TextureDimension::e1D:
897                                         UNREACHABLE();
898                                 }
899                                 D3D12_TEXTURE_COPY_LOCATION srcLocation =
900                                     ComputeTextureCopyLocationForTexture(
901                                         source, copy->source.mipLevel, sourceLayer, aspect);
902 
903                                 D3D12_TEXTURE_COPY_LOCATION dstLocation =
904                                     ComputeTextureCopyLocationForTexture(destination,
905                                                                          copy->destination.mipLevel,
906                                                                          destinationLayer, aspect);
907 
908                                 Origin3D sourceOriginInSubresource = copy->source.origin;
909                                 sourceOriginInSubresource.z = sourceZ;
910                                 D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize(
911                                     sourceOriginInSubresource, copyExtentOneSlice);
912 
913                                 commandList->CopyTextureRegion(
914                                     &dstLocation, copy->destination.origin.x,
915                                     copy->destination.origin.y, destinationZ, &srcLocation,
916                                     &sourceRegion);
917                             }
918                         }
919                     }
920                     break;
921                 }
922 
923                 case Command::ClearBuffer: {
924                     ClearBufferCmd* cmd = mCommands.NextCommand<ClearBufferCmd>();
925                     if (cmd->size == 0) {
926                         // Skip no-op fills.
927                         break;
928                     }
929                     Buffer* dstBuffer = ToBackend(cmd->buffer.Get());
930 
931                     bool clearedToZero;
932                     DAWN_TRY_ASSIGN(clearedToZero, dstBuffer->EnsureDataInitializedAsDestination(
933                                                        commandContext, cmd->offset, cmd->size));
934 
935                     if (!clearedToZero) {
936                         DAWN_TRY(device->ClearBufferToZero(commandContext, cmd->buffer.Get(),
937                                                            cmd->offset, cmd->size));
938                     }
939 
940                     break;
941                 }
942 
943                 case Command::ResolveQuerySet: {
944                     ResolveQuerySetCmd* cmd = mCommands.NextCommand<ResolveQuerySetCmd>();
945                     QuerySet* querySet = ToBackend(cmd->querySet.Get());
946                     uint32_t firstQuery = cmd->firstQuery;
947                     uint32_t queryCount = cmd->queryCount;
948                     Buffer* destination = ToBackend(cmd->destination.Get());
949                     uint64_t destinationOffset = cmd->destinationOffset;
950 
951                     bool cleared;
952                     DAWN_TRY_ASSIGN(cleared, destination->EnsureDataInitializedAsDestination(
953                                                  commandContext, destinationOffset,
954                                                  queryCount * sizeof(uint64_t)));
955                     DAWN_UNUSED(cleared);
956 
957                     // Resolving unavailable queries is undefined behaviour on D3D12, we only can
958                     // resolve the available part of sparse queries. In order to resolve the
959                     // unavailables as 0s, we need to clear the resolving region of the destination
960                     // buffer to 0s.
961                     auto startIt = querySet->GetQueryAvailability().begin() + firstQuery;
962                     auto endIt = querySet->GetQueryAvailability().begin() + firstQuery + queryCount;
963                     bool hasUnavailableQueries = std::find(startIt, endIt, false) != endIt;
964                     if (hasUnavailableQueries) {
965                         DAWN_TRY(device->ClearBufferToZero(commandContext, destination,
966                                                            destinationOffset,
967                                                            queryCount * sizeof(uint64_t)));
968                     }
969 
970                     destination->TrackUsageAndTransitionNow(commandContext,
971                                                             wgpu::BufferUsage::QueryResolve);
972 
973                     RecordResolveQuerySetCmd(commandList, device, querySet, firstQuery, queryCount,
974                                              destination, destinationOffset);
975 
976                     break;
977                 }
978 
979                 case Command::WriteTimestamp: {
980                     WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
981 
982                     RecordWriteTimestampCmd(commandList, cmd);
983                     break;
984                 }
985 
986                 case Command::InsertDebugMarker: {
987                     InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
988                     const char* label = mCommands.NextData<char>(cmd->length + 1);
989 
990                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
991                         // PIX color is 1 byte per channel in ARGB format
992                         constexpr uint64_t kPIXBlackColor = 0xff000000;
993                         ToBackend(GetDevice())
994                             ->GetFunctions()
995                             ->pixSetMarkerOnCommandList(commandList, kPIXBlackColor, label);
996                     }
997                     break;
998                 }
999 
1000                 case Command::PopDebugGroup: {
1001                     mCommands.NextCommand<PopDebugGroupCmd>();
1002 
1003                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1004                         ToBackend(GetDevice())
1005                             ->GetFunctions()
1006                             ->pixEndEventOnCommandList(commandList);
1007                     }
1008                     break;
1009                 }
1010 
1011                 case Command::PushDebugGroup: {
1012                     PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
1013                     const char* label = mCommands.NextData<char>(cmd->length + 1);
1014 
1015                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1016                         // PIX color is 1 byte per channel in ARGB format
1017                         constexpr uint64_t kPIXBlackColor = 0xff000000;
1018                         ToBackend(GetDevice())
1019                             ->GetFunctions()
1020                             ->pixBeginEventOnCommandList(commandList, kPIXBlackColor, label);
1021                     }
1022                     break;
1023                 }
1024 
1025                 case Command::WriteBuffer: {
1026                     WriteBufferCmd* write = mCommands.NextCommand<WriteBufferCmd>();
1027                     const uint64_t offset = write->offset;
1028                     const uint64_t size = write->size;
1029                     if (size == 0) {
1030                         continue;
1031                     }
1032 
1033                     Buffer* dstBuffer = ToBackend(write->buffer.Get());
1034                     uint8_t* data = mCommands.NextData<uint8_t>(size);
1035                     Device* device = ToBackend(GetDevice());
1036 
1037                     UploadHandle uploadHandle;
1038                     DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate(
1039                                                       size, device->GetPendingCommandSerial(),
1040                                                       kCopyBufferToBufferOffsetAlignment));
1041                     ASSERT(uploadHandle.mappedBuffer != nullptr);
1042                     memcpy(uploadHandle.mappedBuffer, data, size);
1043 
1044                     bool cleared;
1045                     DAWN_TRY_ASSIGN(cleared, dstBuffer->EnsureDataInitializedAsDestination(
1046                                                  commandContext, offset, size));
1047                     DAWN_UNUSED(cleared);
1048                     dstBuffer->TrackUsageAndTransitionNow(commandContext,
1049                                                           wgpu::BufferUsage::CopyDst);
1050                     commandList->CopyBufferRegion(
1051                         dstBuffer->GetD3D12Resource(), offset,
1052                         ToBackend(uploadHandle.stagingBuffer)->GetResource(),
1053                         uploadHandle.startOffset, size);
1054                     break;
1055                 }
1056 
1057                 default:
1058                     UNREACHABLE();
1059             }
1060         }
1061 
1062         return {};
1063     }
1064 
RecordComputePass(CommandRecordingContext * commandContext,BindGroupStateTracker * bindingTracker,const ComputePassResourceUsage & resourceUsages)1065     MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandContext,
1066                                                 BindGroupStateTracker* bindingTracker,
1067                                                 const ComputePassResourceUsage& resourceUsages) {
1068         uint64_t currentDispatch = 0;
1069         ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
1070 
1071         Command type;
1072         ComputePipeline* lastPipeline = nullptr;
1073         while (mCommands.NextCommandId(&type)) {
1074             switch (type) {
1075                 case Command::Dispatch: {
1076                     DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
1077 
1078                     // Skip noop dispatches, it can cause D3D12 warning from validation layers and
1079                     // leads to device lost.
1080                     if (dispatch->x == 0 || dispatch->y == 0 || dispatch->z == 0) {
1081                         break;
1082                     }
1083 
1084                     TransitionAndClearForSyncScope(commandContext,
1085                                                    resourceUsages.dispatchUsages[currentDispatch]);
1086                     DAWN_TRY(bindingTracker->Apply(commandContext));
1087 
1088                     RecordNumWorkgroupsForDispatch(commandList, lastPipeline, dispatch);
1089                     commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
1090                     currentDispatch++;
1091                     break;
1092                 }
1093 
1094                 case Command::DispatchIndirect: {
1095                     DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>();
1096 
1097                     TransitionAndClearForSyncScope(commandContext,
1098                                                    resourceUsages.dispatchUsages[currentDispatch]);
1099                     DAWN_TRY(bindingTracker->Apply(commandContext));
1100 
1101                     ComPtr<ID3D12CommandSignature> signature =
1102                         lastPipeline->GetDispatchIndirectCommandSignature();
1103                     commandList->ExecuteIndirect(
1104                         signature.Get(), 1, ToBackend(dispatch->indirectBuffer)->GetD3D12Resource(),
1105                         dispatch->indirectOffset, nullptr, 0);
1106                     currentDispatch++;
1107                     break;
1108                 }
1109 
1110                 case Command::EndComputePass: {
1111                     mCommands.NextCommand<EndComputePassCmd>();
1112                     return {};
1113                 }
1114 
1115                 case Command::SetComputePipeline: {
1116                     SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
1117                     ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get();
1118 
1119                     commandList->SetPipelineState(pipeline->GetPipelineState());
1120 
1121                     bindingTracker->OnSetPipeline(pipeline);
1122                     lastPipeline = pipeline;
1123                     break;
1124                 }
1125 
1126                 case Command::SetBindGroup: {
1127                     SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
1128                     BindGroup* group = ToBackend(cmd->group.Get());
1129                     uint32_t* dynamicOffsets = nullptr;
1130 
1131                     if (cmd->dynamicOffsetCount > 0) {
1132                         dynamicOffsets = mCommands.NextData<uint32_t>(cmd->dynamicOffsetCount);
1133                     }
1134 
1135                     bindingTracker->OnSetBindGroup(cmd->index, group, cmd->dynamicOffsetCount,
1136                                                    dynamicOffsets);
1137                     break;
1138                 }
1139 
1140                 case Command::InsertDebugMarker: {
1141                     InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
1142                     const char* label = mCommands.NextData<char>(cmd->length + 1);
1143 
1144                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1145                         // PIX color is 1 byte per channel in ARGB format
1146                         constexpr uint64_t kPIXBlackColor = 0xff000000;
1147                         ToBackend(GetDevice())
1148                             ->GetFunctions()
1149                             ->pixSetMarkerOnCommandList(commandList, kPIXBlackColor, label);
1150                     }
1151                     break;
1152                 }
1153 
1154                 case Command::PopDebugGroup: {
1155                     mCommands.NextCommand<PopDebugGroupCmd>();
1156 
1157                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1158                         ToBackend(GetDevice())
1159                             ->GetFunctions()
1160                             ->pixEndEventOnCommandList(commandList);
1161                     }
1162                     break;
1163                 }
1164 
1165                 case Command::PushDebugGroup: {
1166                     PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
1167                     const char* label = mCommands.NextData<char>(cmd->length + 1);
1168 
1169                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1170                         // PIX color is 1 byte per channel in ARGB format
1171                         constexpr uint64_t kPIXBlackColor = 0xff000000;
1172                         ToBackend(GetDevice())
1173                             ->GetFunctions()
1174                             ->pixBeginEventOnCommandList(commandList, kPIXBlackColor, label);
1175                     }
1176                     break;
1177                 }
1178 
1179                 case Command::WriteTimestamp: {
1180                     WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
1181 
1182                     RecordWriteTimestampCmd(commandList, cmd);
1183                     break;
1184                 }
1185 
1186                 default:
1187                     UNREACHABLE();
1188             }
1189         }
1190 
1191         return {};
1192     }
1193 
SetupRenderPass(CommandRecordingContext * commandContext,BeginRenderPassCmd * renderPass,RenderPassBuilder * renderPassBuilder)1194     MaybeError CommandBuffer::SetupRenderPass(CommandRecordingContext* commandContext,
1195                                               BeginRenderPassCmd* renderPass,
1196                                               RenderPassBuilder* renderPassBuilder) {
1197         Device* device = ToBackend(GetDevice());
1198 
1199         for (ColorAttachmentIndex i :
1200              IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
1201             RenderPassColorAttachmentInfo& attachmentInfo = renderPass->colorAttachments[i];
1202             TextureView* view = ToBackend(attachmentInfo.view.Get());
1203 
1204             // Set view attachment.
1205             CPUDescriptorHeapAllocation rtvAllocation;
1206             DAWN_TRY_ASSIGN(
1207                 rtvAllocation,
1208                 device->GetRenderTargetViewAllocator()->AllocateTransientCPUDescriptors());
1209 
1210             const D3D12_RENDER_TARGET_VIEW_DESC viewDesc = view->GetRTVDescriptor();
1211             const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor = rtvAllocation.GetBaseDescriptor();
1212 
1213             device->GetD3D12Device()->CreateRenderTargetView(
1214                 ToBackend(view->GetTexture())->GetD3D12Resource(), &viewDesc, baseDescriptor);
1215 
1216             renderPassBuilder->SetRenderTargetView(i, baseDescriptor);
1217 
1218             // Set color load operation.
1219             renderPassBuilder->SetRenderTargetBeginningAccess(
1220                 i, attachmentInfo.loadOp, attachmentInfo.clearColor, view->GetD3D12Format());
1221 
1222             // Set color store operation.
1223             if (attachmentInfo.resolveTarget != nullptr) {
1224                 TextureView* resolveDestinationView = ToBackend(attachmentInfo.resolveTarget.Get());
1225                 Texture* resolveDestinationTexture =
1226                     ToBackend(resolveDestinationView->GetTexture());
1227 
1228                 resolveDestinationTexture->TrackUsageAndTransitionNow(
1229                     commandContext, D3D12_RESOURCE_STATE_RESOLVE_DEST,
1230                     resolveDestinationView->GetSubresourceRange());
1231 
1232                 renderPassBuilder->SetRenderTargetEndingAccessResolve(i, attachmentInfo.storeOp,
1233                                                                       view, resolveDestinationView);
1234             } else {
1235                 renderPassBuilder->SetRenderTargetEndingAccess(i, attachmentInfo.storeOp);
1236             }
1237         }
1238 
1239         if (renderPass->attachmentState->HasDepthStencilAttachment()) {
1240             RenderPassDepthStencilAttachmentInfo& attachmentInfo =
1241                 renderPass->depthStencilAttachment;
1242             TextureView* view = ToBackend(renderPass->depthStencilAttachment.view.Get());
1243 
1244             // Set depth attachment.
1245             CPUDescriptorHeapAllocation dsvAllocation;
1246             DAWN_TRY_ASSIGN(
1247                 dsvAllocation,
1248                 device->GetDepthStencilViewAllocator()->AllocateTransientCPUDescriptors());
1249 
1250             const D3D12_DEPTH_STENCIL_VIEW_DESC viewDesc = view->GetDSVDescriptor(
1251                 attachmentInfo.depthReadOnly, attachmentInfo.stencilReadOnly);
1252             const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor = dsvAllocation.GetBaseDescriptor();
1253 
1254             device->GetD3D12Device()->CreateDepthStencilView(
1255                 ToBackend(view->GetTexture())->GetD3D12Resource(), &viewDesc, baseDescriptor);
1256 
1257             renderPassBuilder->SetDepthStencilView(baseDescriptor);
1258 
1259             const bool hasDepth = view->GetTexture()->GetFormat().HasDepth();
1260             const bool hasStencil = view->GetTexture()->GetFormat().HasStencil();
1261 
1262             // Set depth/stencil load operations.
1263             if (hasDepth) {
1264                 renderPassBuilder->SetDepthAccess(
1265                     attachmentInfo.depthLoadOp, attachmentInfo.depthStoreOp,
1266                     attachmentInfo.clearDepth, view->GetD3D12Format());
1267             } else {
1268                 renderPassBuilder->SetDepthNoAccess();
1269             }
1270 
1271             if (hasStencil) {
1272                 renderPassBuilder->SetStencilAccess(
1273                     attachmentInfo.stencilLoadOp, attachmentInfo.stencilStoreOp,
1274                     attachmentInfo.clearStencil, view->GetD3D12Format());
1275             } else {
1276                 renderPassBuilder->SetStencilNoAccess();
1277             }
1278 
1279         } else {
1280             renderPassBuilder->SetDepthStencilNoAccess();
1281         }
1282 
1283         return {};
1284     }
1285 
EmulateBeginRenderPass(CommandRecordingContext * commandContext,const RenderPassBuilder * renderPassBuilder) const1286     void CommandBuffer::EmulateBeginRenderPass(CommandRecordingContext* commandContext,
1287                                                const RenderPassBuilder* renderPassBuilder) const {
1288         ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
1289 
1290         // Clear framebuffer attachments as needed.
1291         {
1292             for (ColorAttachmentIndex i(uint8_t(0));
1293                  i < renderPassBuilder->GetColorAttachmentCount(); i++) {
1294                 // Load op - color
1295                 if (renderPassBuilder->GetRenderPassRenderTargetDescriptors()[i]
1296                         .BeginningAccess.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) {
1297                     commandList->ClearRenderTargetView(
1298                         renderPassBuilder->GetRenderPassRenderTargetDescriptors()[i].cpuDescriptor,
1299                         renderPassBuilder->GetRenderPassRenderTargetDescriptors()[i]
1300                             .BeginningAccess.Clear.ClearValue.Color,
1301                         0, nullptr);
1302                 }
1303             }
1304 
1305             if (renderPassBuilder->HasDepth()) {
1306                 D3D12_CLEAR_FLAGS clearFlags = {};
1307                 float depthClear = 0.0f;
1308                 uint8_t stencilClear = 0u;
1309 
1310                 if (renderPassBuilder->GetRenderPassDepthStencilDescriptor()
1311                         ->DepthBeginningAccess.Type ==
1312                     D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) {
1313                     clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
1314                     depthClear = renderPassBuilder->GetRenderPassDepthStencilDescriptor()
1315                                      ->DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth;
1316                 }
1317                 if (renderPassBuilder->GetRenderPassDepthStencilDescriptor()
1318                         ->StencilBeginningAccess.Type ==
1319                     D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) {
1320                     clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
1321                     stencilClear =
1322                         renderPassBuilder->GetRenderPassDepthStencilDescriptor()
1323                             ->StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil;
1324                 }
1325 
1326                 if (clearFlags) {
1327                     commandList->ClearDepthStencilView(
1328                         renderPassBuilder->GetRenderPassDepthStencilDescriptor()->cpuDescriptor,
1329                         clearFlags, depthClear, stencilClear, 0, nullptr);
1330                 }
1331             }
1332         }
1333 
1334         commandList->OMSetRenderTargets(
1335             static_cast<uint8_t>(renderPassBuilder->GetColorAttachmentCount()),
1336             renderPassBuilder->GetRenderTargetViews(), FALSE,
1337             renderPassBuilder->HasDepth()
1338                 ? &renderPassBuilder->GetRenderPassDepthStencilDescriptor()->cpuDescriptor
1339                 : nullptr);
1340     }
1341 
RecordRenderPass(CommandRecordingContext * commandContext,BindGroupStateTracker * bindingTracker,BeginRenderPassCmd * renderPass,const bool passHasUAV)1342     MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandContext,
1343                                                BindGroupStateTracker* bindingTracker,
1344                                                BeginRenderPassCmd* renderPass,
1345                                                const bool passHasUAV) {
1346         Device* device = ToBackend(GetDevice());
1347         const bool useRenderPass = device->IsToggleEnabled(Toggle::UseD3D12RenderPass);
1348 
1349         // renderPassBuilder must be scoped to RecordRenderPass because any underlying
1350         // D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS structs must remain
1351         // valid until after EndRenderPass() has been called.
1352         RenderPassBuilder renderPassBuilder(passHasUAV);
1353 
1354         DAWN_TRY(SetupRenderPass(commandContext, renderPass, &renderPassBuilder));
1355 
1356         // Use D3D12's native render pass API if it's available, otherwise emulate the
1357         // beginning and ending access operations.
1358         if (useRenderPass) {
1359             commandContext->GetCommandList4()->BeginRenderPass(
1360                 static_cast<uint8_t>(renderPassBuilder.GetColorAttachmentCount()),
1361                 renderPassBuilder.GetRenderPassRenderTargetDescriptors().data(),
1362                 renderPassBuilder.HasDepth()
1363                     ? renderPassBuilder.GetRenderPassDepthStencilDescriptor()
1364                     : nullptr,
1365                 renderPassBuilder.GetRenderPassFlags());
1366         } else {
1367             EmulateBeginRenderPass(commandContext, &renderPassBuilder);
1368         }
1369 
1370         ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
1371 
1372         // Set up default dynamic state
1373         {
1374             uint32_t width = renderPass->width;
1375             uint32_t height = renderPass->height;
1376             D3D12_VIEWPORT viewport = {
1377                 0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f};
1378             D3D12_RECT scissorRect = {0, 0, static_cast<long>(width), static_cast<long>(height)};
1379             commandList->RSSetViewports(1, &viewport);
1380             commandList->RSSetScissorRects(1, &scissorRect);
1381 
1382             static constexpr std::array<float, 4> defaultBlendFactor = {0, 0, 0, 0};
1383             commandList->OMSetBlendFactor(&defaultBlendFactor[0]);
1384 
1385             commandList->OMSetStencilRef(0);
1386         }
1387 
1388         RenderPipeline* lastPipeline = nullptr;
1389         VertexBufferTracker vertexBufferTracker = {};
1390 
1391         auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) -> MaybeError {
1392             switch (type) {
1393                 case Command::Draw: {
1394                     DrawCmd* draw = iter->NextCommand<DrawCmd>();
1395 
1396                     DAWN_TRY(bindingTracker->Apply(commandContext));
1397                     vertexBufferTracker.Apply(commandList, lastPipeline);
1398                     RecordFirstIndexOffset(commandList, lastPipeline, draw->firstVertex,
1399                                            draw->firstInstance);
1400                     commandList->DrawInstanced(draw->vertexCount, draw->instanceCount,
1401                                                draw->firstVertex, draw->firstInstance);
1402                     break;
1403                 }
1404 
1405                 case Command::DrawIndexed: {
1406                     DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
1407 
1408                     DAWN_TRY(bindingTracker->Apply(commandContext));
1409                     vertexBufferTracker.Apply(commandList, lastPipeline);
1410                     RecordFirstIndexOffset(commandList, lastPipeline, draw->baseVertex,
1411                                            draw->firstInstance);
1412                     commandList->DrawIndexedInstanced(draw->indexCount, draw->instanceCount,
1413                                                       draw->firstIndex, draw->baseVertex,
1414                                                       draw->firstInstance);
1415                     break;
1416                 }
1417 
1418                 case Command::DrawIndirect: {
1419                     DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
1420 
1421                     DAWN_TRY(bindingTracker->Apply(commandContext));
1422                     vertexBufferTracker.Apply(commandList, lastPipeline);
1423 
1424                     // TODO(dawn:548): remove this once builtins are emulated for indirect draws.
1425                     // Zero the index offset values to avoid reusing values from the previous draw
1426                     RecordFirstIndexOffset(commandList, lastPipeline, 0, 0);
1427 
1428                     Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
1429                     ComPtr<ID3D12CommandSignature> signature =
1430                         ToBackend(GetDevice())->GetDrawIndirectSignature();
1431                     commandList->ExecuteIndirect(signature.Get(), 1, buffer->GetD3D12Resource(),
1432                                                  draw->indirectOffset, nullptr, 0);
1433                     break;
1434                 }
1435 
1436                 case Command::DrawIndexedIndirect: {
1437                     DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
1438 
1439                     DAWN_TRY(bindingTracker->Apply(commandContext));
1440                     vertexBufferTracker.Apply(commandList, lastPipeline);
1441 
1442                     // TODO(dawn:548): remove this once builtins are emulated for indirect draws.
1443                     // Zero the index offset values to avoid reusing values from the previous draw
1444                     RecordFirstIndexOffset(commandList, lastPipeline, 0, 0);
1445 
1446                     Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
1447                     ASSERT(buffer != nullptr);
1448 
1449                     ComPtr<ID3D12CommandSignature> signature =
1450                         ToBackend(GetDevice())->GetDrawIndexedIndirectSignature();
1451                     commandList->ExecuteIndirect(signature.Get(), 1, buffer->GetD3D12Resource(),
1452                                                  draw->indirectOffset, nullptr, 0);
1453                     break;
1454                 }
1455 
1456                 case Command::InsertDebugMarker: {
1457                     InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>();
1458                     const char* label = iter->NextData<char>(cmd->length + 1);
1459 
1460                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1461                         // PIX color is 1 byte per channel in ARGB format
1462                         constexpr uint64_t kPIXBlackColor = 0xff000000;
1463                         ToBackend(GetDevice())
1464                             ->GetFunctions()
1465                             ->pixSetMarkerOnCommandList(commandList, kPIXBlackColor, label);
1466                     }
1467                     break;
1468                 }
1469 
1470                 case Command::PopDebugGroup: {
1471                     iter->NextCommand<PopDebugGroupCmd>();
1472 
1473                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1474                         ToBackend(GetDevice())
1475                             ->GetFunctions()
1476                             ->pixEndEventOnCommandList(commandList);
1477                     }
1478                     break;
1479                 }
1480 
1481                 case Command::PushDebugGroup: {
1482                     PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>();
1483                     const char* label = iter->NextData<char>(cmd->length + 1);
1484 
1485                     if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
1486                         // PIX color is 1 byte per channel in ARGB format
1487                         constexpr uint64_t kPIXBlackColor = 0xff000000;
1488                         ToBackend(GetDevice())
1489                             ->GetFunctions()
1490                             ->pixBeginEventOnCommandList(commandList, kPIXBlackColor, label);
1491                     }
1492                     break;
1493                 }
1494 
1495                 case Command::SetRenderPipeline: {
1496                     SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>();
1497                     RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get();
1498 
1499                     commandList->SetPipelineState(pipeline->GetPipelineState());
1500                     commandList->IASetPrimitiveTopology(pipeline->GetD3D12PrimitiveTopology());
1501 
1502                     bindingTracker->OnSetPipeline(pipeline);
1503 
1504                     lastPipeline = pipeline;
1505                     break;
1506                 }
1507 
1508                 case Command::SetBindGroup: {
1509                     SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
1510                     BindGroup* group = ToBackend(cmd->group.Get());
1511                     uint32_t* dynamicOffsets = nullptr;
1512 
1513                     if (cmd->dynamicOffsetCount > 0) {
1514                         dynamicOffsets = iter->NextData<uint32_t>(cmd->dynamicOffsetCount);
1515                     }
1516 
1517                     bindingTracker->OnSetBindGroup(cmd->index, group, cmd->dynamicOffsetCount,
1518                                                    dynamicOffsets);
1519                     break;
1520                 }
1521 
1522                 case Command::SetIndexBuffer: {
1523                     SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
1524 
1525                     D3D12_INDEX_BUFFER_VIEW bufferView;
1526                     bufferView.Format = DXGIIndexFormat(cmd->format);
1527                     bufferView.BufferLocation = ToBackend(cmd->buffer)->GetVA() + cmd->offset;
1528                     bufferView.SizeInBytes = cmd->size;
1529 
1530                     commandList->IASetIndexBuffer(&bufferView);
1531                     break;
1532                 }
1533 
1534                 case Command::SetVertexBuffer: {
1535                     SetVertexBufferCmd* cmd = iter->NextCommand<SetVertexBufferCmd>();
1536 
1537                     vertexBufferTracker.OnSetVertexBuffer(cmd->slot, ToBackend(cmd->buffer.Get()),
1538                                                           cmd->offset, cmd->size);
1539                     break;
1540                 }
1541 
1542                 default:
1543                     UNREACHABLE();
1544                     break;
1545             }
1546             return {};
1547         };
1548 
1549         Command type;
1550         while (mCommands.NextCommandId(&type)) {
1551             switch (type) {
1552                 case Command::EndRenderPass: {
1553                     mCommands.NextCommand<EndRenderPassCmd>();
1554                     if (useRenderPass) {
1555                         commandContext->GetCommandList4()->EndRenderPass();
1556                     } else if (renderPass->attachmentState->GetSampleCount() > 1) {
1557                         ResolveMultisampledRenderPass(commandContext, renderPass);
1558                     }
1559                     return {};
1560                 }
1561 
1562                 case Command::SetStencilReference: {
1563                     SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
1564 
1565                     commandList->OMSetStencilRef(cmd->reference);
1566                     break;
1567                 }
1568 
1569                 case Command::SetViewport: {
1570                     SetViewportCmd* cmd = mCommands.NextCommand<SetViewportCmd>();
1571                     D3D12_VIEWPORT viewport;
1572                     viewport.TopLeftX = cmd->x;
1573                     viewport.TopLeftY = cmd->y;
1574                     viewport.Width = cmd->width;
1575                     viewport.Height = cmd->height;
1576                     viewport.MinDepth = cmd->minDepth;
1577                     viewport.MaxDepth = cmd->maxDepth;
1578 
1579                     commandList->RSSetViewports(1, &viewport);
1580                     break;
1581                 }
1582 
1583                 case Command::SetScissorRect: {
1584                     SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
1585                     D3D12_RECT rect;
1586                     rect.left = cmd->x;
1587                     rect.top = cmd->y;
1588                     rect.right = cmd->x + cmd->width;
1589                     rect.bottom = cmd->y + cmd->height;
1590 
1591                     commandList->RSSetScissorRects(1, &rect);
1592                     break;
1593                 }
1594 
1595                 case Command::SetBlendConstant: {
1596                     SetBlendConstantCmd* cmd = mCommands.NextCommand<SetBlendConstantCmd>();
1597                     const std::array<float, 4> color = ConvertToFloatColor(cmd->color);
1598                     commandList->OMSetBlendFactor(color.data());
1599                     break;
1600                 }
1601 
1602                 case Command::ExecuteBundles: {
1603                     ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>();
1604                     auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count);
1605 
1606                     for (uint32_t i = 0; i < cmd->count; ++i) {
1607                         CommandIterator* iter = bundles[i]->GetCommands();
1608                         iter->Reset();
1609                         while (iter->NextCommandId(&type)) {
1610                             DAWN_TRY(EncodeRenderBundleCommand(iter, type));
1611                         }
1612                     }
1613                     break;
1614                 }
1615 
1616                 case Command::BeginOcclusionQuery: {
1617                     BeginOcclusionQueryCmd* cmd = mCommands.NextCommand<BeginOcclusionQueryCmd>();
1618                     QuerySet* querySet = ToBackend(cmd->querySet.Get());
1619                     ASSERT(D3D12QueryType(querySet->GetQueryType()) ==
1620                            D3D12_QUERY_TYPE_BINARY_OCCLUSION);
1621                     commandList->BeginQuery(querySet->GetQueryHeap(),
1622                                             D3D12_QUERY_TYPE_BINARY_OCCLUSION, cmd->queryIndex);
1623                     break;
1624                 }
1625 
1626                 case Command::EndOcclusionQuery: {
1627                     EndOcclusionQueryCmd* cmd = mCommands.NextCommand<EndOcclusionQueryCmd>();
1628                     QuerySet* querySet = ToBackend(cmd->querySet.Get());
1629                     ASSERT(D3D12QueryType(querySet->GetQueryType()) ==
1630                            D3D12_QUERY_TYPE_BINARY_OCCLUSION);
1631                     commandList->EndQuery(querySet->GetQueryHeap(),
1632                                           D3D12_QUERY_TYPE_BINARY_OCCLUSION, cmd->queryIndex);
1633                     break;
1634                 }
1635 
1636                 case Command::WriteTimestamp: {
1637                     WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
1638 
1639                     RecordWriteTimestampCmd(commandList, cmd);
1640                     break;
1641                 }
1642 
1643                 default: {
1644                     DAWN_TRY(EncodeRenderBundleCommand(&mCommands, type));
1645                     break;
1646                 }
1647             }
1648         }
1649         return {};
1650     }
1651 }}  // namespace dawn_native::d3d12
1652