make winit optional and vsync configurable

This commit is contained in:
Carter Anderson 2020-03-27 17:43:03 -07:00
parent 93bf728475
commit a7704fda31
10 changed files with 160 additions and 118 deletions

View file

@ -5,14 +5,14 @@ authors = ["Carter Anderson <mcanders1@gmail.com>"]
edition = "2018"
[features]
default = ["wgpu"]
default = ["wgpu", "winit"]
[dependencies]
legion = { path = "bevy_legion", features = ["serialize"] }
wgpu = { git = "https://github.com/gfx-rs/wgpu-rs.git", rev = "a7b0d5ae5bc0934439ef559ed145e93f0117c39a", optional = true }
bitflags = "1.0"
glam = "0.8.6"
winit = "0.22.0"
winit = { version = "0.22.0", optional = true }
zerocopy = "0.3"
log = "0.4"
env_logger = "0.7"

View file

@ -1,21 +1,11 @@
use winit::{
event,
event::WindowEvent,
event_loop::{ControlFlow, EventLoop},
};
use crate::{app::AppBuilder, core::Time, render::renderer::Renderer};
use legion::prelude::*;
use crate::{
app::AppBuilder,
core::{Time, Window},
render::renderer::Renderer,
};
pub struct App {
pub universe: Universe,
pub world: World,
pub resources: Resources,
pub run: Option<Box<dyn Fn(App)>>,
pub renderer: Option<Box<dyn Renderer>>,
pub schedule: Schedule,
}
@ -26,6 +16,7 @@ impl App {
world: World,
schedule: Schedule,
resources: Resources,
run: Option<Box<dyn Fn(App)>>,
renderer: Option<Box<dyn Renderer>>,
) -> App {
App {
@ -33,6 +24,7 @@ impl App {
world,
schedule,
renderer,
run,
resources,
}
}
@ -41,7 +33,7 @@ impl App {
AppBuilder::new()
}
fn update(&mut self) {
pub fn update(&mut self) {
if let Some(mut time) = self.resources.get_mut::<Time>() {
time.start();
}
@ -56,76 +48,9 @@ impl App {
}
}
fn handle_event(&mut self, _: WindowEvent) {}
pub fn run(mut self) {
env_logger::init();
let event_loop = EventLoop::new();
log::info!("Initializing the window...");
let window = Window {
width: 1280,
height: 720,
};
let winit_window = winit::window::Window::new(&event_loop).unwrap();
winit_window.set_title("bevy");
winit_window.set_inner_size(winit::dpi::PhysicalSize::new(window.width, window.height));
self.resources.insert(window);
self.resources.insert(winit_window);
log::info!("Entering render loop...");
event_loop.run(move |event, _, control_flow| {
*control_flow = if cfg!(feature = "metal-auto-capture") {
ControlFlow::Exit
} else {
ControlFlow::Poll
};
match event {
event::Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
if let Some(ref mut renderer) = self.renderer {
{
let mut window = self.resources.get_mut::<Window>().unwrap();
window.width = size.width;
window.height = size.height;
}
renderer.resize(
&mut self.world,
&mut self.resources,
size.width,
size.height,
);
} else {
println!("no renderer {} {}", size.width, size.height);
}
}
event::Event::WindowEvent { event, .. } => match event {
WindowEvent::KeyboardInput {
input:
event::KeyboardInput {
virtual_keycode: Some(event::VirtualKeyCode::Escape),
state: event::ElementState::Pressed,
..
},
..
}
| WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
_ => {
self.handle_event(event);
}
},
event::Event::MainEventsCleared => {
self.update();
}
_ => (),
}
});
if let Some(run) = self.run.take() {
run(self)
}
}
}

View file

