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:
parent
091454922b
commit
8fb74a0381
1347
Cargo.lock
generated
1347
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,4 +9,11 @@ edition = "2021"
|
|||||||
log = "^0.4.17"
|
log = "^0.4.17"
|
||||||
chrono = "^0.4.19"
|
chrono = "^0.4.19"
|
||||||
fern = { version = "^0.6.1", features = ["colored"] }
|
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"
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::{
|
|||||||
sprite::{Sprite, TextureSprite, TextSprite, ShapeSprite},
|
sprite::{Sprite, TextureSprite, TextSprite, ShapeSprite},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
utils::{Size, Pixel, Position, Color},
|
utils::{Size, Pixel, Position, Color},
|
||||||
renderer::Renderer,
|
renderer::WgpuRenderer,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
@ -26,15 +26,16 @@ pub trait Application {
|
|||||||
|
|
||||||
//--Canvas struct-----------------------------------------------------------------------------------
|
//--Canvas struct-----------------------------------------------------------------------------------
|
||||||
pub struct Canvas {
|
pub struct Canvas {
|
||||||
renderer: Renderer,
|
renderer: WgpuRenderer,
|
||||||
clear_color: Pixel,
|
clear_color: Pixel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Canvas {
|
impl Canvas {
|
||||||
|
|
||||||
pub fn create<W: HasRawWindowHandle>(window: &W) -> Result<Canvas, &'static str> {
|
pub async fn create<W: HasRawWindowHandle>(window: &W, size: Size)
|
||||||
|
-> Result<Canvas, &'static str>
|
||||||
let renderer = Renderer::create(window)?;
|
{
|
||||||
|
let renderer = WgpuRenderer::create(window, size).await?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
renderer,
|
renderer,
|
||||||
@ -73,13 +74,17 @@ impl Canvas {
|
|||||||
//--Output functions--
|
//--Output functions--
|
||||||
pub fn draw<S: Sprite>(&mut self, sprite: &S) {
|
pub fn draw<S: Sprite>(&mut self, sprite: &S) {
|
||||||
//update texture
|
//update texture
|
||||||
self.renderer.draw(sprite);
|
self.renderer.render(sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_clear_color(&mut self, color: Pixel) {
|
pub fn set_clear_color(&mut self, color: Pixel) {
|
||||||
self.clear_color = color;
|
self.clear_color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_size(&mut self, size: Size) {
|
||||||
|
self.renderer.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.renderer.clear(&self.clear_color);
|
self.renderer.clear(&self.clear_color);
|
||||||
}
|
}
|
||||||
@ -114,7 +119,7 @@ impl Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
self.renderer.finish_frame();
|
self.renderer.present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
src/lib.rs
42
src/lib.rs
@ -1,6 +1,8 @@
|
|||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use pollster::FutureExt;
|
||||||
|
|
||||||
mod canvas;
|
mod canvas;
|
||||||
pub use canvas::Canvas;
|
pub use canvas::Canvas;
|
||||||
pub use canvas::Application;
|
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");
|
.expect("Failed to create window");
|
||||||
|
|
||||||
// construct canvas
|
// construct canvas
|
||||||
let mut canvas = Canvas::create(&window)
|
let size = window.inner_size();
|
||||||
.unwrap();
|
let mut canvas = Canvas::create(&window, size.into()).block_on().unwrap();
|
||||||
|
|
||||||
// init application
|
// init application
|
||||||
app.init(&mut canvas).unwrap();
|
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;
|
*control_flow = ControlFlow::Poll;
|
||||||
|
|
||||||
let _ = match event {
|
match event {
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::CloseRequested,
|
Event::WindowEvent {event, ..} => match event {
|
||||||
..
|
WindowEvent::CloseRequested => {
|
||||||
} => {
|
info!("Close requested, shutting down...");
|
||||||
info!("Close requested, shutting down...");
|
*control_flow = ControlFlow::Exit;
|
||||||
*control_flow = ControlFlow::Exit;
|
},
|
||||||
Ok(())
|
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::MainEventsCleared => app.tick(&mut canvas),
|
|
||||||
Event::RedrawRequested(_) => {
|
Event::RedrawRequested(_) => {
|
||||||
canvas.update();
|
let _ = canvas.update();
|
||||||
Ok(())
|
|
||||||
},
|
},
|
||||||
_ => Ok(())
|
|
||||||
}.unwrap();
|
_ => ()
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ fn setup_logger() -> Result<(), fern::InitError> {
|
|||||||
message
|
message
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.level(log::LevelFilter::Trace)
|
.level(log::LevelFilter::Debug)
|
||||||
.chain(std::io::stdout())
|
.chain(std::io::stdout())
|
||||||
.chain(fern::log_file("output.log")?)
|
.chain(fern::log_file("output.log")?)
|
||||||
.apply()?;
|
.apply()?;
|
||||||
|
|||||||
93
src/renderer.rs
Normal file
93
src/renderer.rs
Normal 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!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
19
src/utils.rs
19
src/utils.rs
@ -10,6 +10,7 @@ pub struct Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--Size struct-------------------------------------------------------------------------------------
|
//--Size struct-------------------------------------------------------------------------------------
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub struct Size {
|
pub struct Size {
|
||||||
pub w: u32,
|
pub w: u32,
|
||||||
pub h: u32,
|
pub h: u32,
|
||||||
@ -18,14 +19,24 @@ pub struct Size {
|
|||||||
impl From<Size> for winit::dpi::Size {
|
impl From<Size> for winit::dpi::Size {
|
||||||
|
|
||||||
fn from(size: Size) -> Self {
|
fn from(size: Size) -> Self {
|
||||||
winit::dpi::Size::Logical (
|
winit::dpi::Size::Physical (
|
||||||
winit::dpi::LogicalSize {
|
winit::dpi::PhysicalSize {
|
||||||
width: size.w.into(),
|
width: size.w,
|
||||||
height: size.h.into()
|
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------------------------------------------------------------------------------------
|
//--Pixel struct------------------------------------------------------------------------------------
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct Rgba {
|
struct Rgba {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user