wip: add init egui impl

This commit is contained in:
zack 2025-03-31 14:54:56 -04:00
parent f71f0d8e10
commit b1c164dc6a
No known key found for this signature in database
GPG key ID: EE8A2B709E2401D1
4 changed files with 790 additions and 55 deletions

724
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@ edition = "2021"
egui.workspace = true egui.workspace = true
ash.workspace = true ash.workspace = true
ash-window.workspace = true ash-window.workspace = true
color-eyre.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true
winit.workspace = true winit.workspace = true
@ -17,3 +18,4 @@ gfx_hal = { path = "../gfx_hal" }
renderer = { path = "../renderer" } renderer = { path = "../renderer" }
resource_manager = { path = "../resource_manager" } resource_manager = { path = "../resource_manager" }
clap = { version = "4.5.34", features = ["derive"] } clap = { version = "4.5.34", features = ["derive"] }
egui-winit = "0.31.1"

View file

@ -8,6 +8,8 @@ use std::{
use ash::vk; use ash::vk;
use clap::Parser; use clap::Parser;
use egui::{Context, ViewportId};
use egui_winit::State;
use gfx_hal::{ use gfx_hal::{
device::Device, error::GfxHalError, instance::Instance, instance::InstanceConfig, device::Device, error::GfxHalError, instance::Instance, instance::InstanceConfig,
physical_device::PhysicalDevice, queue::Queue, surface::Surface, physical_device::PhysicalDevice, queue::Queue, surface::Surface,
@ -57,6 +59,10 @@ struct Application {
// Renderer // Renderer
renderer: Renderer, renderer: Renderer,
egui_ctx: Context,
egui_winit: State,
egui_app: EditorUI,
// Windowing // Windowing
window: Arc<Window>, // Use Arc for potential multi-threading later window: Arc<Window>, // Use Arc for potential multi-threading later
@ -65,6 +71,19 @@ struct Application {
last_frame_time: Instant, last_frame_time: Instant,
} }
#[derive(Default)]
struct EditorUI {}
impl EditorUI {
fn title() -> String {
"engine".to_string()
}
fn build_ui(&mut self, ctx: &egui::Context) {
egui::Window::new(Self::title()).show(ctx, |ui| ui.label(Self::title()));
}
}
#[derive(Default)] #[derive(Default)]
struct ApplicationWrapper { struct ApplicationWrapper {
app: Option<Application>, app: Option<Application>,
@ -223,14 +242,6 @@ impl Application {
// Get specific queues (assuming graphics and present are the same for simplicity) // Get specific queues (assuming graphics and present are the same for simplicity)
let graphics_queue = device.get_graphics_queue(); let graphics_queue = device.get_graphics_queue();
let queue_associated_device_handle = graphics_queue.device().raw().handle(); let queue_associated_device_handle = graphics_queue.device().raw().handle();
info!(
"App: Queue is associated with Device handle: {:?}",
queue_associated_device_handle
);
assert_eq!(
device_handle_at_creation, queue_associated_device_handle,
"Device handle mismatch immediately after queue creation!"
);
// --- 4. Resource Manager --- // --- 4. Resource Manager ---
let resource_manager = Arc::new(ResourceManager::new(instance.clone(), device.clone())?); let resource_manager = Arc::new(ResourceManager::new(instance.clone(), device.clone())?);
@ -238,14 +249,6 @@ impl Application {
let renderer_device_handle_to_pass = device.raw().handle(); let renderer_device_handle_to_pass = device.raw().handle();
let renderer_queue_device_handle_to_pass = graphics_queue.device().raw().handle(); let renderer_queue_device_handle_to_pass = graphics_queue.device().raw().handle();
info!(
"App: Passing Device handle to Renderer: {:?}",
renderer_device_handle_to_pass
);
info!(
"App: Passing Queue associated with Device handle: {:?}",
renderer_queue_device_handle_to_pass
);
// --- 5. Renderer --- // --- 5. Renderer ---
let initial_size = window.inner_size(); let initial_size = window.inner_size();
@ -258,6 +261,18 @@ impl Application {
initial_size.width, initial_size.width,
initial_size.height, initial_size.height,
)?; )?;
let egui_ctx = Context::default();
let egui_winit = State::new(
egui_ctx.clone(),
ViewportId::ROOT,
&window,
None,
None,
None,
);
let egui_app = EditorUI::default();
info!("Renderer initialized."); info!("Renderer initialized.");
Ok(Self { Ok(Self {
@ -269,6 +284,9 @@ impl Application {
_resource_manager: resource_manager, _resource_manager: resource_manager,
renderer, renderer,
window, window,
egui_winit,
egui_ctx,
egui_app,
frame_count: 0, frame_count: 0,
last_fps_update_time: Instant::now(), last_fps_update_time: Instant::now(),
last_frame_time: Instant::now(), last_frame_time: Instant::now(),
@ -320,8 +338,29 @@ impl Application {
self.last_fps_update_time = now; self.last_fps_update_time = now;
} }
let raw_input = self.egui_winit.take_egui_input(&self.window);
let egui::FullOutput {
platform_output,
textures_delta,
shapes,
pixels_per_point,
..
} = self.egui_ctx.run(raw_input, |ctx| {
self.egui_app.build_ui(ctx);
});
self.egui_winit
.handle_platform_output(&self.window, platform_output);
let clipped_primitives = self.egui_ctx.tessellate(shapes, pixels_per_point);
// --- Render Frame --- // --- Render Frame ---
match self.renderer.render_frame() { match self.renderer.render_frame(
pixels_per_point,
textures_delta,
&clipped_primitives,
) {
Ok(_) => { Ok(_) => {
self.window.request_redraw(); self.window.request_redraw();
} }
@ -450,6 +489,7 @@ struct Args {
// --- Entry Point --- // --- Entry Point ---
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
color_eyre::install()?;
let args = Args::parse(); let args = Args::parse();
let fmt_layer = tracing_subscriber::fmt::layer() let fmt_layer = tracing_subscriber::fmt::layer()

View file

@ -4,6 +4,7 @@ use std::{
}; };
use ash::vk; use ash::vk;
use egui::{ClippedPrimitive, TextureId, TexturesDelta};
use egui_ash_renderer::{DynamicRendering, Options, Renderer as EguiRenderer}; use egui_ash_renderer::{DynamicRendering, Options, Renderer as EguiRenderer};
use gfx_hal::{ use gfx_hal::{
device::Device, error::GfxHalError, queue::Queue, surface::Surface, swapchain::Swapchain, device::Device, error::GfxHalError, queue::Queue, surface::Surface, swapchain::Swapchain,
@ -61,6 +62,7 @@ struct FrameData {
command_buffer: vk::CommandBuffer, command_buffer: vk::CommandBuffer,
image_available_semaphore: Semaphore, image_available_semaphore: Semaphore,
render_finished_semaphore: Semaphore, render_finished_semaphore: Semaphore,
textures_to_free: Option<Vec<TextureId>>,
in_flight_fence: Fence, in_flight_fence: Fence,
} }
@ -140,7 +142,10 @@ impl Renderer {
color_attachment_format: swapchain.format().format, color_attachment_format: swapchain.format().format,
depth_attachment_format: Some(depth_format), depth_attachment_format: Some(depth_format),
}, },
Options::default(), Options {
srgb_framebuffer: true,
..Default::default()
},
)?; )?;
Ok(Self { Ok(Self {
@ -178,7 +183,12 @@ impl Renderer {
} }
} }
pub fn render_frame(&mut self) -> Result<(), RendererError> { pub fn render_frame(
&mut self,
pixels_per_point: f32,
textures_delta: TexturesDelta,
clipped_primitives: &[ClippedPrimitive],
) -> Result<(), RendererError> {
// --- Handle Resize --- // --- Handle Resize ---
if self.window_resized { if self.window_resized {
self.window_resized = false; self.window_resized = false;
@ -190,7 +200,7 @@ impl Renderer {
// --- Wait for Previous Frame --- // --- Wait for Previous Frame ---
let frame_index = self.current_frame; let frame_index = self.current_frame;
let frame_data = &self.frames_data[frame_index]; let frame_data = &mut self.frames_data[frame_index];
frame_data.in_flight_fence.wait(None)?; // Wait indefinitely frame_data.in_flight_fence.wait(None)?; // Wait indefinitely
@ -219,6 +229,11 @@ impl Renderer {
// --- Reset Fence (only after successful acquisition) --- // --- Reset Fence (only after successful acquisition) ---
frame_data.in_flight_fence.reset()?; frame_data.in_flight_fence.reset()?;
if let Some(textures) = frame_data.textures_to_free.take() {
tracing::debug!("Freeing EGUI Textures");
self.egui_renderer.free_textures(&textures)?;
}
// --- Record Command Buffer --- // --- Record Command Buffer ---
unsafe { unsafe {
// Need unsafe for Vulkan commands // Need unsafe for Vulkan commands
@ -238,6 +253,29 @@ impl Renderer {
.begin_command_buffer(command_buffer, &cmd_begin_info)?; .begin_command_buffer(command_buffer, &cmd_begin_info)?;
} }
if !textures_delta.free.is_empty() {
tracing::debug!("Setting textures to free");
frame_data.textures_to_free = Some(textures_delta.free.clone());
}
if !textures_delta.set.is_empty() {
tracing::trace!("Setting EGUI textures");
self.egui_renderer.set_textures(
self.device.get_graphics_queue().handle(),
frame_data.command_pool,
textures_delta.set.as_slice(),
)?;
}
tracing::info!("Rendering EGUI");
self.egui_renderer.cmd_draw(
command_buffer,
self.swapchain_extent,
pixels_per_point,
clipped_primitives,
)?;
tracing::debug!("Rendered EGUI");
let current_swapchain_image = swapchain_ref.images()[image_index as usize]; let current_swapchain_image = swapchain_ref.images()[image_index as usize];
let initial_layout_transition_barrier = vk::ImageMemoryBarrier::default() let initial_layout_transition_barrier = vk::ImageMemoryBarrier::default()
@ -862,6 +900,7 @@ impl Renderer {
}; };
frames_data.push(FrameData { frames_data.push(FrameData {
textures_to_free: None,
command_pool, command_pool,
command_buffer, // Stays allocated, just reset/rerecorded command_buffer, // Stays allocated, just reset/rerecorded
image_available_semaphore, image_available_semaphore,