From 84062873e162bc4a7c799fb67f72dbd055eb15ca Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Wed, 1 May 2024 01:23:05 +0200 Subject: Some work on WSI --- deimos/core/base.h | 15 ++++++ deimos/core/gsl.h | 2 + deimos/core/os.h | 14 ++++++ deimos/core/os_win32.cpp | 71 +++++++++++++++++++++++++++-- deimos/vulkan/vulkan_instance_functions.inc | 1 + main/BUILD | 3 ++ main/main.cpp | 36 +++++++++++---- todo.txt | 3 ++ 8 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 todo.txt diff --git a/deimos/core/base.h b/deimos/core/base.h index 70958a5..34a341f 100644 --- a/deimos/core/base.h +++ b/deimos/core/base.h @@ -104,6 +104,12 @@ public: deimos_DEFAULT_COPY_MOVE(Span); + template + constexpr Span(T (&data)[N]) : // NOLINT + m_begin{data}, + m_size{N} + {} + constexpr Span(T* begin, int64_t size) : m_begin{begin}, m_size{size} @@ -127,6 +133,7 @@ public: constexpr T* begin() const { return m_begin; } constexpr T* end() const { return m_begin + m_size; } // NOLINT constexpr int64_t size() const { return m_size; } + constexpr int64_t size_bytes() const { return m_size * (int64_t)sizeof(T); } constexpr bool empty() const { return m_size == 0; } constexpr T& operator[](int64_t i) const @@ -134,6 +141,13 @@ public: Expects(i >= 0 && i < m_size); return m_begin[i]; // NOLINT } + + constexpr Span subspan(int64_t offset, int64_t size) const + { + Expects(offset >= 0 && size >= 0); + Expects(offset + size <= m_size); + return Span(m_begin + offset, size); + } }; template @@ -163,6 +177,7 @@ public: constexpr const char* data() const { return m_begin; } constexpr int64_t size() const { return m_size; } + constexpr int64_t size_bytes() const { return m_size; } constexpr bool empty() const { return m_size == 0; } }; diff --git a/deimos/core/gsl.h b/deimos/core/gsl.h index d80d746..1270fa4 100644 --- a/deimos/core/gsl.h +++ b/deimos/core/gsl.h @@ -5,6 +5,8 @@ namespace gsl using zstring = char*; using czstring = const char*; +using wzstring = wchar_t*; +using cwzstring = const wchar_t*; template using owner = T; diff --git a/deimos/core/os.h b/deimos/core/os.h index 271ecfb..ecbe3cd 100644 --- a/deimos/core/os.h +++ b/deimos/core/os.h @@ -2,6 +2,7 @@ #include "deimos/core/base.h" #include "deimos/core/id_name.h" +#include "deimos/core/status.h" #include "deimos/core/io.h" namespace deimos @@ -49,6 +50,18 @@ public: virtual void Commit(void* ptr, int64_t size) = 0; }; +struct OsWindowHandle; + +class OsWindowApi +{ +public: + OsWindowApi() = default; + deimos_NO_COPY_MOVE(OsWindowApi); + virtual ~OsWindowApi() = default; + + virtual StatusOr> Create(gsl::czstring title, int32_t width, int32_t height) = 0; +}; + class OsApi { public: @@ -57,6 +70,7 @@ public: OsConsoleApi* console{}; OsDllApi* dll{}; OsVirtualMemoryApi* virtual_memory{}; + OsWindowApi* window{}; }; class OsConsoleWriter : public IWriter diff --git a/deimos/core/os_win32.cpp b/deimos/core/os_win32.cpp index d848530..fe904cd 100644 --- a/deimos/core/os_win32.cpp +++ b/deimos/core/os_win32.cpp @@ -8,6 +8,17 @@ namespace deimos { +gsl::cwzstring Utf8ToUtf16Z(StringView src, Span buffer) +{ + Expects(buffer.size() > 0 && buffer.size() > src.size()); + + int res = ::MultiByteToWideChar(CP_UTF8, 0, src.data(), (int)src.size_bytes(), buffer.data(), (int)buffer.size() - 1); + if (res < 0) { return L"< MBTWC ERROR >"; } + + buffer[res] = L'\0'; + return buffer.data(); +} + class Win32ConsoleApiImpl : public OsConsoleApi { HANDLE m_stdout; @@ -73,18 +84,68 @@ public: } }; +class Win32WindowApiImpl : public OsWindowApi +{ + static constexpr wchar_t kClassName[] = L"Deimos window class"; + + bool m_class_registered = false; + + void RegisterClass() + { + Expects(!m_class_registered); + + WNDCLASSW wnd_class{}; + wnd_class.lpfnWndProc = ::DefWindowProcW; + wnd_class.hInstance = ::GetModuleHandleW(nullptr); + wnd_class.lpszClassName = kClassName; + + ::RegisterClassW(&wnd_class); + + m_class_registered = true; + } + +public: + StatusOr> Create(gsl::czstring title, int32_t width, int32_t height) override + { + if (!m_class_registered) + { + RegisterClass(); + } + Ensures(m_class_registered); + + wchar_t title_w_buffer[128]{}; + gsl::cwzstring title_w = Utf8ToUtf16Z(title, title_w_buffer); + + HWND hwnd = ::CreateWindowExW( + 0, kClassName, title_w, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, width, height, + nullptr, nullptr, ::GetModuleHandle(nullptr), nullptr); + + if (hwnd == nullptr) + { + return InternalError("Error while creating Win32 window"); + } + + ::ShowWindow(hwnd, SW_SHOW); + + return nullptr; + } +}; + class Win32OsApiImpl : public OsApi { - Win32ConsoleApiImpl m_console_api; - Win32DllApiImpl m_dll_api; - Win32VirtualMemoryApiImpl m_virtual_memory_api; + Win32ConsoleApiImpl m_console_api; + Win32DllApiImpl m_dll_api; + Win32VirtualMemoryApiImpl m_virtual_memory_api; + Win32WindowApiImpl m_window_api; public: Win32OsApiImpl() { - console = &m_console_api; - dll = &m_dll_api; + console = &m_console_api; + dll = &m_dll_api; virtual_memory = &m_virtual_memory_api; + window = &m_window_api; } }; diff --git a/deimos/vulkan/vulkan_instance_functions.inc b/deimos/vulkan/vulkan_instance_functions.inc index c9862a5..48daf68 100644 --- a/deimos/vulkan/vulkan_instance_functions.inc +++ b/deimos/vulkan/vulkan_instance_functions.inc @@ -2,6 +2,7 @@ FN(EnumeratePhysicalDevices) FN(GetPhysicalDeviceProperties2) FN(GetPhysicalDeviceQueueFamilyProperties) +FN(GetPhysicalDeviceWin32PresentationSupportKHR) FN(DestroyInstance) FN(CreateDevice) FN(GetDeviceProcAddr) diff --git a/main/BUILD b/main/BUILD index 8e77f54..f9e432c 100644 --- a/main/BUILD +++ b/main/BUILD @@ -3,6 +3,9 @@ cc_binary( srcs = [ "main.cpp", ], + linkopts = [ + "User32.lib", + ], deps = [ "//deimos/vulkan", "//deimos/core", diff --git a/main/main.cpp b/main/main.cpp index e740c36..938d225 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -8,6 +9,7 @@ using namespace deimos; static LogApi* log_api; static TempAllocatorApi* temp_api; +static OsApi* os_api; static const VkAllocationCallbacks* kVkAlloc = nullptr; @@ -73,29 +75,33 @@ StatusOr FindPhysicalDevice(VulkanApi* vk, VkInstance instance vk->EnumeratePhysicalDevices(instance, &physical_device_count, devices.data()); // @Todo Physical device selection + // In fact, FindQueueFamily should be done here. return devices[0]; } -StatusOr FindQueueFamily(VulkanApi* vk, VkPhysicalDevice device) +StatusOr FindQueueFamily(VulkanApi* vk, VkPhysicalDevice physical_device) { auto temp_alloc = temp_api->Acquire(); uint32_t queue_family_count = 0; - vk->GetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr); + vk->GetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr); if (queue_family_count == 0) { - return InternalError("No queue on this physical device??"); + return InternalError("No queue on this physical device"); } log_api->LogInfo("Physical device has $ queue families", queue_family_count); auto queue_families = temp_alloc.allocator().NewArray(queue_family_count); - vk->GetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.data()); + vk->GetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families.data()); for (uint32_t index = 0; index < queue_family_count; ++index) { const auto& prps = queue_families[index]; - if ((prps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && (prps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0) + + bool supports_graphics_compute = (prps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && (prps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0; + bool supports_presentation = vk->GetPhysicalDeviceWin32PresentationSupportKHR(physical_device, index) == VK_TRUE; + if (supports_graphics_compute && supports_presentation) { return index; } @@ -104,7 +110,7 @@ StatusOr FindQueueFamily(VulkanApi* vk, VkPhysicalDevice device) return InternalError("Couldn't find a suitable queue"); } -StatusOr CreateDevice(VulkanApi* vk, VkPhysicalDevice gpu, uint32_t queue_family) +StatusOr CreateDevice(VulkanApi* vk, VkPhysicalDevice physical_device, uint32_t queue_family) { const float queue_priority = 1.0F; @@ -135,7 +141,7 @@ StatusOr CreateDevice(VulkanApi* vk, VkPhysicalDevice gpu, uint32_t qu }; VkDevice device = VK_NULL_HANDLE; - VkResult res = vk->CreateDevice(gpu, &create_info, kVkAlloc, &device); + VkResult res = vk->CreateDevice(physical_device, &create_info, kVkAlloc, &device); if (res != VK_SUCCESS) { return InternalError("vkCreateDeviceFailed"); @@ -168,7 +174,6 @@ Status InitializeVulkan(ApiRegistry* api_registry) } { - VkPhysicalDeviceVulkan12Properties prps12{}; prps12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; prps12.pNext = nullptr; @@ -215,14 +220,27 @@ int main(int /* argc */, char* /* argv */[]) auto* api_registry = InitializeGlobalApiRegistry(); log_api = api_registry->Get(); temp_api = api_registry->Get(); + os_api = api_registry->Get(); + log_api->LogInfo("Base APIs registered"); + OsWindowHandle* window{}; + { + auto s = os_api->window->Create("Deimos", 1280, 720); + if (!s.ok()) + { + log_api->LogError("Window error: $", s); + return 1; + } + window = s.value(); + } + const Status s = InitializeVulkan(api_registry); if (!s.ok()) { log_api->LogError("Vulkan initializaiton error: $", s); + return 1; } - log_api->LogInfo("OK"); diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..51cfd6b --- /dev/null +++ b/todo.txt @@ -0,0 +1,3 @@ +Smarter physical device selection @code +vulkan +Select layers & extensions based on config @code +vulkan +Last allocation optimization for temporary allocator @code +memory +core -- cgit