Make the D3D12 backend support implicit barriers
With this the backend ignores explicit usage transition hints from the frontent and generates all the barriers automatically based on resource usage. The current implementation is very naive and encodes a barrier immediately just before a resource is used in a new state.
This commit is contained in:
parent
2beeae3ad3
commit
a430a9a0aa
|
@ -67,7 +67,7 @@ namespace backend { namespace d3d12 {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Buffer::Buffer(Device* device, BufferBuilder* builder) : BufferBase(builder), mDevice(device) {
|
Buffer::Buffer(BufferBuilder* builder) : BufferBase(builder) {
|
||||||
D3D12_RESOURCE_DESC resourceDescriptor;
|
D3D12_RESOURCE_DESC resourceDescriptor;
|
||||||
resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
resourceDescriptor.Alignment = 0;
|
resourceDescriptor.Alignment = 0;
|
||||||
|
@ -82,26 +82,31 @@ namespace backend { namespace d3d12 {
|
||||||
resourceDescriptor.Flags = D3D12ResourceFlags(GetAllowedUsage());
|
resourceDescriptor.Flags = D3D12ResourceFlags(GetAllowedUsage());
|
||||||
|
|
||||||
auto heapType = D3D12HeapType(GetAllowedUsage());
|
auto heapType = D3D12HeapType(GetAllowedUsage());
|
||||||
auto bufferUsage = D3D12BufferUsage(GetUsage());
|
auto bufferUsage = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
|
||||||
// D3D12 requires buffers on the READBACK heap to have the D3D12_RESOURCE_STATE_COPY_DEST
|
// D3D12 requires buffers on the READBACK heap to have the D3D12_RESOURCE_STATE_COPY_DEST
|
||||||
// state
|
// state
|
||||||
if (heapType == D3D12_HEAP_TYPE_READBACK) {
|
if (heapType == D3D12_HEAP_TYPE_READBACK) {
|
||||||
bufferUsage |= D3D12_RESOURCE_STATE_COPY_DEST;
|
bufferUsage |= D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
mFixedResourceState = true;
|
||||||
|
mLastUsage = nxt::BufferUsageBit::TransferDst;
|
||||||
}
|
}
|
||||||
|
|
||||||
// D3D12 requires buffers on the UPLOAD heap to have the D3D12_RESOURCE_STATE_GENERIC_READ
|
// D3D12 requires buffers on the UPLOAD heap to have the D3D12_RESOURCE_STATE_GENERIC_READ
|
||||||
// state
|
// state
|
||||||
if (heapType == D3D12_HEAP_TYPE_UPLOAD) {
|
if (heapType == D3D12_HEAP_TYPE_UPLOAD) {
|
||||||
bufferUsage |= D3D12_RESOURCE_STATE_GENERIC_READ;
|
bufferUsage |= D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||||
|
mFixedResourceState = true;
|
||||||
|
mLastUsage = nxt::BufferUsageBit::TransferSrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
mResource =
|
mResource = ToBackend(GetDevice())
|
||||||
device->GetResourceAllocator()->Allocate(heapType, resourceDescriptor, bufferUsage);
|
->GetResourceAllocator()
|
||||||
|
->Allocate(heapType, resourceDescriptor, bufferUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::~Buffer() {
|
Buffer::~Buffer() {
|
||||||
mDevice->GetResourceAllocator()->Release(mResource);
|
ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Buffer::GetD3D12Size() const {
|
uint32_t Buffer::GetD3D12Size() const {
|
||||||
|
@ -113,31 +118,35 @@ namespace backend { namespace d3d12 {
|
||||||
return mResource;
|
return mResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage,
|
void Buffer::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
nxt::BufferUsageBit targetUsage,
|
nxt::BufferUsageBit usage) {
|
||||||
D3D12_RESOURCE_BARRIER* barrier) {
|
// Resources in upload and readback heaps must be kept in the COPY_SOURCE/DEST state
|
||||||
if (GetAllowedUsage() & (nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::MapWrite)) {
|
if (mFixedResourceState) {
|
||||||
// Transitions are never needed for mapped buffers because they are created with and
|
ASSERT(usage == mLastUsage);
|
||||||
// always need the Transfer(Dst|Src) state. Mapped buffers cannot have states outside of
|
return;
|
||||||
// (MapRead|TransferDst) and (MapWrite|TransferSrc)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_RESOURCE_STATES stateBefore = D3D12BufferUsage(currentUsage);
|
// We can skip transitions to already current usages.
|
||||||
D3D12_RESOURCE_STATES stateAfter = D3D12BufferUsage(targetUsage);
|
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
||||||
|
bool lastIncludesTarget = (mLastUsage & usage) == usage;
|
||||||
if (stateBefore == stateAfter) {
|
if (lastIncludesTarget) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
D3D12_RESOURCE_STATES lastState = D3D12BufferUsage(mLastUsage);
|
||||||
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
D3D12_RESOURCE_STATES newState = D3D12BufferUsage(usage);
|
||||||
barrier->Transition.pResource = mResource.Get();
|
|
||||||
barrier->Transition.StateBefore = stateBefore;
|
|
||||||
barrier->Transition.StateAfter = stateAfter;
|
|
||||||
barrier->Transition.Subresource = 0;
|
|
||||||
|
|
||||||
return true;
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
|
barrier.Transition.pResource = mResource.Get();
|
||||||
|
barrier.Transition.StateBefore = lastState;
|
||||||
|
barrier.Transition.StateAfter = newState;
|
||||||
|
barrier.Transition.Subresource = 0;
|
||||||
|
|
||||||
|
commandList->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
|
mLastUsage = usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const {
|
D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const {
|
||||||
|
@ -153,7 +162,10 @@ namespace backend { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint8_t* data) {
|
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint8_t* data) {
|
||||||
mDevice->GetResourceUploader()->BufferSubData(mResource, start, count, data);
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
|
TransitionUsageNow(device->GetPendingCommandList(), nxt::BufferUsageBit::TransferDst);
|
||||||
|
device->GetResourceUploader()->BufferSubData(mResource, start, count, 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) {
|
||||||
|
@ -161,6 +173,8 @@ namespace backend { namespace d3d12 {
|
||||||
char* data = nullptr;
|
char* data = nullptr;
|
||||||
ASSERT_SUCCESS(mResource->Map(0, &readRange, reinterpret_cast<void**>(&data)));
|
ASSERT_SUCCESS(mResource->Map(0, &readRange, reinterpret_cast<void**>(&data)));
|
||||||
|
|
||||||
|
// 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.
|
||||||
MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker();
|
MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker();
|
||||||
tracker->Track(this, serial, data + start, false);
|
tracker->Track(this, serial, data + start, false);
|
||||||
}
|
}
|
||||||
|
@ -170,6 +184,8 @@ namespace backend { namespace d3d12 {
|
||||||
char* data = nullptr;
|
char* data = nullptr;
|
||||||
ASSERT_SUCCESS(mResource->Map(0, &readRange, reinterpret_cast<void**>(&data)));
|
ASSERT_SUCCESS(mResource->Map(0, &readRange, reinterpret_cast<void**>(&data)));
|
||||||
|
|
||||||
|
// There is no need to transition the resource to a new state: D3D12 seems to make the CPU
|
||||||
|
// writes available on queue submission.
|
||||||
MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker();
|
MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker();
|
||||||
tracker->Track(this, serial, data + start, true);
|
tracker->Track(this, serial, data + start, true);
|
||||||
}
|
}
|
||||||
|
@ -179,15 +195,10 @@ namespace backend { namespace d3d12 {
|
||||||
// modified
|
// modified
|
||||||
D3D12_RANGE writeRange = {};
|
D3D12_RANGE writeRange = {};
|
||||||
mResource->Unmap(0, &writeRange);
|
mResource->Unmap(0, &writeRange);
|
||||||
mDevice->GetResourceAllocator()->Release(mResource);
|
ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage,
|
void Buffer::TransitionUsageImpl(nxt::BufferUsageBit, nxt::BufferUsageBit) {
|
||||||
nxt::BufferUsageBit targetUsage) {
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
|
||||||
if (GetResourceTransitionBarrier(currentUsage, targetUsage, &barrier)) {
|
|
||||||
mDevice->GetPendingCommandList()->ResourceBarrier(1, &barrier);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferView::BufferView(BufferViewBuilder* builder) : BufferViewBase(builder) {
|
BufferView::BufferView(BufferViewBuilder* builder) : BufferViewBase(builder) {
|
||||||
|
|
|
@ -26,21 +26,18 @@ namespace backend { namespace d3d12 {
|
||||||
|
|
||||||
class Buffer : public BufferBase {
|
class Buffer : public BufferBase {
|
||||||
public:
|
public:
|
||||||
Buffer(Device* device, BufferBuilder* builder);
|
Buffer(BufferBuilder* builder);
|
||||||
~Buffer();
|
~Buffer();
|
||||||
|
|
||||||
uint32_t GetD3D12Size() const;
|
uint32_t GetD3D12Size() const;
|
||||||
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);
|
|
||||||
void OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite);
|
void OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite);
|
||||||
|
|
||||||
private:
|
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
Device* mDevice;
|
nxt::BufferUsageBit usage);
|
||||||
ComPtr<ID3D12Resource> mResource;
|
|
||||||
|
|
||||||
|
private:
|
||||||
// NXT API
|
// NXT API
|
||||||
void SetSubDataImpl(uint32_t start, uint32_t count, const uint8_t* data) override;
|
void SetSubDataImpl(uint32_t start, uint32_t count, const uint8_t* data) override;
|
||||||
void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
|
void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
|
||||||
|
@ -48,6 +45,10 @@ namespace backend { namespace d3d12 {
|
||||||
void UnmapImpl() override;
|
void UnmapImpl() override;
|
||||||
void TransitionUsageImpl(nxt::BufferUsageBit currentUsage,
|
void TransitionUsageImpl(nxt::BufferUsageBit currentUsage,
|
||||||
nxt::BufferUsageBit targetUsage) override;
|
nxt::BufferUsageBit targetUsage) override;
|
||||||
|
|
||||||
|
ComPtr<ID3D12Resource> mResource;
|
||||||
|
bool mFixedResourceState = false;
|
||||||
|
nxt::BufferUsageBit mLastUsage = nxt::BufferUsageBit::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BufferView : public BufferViewBase {
|
class BufferView : public BufferViewBase {
|
||||||
|
|
|
@ -230,7 +230,9 @@ namespace backend { namespace d3d12 {
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
|
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
|
||||||
: CommandBufferBase(builder), mCommands(builder->AcquireCommands()) {
|
: CommandBufferBase(builder),
|
||||||
|
mCommands(builder->AcquireCommands()),
|
||||||
|
mPassResourceUsages(builder->AcquirePassResourceUsage()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandBuffer::~CommandBuffer() {
|
CommandBuffer::~CommandBuffer() {
|
||||||
|
@ -261,27 +263,55 @@ namespace backend { namespace d3d12 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Records the necessary barriers for the resource usage pre-computed by the frontend
|
||||||
|
auto TransitionForPass = [](ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
|
const PassResourceUsage& usages) {
|
||||||
|
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||||
|
Buffer* buffer = ToBackend(usages.buffers[i]);
|
||||||
|
buffer->TransitionUsageNow(commandList, usages.bufferUsages[i]);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
|
Texture* texture = ToBackend(usages.textures[i]);
|
||||||
|
texture->TransitionUsageNow(commandList, usages.textureUsages[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t nextPassNumber = 0;
|
||||||
|
|
||||||
Command type;
|
Command type;
|
||||||
while (mCommands.NextCommandId(&type)) {
|
while (mCommands.NextCommandId(&type)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::BeginComputePass: {
|
case Command::BeginComputePass: {
|
||||||
mCommands.NextCommand<BeginComputePassCmd>();
|
mCommands.NextCommand<BeginComputePassCmd>();
|
||||||
|
|
||||||
|
TransitionForPass(commandList, mPassResourceUsages[nextPassNumber]);
|
||||||
RecordComputePass(commandList, &bindingTracker);
|
RecordComputePass(commandList, &bindingTracker);
|
||||||
|
|
||||||
|
nextPassNumber++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::BeginRenderPass: {
|
case Command::BeginRenderPass: {
|
||||||
BeginRenderPassCmd* beginRenderPassCmd =
|
BeginRenderPassCmd* beginRenderPassCmd =
|
||||||
mCommands.NextCommand<BeginRenderPassCmd>();
|
mCommands.NextCommand<BeginRenderPassCmd>();
|
||||||
|
|
||||||
|
TransitionForPass(commandList, mPassResourceUsages[nextPassNumber]);
|
||||||
RecordRenderPass(commandList, &bindingTracker,
|
RecordRenderPass(commandList, &bindingTracker,
|
||||||
ToBackend(beginRenderPassCmd->info.Get()));
|
ToBackend(beginRenderPassCmd->info.Get()));
|
||||||
|
|
||||||
|
nextPassNumber++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::CopyBufferToBuffer: {
|
case Command::CopyBufferToBuffer: {
|
||||||
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
|
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
|
||||||
auto src = ToBackend(copy->source.buffer.Get())->GetD3D12Resource();
|
Buffer* srcBuffer = ToBackend(copy->source.buffer.Get());
|
||||||
auto dst = ToBackend(copy->destination.buffer.Get())->GetD3D12Resource();
|
Buffer* dstBuffer = ToBackend(copy->destination.buffer.Get());
|
||||||
commandList->CopyBufferRegion(dst.Get(), copy->destination.offset, src.Get(),
|
|
||||||
copy->source.offset, copy->size);
|
srcBuffer->TransitionUsageNow(commandList, nxt::BufferUsageBit::TransferSrc);
|
||||||
|
dstBuffer->TransitionUsageNow(commandList, nxt::BufferUsageBit::TransferDst);
|
||||||
|
|
||||||
|
commandList->CopyBufferRegion(
|
||||||
|
dstBuffer->GetD3D12Resource().Get(), copy->destination.offset,
|
||||||
|
srcBuffer->GetD3D12Resource().Get(), copy->source.offset, copy->size);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::CopyBufferToTexture: {
|
case Command::CopyBufferToTexture: {
|
||||||
|
@ -289,6 +319,9 @@ namespace backend { namespace d3d12 {
|
||||||
Buffer* buffer = ToBackend(copy->source.buffer.Get());
|
Buffer* buffer = ToBackend(copy->source.buffer.Get());
|
||||||
Texture* texture = ToBackend(copy->destination.texture.Get());
|
Texture* texture = ToBackend(copy->destination.texture.Get());
|
||||||
|
|
||||||
|
buffer->TransitionUsageNow(commandList, nxt::BufferUsageBit::TransferSrc);
|
||||||
|
texture->TransitionUsageNow(commandList, nxt::TextureUsageBit::TransferDst);
|
||||||
|
|
||||||
auto copySplit = ComputeTextureCopySplit(
|
auto copySplit = ComputeTextureCopySplit(
|
||||||
copy->destination.x, copy->destination.y, copy->destination.z,
|
copy->destination.x, copy->destination.y, copy->destination.z,
|
||||||
copy->destination.width, copy->destination.height, copy->destination.depth,
|
copy->destination.width, copy->destination.height, copy->destination.depth,
|
||||||
|
@ -332,6 +365,9 @@ namespace backend { namespace d3d12 {
|
||||||
Texture* texture = ToBackend(copy->source.texture.Get());
|
Texture* texture = ToBackend(copy->source.texture.Get());
|
||||||
Buffer* buffer = ToBackend(copy->destination.buffer.Get());
|
Buffer* buffer = ToBackend(copy->destination.buffer.Get());
|
||||||
|
|
||||||
|
texture->TransitionUsageNow(commandList, nxt::TextureUsageBit::TransferSrc);
|
||||||
|
buffer->TransitionUsageNow(commandList, nxt::BufferUsageBit::TransferDst);
|
||||||
|
|
||||||
auto copySplit = ComputeTextureCopySplit(
|
auto copySplit = ComputeTextureCopySplit(
|
||||||
copy->source.x, copy->source.y, copy->source.z, copy->source.width,
|
copy->source.x, copy->source.y, copy->source.z, copy->source.width,
|
||||||
copy->source.height, copy->source.depth,
|
copy->source.height, copy->source.depth,
|
||||||
|
@ -373,31 +409,13 @@ namespace backend { namespace d3d12 {
|
||||||
case Command::TransitionBufferUsage: {
|
case Command::TransitionBufferUsage: {
|
||||||
TransitionBufferUsageCmd* cmd =
|
TransitionBufferUsageCmd* cmd =
|
||||||
mCommands.NextCommand<TransitionBufferUsageCmd>();
|
mCommands.NextCommand<TransitionBufferUsageCmd>();
|
||||||
|
cmd->buffer->UpdateUsageInternal(cmd->usage);
|
||||||
Buffer* buffer = ToBackend(cmd->buffer.Get());
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
|
||||||
if (buffer->GetResourceTransitionBarrier(buffer->GetUsage(), cmd->usage,
|
|
||||||
&barrier)) {
|
|
||||||
commandList->ResourceBarrier(1, &barrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer->UpdateUsageInternal(cmd->usage);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::TransitionTextureUsage: {
|
case Command::TransitionTextureUsage: {
|
||||||
TransitionTextureUsageCmd* cmd =
|
TransitionTextureUsageCmd* cmd =
|
||||||
mCommands.NextCommand<TransitionTextureUsageCmd>();
|
mCommands.NextCommand<TransitionTextureUsageCmd>();
|
||||||
|
cmd->texture->UpdateUsageInternal(cmd->usage);
|
||||||
Texture* texture = ToBackend(cmd->texture.Get());
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
|
||||||
if (texture->GetResourceTransitionBarrier(texture->GetUsage(), cmd->usage,
|
|
||||||
&barrier)) {
|
|
||||||
commandList->ResourceBarrier(1, &barrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture->UpdateUsageInternal(cmd->usage);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: { UNREACHABLE(); } break;
|
default: { UNREACHABLE(); } break;
|
||||||
|
@ -456,8 +474,6 @@ namespace backend { namespace d3d12 {
|
||||||
// It's already validated that this texture is either frozen to the correct
|
// It's already validated that this texture is either frozen to the correct
|
||||||
// usage, or not frozen.
|
// usage, or not frozen.
|
||||||
if (!texture->IsFrozen()) {
|
if (!texture->IsFrozen()) {
|
||||||
texture->TransitionUsageImpl(texture->GetUsage(),
|
|
||||||
nxt::TextureUsageBit::OutputAttachment);
|
|
||||||
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,8 +492,6 @@ namespace backend { namespace d3d12 {
|
||||||
// It's already validated that this texture is either frozen to the correct
|
// It's already validated that this texture is either frozen to the correct
|
||||||
// usage, or not frozen.
|
// usage, or not frozen.
|
||||||
if (!texture->IsFrozen()) {
|
if (!texture->IsFrozen()) {
|
||||||
texture->TransitionUsageImpl(texture->GetUsage(),
|
|
||||||
nxt::TextureUsageBit::OutputAttachment);
|
|
||||||
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ namespace backend { namespace d3d12 {
|
||||||
RenderPassDescriptor* renderPass);
|
RenderPassDescriptor* renderPass);
|
||||||
|
|
||||||
CommandIterator mCommands;
|
CommandIterator mCommands;
|
||||||
|
std::vector<PassResourceUsage> mPassResourceUsages;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace backend::d3d12
|
}} // namespace backend::d3d12
|
||||||
|
|
|
@ -274,7 +274,7 @@ namespace backend { namespace d3d12 {
|
||||||
return new BlendState(builder);
|
return new BlendState(builder);
|
||||||
}
|
}
|
||||||
BufferBase* Device::CreateBuffer(BufferBuilder* builder) {
|
BufferBase* Device::CreateBuffer(BufferBuilder* builder) {
|
||||||
return new Buffer(this, builder);
|
return new Buffer(builder);
|
||||||
}
|
}
|
||||||
BufferViewBase* Device::CreateBufferView(BufferViewBuilder* builder) {
|
BufferViewBase* Device::CreateBufferView(BufferViewBuilder* builder) {
|
||||||
return new BufferView(builder);
|
return new BufferView(builder);
|
||||||
|
|
|
@ -101,8 +101,7 @@ namespace backend { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
nxtSwapChainError NativeSwapChainImpl::Present() {
|
nxtSwapChainError NativeSwapChainImpl::Present() {
|
||||||
// Flush pending commands that include the transition of the texture to present.
|
// This assumes the texture has already been transition to the PRESENT state.
|
||||||
mDevice->ExecuteCommandLists({});
|
|
||||||
|
|
||||||
ASSERT_SUCCESS(mSwapChain->Present(1, 0));
|
ASSERT_SUCCESS(mSwapChain->Present(1, 0));
|
||||||
// TODO(cwallez@chromium.org): Make the serial ticking implicit.
|
// TODO(cwallez@chromium.org): Make the serial ticking implicit.
|
||||||
|
|
|
@ -26,6 +26,9 @@ namespace backend { namespace d3d12 {
|
||||||
nxtWSIContextD3D12 wsiContext = {};
|
nxtWSIContextD3D12 wsiContext = {};
|
||||||
wsiContext.device = reinterpret_cast<nxtDevice>(GetDevice());
|
wsiContext.device = reinterpret_cast<nxtDevice>(GetDevice());
|
||||||
im.Init(im.userData, &wsiContext);
|
im.Init(im.userData, &wsiContext);
|
||||||
|
|
||||||
|
ASSERT(im.textureUsage != NXT_TEXTURE_USAGE_BIT_NONE);
|
||||||
|
mTextureUsage = static_cast<nxt::TextureUsageBit>(im.textureUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapChain::~SwapChain() {
|
SwapChain::~SwapChain() {
|
||||||
|
@ -44,7 +47,13 @@ namespace backend { namespace d3d12 {
|
||||||
return new Texture(builder, nativeTexture);
|
return new Texture(builder, nativeTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapChain::OnBeforePresent(TextureBase*) {
|
void SwapChain::OnBeforePresent(TextureBase* texture) {
|
||||||
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
|
// Perform the necessary transition for the texture to be presented.
|
||||||
|
ToBackend(texture)->TransitionUsageNow(device->GetPendingCommandList(), mTextureUsage);
|
||||||
|
|
||||||
|
device->ExecuteCommandLists({});
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace backend::d3d12
|
}} // namespace backend::d3d12
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace backend { namespace d3d12 {
|
||||||
protected:
|
protected:
|
||||||
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
|
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
|
||||||
void OnBeforePresent(TextureBase* texture) override;
|
void OnBeforePresent(TextureBase* texture) override;
|
||||||
|
|
||||||
|
nxt::TextureUsageBit mTextureUsage;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace backend::d3d12
|
}} // namespace backend::d3d12
|
||||||
|
|
|
@ -150,32 +150,31 @@ namespace backend { namespace d3d12 {
|
||||||
return mResourcePtr;
|
return mResourcePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage,
|
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
nxt::TextureUsageBit targetUsage,
|
nxt::TextureUsageBit usage) {
|
||||||
D3D12_RESOURCE_BARRIER* barrier) {
|
// Avoid transitioning the texture when it isn't needed.
|
||||||
D3D12_RESOURCE_STATES stateBefore = D3D12TextureUsage(currentUsage, GetFormat());
|
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
||||||
D3D12_RESOURCE_STATES stateAfter = D3D12TextureUsage(targetUsage, GetFormat());
|
if (usage == mLastUsage) {
|
||||||
|
return;
|
||||||
if (stateBefore == stateAfter) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
D3D12_RESOURCE_STATES lastState = D3D12TextureUsage(mLastUsage, GetFormat());
|
||||||
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
D3D12_RESOURCE_STATES newState = D3D12TextureUsage(usage, GetFormat());
|
||||||
barrier->Transition.pResource = mResourcePtr;
|
|
||||||
barrier->Transition.StateBefore = stateBefore;
|
|
||||||
barrier->Transition.StateAfter = stateAfter;
|
|
||||||
barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Texture::TransitionUsageImpl(nxt::TextureUsageBit currentUsage,
|
|
||||||
nxt::TextureUsageBit targetUsage) {
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
if (GetResourceTransitionBarrier(currentUsage, targetUsage, &barrier)) {
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
mDevice->GetPendingCommandList()->ResourceBarrier(1, &barrier);
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
|
barrier.Transition.pResource = mResourcePtr;
|
||||||
|
barrier.Transition.StateBefore = lastState;
|
||||||
|
barrier.Transition.StateAfter = newState;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|
||||||
|
commandList->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
|
mLastUsage = usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Texture::TransitionUsageImpl(nxt::TextureUsageBit, nxt::TextureUsageBit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureView::TextureView(TextureViewBuilder* builder) : TextureViewBase(builder) {
|
TextureView::TextureView(TextureViewBuilder* builder) : TextureViewBase(builder) {
|
||||||
|
|
|
@ -33,17 +33,18 @@ namespace backend { namespace d3d12 {
|
||||||
|
|
||||||
DXGI_FORMAT GetD3D12Format() const;
|
DXGI_FORMAT GetD3D12Format() const;
|
||||||
ID3D12Resource* GetD3D12Resource();
|
ID3D12Resource* GetD3D12Resource();
|
||||||
bool GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage,
|
|
||||||
nxt::TextureUsageBit targetUsage,
|
|
||||||
D3D12_RESOURCE_BARRIER* barrier);
|
|
||||||
|
|
||||||
|
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
|
nxt::TextureUsageBit usage);
|
||||||
|
|
||||||
|
private:
|
||||||
void TransitionUsageImpl(nxt::TextureUsageBit currentUsage,
|
void TransitionUsageImpl(nxt::TextureUsageBit currentUsage,
|
||||||
nxt::TextureUsageBit targetUsage) override;
|
nxt::TextureUsageBit targetUsage) override;
|
||||||
|
|
||||||
private:
|
|
||||||
Device* mDevice;
|
Device* mDevice;
|
||||||
ComPtr<ID3D12Resource> mResource = {};
|
ComPtr<ID3D12Resource> mResource = {};
|
||||||
ID3D12Resource* mResourcePtr = nullptr;
|
ID3D12Resource* mResourcePtr = nullptr;
|
||||||
|
nxt::TextureUsageBit mLastUsage = nxt::TextureUsageBit::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextureView : public TextureViewBase {
|
class TextureView : public TextureViewBase {
|
||||||
|
|
Loading…
Reference in New Issue