From ea3641153e8e4de6204394afca73999fd7784b8b Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 16 Feb 2022 02:05:42 -0500 Subject: [PATCH] aurora: Dawn initialization --- CMakeLists.txt | 5 - aurora/CMakeLists.txt | 8 +- aurora/include/aurora/aurora.hpp | 4 +- aurora/include/aurora/common.hpp | 326 +++++++++++++++++++++++++++++++ aurora/lib/aurora.cpp | 176 ++++++++++++++++- 5 files changed, 508 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ca27b9dc..a9b31c2e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,11 +484,6 @@ target_include_directories(hecl-light PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(hecl-full PRIVATE zeus nod) target_link_libraries(hecl-light PRIVATE zeus nod) -add_subdirectory(extern/SDL EXCLUDE_FROM_ALL) -if (NOT MSVC) - target_compile_options(SDL2-static PRIVATE -Wno-implicit-fallthrough) -endif () - if(NOT TARGET atdna) # Import native atdna if cross-compiling find_package(atdna REQUIRED) diff --git a/aurora/CMakeLists.txt b/aurora/CMakeLists.txt index e38410963..a0bf0ab40 100644 --- a/aurora/CMakeLists.txt +++ b/aurora/CMakeLists.txt @@ -1,3 +1,8 @@ +add_subdirectory(../extern/SDL SDL2 EXCLUDE_FROM_ALL) +if (NOT MSVC) + target_compile_options(SDL2-static PRIVATE -Wno-implicit-fallthrough) +endif () + add_subdirectory(../extern/dawn dawn EXCLUDE_FROM_ALL) if (NOT MSVC) target_compile_options(SPIRV-Tools-static PRIVATE -Wno-implicit-fallthrough) @@ -7,4 +12,5 @@ endif () add_library(aurora STATIC lib/aurora.cpp lib/imgui.cpp lib/gfx/common.cpp) target_include_directories(aurora PUBLIC include ../Runtime) target_include_directories(aurora PRIVATE ../imgui ../extern/imgui) -target_link_libraries(aurora PRIVATE webgpu_dawn zeus logvisor) # TODO remove logvisor from rstl.hpp +target_link_libraries(aurora PRIVATE dawn_native dawncpp webgpu_dawn zeus logvisor SDL2-static) +target_compile_definitions(aurora PRIVATE AURORA_ENABLE_VULKAN AURORA_ENABLE_OPENGL) diff --git a/aurora/include/aurora/aurora.hpp b/aurora/include/aurora/aurora.hpp index 8cab4adae..4418b3ac6 100644 --- a/aurora/include/aurora/aurora.hpp +++ b/aurora/include/aurora/aurora.hpp @@ -1,5 +1,7 @@ #pragma once +#include "common.hpp" + #include #include #include @@ -220,7 +222,7 @@ struct AppDelegate { void app_run(std::unique_ptr app, Icon icon) noexcept; [[nodiscard]] std::vector get_args() noexcept; [[nodiscard]] WindowSize get_window_size() noexcept; -void set_window_title(std::string_view title) noexcept; +void set_window_title(zstring_view title) noexcept; [[nodiscard]] Backend get_backend() noexcept; [[nodiscard]] std::string_view get_backend_string() noexcept; void set_fullscreen(bool fullscreen) noexcept; diff --git a/aurora/include/aurora/common.hpp b/aurora/include/aurora/common.hpp index 007cc2b3d..cee65b348 100644 --- a/aurora/include/aurora/common.hpp +++ b/aurora/include/aurora/common.hpp @@ -69,4 +69,330 @@ private: const T* ptr = nullptr; size_t length = 0; }; + +template > +class basic_zstring_view; + +using zstring_view = basic_zstring_view; +using wzstring_view = basic_zstring_view; +using u16zstring_view = basic_zstring_view; +using u32zstring_view = basic_zstring_view; + +template +class basic_zstring_view { +public: + using underlying_type = std::basic_string_view; + + using traits_type = typename underlying_type::traits_type; + using value_type = typename underlying_type::value_type; + using pointer = typename underlying_type::pointer; + using const_pointer = typename underlying_type::const_pointer; + using reference = typename underlying_type::reference; + using const_reference = typename underlying_type::const_reference; + using const_iterator = typename underlying_type::const_iterator; + using iterator = typename underlying_type::iterator; + using const_reverse_iterator = typename underlying_type::const_reverse_iterator; + using reverse_iterator = typename underlying_type::reverse_iterator; + using size_type = typename underlying_type::size_type; + using difference_type = typename underlying_type::difference_type; + + static constexpr size_type npos = -1; + + constexpr basic_zstring_view() noexcept = default; + constexpr basic_zstring_view(const basic_zstring_view& other) noexcept = default; + constexpr basic_zstring_view(const CharT* s) : m_view{s} {} + constexpr basic_zstring_view(const std::string& str) : m_view{str.c_str()} {} + + // Needed as a workaround for gcc bug #61648 + // Allows non-friend string literal operators the ability to indirectly call the private constructor + // Safe calling of this requires *certainty* that s[count] is a null character + // Has to be public thusly, but don't call this + static constexpr basic_zstring_view _INTERNAL_unsafe_make_from_string_range(const CharT* s, size_type count) { + return {s, count}; + } + + constexpr basic_zstring_view& operator=(const basic_zstring_view& view) noexcept = default; + + constexpr const_iterator begin() const noexcept { return m_view.begin(); } + + constexpr const_iterator cbegin() const noexcept { return m_view.cbegin(); } + + constexpr const_iterator end() const noexcept { return m_view.end(); } + + constexpr const_iterator cend() const noexcept { return m_view.cend(); } + + constexpr const_reverse_iterator rbegin() const noexcept { return m_view.rbegin(); } + + constexpr const_reverse_iterator crbegin() const noexcept { return m_view.crbegin(); } + + constexpr const_reverse_iterator rend() const noexcept { return m_view.rend(); } + + constexpr const_reverse_iterator crend() const noexcept { return m_view.crend(); } + + constexpr const_reference operator[](size_type pos) const { return m_view[pos]; } + + constexpr const_reference at(size_type pos) const { return m_view.at(pos); } + + constexpr const_reference front() const { return m_view.front(); } + + constexpr const_reference back() const { return m_view.back(); } + + constexpr const_pointer data() const noexcept { return m_view.data(); } + + // Additional function + constexpr const_pointer c_str() const noexcept { return m_view.data(); } + + constexpr size_type size() const noexcept { return m_view.size(); } + + constexpr size_type length() const noexcept { return m_view.length(); } + + constexpr size_type max_size() const noexcept { return m_view.max_size(); } + + constexpr bool empty() const noexcept { return m_view.empty(); } + + constexpr void remove_prefix(size_type n) { m_view.remove_prefix(n); } + + constexpr void swap(basic_zstring_view& v) noexcept { swap(m_view, v.m_view); } + + size_type copy(CharT* dest, size_type count, size_type pos = 0) const { return m_view.copy(dest, count, pos); } + + constexpr underlying_type substr(size_type pos = 0, size_type count = npos) const { + return m_view.substr(pos, count); + } + + // Additional function + constexpr basic_zstring_view suffix(size_type start = 0) const { + return basic_zstring_view{m_view.substr(start, npos)}; + } + + constexpr int compare(underlying_type v) const noexcept { return m_view.compare(v); } + + constexpr int compare(size_type pos1, size_type count1, underlying_type v) const { + return m_view.compare(pos1, count1, v); + } + + constexpr int compare(size_type pos1, size_type count1, underlying_type v, size_type pos2, size_type count2) const { + return m_view.compare(pos1, count1, v, pos2, count2); + } + + constexpr int compare(const CharT* s) const { return m_view.compare(s); } + + constexpr int compare(size_type pos1, size_type count1, const CharT* s, size_type count2) const { + return m_view.compare(pos1, count1, s, count2); + } + + constexpr bool starts_with(underlying_type x) const noexcept { return m_view.starts_with(x); } + + constexpr bool starts_with(CharT x) const noexcept { return m_view.starts_with(x); } + + constexpr bool starts_with(const CharT* x) const { return m_view.starts_with(x); } + + constexpr bool ends_with(underlying_type x) const noexcept { return m_view.ends_with(x); } + + constexpr bool ends_with(CharT x) const noexcept { return m_view.ends_with(x); } + + constexpr bool ends_with(const CharT* x) const { return m_view.ends_with(x); } + + constexpr size_type find(underlying_type v, size_type pos = 0) const noexcept { return m_view.find(v, pos); } + + constexpr size_type find(CharT ch, size_type pos = 0) const noexcept { return m_view.find(ch, pos); } + + constexpr size_type find(const CharT* s, size_type pos, size_type count) const { return m_view.find(s, pos, count); } + + constexpr size_type find(const CharT* s, size_type pos = 0) const { return m_view.find(s, pos); } + + constexpr size_type rfind(underlying_type v, size_type pos = npos) const noexcept { return m_view.rfind(v, pos); } + + constexpr size_type rfind(CharT ch, size_type pos = npos) const noexcept { return m_view.rfind(ch, pos); } + + constexpr size_type rfind(const CharT* s, size_type pos, size_type count) const { + return m_view.rfind(s, pos, count); + } + + constexpr size_type rfind(const CharT* s, size_type pos = npos) const { return m_view.rfind(s, pos); } + + constexpr size_type find_first_of(underlying_type v, size_type pos = 0) const noexcept { + return m_view.find_first_of(v, pos); + } + + constexpr size_type find_first_of(CharT c, size_type pos = 0) const noexcept { return m_view.find_first_of(c, pos); } + + constexpr size_type find_first_of(const CharT* s, size_type pos, size_type count) const { + return m_view.find_first_of(s, pos, count); + } + + constexpr size_type find_first_of(const CharT* s, size_type pos = 0) const { return m_view.find_first_of(s, pos); } + + constexpr size_type find_last_of(underlying_type v, size_type pos = npos) const noexcept { + return m_view.find_last_of(v, pos); + } + + constexpr size_type find_last_of(CharT c, size_type pos = npos) const noexcept { return m_view.find_last_of(c, pos); } + + constexpr size_type find_last_of(const CharT* s, size_type pos, size_type count) const { + return m_view.find_last_of(s, pos, count); + } + + constexpr size_type find_last_of(const CharT* s, size_type pos = npos) const { return m_view.find_last_of(s, pos); } + + constexpr size_type find_first_not_of(underlying_type v, size_type pos = 0) const noexcept { + return m_view.find_first_not_of(v, pos); + } + + constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const noexcept { + return m_view.find_first_not_of(c, pos); + } + + constexpr size_type find_first_not_of(const CharT* s, size_type pos, size_type count) const { + return m_view.find_first_not_of(s, pos, count); + } + + constexpr size_type find_first_not_of(const CharT* s, size_type pos = 0) const { + return m_view.find_first_not_of(s, pos); + } + + constexpr size_type find_last_not_of(underlying_type v, size_type pos = npos) const noexcept { + return m_view.find_last_not_of(v, pos); + } + + constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const noexcept { + return m_view.find_last_not_of(c, pos); + } + + constexpr size_type find_last_not_of(const CharT* s, size_type pos, size_type count) const { + return m_view.find_last_not_of(s, pos, count); + } + + constexpr size_type find_last_not_of(const CharT* s, size_type pos = npos) const { + return m_view.find_last_not_of(s, pos); + } + + constexpr const underlying_type& view() const noexcept { return m_view; } + + constexpr operator underlying_type() const noexcept { return m_view; } + +private: + // Private constructor, called by the string literal operators + constexpr basic_zstring_view(const CharT* s, size_type count) : m_view{s, count} {} + + // Private constructor, needed by suffix() + explicit constexpr basic_zstring_view(const underlying_type& v) noexcept : m_view{v} {} + + underlying_type m_view; +}; + +template +constexpr bool operator==(basic_zstring_view lhs, basic_zstring_view rhs) noexcept { + return lhs.view() == rhs.view(); +} + +template +constexpr bool operator==(basic_zstring_view lhs, std::basic_string_view rhs) noexcept { + return lhs.view() == rhs; +} + +template +constexpr bool operator==(std::basic_string_view lhs, basic_zstring_view rhs) noexcept { + return lhs == rhs.view(); +} + +template +constexpr bool operator!=(basic_zstring_view lhs, basic_zstring_view rhs) noexcept { + return lhs.view() != rhs.view(); +} + +template +constexpr bool operator!=(basic_zstring_view lhs, std::basic_string_view rhs) noexcept { + return lhs.view() != rhs; +} + +template +constexpr bool operator!=(std::basic_string_view lhs, basic_zstring_view rhs) noexcept { + return lhs != rhs.view(); +} + +template +constexpr bool operator<(basic_zstring_view lhs, basic_zstring_view rhs) noexcept { + return lhs.view() < rhs.view(); +} + +template +constexpr bool operator<(basic_zstring_view lhs, std::basic_string_view rhs) noexcept { + return lhs.view() < rhs; +} + +template +constexpr bool operator<(std::basic_string_view lhs, basic_zstring_view rhs) noexcept { + return lhs < rhs.view(); +} + +template +constexpr bool operator<=(basic_zstring_view lhs, basic_zstring_view rhs) noexcept { + return lhs.view() <= rhs.view(); +} + +template +constexpr bool operator<=(basic_zstring_view lhs, std::basic_string_view rhs) noexcept { + return lhs.view() <= rhs; +} + +template +constexpr bool operator<=(std::basic_string_view lhs, basic_zstring_view rhs) noexcept { + return lhs <= rhs.view(); +} + +template +constexpr bool operator>(basic_zstring_view lhs, basic_zstring_view rhs) noexcept { + return lhs.view() > rhs.view(); +} + +template +constexpr bool operator>(basic_zstring_view lhs, std::basic_string_view rhs) noexcept { + return lhs.view() > rhs; +} + +template +constexpr bool operator>(std::basic_string_view lhs, basic_zstring_view rhs) noexcept { + return lhs > rhs.view(); +} + +template +constexpr bool operator>=(basic_zstring_view lhs, basic_zstring_view rhs) noexcept { + return lhs.view() >= rhs.view(); +} + +template +constexpr bool operator>=(basic_zstring_view lhs, std::basic_string_view rhs) noexcept { + return lhs.view() >= rhs; +} + +template +constexpr bool operator>=(std::basic_string_view lhs, basic_zstring_view rhs) noexcept { + return lhs >= rhs.view(); +} + +template +auto operator<<(std::basic_ostream& os, basic_zstring_view v) -> decltype(os) { + return os << v.view(); +} + +inline namespace literals { +inline namespace zstring_view_literals { +constexpr zstring_view operator""_zsv(const char* str, std::size_t len) noexcept { + return zstring_view::_INTERNAL_unsafe_make_from_string_range(str, len); +} + +constexpr u16zstring_view operator""_zsv(const char16_t* str, std::size_t len) noexcept { + return u16zstring_view::_INTERNAL_unsafe_make_from_string_range(str, len); +} + +constexpr u32zstring_view operator""_zsv(const char32_t* str, std::size_t len) noexcept { + return u32zstring_view::_INTERNAL_unsafe_make_from_string_range(str, len); +} + +constexpr wzstring_view operator""_zsv(const wchar_t* str, std::size_t len) noexcept { + return wzstring_view::_INTERNAL_unsafe_make_from_string_range(str, len); +} +} // namespace zstring_view_literals +} // namespace literals } // namespace aurora diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index 3211b3c7f..1732d214b 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -1,17 +1,185 @@ +#include #include +#include #include +#include +#ifdef AURORA_ENABLE_VULKAN +#include +#include +#endif +#ifdef AURORA_ENABLE_OPENGL +#include +#include +#endif +#include +#include namespace aurora { -void app_run(std::unique_ptr app, Icon icon) noexcept {} +static logvisor::Module Log("aurora"); + +// SDL +static SDL_Window* g_Window; + +// Dawn / WebGPU +#ifdef AURORA_ENABLE_VULKAN +static wgpu::BackendType backendType = wgpu::BackendType::Vulkan; +#elif AURORA_ENABLE_METAL +static wgpu::BackendType backendType = wgpu::BackendType::Metal; +#else +static wgpu::BackendType backendType = wgpu::BackendType::OpenGL; +#endif +static wgpu::SwapChain g_SwapChain; +static DawnSwapChainImplementation g_SwapChainImpl; +static wgpu::Queue g_Queue; +static wgpu::Device g_Device; +static wgpu::TextureFormat g_SwapChainFormat; + +static void set_window_icon(Icon icon) noexcept { + SDL_Surface* iconSurface = SDL_CreateRGBSurfaceFrom(icon.data.get(), icon.width, icon.height, 32, 4 * icon.width, +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff +#else + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 +#endif + ); + if (iconSurface == nullptr) { + Log.report(logvisor::Fatal, FMT_STRING("Failed to create icon surface: {}"), SDL_GetError()); + } + SDL_SetWindowIcon(g_Window, iconSurface); + SDL_FreeSurface(iconSurface); +} + +static bool poll_events() noexcept { + SDL_Event event; + while (SDL_PollEvent(&event) != 0) { + switch (event.type) { + case SDL_QUIT: + Log.report(logvisor::Info, FMT_STRING("Received quit request")); + return false; + } + // TODO why doesn't this work? + const auto typedEvent = magic_enum::enum_cast(event.type); + if (typedEvent) { + Log.report(logvisor::Info, FMT_STRING("Received SDL event: {}"), magic_enum::enum_name(typedEvent.value())); + } else { + Log.report(logvisor::Info, FMT_STRING("Received SDL event: {}"), event.type); + } + } + return true; +} + +void app_run(std::unique_ptr app, Icon icon) noexcept { + Log.report(logvisor::Info, FMT_STRING("Creating Dawn instance")); + auto instance = std::make_unique(); + instance->DiscoverDefaultAdapters(); + + dawn::native::Adapter backendAdapter; + { + std::vector adapters = instance->GetAdapters(); + auto adapterIt = std::find_if(adapters.begin(), adapters.end(), [](const dawn::native::Adapter adapter) -> bool { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + return properties.backendType == backendType; + }); + if (adapterIt == adapters.end()) { + Log.report(logvisor::Fatal, FMT_STRING("Failed to find usable graphics backend")); + } + backendAdapter = *adapterIt; + } + wgpu::AdapterProperties adapterProperties; + backendAdapter.GetProperties(&adapterProperties); + const auto backendName = magic_enum::enum_name(adapterProperties.backendType); + Log.report(logvisor::Info, FMT_STRING("Using {} graphics backend"), backendName); + + if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { + Log.report(logvisor::Fatal, FMT_STRING("Error initializing SDL: {}"), SDL_GetError()); + } + + Uint32 flags = SDL_WINDOW_SHOWN; + switch (adapterProperties.backendType) { +#ifdef AURORA_ENABLE_VULKAN + case wgpu::BackendType::Vulkan: + flags |= SDL_WINDOW_VULKAN; + break; +#endif +#ifdef AURORA_ENABLE_METAL + case wgpu::BackendType::Metal: + flags |= SDL_WINDOW_METAL; + break; +#endif +#ifdef AURORA_ENABLE_OPENGL + case wgpu::BackendType::OpenGL: + flags |= SDL_WINDOW_OPENGL; + break; +#endif + default: + break; + } + g_Window = SDL_CreateWindow("Metaforce", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, flags); + if (g_Window == nullptr) { + Log.report(logvisor::Fatal, FMT_STRING("Error creating window: {}"), SDL_GetError()); + } + set_window_icon(std::move(icon)); + + g_Device = wgpu::Device::Acquire(backendAdapter.CreateDevice()); + switch (adapterProperties.backendType) { +#ifdef AURORA_ENABLE_VULKAN + case wgpu::BackendType::Vulkan: { + VkSurfaceKHR surface = VK_NULL_HANDLE; + if (SDL_Vulkan_CreateSurface(g_Window, dawn::native::vulkan::GetInstance(g_Device.Get()), &surface) != SDL_TRUE) { + Log.report(logvisor::Fatal, FMT_STRING("Failed to create Vulkan surface: {}"), SDL_GetError()); + } + g_SwapChainImpl = dawn::native::vulkan::CreateNativeSwapChainImpl(g_Device.Get(), surface); + g_SwapChainFormat = + static_cast(dawn::native::vulkan::GetNativeSwapChainPreferredFormat(&g_SwapChainImpl)); + break; + } +#endif +#ifdef AURORA_ENABLE_METAL + case wgpu::BackendType::Metal: { + // TODO + g_SwapChainFormat = WGPUTextureFormat_BGRA8Unorm; + break; + } +#endif +#ifdef AURORA_ENABLE_OPENGL + case wgpu::BackendType::OpenGL: { + g_SwapChainImpl = dawn::native::opengl::CreateNativeSwapChainImpl( + g_Device.Get(), [](void* userdata) { SDL_GL_SwapWindow(static_cast(userdata)); }, g_Window); + g_SwapChainFormat = + static_cast(dawn::native::opengl::GetNativeSwapChainPreferredFormat(&g_SwapChainImpl)); + break; + } +#endif + default: + Log.report(logvisor::Fatal, FMT_STRING("Unsupported backend {}"), backendName); + } + + g_Queue = g_Device.GetQueue(); + { + wgpu::SwapChainDescriptor descriptor{}; + descriptor.implementation = reinterpret_cast(&g_SwapChainImpl); + g_SwapChain = g_Device.CreateSwapChain(nullptr, &descriptor); + } + { + int width, height; + SDL_GetWindowSize(g_Window, &width, &height); + g_SwapChain.Configure(g_SwapChainFormat, wgpu::TextureUsage::RenderAttachment, width, height); + } + + while (poll_events()) {} + + SDL_DestroyWindow(g_Window); + SDL_Quit(); +} + std::vector get_args() noexcept { return {}; // TODO } WindowSize get_window_size() noexcept { return {}; // TODO } -void set_window_title(std::string_view title) noexcept { - // TODO -} +void set_window_title(zstring_view title) noexcept { SDL_SetWindowTitle(g_Window, title.c_str()); } Backend get_backend() noexcept { return Backend::Vulkan; // TODO }