Fix D3D12 over-eager lazy zero initialization for textures

Bug: dawn:145, dawn:348
Change-Id: Iafa1644424e67020b004765a0c9ccff2e077ead3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16980
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng 2020-03-16 17:48:26 +00:00 committed by Commit Bot service account
parent 022952303c
commit c7e16e351f
4 changed files with 85 additions and 49 deletions

View File

@ -538,7 +538,7 @@ namespace dawn_native { namespace d3d12 {
return true; return true;
} }
D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(uint32_t baseMipLevel, D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(uint32_t mipLevel,
uint32_t baseArrayLayer, uint32_t baseArrayLayer,
uint32_t layerCount) const { uint32_t layerCount) const {
ASSERT(GetDimension() == wgpu::TextureDimension::e2D); ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
@ -548,7 +548,7 @@ namespace dawn_native { namespace d3d12 {
ASSERT(GetNumMipLevels() == 1); ASSERT(GetNumMipLevels() == 1);
ASSERT(layerCount == 1); ASSERT(layerCount == 1);
ASSERT(baseArrayLayer == 0); ASSERT(baseArrayLayer == 0);
ASSERT(baseMipLevel == 0); ASSERT(mipLevel == 0);
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
} else { } else {
// Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array
@ -560,23 +560,30 @@ namespace dawn_native { namespace d3d12 {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.FirstArraySlice = baseArrayLayer; rtvDesc.Texture2DArray.FirstArraySlice = baseArrayLayer;
rtvDesc.Texture2DArray.ArraySize = layerCount; rtvDesc.Texture2DArray.ArraySize = layerCount;
rtvDesc.Texture2DArray.MipSlice = baseMipLevel; rtvDesc.Texture2DArray.MipSlice = mipLevel;
rtvDesc.Texture2DArray.PlaneSlice = 0; rtvDesc.Texture2DArray.PlaneSlice = 0;
} }
return rtvDesc; return rtvDesc;
} }
D3D12_DEPTH_STENCIL_VIEW_DESC Texture::GetDSVDescriptor(uint32_t baseMipLevel) const { D3D12_DEPTH_STENCIL_VIEW_DESC Texture::GetDSVDescriptor(uint32_t mipLevel,
uint32_t baseArrayLayer,
uint32_t layerCount) const {
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Format = GetD3D12Format(); dsvDesc.Format = GetD3D12Format();
dsvDesc.Flags = D3D12_DSV_FLAG_NONE; dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
ASSERT(baseMipLevel == 0);
if (IsMultisampledTexture()) { if (IsMultisampledTexture()) {
ASSERT(GetNumMipLevels() == 1);
ASSERT(layerCount == 1);
ASSERT(baseArrayLayer == 0);
ASSERT(mipLevel == 0);
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
} else { } else {
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
dsvDesc.Texture2D.MipSlice = baseMipLevel; dsvDesc.Texture2DArray.FirstArraySlice = baseArrayLayer;
dsvDesc.Texture2DArray.ArraySize = layerCount;
dsvDesc.Texture2DArray.MipSlice = mipLevel;
} }
return dsvDesc; return dsvDesc;
@ -606,15 +613,26 @@ namespace dawn_native { namespace d3d12 {
if (GetFormat().isRenderable) { if (GetFormat().isRenderable) {
if (GetFormat().HasDepthOrStencil()) { if (GetFormat().HasDepthOrStencil()) {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE); TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE);
D3D12_CLEAR_FLAGS clearFlags = {};
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount;
++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(level, 1, layer, 1)) {
// Skip lazy clears if already initialized.
continue;
}
DescriptorHeapHandle dsvHeap; DescriptorHeapHandle dsvHeap;
DAWN_TRY_ASSIGN(dsvHeap, descriptorHeapAllocator->AllocateCPUHeap( DAWN_TRY_ASSIGN(dsvHeap, descriptorHeapAllocator->AllocateCPUHeap(
D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1)); D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1));
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0); D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0);
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(baseMipLevel); D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(level, layer, 1);
device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(), &dsvDesc, device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(),
dsvHandle); &dsvDesc, dsvHandle);
D3D12_CLEAR_FLAGS clearFlags = {};
if (GetFormat().HasDepth()) { if (GetFormat().HasDepth()) {
clearFlags |= D3D12_CLEAR_FLAG_DEPTH; clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
} }
@ -622,26 +640,37 @@ namespace dawn_native { namespace d3d12 {
clearFlags |= D3D12_CLEAR_FLAG_STENCIL; clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
} }
commandList->ClearDepthStencilView(dsvHandle, clearFlags, fClearColor, clearColor, commandList->ClearDepthStencilView(dsvHandle, clearFlags, fClearColor,
0, nullptr); clearColor, 0, nullptr);
}
}
} else { } else {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET); TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET);
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor,
fClearColor};
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount;
++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(level, 1, layer, 1)) {
// Skip lazy clears if already initialized.
continue;
}
DescriptorHeapHandle rtvHeap; DescriptorHeapHandle rtvHeap;
DAWN_TRY_ASSIGN(rtvHeap, descriptorHeapAllocator->AllocateCPUHeap( DAWN_TRY_ASSIGN(rtvHeap, descriptorHeapAllocator->AllocateCPUHeap(
D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1)); D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1));
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(0); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(0);
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor,
fClearColor};
// TODO(natlee@microsoft.com): clear all array layers for 2D array textures D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(level, layer, 1);
for (uint32_t i = baseMipLevel; i < baseMipLevel + levelCount; i++) { device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(),
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = &rtvDesc, rtvHandle);
GetRTVDescriptor(i, baseArrayLayer, layerCount);
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc,
rtvHandle);
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr); commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
} }
} }
}
} else { } else {
// TODO(natlee@microsoft.com): test compressed textures are cleared // TODO(natlee@microsoft.com): test compressed textures are cleared
// create temp buffer with clear color to copy to the texture image // create temp buffer with clear color to copy to the texture image
@ -661,14 +690,20 @@ namespace dawn_native { namespace d3d12 {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST); TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST);
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
// compute d3d12 texture copy locations for texture and buffer // compute d3d12 texture copy locations for texture and buffer
Extent3D copySize = {GetSize().width, GetSize().height, 1}; Extent3D copySize = GetMipLevelVirtualSize(level);
TextureCopySplit copySplit = ComputeTextureCopySplit( TextureCopySplit copySplit = ComputeTextureCopySplit(
{0, 0, 0}, copySize, GetFormat(), uploadHandle.startOffset, rowPitch, 0); {0, 0, 0}, copySize, GetFormat(), uploadHandle.startOffset, rowPitch, 0);
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount; for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount;
++layer) { ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(level, 1, layer, 1)) {
// Skip lazy clears if already initialized.
continue;
}
D3D12_TEXTURE_COPY_LOCATION textureLocation = D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(this, level, layer); ComputeTextureCopyLocationForTexture(this, level, layer);
for (uint32_t i = 0; i < copySplit.count; ++i) { for (uint32_t i = 0; i < copySplit.count; ++i) {
@ -770,11 +805,10 @@ namespace dawn_native { namespace d3d12 {
D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() const { D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() const {
// TODO(jiawei.shao@intel.com): support rendering into a layer of a texture. // TODO(jiawei.shao@intel.com): support rendering into a layer of a texture.
ASSERT(GetLayerCount() == 1);
ASSERT(GetLevelCount() == 1); ASSERT(GetLevelCount() == 1);
ASSERT(GetBaseMipLevel() == 0); uint32_t mipLevel = GetBaseMipLevel();
ASSERT(GetBaseArrayLayer() == 0); return ToBackend(GetTexture())
return ToBackend(GetTexture())->GetDSVDescriptor(GetBaseMipLevel()); ->GetDSVDescriptor(mipLevel, GetBaseArrayLayer(), GetLayerCount());
} }
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12

View File

@ -49,10 +49,12 @@ namespace dawn_native { namespace d3d12 {
DXGI_FORMAT GetD3D12Format() const; DXGI_FORMAT GetD3D12Format() const;
ID3D12Resource* GetD3D12Resource() const; ID3D12Resource* GetD3D12Resource() const;
D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(uint32_t baseMipLevel, D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(uint32_t mipLevel,
uint32_t baseArrayLayer,
uint32_t layerCount) const;
D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor(uint32_t mipLevel,
uint32_t baseArrayLayer, uint32_t baseArrayLayer,
uint32_t layerCount) const; uint32_t layerCount) const;
D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor(uint32_t baseMipLevel) const;
void EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext, void EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext,
uint32_t baseMipLevel, uint32_t baseMipLevel,
uint32_t levelCount, uint32_t levelCount,

View File

@ -195,7 +195,7 @@ TEST_P(NonzeroTextureCreationTests, NonRenderableTextureClearWithMultiArrayLayer
// Test that all subresources of a renderable texture are filled because the toggle is enabled. // Test that all subresources of a renderable texture are filled because the toggle is enabled.
TEST_P(NonzeroTextureCreationTests, AllSubresourcesFilled) { TEST_P(NonzeroTextureCreationTests, AllSubresourcesFilled) {
// TODO(crbug.com/dawn/145): Implement on other platforms. // TODO(crbug.com/dawn/145): Implement on other platforms.
DAWN_SKIP_TEST_IF(!IsMetal()); DAWN_SKIP_TEST_IF(!IsMetal() && !IsD3D12());
wgpu::TextureDescriptor baseDescriptor; wgpu::TextureDescriptor baseDescriptor;
baseDescriptor.dimension = wgpu::TextureDimension::e2D; baseDescriptor.dimension = wgpu::TextureDimension::e2D;
@ -251,7 +251,7 @@ TEST_P(NonzeroTextureCreationTests, AllSubresourcesFilled) {
// Test that all subresources of a nonrenderable texture are filled because the toggle is enabled. // Test that all subresources of a nonrenderable texture are filled because the toggle is enabled.
TEST_P(NonzeroTextureCreationTests, NonRenderableAllSubresourcesFilled) { TEST_P(NonzeroTextureCreationTests, NonRenderableAllSubresourcesFilled) {
// TODO(crbug.com/dawn/145): Implement on other platforms. // TODO(crbug.com/dawn/145): Implement on other platforms.
DAWN_SKIP_TEST_IF(!IsMetal()); DAWN_SKIP_TEST_IF(!IsMetal() && !IsD3D12());
wgpu::TextureDescriptor baseDescriptor; wgpu::TextureDescriptor baseDescriptor;
baseDescriptor.dimension = wgpu::TextureDimension::e2D; baseDescriptor.dimension = wgpu::TextureDimension::e2D;
@ -259,7 +259,7 @@ TEST_P(NonzeroTextureCreationTests, NonRenderableAllSubresourcesFilled) {
baseDescriptor.size.height = kSize; baseDescriptor.size.height = kSize;
baseDescriptor.size.depth = 1; baseDescriptor.size.depth = 1;
baseDescriptor.sampleCount = 1; baseDescriptor.sampleCount = 1;
baseDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; baseDescriptor.format = wgpu::TextureFormat::RGBA8Snorm;
baseDescriptor.mipLevelCount = 1; baseDescriptor.mipLevelCount = 1;
baseDescriptor.arrayLayerCount = 1; baseDescriptor.arrayLayerCount = 1;
baseDescriptor.usage = wgpu::TextureUsage::CopySrc; baseDescriptor.usage = wgpu::TextureUsage::CopySrc;

View File

@ -872,7 +872,7 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencilStoreOpClear) {
// uninitialized mip does not clear the initialized mip. // uninitialized mip does not clear the initialized mip.
TEST_P(TextureZeroInitTest, PreservesInitializedMip) { TEST_P(TextureZeroInitTest, PreservesInitializedMip) {
// TODO(crbug.com/dawn/145): Fix this on other backends // TODO(crbug.com/dawn/145): Fix this on other backends
DAWN_SKIP_TEST_IF(!IsMetal()); DAWN_SKIP_TEST_IF(!IsMetal() && !IsD3D12());
wgpu::TextureDescriptor sampleTextureDescriptor = CreateTextureDescriptor( wgpu::TextureDescriptor sampleTextureDescriptor = CreateTextureDescriptor(
2, 1, 2, 1,
@ -953,7 +953,7 @@ TEST_P(TextureZeroInitTest, PreservesInitializedMip) {
// the uninitialized layer does not clear the initialized layer. // the uninitialized layer does not clear the initialized layer.
TEST_P(TextureZeroInitTest, PreservesInitializedArrayLayer) { TEST_P(TextureZeroInitTest, PreservesInitializedArrayLayer) {
// TODO(crbug.com/dawn/145): Fix this on other backends // TODO(crbug.com/dawn/145): Fix this on other backends
DAWN_SKIP_TEST_IF(!IsMetal()); DAWN_SKIP_TEST_IF(!IsMetal() && !IsD3D12());
wgpu::TextureDescriptor sampleTextureDescriptor = CreateTextureDescriptor( wgpu::TextureDescriptor sampleTextureDescriptor = CreateTextureDescriptor(
1, 2, 1, 2,