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:
Brandon Jones 2019-06-07 17:08:47 +00:00 committed by Commit Bot service account
parent 2b82eb2902
commit de1ac9fd7b
5 changed files with 91 additions and 43 deletions

View File

@ -111,6 +111,32 @@ namespace dawn_native { namespace d3d12 {
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 {
// TODO(enga@google.com): TODO investigate if this needs to be a constraint at the API level
return Align(GetSize(), 256);
@ -120,33 +146,17 @@ namespace dawn_native { namespace d3d12 {
return mResource;
}
void Buffer::SetUsage(dawn::BufferUsageBit newUsage) {
mLastUsage = newUsage;
}
void Buffer::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
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;
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);
}
mLastUsage = usage;
}

View File

@ -29,11 +29,13 @@ namespace dawn_native { namespace d3d12 {
Buffer(Device* device, const BufferDescriptor* descriptor);
~Buffer();
bool CreateD3D12ResourceBarrierIfNeeded(D3D12_RESOURCE_BARRIER* barrier,
dawn::BufferUsageBit newUsage) const;
uint32_t GetD3D12Size() const;
ComPtr<ID3D12Resource> GetD3D12Resource();
D3D12_GPU_VIRTUAL_ADDRESS GetVA() const;
void OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite);
void SetUsage(dawn::BufferUsageBit newUsage);
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
dawn::BufferUsageBit usage);

View File

@ -429,13 +429,28 @@ namespace dawn_native { namespace d3d12 {
// Records the necessary barriers for the resource usage pre-computed by the frontend
auto TransitionForPass = [](ComPtr<ID3D12GraphicsCommandList> commandList,
const PassResourceUsage& usages) {
std::vector<D3D12_RESOURCE_BARRIER> barriers;
for (size_t i = 0; i < usages.buffers.size(); ++i) {
Buffer* buffer = ToBackend(usages.buffers[i]);
buffer->TransitionUsageNow(commandList, usages.bufferUsages[i]);
D3D12_RESOURCE_BARRIER barrier;
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) {
Texture* texture = ToBackend(usages.textures[i]);
texture->TransitionUsageNow(commandList, usages.textureUsages[i]);
D3D12_RESOURCE_BARRIER barrier;
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());
}
};

View File

@ -172,6 +172,30 @@ namespace dawn_native { namespace d3d12 {
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() {
// If we own the resource, release it.
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,
dawn::TextureUsageBit usage) {
TransitionUsageNow(commandList, D3D12TextureUsage(usage, GetFormat()));
@ -202,21 +230,10 @@ namespace dawn_native { namespace d3d12 {
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
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;
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;
if (CreateD3D12ResourceBarrierIfNeeded(&barrier, newState)) {
commandList->ResourceBarrier(1, &barrier);
}
mLastState = newState;
}

View File

@ -31,9 +31,13 @@ namespace dawn_native { namespace d3d12 {
Texture(Device* device, const TextureDescriptor* descriptor, ID3D12Resource* nativeTexture);
~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;
ID3D12Resource* GetD3D12Resource() const;
void SetUsage(dawn::TextureUsageBit newUsage);
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
dawn::TextureUsageBit usage);
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,