From 2ef2be746d0aac990f21fdac68b4b7eb420b8ed0 Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Sat, 13 Jun 2020 00:59:13 +0000 Subject: [PATCH] D3D12: Enable nonzero_clear_resources_on_creation_for_testing on buffer This patch enables nonzero_clear_resources_on_creation_for_testing toggle on buffer on D3D12 backends as a preparation of supporting buffer lazy-initialization in Dawn. BUG=dawn:414 TEST=dawn_end2end_tests Change-Id: Id4f45ff5ccf906692c3855451b120aa56f68c7a9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23142 Reviewed-by: Corentin Wallez Reviewed-by: Austin Eng Commit-Queue: Jiawei Shao --- src/dawn_native/d3d12/BufferD3D12.cpp | 94 ++++++++++++++----- src/dawn_native/d3d12/BufferD3D12.h | 6 ++ .../end2end/NonzeroBufferCreationTests.cpp | 5 +- 3 files changed, 78 insertions(+), 27 deletions(-) diff --git a/src/dawn_native/d3d12/BufferD3D12.cpp b/src/dawn_native/d3d12/BufferD3D12.cpp index 8b42c95aec..879709f4ba 100644 --- a/src/dawn_native/d3d12/BufferD3D12.cpp +++ b/src/dawn_native/d3d12/BufferD3D12.cpp @@ -17,6 +17,7 @@ #include "common/Assert.h" #include "common/Constants.h" #include "common/Math.h" +#include "dawn_native/DynamicUploader.h" #include "dawn_native/d3d12/CommandRecordingContext.h" #include "dawn_native/d3d12/D3D12Error.h" #include "dawn_native/d3d12/DeviceD3D12.h" @@ -120,6 +121,11 @@ namespace dawn_native { namespace d3d12 { DAWN_TRY_ASSIGN( mResourceAllocation, ToBackend(GetDevice())->AllocateMemory(heapType, resourceDescriptor, bufferUsage)); + + if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { + DAWN_TRY(ClearBuffer(ClearValue::NonZero)); + } + return {}; } @@ -238,57 +244,60 @@ namespace dawn_native { namespace d3d12 { return (GetUsage() & (wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite)) != 0; } - MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) { + MaybeError Buffer::MapBufferInternal(D3D12_RANGE mappedRange, + void** mappedPointer, + const char* contextInfo) { // The mapped buffer can be accessed at any time, so it must be locked to ensure it is never // evicted. This buffer should already have been made resident when it was created. Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); DAWN_TRY(ToBackend(GetDevice())->GetResidencyManager()->LockAllocation(heap)); + DAWN_TRY( + CheckHRESULT(GetD3D12Resource()->Map(0, &mappedRange, mappedPointer), contextInfo)); + return {}; + } + + void Buffer::UnmapBufferInternal(D3D12_RANGE mappedRange) { + GetD3D12Resource()->Unmap(0, &mappedRange); + + // When buffers are mapped, they are locked to keep them in resident memory. We must unlock + // them when they are unmapped. + Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); + ToBackend(GetDevice())->GetResidencyManager()->UnlockAllocation(heap); + } + + MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) { mWrittenMappedRange = {0, static_cast(GetSize())}; - DAWN_TRY(CheckHRESULT(GetD3D12Resource()->Map(0, &mWrittenMappedRange, - reinterpret_cast(mappedPointer)), - "D3D12 map at creation")); + DAWN_TRY(MapBufferInternal(mWrittenMappedRange, reinterpret_cast(mappedPointer), + "D3D12 map at creation")); mMappedData = reinterpret_cast(mappedPointer); return {}; } MaybeError Buffer::MapReadAsyncImpl(uint32_t serial) { - // The mapped buffer can be accessed at any time, so we must make the buffer resident and - // lock it to ensure it is never evicted. - Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); - DAWN_TRY(ToBackend(GetDevice())->GetResidencyManager()->LockAllocation(heap)); - mWrittenMappedRange = {}; D3D12_RANGE readRange = {0, static_cast(GetSize())}; - DAWN_TRY(CheckHRESULT( - GetD3D12Resource()->Map(0, &readRange, reinterpret_cast(&mMappedData)), - "D3D12 map read async")); + DAWN_TRY(MapBufferInternal(readRange, reinterpret_cast(&mMappedData), + "D3D12 map read async")); + // There is no need to transition the resource to a new state: D3D12 seems to make the GPU // writes available when the fence is passed. return {}; } MaybeError Buffer::MapWriteAsyncImpl(uint32_t serial) { - // The mapped buffer can be accessed at any time, so we must make the buffer resident and - // lock it to ensure it is never evicted. - Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); - DAWN_TRY(ToBackend(GetDevice())->GetResidencyManager()->LockAllocation(heap)); - mWrittenMappedRange = {0, static_cast(GetSize())}; - DAWN_TRY(CheckHRESULT(GetD3D12Resource()->Map(0, &mWrittenMappedRange, - reinterpret_cast(&mMappedData)), - "D3D12 map write async")); + DAWN_TRY(MapBufferInternal(mWrittenMappedRange, reinterpret_cast(&mMappedData), + "D3D12 map write async")); + // There is no need to transition the resource to a new state: D3D12 seems to make the CPU // writes available on queue submission. return {}; } void Buffer::UnmapImpl() { - GetD3D12Resource()->Unmap(0, &mWrittenMappedRange); - // When buffers are mapped, they are locked to keep them in resident memory. We must unlock - // them when they are unmapped. - Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap()); - ToBackend(GetDevice())->GetResidencyManager()->UnlockAllocation(heap); + UnmapBufferInternal(mWrittenMappedRange); + mWrittenMappedRange = {}; mMappedData = nullptr; } @@ -317,4 +326,39 @@ namespace dawn_native { namespace d3d12 { return mResourceAllocation.GetInfo().mMethod == allocationMethod; } + MaybeError Buffer::ClearBuffer(ClearValue clearValue) { + // TODO(jiawei.shao@intel.com): support buffer lazy-initialization to 0. + ASSERT(clearValue == BufferBase::ClearValue::NonZero); + constexpr uint8_t kClearBufferValue = 1u; + + Device* device = ToBackend(GetDevice()); + + // The state of the buffers on UPLOAD heap must always be GENERIC_READ and cannot be + // changed away, so we can only clear such buffer with buffer mapping. + if (D3D12HeapType(GetUsage()) == D3D12_HEAP_TYPE_UPLOAD) { + uint8_t* mappedData = nullptr; + D3D12_RANGE writeRange = {0, static_cast(GetSize())}; + DAWN_TRY(MapBufferInternal(writeRange, reinterpret_cast(&mappedData), + "D3D12 map at clear buffer")); + + memset(mappedData, kClearBufferValue, GetSize()); + + UnmapBufferInternal(writeRange); + mappedData = nullptr; + } else { + // TODO(jiawei.shao@intel.com): use ClearUnorderedAccessView*() when the buffer usage + // includes STORAGE. + DynamicUploader* uploader = device->GetDynamicUploader(); + UploadHandle uploadHandle; + DAWN_TRY_ASSIGN(uploadHandle, + uploader->Allocate(GetSize(), device->GetPendingCommandSerial())); + + memset(uploadHandle.mappedBuffer, kClearBufferValue, GetSize()); + + DAWN_TRY(device->CopyFromStagingToBuffer(uploadHandle.stagingBuffer, + uploadHandle.startOffset, this, 0, GetSize())); + } + + return {}; + } }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/BufferD3D12.h b/src/dawn_native/d3d12/BufferD3D12.h index 5410738d27..3c51b74394 100644 --- a/src/dawn_native/d3d12/BufferD3D12.h +++ b/src/dawn_native/d3d12/BufferD3D12.h @@ -55,11 +55,17 @@ namespace dawn_native { namespace d3d12 { bool IsMapWritable() const override; virtual MaybeError MapAtCreationImpl(uint8_t** mappedPointer) override; void* GetMappedPointerImpl() override; + MaybeError MapBufferInternal(D3D12_RANGE mappedRange, + void** mappedPointer, + const char* contextInfo); + void UnmapBufferInternal(D3D12_RANGE mappedRange); bool TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext, D3D12_RESOURCE_BARRIER* barrier, wgpu::BufferUsage newUsage); + MaybeError ClearBuffer(ClearValue clearValue); + ResourceHeapAllocation mResourceAllocation; bool mFixedResourceState = false; wgpu::BufferUsage mLastUsage = wgpu::BufferUsage::None; diff --git a/src/tests/end2end/NonzeroBufferCreationTests.cpp b/src/tests/end2end/NonzeroBufferCreationTests.cpp index aeb62f9a79..e3fefa7b62 100644 --- a/src/tests/end2end/NonzeroBufferCreationTests.cpp +++ b/src/tests/end2end/NonzeroBufferCreationTests.cpp @@ -35,8 +35,8 @@ TEST_P(NonzeroBufferCreationTests, BufferCreationWithCopyDstUsage) { } // Verify that each byte of the buffer has all been initialized to 1 with the toggle enabled when it -// is created without CopyDst usage. -TEST_P(NonzeroBufferCreationTests, BufferCreationWithoutCopyDstUsage) { +// is created with MapWrite without CopyDst usage. +TEST_P(NonzeroBufferCreationTests, BufferCreationWithMapWriteWithoutCopyDstUsage) { constexpr uint32_t kSize = 32u; wgpu::BufferDescriptor descriptor; @@ -51,5 +51,6 @@ TEST_P(NonzeroBufferCreationTests, BufferCreationWithoutCopyDstUsage) { } DAWN_INSTANTIATE_TEST(NonzeroBufferCreationTests, + D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}), MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}), VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}));