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 <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
1663b1d04d
commit
2ef2be746d
|
@ -17,6 +17,7 @@
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
#include "common/Constants.h"
|
#include "common/Constants.h"
|
||||||
#include "common/Math.h"
|
#include "common/Math.h"
|
||||||
|
#include "dawn_native/DynamicUploader.h"
|
||||||
#include "dawn_native/d3d12/CommandRecordingContext.h"
|
#include "dawn_native/d3d12/CommandRecordingContext.h"
|
||||||
#include "dawn_native/d3d12/D3D12Error.h"
|
#include "dawn_native/d3d12/D3D12Error.h"
|
||||||
#include "dawn_native/d3d12/DeviceD3D12.h"
|
#include "dawn_native/d3d12/DeviceD3D12.h"
|
||||||
|
@ -120,6 +121,11 @@ namespace dawn_native { namespace d3d12 {
|
||||||
DAWN_TRY_ASSIGN(
|
DAWN_TRY_ASSIGN(
|
||||||
mResourceAllocation,
|
mResourceAllocation,
|
||||||
ToBackend(GetDevice())->AllocateMemory(heapType, resourceDescriptor, bufferUsage));
|
ToBackend(GetDevice())->AllocateMemory(heapType, resourceDescriptor, bufferUsage));
|
||||||
|
|
||||||
|
if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
|
||||||
|
DAWN_TRY(ClearBuffer(ClearValue::NonZero));
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,57 +244,60 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return (GetUsage() & (wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite)) != 0;
|
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
|
// 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.
|
// evicted. This buffer should already have been made resident when it was created.
|
||||||
Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap());
|
Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap());
|
||||||
DAWN_TRY(ToBackend(GetDevice())->GetResidencyManager()->LockAllocation(heap));
|
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<size_t>(GetSize())};
|
mWrittenMappedRange = {0, static_cast<size_t>(GetSize())};
|
||||||
DAWN_TRY(CheckHRESULT(GetD3D12Resource()->Map(0, &mWrittenMappedRange,
|
DAWN_TRY(MapBufferInternal(mWrittenMappedRange, reinterpret_cast<void**>(mappedPointer),
|
||||||
reinterpret_cast<void**>(mappedPointer)),
|
"D3D12 map at creation"));
|
||||||
"D3D12 map at creation"));
|
|
||||||
mMappedData = reinterpret_cast<char*>(mappedPointer);
|
mMappedData = reinterpret_cast<char*>(mappedPointer);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError Buffer::MapReadAsyncImpl(uint32_t serial) {
|
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 = {};
|
mWrittenMappedRange = {};
|
||||||
D3D12_RANGE readRange = {0, static_cast<size_t>(GetSize())};
|
D3D12_RANGE readRange = {0, static_cast<size_t>(GetSize())};
|
||||||
DAWN_TRY(CheckHRESULT(
|
DAWN_TRY(MapBufferInternal(readRange, reinterpret_cast<void**>(&mMappedData),
|
||||||
GetD3D12Resource()->Map(0, &readRange, reinterpret_cast<void**>(&mMappedData)),
|
"D3D12 map read async"));
|
||||||
"D3D12 map read async"));
|
|
||||||
// There is no need to transition the resource to a new state: D3D12 seems to make the GPU
|
// 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.
|
// writes available when the fence is passed.
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError Buffer::MapWriteAsyncImpl(uint32_t serial) {
|
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<size_t>(GetSize())};
|
mWrittenMappedRange = {0, static_cast<size_t>(GetSize())};
|
||||||
DAWN_TRY(CheckHRESULT(GetD3D12Resource()->Map(0, &mWrittenMappedRange,
|
DAWN_TRY(MapBufferInternal(mWrittenMappedRange, reinterpret_cast<void**>(&mMappedData),
|
||||||
reinterpret_cast<void**>(&mMappedData)),
|
"D3D12 map write async"));
|
||||||
"D3D12 map write async"));
|
|
||||||
// There is no need to transition the resource to a new state: D3D12 seems to make the CPU
|
// There is no need to transition the resource to a new state: D3D12 seems to make the CPU
|
||||||
// writes available on queue submission.
|
// writes available on queue submission.
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::UnmapImpl() {
|
void Buffer::UnmapImpl() {
|
||||||
GetD3D12Resource()->Unmap(0, &mWrittenMappedRange);
|
UnmapBufferInternal(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);
|
|
||||||
mWrittenMappedRange = {};
|
mWrittenMappedRange = {};
|
||||||
mMappedData = nullptr;
|
mMappedData = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -317,4 +326,39 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return mResourceAllocation.GetInfo().mMethod == allocationMethod;
|
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<size_t>(GetSize())};
|
||||||
|
DAWN_TRY(MapBufferInternal(writeRange, reinterpret_cast<void**>(&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
|
}} // namespace dawn_native::d3d12
|
||||||
|
|
|
@ -55,11 +55,17 @@ namespace dawn_native { namespace d3d12 {
|
||||||
bool IsMapWritable() const override;
|
bool IsMapWritable() const override;
|
||||||
virtual MaybeError MapAtCreationImpl(uint8_t** mappedPointer) override;
|
virtual MaybeError MapAtCreationImpl(uint8_t** mappedPointer) override;
|
||||||
void* GetMappedPointerImpl() override;
|
void* GetMappedPointerImpl() override;
|
||||||
|
MaybeError MapBufferInternal(D3D12_RANGE mappedRange,
|
||||||
|
void** mappedPointer,
|
||||||
|
const char* contextInfo);
|
||||||
|
void UnmapBufferInternal(D3D12_RANGE mappedRange);
|
||||||
|
|
||||||
bool TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
|
bool TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
|
||||||
D3D12_RESOURCE_BARRIER* barrier,
|
D3D12_RESOURCE_BARRIER* barrier,
|
||||||
wgpu::BufferUsage newUsage);
|
wgpu::BufferUsage newUsage);
|
||||||
|
|
||||||
|
MaybeError ClearBuffer(ClearValue clearValue);
|
||||||
|
|
||||||
ResourceHeapAllocation mResourceAllocation;
|
ResourceHeapAllocation mResourceAllocation;
|
||||||
bool mFixedResourceState = false;
|
bool mFixedResourceState = false;
|
||||||
wgpu::BufferUsage mLastUsage = wgpu::BufferUsage::None;
|
wgpu::BufferUsage mLastUsage = wgpu::BufferUsage::None;
|
||||||
|
|
|
@ -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
|
// Verify that each byte of the buffer has all been initialized to 1 with the toggle enabled when it
|
||||||
// is created without CopyDst usage.
|
// is created with MapWrite without CopyDst usage.
|
||||||
TEST_P(NonzeroBufferCreationTests, BufferCreationWithoutCopyDstUsage) {
|
TEST_P(NonzeroBufferCreationTests, BufferCreationWithMapWriteWithoutCopyDstUsage) {
|
||||||
constexpr uint32_t kSize = 32u;
|
constexpr uint32_t kSize = 32u;
|
||||||
|
|
||||||
wgpu::BufferDescriptor descriptor;
|
wgpu::BufferDescriptor descriptor;
|
||||||
|
@ -51,5 +51,6 @@ TEST_P(NonzeroBufferCreationTests, BufferCreationWithoutCopyDstUsage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(NonzeroBufferCreationTests,
|
DAWN_INSTANTIATE_TEST(NonzeroBufferCreationTests,
|
||||||
|
D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}),
|
||||||
MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}),
|
MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}),
|
||||||
VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}));
|
VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}));
|
||||||
|
|
Loading…
Reference in New Issue