D3D12: Batch Usage Transitions For Render Pass
Instead of looping through usages and calling ResourceBarrier for each transition, we should load all transitions into a single call. This allows the driver to make better optimization decisions. Bug: dawn:163 Change-Id: I4859aa2c71b60a40249df00ad67ab13eb0389cd9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7680 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
This commit is contained in:
parent
2b82eb2902
commit
de1ac9fd7b
|
@ -111,6 +111,32 @@ namespace dawn_native { namespace d3d12 {
|
||||||
DestroyInternal();
|
DestroyInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Buffer::CreateD3D12ResourceBarrierIfNeeded(D3D12_RESOURCE_BARRIER* barrier,
|
||||||
|
dawn::BufferUsageBit newUsage) const {
|
||||||
|
// Resources in upload and readback heaps must be kept in the COPY_SOURCE/DEST state
|
||||||
|
if (mFixedResourceState) {
|
||||||
|
ASSERT(mLastUsage == newUsage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can skip transitions to already current usages.
|
||||||
|
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
||||||
|
if ((mLastUsage & newUsage) == newUsage) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_RESOURCE_STATES lastState = D3D12BufferUsage(mLastUsage);
|
||||||
|
D3D12_RESOURCE_STATES newState = D3D12BufferUsage(newUsage);
|
||||||
|
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 = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t Buffer::GetD3D12Size() const {
|
uint32_t Buffer::GetD3D12Size() const {
|
||||||
// TODO(enga@google.com): TODO investigate if this needs to be a constraint at the API level
|
// TODO(enga@google.com): TODO investigate if this needs to be a constraint at the API level
|
||||||
return Align(GetSize(), 256);
|
return Align(GetSize(), 256);
|
||||||
|
@ -120,33 +146,17 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return mResource;
|
return mResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::SetUsage(dawn::BufferUsageBit newUsage) {
|
||||||
|
mLastUsage = newUsage;
|
||||||
|
}
|
||||||
|
|
||||||
void Buffer::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void Buffer::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
dawn::BufferUsageBit usage) {
|
dawn::BufferUsageBit usage) {
|
||||||
// Resources in upload and readback heaps must be kept in the COPY_SOURCE/DEST state
|
|
||||||
if (mFixedResourceState) {
|
|
||||||
ASSERT(usage == mLastUsage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can skip transitions to already current usages.
|
|
||||||
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
|
||||||
bool lastIncludesTarget = (mLastUsage & usage) == usage;
|
|
||||||
if (lastIncludesTarget) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_RESOURCE_STATES lastState = D3D12BufferUsage(mLastUsage);
|
|
||||||
D3D12_RESOURCE_STATES newState = D3D12BufferUsage(usage);
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
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;
|
|
||||||
|
|
||||||
|
if (CreateD3D12ResourceBarrierIfNeeded(&barrier, usage)) {
|
||||||
commandList->ResourceBarrier(1, &barrier);
|
commandList->ResourceBarrier(1, &barrier);
|
||||||
|
}
|
||||||
|
|
||||||
mLastUsage = usage;
|
mLastUsage = usage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,11 +29,13 @@ namespace dawn_native { namespace d3d12 {
|
||||||
Buffer(Device* device, const BufferDescriptor* descriptor);
|
Buffer(Device* device, const BufferDescriptor* descriptor);
|
||||||
~Buffer();
|
~Buffer();
|
||||||
|
|
||||||
|
bool CreateD3D12ResourceBarrierIfNeeded(D3D12_RESOURCE_BARRIER* barrier,
|
||||||
|
dawn::BufferUsageBit newUsage) const;
|
||||||
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;
|
||||||
void OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite);
|
void OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite);
|
||||||
|
void SetUsage(dawn::BufferUsageBit newUsage);
|
||||||
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
dawn::BufferUsageBit usage);
|
dawn::BufferUsageBit usage);
|
||||||
|
|
||||||
|
|
|
@ -429,13 +429,28 @@ namespace dawn_native { namespace d3d12 {
|
||||||
// Records the necessary barriers for the resource usage pre-computed by the frontend
|
// Records the necessary barriers for the resource usage pre-computed by the frontend
|
||||||
auto TransitionForPass = [](ComPtr<ID3D12GraphicsCommandList> commandList,
|
auto TransitionForPass = [](ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
const PassResourceUsage& usages) {
|
const PassResourceUsage& usages) {
|
||||||
|
std::vector<D3D12_RESOURCE_BARRIER> barriers;
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||||
Buffer* buffer = ToBackend(usages.buffers[i]);
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
buffer->TransitionUsageNow(commandList, usages.bufferUsages[i]);
|
if (ToBackend(usages.buffers[i])
|
||||||
|
->CreateD3D12ResourceBarrierIfNeeded(&barrier, usages.bufferUsages[i])) {
|
||||||
|
barriers.push_back(barrier);
|
||||||
|
ToBackend(usages.buffers[i])->SetUsage(usages.bufferUsages[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
Texture* texture = ToBackend(usages.textures[i]);
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
texture->TransitionUsageNow(commandList, usages.textureUsages[i]);
|
if (ToBackend(usages.textures[i])
|
||||||
|
->CreateD3D12ResourceBarrierIfNeeded(&barrier, usages.textureUsages[i])) {
|
||||||
|
barriers.push_back(barrier);
|
||||||
|
ToBackend(usages.textures[i])->SetUsage(usages.textureUsages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (barriers.size()) {
|
||||||
|
commandList->ResourceBarrier(barriers.size(), barriers.data());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,30 @@ namespace dawn_native { namespace d3d12 {
|
||||||
DestroyInternal();
|
DestroyInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Texture::CreateD3D12ResourceBarrierIfNeeded(D3D12_RESOURCE_BARRIER* barrier,
|
||||||
|
dawn::TextureUsageBit newUsage) const {
|
||||||
|
return CreateD3D12ResourceBarrierIfNeeded(barrier,
|
||||||
|
D3D12TextureUsage(newUsage, GetFormat()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Texture::CreateD3D12ResourceBarrierIfNeeded(D3D12_RESOURCE_BARRIER* barrier,
|
||||||
|
D3D12_RESOURCE_STATES newState) const {
|
||||||
|
// Avoid transitioning the texture when it isn't needed.
|
||||||
|
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
||||||
|
if (mLastState == newState) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
|
barrier->Transition.pResource = mResourcePtr;
|
||||||
|
barrier->Transition.StateBefore = mLastState;
|
||||||
|
barrier->Transition.StateAfter = newState;
|
||||||
|
barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Texture::DestroyImpl() {
|
void Texture::DestroyImpl() {
|
||||||
// If we own the resource, release it.
|
// If we own the resource, release it.
|
||||||
ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource);
|
ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource);
|
||||||
|
@ -195,6 +219,10 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Texture::SetUsage(dawn::TextureUsageBit newUsage) {
|
||||||
|
mLastState = D3D12TextureUsage(newUsage, GetFormat());
|
||||||
|
}
|
||||||
|
|
||||||
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
dawn::TextureUsageBit usage) {
|
dawn::TextureUsageBit usage) {
|
||||||
TransitionUsageNow(commandList, D3D12TextureUsage(usage, GetFormat()));
|
TransitionUsageNow(commandList, D3D12TextureUsage(usage, GetFormat()));
|
||||||
|
@ -202,21 +230,10 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
D3D12_RESOURCE_STATES newState) {
|
D3D12_RESOURCE_STATES newState) {
|
||||||
// Avoid transitioning the texture when it isn't needed.
|
|
||||||
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
|
||||||
if (mLastState == newState) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
if (CreateD3D12ResourceBarrierIfNeeded(&barrier, newState)) {
|
||||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
||||||
barrier.Transition.pResource = mResourcePtr;
|
|
||||||
barrier.Transition.StateBefore = mLastState;
|
|
||||||
barrier.Transition.StateAfter = newState;
|
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
||||||
|
|
||||||
commandList->ResourceBarrier(1, &barrier);
|
commandList->ResourceBarrier(1, &barrier);
|
||||||
|
}
|
||||||
|
|
||||||
mLastState = newState;
|
mLastState = newState;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,13 @@ namespace dawn_native { namespace d3d12 {
|
||||||
Texture(Device* device, const TextureDescriptor* descriptor, ID3D12Resource* nativeTexture);
|
Texture(Device* device, const TextureDescriptor* descriptor, ID3D12Resource* nativeTexture);
|
||||||
~Texture();
|
~Texture();
|
||||||
|
|
||||||
|
bool CreateD3D12ResourceBarrierIfNeeded(D3D12_RESOURCE_BARRIER* barrier,
|
||||||
|
dawn::TextureUsageBit newUsage) const;
|
||||||
|
bool CreateD3D12ResourceBarrierIfNeeded(D3D12_RESOURCE_BARRIER* barrier,
|
||||||
|
D3D12_RESOURCE_STATES newState) const;
|
||||||
DXGI_FORMAT GetD3D12Format() const;
|
DXGI_FORMAT GetD3D12Format() const;
|
||||||
ID3D12Resource* GetD3D12Resource() const;
|
ID3D12Resource* GetD3D12Resource() const;
|
||||||
|
void SetUsage(dawn::TextureUsageBit newUsage);
|
||||||
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
dawn::TextureUsageBit usage);
|
dawn::TextureUsageBit usage);
|
||||||
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
|
|
Loading…
Reference in New Issue