Copy from a zeroed-out buffer to clear in D3D12

When setting a buffer to zero now uses copies from a previously
allocated, zeroed out buffer to perform the clear rather than making new
allocations every time.

Bug: dawn:1160
Change-Id: I0c8e7e56b2afcb5961723e352d8bbdf276f4557c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/70760
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Brandon Jones <bajones@chromium.org>
This commit is contained in:
Brandon Jones 2021-12-01 16:17:20 +00:00 committed by Dawn LUCI CQ
parent 2294cf4480
commit e7efad0325
4 changed files with 73 additions and 1 deletions

View File

@ -469,6 +469,8 @@ namespace dawn_native { namespace d3d12 {
"D3D12 map at clear buffer")); "D3D12 map at clear buffer"));
memset(mMappedData, clearValue, size); memset(mMappedData, clearValue, size);
UnmapImpl(); UnmapImpl();
} else if (clearValue == 0u) {
DAWN_TRY(device->ClearBufferToZero(commandContext, this, offset, size));
} else { } else {
// TODO(crbug.com/dawn/852): use ClearUnorderedAccessView*() when the buffer usage // TODO(crbug.com/dawn/852): use ClearUnorderedAccessView*() when the buffer usage
// includes STORAGE. // includes STORAGE.

View File

@ -15,6 +15,7 @@
#include "dawn_native/d3d12/DeviceD3D12.h" #include "dawn_native/d3d12/DeviceD3D12.h"
#include "common/GPUInfo.h" #include "common/GPUInfo.h"
#include "dawn_native/DynamicUploader.h"
#include "dawn_native/Instance.h" #include "dawn_native/Instance.h"
#include "dawn_native/d3d12/AdapterD3D12.h" #include "dawn_native/d3d12/AdapterD3D12.h"
#include "dawn_native/d3d12/BackendD3D12.h" #include "dawn_native/d3d12/BackendD3D12.h"
@ -49,6 +50,9 @@ namespace dawn_native { namespace d3d12 {
static constexpr uint16_t kShaderVisibleDescriptorHeapSize = 1024; static constexpr uint16_t kShaderVisibleDescriptorHeapSize = 1024;
static constexpr uint8_t kAttachmentDescriptorHeapSize = 64; static constexpr uint8_t kAttachmentDescriptorHeapSize = 64;
// Value may change in the future to better accomodate large clears.
static constexpr uint64_t kZeroBufferSize = 1024 * 1024 * 4; // 4 Mb
static constexpr uint64_t kMaxDebugMessagesToPrint = 5; static constexpr uint64_t kMaxDebugMessagesToPrint = 5;
// static // static
@ -166,6 +170,9 @@ namespace dawn_native { namespace d3d12 {
// The environment can only use DXC when it's available. Override the decision if it is not // The environment can only use DXC when it's available. Override the decision if it is not
// applicable. // applicable.
DAWN_TRY(ApplyUseDxcToggle()); DAWN_TRY(ApplyUseDxcToggle());
DAWN_TRY(CreateZeroBuffer());
return {}; return {};
} }
@ -251,6 +258,59 @@ namespace dawn_native { namespace d3d12 {
return &mPendingCommands; return &mPendingCommands;
} }
MaybeError Device::CreateZeroBuffer() {
BufferDescriptor zeroBufferDescriptor;
zeroBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
zeroBufferDescriptor.size = kZeroBufferSize;
zeroBufferDescriptor.label = "ZeroBuffer_Internal";
DAWN_TRY_ASSIGN(mZeroBuffer, Buffer::Create(this, &zeroBufferDescriptor));
return {};
}
MaybeError Device::ClearBufferToZero(CommandRecordingContext* commandContext,
BufferBase* destination,
uint64_t offset,
uint64_t size) {
// TODO(crbug.com/dawn/852): It would be ideal to clear the buffer in CreateZeroBuffer, but
// the allocation of the staging buffer causes various end2end tests that monitor heap usage
// to fail if it's done during device creation. Perhaps ClearUnorderedAccessView*() can be
// used to avoid that.
if (!mZeroBuffer->IsDataInitialized()) {
DynamicUploader* uploader = GetDynamicUploader();
UploadHandle uploadHandle;
DAWN_TRY_ASSIGN(uploadHandle,
uploader->Allocate(kZeroBufferSize, GetPendingCommandSerial(),
kCopyBufferToBufferOffsetAlignment));
memset(uploadHandle.mappedBuffer, 0u, kZeroBufferSize);
CopyFromStagingToBufferImpl(commandContext, uploadHandle.stagingBuffer,
uploadHandle.startOffset, mZeroBuffer.Get(), 0,
kZeroBufferSize);
mZeroBuffer->SetIsDataInitialized();
}
Buffer* dstBuffer = ToBackend(destination);
// Necessary to ensure residency of the zero buffer.
mZeroBuffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopySrc);
dstBuffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopyDst);
while (size > 0) {
uint64_t copySize = std::min(kZeroBufferSize, size);
commandContext->GetCommandList()->CopyBufferRegion(
dstBuffer->GetD3D12Resource(), offset, mZeroBuffer->GetD3D12Resource(), 0,
copySize);
offset += copySize;
size -= copySize;
}
return {};
}
MaybeError Device::TickImpl() { MaybeError Device::TickImpl() {
// Perform cleanup operations to free unused objects // Perform cleanup operations to free unused objects
ExecutionSerial completedSerial = GetCompletedCommandSerial(); ExecutionSerial completedSerial = GetCompletedCommandSerial();

View File

@ -72,6 +72,11 @@ namespace dawn_native { namespace d3d12 {
ResultOrError<CommandRecordingContext*> GetPendingCommandContext(); ResultOrError<CommandRecordingContext*> GetPendingCommandContext();
MaybeError ClearBufferToZero(CommandRecordingContext* commandContext,
BufferBase* destination,
uint64_t destinationOffset,
uint64_t size);
const D3D12DeviceInfo& GetDeviceInfo() const; const D3D12DeviceInfo& GetDeviceInfo() const;
MaybeError NextSerial(); MaybeError NextSerial();
@ -191,6 +196,8 @@ namespace dawn_native { namespace d3d12 {
MaybeError ApplyUseDxcToggle(); MaybeError ApplyUseDxcToggle();
MaybeError CreateZeroBuffer();
ComPtr<ID3D12Fence> mFence; ComPtr<ID3D12Fence> mFence;
HANDLE mFenceEvent = nullptr; HANDLE mFenceEvent = nullptr;
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override; ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
@ -246,6 +253,10 @@ namespace dawn_native { namespace d3d12 {
// release is called. // release is called.
std::unique_ptr<SamplerHeapCache> mSamplerHeapCache; std::unique_ptr<SamplerHeapCache> mSamplerHeapCache;
// A buffer filled with zeros that is used to copy into other buffers when they need to be
// cleared.
Ref<Buffer> mZeroBuffer;
// The number of nanoseconds required for a timestamp query to be incremented by 1 // The number of nanoseconds required for a timestamp query to be incremented by 1
float mTimestampPeriod = 1.0f; float mTimestampPeriod = 1.0f;
}; };

View File

@ -351,7 +351,6 @@ namespace dawn_native { namespace d3d12 {
// Places an artifical cap on Dawn's budget so we can test in a predictable manner. If used, // Places an artifical cap on Dawn's budget so we can test in a predictable manner. If used,
// this function must be called before any resources have been created. // this function must be called before any resources have been created.
void ResidencyManager::RestrictBudgetForTesting(uint64_t artificialBudgetCap) { void ResidencyManager::RestrictBudgetForTesting(uint64_t artificialBudgetCap) {
ASSERT(mVideoMemoryInfo.local.lruCache.empty());
ASSERT(mVideoMemoryInfo.nonLocal.lruCache.empty()); ASSERT(mVideoMemoryInfo.nonLocal.lruCache.empty());
ASSERT(!mRestrictBudgetForTesting); ASSERT(!mRestrictBudgetForTesting);