Started implementing Wgpu renderer

+ implemented basic setup code
+ implemented basic resize code
! renderer will default to GLES backend due to NV prime (Wgpu bug)
This commit is contained in:
Steins7 2022-07-02 23:25:33 +02:00
parent 091454922b
commit 8fb74a0381
7 changed files with 1500 additions and 29 deletions

1347
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,4 +9,11 @@ edition = "2021"
log = "^0.4.17"
chrono = "^0.4.19"
fern = { version = "^0.6.1", features = ["colored"] }
bitflags = "^1.3.2"
cgmath = "^0.18.0"
pollster = "^0.2.5"
winit = "^0.26.1"
raw-window-handle = "^0.4.3"
wgpu = "^0.13.0"

View File

@ -8,7 +8,7 @@ use crate::{
sprite::{Sprite, TextureSprite, TextSprite, ShapeSprite},
texture::Texture,
utils::{Size, Pixel, Position, Color},
renderer::Renderer,
renderer::WgpuRenderer,
};
use std::{
@ -26,15 +26,16 @@ pub trait Application {
//--Canvas struct-----------------------------------------------------------------------------------
pub struct Canvas {
renderer: Renderer,
renderer: WgpuRenderer,
clear_color: Pixel,
}
impl Canvas {
pub fn create<W: HasRawWindowHandle>(window: &W) -> Result<Canvas, &'static str> {
let renderer = Renderer::create(window)?;
pub async fn create<W: HasRawWindowHandle>(window: &W, size: Size)
-> Result<Canvas, &'static str>
{
let renderer = WgpuRenderer::create(window, size).await?;
Ok(Self {
renderer,
@ -73,13 +74,17 @@ impl Canvas {
//--Output functions--
pub fn draw<S: Sprite>(&mut self, sprite: &S) {
//update texture
self.renderer.draw(sprite);
self.renderer.render(sprite);
}
pub fn set_clear_color(&mut self, color: Pixel) {
self.clear_color = color;
}
pub fn set_size(&mut self, size: Size) {
self.renderer.resize(size);
}
pub fn clear(&mut self) {
self.renderer.clear(&self.clear_color);
}
@ -114,7 +119,7 @@ impl Canvas {
}
pub fn update(&mut self) {
self.renderer.finish_frame();
self.renderer.present();
}
}

View File

@ -1,6 +1,8 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use pollster::FutureExt;
mod canvas;
pub use canvas::Canvas;
pub use canvas::Application;
@ -29,8 +31,8 @@ pub fn run_canvas<A: 'static + Application>(title: &'static str, size: Size, mut
.expect("Failed to create window");
// construct canvas
let mut canvas = Canvas::create(&window)
.unwrap();
let size = window.inner_size();
let mut canvas = Canvas::create(&window, size.into()).block_on().unwrap();
// init application
app.init(&mut canvas).unwrap();
@ -46,22 +48,32 @@ pub fn run_canvas<A: 'static + Application>(title: &'static str, size: Size, mut
*control_flow = ControlFlow::Poll;
let _ = match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
match event {
Event::WindowEvent {event, ..} => match event {
WindowEvent::CloseRequested => {
info!("Close requested, shutting down...");
*control_flow = ControlFlow::Exit;
Ok(())
},
Event::MainEventsCleared => app.tick(&mut canvas),
WindowEvent::Resized (size) => {
canvas.set_size(size.into());
},
WindowEvent::ScaleFactorChanged {new_inner_size, ..} => {
// new_inner_size is &&mut so we have to dereference it twice
canvas.set_size((*new_inner_size).into());
},
_ => (),
},
Event::MainEventsCleared => {
let _ = app.tick(&mut canvas);
},
Event::RedrawRequested(_) => {
canvas.update();
Ok(())
let _ = canvas.update();
},
_ => Ok(())
}.unwrap();
_ => ()
};
});
}

View File

@ -19,7 +19,7 @@ fn setup_logger() -> Result<(), fern::InitError> {
message
))
})
.level(log::LevelFilter::Trace)
.level(log::LevelFilter::Debug)
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?)
.apply()?;

93
src/renderer.rs Normal file
View File

@ -0,0 +1,93 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use raw_window_handle::HasRawWindowHandle;
use wgpu;
use crate::{
sprite::Sprite,
utils::{Pixel, Size},
};
//--Renderer struct---------------------------------------------------------------------------------
pub struct WgpuRenderer {
surface: wgpu::Surface,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
size: Size,
}
impl WgpuRenderer {
pub async fn create<W: HasRawWindowHandle>(window: &W, size: Size)
-> Result<Self, &'static str>
{
if size.w == 0 || size.h == 0 {
return Err("window has zero as at least one of its dimensions");
}
let instance = wgpu::Instance::new(wgpu::Backends::all());
let surface = unsafe { instance.create_surface(window) };
let adapter = instance.request_adapter(
&wgpu::RequestAdapterOptions {
//for now, integrated GPU is enough, may be revised later
power_preference: wgpu::PowerPreference::LowPower,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
},
).await.unwrap();
let (device, queue) = adapter.request_device(
&wgpu::DeviceDescriptor {
//using minimum requirements possible since 2D isn't very demanding anyway
features: wgpu::Features::empty(),
limits: wgpu::Limits::downlevel_webgl2_defaults(),
label: None,
},
None, // Trace path
).await.unwrap();
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
//first format in the list is preferred
format: *surface.get_supported_formats(&adapter).first()
.ok_or_else(|| { "Surface is incompatible with current adapter" })?,
width: size.w,
height: size.h,
present_mode: wgpu::PresentMode::Fifo,
};
surface.configure(&device, &config);
Ok(Self {
surface,
device,
queue,
config,
size,
})
}
pub fn render<S: Sprite>(&mut self, _sprite: &S) {
unimplemented!();
}
pub fn resize(&mut self, size: Size) {
if size.w == 0 || size.h == 0 {
panic!("window has zero as at least one of its dimensions");
}
self.size = size;
self.config.width = size.w;
self.config.height = size.h;
self.surface.configure(&self.device, &self.config);
}
pub fn clear(&mut self, _color: &Pixel) {
unimplemented!();
}
pub fn present(&mut self) {
unimplemented!();
}
}

View File

@ -10,6 +10,7 @@ pub struct Position {
}
//--Size struct-------------------------------------------------------------------------------------
#[derive(Copy, Clone)]
pub struct Size {
pub w: u32,
pub h: u32,
@ -18,14 +19,24 @@ pub struct Size {
impl From<Size> for winit::dpi::Size {
fn from(size: Size) -> Self {
winit::dpi::Size::Logical (
winit::dpi::LogicalSize {
width: size.w.into(),
height: size.h.into()
winit::dpi::Size::Physical (
winit::dpi::PhysicalSize {
width: size.w,
height: size.h,
})
}
}
impl From<winit::dpi::PhysicalSize<u32>> for Size {
fn from(size: winit::dpi::PhysicalSize<u32>) -> Self {
Self {
w: size.width,
h: size.height,
}
}
}
//--Pixel struct------------------------------------------------------------------------------------
#[derive(Copy, Clone)]
struct Rgba {