hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-19 20:33:30 +0200
committerhachem <im@hachem.wtf>2026-08-19 20:33:30 +0200
commitdce67620b95a9555c7db950196b22f1bb88a307b (patch)
treef4aa836c3c512928a843620b28fe9d47ec52a7f2
parent62ae550170402a0fa0dbbbb2b739176d5c4bcf1e (diff)
feat: vulkan is going to be the end of me bro
-rw-r--r--premake5.lua13
-rw-r--r--src/core/application.cpp115
-rw-r--r--src/core/application.h4
-rw-r--r--src/core/window.cpp24
4 files changed, 114 insertions, 42 deletions
diff --git a/premake5.lua b/premake5.lua
index d0e17d3..2559098 100644
--- a/premake5.lua
+++ b/premake5.lua
@@ -363,10 +363,12 @@ project "Donut"
}
filter "system:macosx"
- -- Objective-C++ (Metal) sources compile only on macOS.
+ -- Objective-C++ (Metal) sources + the ImGui Vulkan backend compile only
+ -- on macOS (Vulkan headers come from Homebrew there).
files
{
- "src/**.mm"
+ "src/**.mm",
+ "ext/imgui/backends/imgui_impl_vulkan.cpp"
}
-- Compile the Slang shaders to assets/shaders/generated/ before building.
@@ -376,6 +378,10 @@ project "Donut"
'bash "%{wks.location}/tools/compile-shaders.sh"'
}
+ -- Vulkan (via MoltenVK) from Homebrew; see tools/vulkan-env.sh for runtime.
+ includedirs { "/opt/homebrew/include" }
+ libdirs { "/opt/homebrew/lib" }
+
links
{
"Cocoa.framework",
@@ -383,7 +389,8 @@ project "Donut"
"CoreFoundation.framework",
"QuartzCore.framework",
"Metal.framework",
- "Foundation.framework"
+ "Foundation.framework",
+ "vulkan"
}
filter "configurations:Debug"
diff --git a/src/core/application.cpp b/src/core/application.cpp
index fa5fd6e..0f07979 100644
--- a/src/core/application.cpp
+++ b/src/core/application.cpp
@@ -8,10 +8,14 @@
#include "states/world_builder_state.h"
#include <GLFW/glfw3.h>
+#include <imgui.h>
#include <ImGuizmo.h>
+#include "platform/vulkan/vulkan_renderer.h"
+
#ifdef __APPLE__
#include "platform/metal/metal_context.h"
+#include "platform/vulkan/vulkan_context.h"
#endif
namespace Donut
@@ -23,8 +27,19 @@ namespace Donut
{
s_instance = this;
+ Logger::init();
+ SettingsManager::initialize();
+ {
+ const auto& settings = SettingsManager::get_settings_const();
+ RendererAPI::set_api(settings.graphics.render_api == "Vulkan"
+ ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL);
+ }
+
+ if (RendererAPI::get_api() == RendererAPI::API::Vulkan)
+ vulkan_prepare_glfw();
+
m_window = create_scope<Window>(name, width, height);
- m_window->set_event_callback([this](Event& event)
+ m_window->set_event_callback([this](Event& event)
{
on_event(event);
});
@@ -42,16 +57,36 @@ namespace Donut
{
while (m_running)
{
- if (!m_minimized)
+ if (m_vulkan_renderer)
{
- on_update();
- on_render();
+ glfwPollEvents();
+ if (!m_minimized)
+ m_vulkan_renderer->draw_frame(glm::vec4(0.05f, 0.06f, 0.10f, 1.0f),
+ [this] { build_vulkan_ui(); });
+ }
+ else
+ {
+ if (!m_minimized)
+ {
+ on_update();
+ on_render();
+ }
+ m_window->on_update();
}
-
- m_window->on_update();
}
}
+ void Application::build_vulkan_ui()
+ {
+ 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 +108,24 @@ namespace Donut
m_minimized = true;
else
m_minimized = false;
-
- Renderer::on_window_resize(e.get_width(), e.get_height());
- m_engine->set_window_dimensions(e.get_width(), e.get_height());
+
+ if (m_vulkan_renderer)
+ {
+ m_vulkan_renderer->on_resize(e.get_width(), e.get_height());
+ }
+ else
+ {
+ Renderer::on_window_resize(e.get_width(), e.get_height());
+ if (m_engine) m_engine->set_window_dimensions(e.get_width(), e.get_height());
+ }
event.handled = true;
return true;
});
- dispatcher.dispatch<KeyPressedEvent>([this, &event](KeyPressedEvent& e)
+ dispatcher.dispatch<KeyPressedEvent>([this, &event](KeyPressedEvent& e)
{
+ if (!m_state_manager)
+ return true;
if (e.get_key_code() == GLFW_KEY_1)
{
m_state_manager->switch_to_state("Config");
@@ -103,34 +147,34 @@ namespace Donut
return true;
});
-
- m_state_manager->on_event(event);
+
+ if (m_state_manager)
+ m_state_manager->on_event(event);
}
void Application::on_init()
{
- Logger::init();
+ if (RendererAPI::get_api() == RendererAPI::API::Vulkan)
+ {
+ int w = 0, h = 0;
+ glfwGetFramebufferSize((GLFWwindow*)m_window->get_native_window(), &w, &h);
+ m_vulkan_renderer = create_scope<VulkanRenderer>();
+ if (!m_vulkan_renderer->init(m_window->get_native_window(), w, h))
+ DONUT_ERROR("Vulkan renderer initialization failed");
+ else
+ m_vulkan_renderer->init_im_gui();
+ return;
+ }
-#ifdef __APPLE__
- metal_probe();
- metal_compute_self_test();
-#endif
-
- SettingsManager::initialize();
-
- const auto& settings = SettingsManager::get_settings_const();
- RendererAPI::API api = (settings.graphics.render_api == "Vulkan") ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL;
- RendererAPI::set_api(api);
-
Renderer::init();
m_window->init_im_gui();
-
+
Renderer::on_window_resize(1280, 720);
RenderCommand::set_face_culling(false);
m_engine = create_scope<Engine>();
m_engine->set_window_dimensions(1280, 720);
-
+
m_state_manager = create_scope<StateManager>();
m_state_manager->register_state("Config", create_scope<ConfigState>());
m_state_manager->register_state("Simulation", create_scope<SimulationState>());
@@ -138,12 +182,19 @@ namespace Donut
m_state_manager->switch_to_state("Config");
}
- void Application::on_shutdown()
- {
- if (m_state_manager)
- m_state_manager->shutdown();
-
- Renderer::shutdown();
+ void Application::on_shutdown()
+ {
+ if (m_vulkan_renderer)
+ {
+ m_vulkan_renderer->shutdown();
+ m_vulkan_renderer.reset();
+ }
+ else
+ {
+ if (m_state_manager)
+ m_state_manager->shutdown();
+ Renderer::shutdown();
+ }
SettingsManager::shutdown();
Logger::shutdown();
}
diff --git a/src/core/application.h b/src/core/application.h
index 8e13f7b..3c76dcc 100644
--- a/src/core/application.h
+++ b/src/core/application.h
@@ -10,6 +10,8 @@
namespace Donut
{
+ class VulkanRenderer;
+
class Application
{
public:
@@ -31,10 +33,12 @@ namespace Donut
void on_render();
void on_event(Event& event);
void setup_docking_layout();
+ void build_vulkan_ui();
private:
Scope<StateManager> m_state_manager;
Scope<Window> m_window;
Scope<Engine> m_engine;
+ Scope<VulkanRenderer> m_vulkan_renderer;
bool m_running;
bool m_minimized;
diff --git a/src/core/window.cpp b/src/core/window.cpp
index cb93d04..0a9ac8b 100644
--- a/src/core/window.cpp
+++ b/src/core/window.cpp
@@ -1,6 +1,7 @@
#include <glad/glad.h>
#include "window.h"
#include "theme_manager.h"
+#include "rendering/renderer.h"
#include <cstdint>
@@ -42,12 +43,19 @@ namespace Donut
DONUT_INFO("GLFW initialized successfully");
}
+ if (RendererAPI::get_api() == RendererAPI::API::Vulkan)
+ {
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ }
+ else
+ {
#ifdef __APPLE__
- 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);
+ 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)
@@ -59,7 +67,8 @@ namespace Donut
DONUT_INFO("GLFW window created successfully");
- glfwMakeContextCurrent(m_window);
+ if (RendererAPI::get_api() != RendererAPI::API::Vulkan)
+ glfwMakeContextCurrent(m_window);
glfwSetWindowUserPointer(m_window, this);
glfwSetErrorCallback(glfw_error_callback);
@@ -96,7 +105,8 @@ namespace Donut
void Window::on_update() const
{
glfwPollEvents();
- glfwSwapBuffers(m_window);
+ if (RendererAPI::get_api() != RendererAPI::API::Vulkan)
+ glfwSwapBuffers(m_window);
}
bool Window::should_close() const
@@ -208,7 +218,7 @@ namespace Donut
void Window::glfw_error_callback(int error, const char* description)
{
- DONUT_ERROR("GLFW Error (", error, "): ", description);
+ DONUT_ERROR("GLFW Error ({}): {}", error, description ? description : "");
}
void Window::glfw_window_close_callback(GLFWwindow* window)