From fbc43bc9855d6be9ef19a79218aae454ff58645c Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Sat, 3 Jan 2026 19:18:26 -0300 Subject: [PATCH] Revert "[vk] Unify RAII in Vulkan (#2679)" * properly use RENDERER_ENABLE_RAII * keep it ON as default This reverts commit db65f107689f853141fd2cf4cb7b6b55b24aff3e. --- .../features/settings/model/BooleanSetting.kt | 5 +- .../settings/model/view/SettingsItem.kt | 8 + .../settings/ui/SettingsFragmentPresenter.kt | 1 + .../app/src/main/res/values/strings.xml | 2 + src/common/settings.h | 1 + src/qt_common/config/shared_translation.cpp | 7 + .../renderer_vulkan/renderer_vulkan.cpp | 9 + .../renderer_vulkan/renderer_vulkan.h | 7 + .../renderer_vulkan/vk_swapchain.cpp | 1 - src/video_core/vulkan_common/vulkan_raii.h | 234 ++++++++++++++++++ .../vulkan_common/vulkan_wrapper.cpp | 11 +- src/video_core/vulkan_common/vulkan_wrapper.h | 66 +++-- 12 files changed, 312 insertions(+), 40 deletions(-) create mode 100644 src/video_core/vulkan_common/vulkan_raii.h diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index bd898251e6..b40aff9ea0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -23,6 +23,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_FORCE_MAX_CLOCK("force_max_clock"), RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"), RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"), + RENDERER_ENABLE_RAII("renderer_enable_raii"), SYNC_MEMORY_OPERATIONS("sync_memory_operations"), BUFFER_REORDER_DISABLE("disable_buffer_reorder"), RENDERER_DEBUG("debug"), @@ -71,9 +72,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { DONT_SHOW_DRIVER_SHADER_WARNING("dont_show_driver_shader_warning"), ENABLE_OVERLAY("enable_overlay"); - -// external fun isFrameSkippingEnabled(): Boolean - external fun isFrameInterpolationEnabled(): Boolean + external fun isRaiiEnabled(): Boolean override fun getBoolean(needsGlobal: Boolean): Boolean = NativeConfig.getBoolean(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 50143a449e..9e3c32e0d6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -630,6 +630,14 @@ abstract class SettingsItem( valuesId = R.array.optimizeSpirvOutputValues ) ) + put( + SwitchSetting( + BooleanSetting.RENDERER_ENABLE_RAII, + titleId = R.string.renderer_enable_raii, + descriptionId = R.string.renderer_enable_raii_description + ) + ) + put( SingleChoiceSetting( IntSetting.DMA_ACCURACY, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index dc58e7d23b..e0ebe3b46b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -270,6 +270,7 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key) add(IntSetting.RENDERER_ASTC_RECOMPRESSION.key) + add(BooleanSetting.RENDERER_ENABLE_RAII.key) add(BooleanSetting.SYNC_MEMORY_OPERATIONS.key) add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key) add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 4bfa5afd01..11250fa7b0 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -469,6 +469,8 @@ Anti-aliasing method Optimize SPIRV output Optimizes compiled shaders to improve GPU efficiency, but may introduce longer loading times and initial slowdowns. + RAII + A method of automatic resource management in Vulkan that ensures proper release of resources when they are no longer needed, but may cause crashes in bundled games. Advanced diff --git a/src/common/settings.h b/src/common/settings.h index 874ba7aee2..44f799bc00 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -451,6 +451,7 @@ struct Values { "astc_recompression", Category::RendererAdvanced}; + SwitchableSetting renderer_enable_raii{linkage, false, "renderer_enable_raii", Category::Renderer}; SwitchableSetting sync_memory_operations{linkage, false, diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index a3a720db8e..4783d6659b 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -254,6 +254,13 @@ std::unique_ptr InitializeTranslations(QObject* parent) // Renderer (Advanced Graphics) INSERT(Settings, use_asynchronous_gpu_emulation, QString(), QString()); + INSERT(Settings, + renderer_enable_raii, + tr("RAII"), + tr("A method of automatic resource management in Vulkan " + "that ensures proper release of resources " + "when they are no longer needed, but may cause crashes in bundled games.")); + INSERT(Settings, sync_memory_operations, tr("Sync Memory Operations"), tr("Ensures data consistency between compute and memory operations.\nThis option fixes issues in games, but may degrade performance.\nUnreal Engine 4 games often see the most significant changes thereof.")); INSERT(Settings, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 3b47570a7e..eb185cf253 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -164,6 +164,15 @@ try PresentFiltersForAppletCapture) , rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler) { + // Initialize RAII wrappers after creating the main objects + if (Settings::values.renderer_enable_raii.GetValue()) { + managed_instance = MakeManagedInstance(instance, dld); + if (Settings::values.renderer_debug) { + managed_debug_messenger = MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld); + } + managed_surface = MakeManagedSurface(surface, instance, dld); + } + if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { turbo_mode.emplace(instance, dld); scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 4fb88b29de..ef1d90d609 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -23,6 +23,7 @@ #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +#include "video_core/vulkan_common/vulkan_raii.h" namespace Core::Memory { class Memory; @@ -80,10 +81,16 @@ private: // Keep original handles for compatibility with existing code vk::Instance instance; + // RAII wrapper for instance + ManagedInstance managed_instance; vk::DebugUtilsMessenger debug_messenger; + // RAII wrapper for debug messenger + ManagedDebugUtilsMessenger managed_debug_messenger; vk::SurfaceKHR surface; + // RAII wrapper for surface + ManagedSurface managed_surface; Device device; MemoryAllocator memory_allocator; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 7418ad934e..6d6fa1908d 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -361,7 +361,6 @@ void Swapchain::CreateSemaphores() { void Swapchain::Destroy() { frame_index = 0; present_semaphores.clear(); - render_semaphores.clear(); swapchain.reset(); } diff --git a/src/video_core/vulkan_common/vulkan_raii.h b/src/video_core/vulkan_common/vulkan_raii.h new file mode 100644 index 0000000000..188ea521c3 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_raii.h @@ -0,0 +1,234 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2025 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include + +#include "common/logging/log.h" + +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { + +/** + * RAII wrapper for Vulkan resources. + * Automatically manages the lifetime of Vulkan objects using RAII principles. + */ +template +class VulkanRaii { +public: + using DeleterFunc = std::function; + + // Default constructor - creates a null handle + VulkanRaii() : handle{}, deleter{}, dispatch{} {} + + // Constructor with handle and deleter + VulkanRaii(T handle_, DeleterFunc deleter_, const Dispatch& dispatch_, const char* resource_name = "Vulkan resource") + : handle{handle_}, deleter{std::move(deleter_)}, dispatch{dispatch_} { + LOG_DEBUG(Render_Vulkan, "RAII wrapper created for {}", resource_name); + } + + // Move constructor + VulkanRaii(VulkanRaii&& other) noexcept + : handle{std::exchange(other.handle, VK_NULL_HANDLE)}, + deleter{std::move(other.deleter)}, + dispatch{other.dispatch} { + } + + // Move assignment + VulkanRaii& operator=(VulkanRaii&& other) noexcept { + if (this != &other) { + cleanup(); + handle = std::exchange(other.handle, VK_NULL_HANDLE); + deleter = std::move(other.deleter); + dispatch = other.dispatch; + } + return *this; + } + + // Destructor - automatically cleans up the resource + ~VulkanRaii() { + cleanup(); + } + + // Disallow copying + VulkanRaii(const VulkanRaii&) = delete; + VulkanRaii& operator=(const VulkanRaii&) = delete; + + // Get the underlying handle + T get() const noexcept { + return handle; + } + + // Check if the handle is valid + bool valid() const noexcept { + return handle != VK_NULL_HANDLE; + } + + // Release ownership of the handle without destroying it + T release() noexcept { + return std::exchange(handle, VK_NULL_HANDLE); + } + + // Reset the handle (destroying the current one if it exists) + void reset(T new_handle = VK_NULL_HANDLE, DeleterFunc new_deleter = {}) { + cleanup(); + handle = new_handle; + deleter = std::move(new_deleter); + } + + // Implicit conversion to handle type + operator T() const noexcept { + return handle; + } + + // Dereference operator for pointer-like access + T operator->() const noexcept { + return handle; + } + +private: + // Optimized cleanup function + void cleanup() noexcept { + if (handle != VK_NULL_HANDLE && deleter) { + deleter(handle, dispatch); + handle = VK_NULL_HANDLE; + } + } + + T handle; + DeleterFunc deleter; + Dispatch dispatch; +}; + +// Common type aliases for Vulkan RAII wrappers with clearer names +using ManagedInstance = VulkanRaii; +using ManagedDevice = VulkanRaii; +using ManagedSurface = VulkanRaii; +using ManagedSwapchain = VulkanRaii; +using ManagedCommandPool = VulkanRaii; +using ManagedBuffer = VulkanRaii; +using ManagedImage = VulkanRaii; +using ManagedImageView = VulkanRaii; +using ManagedSampler = VulkanRaii; +using ManagedShaderModule = VulkanRaii; +using ManagedPipeline = VulkanRaii; +using ManagedPipelineLayout = VulkanRaii; +using ManagedDescriptorSetLayout = VulkanRaii; +using ManagedDescriptorPool = VulkanRaii; +using ManagedSemaphore = VulkanRaii; +using ManagedFence = VulkanRaii; +using ManagedDebugUtilsMessenger = VulkanRaii; + +// Helper functions to create RAII wrappers + +/** + * Creates an RAII wrapper for a Vulkan instance + */ +inline ManagedInstance MakeManagedInstance(const vk::Instance& instance, const vk::InstanceDispatch& dispatch) { + auto deleter = [](VkInstance handle, const vk::InstanceDispatch& dld) { + dld.vkDestroyInstance(handle, nullptr); + }; + return ManagedInstance(*instance, deleter, dispatch, "VkInstance"); +} + +/** + * Creates an RAII wrapper for a Vulkan device + */ +inline ManagedDevice MakeManagedDevice(const vk::Device& device, const vk::DeviceDispatch& dispatch) { + auto deleter = [](VkDevice handle, const vk::DeviceDispatch& dld) { + dld.vkDestroyDevice(handle, nullptr); + }; + return ManagedDevice(*device, deleter, dispatch, "VkDevice"); +} + +/** + * Creates an RAII wrapper for a Vulkan surface + */ +inline ManagedSurface MakeManagedSurface(const vk::SurfaceKHR& surface, const vk::Instance& instance, const vk::InstanceDispatch& dispatch) { + auto deleter = [instance_ptr = *instance](VkSurfaceKHR handle, const vk::InstanceDispatch& dld) { + dld.vkDestroySurfaceKHR(instance_ptr, handle, nullptr); + }; + return ManagedSurface(*surface, deleter, dispatch, "VkSurfaceKHR"); +} + +/** + * Creates an RAII wrapper for a Vulkan debug messenger + */ +inline ManagedDebugUtilsMessenger MakeManagedDebugUtilsMessenger(const vk::DebugUtilsMessenger& messenger, + const vk::Instance& instance, + const vk::InstanceDispatch& dispatch) { + auto deleter = [instance_ptr = *instance](VkDebugUtilsMessengerEXT handle, const vk::InstanceDispatch& dld) { + dld.vkDestroyDebugUtilsMessengerEXT(instance_ptr, handle, nullptr); + }; + return ManagedDebugUtilsMessenger(*messenger, deleter, dispatch, "VkDebugUtilsMessengerEXT"); +} + +/** + * Creates an RAII wrapper for a Vulkan swapchain + */ +inline ManagedSwapchain MakeManagedSwapchain(VkSwapchainKHR swapchain_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { + auto deleter = [device_handle](VkSwapchainKHR handle, const vk::DeviceDispatch& dld) { + dld.vkDestroySwapchainKHR(device_handle, handle, nullptr); + }; + return ManagedSwapchain(swapchain_handle, deleter, dispatch, "VkSwapchainKHR"); +} + +/** + * Creates an RAII wrapper for a Vulkan buffer + */ +inline ManagedBuffer MakeManagedBuffer(VkBuffer buffer_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { + auto deleter = [device_handle](VkBuffer handle, const vk::DeviceDispatch& dld) { + dld.vkDestroyBuffer(device_handle, handle, nullptr); + }; + return ManagedBuffer(buffer_handle, deleter, dispatch, "VkBuffer"); +} + +/** + * Creates an RAII wrapper for a Vulkan image + */ +inline ManagedImage MakeManagedImage(VkImage image_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { + auto deleter = [device_handle](VkImage handle, const vk::DeviceDispatch& dld) { + dld.vkDestroyImage(device_handle, handle, nullptr); + }; + return ManagedImage(image_handle, deleter, dispatch, "VkImage"); +} + +/** + * Creates an RAII wrapper for a Vulkan image view + */ +inline ManagedImageView MakeManagedImageView(VkImageView view_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { + auto deleter = [device_handle](VkImageView handle, const vk::DeviceDispatch& dld) { + dld.vkDestroyImageView(device_handle, handle, nullptr); + }; + return ManagedImageView(view_handle, deleter, dispatch, "VkImageView"); +} + +/** + * Creates an RAII wrapper for a Vulkan semaphore + */ +inline ManagedSemaphore MakeManagedSemaphore(VkSemaphore semaphore_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { + auto deleter = [device_handle](VkSemaphore handle, const vk::DeviceDispatch& dld) { + dld.vkDestroySemaphore(device_handle, handle, nullptr); + }; + return ManagedSemaphore(semaphore_handle, deleter, dispatch, "VkSemaphore"); +} + +/** + * Creates an RAII wrapper for a Vulkan fence + */ +inline ManagedFence MakeManagedFence(VkFence fence_handle, VkDevice device_handle, const vk::DeviceDispatch& dispatch) { + auto deleter = [device_handle](VkFence handle, const vk::DeviceDispatch& dld) { + dld.vkDestroyFence(device_handle, handle, nullptr); + }; + return ManagedFence(fence_handle, deleter, dispatch, "VkFence"); +} + +} // namespace Vulkan \ No newline at end of file diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 534a11edd4..92324807c3 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -12,6 +12,7 @@ #include "common/common_types.h" #include "common/logging/log.h" +#include "common/settings.h" #include "video_core/vulkan_common/vk_enum_string_helper.h" #include "video_core/vulkan_common/vma.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -313,7 +314,10 @@ const char* Exception::what() const noexcept { } void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { - dld.vkDestroyInstance(instance, nullptr); + // FIXME: A double free occurs here if RAII is enabled. + if (!Settings::values.renderer_enable_raii.GetValue()) { + dld.vkDestroyInstance(instance, nullptr); + } } void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept { @@ -416,7 +420,10 @@ void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle, } void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { - dld.vkDestroySurfaceKHR(instance, handle, nullptr); + // FIXME: A double free occurs here if RAII is enabled. + if (!Settings::values.renderer_enable_raii.GetValue()) { + dld.vkDestroySurfaceKHR(instance, handle, nullptr); + } } VkResult Free(VkDevice device, VkDescriptorPool handle, Span sets, diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 04b9420d98..a2e2efe61a 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -519,7 +519,7 @@ public: } /// Returns true when there's a held object. - explicit operator bool() const noexcept { + operator bool() const noexcept { return handle != nullptr; } @@ -630,7 +630,7 @@ class Instance : public Handle { public: /// Creates a Vulkan instance. /// @throw Exception on initialization error. - [[nodiscard]] static Instance Create(u32 version, Span layers, Span extensions, + static Instance Create(u32 version, Span layers, Span extensions, InstanceDispatch& dispatch); /// Enumerates physical devices. @@ -640,12 +640,12 @@ public: /// Creates a debug callback messenger. /// @throw Exception on creation failure. - [[nodiscard]] DebugUtilsMessenger CreateDebugUtilsMessenger( + DebugUtilsMessenger CreateDebugUtilsMessenger( const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; /// Creates a debug report callback. /// @throw Exception on creation failure. - [[nodiscard]] DebugReportCallback CreateDebugReportCallback( + DebugReportCallback CreateDebugReportCallback( const VkDebugReportCallbackCreateInfoEXT& create_info) const; /// Returns dispatch table. @@ -989,60 +989,58 @@ class Device : public Handle { using Handle::Handle; public: - [[nodiscard]] static Device Create(VkPhysicalDevice physical_device, - Span queues_ci, - Span enabled_extensions, const void* next, - DeviceDispatch& dispatch); + static Device Create(VkPhysicalDevice physical_device, Span queues_ci, + Span enabled_extensions, const void* next, + DeviceDispatch& dispatch); - [[nodiscard]] Queue GetQueue(u32 family_index) const noexcept; + Queue GetQueue(u32 family_index) const noexcept; - [[nodiscard]] BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; + BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; - [[nodiscard]] ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; + ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; - [[nodiscard]] Semaphore CreateSemaphore() const; + Semaphore CreateSemaphore() const; - [[nodiscard]] Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; + Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; - [[nodiscard]] Fence CreateFence(const VkFenceCreateInfo& ci) const; + Fence CreateFence(const VkFenceCreateInfo& ci) const; - [[nodiscard]] DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; + DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; - [[nodiscard]] RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const; + RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const; - [[nodiscard]] DescriptorSetLayout CreateDescriptorSetLayout( - const VkDescriptorSetLayoutCreateInfo& ci) const; + DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const; - [[nodiscard]] PipelineCache CreatePipelineCache(const VkPipelineCacheCreateInfo& ci) const; + PipelineCache CreatePipelineCache(const VkPipelineCacheCreateInfo& ci) const; - [[nodiscard]] PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; + PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; - [[nodiscard]] Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci, - VkPipelineCache cache = nullptr) const; + Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci, + VkPipelineCache cache = nullptr) const; - [[nodiscard]] Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci, - VkPipelineCache cache = nullptr) const; + Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci, + VkPipelineCache cache = nullptr) const; - [[nodiscard]] Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; + Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; - [[nodiscard]] Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const; + Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const; - [[nodiscard]] CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; + CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; - [[nodiscard]] DescriptorUpdateTemplate CreateDescriptorUpdateTemplate( + DescriptorUpdateTemplate CreateDescriptorUpdateTemplate( const VkDescriptorUpdateTemplateCreateInfo& ci) const; - [[nodiscard]] QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; + QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; - [[nodiscard]] ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; + ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; - [[nodiscard]] Event CreateEvent() const; + Event CreateEvent() const; - [[nodiscard]] SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; + SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; - [[nodiscard]] DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept; + DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept; - [[nodiscard]] DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const; + DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const; VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer, void* pnext = nullptr) const noexcept;