Implement MapReadAsync on D3D12 backend
Buffers with MapRead allowed are created on the READBACK heap and always add the D3D12_RESOURCE_STATE_COPY_DEST state (required by D3D12). Likewise MapWrite adds the D3D12_RESOURCE_STATE_GENERIC_READ state and places resources on the UPLOAD heap. Because these states are required, transitions for mapped buffers do nothing.
This commit is contained in:
parent
8fa550c015
commit
47261d4ecb
|
@ -43,6 +43,16 @@ namespace d3d12 {
|
||||||
|
|
||||||
return resourceState;
|
return resourceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D12_HEAP_TYPE D3D12HeapType(nxt::BufferUsageBit allowedUsage) {
|
||||||
|
if (allowedUsage & nxt::BufferUsageBit::MapRead) {
|
||||||
|
return D3D12_HEAP_TYPE_READBACK;
|
||||||
|
} else if (allowedUsage & nxt::BufferUsageBit::MapWrite) {
|
||||||
|
return D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
} else {
|
||||||
|
return D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::Buffer(Device* device, BufferBuilder* builder)
|
Buffer::Buffer(Device* device, BufferBuilder* builder)
|
||||||
|
@ -61,7 +71,20 @@ namespace d3d12 {
|
||||||
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE;
|
resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12BufferUsage(GetUsage()));
|
auto heapType = D3D12HeapType(GetAllowedUsage());
|
||||||
|
auto bufferUsage = D3D12BufferUsage(GetUsage());
|
||||||
|
|
||||||
|
// D3D12 requires buffers on the READBACK heap to have the D3D12_RESOURCE_STATE_COPY_DEST state
|
||||||
|
if (heapType == D3D12_HEAP_TYPE_READBACK) {
|
||||||
|
bufferUsage |= D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// D3D12 requires buffers on the UPLOAD heap to have the D3D12_RESOURCE_STATE_GENERIC_READ state
|
||||||
|
if (heapType == D3D12_HEAP_TYPE_UPLOAD) {
|
||||||
|
bufferUsage |= D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
resource = device->GetResourceAllocator()->Allocate(heapType, resourceDescriptor, bufferUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::~Buffer() {
|
Buffer::~Buffer() {
|
||||||
|
@ -78,6 +101,12 @@ namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
|
bool Buffer::GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
|
||||||
|
if (GetAllowedUsage() & (nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::MapWrite)) {
|
||||||
|
// Transitions are never needed for mapped buffers because they are created with and always need the Transfer(Dst|Src) state.
|
||||||
|
// Mapped buffers cannot have states outside of (MapRead|TransferDst) and (MapWrite|TransferSrc)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
D3D12_RESOURCE_STATES stateBefore = D3D12BufferUsage(currentUsage);
|
D3D12_RESOURCE_STATES stateBefore = D3D12BufferUsage(currentUsage);
|
||||||
D3D12_RESOURCE_STATES stateAfter = D3D12BufferUsage(targetUsage);
|
D3D12_RESOURCE_STATES stateAfter = D3D12BufferUsage(targetUsage);
|
||||||
|
|
||||||
|
@ -99,16 +128,28 @@ namespace d3d12 {
|
||||||
return resource->GetGPUVirtualAddress();
|
return resource->GetGPUVirtualAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::OnMapReadCommandSerialFinished(uint32_t mapSerial, const void* data) {
|
||||||
|
CallMapReadCallback(mapSerial, NXT_BUFFER_MAP_READ_STATUS_SUCCESS, data);
|
||||||
|
}
|
||||||
|
|
||||||
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
|
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
|
||||||
device->GetResourceUploader()->BufferSubData(resource, start * sizeof(uint32_t), count * sizeof(uint32_t), data);
|
device->GetResourceUploader()->BufferSubData(resource, start * sizeof(uint32_t), count * sizeof(uint32_t), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
|
void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
|
||||||
// TODO(cwallez@chromium.org): Implement Map Read for the null backend
|
D3D12_RANGE readRange = { start, start + count };
|
||||||
|
char* data = nullptr;
|
||||||
|
ASSERT_SUCCESS(resource->Map(0, &readRange, reinterpret_cast<void**>(&data)));
|
||||||
|
|
||||||
|
MapReadRequestTracker* tracker = ToBackend(GetDevice())->GetMapReadRequestTracker();
|
||||||
|
tracker->Track(this, serial, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::UnmapImpl() {
|
void Buffer::UnmapImpl() {
|
||||||
// TODO(cwallez@chromium.org): Implement Map Read for the null backend
|
// TODO(enga@google.com): When MapWrite is implemented, this should state the range that was modified
|
||||||
|
D3D12_RANGE writeRange = {};
|
||||||
|
resource->Unmap(0, &writeRange);
|
||||||
|
device->GetResourceAllocator()->Release(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) {
|
void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) {
|
||||||
|
@ -147,5 +188,29 @@ namespace d3d12 {
|
||||||
return uavDesc;
|
return uavDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MapReadRequestTracker::MapReadRequestTracker(Device* device)
|
||||||
|
: device(device) {
|
||||||
|
}
|
||||||
|
|
||||||
|
MapReadRequestTracker::~MapReadRequestTracker() {
|
||||||
|
ASSERT(inflightRequests.Empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapReadRequestTracker::Track(Buffer* buffer, uint32_t mapSerial, const void* data) {
|
||||||
|
Request request;
|
||||||
|
request.buffer = buffer;
|
||||||
|
request.mapSerial = mapSerial;
|
||||||
|
request.data = data;
|
||||||
|
|
||||||
|
inflightRequests.Enqueue(std::move(request), device->GetSerial());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapReadRequestTracker::Tick(Serial finishedSerial) {
|
||||||
|
for (auto& request : inflightRequests.IterateUpTo(finishedSerial)) {
|
||||||
|
request.buffer->OnMapReadCommandSerialFinished(request.mapSerial, request.data);
|
||||||
|
}
|
||||||
|
inflightRequests.ClearUpTo(finishedSerial);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define BACKEND_D3D12_BUFFERD3D12_H_
|
#define BACKEND_D3D12_BUFFERD3D12_H_
|
||||||
|
|
||||||
#include "common/Buffer.h"
|
#include "common/Buffer.h"
|
||||||
|
#include "common/SerialQueue.h"
|
||||||
|
|
||||||
#include "d3d12_platform.h"
|
#include "d3d12_platform.h"
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ namespace d3d12 {
|
||||||
ComPtr<ID3D12Resource> GetD3D12Resource();
|
ComPtr<ID3D12Resource> GetD3D12Resource();
|
||||||
D3D12_GPU_VIRTUAL_ADDRESS GetVA() const;
|
D3D12_GPU_VIRTUAL_ADDRESS GetVA() const;
|
||||||
bool GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
|
bool GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
|
||||||
|
void OnMapReadCommandSerialFinished(uint32_t mapSerial, const void* data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Device* device;
|
Device* device;
|
||||||
|
@ -59,6 +61,25 @@ namespace d3d12 {
|
||||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc;
|
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MapReadRequestTracker {
|
||||||
|
public:
|
||||||
|
MapReadRequestTracker(Device* device);
|
||||||
|
~MapReadRequestTracker();
|
||||||
|
|
||||||
|
void Track(Buffer* buffer, uint32_t mapSerial, const void* data);
|
||||||
|
void Tick(Serial finishedSerial);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Device* device;
|
||||||
|
|
||||||
|
struct Request {
|
||||||
|
Ref<Buffer> buffer;
|
||||||
|
uint32_t mapSerial;
|
||||||
|
const void* data;
|
||||||
|
};
|
||||||
|
SerialQueue<Request> inflightRequests;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ namespace d3d12 {
|
||||||
: d3d12Device(d3d12Device),
|
: d3d12Device(d3d12Device),
|
||||||
commandAllocatorManager(new CommandAllocatorManager(this)),
|
commandAllocatorManager(new CommandAllocatorManager(this)),
|
||||||
descriptorHeapAllocator(new DescriptorHeapAllocator(this)),
|
descriptorHeapAllocator(new DescriptorHeapAllocator(this)),
|
||||||
|
mapReadRequestTracker(new MapReadRequestTracker(this)),
|
||||||
resourceAllocator(new ResourceAllocator(this)),
|
resourceAllocator(new ResourceAllocator(this)),
|
||||||
resourceUploader(new ResourceUploader(this)) {
|
resourceUploader(new ResourceUploader(this)) {
|
||||||
|
|
||||||
|
@ -114,6 +115,10 @@ namespace d3d12 {
|
||||||
return descriptorHeapAllocator;
|
return descriptorHeapAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MapReadRequestTracker* Device::GetMapReadRequestTracker() const {
|
||||||
|
return mapReadRequestTracker;
|
||||||
|
}
|
||||||
|
|
||||||
ResourceAllocator* Device::GetResourceAllocator() {
|
ResourceAllocator* Device::GetResourceAllocator() {
|
||||||
return resourceAllocator;
|
return resourceAllocator;
|
||||||
}
|
}
|
||||||
|
@ -162,6 +167,9 @@ namespace d3d12 {
|
||||||
resourceAllocator->Tick(lastCompletedSerial);
|
resourceAllocator->Tick(lastCompletedSerial);
|
||||||
commandAllocatorManager->Tick(lastCompletedSerial);
|
commandAllocatorManager->Tick(lastCompletedSerial);
|
||||||
descriptorHeapAllocator->Tick(lastCompletedSerial);
|
descriptorHeapAllocator->Tick(lastCompletedSerial);
|
||||||
|
mapReadRequestTracker->Tick(lastCompletedSerial);
|
||||||
|
ExecuteCommandLists({});
|
||||||
|
NextSerial();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Device::GetSerial() const {
|
uint64_t Device::GetSerial() const {
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace d3d12 {
|
||||||
|
|
||||||
class CommandAllocatorManager;
|
class CommandAllocatorManager;
|
||||||
class DescriptorHeapAllocator;
|
class DescriptorHeapAllocator;
|
||||||
|
class MapReadRequestTracker;
|
||||||
class ResourceAllocator;
|
class ResourceAllocator;
|
||||||
class ResourceUploader;
|
class ResourceUploader;
|
||||||
|
|
||||||
|
@ -115,6 +116,7 @@ namespace d3d12 {
|
||||||
ComPtr<ID3D12CommandQueue> GetCommandQueue();
|
ComPtr<ID3D12CommandQueue> GetCommandQueue();
|
||||||
|
|
||||||
DescriptorHeapAllocator* GetDescriptorHeapAllocator();
|
DescriptorHeapAllocator* GetDescriptorHeapAllocator();
|
||||||
|
MapReadRequestTracker* GetMapReadRequestTracker() const;
|
||||||
ResourceAllocator* GetResourceAllocator();
|
ResourceAllocator* GetResourceAllocator();
|
||||||
ResourceUploader* GetResourceUploader();
|
ResourceUploader* GetResourceUploader();
|
||||||
|
|
||||||
|
@ -144,6 +146,7 @@ namespace d3d12 {
|
||||||
|
|
||||||
CommandAllocatorManager* commandAllocatorManager;
|
CommandAllocatorManager* commandAllocatorManager;
|
||||||
DescriptorHeapAllocator* descriptorHeapAllocator;
|
DescriptorHeapAllocator* descriptorHeapAllocator;
|
||||||
|
MapReadRequestTracker* mapReadRequestTracker;
|
||||||
ResourceAllocator* resourceAllocator;
|
ResourceAllocator* resourceAllocator;
|
||||||
ResourceUploader* resourceUploader;
|
ResourceUploader* resourceUploader;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue