D3D12: Silence known debug layer warnings
This will help remove noise in debug layer output. This patch also
promotes warnings and higher to Dawn errors.
BUG: dawn:363, dawn:418, dawn:419, dawn:421
Change-Id: I3112c94aff71fc7e76dff48c82bafe9e051ed3b4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/21702
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Bryan Bernhart <bryan.bernhart@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/d3d12/AdapterD3D12.cpp b/src/dawn_native/d3d12/AdapterD3D12.cpp
index 4124a76..b2a35cb 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.cpp
+++ b/src/dawn_native/d3d12/AdapterD3D12.cpp
@@ -15,7 +15,9 @@
#include "dawn_native/d3d12/AdapterD3D12.h"
#include "common/Constants.h"
+#include "dawn_native/Instance.h"
#include "dawn_native/d3d12/BackendD3D12.h"
+#include "dawn_native/d3d12/D3D12Error.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/PlatformFunctions.h"
@@ -40,6 +42,10 @@
mBackend(backend) {
}
+ Adapter::~Adapter() {
+ CleanUpDebugLayerFilters();
+ }
+
const D3D12DeviceInfo& Adapter::GetDeviceInfo() const {
return mDeviceInfo;
}
@@ -66,6 +72,8 @@
return DAWN_INTERNAL_ERROR("D3D12CreateDevice failed");
}
+ DAWN_TRY(InitializeDebugLayerFilters());
+
DXGI_ADAPTER_DESC1 adapterDesc;
mHardwareAdapter->GetDesc1(&adapterDesc);
@@ -96,6 +104,89 @@
mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
}
+ MaybeError Adapter::InitializeDebugLayerFilters() {
+ if (!GetInstance()->IsBackendValidationEnabled()) {
+ return {};
+ }
+ ComPtr<ID3D12InfoQueue> infoQueue;
+ ASSERT_SUCCESS(mD3d12Device.As(&infoQueue));
+ // We create storage filter with a deny list to deny specific messages from getting
+ // written to the queue. The filter will silence them in the debug output.
+ D3D12_INFO_QUEUE_FILTER storageFilter = {};
+
+ D3D12_MESSAGE_ID denyIds[] = {
+
+ //
+ // Permanent IDs: list of warnings that are not applicable
+ //
+
+ // Resource sub-allocation partially maps pre-allocated heaps. This means the
+ // entire physical addresses space may have no resources or have many resources
+ // assigned the same heap.
+ D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE,
+ D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS,
+
+ // The debug layer validates pipeline objects when they are created. Dawn validates
+ // them when them when they are set. Therefore, since the issue is caught at a later
+ // time, we can silence this warnings.
+ D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET,
+
+ // Adding a clear color during resource creation would require heuristics or delayed
+ // creation.
+ // https://crbug.com/dawn/418
+ D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
+ D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
+
+ // Dawn enforces proper Unmaps at a later time.
+ // https://crbug.com/dawn/422
+ D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_GPU_WRITTEN_READBACK_RESOURCE_MAPPED,
+
+ //
+ // Temporary IDs: list of warnings that should be fixed or promoted
+ //
+
+ // Remove after warning have been addressed
+ // https://crbug.com/dawn/419
+ D3D12_MESSAGE_ID_UNMAP_RANGE_NOT_EMPTY,
+
+ // Remove after warning have been addressed
+ // https://crbug.com/dawn/421
+ D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_INCOMPATIBLE_RESOURCE_STATE,
+ };
+
+ storageFilter.DenyList.NumIDs = ARRAYSIZE(denyIds);
+ storageFilter.DenyList.pIDList = denyIds;
+ DAWN_TRY(CheckHRESULT(infoQueue->PushStorageFilter(&storageFilter),
+ "ID3D12InfoQueue::PushStorageFilter"));
+
+ // We create a retrieval filter with an allow list to select which messages we are
+ // allowed to be read back from the queue. If any messages are read back, they are
+ // converted to Dawn errors.
+ D3D12_INFO_QUEUE_FILTER retrievalFilter{};
+ // We will only create errors from warnings or worse. This ignores info and message.
+ D3D12_MESSAGE_SEVERITY severities[] = {
+ D3D12_MESSAGE_SEVERITY_ERROR,
+ D3D12_MESSAGE_SEVERITY_WARNING,
+ D3D12_MESSAGE_SEVERITY_CORRUPTION,
+ };
+ retrievalFilter.AllowList.NumSeverities = ARRAYSIZE(severities);
+ retrievalFilter.AllowList.pSeverityList = severities;
+ DAWN_TRY(CheckHRESULT(infoQueue->PushRetrievalFilter(&retrievalFilter),
+ "ID3D12InfoQueue::PushRetrievalFilter"));
+
+ return {};
+ }
+
+ void Adapter::CleanUpDebugLayerFilters() {
+ if (!GetInstance()->IsBackendValidationEnabled()) {
+ return;
+ }
+ ComPtr<ID3D12InfoQueue> infoQueue;
+ ASSERT_SUCCESS(mD3d12Device.As(&infoQueue));
+ infoQueue->PopRetrievalFilter();
+ infoQueue->PopStorageFilter();
+ }
+
ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
return Device::Create(this, descriptor);
}
diff --git a/src/dawn_native/d3d12/AdapterD3D12.h b/src/dawn_native/d3d12/AdapterD3D12.h
index 48345c1..e0910bf 100644
--- a/src/dawn_native/d3d12/AdapterD3D12.h
+++ b/src/dawn_native/d3d12/AdapterD3D12.h
@@ -27,7 +27,7 @@
class Adapter : public AdapterBase {
public:
Adapter(Backend* backend, ComPtr<IDXGIAdapter3> hardwareAdapter);
- ~Adapter() override = default;
+ ~Adapter() override;
const D3D12DeviceInfo& GetDeviceInfo() const;
IDXGIAdapter3* GetHardwareAdapter() const;
@@ -39,6 +39,8 @@
private:
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
void InitializeSupportedExtensions();
+ MaybeError InitializeDebugLayerFilters();
+ void CleanUpDebugLayerFilters();
ComPtr<IDXGIAdapter3> mHardwareAdapter;
ComPtr<ID3D12Device> mD3d12Device;
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 7983b98..aea4aca 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -17,6 +17,7 @@
#include "common/Assert.h"
#include "dawn_native/BackendConnection.h"
#include "dawn_native/ErrorData.h"
+#include "dawn_native/Instance.h"
#include "dawn_native/d3d12/AdapterD3D12.h"
#include "dawn_native/d3d12/BackendD3D12.h"
#include "dawn_native/d3d12/BindGroupD3D12.h"
@@ -41,12 +42,16 @@
#include "dawn_native/d3d12/SwapChainD3D12.h"
#include "dawn_native/d3d12/TextureD3D12.h"
+#include <sstream>
+
namespace dawn_native { namespace d3d12 {
// TODO(dawn:155): Figure out these values.
static constexpr uint16_t kShaderVisibleDescriptorHeapSize = 1024;
static constexpr uint8_t kAttachmentDescriptorHeapSize = 64;
+ static constexpr uint64_t kMaxDebugMessagesToPrint = 5;
+
// static
ResultOrError<Device*> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) {
Ref<Device> device = AcquireRef(new Device(adapter, descriptor));
@@ -221,6 +226,9 @@
mUsedComObjectRefs.ClearUpTo(completedSerial);
DAWN_TRY(ExecutePendingCommandContext());
DAWN_TRY(NextSerial());
+
+ DAWN_TRY(CheckDebugLayerAndGenerateErrors());
+
return {};
}
@@ -460,6 +468,51 @@
return {};
}
+ MaybeError Device::CheckDebugLayerAndGenerateErrors() {
+ if (!GetAdapter()->GetInstance()->IsBackendValidationEnabled()) {
+ return {};
+ }
+
+ ComPtr<ID3D12InfoQueue> infoQueue;
+ ASSERT_SUCCESS(mD3d12Device.As(&infoQueue));
+ uint64_t totalErrors = infoQueue->GetNumStoredMessagesAllowedByRetrievalFilter();
+
+ // Check if any errors have occurred otherwise we would be creating an empty error. Note
+ // that we use GetNumStoredMessagesAllowedByRetrievalFilter instead of GetNumStoredMessages
+ // because we only convert WARNINGS or higher messages to dawn errors.
+ if (totalErrors == 0) {
+ return {};
+ }
+
+ std::ostringstream messages;
+ uint64_t errorsToPrint = std::min(kMaxDebugMessagesToPrint, totalErrors);
+ for (uint64_t i = 0; i < errorsToPrint; ++i) {
+ SIZE_T messageLength = 0;
+ HRESULT hr = infoQueue->GetMessageW(i, nullptr, &messageLength);
+ if (FAILED(hr)) {
+ messages << " ID3D12InfoQueue::GetMessageW failed with " << hr << '\n';
+ continue;
+ }
+
+ std::unique_ptr<uint8_t[]> messageData(new uint8_t[messageLength]);
+ D3D12_MESSAGE* message = reinterpret_cast<D3D12_MESSAGE*>(messageData.get());
+ hr = infoQueue->GetMessageW(i, message, &messageLength);
+ if (FAILED(hr)) {
+ messages << " ID3D12InfoQueue::GetMessageW failed with " << hr << '\n';
+ continue;
+ }
+
+ messages << message->pDescription << " (" << message->ID << ")\n";
+ }
+ if (errorsToPrint < totalErrors) {
+ messages << (totalErrors - errorsToPrint) << " messages silenced\n";
+ }
+ // We only print up to the first kMaxDebugMessagesToPrint errors
+ infoQueue->ClearStoredMessages();
+
+ return DAWN_INTERNAL_ERROR(messages.str());
+ }
+
void Device::ShutDownImpl() {
ASSERT(GetState() == State::Disconnected);
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index 5f0fafc..7ce3a95 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -156,6 +156,8 @@
void ShutDownImpl() override;
MaybeError WaitForIdleForDestruction() override;
+ MaybeError CheckDebugLayerAndGenerateErrors();
+
ComPtr<ID3D12Fence> mFence;
HANDLE mFenceEvent = nullptr;
Serial CheckAndUpdateCompletedSerials() override;