From f4a25f854cd20f4793c8d88cf2ecf555079ece17 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 02:08:29 -0300 Subject: [PATCH 1/5] vk_device: Add query for RGBA8Uint --- src/video_core/renderer_vulkan/vk_device.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 92854a4b3..a57428059 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -464,6 +464,7 @@ std::vector VKDevice::GetDeviceQueueCreateInfos() con std::unordered_map VKDevice::GetFormatProperties( const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) { static constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32, + vk::Format::eA8B8G8R8UintPack32, vk::Format::eA8B8G8R8SnormPack32, vk::Format::eA8B8G8R8SrgbPack32, vk::Format::eB5G6R5UnormPack16, From 54747d60bc6cce24b51af737ef2b26b6b120661e Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 02:09:05 -0300 Subject: [PATCH 2/5] vk_device: Add entry to catch device losses VK_NV_device_diagnostic_checkpoints allows us to push data to a Vulkan queue and then query it even after a device loss. This allows us to push the current pipeline object and see what was the call that killed the device. --- src/video_core/renderer_vulkan/vk_device.cpp | 21 +++++++++++++++++++ src/video_core/renderer_vulkan/vk_device.h | 9 ++++++++ .../renderer_vulkan/vk_resource_manager.cpp | 11 +++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index a57428059..939eebe83 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -3,12 +3,15 @@ // Refer to the license.txt file included. #include +#include #include #include #include #include +#include #include #include "common/assert.h" +#include "core/settings.h" #include "video_core/renderer_vulkan/declarations.h" #include "video_core/renderer_vulkan/vk_device.h" @@ -201,6 +204,22 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format, return wanted_format; } +void VKDevice::ReportLoss() const { + LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); + + // Wait some time to let the log flush + std::this_thread::sleep_for(std::chrono::seconds{1}); + + if (!nv_device_diagnostic_checkpoints) { + return; + } + + [[maybe_unused]] const std::vector data = graphics_queue.getCheckpointDataNV(dld); + // Catch here in debug builds (or with optimizations disabled) the last graphics pipeline to be + // executed. It can be done on a debugger by evaluating the expression: + // *(VKGraphicsPipeline*)data[0] +} + bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, const vk::DispatchLoaderDynamic& dldi) const { // Disable for now to avoid converting ASTC twice. @@ -381,6 +400,8 @@ std::vector VKDevice::LoadExtensions(const vk::DispatchLoaderDynami VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true); Test(extension, ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); + Test(extension, nv_device_diagnostic_checkpoints, + VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME, true); } if (khr_shader_float16_int8) { diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index a844c52df..72603f9f6 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -39,6 +39,9 @@ public: vk::Format GetSupportedFormat(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage, FormatType format_type) const; + /// Reports a device loss. + void ReportLoss() const; + /// Returns the dispatch loader with direct function pointers of the device. const vk::DispatchLoaderDynamic& GetDispatchLoader() const { return dld; @@ -159,6 +162,11 @@ public: return ext_shader_viewport_index_layer; } + /// Returns true if the device supports VK_NV_device_diagnostic_checkpoints. + bool IsNvDeviceDiagnosticCheckpoints() const { + return nv_device_diagnostic_checkpoints; + } + /// Returns the vendor name reported from Vulkan. std::string_view GetVendorName() const { return vendor_name; @@ -218,6 +226,7 @@ private: bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. + bool nv_device_diagnostic_checkpoints{}; ///< Support for VK_NV_device_diagnostic_checkpoints. // Telemetry parameters std::string vendor_name; ///< Device's driver name. diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index 13c46e5b8..a0ca5f2ae 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -72,9 +72,18 @@ VKFence::VKFence(const VKDevice& device, UniqueFence handle) VKFence::~VKFence() = default; void VKFence::Wait() { + static constexpr u64 timeout = std::numeric_limits::max(); const auto dev = device.GetLogical(); const auto& dld = device.GetDispatchLoader(); - dev.waitForFences({*handle}, true, std::numeric_limits::max(), dld); + switch (const auto result = dev.waitForFences(1, &*handle, true, timeout, dld)) { + case vk::Result::eSuccess: + return; + case vk::Result::eErrorDeviceLost: + device.ReportLoss(); + [[fallthrough]]; + default: + vk::throwResultException(result, "vk::waitForFences"); + } } void VKFence::Release() { From 6ddffa010a86698543e2d0ecc07d1b93d8700e53 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 02:13:32 -0300 Subject: [PATCH 3/5] vk_resource_manager: Implement VKFenceWatch move constructor This allows us to put VKFenceWatch inside a std::vector without storing it in heap. On move we have to signal the fences where the new protected resource is, adding some overhead. --- .../renderer_vulkan/vk_resource_manager.cpp | 24 +++++++++++++++++++ .../renderer_vulkan/vk_resource_manager.h | 8 +++++++ 2 files changed, 32 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index a0ca5f2ae..aa145de5c 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -142,8 +142,32 @@ void VKFence::Unprotect(VKResource* resource) { protected_resources.erase(it); } +void VKFence::RedirectProtection(VKResource* old_resource, VKResource* new_resource) noexcept { + std::replace(std::begin(protected_resources), std::end(protected_resources), old_resource, + new_resource); +} + VKFenceWatch::VKFenceWatch() = default; +VKFenceWatch::VKFenceWatch(VKFence& initial_fence) { + Watch(initial_fence); +} + +VKFenceWatch::VKFenceWatch(VKFenceWatch&& rhs) noexcept { + fence = std::exchange(rhs.fence, nullptr); + if (fence) { + fence->RedirectProtection(&rhs, this); + } +} + +VKFenceWatch& VKFenceWatch::operator=(VKFenceWatch&& rhs) noexcept { + fence = std::exchange(rhs.fence, nullptr); + if (fence) { + fence->RedirectProtection(&rhs, this); + } + return *this; +} + VKFenceWatch::~VKFenceWatch() { if (fence) { fence->Unprotect(this); diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index 08ee86fa6..3a9683f95 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -65,6 +65,9 @@ public: /// Removes protection for a resource. void Unprotect(VKResource* resource); + /// Redirects one protected resource to a new address. + void RedirectProtection(VKResource* old_resource, VKResource* new_resource) noexcept; + /// Retreives the fence. operator vk::Fence() const { return *handle; @@ -97,8 +100,13 @@ private: class VKFenceWatch final : public VKResource { public: explicit VKFenceWatch(); + VKFenceWatch(VKFence& initial_fence); + VKFenceWatch(VKFenceWatch&&) noexcept; + VKFenceWatch(const VKFenceWatch&) = delete; ~VKFenceWatch() override; + VKFenceWatch& operator=(VKFenceWatch&&) noexcept; + /// Waits for the fence to be released. void Wait(); From ec983a245100eee028344391029adc5c2aac7848 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 02:14:52 -0300 Subject: [PATCH 4/5] vk_reosurce_manager: Add assert for releasing fences Notify the programmer when a request to release a fence is invalid because the fence is already free. --- src/video_core/renderer_vulkan/vk_resource_manager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index aa145de5c..525b4bb46 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -87,6 +87,7 @@ void VKFence::Wait() { } void VKFence::Release() { + ASSERT(is_owned); is_owned = false; } From e41da22c8df960d85c6942ff21bf8f119b8ad0ed Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 19 Dec 2019 02:16:21 -0300 Subject: [PATCH 5/5] vk_resource_manager: Add entry to VKFence to test its usage --- src/video_core/renderer_vulkan/vk_resource_manager.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index 3a9683f95..d4cbc95a5 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -124,6 +124,14 @@ public: void OnFenceRemoval(VKFence* signaling_fence) override; + /** + * Do not use it paired with Watch. Use TryWatch instead. + * Returns true when the watch is free. + */ + bool IsUsed() const { + return fence != nullptr; + } + private: VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free. };