diff options
| author | hachem <im@hachem.wtf> | 2026-08-19 20:33:30 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-08-19 20:33:30 +0200 |
| commit | e3abaaf59777258ba06705135a0cafcb5918ad12 (patch) | |
| tree | 889ab40dfc1967b38bcb5735e018d6b2c41d7390 /src/Core | |
| parent | f455eb427804866a5ce61ea3ea01715cb5ac9116 (diff) | |
[feat]: vulkan is going to be the end of me bro
Diffstat (limited to 'src/Core')
| -rw-r--r-- | src/Core/Application.cpp | 124 | ||||
| -rw-r--r-- | src/Core/Application.h | 4 | ||||
| -rw-r--r-- | src/Core/Window.cpp | 33 |
3 files changed, 118 insertions, 43 deletions
diff --git a/src/Core/Application.cpp b/src/Core/Application.cpp index df42877..c73dc6d 100644 --- a/src/Core/Application.cpp +++ b/src/Core/Application.cpp @@ -8,10 +8,14 @@ #include "States/WorldBuilderState.h" #include <GLFW/glfw3.h> +#include <imgui.h> #include <ImGuizmo.h> +#include "Platform/Vulkan/VulkanRenderer.h" + #ifdef __APPLE__ #include "Platform/Metal/MetalContext.h" +#include "Platform/Vulkan/VulkanContext.h" #endif namespace Donut @@ -23,8 +27,21 @@ namespace Donut { s_Instance = this; + // Select the render API before the window is created: the window is + // built differently for Vulkan (GLFW_NO_API) than for OpenGL. + Logger::Init(); + SettingsManager::Initialize(); + { + const auto& settings = SettingsManager::GetSettingsConst(); + RendererAPI::SetAPI(settings.graphics.renderAPI == "Vulkan" + ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL); + } + + if (RendererAPI::GetAPI() == RendererAPI::API::Vulkan) + VulkanPrepareGLFW(); // must precede glfwInit() inside the Window ctor + m_Window = CreateScope<Window>(name, width, height); - m_Window->SetEventCallback([this](Event& event) + m_Window->SetEventCallback([this](Event& event) { OnEvent(event); }); @@ -42,16 +59,39 @@ namespace Donut { while (m_Running) { - if (!m_Minimized) + if (m_VulkanRenderer) { - OnUpdate(); - OnRender(); + glfwPollEvents(); // before the ImGui frame so input is current + if (!m_Minimized) + m_VulkanRenderer->DrawFrame(glm::vec4(0.05f, 0.06f, 0.10f, 1.0f), + [this] { BuildVulkanUI(); }); + } + else + { + if (!m_Minimized) + { + OnUpdate(); + OnRender(); + } + m_Window->OnUpdate(); // polls events + swaps buffers (OpenGL) } - - m_Window->OnUpdate(); } } + void Application::BuildVulkanUI() + { + // Placeholder UI proving the ImGui Vulkan backend renders. The real + // application UI (states' OnImUIRender) moves here once the scene is + // ported to Vulkan (B-3). + ImGui::Begin("Donut - Vulkan backend"); + ImGui::Text("Geodesic black hole through Vulkan (MoltenVK)."); + ImGui::Text("%.1f FPS", ImGui::GetIO().Framerate); + ImGui::Separator(); + ImGui::TextWrapped("Drag to orbit, scroll to zoom. HDRI starfield is live; " + "next is porting the simulation UI to Vulkan."); + ImGui::End(); + } + void Application::Close() { m_Running = false; @@ -73,15 +113,24 @@ namespace Donut m_Minimized = true; else m_Minimized = false; - - Renderer::OnWindowResize(e.GetWidth(), e.GetHeight()); - m_Engine->SetWindowDimensions(e.GetWidth(), e.GetHeight()); + + if (m_VulkanRenderer) + { + m_VulkanRenderer->OnResize(e.GetWidth(), e.GetHeight()); + } + else + { + Renderer::OnWindowResize(e.GetWidth(), e.GetHeight()); + if (m_Engine) m_Engine->SetWindowDimensions(e.GetWidth(), e.GetHeight()); + } event.Handled = true; return true; }); - dispatcher.Dispatch<KeyPressedEvent>([this, &event](KeyPressedEvent& e) + dispatcher.Dispatch<KeyPressedEvent>([this, &event](KeyPressedEvent& e) { + if (!m_StateManager) + return true; if (e.GetKeyCode() == GLFW_KEY_1) { m_StateManager->SwitchToState("Config"); @@ -103,34 +152,38 @@ namespace Donut return true; }); - - m_StateManager->OnEvent(event); + + if (m_StateManager) + m_StateManager->OnEvent(event); } void Application::OnInit() { - Logger::Init(); + // (Logger, settings and API selection happen in the constructor.) + + if (RendererAPI::GetAPI() == RendererAPI::API::Vulkan) + { + int w = 0, h = 0; + glfwGetFramebufferSize((GLFWwindow*)m_Window->GetNativeWindow(), &w, &h); + m_VulkanRenderer = CreateScope<VulkanRenderer>(); + if (!m_VulkanRenderer->Init(m_Window->GetNativeWindow(), w, h)) + DONUT_ERROR("Vulkan renderer initialization failed"); + else + m_VulkanRenderer->InitImGui(); + // Scene rendering hooks in here in the B-3 phase; the Vulkan path now + // clears, presents, and draws the ImGui UI. + return; + } -#ifdef __APPLE__ - MetalProbe(); // Phase 1: native Metal device available? - MetalComputeSelfTest(); // Phase 1: full compute dispatch + read-back works? -#endif - - SettingsManager::Initialize(); - - const auto& settings = SettingsManager::GetSettingsConst(); - RendererAPI::API api = (settings.graphics.renderAPI == "Vulkan") ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL; - RendererAPI::SetAPI(api); - Renderer::Init(); m_Window->InitImGui(); - + Renderer::OnWindowResize(1280, 720); RenderCommand::SetFaceCulling(false); m_Engine = CreateScope<Engine>(); m_Engine->SetWindowDimensions(1280, 720); - + m_StateManager = CreateScope<StateManager>(); m_StateManager->RegisterState("Config", CreateScope<ConfigState>()); m_StateManager->RegisterState("Simulation", CreateScope<SimulationState>()); @@ -138,12 +191,19 @@ namespace Donut m_StateManager->SwitchToState("Config"); } - void Application::OnShutdown() - { - if (m_StateManager) - m_StateManager->Shutdown(); - - Renderer::Shutdown(); + void Application::OnShutdown() + { + if (m_VulkanRenderer) + { + m_VulkanRenderer->Shutdown(); + m_VulkanRenderer.reset(); + } + else + { + if (m_StateManager) + m_StateManager->Shutdown(); + Renderer::Shutdown(); + } SettingsManager::Shutdown(); Logger::Shutdown(); } diff --git a/src/Core/Application.h b/src/Core/Application.h index c16b6d9..b715170 100644 --- a/src/Core/Application.h +++ b/src/Core/Application.h @@ -10,6 +10,8 @@ namespace Donut { + class VulkanRenderer; // live-window Vulkan backend (Platform/Vulkan) + class Application { public: @@ -31,10 +33,12 @@ namespace Donut void OnRender(); void OnEvent(Event& event); void SetupDockingLayout(); + void BuildVulkanUI(); // ImGui UI built each frame on the Vulkan path private: Scope<StateManager> m_StateManager; Scope<Window> m_Window; Scope<Engine> m_Engine; + Scope<VulkanRenderer> m_VulkanRenderer; // non-null only when the Vulkan API is selected bool m_Running; bool m_Minimized; diff --git a/src/Core/Window.cpp b/src/Core/Window.cpp index c890979..ade0c26 100644 --- a/src/Core/Window.cpp +++ b/src/Core/Window.cpp @@ -1,6 +1,7 @@ #include <glad/glad.h> #include "Window.h" #include "ThemeManager.h" +#include "Rendering/Renderer.h" // RendererAPI::GetAPI() #include <cstdint> @@ -42,16 +43,24 @@ namespace Donut DONUT_INFO("GLFW initialized successfully"); } + if (RendererAPI::GetAPI() == RendererAPI::API::Vulkan) + { + // Vulkan manages presentation itself; GLFW must not create a GL context. + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + } + else + { #ifdef __APPLE__ - // macOS only exposes OpenGL up to 4.1 Core Profile, and requires a - // forward-compatible core-profile context for any modern (>= 3.3) - // shader to compile. Without these hints GLFW hands back a legacy - // 2.1 context and every GLSL shader in the project fails to build. - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); + // macOS only exposes OpenGL up to 4.1 Core Profile, and requires a + // forward-compatible core-profile context for any modern (>= 3.3) + // shader to compile. Without these hints GLFW hands back a legacy + // 2.1 context and every GLSL shader in the project fails to build. + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); #endif + } m_Window = glfwCreateWindow(m_Width, m_Height, m_Title.c_str(), nullptr, nullptr); if (!m_Window) @@ -63,7 +72,8 @@ namespace Donut DONUT_INFO("GLFW window created successfully"); - glfwMakeContextCurrent(m_Window); + if (RendererAPI::GetAPI() != RendererAPI::API::Vulkan) + glfwMakeContextCurrent(m_Window); glfwSetWindowUserPointer(m_Window, this); glfwSetErrorCallback(GLFWErrorCallback); @@ -100,7 +110,8 @@ namespace Donut void Window::OnUpdate() const { glfwPollEvents(); - glfwSwapBuffers(m_Window); + if (RendererAPI::GetAPI() != RendererAPI::API::Vulkan) + glfwSwapBuffers(m_Window); // Vulkan presents via the swapchain instead } bool Window::ShouldClose() const @@ -219,7 +230,7 @@ namespace Donut void Window::GLFWErrorCallback(int error, const char* description) { - DONUT_ERROR("GLFW Error (", error, "): ", description); + DONUT_ERROR("GLFW Error ({}): {}", error, description ? description : ""); } void Window::GLFWWindowCloseCallback(GLFWwindow* window) |
