From 151ddcf419bcbe6e914b7cf47698744727671648 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Tue, 31 Mar 2020 20:26:44 -0300
Subject: [PATCH] renderer_vulkan/wrapper: Add instance handle

---
 src/video_core/renderer_vulkan/wrapper.cpp | 70 ++++++++++++++++++++++
 src/video_core/renderer_vulkan/wrapper.h   | 17 ++++++
 2 files changed, 87 insertions(+)

diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index c412b7f209..2e743e9268 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -339,4 +339,74 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe
     return VK_SUCCESS;
 }
 
+Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions,
+                          InstanceDispatch& dld) noexcept {
+    VkApplicationInfo application_info;
+    application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+    application_info.pNext = nullptr;
+    application_info.pApplicationName = "yuzu Emulator";
+    application_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
+    application_info.pEngineName = "yuzu Emulator";
+    application_info.engineVersion = VK_MAKE_VERSION(0, 1, 0);
+    application_info.apiVersion = VK_API_VERSION_1_1;
+
+    VkInstanceCreateInfo ci;
+    ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+    ci.pNext = nullptr;
+    ci.flags = 0;
+    ci.pApplicationInfo = &application_info;
+    ci.enabledLayerCount = layers.size();
+    ci.ppEnabledLayerNames = layers.data();
+    ci.enabledExtensionCount = extensions.size();
+    ci.ppEnabledExtensionNames = extensions.data();
+
+    VkInstance instance;
+    if (dld.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) {
+        // Failed to create the instance.
+        return {};
+    }
+    if (!Proc(dld.vkDestroyInstance, dld, "vkDestroyInstance", instance)) {
+        // We successfully created an instance but the destroy function couldn't be loaded.
+        // This is a good moment to panic.
+        return {};
+    }
+
+    return Instance(instance, dld);
+}
+
+std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() {
+    u32 num;
+    if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) {
+        return std::nullopt;
+    }
+    std::vector<VkPhysicalDevice> physical_devices(num);
+    if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) {
+        return std::nullopt;
+    }
+    return physical_devices;
+}
+
+DebugCallback Instance::TryCreateDebugCallback(
+    PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept {
+    VkDebugUtilsMessengerCreateInfoEXT ci;
+    ci.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
+    ci.pNext = nullptr;
+    ci.flags = 0;
+    ci.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
+                         VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
+                         VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
+                         VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+    ci.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
+                     VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
+                     VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+    ci.pfnUserCallback = callback;
+    ci.pUserData = nullptr;
+
+    VkDebugUtilsMessengerEXT messenger;
+    if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) {
+        return {};
+    }
+    return DebugCallback(messenger, handle, *dld);
+}
+
 } // namespace Vulkan::vk
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 686c2b9a14..8eb31e77d7 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -542,4 +542,21 @@ using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
 using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>;
 using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>;
 
+/// Vulkan instance owning handle.
+class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
+    using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
+
+public:
+    /// Creates a Vulkan instance. Use "operator bool" for error handling.
+    static Instance Create(Span<const char*> layers, Span<const char*> extensions,
+                           InstanceDispatch& dld) noexcept;
+
+    /// Enumerates physical devices.
+    /// @return Physical devices and an empty handle on failure.
+    std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices();
+
+    /// Tries to create a debug callback messenger. Returns an empty handle on failure.
+    DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept;
+};
+
 } // namespace Vulkan::vk