D3D12: Don't set D3D12_CLEAR_VALUE on depth textures on Gen12 GPUs

This patch adds a workaround for Intel Gen12 GPUs that we don't set
D3D12_CLEAR_VALUE when creating a texture with any DXGI depth formats
(DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_D32_FLOAT,
DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_D32_FLOAT_S8X24_UINT)
because on these GPUs the texture data may be corrupted after several
call of ClearDepthStencilView() if D3D12_CLEAR_VALUE is set in the
call of CreatePlacedResource() or CreateCommittedResource().

Bug: dawn:1487
Test: dawn_end2end_tests
Change-Id: Id44af0f6fe31773820f5e20d05edd275dd921e53
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96482
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Jiawei Shao 2022-07-20 02:28:34 +00:00 committed by Dawn LUCI CQ
parent aea3154e46
commit 44b0a5e9a3
5 changed files with 146 additions and 2 deletions

View File

@ -274,6 +274,11 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
"the initialization when the entire subresource is the copy destination as a workaround on "
"Intel D3D12 drivers.",
"https://crbug.com/dawn/1487"}},
{Toggle::D3D12DontSetClearValueOnDepthTextureCreation,
{"d3d12_dont_set_clear_value_on_depth_texture_creation",
"Don't set D3D12_CLEAR_VALUE when creating depth textures with CreatePlacedResource() or "
"CreateCommittedResource() as a workaround on Intel Gen12 D3D12 drivers.",
"https://crbug.com/dawn/1487"}},
// Comment to separate the }} so it is clearer what to copy-paste to add a toggle.
}};
} // anonymous namespace

View File