@ -1,7 +1,8 @@
use crate::{
app::{system_stage, App},
asset::*,
core::Time,
core::{Window, Time, window::winit::get_winit_run},
diagnostic::{diagnostics, Diagnostics},
legion::prelude::{Resources, Runnable, Schedulable, Schedule, Universe, World},
plugin::load_plugin,
prelude::StandardMaterial,
@ -9,7 +10,7 @@ use crate::{
draw_target::draw_targets::*, mesh::Mesh, pass::passes::*, pipeline::pipelines::*,
render_resource::resource_providers::*, renderer::Renderer, texture::Texture, *,
},
ui, diagnostic::{Diagnostics, diagnostics},
ui,
};
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
@ -20,13 +21,14 @@ use render_resource::{
EntityRenderResourceAssignments, RenderResourceAssignments,
};
use shader::Shader;
use std::{time::Duration, collections::HashMap};
use std::{collections::HashMap, time::Duration};
pub struct AppBuilder {
pub world: Option<World>,
pub resources: Option<Resources>,
pub universe: Option<Universe>,
pub renderer: Option<Box<dyn Renderer>>,
pub run: Option<Box<dyn Fn(App)>>,
pub render_graph: Option<RenderGraph>,
pub setup_systems: Vec<Box<dyn Schedulable>>,
pub system_stages: HashMap<String, Vec<Box<dyn Schedulable>>>,
@ -45,6 +47,7 @@ impl AppBuilder {
resources: Some(resources),
render_graph: Some(RenderGraph::default()),
renderer: None,
run: None,
setup_systems: Vec::new(),
system_stages: HashMap::new(),
runnable_stages: HashMap::new(),
@ -93,6 +96,7 @@ impl AppBuilder {
self.world.take().unwrap(),
schedule_builder.build(),
self.resources.take().unwrap(),
self.run.take(),
self.renderer.take(),
)
}
@ -159,6 +163,7 @@ impl AppBuilder {
pub fn add_default_resources(&mut self) -> &mut Self {
let resources = self.resources.as_mut().unwrap();
resources.insert(Window::default());
resources.insert(Time::new());
resources.insert(Diagnostics::default());
resources.insert(AssetStorage::<Mesh>::new());
@ -266,8 +271,20 @@ impl AppBuilder {
self
}
#[cfg(feature = "winit")]
pub fn add_winit(&mut self) -> &mut Self {
self.run = Some(get_winit_run());
self
}
#[cfg(not(feature = "winit"))]
pub fn add_winit(&mut self) -> &mut Self {
self
}
pub fn add_defaults(&mut self) -> &mut Self {
self.add_default_resources()
self.add_winit()
.add_default_resources()
.add_default_systems()
.add_render_graph_defaults()
.add_wgpu_renderer()

View file

@ -1,4 +0,0 @@
pub struct Window {
pub width: u32,
pub height: u32,
}

26
src/core/window/mod.rs Normal file
View file

@ -0,0 +1,26 @@
#[cfg(feature = "winit")]
pub mod winit;
use uuid::Uuid;
pub struct WindowId(Uuid);
pub struct Window {
pub id: Uuid,
pub width: u32,
pub height: u32,
pub title: String,
pub vsync: bool,
}
impl Default for Window {
fn default() -> Self {
Window {
id: Uuid::new_v4(),
title: "bevy".to_string(),
width: 1280,
height: 720,
vsync: true,
}
}
}

View file

@ -0,0 +1,74 @@
use crate::app::App;
use winit::{
event,
event::WindowEvent,
event_loop::{ControlFlow, EventLoop},
};
use super::Window;
pub fn get_winit_run() -> Box<dyn Fn(App)> {
Box::new(|mut app: App| {
env_logger::init();
let event_loop = EventLoop::new();
log::info!("Initializing the window...");
let winit_window = {
let window = app.resources.get::<Window>().unwrap();
let winit_window = winit::window::Window::new(&event_loop).unwrap();
winit_window.set_title(&window.title);
winit_window.set_inner_size(winit::dpi::PhysicalSize::new(window.width, window.height));
winit_window
};
app.resources.insert(winit_window);
log::info!("Entering render loop...");
event_loop.run(move |event, _, control_flow| {
*control_flow = if cfg!(feature = "metal-auto-capture") {
ControlFlow::Exit
} else {
ControlFlow::Poll
};
match event {
event::Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
if let Some(ref mut renderer) = app.renderer {
{
let mut window = app.resources.get_mut::<Window>().unwrap();
window.width = size.width;
window.height = size.height;
}
renderer.resize(
&mut app.world,
&mut app.resources,
);
} else {
println!("no renderer {} {}", size.width, size.height);
}
}
event::Event::WindowEvent { event, .. } => match event {
WindowEvent::KeyboardInput {
input:
event::KeyboardInput {
virtual_keycode: Some(event::VirtualKeyCode::Escape),
state: event::ElementState::Pressed,
..
},
..
}
| WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
_ => {}
},
event::Event::MainEventsCleared => {
app.update();
}
_ => (),
}
});
})
}

View file

@ -66,9 +66,9 @@ pub fn print_diagnostics_system(wait: Duration) -> Box<dyn Schedulable> {
elasped = 0.0;
for diagnostic in diagnostics.iter() {
if let Some(value) = diagnostic.value() {
println!("{}: {}", diagnostic.name, value);
println!("{}: {:.6}", diagnostic.name, value);
if let Some(average) = diagnostic.average() {
println!(" average: {}", average);
println!(" average: {:.6}", average);
}
}
}

View file

@ -11,7 +11,7 @@ use crate::{
use std::ops::Range;
pub trait Renderer {
fn resize(&mut self, world: &mut World, resources: &mut Resources, width: u32, height: u32);
fn resize(&mut self, world: &mut World, resources: &mut Resources);
fn update(&mut self, world: &mut World, resources: &mut Resources);
fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource;
fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource;

View file

@ -26,7 +26,6 @@ pub struct WgpuRenderer {
pub queue: wgpu::Queue,
pub surface: Option<wgpu::Surface>,
pub encoder: Option<wgpu::CommandEncoder>,
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub wgpu_resources: WgpuResources,
pub intialized: bool,
@ -49,21 +48,12 @@ impl WgpuRenderer {
limits: wgpu::Limits::default(),
});
let swap_chain_descriptor = wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
format: wgpu::TextureFormat::Bgra8UnormSrgb,
width: 0,
height: 0,
present_mode: wgpu::PresentMode::Vsync,
};
WgpuRenderer {
device: Rc::new(RefCell::new(device)),
queue,
surface: None,
encoder: None,
intialized: false,
swap_chain_descriptor,
wgpu_resources: WgpuResources::default(),
render_pipelines: HashMap::new(),
}
@ -76,13 +66,7 @@ impl WgpuRenderer {
self.create_surface(resources);
self.initialize_resource_providers(world, resources);
let (width, height) = {
let window = resources.get::<Window>().unwrap();
(window.width, window.height)
};
self.resize(world, resources, width, height);
self.resize(world, resources);
self.intialized = true;
}
@ -361,24 +345,27 @@ impl WgpuRenderer {
}
impl Renderer for WgpuRenderer {
fn resize(&mut self, world: &mut World, resources: &mut Resources, width: u32, height: u32) {
fn resize(&mut self, world: &mut World, resources: &mut Resources) {
self.encoder = Some(
self.device
.borrow()
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }),
);
self.swap_chain_descriptor.width = width;
self.swap_chain_descriptor.height = height;
let swap_chain_descriptor: wgpu::SwapChainDescriptor = {
let window: &Window = &resources.get::<Window>().unwrap();
window.into()
};
let swap_chain = self
.device
.borrow()
.create_swap_chain(self.surface.as_ref().unwrap(), &self.swap_chain_descriptor);
.create_swap_chain(self.surface.as_ref().unwrap(), &swap_chain_descriptor);
// WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues, so lets just store it in World.
resources.insert(swap_chain);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
for resource_provider in render_graph.resource_providers.iter_mut() {
resource_provider.resize(self, world, resources, width, height);
resource_provider.resize(self, world, resources, swap_chain_descriptor.width, swap_chain_descriptor.height);
}
// consume current encoder

View file

@ -1,4 +1,5 @@
use crate::{
core::Window,
prelude::Color,
render::{
pass::{LoadOp, StoreOp},
@ -473,3 +474,19 @@ impl From<FilterMode> for wgpu::FilterMode {
}
}
}
impl From<&Window> for wgpu::SwapChainDescriptor {
fn from(window: &Window) -> Self {
wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
format: wgpu::TextureFormat::Bgra8UnormSrgb,
width: window.width,
height: window.height,
present_mode: if window.vsync {
wgpu::PresentMode::Vsync
} else {
wgpu::PresentMode::NoVsync
},
}
}
}