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