diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-05-02 00:09:00 +0200 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-05-02 00:09:00 +0200 |
commit | 1b5f373f8e913aa948ef0964d26a0082e6563f0a (patch) | |
tree | be5b465b643f308b207925af8ec95df542c277bb | |
parent | a3fdb87df94f8d377b7ea90ca50a06418fda3867 (diff) |
Vulkan surface creation & present queue selection
-rw-r--r-- | deimos/core/base.h | 3 | ||||
-rw-r--r-- | deimos/core/os.h | 5 | ||||
-rw-r--r-- | deimos/core/os_win32.cpp | 18 | ||||
-rw-r--r-- | deimos/vulkan/vulkan_instance_functions.inc | 6 | ||||
-rw-r--r-- | main/main.cpp | 139 | ||||
-rw-r--r-- | 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<void*>(window->hwnd);
+ }
+
+ void* Win32Hinstance(const OsWindow*) override
+ {
+ return std::bit_cast<void*>(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<VkInstance> CreateInstance(VulkanApi* vk)
{
const VkApplicationInfo application_info{
@@ -58,34 +57,33 @@ StatusOr<VkInstance> CreateInstance(VulkanApi* vk) return instance;
}
-StatusOr<VkPhysicalDevice> FindPhysicalDevice(VulkanApi* vk, VkInstance instance)
+StatusOr<VkSurfaceKHR> 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<VkPhysicalDevice>(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<uint32_t> FindQueueFamily(VulkanApi* vk, VkPhysicalDevice physical_device)
+StatusOr<uint32_t> 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<uint32_t> 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<uint32_t> 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<VkPhysicalDevice>(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<VkDevice> CreateDevice(VulkanApi* vk, VkPhysicalDevice physical_device, uint32_t queue_family)
{
const float queue_priority = 1.0F;
@@ -150,7 +205,7 @@ StatusOr<VkDevice> 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<VulkanLoaderApi>();
@@ -166,32 +221,19 @@ Status InitializeVulkan(ApiRegistry* api_registry) loader_api->LoadInstance(vk, instance);
- VkPhysicalDevice physical_device{};
+ VkSurfaceKHR surface{};
{
- StatusOr<VkPhysicalDevice> s = FindPhysicalDevice(vk, instance);
+ StatusOr<VkSurfaceKHR> 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<uint32_t> 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;
}
@@ -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
|