From e168f4e93f563e43f70e9308ea9072638ec818bf Mon Sep 17 00:00:00 2001 From: Caznix Date: Sun, 1 Dec 2024 22:58:52 -0500 Subject: [PATCH] draw with wgpu --- engine/src/core/mod.rs | 2 +- engine/src/core/renderer/ctx.rs | 100 ++++++++++++++++++++++++++++++++ engine/src/core/renderer/mod.rs | 35 +++++++---- engine/src/main.rs | 8 +-- 4 files changed, 129 insertions(+), 16 deletions(-) create mode 100644 engine/src/core/renderer/ctx.rs diff --git a/engine/src/core/mod.rs b/engine/src/core/mod.rs index deea4b7..cebc91e 100644 --- a/engine/src/core/mod.rs +++ b/engine/src/core/mod.rs @@ -8,7 +8,7 @@ use winit::event_loop::{ControlFlow, EventLoop}; -pub fn init_render() -> Result<()> { +pub fn init_renderer() -> Result<()> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); let mut app = App::default(); diff --git a/engine/src/core/renderer/ctx.rs b/engine/src/core/renderer/ctx.rs new file mode 100644 index 0000000..690ed0b --- /dev/null +++ b/engine/src/core/renderer/ctx.rs @@ -0,0 +1,100 @@ +use std::sync::Arc; + +use anyhow::Result; +use tokio::task::spawn_blocking; +use winit::window::Window; + +pub struct WgpuCtx<'window> { + device: wgpu::Device, + queue: wgpu::Queue, + surface: wgpu::Surface<'window>, + surface_config: wgpu::SurfaceConfiguration, + adapter: wgpu::Adapter, +} + +impl<'window> WgpuCtx<'window> { + pub async fn new(window: Arc) -> Result> { + let instnace = wgpu::Instance::default(); + let surface = instnace.create_surface(Arc::clone(&window))?; + let adapter = instnace + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::default(), + force_fallback_adapter: false, + compatible_surface: Some(&surface), + }) + .await + .expect("Failed to obtain render adapter"); + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_webgl2_defaults() + .using_resolution(adapter.limits()), + memory_hints: wgpu::MemoryHints::Performance, + }, + None, + ) + .await + .expect("Failed to create rendering device"); + + let size = window.inner_size(); + let width = size.width.max(1); + let height = size.height.max(1); + + let surface_config = surface.get_default_config(&adapter, width, height).unwrap(); + surface.configure(&device, &surface_config); + + Ok(WgpuCtx { + device: device, + queue: queue, + surface: surface, + surface_config: surface_config, + adapter: adapter, + }) + } + pub fn new_blocking(window: Arc) -> Result> { + tokio::task::block_in_place(|| { + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async { WgpuCtx::new(window).await }) + }) + } + pub fn resize(&mut self, new_size: (u32, u32)) { + let (width, height) = new_size; + self.surface_config.width = width.max(1); + self.surface_config.height = height.max(1); + self.surface.configure(&self.device, &self.surface_config); + } + pub fn draw(&mut self) { + let surface_texture = self + .surface + .get_current_texture() + .expect("Failed to get surface texture"); + let view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + } + self.queue.submit(Some(encoder.finish())); + surface_texture.present(); + } +} diff --git a/engine/src/core/renderer/mod.rs b/engine/src/core/renderer/mod.rs index 791f600..c6fcdab 100644 --- a/engine/src/core/renderer/mod.rs +++ b/engine/src/core/renderer/mod.rs @@ -1,22 +1,28 @@ -use log2::{debug, error}; +use std::sync::Arc; + +use ctx::WgpuCtx; +use log2::{debug, error, trace}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; -use winit::window::{Window, WindowId}; - +use winit::window::{self, Window, WindowId}; +pub mod ctx; #[derive(Default)] -pub struct App { - window: Option, +pub struct App<'window> { + window: Option>, + ctx: Option>, } -impl ApplicationHandler for App { +impl ApplicationHandler for App<'_> { fn resumed(&mut self, event_loop: &ActiveEventLoop) { if self.window.is_none() { let win_attr = Window::default_attributes().with_title("Zenyx"); - let window = event_loop + let window = Arc::new(event_loop .create_window(win_attr) - .expect("create window err."); - self.window = Some(window); + .expect("create window err.")); + self.window = Some(window.clone()); + let wgpu_ctx = WgpuCtx::new_blocking(window.clone()).unwrap(); + self.ctx = Some(wgpu_ctx) } } @@ -32,12 +38,21 @@ impl ApplicationHandler for App { debug!("Window closed, exiting"); std::process::exit(0) } + WindowEvent::RedrawRequested => { + if let Some(ctx) = &mut self.ctx { + ctx.draw(); + } + } WindowEvent::Resized(size) => { + if let (Some(wgpu_ctx),Some(window)) = (&mut self.ctx, &self.window) { + wgpu_ctx.resize(size.into()); + window.request_redraw(); let size_str: String = size.height.to_string() + "x" + &size.width.to_string(); //self.window.as_ref().unwrap().set_title(&format!("you reszed the window to {size_str}")); debug!("Window resized to {:?}", size_str); } - _ => error!("Unhandled window event"), + } + _ => trace!("Unhandled window event"), } } } \ No newline at end of file diff --git a/engine/src/main.rs b/engine/src/main.rs index c5e5729..5baa920 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -1,4 +1,3 @@ - use anyhow::Result; use log2::info; @@ -6,17 +5,16 @@ pub mod core; #[tokio::main] async fn main() -> Result<()> { - let _log2 = log2::open("z.log").tee(true).level("trace").start(); + let _log2 = log2::open("z.log").tee(true).level("debug").start(); info!("Initalizing Engine"); let shell_thread = tokio::task::spawn(async { info!("Shell thread started"); core::repl::handle_repl().await; - } -); + }); core::splash::print_splash(); info!("Engine Initalized"); - core::init_render()?; + core::init_renderer()?; shell_thread.await?; Ok(()) }