From 1b5f373f8e913aa948ef0964d26a0082e6563f0a Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Thu, 2 May 2024 00:09:00 +0200 Subject: Vulkan surface creation & present queue selection --- deimos/core/base.h | 3 + deimos/core/os.h | 5 + deimos/core/os_win32.cpp | 18 +++- deimos/vulkan/vulkan_instance_functions.inc | 6 +- main/main.cpp | 139 ++++++++++++++++++---------- todo.txt | 2 + 6 files changed, 122 insertions(+), 51 deletions(-) diff --git a/deimos/core/base.h b/deimos/core/base.h index 34a341f..0c15ccd 100644 --- a/deimos/core/base.h +++ b/deimos/core/base.h @@ -1,5 +1,8 @@ #pragma once +// @Todo Add some compile-time config stuff +#define DEIMOS_OS_WIN32 1 // NOLINT + #include "deimos/core/std.h" #include "deimos/core/gsl.h" diff --git a/deimos/core/os.h b/deimos/core/os.h index c440555..d310185 100644 --- a/deimos/core/os.h +++ b/deimos/core/os.h @@ -64,6 +64,11 @@ public: virtual void Update(OsWindow*) = 0; virtual bool QuitRequested(const OsWindow*) = 0; + +#if DEIMOS_OS_WIN32 + virtual void* Win32Hwnd(const OsWindow*) = 0; + virtual void* Win32Hinstance(const OsWindow*) = 0; +#endif }; class OsApi diff --git a/deimos/core/os_win32.cpp b/deimos/core/os_win32.cpp index e80a1d5..84fc3a3 100644 --- a/deimos/core/os_win32.cpp +++ b/deimos/core/os_win32.cpp @@ -95,6 +95,7 @@ class Win32WindowApiImpl : public OsWindowApi { static constexpr wchar_t kClassName[] = L"Deimos window class"; + HINSTANCE m_hinstance; Allocator* m_allocator; bool m_class_registered = false; @@ -134,7 +135,7 @@ class Win32WindowApiImpl : public OsWindowApi WNDCLASSW wnd_class{}; wnd_class.lpfnWndProc = WindowProc; - wnd_class.hInstance = ::GetModuleHandleW(nullptr); + wnd_class.hInstance = m_hinstance; wnd_class.lpszClassName = kClassName; ::RegisterClassW(&wnd_class); @@ -144,6 +145,7 @@ class Win32WindowApiImpl : public OsWindowApi public: explicit Win32WindowApiImpl(Allocator* allocator) : + m_hinstance{::GetModuleHandleW(nullptr)}, m_allocator{allocator} {} @@ -163,7 +165,7 @@ public: HWND hwnd = ::CreateWindowExW( 0, kClassName, title_w, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, - nullptr, nullptr, ::GetModuleHandle(nullptr), window); + nullptr, nullptr, m_hinstance, window); if (hwnd == nullptr) { @@ -192,6 +194,18 @@ public: { return window->quit_requested; } + +#if DEIMOS_OS_WIN32 + void* Win32Hwnd(const OsWindow* window) override + { + return std::bit_cast(window->hwnd); + } + + void* Win32Hinstance(const OsWindow*) override + { + return std::bit_cast(m_hinstance); + } +#endif }; class Win32OsApiImpl : public OsApi diff --git a/deimos/vulkan/vulkan_instance_functions.inc b/deimos/vulkan/vulkan_instance_functions.inc index 48daf68..0a46455 100644 --- a/deimos/vulkan/vulkan_instance_functions.inc +++ b/deimos/vulkan/vulkan_instance_functions.inc @@ -2,8 +2,12 @@ FN(EnumeratePhysicalDevices) FN(GetPhysicalDeviceProperties2) FN(GetPhysicalDeviceQueueFamilyProperties) -FN(GetPhysicalDeviceWin32PresentationSupportKHR) FN(DestroyInstance) + FN(CreateDevice) FN(GetDeviceProcAddr) + +FN(CreateWin32SurfaceKHR) +FN(DestroySurfaceKHR) +FN(GetPhysicalDeviceSurfaceSupportKHR) // NOLINTEND diff --git a/main/main.cpp b/main/main.cpp index 4a999ce..602b6ab 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -13,7 +13,6 @@ static OsApi* os_api; static const VkAllocationCallbacks* kVkAlloc = nullptr; -[[nodiscard]] StatusOr CreateInstance(VulkanApi* vk) { const VkApplicationInfo application_info{ @@ -58,34 +57,33 @@ StatusOr CreateInstance(VulkanApi* vk) return instance; } -StatusOr FindPhysicalDevice(VulkanApi* vk, VkInstance instance) +StatusOr CreateSurface(VulkanApi* vk, VkInstance instance, OsWindow* window) { - auto temp_alloc = temp_api->Acquire(); - - uint32_t physical_device_count = 0; - vk->EnumeratePhysicalDevices(instance, &physical_device_count, nullptr); - if (physical_device_count == 0) + const VkWin32SurfaceCreateInfoKHR create_info{ + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .hinstance = os_api->window->Win32Hinstance(window), + .hwnd = os_api->window->Win32Hwnd(window), + }; + + VkSurfaceKHR surface{}; + const VkResult res = vk->CreateWin32SurfaceKHR(instance, &create_info, kVkAlloc, &surface); + if (res != VK_SUCCESS) { - return InternalError("No Vulkan device found"); + return InternalError("vkCreateWin32SurfaceKHR failed"); } - log_api->LogInfo("Found $ physical devices", physical_device_count); - - auto devices = temp_alloc.allocator().NewArray(physical_device_count); - vk->EnumeratePhysicalDevices(instance, &physical_device_count, devices.data()); - - // @Todo Physical device selection - // In fact, FindQueueFamily should be done here. - return devices[0]; + return surface; } -StatusOr FindQueueFamily(VulkanApi* vk, VkPhysicalDevice physical_device) +StatusOr FindQueueFamily(VulkanApi* vk, VkPhysicalDevice physical_device, VkSurfaceKHR surface) { auto temp_alloc = temp_api->Acquire(); uint32_t queue_family_count = 0; vk->GetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr); - if (queue_family_count == 0) + if (queue_family_count == 0) { return InternalError("No queue on this physical device"); } @@ -100,7 +98,11 @@ StatusOr FindQueueFamily(VulkanApi* vk, VkPhysicalDevice physical_devi const auto& prps = queue_families[index]; const bool supports_graphics_compute = (prps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && (prps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0; - const bool supports_presentation = vk->GetPhysicalDeviceWin32PresentationSupportKHR(physical_device, index) == VK_TRUE; + + VkBool32 vk_supports_presentation{}; + const VkResult presentation_res = vk->GetPhysicalDeviceSurfaceSupportKHR(physical_device, index, surface, &vk_supports_presentation); + const bool supports_presentation = presentation_res == VK_SUCCESS && vk_supports_presentation == VK_TRUE; + if (supports_graphics_compute && supports_presentation) { return index; @@ -110,6 +112,59 @@ StatusOr FindQueueFamily(VulkanApi* vk, VkPhysicalDevice physical_devi return InternalError("Couldn't find a suitable queue"); } +Status FindPhysicalDevice( + VulkanApi* vk, + VkInstance instance, + VkSurfaceKHR surface, + VkPhysicalDevice* out_physical_device, + uint32_t* out_queue_family) +{ + auto temp_alloc = temp_api->Acquire(); + + uint32_t physical_device_count = 0; + vk->EnumeratePhysicalDevices(instance, &physical_device_count, nullptr); + if (physical_device_count == 0) + { + return InternalError("No Vulkan device found"); + } + + log_api->LogInfo("Found $ physical devices", physical_device_count); + + auto physical_devices = temp_alloc.allocator().NewArray(physical_device_count); + vk->EnumeratePhysicalDevices(instance, &physical_device_count, physical_devices.data()); + + for (VkPhysicalDevice physical_device: physical_devices) + { + { + VkPhysicalDeviceVulkan12Properties prps12{}; + prps12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; + prps12.pNext = nullptr; + + VkPhysicalDeviceProperties2 prps{}; + prps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + prps.pNext = &prps12; + + vk->GetPhysicalDeviceProperties2(physical_device, &prps); + + log_api->LogInfo("Trying Vulkan device $ ($, $)", + prps.properties.deviceName, prps12.driverName, prps12.driverInfo); + } + + auto maybe_queue_family = FindQueueFamily(vk, physical_device, surface); + if (maybe_queue_family.ok()) + { + log_api->LogInfo("This device is compatible, choosing it"); + *out_physical_device = physical_device; + *out_queue_family = maybe_queue_family.value(); + return {}; + } + + log_api->LogInfo("Incompatible because: $", maybe_queue_family); + } + + return InternalError("No suitable device found"); +} + StatusOr CreateDevice(VulkanApi* vk, VkPhysicalDevice physical_device, uint32_t queue_family) { const float queue_priority = 1.0F; @@ -150,7 +205,7 @@ StatusOr CreateDevice(VulkanApi* vk, VkPhysicalDevice physical_device, return device; } -Status InitializeVulkan(ApiRegistry* api_registry) +Status InitializeVulkan(ApiRegistry* api_registry, OsWindow* window) { RegisterVulkanLoaderApi(api_registry); auto* loader_api = api_registry->Get(); @@ -166,32 +221,19 @@ Status InitializeVulkan(ApiRegistry* api_registry) loader_api->LoadInstance(vk, instance); - VkPhysicalDevice physical_device{}; + VkSurfaceKHR surface{}; { - StatusOr s = FindPhysicalDevice(vk, instance); + StatusOr s = CreateSurface(vk, instance, window); if (!s.ok()) { return s.status(); } - physical_device = s.value(); + surface = s.value(); + log_api->LogInfo("Vulkan surface created"); } + VkPhysicalDevice physical_device{}; + uint32_t queue_family{}; { - VkPhysicalDeviceVulkan12Properties prps12{}; - prps12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; - prps12.pNext = nullptr; - - VkPhysicalDeviceProperties2 prps{}; - prps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - prps.pNext = &prps12; - - vk->GetPhysicalDeviceProperties2(physical_device, &prps); - log_api->LogInfo("Vulkan device: $", prps.properties.deviceName); - log_api->LogInfo("Vulkan driver: $, $", prps12.driverName, prps12.driverInfo); - } - - uint32_t queue_family = 0; - { - StatusOr s = FindQueueFamily(vk, physical_device); - if (!s.ok()) { return s.status(); } - queue_family = s.value(); + Status s = FindPhysicalDevice(vk, instance, surface, &physical_device, &queue_family); + if (!s.ok()) { return s; } log_api->LogInfo("Vulkan queue family: $", queue_family); } @@ -210,6 +252,7 @@ Status InitializeVulkan(ApiRegistry* api_registry) Ensures(queue != VK_NULL_HANDLE); vk->DestroyDevice(device, kVkAlloc); + vk->DestroySurfaceKHR(instance, surface, kVkAlloc); vk->DestroyInstance(instance, kVkAlloc); return {}; @@ -235,19 +278,19 @@ int main(int /* argc */, char* /* argv */[]) window = s.value(); } - while (!os_api->window->QuitRequested(window)) - { - os_api->window->Update(window); - } - - const Status s = InitializeVulkan(api_registry); + const Status s = InitializeVulkan(api_registry, window); if (!s.ok()) { log_api->LogError("Vulkan initializaiton error: $", s); return 1; } - log_api->LogInfo("OK"); + while (!os_api->window->QuitRequested(window)) + { + os_api->window->Update(window); + } + + log_api->LogInfo("Goodbye"); return 0; } diff --git a/todo.txt b/todo.txt index 51cfd6b..c132e8d 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,5 @@ Smarter physical device selection @code +vulkan Select layers & extensions based on config @code +vulkan Last allocation optimization for temporary allocator @code +memory +core +Compile-time configuration @code +core +Add Optional @code +core -- cgit