@ -73,6 +73,7 @@ enum class Toggle {
MetalRenderR8RG8UnormSmallMipToTempTexture,
EnableBlobCache,
D3D12ForceInitializeCopyableDepthStencilTextureOnCreation,
D3D12DontSetClearValueOnDepthTextureCreation,
EnumCount,
InvalidEnum = EnumCount,

View File

@ -661,6 +661,12 @@ void Device::InitTogglesFromDriver() {
SetToggle(Toggle::D3D12ForceInitializeCopyableDepthStencilTextureOnCreation, true);
}
// Currently this workaround is only needed on Intel Gen12 GPUs.
// See http://crbug.com/dawn/1487 for more information.
if (gpu_info::IsIntelXe(vendorId, deviceId)) {
SetToggle(Toggle::D3D12DontSetClearValueOnDepthTextureCreation, true);
}
// Currently this workaround is needed on any D3D12 backend for some particular situations.
// But we may need to limit it if D3D12 runtime fixes the bug on its new release. See
// https://crbug.com/dawn/1289 for more information.

View File

@ -152,7 +152,19 @@ uint64_t GetResourcePlacementAlignment(ResourceHeapKind resourceHeapKind,
}
}
bool IsClearValueOptimizable(const D3D12_RESOURCE_DESC& resourceDescriptor) {
bool IsClearValueOptimizable(DeviceBase* device, const D3D12_RESOURCE_DESC& resourceDescriptor) {
if (device->IsToggleEnabled(Toggle::D3D12DontSetClearValueOnDepthTextureCreation)) {
switch (resourceDescriptor.Format) {
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
return false;
default:
break;
}
}
// Optimized clear color cannot be set on buffers, non-render-target/depth-stencil
// textures, or typeless resources
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createcommittedresource
@ -192,7 +204,7 @@ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::AllocateMemory(
// some architectures.
D3D12_CLEAR_VALUE zero{};
D3D12_CLEAR_VALUE* optimizedClearValue = nullptr;
if (IsClearValueOptimizable(resourceDescriptor)) {
if (IsClearValueOptimizable(mDevice, resourceDescriptor)) {
zero.Format = resourceDescriptor.Format;
optimizedClearValue = &zero;
}

View File

@ -303,4 +303,124 @@ DAWN_INSTANTIATE_TEST_P(StencilClearValueOverflowTest,
wgpu::TextureFormat::Depth32FloatStencil8, wgpu::TextureFormat::Stencil8},
{Check::CopyStencil, Check::StencilTest});
// Regression tests to reproduce a flaky failure when running whole WebGPU CTS on Intel Gen12 GPUs.
// See crbug.com/dawn/1487 for more details.
using SupportsTextureBinding = bool;
DAWN_TEST_PARAM_STRUCT(DepthTextureClearTwiceTestParams, Format, SupportsTextureBinding);
class DepthTextureClearTwiceTest : public DawnTestWithParams<DepthTextureClearTwiceTestParams> {
public:
void RecordClearDepthAspectAtLevel(wgpu::CommandEncoder encoder,
wgpu::Texture depthTexture,
uint32_t level,
float clearValue) {
wgpu::TextureViewDescriptor viewDescriptor = {};
viewDescriptor.baseArrayLayer = 0;
viewDescriptor.arrayLayerCount = 1;
viewDescriptor.baseMipLevel = level;
viewDescriptor.mipLevelCount = 1;
wgpu::TextureView view = depthTexture.CreateView(&viewDescriptor);
wgpu::RenderPassDescriptor renderPassDescriptor = {};
renderPassDescriptor.colorAttachmentCount = 0;
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment = {};
depthStencilAttachment.view = view;
depthStencilAttachment.depthClearValue = clearValue;
depthStencilAttachment.depthLoadOp = wgpu::LoadOp::Clear;
depthStencilAttachment.depthStoreOp = wgpu::StoreOp::Store;
if (!utils::IsDepthOnlyFormat(GetParam().mFormat)) {
depthStencilAttachment.stencilLoadOp = wgpu::LoadOp::Load;
depthStencilAttachment.stencilStoreOp = wgpu::StoreOp::Store;
}
renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
renderPass.End();
}
protected:
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
switch (GetParam().mFormat) {
case wgpu::TextureFormat::Depth32FloatStencil8:
if (SupportsFeatures({wgpu::FeatureName::Depth32FloatStencil8})) {
mIsFormatSupported = true;
return {wgpu::FeatureName::Depth32FloatStencil8};
}
return {};
default:
mIsFormatSupported = true;
return {};
}
}
bool mIsFormatSupported = false;
};
TEST_P(DepthTextureClearTwiceTest, ClearDepthAspectTwice) {
DAWN_SUPPRESS_TEST_IF(!mIsFormatSupported);
constexpr uint32_t kSize = 64;
constexpr uint32_t kLevelCount = 5;
wgpu::TextureFormat depthFormat = GetParam().mFormat;
wgpu::TextureDescriptor descriptor;
descriptor.size = {kSize, kSize};
descriptor.format = depthFormat;
descriptor.mipLevelCount = kLevelCount;
// The toggle "d3d12_force_initialize_copyable_depth_stencil_texture_on_creation" is not related
// to this test as we don't specify wgpu::TextureUsage::CopyDst in the test.
descriptor.usage = wgpu::TextureUsage::RenderAttachment;
if (GetParam().mSupportsTextureBinding) {
descriptor.usage |= wgpu::TextureUsage::TextureBinding;
}
wgpu::Texture depthTexture = device.CreateTexture(&descriptor);
// First, clear all the subresources to 0.
{
constexpr float kClearValue = 0.f;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
for (uint32_t level = 0; level < kLevelCount; ++level) {
RecordClearDepthAspectAtLevel(encoder, depthTexture, level, kClearValue);
}
wgpu::CommandBuffer commandBuffer = encoder.Finish();
queue.Submit(1, &commandBuffer);
}
// Then, clear several mipmap levels to 0.8.
{
constexpr float kClearValue = 0.8f;
constexpr std::array<uint32_t, 2> kLevelsToSet = {2u, 4u};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
for (uint32_t level : kLevelsToSet) {
RecordClearDepthAspectAtLevel(encoder, depthTexture, level, kClearValue);
}
wgpu::CommandBuffer commandBuffer = encoder.Finish();
queue.Submit(1, &commandBuffer);
}
// Check if the data in remaining mipmap levels is still 0.
{
constexpr std::array<uint32_t, 3> kLevelsToTest = {0, 1u, 3u};
for (uint32_t level : kLevelsToTest) {
uint32_t sizeAtLevel = kSize >> level;
std::vector<float> expectedValue(sizeAtLevel * sizeAtLevel, 0.f);
ExpectAttachmentDepthTestData(depthTexture, GetParam().mFormat, sizeAtLevel,
sizeAtLevel, 0, level, expectedValue);
}
}
}
DAWN_INSTANTIATE_TEST_P(DepthTextureClearTwiceTest,
{D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(),
VulkanBackend()},
{wgpu::TextureFormat::Depth16Unorm, wgpu::TextureFormat::Depth24Plus,
wgpu::TextureFormat::Depth32Float,
wgpu::TextureFormat::Depth32FloatStencil8,
wgpu::TextureFormat::Depth24PlusStencil8},
{true, false});
} // namespace