From acedd2ad06ab120861afd5c27dd89264d9768f1a Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 25 Apr 2026 08:02:00 +0000 Subject: [PATCH] [vulkan] support VK_EXT_fault_info when VK_ERROR_DEVICE_LOST is incurred Signed-off-by: lizzie --- .../vulkan_common/vulkan_device.cpp | 49 +++++++++++++++++++ src/video_core/vulkan_common/vulkan_device.h | 1 + .../vulkan_common/vulkan_wrapper.cpp | 1 + src/video_core/vulkan_common/vulkan_wrapper.h | 1 + 4 files changed, 52 insertions(+) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6e55306079..1f66ca28fb 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -25,6 +25,7 @@ #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/gpu_logging/gpu_logging.h" +#include "vulkan/vulkan_core.h" #if defined(ANDROID) && defined(ARCHITECTURE_arm64) #include @@ -772,6 +773,54 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags void Device::ReportLoss() const { LOG_CRITICAL(Render_Vulkan, "Device loss occurred!"); + if (extensions.device_fault) { + VkDeviceFaultCountsEXT fault_counts{ + .sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT + }; + dld.vkGetDeviceFaultInfoEXT(VkDevice(GetLogical().address()), &fault_counts, nullptr); + std::vector address_info(fault_counts.addressInfoCount); + std::vector vendor_info(fault_counts.vendorInfoCount); + std::vector vendor_binary_data(fault_counts.vendorBinarySize); + VkDeviceFaultInfoEXT fault_info{ + .sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT, + .pAddressInfos = address_info.data(), + .pVendorInfos = vendor_info.data(), + .pVendorBinaryData = vendor_binary_data.data() + }; + dld.vkGetDeviceFaultInfoEXT(VkDevice(GetLogical().address()), &fault_counts, &fault_info); + std::string s = "Fault report\n"; + if (address_info.size() > 0) { + s += "address-info\n"; + for (auto const& ai : address_info) { + s += fmt::format("{:#x} => {}\n", ai.reportedAddress, [t = ai.addressType] { + switch (t) { +#define VKFATC(n) case n: return #n; + VKFATC(VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT) + VKFATC(VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT) + VKFATC(VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT) + VKFATC(VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT) + VKFATC(VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT) + VKFATC(VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT) + VKFATC(VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT) +#undef VKFATC + default: return "unknown"; + } + }()); + } + } + if (vendor_info.size() > 0) { + s += "vendor-info\n"; + for (auto const& vi : vendor_info) + s += fmt::format("{:#x}-{:#x}: {}\n", vi.vendorFaultCode, vi.vendorFaultCode, vi.description); + } + if (vendor_binary_data.size() > 0) { + s += "vendor-binary-data\n"; + for (size_t i = 0; i < vendor_binary_data.size(); ++i) + s += fmt::format("{:02x} ", vendor_binary_data[i]); + s += "\n"; + } + } + // Wait for the log to flush and for Nsight Aftermath to dump the results std::this_thread::sleep_for(std::chrono::seconds{15}); } diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index a8a89aee89..fc3c9c30f7 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -82,6 +82,7 @@ VK_DEFINE_HANDLE(VmaAllocator) EXTENSION(EXT, SHADER_STENCIL_EXPORT, shader_stencil_export) \ EXTENSION(EXT, SHADER_VIEWPORT_INDEX_LAYER, shader_viewport_index_layer) \ EXTENSION(EXT, TOOLING_INFO, tooling_info) \ + EXTENSION(EXT, DEVICE_FAULT, device_fault) \ EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \ EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \ EXTENSION(KHR, DRIVER_PROPERTIES, driver_properties) \ diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 871ce52678..d687b0887f 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -236,6 +236,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { X(vkUpdateDescriptorSets); X(vkWaitForFences); X(vkWaitSemaphores); + X(vkGetDeviceFaultInfoEXT); // Support for timeline semaphores is mandatory in Vulkan 1.2 if (!dld.vkGetSemaphoreCounterValue) { diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 4a3baad2c4..3e09b79bc0 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -338,6 +338,7 @@ struct DeviceDispatch : InstanceDispatch { PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets{}; PFN_vkWaitForFences vkWaitForFences{}; PFN_vkWaitSemaphores vkWaitSemaphores{}; + PFN_vkGetDeviceFaultInfoEXT vkGetDeviceFaultInfoEXT{}; }; /// Loads instance agnostic function pointers.