GPU: Expose debug information from devices

Co-authored-by: Nikita Kogut <glinka1202@gmail.com>
This commit is contained in:
Lucas Murray
2025-04-02 17:29:29 +11:00
committed by Sam Lantinga
parent 008690d016
commit f78aa4d8ea
9 changed files with 326 additions and 26 deletions

View File

@@ -586,6 +586,13 @@ SDL_GPUShaderFormat SDL_GetGPUShaderFormats(SDL_GPUDevice *device)
return device->shader_formats;
}
SDL_PropertiesID SDL_GetGPUDeviceDebugProperties(SDL_GPUDevice *device)
{
CHECK_DEVICE_MAGIC(device, 0);
return device->GetDeviceDebugProperties(device);
}
Uint32 SDL_GPUTextureFormatTexelBlockSize(
SDL_GPUTextureFormat format)
{

View File

@@ -459,10 +459,12 @@ typedef struct SDL_GPURenderer SDL_GPURenderer;
struct SDL_GPUDevice
{
// Quit
// Device
void (*DestroyDevice)(SDL_GPUDevice *device);
SDL_PropertiesID (*GetDeviceDebugProperties)(SDL_GPUDevice *device);
// State Creation
SDL_GPUComputePipeline *(*CreateComputePipeline)(
@@ -894,6 +896,7 @@ struct SDL_GPUDevice
result->func = name##_##func;
#define ASSIGN_DRIVER(name) \
ASSIGN_DRIVER_FUNC(DestroyDevice, name) \
ASSIGN_DRIVER_FUNC(GetDeviceDebugProperties, name) \
ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \
ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \
ASSIGN_DRIVER_FUNC(CreateSampler, name) \

View File

@@ -765,6 +765,7 @@ struct D3D12Renderer
// FIXME: these might not be necessary since we're not using custom heaps
bool UMA;
bool UMACacheCoherent;
SDL_PropertiesID debugProps;
Uint32 allowedFramesInFlight;
// Indirect command signatures
@@ -1535,6 +1536,8 @@ static void D3D12_INTERNAL_DestroyRenderer(D3D12Renderer *renderer)
SDL_free(renderer->graphicsPipelinesToDestroy);
SDL_free(renderer->computePipelinesToDestroy);
SDL_DestroyProperties(renderer->debugProps);
// Tear down D3D12 objects
if (renderer->indirectDrawCommandSignature) {
ID3D12CommandSignature_Release(renderer->indirectDrawCommandSignature);
@@ -1622,6 +1625,12 @@ static void D3D12_DestroyDevice(SDL_GPUDevice *device)
SDL_free(device);
}
static SDL_PropertiesID D3D12_GetDeviceDebugProperties(SDL_GPUDevice *device)
{
D3D12Renderer *renderer = (D3D12Renderer *)device->driverData;
return renderer->debugProps;
}
// Barriers
static inline Uint32 D3D12_INTERNAL_CalcSubresource(
@@ -8512,6 +8521,11 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
D3D12_FEATURE_DATA_ARCHITECTURE architecture;
D3D12_COMMAND_QUEUE_DESC queueDesc;
bool verboseLogs = SDL_GetBooleanProperty(
props,
SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN,
true);
renderer = (D3D12Renderer *)SDL_calloc(1, sizeof(D3D12Renderer));
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
@@ -8612,15 +8626,39 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
CHECK_D3D12_ERROR_AND_RETURN("Could not get adapter driver version", NULL);
}
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: D3D12");
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "D3D12 Adapter: %S", adapterDesc.Description);
SDL_LogInfo(
SDL_LOG_CATEGORY_GPU,
"D3D12 Driver: %d.%d.%d.%d",
renderer->debugProps = SDL_CreateProperties();
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: D3D12");
}
// Record device name
char *deviceName = SDL_iconv_wchar_utf8(&adapterDesc.Description[0]);
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_NAME_STRING,
deviceName);
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "D3D12 Adapter: %s", deviceName);
}
SDL_free(deviceName);
// Record driver version
char driverVer[64];
(void)SDL_snprintf(
driverVer,
SDL_arraysize(driverVer),
"%d.%d.%d.%d",
HIWORD(umdVersion.HighPart),
LOWORD(umdVersion.HighPart),
HIWORD(umdVersion.LowPart),
LOWORD(umdVersion.LowPart));
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_DRIVER_VERSION_STRING,
driverVer);
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "D3D12 Driver: %s", driverVer);
}
#endif
// Load the D3D library

