Basic window surface

This commit is contained in:
Jarrod Doyle 2024-03-07 17:01:02 +00:00
parent d25d006cec
commit 4cd1a3e7cd
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
5 changed files with 169 additions and 8 deletions

7
Cargo.lock generated
View File

@ -1039,6 +1039,12 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "pollster"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
[[package]] [[package]]
name = "presser" name = "presser"
version = "0.3.1" version = "0.3.1"
@ -1232,6 +1238,7 @@ dependencies = [
"anyhow", "anyhow",
"env_logger", "env_logger",
"log", "log",
"pollster",
"wgpu", "wgpu",
"winit", "winit",
] ]

View File

@ -9,5 +9,6 @@ edition = "2021"
anyhow = "1.0.80" anyhow = "1.0.80"
env_logger = "0.11.3" env_logger = "0.11.3"
log = "0.4.21" log = "0.4.21"
pollster = "0.3.0"
wgpu = "0.19.3" wgpu = "0.19.3"
winit = "0.29.14" winit = "0.29.14"

107
src/gfx/context.rs Normal file
View File

@ -0,0 +1,107 @@
use anyhow::Result;
use winit::{
dpi::PhysicalSize, event::WindowEvent, event_loop::EventLoopWindowTarget, window::Window,
};
pub struct Context<'w> {
pub window: &'w Window,
pub instance: wgpu::Instance,
pub size: PhysicalSize<u32>,
pub surface: wgpu::Surface<'w>,
pub surface_config: wgpu::SurfaceConfiguration,
pub adapter: wgpu::Adapter,
pub device: wgpu::Device,
pub queue: wgpu::Queue,
}
impl<'w> Context<'w> {
pub async fn new(window: &'w Window, limits: wgpu::Limits) -> Result<Self> {
log::info!("Initialising WGPU context...");
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::VULKAN,
dx12_shader_compiler: Default::default(),
..Default::default()
});
// To be able to start drawing we need a few things:
// - A surface
// - A GPU device to draw to the surface
// - A draw command queue
log::info!("Initialising window surface...");
let surface = instance.create_surface(window)?;
log::info!("Requesting GPU adapter...");
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
force_fallback_adapter: false,
compatible_surface: Some(&surface),
})
.await
.unwrap();
log::info!("Checking GPU adapter meets requirements");
log::info!("Requesting GPU device...");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::empty(),
required_limits: limits,
},
None,
)
.await
.unwrap();
log::info!("Configuring window surface...");
let size = window.inner_size();
let surface_config = surface
.get_default_config(&adapter, size.width, size.height)
.unwrap();
surface.configure(&device, &surface_config);
Ok(Self {
window,
instance,
size,
surface,
surface_config,
adapter,
device,
queue,
})
}
pub fn resize_surface(&mut self, new_size: PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 {
self.size = new_size;
self.surface_config.width = new_size.width;
self.surface_config.height = new_size.height;
self.surface.configure(&self.device, &self.surface_config);
}
}
pub fn handle_window_event(
&mut self,
event: &WindowEvent,
elwt: &EventLoopWindowTarget<()>,
) -> bool {
let mut handled = true;
match event {
WindowEvent::CloseRequested => {
elwt.exit();
}
WindowEvent::Resized(physical_size) => {
self.resize_surface(*physical_size);
}
WindowEvent::ScaleFactorChanged { .. } => {
self.resize_surface(self.window.inner_size());
}
_ => handled = false,
}
handled
}
}

3
src/gfx/mod.rs Normal file
View File

@ -0,0 +1,3 @@
mod context;
pub use self::context::Context;

View File

@ -1,8 +1,12 @@
mod gfx;
use anyhow::Result; use anyhow::Result;
use gfx::Context;
use wgpu::Limits;
use winit::{ use winit::{
dpi::LogicalSize, dpi::LogicalSize,
event::*, event::*,
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget}, event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
@ -10,15 +14,23 @@ pub fn main() -> Result<()> {
env_logger::init(); env_logger::init();
let (event_loop, window) = make_window()?; let (event_loop, window) = make_window()?;
run(event_loop, window)?; let context = pollster::block_on(Context::new(&window, Limits::default()))?;
run(event_loop, context)?;
Ok(()) Ok(())
} }
pub fn run(event_loop: EventLoop<()>, window: Window) -> Result<()> { pub fn run(event_loop: EventLoop<()>, mut context: Context) -> Result<()> {
event_loop.run(|event, elwt| match event { event_loop.run(|event, elwt| match event {
Event::WindowEvent { window_id, event } if window_id == window.id() => { Event::WindowEvent { window_id, event } if window_id == context.window.id() => {
handle_window_event(event, elwt); if context.handle_window_event(&event, elwt) {
return;
}
if let WindowEvent::RedrawRequested = event {
render(&context);
context.window.request_redraw();
}
} }
_ => (), _ => (),
})?; })?;
@ -38,8 +50,39 @@ fn make_window() -> Result<(EventLoop<()>, Window)> {
Ok((event_loop, window)) Ok((event_loop, window))
} }
fn handle_window_event(event: WindowEvent, elwt: &EventLoopWindowTarget<()>) { fn render(context: &Context) {
if let WindowEvent::CloseRequested = event { let output = context.surface.get_current_texture().unwrap();
elwt.exit(); let view = output
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = context
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
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,
occlusion_query_set: None,
timestamp_writes: None,
});
} }
// submit will accept anything that implements IntoIter
context.queue.submit(std::iter::once(encoder.finish()));
output.present();
} }