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>
This commit is contained in:
parent
c8000bb02b
commit
182af0a4c2
|
@ -169,20 +169,26 @@ namespace dawn_native { namespace d3d12 {
|
|||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
}
|
||||
|
||||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
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);
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
// 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 =
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
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());
|
||||
|
||||
|
|
|
@ -486,10 +486,17 @@ namespace dawn_native { namespace d3d12 {
|
|||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
}
|
||||
}
|
||||
} 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 @@ namespace dawn_native { namespace d3d12 {
|
|||
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
|
||||
|
|
|
@ -60,15 +60,29 @@ namespace dawn_native { namespace d3d12 {
|
|||
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 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
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;
|
||||
|
|
|
@ -196,4 +196,8 @@ TEST_P(TextureSubresourceTest, ArrayLayersTest) {
|
|||
//
|
||||
// * 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());
|
||||
|
|
Loading…
Reference in New Issue