Intro
I develop a lot of graphics code using Vulkan, OpenGL, D3D12 and Metal and have found the following methods to make my life easier when something doesn't render right:Enable the debug layer
Enable your API's debug output and check for runtime errors and warnings and fix them all.D3D12
ID3D12Debug* debugController;
const HRESULT dhr = D3D12GetDebugInterface( IID_PPV_ARGS( &debugController ) );
if (dhr == S_OK)
{
debugController->EnableDebugLayer();
debugController->Release();
}
... CreateDevice()...
hr = device->QueryInterface( IID_PPV_ARGS( &infoQueue ) );
infoQueue->SetBreakOnSeverity( D3D12_MESSAGE_SEVERITY_ERROR, TRUE );
OpenGL
See https://www.opengl.org/wiki/Debug_Output
Vulkan
Sidenote: On my system RenderDoc crashes if I try to attach a program that has debug layer enabled.
First you need to install LunarG Vulkan SDK from http://lunarg.com/vulkan-sdk/
I contain my debug layer code inside a namespace like this:
namespace debug
{
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback = nullptr;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback = nullptr;
PFN_vkDebugReportMessageEXT dbgBreakCallback = nullptr;
VkDebugReportCallbackEXT debugReportCallback = nullptr;
const int validationLayerCount = 9;
const char *validationLayerNames[] =
{
"VK_LAYER_GOOGLE_threading",
"VK_LAYER_LUNARG_mem_tracker",
"VK_LAYER_LUNARG_object_tracker",
"VK_LAYER_LUNARG_draw_state",
"VK_LAYER_LUNARG_param_checker",
"VK_LAYER_LUNARG_swapchain",
"VK_LAYER_LUNARG_device_limits",
"VK_LAYER_LUNARG_image",
"VK_LAYER_GOOGLE_unique_objects",
};
VkBool32 messageCallback(
VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT,
uint64_t, size_t, int32_t msgCode,
const char* pLayerPrefix, const char* pMsg,
void* )
{
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
{
ae3d::System::Print( "Vulkan error: [%s], code: %d: %s\n", pLayerPrefix, msgCode, pMsg );
}
else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
{
ae3d::System::Print( "Vulkan warning: [%s], code: %d: %s\n", pLayerPrefix, msgCode, pMsg );
}
return VK_FALSE;
}
void Setup( VkInstance instance )
{
CreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( instance, "vkCreateDebugReportCallbackEXT" );
DestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( instance, "vkDestroyDebugReportCallbackEXT" );
dbgBreakCallback = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr( instance, "vkDebugReportMessageEXT" );
VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
dbgCreateInfo.pNext = nullptr;
dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)messageCallback;
dbgCreateInfo.pUserData = nullptr;
dbgCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
VkResult err = CreateDebugReportCallback( instance, &dbgCreateInfo, nullptr, &debugReportCallback );
}
When creating Vulkan instance, I append VK_EXT_DEBUG_REPORT_EXTENSION_NAME into instanceCreateInfo.ppEnabledExtensionNames.
When creating Vulkan device, I pass validation layers like this:
deviceCreateInfo.enabledLayerCount = debug::validationLayerCount;
deviceCreateInfo.ppEnabledLayerNames = debug::validationLayerNames;
Use debug names
Debug names appear in graphics debugger tools and validation layer messages so they help you find the object.OpenGL
You'll need to make sure extension KHR_debug is available before using these functions:glObjectLabel( GL_TEXTURE, textureHandle, nameLength, name );
glObjectLabel( GL_PROGRAM, shaderHandle, nameLength, name );
glObjectLabel( GL_FRAMEBUFFER, fboHandle, nameLength, name );
etc.
D3D12
ID3D12Resource* texture = ...;texture->SetName( L"texture" );
If you need to convert a const char* into an LPCWSTR you can do it like this:
wchar_t wstr[ 128 ];
std::mbstowcs( wstr, my_string.c_str(), 128 );
texture->SetName( wstr );
Metal
Many objects have a .label property:metalTexture.label = @"texture";
Use tools
These tools can be used to verify the rendering process by inspecting textures, render targets, buffers, rasterizer state etc.RenderDoc is a good debugger for D3D11, OpenGL and Vulkan.
For D3D12 Visual Studio's own debugger is good. You can get it by installing "graphics tools" in Windows 10: Settings->System->Apps & Features -> Manage optional features
OpenGL ES and Metal users on Mac will probably use Xcode's debugger.
AMD and NVIDIA also have tools for this.
No comments:
Post a Comment