Handle failed calls to ID3D12CommandQueue::GetTimestampFrequency

ID2D12CommandQueue::GetTimestampFrequency returns an error HRESULT
when there are bugs in Windows container and vGPU implementations.

To workaround, we check the return value during adapter creation
and disable the timestamp query extension upon failure.

Device creation is still allowed to succeed when the method returns
failure.

Change-Id: Ie71f8712fc9f4f50e4ce26ecfec929b5b1a126d4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63225
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Rafael Cintron <rafael.cintron@microsoft.com>
diff --git a/src/dawn_native/d3d12/AdapterD3D12.cpp b/src/dawn_native/d3d12/AdapterD3D12.cpp
index d26603a..7021b59 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.cpp
+++ b/src/dawn_native/d3d12/AdapterD3D12.cpp
@@ -109,10 +109,33 @@
         return {};
     }
 
+    bool Adapter::AreTimestampQueriesSupported() const {
+        D3D12_COMMAND_QUEUE_DESC queueDesc = {};
+        queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
+        queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+        ComPtr<ID3D12CommandQueue> d3d12CommandQueue;
+        HRESULT hr = mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&d3d12CommandQueue));
+        if (FAILED(hr)) {
+            return false;
+        }
+
+        // GetTimestampFrequency returns an error HRESULT when there are bugs in Windows container
+        // and vGPU implementations.
+        uint64_t timeStampFrequency;
+        hr = d3d12CommandQueue->GetTimestampFrequency(&timeStampFrequency);
+        if (FAILED(hr)) {
+            return false;
+        }
+
+        return true;
+    }
+
     void Adapter::InitializeSupportedExtensions() {
+        if (AreTimestampQueriesSupported()) {
+            mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
+        }
         mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC);
         mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
-        mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
         mSupportedExtensions.EnableExtension(Extension::MultiPlanarFormats);
     }
 
diff --git a/src/dawn_native/d3d12/AdapterD3D12.h b/src/dawn_native/d3d12/AdapterD3D12.h
index ea6975e..1e3654e 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.h
+++ b/src/dawn_native/d3d12/AdapterD3D12.h
@@ -45,6 +45,8 @@
         ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
         MaybeError ResetInternalDeviceForTestingImpl() override;
 
+        bool AreTimestampQueriesSupported() const;
+
         void InitializeSupportedExtensions();
         MaybeError InitializeDebugLayerFilters();
         void CleanUpDebugLayerFilters();
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 9964e69..7512352 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -73,14 +73,17 @@
             CheckHRESULT(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)),
                          "D3D12 create command queue"));
 
-        // Get GPU timestamp counter frequency (in ticks/second). This fails if the specified
-        // command queue doesn't support timestamps, D3D12_COMMAND_LIST_TYPE_DIRECT always support
-        // timestamps.
-        uint64_t frequency;
-        DAWN_TRY(CheckHRESULT(mCommandQueue->GetTimestampFrequency(&frequency),
-                              "D3D12 get timestamp frequency"));
-        // Calculate the period in nanoseconds by the frequency.
-        mTimestampPeriod = static_cast<float>(1e9) / frequency;
+        if (IsExtensionEnabled(Extension::TimestampQuery)) {
+            // Get GPU timestamp counter frequency (in ticks/second). This fails if the specified
+            // command queue doesn't support timestamps. D3D12_COMMAND_LIST_TYPE_DIRECT queues
+            // always support timestamps except where there are bugs in Windows container and vGPU
+            // implementations.
+            uint64_t frequency;
+            DAWN_TRY(CheckHRESULT(mCommandQueue->GetTimestampFrequency(&frequency),
+                                  "D3D12 get timestamp frequency"));
+            // Calculate the period in nanoseconds by the frequency.
+            mTimestampPeriod = static_cast<float>(1e9) / frequency;
+        }
 
         // If PIX is not attached, the QueryInterface fails. Hence, no need to check the return
         // value.