DXGI Debug Device
direct3d, win10, win8Originally posted to Chuck Walbourn's Blog on MSDN,
In my original post on using the debug layer, I mentioned several tricks for getting helpful behavior out of the Direct3D SDK debug layer for your applications. This best practice is demonstrated in my Visual C++ Game templates as follows:
#ifndef NDEBUG
Microsoft::ComPtr<ID3D11Debug> d3dDebug;
hr = m_d3dDevice.As(&d3dDebug);
if (SUCCEEDED(hr))
{
ComPtr<ID3D11InfoQueue> d3dInfoQueue;
hr = d3dDebug.As(&d3dInfoQueue);
if (SUCCEEDED(hr))
{
#ifdef _DEBUG
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
#endif
D3D11_MESSAGE_ID hide [] =
{
D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
// TODO: Add more message IDs here as needed
};
D3D11_INFO_QUEUE_FILTER filter = {};
filter.DenyList.NumIDs = _countof(hide);
filter.DenyList.pIDList = hide;
d3dInfoQueue->AddStorageFilterEntries(&filter);
}
}
#endif
This snippet ensures that a common but harmless warning message is suppressed in non-Production builds, and enables ‘break on’ functionality in Debug builds if there are any serious corruption or error messages.
With the Direct3D 11.1 Runtime or later, you can also use a DXGI debug interface to track down additional leaks that are not known to your Direct3D 11 device. How this new interface is exposed, however, is a bit confusing.
For traditional Windows desktop apps, you are expected to use explicit linking. Since the DXGI debug layer is not present on end-user machines, this pattern encourages being able to handle the case of it not being present on the system. The confusing part is that the function you need, DXGIGetDebugInterface
is not defined in any header and is not present in any import library.
#include <dxgidebug.h>
#if defined(_DEBUG)
Microsoft::WRL::ComPtr<IDXGIInfoQueue> dxgiInfoQueue;
typedef HRESULT (WINAPI * LPDXGIGETDEBUGINTERFACE)(REFIID, void ** );
HMODULE dxgidebug = LoadLibraryEx( L"dxgidebug.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32 );
if ( dxgidebug )
{
auto dxgiGetDebugInterface = reinterpret_cast<LPDXGIGETDEBUGINTERFACE>(
reinterpret_cast<void*>( GetProcAddress( dxgidebug, "DXGIGetDebugInterface" ) ) );
if ( SUCCEEDED( dxgiGetDebugInterface( IID_PPV_ARGS( dxgiInfoQueue.GetAddressOf() ) ) ) )
{
dxgiInfoQueue->SetBreakOnSeverity( DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true );
dxgiInfoQueue->SetBreakOnSeverity( DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true );
}
}
#endif
One issue with this pattern is that you can’t use it for Windows Store or universal Windows apps since LoadPackagedLibrary
cannot load a system DLL as a security measure. In the DirectX 11.2 Runtime (Windows 8.1 and Windows 10), there is now a DXGIGetDebugInterface1
defined in the dxgi1_3.h
header and in the dxgi.lib
import library. This implicit linking works fine for Windows Store apps and UWP, but for desktop apps you should stick with the explicit method particularly if you need Windows 7 support as this function is not present in the 11.1 or 11.0 runtime.
#if defined(_DEBUG)
Microsoft::WRL::ComPtr<IDXGIInfoQueue> dxgiInfoQueue;
if ( SUCCEEDED( DXGIGetDebugInterface1( 0, IID_PPV_ARGS( dxgiInfoQueue.GetAddressOf() ) ) ) )
{
dxgiInfoQueue->SetBreakOnSeverity( DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true );
dxgiInfoQueue->SetBreakOnSeverity( DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true );
}
#endif
As with the Direct3D debug layer, there is a method for reporting live DXGI objects as well for tracking down resource leaks. You obtain a IDXGIDevice
instance the same was as you do a IDXGIInfoQueue
interface above, and then call ReportLiveObjects.
DXGUID: One other issue of note is that the various DXGI debug control GUIDs (i.e. DXGI_DEBUG_ALL
) are missing from DXGUID.LIB
. You have to define it yourself using INITGUID
. This is fixed for the Windows 10 SDK.
DirectX 12: Since DirectX 12 is only supported on Windows 10, you should use the DXGI debug interface obtained from CreateDXGIFactory2
using DXGI_CREATE_FACTORY_DEBUG
as the flag.
DWORD debugFactoryFlags = 0;
#if defined(_DEBUG)
// Enable the debug layer (requires the Graphics Tools "optional feature").
//
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf()))))
{
debugController->EnableDebugLayer();
}
else
{
OutputDebugStringA("WARNING: Direct3D Debug Device is not available\n");
}
ComPtr<IDXGIInfoQueue> dxgiInfoQueue;
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgiInfoQueue.GetAddressOf()))))
{
dxgiFactoryFlags = DXGI_CREATE_FACTORY_DEBUG;
dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);
dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);
}
}
#endif
ThrowIfFailed(
CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf()))
);
Related: Direct3D SDK Debug Layer Tricks, DirectX 11.1 and Windows 7 Update