Implement texture subresource on D3D12
When we use a texture for different purpose, we need to add proper
barrier(s) in order to make it ready. Previously, the barrier is
done per entire texture. So it is invalid to sample/read/copy from
one subresource (say a mip/array slice) and render/write/copy to
another subresource of the same texture at the same time.
With this patch, barrier is set per each texture subresource. So it is
valid to use a subresource as source and use another subresource of the
same texture as destination at the same time.
However, planar slices like depth/stencil planes are not handled
gracefully. This is a TODO task. Another task is to combine barriers
into one if they can be combined. I will do this optimization in
another patch in near future.
Bug: dawn:157
Change-Id: I783a76cb88fcdffb60c307ddfb89d50f1583201a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22101
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 2321a4c..86254d7 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -169,20 +169,26 @@
wgpu::BufferUsage::Storage);
break;
- case wgpu::BindingType::ReadonlyStorageTexture:
- ToBackend(static_cast<TextureView*>(mBindings[index][binding])
- ->GetTexture())
- ->TrackUsageAndTransitionNow(commandContext,
- kReadonlyStorageTexture);
+ case wgpu::BindingType::ReadonlyStorageTexture: {
+ TextureViewBase* view =
+ static_cast<TextureViewBase*>(mBindings[index][binding]);
+ ToBackend(view->GetTexture())
+ ->TrackUsageAndTransitionNow(
+ commandContext, kReadonlyStorageTexture,
+ view->GetBaseMipLevel(), view->GetLevelCount(),
+ view->GetBaseArrayLayer(), view->GetLayerCount());
break;
-
- case wgpu::BindingType::WriteonlyStorageTexture:
- ToBackend(static_cast<TextureView*>(mBindings[index][binding])
- ->GetTexture())
- ->TrackUsageAndTransitionNow(commandContext,
- wgpu::TextureUsage::Storage);
+ }
+ case wgpu::BindingType::WriteonlyStorageTexture: {
+ TextureViewBase* view =
+ static_cast<TextureViewBase*>(mBindings[index][binding]);
+ ToBackend(view->GetTexture())
+ ->TrackUsageAndTransitionNow(
+ commandContext, wgpu::TextureUsage::Storage,
+ view->GetBaseMipLevel(), view->GetLevelCount(),
+ view->GetBaseArrayLayer(), view->GetLayerCount());
break;
-
+ }
case wgpu::BindingType::StorageTexture:
// Not implemented.
@@ -434,15 +440,19 @@
continue;
}
- Texture* colorTexture =
- ToBackend(renderPass->colorAttachments[i].view->GetTexture());
+ TextureViewBase* colorView = renderPass->colorAttachments[i].view.Get();
+ Texture* colorTexture = ToBackend(colorView->GetTexture());
Texture* resolveTexture = ToBackend(resolveTarget->GetTexture());
// Transition the usages of the color attachment and resolve target.
- colorTexture->TrackUsageAndTransitionNow(commandContext,
- D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
- resolveTexture->TrackUsageAndTransitionNow(commandContext,
- D3D12_RESOURCE_STATE_RESOLVE_DEST);
+ colorTexture->TrackUsageAndTransitionNow(
+ commandContext, D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
+ colorView->GetBaseMipLevel(), colorView->GetLevelCount(),
+ colorView->GetBaseArrayLayer(), colorView->GetLayerCount());
+ resolveTexture->TrackUsageAndTransitionNow(
+ commandContext, D3D12_RESOURCE_STATE_RESOLVE_DEST,
+ resolveTarget->GetBaseMipLevel(), resolveTarget->GetLevelCount(),
+ resolveTarget->GetBaseArrayLayer(), resolveTarget->GetLayerCount());
// Do MSAA resolve with ResolveSubResource().
ID3D12Resource* colorTextureHandle = colorTexture->GetD3D12Resource();
@@ -510,12 +520,9 @@
wgpu::TextureUsage textureUsages = wgpu::TextureUsage::None;
for (size_t i = 0; i < usages.textures.size(); ++i) {
- D3D12_RESOURCE_BARRIER barrier;
- if (ToBackend(usages.textures[i])
- ->TrackUsageAndGetResourceBarrier(commandContext, &barrier,
- usages.textureUsages[i].usage)) {
- barriers.push_back(barrier);
- }
+ ToBackend(usages.textures[i])
+ ->TrackUsageAndGetResourceBarrierForPass(
+ commandContext, &barriers, usages.textureUsages[i].subresourceUsages);
textureUsages |= usages.textureUsages[i].usage;
}
@@ -593,8 +600,9 @@
}
buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopySrc);
- texture->TrackUsageAndTransitionNow(commandContext,
- wgpu::TextureUsage::CopyDst);
+ texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopyDst,
+ copy->destination.mipLevel, 1,
+ copy->destination.arrayLayer, 1);
auto copySplit = ComputeTextureCopySplit(
copy->destination.origin, copy->copySize, texture->GetFormat(),
@@ -629,8 +637,9 @@
texture->EnsureSubresourceContentInitialized(
commandContext, copy->source.mipLevel, 1, copy->source.arrayLayer, 1);
- texture->TrackUsageAndTransitionNow(commandContext,
- wgpu::TextureUsage::CopySrc);
+ texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopySrc,
+ copy->source.mipLevel, 1,
+ copy->source.arrayLayer, 1);
buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopyDst);
TextureCopySplit copySplit = ComputeTextureCopySplit(
@@ -680,9 +689,12 @@
commandContext, copy->destination.mipLevel, 1,
copy->destination.arrayLayer, copy->copySize.depth);
}
- source->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopySrc);
- destination->TrackUsageAndTransitionNow(commandContext,
- wgpu::TextureUsage::CopyDst);
+ source->TrackUsageAndTransitionNow(
+ commandContext, wgpu::TextureUsage::CopySrc, copy->source.mipLevel, 1,
+ copy->source.arrayLayer, copy->copySize.depth);
+ destination->TrackUsageAndTransitionNow(
+ commandContext, wgpu::TextureUsage::CopyDst, copy->destination.mipLevel, 1,
+ copy->destination.arrayLayer, copy->copySize.depth);
if (CanUseCopyResource(source, destination, copy->copySize)) {
commandList->CopyResource(destination->GetD3D12Resource(),
@@ -870,7 +882,11 @@
ToBackend(resolveDestinationView->GetTexture());
resolveDestinationTexture->TrackUsageAndTransitionNow(
- commandContext, D3D12_RESOURCE_STATE_RESOLVE_DEST);
+ commandContext, D3D12_RESOURCE_STATE_RESOLVE_DEST,
+ resolveDestinationView->GetBaseMipLevel(),
+ resolveDestinationView->GetLevelCount(),
+ resolveDestinationView->GetBaseArrayLayer(),
+ resolveDestinationView->GetLayerCount());
renderPassBuilder->SetRenderTargetEndingAccessResolve(i, attachmentInfo.storeOp,
view, resolveDestinationView);
diff --git a/src/dawn_native/d3d12/CommandRecordingContext.cpp b/src/dawn_native/d3d12/CommandRecordingContext.cpp
index 81dad3c..d652d87 100644
--- a/src/dawn_native/d3d12/CommandRecordingContext.cpp
+++ b/src/dawn_native/d3d12/CommandRecordingContext.cpp
@@ -61,7 +61,7 @@
// common state right before command list submission. TransitionUsageNow itself ensures
// no unnecessary transitions happen if the resources is already in the common state.
for (Texture* texture : mSharedTextures) {
- texture->TrackUsageAndTransitionNow(this, D3D12_RESOURCE_STATE_COMMON);
+ texture->TrackAllUsageAndTransitionNow(this, D3D12_RESOURCE_STATE_COMMON);
}
MaybeError error =
diff --git a/src/dawn_native/d3d12/SwapChainD3D12.cpp b/src/dawn_native/d3d12/SwapChainD3D12.cpp
index 45ec25b..ee5e9cc 100644
--- a/src/dawn_native/d3d12/SwapChainD3D12.cpp
+++ b/src/dawn_native/d3d12/SwapChainD3D12.cpp
@@ -55,7 +55,7 @@
DAWN_TRY_ASSIGN(commandContext, device->GetPendingCommandContext());
// Perform the necessary transition for the texture to be presented.
- ToBackend(texture)->TrackUsageAndTransitionNow(commandContext, mTextureUsage);
+ ToBackend(texture)->TrackAllUsageAndTransitionNow(commandContext, mTextureUsage);
DAWN_TRY(device->ExecutePendingCommandContext());
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 77966b4..78bf027 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -486,10 +486,17 @@
return {};
}
+ Texture::Texture(Device* device, const TextureDescriptor* descriptor, TextureState state)
+ : TextureBase(device, descriptor, state),
+ mSubresourceStateAndDecay(
+ GetSubresourceCount(),
+ {D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON, UINT64_MAX, false}) {
+ }
+
Texture::Texture(Device* device,
const TextureDescriptor* descriptor,
ComPtr<ID3D12Resource> nativeTexture)
- : TextureBase(device, descriptor, TextureState::OwnedExternal) {
+ : Texture(device, descriptor, TextureState::OwnedExternal) {
AllocationInfo info;
info.mMethod = AllocationMethod::kExternal;
// When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the
@@ -546,126 +553,185 @@
}
}
- // When true is returned, a D3D12_RESOURCE_BARRIER has been created and must be used in a
- // ResourceBarrier call. Failing to do so will cause the tracked state to become invalid and can
- // cause subsequent errors.
- bool Texture::TrackUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_BARRIER* barrier,
- wgpu::TextureUsage newUsage) {
- return TrackUsageAndGetResourceBarrier(commandContext, barrier,
- D3D12TextureUsage(newUsage, GetFormat()));
+ void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
+ wgpu::TextureUsage usage,
+ uint32_t mipLevel,
+ uint32_t levelCount,
+ uint32_t arrayLayer,
+ uint32_t layerCount) {
+ TrackUsageAndTransitionNow(commandContext, D3D12TextureUsage(usage, GetFormat()), mipLevel,
+ levelCount, arrayLayer, layerCount);
}
- // When true is returned, a D3D12_RESOURCE_BARRIER has been created and must be used in a
- // ResourceBarrier call. Failing to do so will cause the tracked state to become invalid and can
- // cause subsequent errors.
- bool Texture::TrackUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_BARRIER* barrier,
- D3D12_RESOURCE_STATES newState) {
+ void Texture::TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext,
+ wgpu::TextureUsage usage) {
+ TrackUsageAndTransitionNow(commandContext, D3D12TextureUsage(usage, GetFormat()), 0,
+ GetNumMipLevels(), 0, GetArrayLayers());
+ }
+
+ void Texture::TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext,
+ D3D12_RESOURCE_STATES newState) {
+ TrackUsageAndTransitionNow(commandContext, newState, 0, GetNumMipLevels(), 0,
+ GetArrayLayers());
+ }
+
+ void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
+ D3D12_RESOURCE_STATES newState,
+ uint32_t baseMipLevel,
+ uint32_t levelCount,
+ uint32_t baseArrayLayer,
+ uint32_t layerCount) {
if (mResourceAllocation.GetInfo().mMethod != AllocationMethod::kExternal) {
// Track the underlying heap to ensure residency.
Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap());
commandContext->TrackHeapUsage(heap, GetDevice()->GetPendingCommandSerial());
}
- // Return the resource barrier.
- return TransitionUsageAndGetResourceBarrier(commandContext, barrier, newState);
- }
+ std::vector<D3D12_RESOURCE_BARRIER> barriers;
+ barriers.reserve(levelCount * layerCount);
- void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
- wgpu::TextureUsage usage) {
- D3D12_RESOURCE_BARRIER barrier;
-
- if (TrackUsageAndGetResourceBarrier(commandContext, &barrier, usage)) {
- commandContext->GetCommandList()->ResourceBarrier(1, &barrier);
+ TransitionUsageAndGetResourceBarrier(commandContext, &barriers, newState, baseMipLevel,
+ levelCount, baseArrayLayer, layerCount);
+ if (barriers.size()) {
+ commandContext->GetCommandList()->ResourceBarrier(barriers.size(), barriers.data());
}
}
- void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_STATES newState) {
- D3D12_RESOURCE_BARRIER barrier;
-
- if (TrackUsageAndGetResourceBarrier(commandContext, &barrier, newState)) {
- commandContext->GetCommandList()->ResourceBarrier(1, &barrier);
+ void Texture::TransitionSingleSubresource(std::vector<D3D12_RESOURCE_BARRIER>* barriers,
+ D3D12_RESOURCE_STATES newState,
+ uint32_t index,
+ const Serial pendingCommandSerial) {
+ StateAndDecay* state = &mSubresourceStateAndDecay[index];
+ // Avoid transitioning the texture when it isn't needed.
+ // TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
+ if (state->lastState == newState) {
+ return;
}
+
+ D3D12_RESOURCE_STATES lastState = state->lastState;
+
+ // The COMMON state represents a state where no write operations can be pending, and
+ // where all pixels are uncompressed. This makes it possible to transition to and
+ // from some states without synchronization (i.e. without an explicit
+ // ResourceBarrier call). Textures can be implicitly promoted to 1) a single write
+ // state, or 2) multiple read states. Textures will implicitly decay to the COMMON
+ // state when all of the following are true: 1) the texture is accessed on a command
+ // list, 2) the ExecuteCommandLists call that uses that command list has ended, and
+ // 3) the texture was promoted implicitly to a read-only state and is still in that
+ // state.
+ // https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#implicit-state-transitions
+
+ // To track implicit decays, we must record the pending serial on which that
+ // transition will occur. When that texture is used again, the previously recorded
+ // serial must be compared to the last completed serial to determine if the texture
+ // has implicity decayed to the common state.
+ if (state->isValidToDecay && pendingCommandSerial > state->lastDecaySerial) {
+ lastState = D3D12_RESOURCE_STATE_COMMON;
+ }
+
+ // Update the tracked state.
+ state->lastState = newState;
+
+ // Destination states that qualify for an implicit promotion for a
+ // non-simultaneous-access texture: NON_PIXEL_SHADER_RESOURCE,
+ // PIXEL_SHADER_RESOURCE, COPY_SRC, COPY_DEST.
+ {
+ static constexpr D3D12_RESOURCE_STATES kD3D12PromotableReadOnlyStates =
+ D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
+ D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+
+ if (lastState == D3D12_RESOURCE_STATE_COMMON) {
+ if (newState == (newState & kD3D12PromotableReadOnlyStates)) {
+ // Implicit texture state decays can only occur when the texture was implicitly
+ // transitioned to a read-only state. isValidToDecay is needed to differentiate
+ // between resources that were implictly or explicitly transitioned to a
+ // read-only state.
+ state->isValidToDecay = true;
+ state->lastDecaySerial = pendingCommandSerial;
+ return;
+ } else if (newState == D3D12_RESOURCE_STATE_COPY_DEST) {
+ state->isValidToDecay = false;
+ return;
+ }
+ }
+ }
+
+ D3D12_RESOURCE_BARRIER barrier;
+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ barrier.Transition.pResource = GetD3D12Resource();
+ barrier.Transition.StateBefore = lastState;
+ barrier.Transition.StateAfter = newState;
+ barrier.Transition.Subresource = index;
+ barriers->push_back(barrier);
+ // TODO(yunchao.he@intel.com): support subresource for depth/stencil. Depth stencil
+ // texture has different plane slices. While the current implementation only has differernt
+ // mip slices and array slices for subresources.
+ // This is a hack because Dawn doesn't handle subresource of multiplanar resources
+ // correctly. We force the transition to be the same for all planes to match what the
+ // frontend validation checks for. This hack might be incorrect for stencil-only texture
+ // because we always set transition barrier for depth plane.
+ if (newState == D3D12_RESOURCE_STATE_DEPTH_WRITE && GetFormat().HasStencil()) {
+ D3D12_RESOURCE_BARRIER barrierStencil = barrier;
+ barrierStencil.Transition.Subresource += GetArrayLayers() * GetNumMipLevels();
+ barriers->push_back(barrierStencil);
+ }
+
+ state->isValidToDecay = false;
}
- // When true is returned, a D3D12_RESOURCE_BARRIER has been created and must be used in a
- // ResourceBarrier call. Failing to do so will cause the tracked state to become invalid and can
- // cause subsequent errors.
- bool Texture::TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_BARRIER* barrier,
- D3D12_RESOURCE_STATES newState) {
+ void Texture::HandleTransitionSpecialCases(CommandRecordingContext* commandContext) {
// Textures with keyed mutexes can be written from other graphics queues. Hence, they
// must be acquired before command list submission to ensure work from the other queues
// has finished. See Device::ExecuteCommandContext.
if (mDxgiKeyedMutex != nullptr) {
commandContext->AddToSharedTextureList(this);
}
+ }
- // 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;
- }
+ void Texture::TransitionUsageAndGetResourceBarrier(
+ CommandRecordingContext* commandContext,
+ std::vector<D3D12_RESOURCE_BARRIER>* barriers,
+ D3D12_RESOURCE_STATES newState,
+ uint32_t baseMipLevel,
+ uint32_t levelCount,
+ uint32_t baseArrayLayer,
+ uint32_t layerCount) {
+ HandleTransitionSpecialCases(commandContext);
- D3D12_RESOURCE_STATES lastState = mLastState;
-
- // The COMMON state represents a state where no write operations can be pending, and where
- // all pixels are uncompressed. This makes it possible to transition to and from some states
- // without synchronization (i.e. without an explicit ResourceBarrier call). Textures can be
- // implicitly promoted to 1) a single write state, or 2) multiple read states. Textures will
- // implicitly decay to the COMMON state when all of the following are true: 1) the texture
- // is accessed on a command list, 2) the ExecuteCommandLists call that uses that command
- // list has ended, and 3) the texture was promoted implicitly to a read-only state and is
- // still in that state.
- // https://docs.microsoft.com/en-us/windows/desktop/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#implicit-state-transitions
-
- // To track implicit decays, we must record the pending serial on which that transition will
- // occur. When that texture is used again, the previously recorded serial must be compared
- // to the last completed serial to determine if the texture has implicity decayed to the
- // common state.
const Serial pendingCommandSerial = ToBackend(GetDevice())->GetPendingCommandSerial();
- if (mValidToDecay && pendingCommandSerial > mLastUsedSerial) {
- lastState = D3D12_RESOURCE_STATE_COMMON;
- }
+ for (uint32_t arrayLayer = 0; arrayLayer < layerCount; ++arrayLayer) {
+ for (uint32_t mipLevel = 0; mipLevel < levelCount; ++mipLevel) {
+ uint32_t index =
+ GetSubresourceIndex(baseMipLevel + mipLevel, baseArrayLayer + arrayLayer);
- // Update the tracked state.
- mLastState = newState;
-
- // Destination states that qualify for an implicit promotion for a non-simultaneous-access
- // texture: NON_PIXEL_SHADER_RESOURCE, PIXEL_SHADER_RESOURCE, COPY_SRC, COPY_DEST.
- {
- static constexpr D3D12_RESOURCE_STATES kD3D12TextureReadOnlyStates =
- D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
- D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
-
- if (lastState == D3D12_RESOURCE_STATE_COMMON) {
- if (newState == (newState & kD3D12TextureReadOnlyStates)) {
- // Implicit texture state decays can only occur when the texture was implicitly
- // transitioned to a read-only state. mValidToDecay is needed to differentiate
- // between resources that were implictly or explicitly transitioned to a
- // read-only state.
- mValidToDecay = true;
- mLastUsedSerial = pendingCommandSerial;
- return false;
- } else if (newState == D3D12_RESOURCE_STATE_COPY_DEST) {
- mValidToDecay = false;
- return false;
- }
+ TransitionSingleSubresource(barriers, newState, index, pendingCommandSerial);
}
}
+ }
- barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
- barrier->Transition.pResource = GetD3D12Resource();
- barrier->Transition.StateBefore = lastState;
- barrier->Transition.StateAfter = newState;
- barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ void Texture::TrackUsageAndGetResourceBarrierForPass(
+ CommandRecordingContext* commandContext,
+ std::vector<D3D12_RESOURCE_BARRIER>* barriers,
+ const std::vector<wgpu::TextureUsage>& subresourceUsages) {
+ HandleTransitionSpecialCases(commandContext);
- mValidToDecay = false;
+ const Serial pendingCommandSerial = ToBackend(GetDevice())->GetPendingCommandSerial();
+ for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) {
+ for (uint32_t mipLevel = 0; mipLevel < GetNumMipLevels(); ++mipLevel) {
+ uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer);
- return true;
+ // Skip if this subresource is not used during the current pass
+ if (subresourceUsages[index] == wgpu::TextureUsage::None) {
+ continue;
+ }
+
+ D3D12_RESOURCE_STATES newState =
+ D3D12TextureUsage(subresourceUsages[index], GetFormat());
+
+ TransitionSingleSubresource(barriers, newState, index, pendingCommandSerial);
+ }
+ }
}
D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(uint32_t mipLevel,
@@ -741,7 +807,8 @@
if (GetFormat().isRenderable) {
if (GetFormat().HasDepthOrStencil()) {
- TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE);
+ TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE,
+ baseMipLevel, levelCount, baseArrayLayer, layerCount);
D3D12_CLEAR_FLAGS clearFlags = {};
@@ -775,7 +842,8 @@
}
}
} else {
- TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET);
+ TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET,
+ baseMipLevel, levelCount, baseArrayLayer, layerCount);
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor,
fClearColor};
@@ -818,7 +886,8 @@
uploader->Allocate(bufferSize, device->GetPendingCommandSerial()));
memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
- TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST);
+ TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST, baseMipLevel,
+ levelCount, baseArrayLayer, layerCount);
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
// compute d3d12 texture copy locations for texture and buffer
diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h
index 45443c1..c8c7f5a 100644
--- a/src/dawn_native/d3d12/TextureD3D12.h
+++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -60,15 +60,29 @@
uint32_t baseArrayLayer,
uint32_t layerCount);
- bool TrackUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_BARRIER* barrier,
- wgpu::TextureUsage newUsage);
+ void TrackUsageAndGetResourceBarrierForPass(
+ CommandRecordingContext* commandContext,
+ std::vector<D3D12_RESOURCE_BARRIER>* barrier,
+ const std::vector<wgpu::TextureUsage>& subresourceUsages);
void TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
- wgpu::TextureUsage usage);
+ wgpu::TextureUsage usage,
+ uint32_t baseMipLevel,
+ uint32_t levelCount,
+ uint32_t baseArrayLayer,
+ uint32_t layerCount);
void TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_STATES newState);
+ D3D12_RESOURCE_STATES newState,
+ uint32_t baseMipLevel,
+ uint32_t levelCount,
+ uint32_t baseArrayLayer,
+ uint32_t layerCount);
+ void TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext,
+ wgpu::TextureUsage usage);
+ void TrackAllUsageAndTransitionNow(CommandRecordingContext* commandContext,
+ D3D12_RESOURCE_STATES newState);
private:
+ Texture(Device* device, const TextureDescriptor* descriptor, TextureState state);
~Texture() override;
using TextureBase::TextureBase;
@@ -89,18 +103,28 @@
UINT16 GetDepthOrArraySize();
- bool TrackUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_BARRIER* barrier,
- D3D12_RESOURCE_STATES newState);
- bool TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
- D3D12_RESOURCE_BARRIER* barrier,
- D3D12_RESOURCE_STATES newState);
+ void TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
+ std::vector<D3D12_RESOURCE_BARRIER>* barrier,
+ D3D12_RESOURCE_STATES newState,
+ uint32_t baseMipLevel,
+ uint32_t levelCount,
+ uint32_t baseArrayLayer,
+ uint32_t layerCount);
+
+ void TransitionSingleSubresource(std::vector<D3D12_RESOURCE_BARRIER>* barriers,
+ D3D12_RESOURCE_STATES subresourceNewState,
+ uint32_t index,
+ const Serial pendingCommandSerial);
+ void HandleTransitionSpecialCases(CommandRecordingContext* commandContext);
+
+ struct StateAndDecay {
+ D3D12_RESOURCE_STATES lastState;
+ Serial lastDecaySerial;
+ bool isValidToDecay;
+ };
+ std::vector<StateAndDecay> mSubresourceStateAndDecay;
ResourceHeapAllocation mResourceAllocation;
- D3D12_RESOURCE_STATES mLastState = D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON;
-
- Serial mLastUsedSerial = UINT64_MAX;
- bool mValidToDecay = false;
bool mSwapChainTexture = false;
Serial mAcquireMutexKey = 0;
diff --git a/src/tests/end2end/TextureSubresourceTests.cpp b/src/tests/end2end/TextureSubresourceTests.cpp
index 03dd486..29411de 100644
--- a/src/tests/end2end/TextureSubresourceTests.cpp
+++ b/src/tests/end2end/TextureSubresourceTests.cpp
@@ -196,4 +196,8 @@
//
// * add tests for clear operation upon texture subresource if needed
-DAWN_INSTANTIATE_TEST(TextureSubresourceTest, MetalBackend(), OpenGLBackend(), VulkanBackend());
+DAWN_INSTANTIATE_TEST(TextureSubresourceTest,
+ D3D12Backend(),
+ MetalBackend(),
+ OpenGLBackend(),
+ VulkanBackend());