View File

@@ -643,6 +643,7 @@ struct MetalRenderer
id<MTLCommandQueue> queue;
bool debugMode;
SDL_PropertiesID debugProps;
Uint32 allowedFramesInFlight;
MetalWindowData **claimedWindows;
@@ -765,11 +766,20 @@ static void METAL_DestroyDevice(SDL_GPUDevice *device)
// Release the command queue
renderer->queue = nil;
// Release debug properties
SDL_DestroyProperties(renderer->debugProps);
// Free the primary structures
SDL_free(renderer);
SDL_free(device);
}
static SDL_PropertiesID METAL_GetDeviceDebugProperties(SDL_GPUDevice *device)
{
MetalRenderer *renderer = (MetalRenderer *)device->driverData;
return renderer->debugProps;
}
// Resource tracking
static void METAL_INTERNAL_TrackBuffer(
@@ -4444,6 +4454,11 @@ static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SD
id<MTLDevice> device = NULL;
bool hasHardwareSupport = false;
bool verboseLogs = SDL_GetBooleanProperty(
props,
SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN,
true);
if (debugMode) {
/* Due to a Metal driver quirk, once a MTLDevice has been created
* with this environment variable set, the Metal validation layers
@@ -4497,12 +4512,20 @@ static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SD
renderer->device = device;
renderer->queue = [device newCommandQueue];
// Print driver info
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Metal");
SDL_LogInfo(
SDL_LOG_CATEGORY_GPU,
"Metal Device: %s",
[device.name UTF8String]);
renderer->debugProps = SDL_CreateProperties();
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Metal");
}
// Record device name
const char *deviceName = [device.name UTF8String];
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_NAME_STRING,
deviceName);
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Metal Device: %s", deviceName);
}
// Remember debug mode
renderer->debugMode = debugMode;

View File

@@ -1096,6 +1096,7 @@ struct VulkanRenderer
bool debugMode;
bool preferLowPower;
SDL_PropertiesID debugProps;
Uint32 allowedFramesInFlight;
VulkanExtensions supports;
@@ -4917,11 +4918,20 @@ static void VULKAN_DestroyDevice(
renderer->vkDestroyDevice(renderer->logicalDevice, NULL);
renderer->vkDestroyInstance(renderer->instance, NULL);
SDL_DestroyProperties(renderer->debugProps);
SDL_free(renderer);
SDL_free(device);
SDL_Vulkan_UnloadLibrary();
}
static SDL_PropertiesID VULKAN_GetDeviceDebugProperties(
SDL_GPUDevice *device)
{
VulkanRenderer *renderer = (VulkanRenderer *)device->driverData;
return renderer->debugProps;
}
static DescriptorSetCache *VULKAN_INTERNAL_AcquireDescriptorSetCache(
VulkanRenderer *renderer)
{
@@ -11568,6 +11578,11 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
SDL_GPUDevice *result;
Uint32 i;
bool verboseLogs = SDL_GetBooleanProperty(
props,
SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN,
true);
if (!SDL_Vulkan_LoadLibrary(NULL)) {
SDL_assert(!"This should have failed in PrepareDevice first!");
return NULL;
@@ -11585,25 +11600,108 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
SET_STRING_ERROR_AND_RETURN("Failed to initialize Vulkan!", NULL);
}
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan");
SDL_LogInfo(
SDL_LOG_CATEGORY_GPU,
"Vulkan Device: %s",
renderer->physicalDeviceProperties.properties.deviceName);
renderer->debugProps = SDL_CreateProperties();
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan");
}
// Record device name
const char *deviceName = renderer->physicalDeviceProperties.properties.deviceName;
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_NAME_STRING,
deviceName);
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Device: %s", deviceName);
}
// Record driver version. This is provided as a backup if
// VK_KHR_driver_properties is not available but as most drivers support it
// this property should be rarely used.
//
// This uses a vendor-specific encoding and it isn't well documented. The
// vendor ID is the registered PCI ID of the vendor and can be found in
// online databases.
char driverVer[64];
Uint32 rawDriverVer = renderer->physicalDeviceProperties.properties.driverVersion;
Uint32 vendorId = renderer->physicalDeviceProperties.properties.vendorID;
if (vendorId == 0x10de) {
// Nvidia uses 10|8|8|6 encoding.
(void)SDL_snprintf(
driverVer,
SDL_arraysize(driverVer),
"%d.%d.%d.%d",
(rawDriverVer >> 22) & 0x3ff,
(rawDriverVer >> 14) & 0xff,
(rawDriverVer >> 6) & 0xff,
rawDriverVer & 0x3f);
}
#ifdef SDL_PLATFORM_WINDOWS
else if (vendorId == 0x8086) {
// Intel uses 18|14 encoding on Windows only.
(void)SDL_snprintf(
driverVer,
SDL_arraysize(driverVer),
"%d.%d",
(rawDriverVer >> 14) & 0x3ffff,
rawDriverVer & 0x3fff);
}
#endif
else {
// Assume standard Vulkan 10|10|12 encoding for everything else. AMD and
// Mesa are known to use this encoding.
(void)SDL_snprintf(
driverVer,
SDL_arraysize(driverVer),
"%d.%d.%d",
(rawDriverVer >> 22) & 0x3ff,
(rawDriverVer >> 12) & 0x3ff,
rawDriverVer & 0xfff);
}
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_DRIVER_VERSION_STRING,
driverVer);
// Log this only if VK_KHR_driver_properties is not available.
if (renderer->supports.KHR_driver_properties) {
SDL_LogInfo(
SDL_LOG_CATEGORY_GPU,
"Vulkan Driver: %s %s",
renderer->physicalDeviceDriverProperties.driverName,
renderer->physicalDeviceDriverProperties.driverInfo);
SDL_LogInfo(
SDL_LOG_CATEGORY_GPU,
"Vulkan Conformance: %u.%u.%u",
// Record driver name and version
const char *driverName = renderer->physicalDeviceDriverProperties.driverName;
const char *driverInfo = renderer->physicalDeviceDriverProperties.driverInfo;
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_DRIVER_NAME_STRING,
driverName);
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_DRIVER_INFO_STRING,
driverInfo);
if (verboseLogs) {
// FIXME: driverInfo can be a multiline string.
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s %s", driverName, driverInfo);
}
// Record conformance level
char conformance[64];
(void)SDL_snprintf(
conformance,
SDL_arraysize(conformance),
"%u.%u.%u.%u",
renderer->physicalDeviceDriverProperties.conformanceVersion.major,
renderer->physicalDeviceDriverProperties.conformanceVersion.minor,
renderer->physicalDeviceDriverProperties.conformanceVersion.subminor,
renderer->physicalDeviceDriverProperties.conformanceVersion.patch);
SDL_SetStringProperty(
renderer->debugProps,
SDL_PROP_GPU_DEVICE_DEBUG_VULKAN_CONFORMANCE_STRING,
conformance);
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Conformance: %s", conformance);
}
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "KHR_driver_properties unsupported! Bother your vendor about this!");
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s", driverVer);
}
}
if (!VULKAN_INTERNAL_CreateLogicalDevice(