Add nonzero_clear_resources_on_creation_for_testing toggle for d3d12

Forces texture to clear to non-zero on creation to test the logic of
lazy clearing.

Bug: dawn:145
Change-Id: Ia738bf03be29dc620caf5f6d04b57c29b6919e85
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7280
Commit-Queue: Natasha Lee <natlee@microsoft.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index a972903..058ab6c 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -47,6 +47,9 @@
                    ComPtr<ID3D12Device> d3d12Device,
                    const DeviceDescriptor* descriptor)
         : DeviceBase(adapter, descriptor), mD3d12Device(d3d12Device) {
+        if (descriptor != nullptr) {
+            ApplyToggleOverrides(descriptor);
+        }
         // Create device-global objects
         D3D12_COMMAND_QUEUE_DESC queueDesc = {};
         queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 5e9a63b..795a712 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -14,6 +14,7 @@
 
 #include "dawn_native/d3d12/TextureD3D12.h"
 
+#include "dawn_native/d3d12/DescriptorHeapAllocator.h"
 #include "dawn_native/d3d12/DeviceD3D12.h"
 #include "dawn_native/d3d12/ResourceAllocator.h"
 
@@ -138,6 +139,25 @@
                         ->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor,
                                    D3D12_RESOURCE_STATE_COMMON);
         mResourcePtr = mResource.Get();
+
+        if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
+            TransitionUsageNow(device->GetPendingCommandList(), D3D12_RESOURCE_STATE_RENDER_TARGET);
+            uint32_t arrayLayerCount = GetArrayLayers();
+
+            DescriptorHeapAllocator* descriptorHeapAllocator = device->GetDescriptorHeapAllocator();
+            DescriptorHeapHandle rtvHeap =
+                descriptorHeapAllocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1);
+            D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(0);
+
+            const float clearColor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+            // TODO(natlee@microsoft.com): clear all array layers for 2D array textures
+            for (int i = 0; i < resourceDescriptor.MipLevels; i++) {
+                D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(i, arrayLayerCount, 0);
+                device->GetD3D12Device()->CreateRenderTargetView(mResourcePtr, &rtvDesc, rtvHandle);
+                device->GetPendingCommandList()->ClearRenderTargetView(rtvHandle, clearColor, 0,
+                                                                       nullptr);
+            }
+        }
     }
 
     // With this constructor, the lifetime of the ID3D12Resource is externally managed.
@@ -201,6 +221,34 @@
         mLastState = newState;
     }
 
+    D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(uint32_t mipSlice,
+                                                            uint32_t arrayLayers,
+                                                            uint32_t baseArrayLayer) const {
+        ASSERT(GetDimension() == dawn::TextureDimension::e2D);
+        D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
+        rtvDesc.Format = GetD3D12Format();
+        if (IsMultisampledTexture()) {
+            ASSERT(GetNumMipLevels() == 1);
+            ASSERT(arrayLayers == 1);
+            ASSERT(baseArrayLayer == 0);
+            ASSERT(mipSlice == 0);
+            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
+        } else {
+            // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array
+            // layer and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as
+            // 1-layer 2D array textures. (Just like how we treat SRVs)
+            // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv
+            // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array
+            // _rtv
+            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
+            rtvDesc.Texture2DArray.FirstArraySlice = baseArrayLayer;
+            rtvDesc.Texture2DArray.ArraySize = arrayLayers;
+            rtvDesc.Texture2DArray.MipSlice = mipSlice;
+            rtvDesc.Texture2DArray.PlaneSlice = 0;
+        }
+        return rtvDesc;
+    }
+
     uint32_t Texture::GetSubresourceIndex(uint32_t mipmapLevel, uint32_t arraySlice) const {
         return GetNumMipLevels() * arraySlice + mipmapLevel;
     }
@@ -254,28 +302,8 @@
     }
 
     D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() const {
-        ASSERT(GetTexture()->GetDimension() == dawn::TextureDimension::e2D);
-        D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
-        rtvDesc.Format = GetD3D12Format();
-        if (GetTexture()->IsMultisampledTexture()) {
-            ASSERT(GetTexture()->GetArrayLayers() == 1 && GetTexture()->GetNumMipLevels() == 1 &&
-                   GetBaseArrayLayer() == 0 && GetBaseMipLevel() == 0);
-            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
-        } else {
-            // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array
-            // layer and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as
-            // 1-layer 2D array textures. (Just like how we treat SRVs)
-            // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv
-            // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array
-            // _rtv
-            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
-            rtvDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer();
-            rtvDesc.Texture2DArray.ArraySize = GetLayerCount();
-            rtvDesc.Texture2DArray.MipSlice = GetBaseMipLevel();
-            rtvDesc.Texture2DArray.PlaneSlice = 0;
-        }
-
-        return rtvDesc;
+        return ToBackend(GetTexture())
+            ->GetRTVDescriptor(GetBaseMipLevel(), GetLayerCount(), GetBaseArrayLayer());
     }
 
     D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() const {
diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h
index 33b6be3..3aea5ad 100644
--- a/src/dawn_native/d3d12/TextureD3D12.h
+++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -40,6 +40,9 @@
                                 D3D12_RESOURCE_STATES newState);
 
         uint32_t GetSubresourceIndex(uint32_t mipmapLevel, uint32_t arraySlice) const;
+        D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(uint32_t mipSlice,
+                                                       uint32_t arrayLayers,
+                                                       uint32_t baseArrayLayer) const;
 
       private:
         // Dawn API
diff --git a/src/tests/end2end/NonzeroTextureCreationTests.cpp b/src/tests/end2end/NonzeroTextureCreationTests.cpp
index 3053d13..cbb5232 100644
--- a/src/tests/end2end/NonzeroTextureCreationTests.cpp
+++ b/src/tests/end2end/NonzeroTextureCreationTests.cpp
@@ -94,8 +94,8 @@
     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, 0, 0, kSize, kSize, 0, 2);

 }

 

-DAWN_INSTANTIATE_TEST(NonzeroTextureCreationTests,

-                      ForceWorkaround(OpenGLBackend,

-                                      "nonzero_clear_resources_on_creation_for_testing"),

-                      ForceWorkaround(VulkanBackend,

-                                      "nonzero_clear_resources_on_creation_for_testing"));

+DAWN_INSTANTIATE_TEST(

+    NonzeroTextureCreationTests,

+    ForceWorkaround(D3D12Backend, "nonzero_clear_resources_on_creation_for_testing"),

+    ForceWorkaround(OpenGLBackend, "nonzero_clear_resources_on_creation_for_testing"),

+    ForceWorkaround(VulkanBackend, "nonzero_clear_resources_on_creation_for_testing"));