diff --git a/src/main.cpp b/src/main.cpp index af8eef4..485a090 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,13 +2,15 @@ #define GLFW_INCLUDE_VULKAN #include #include +#include #include +#include #include #define VULKAN_HPP_NO_CONSTRUCTORS #include -#include "fmt/base.h" +#include "util/magic_enum.hpp" #include "util/types.h" namespace vk { @@ -28,7 +30,7 @@ constexpr bool enableValidationLayers = true; class VulkanApp { public: - void run() { + fn run() -> void { initWindow(); initVulkan(); mainLoop(); @@ -44,14 +46,21 @@ class VulkanApp { vk::DispatchLoaderDynamic mLoader; vk::PhysicalDevice mPhysicalDevice; + vk::UniqueDevice mDevice; + + vk::Queue mGraphicsQueue; + vk::Queue mPresentQueue; + + vk::UniqueSurfaceKHR mSurface; struct QueueFamilyIndices { std::optional graphics_family; + std::optional present_family; - fn isComplete() -> bool { return graphics_family.has_value(); } + fn isComplete() -> bool { return graphics_family.has_value() && present_family.has_value(); } }; - void initWindow() { + fn initWindow() -> void { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); @@ -60,17 +69,19 @@ class VulkanApp { mWindow = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); } - void initVulkan() { + fn initVulkan() -> void { createInstance(); setupDebugMessenger(); + createSurface(); pickPhysicalDevice(); + createLogicalDevice(); } - void mainLoop() { + fn mainLoop() -> void { while (!glfwWindowShouldClose(mWindow)) { glfwPollEvents(); } } - void cleanup() { + fn cleanup() -> void { glfwDestroyWindow(mWindow); glfwTerminate(); } @@ -114,7 +125,7 @@ class VulkanApp { } } - void setupDebugMessenger() { + fn setupDebugMessenger() -> void { if (!enableValidationLayers) return; @@ -131,6 +142,20 @@ class VulkanApp { mDebugMessenger = mInstance->createDebugUtilsMessengerEXTUnique(messengerCreateInfo, nullptr, mLoader); } + fn createSurface() -> void { + VkSurfaceKHR surface = nullptr; + + // FIXME: This is failing on macOS for some reason + VkResult result = glfwCreateWindowSurface(mInstance.get(), mWindow, nullptr, &surface); + + if (result != VK_SUCCESS) + throw std::runtime_error( + "Failed to create window surface! Error code: " + string(magic_enum::enum_name(result)) + ); + + mSurface = vk::UniqueSurfaceKHR(surface, mInstance.get()); + } + fn pickPhysicalDevice() -> void { std::vector devices = mInstance->enumeratePhysicalDevices(); @@ -157,13 +182,42 @@ class VulkanApp { throw std::runtime_error("Failed to find a suitable GPU!"); } - static fn isDeviceSuitable(vk::PhysicalDevice device) -> bool { + fn createLogicalDevice() -> void { + QueueFamilyIndices indices = findQueueFamilies(mPhysicalDevice); + + std::vector queueCreateInfos; + std::set uniqueQueueFamilies = { indices.graphics_family.value(), indices.present_family.value() }; + + f32 queuePriority = 1.0F; + + for (u32 queueFamily : uniqueQueueFamilies) { + vk::DeviceQueueCreateInfo queueCreateInfo { .queueFamilyIndex = queueFamily, + .queueCount = 1, + .pQueuePriorities = &queuePriority }; + + queueCreateInfos.push_back(queueCreateInfo); + } + + vk::PhysicalDeviceFeatures deviceFeatures; + + vk::DeviceCreateInfo createInfo { .queueCreateInfoCount = static_cast(queueCreateInfos.size()), + .pQueueCreateInfos = queueCreateInfos.data(), + .enabledExtensionCount = 0, + .ppEnabledExtensionNames = nullptr, + .pEnabledFeatures = &deviceFeatures }; + + mDevice = mPhysicalDevice.createDeviceUnique(createInfo); + + mGraphicsQueue = mDevice->getQueue(indices.graphics_family.value(), 0); + } + + fn isDeviceSuitable(vk::PhysicalDevice device) -> bool { QueueFamilyIndices indices = findQueueFamilies(device); return indices.isComplete(); } - static fn findQueueFamilies(vk::PhysicalDevice device) -> QueueFamilyIndices { + fn findQueueFamilies(vk::PhysicalDevice device) -> QueueFamilyIndices { QueueFamilyIndices indices; std::vector queueFamilies = device.getQueueFamilyProperties(); @@ -172,6 +226,11 @@ class VulkanApp { if (queueFamilies[i].queueFlags & vk::QueueFlagBits::eGraphics) indices.graphics_family = i; + vk::Bool32 presentSupport = device.getSurfaceSupportKHR(i, mSurface.get()); + + if (presentSupport) + indices.present_family = i; + if (indices.isComplete()) break; } @@ -221,7 +280,7 @@ class VulkanApp { VkDebugUtilsMessageTypeFlagsEXT /*messageType*/, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* /*pUserData*/ - ) -> VkBool32 { + ) -> vk::Bool32 { fmt::println("Validation layer: {}", pCallbackData->pMessage); return VK_FALSE;