From e755d3b1d8965fcb268c2ae44ded4c625d7b7731 Mon Sep 17 00:00:00 2001 From: Till Date: Thu, 25 Jun 2020 00:59:10 +0200 Subject: [PATCH] Fix and module update --- Cargo.toml | 24 ++-- src/input.rs | 73 ++++++---- src/main.rs | 60 ++++---- src/vulkan.rs | 371 +++++++++++++++++++++----------------------------- 4 files changed, 235 insertions(+), 293 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6d4e9d9..88a38f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,16 +5,14 @@ authors = ["Till "] edition = "2018" [dependencies] -vulkano-shaders = "0.13" -vulkano = "0.13" -vulkano-win = "0.13" -shade_runner = "0.1.2" -shaderc = "0.5.0" -cgmath = "0.17" -winit = "0.19" -image = "0.22.0" -serde = "1.0.97" -serde_derive = "1.0.97" -toml = "0.5.1" -gilrs = "0.7.1" -gltf = "0.13.0" \ No newline at end of file +vulkano-shaders = "0.19.0" +vulkano = "0.19.0" +vulkano-win = "0.19.0" +cgmath = "0.17.0" +winit = "0.22.2" +image = "0.23.6" +serde = "1.0.114" +serde_derive = "1.0.114" +toml = "0.5.6" +gilrs = "0.7.4" +gltf = "0.15.2" \ No newline at end of file diff --git a/src/input.rs b/src/input.rs index f586d95..35fe6fc 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,4 +1,6 @@ -use winit::{ScanCode, ModifiersState, MouseButton, ElementState, MouseScrollDelta, Event, WindowEvent, DeviceEvent}; +#![allow(deprecated)] + +use winit::event::{ScanCode, MouseButton, ElementState, MouseScrollDelta, Event, WindowEvent, DeviceEvent, ModifiersState}; use std::collections::{HashMap, HashSet}; use std::fs; @@ -81,6 +83,25 @@ pub struct InputState { controller_input: Gilrs, } +#[derive(Debug, Eq, PartialEq, Hash, Clone)] +pub struct KeyboardModifierState { + shift: bool, + ctrl: bool, + alt: bool, + logo: bool +} + +impl KeyboardModifierState { + pub fn from_deprecated_state(old_state: &ModifiersState) -> KeyboardModifierState { + KeyboardModifierState { + shift: old_state.shift(), + ctrl: old_state.ctrl(), + alt: old_state.alt(), + logo: old_state.logo() + } + } +} + impl InputState { pub fn new(toml_path: &str, log_config: LogConfig) -> InputState { let config: InputConfig = toml::from_slice(&fs::read(toml_path).expect("Failed to read input config!")).expect("Failed to parse input config!"); @@ -92,7 +113,7 @@ impl InputState { controller_input: Gilrs::new().unwrap() }; config.button.iter().for_each(|bn| { - let modifiers = ModifiersState { + let modifiers = KeyboardModifierState { shift: bn.shift.is_some(), ctrl: bn.ctrl.is_some(), alt: bn.alt.is_some(), @@ -138,7 +159,7 @@ impl InputState { AxisInput::Digital(positive_button, negative_button) }, InputConfigAxis { mouse_axis: Some(axis_name), .. } => { - let modifiers = ModifiersState { + let modifiers = KeyboardModifierState { shift: axis.shift.is_some(), ctrl: axis.ctrl.is_some(), alt: axis.alt.is_some(), @@ -167,11 +188,11 @@ impl InputState { return state; } - pub fn on_window_event(self: &mut Self, event: &Event) { + pub fn on_window_event(self: &mut Self, event: &Event<()>) { match event { - Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input }, .. } => { + Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input, .. }, .. } => { if self.log_config.input_events { - let mods = mods_to_string(&input.modifiers); + let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&input.modifiers)); if mods.len() > 0 { println!("Keyboard {:?} {:?} {:?} + {:?}", device_id, input.state, &mods, input.scancode) } else { @@ -179,11 +200,11 @@ impl InputState { } } - self.on_keyboard_event(input.state, input.scancode, input.modifiers); + self.on_keyboard_event(input.state, input.scancode, KeyboardModifierState::from_deprecated_state(&input.modifiers)); }, Event::WindowEvent { event: WindowEvent::MouseInput { device_id, state, button, modifiers }, .. } => { if self.log_config.input_events { - let mods = mods_to_string(&modifiers); + let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&modifiers)); if mods.len() > 0 { println!("Mouse {:?} {:?} {:?} + {:?}", device_id, state, &mods, button) } else { @@ -191,11 +212,11 @@ impl InputState { } } - self.on_mouse_event(state, button, modifiers); + self.on_mouse_event(state, button, &KeyboardModifierState::from_deprecated_state(&modifiers)); }, Event::WindowEvent { event: WindowEvent::MouseWheel { device_id, delta, phase, modifiers }, .. } => { if self.log_config.input_events { - let mods = mods_to_string(&modifiers); + let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&modifiers)); if mods.len() > 0 { println!("Scroll {:?} {:?} {:?} + {:?}", device_id, phase, &mods, delta) } else { @@ -203,7 +224,7 @@ impl InputState { } } - self.on_mouse_wheel_event(delta, modifiers); + self.on_mouse_wheel_event(delta, &KeyboardModifierState::from_deprecated_state(&modifiers)); }, Event::DeviceEvent { device_id, event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) } } => { if self.log_config.input_events { @@ -269,10 +290,10 @@ impl InputState { axis.axis_inputs.iter().map(|item| { match item { AxisInput::Wheel(modifiers) => { - if self.modifiers_are_pressed(*modifiers) { self.analog_wheel_state } else { 0.0 } + if self.modifiers_are_pressed(modifiers) { self.analog_wheel_state } else { 0.0 } }, AxisInput::MouseMove(direction, modifiers) => { - if self.modifiers_are_pressed(*modifiers) { + if self.modifiers_are_pressed(modifiers) { match direction { MouseMoveDirection::X => self.mouse_delta_x as f32, MouseMoveDirection::Y => self.mouse_delta_y as f32, @@ -301,11 +322,11 @@ impl InputState { match digital_input { DigitalInput::Keyboard(keyboard_input) => { self.pressed_scan_codes.contains(&keyboard_input.scan_code) - && self.modifiers_are_pressed(keyboard_input.modifiers) + && self.modifiers_are_pressed(&keyboard_input.modifiers) }, DigitalInput::Mouse(mouse_input) => { self.pressed_mouse_buttons.contains(&mouse_input.button) - && self.modifiers_are_pressed(mouse_input.modifiers) + && self.modifiers_are_pressed(&mouse_input.modifiers) }, DigitalInput::Wheel(wheel_input) => { self.input_events.contains(&DigitalInputEvent::Pressed(DigitalInput::Wheel(wheel_input.clone()))) @@ -316,7 +337,7 @@ impl InputState { } } - fn modifiers_are_pressed(self: &Self, modifiers: ModifiersState) -> bool { + fn modifiers_are_pressed(self: &Self, modifiers: &KeyboardModifierState) -> bool { (!modifiers.ctrl || self.pressed_scan_codes.contains(&29)) && (!modifiers.shift || self.pressed_scan_codes.contains(&42) || self.pressed_scan_codes.contains(&54)) && (!modifiers.alt || self.pressed_scan_codes.contains(&56)) @@ -327,7 +348,7 @@ impl InputState { if input.digital_inputs.iter().any(|di| self.digital_input_pressed(di)) { 1.0 } else { 0.0 } } - pub fn on_keyboard_event(self: &mut Self, state: ElementState, scan_code: ScanCode, modifiers: ModifiersState) { + pub fn on_keyboard_event(self: &mut Self, state: ElementState, scan_code: ScanCode, modifiers: KeyboardModifierState) { let input = DigitalInput::Keyboard(KeyboardInput { scan_code, modifiers }); match state { ElementState::Pressed => { @@ -341,7 +362,7 @@ impl InputState { } } - pub fn on_mouse_event(self: &mut Self, state: &ElementState, button: &MouseButton, modifiers: &ModifiersState) { + pub fn on_mouse_event(self: &mut Self, state: &ElementState, button: &MouseButton, modifiers: &KeyboardModifierState) { let input = DigitalInput::Mouse(MouseInput { button: button.clone(), modifiers: modifiers.clone() }); match state { ElementState::Pressed => { @@ -355,7 +376,7 @@ impl InputState { } } - pub fn on_mouse_wheel_event(self: &mut Self, delta: &MouseScrollDelta, modifiers: &ModifiersState) { + pub fn on_mouse_wheel_event(self: &mut Self, delta: &MouseScrollDelta, modifiers: &KeyboardModifierState) { let vertical_direction = match delta { MouseScrollDelta::LineDelta(_x, y) => { if *y > 0.0 { Some(WheelInputDirection::Up) } @@ -412,7 +433,7 @@ impl InputState { } } -fn mods_to_string(modifiers: &ModifiersState) -> String { +fn mods_to_string(modifiers: &KeyboardModifierState) -> String { String::from_iter( vec!["shift", "ctrl", "alt", "logo"].iter() .zip(vec![modifiers.shift, modifiers.ctrl, modifiers.alt, modifiers.logo]) @@ -422,8 +443,8 @@ fn mods_to_string(modifiers: &ModifiersState) -> String { #[derive(Debug)] pub enum AxisInput { - Wheel(ModifiersState), - MouseMove(MouseMoveDirection, ModifiersState), + Wheel(KeyboardModifierState), + MouseMove(MouseMoveDirection, KeyboardModifierState), Digital(VirtualButton, VirtualButton), Controller(AnalogControllerInput), } @@ -439,19 +460,19 @@ pub enum DigitalInput { #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub struct KeyboardInput { scan_code: ScanCode, - modifiers: ModifiersState, + modifiers: KeyboardModifierState, } #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub struct MouseInput { button: MouseButton, - modifiers: ModifiersState, + modifiers: KeyboardModifierState, } #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub struct WheelInput { direction: WheelInputDirection, - modifiers: ModifiersState, + modifiers: KeyboardModifierState, } #[derive(Debug, Eq, PartialEq, Hash, Clone)] @@ -474,7 +495,7 @@ pub enum MouseMoveDirection { #[derive(Debug, PartialEq, Clone)] pub struct AnalogWheelInput { value: f32, - modifiers: ModifiersState, + modifiers: KeyboardModifierState, } #[derive(Debug, PartialEq, Clone)] diff --git a/src/main.rs b/src/main.rs index 9479570..cb1f688 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,14 @@ -use winit::{Event}; -use cgmath::{Matrix4, Rad, Vector3, Deg, Quaternion, Rotation3, One, Rotation}; +use cgmath::{Deg, Matrix4, One, Quaternion, Rad, Rotation, Rotation3, Vector3}; +use winit::event::Event; -mod vulkan; -use crate::vulkan::{Game, LinePoint, GameObject, VulkanRenderer, RenderResult, MeshHandle, GameObjectHandle}; +use crate::config::LogConfig; +use crate::input::InputState; +use crate::vulkan::{Game, GameObject, GameObjectHandle, LinePoint, MeshHandle, VulkanRenderer}; use crate::vulkan::vs::ty::UniformBufferObject; +mod vulkan; mod input; -use crate::input::{InputState}; - mod config; -use crate::config::LogConfig; - mod mesh; struct TestGame { @@ -23,24 +21,9 @@ struct TestGame { } impl Game for TestGame { - fn on_window_event(self: &mut Self, event: &Event) { + fn on_window_event(self: &mut Self, event: &Event<()>) { self.input.on_window_event(event); } -} - -impl TestGame { - fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) { - let (meshes, textures) = mesh::load_mesh("models/iski51.gltf", self.log_config.mesh_load_info).unwrap(); - self.test_meshes = meshes.into_iter().map(|m| { - let id = match m.texture_index { - Some(tex_id) => tex_id + 1, - None => 0, - }; - (renderer.upload_mesh(m), id) - }).collect(); - textures.iter().for_each(|tex| renderer.upload_texture(tex)); - println!("Game loaded!"); - } fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> UniformBufferObject { self.input.frame_start(); @@ -96,6 +79,21 @@ impl TestGame { } } +impl TestGame { + fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) { + let (meshes, textures) = mesh::load_mesh("models/box.gltf", self.log_config.mesh_load_info).unwrap(); + self.test_meshes = meshes.into_iter().map(|m| { + let id = match m.texture_index { + Some(tex_id) => tex_id + 1, + None => 0, + }; + (renderer.upload_mesh(m), id) + }).collect(); + textures.iter().for_each(|tex| renderer.upload_texture(tex)); + println!("Game loaded!"); + } +} + fn main() { let log_config = LogConfig::from_file("config/log.toml"); @@ -109,7 +107,7 @@ fn main() { }; let line_count = 30; - let mut renderer = VulkanRenderer::init( + let (mut renderer, event_loop) = VulkanRenderer::init( (-line_count..=line_count) .flat_map(|it| vec![ LinePoint { position: [it as f32, 0., -line_count as f32] }, @@ -121,15 +119,5 @@ fn main() { ); game.game_start(&mut renderer); - - let mut continue_rendering = true; - let mut ubo = game.update(&mut renderer); - - while continue_rendering { - match renderer.render_loop(&mut game, ubo) { - RenderResult::Ok => ubo = game.update(&mut renderer), - RenderResult::Reload => println!("Render loop reloaded..."), - RenderResult::Quit => continue_rendering = false, - } - } + vulkan::start_event_loop(renderer, Box::new(game), event_loop); } \ No newline at end of file diff --git a/src/vulkan.rs b/src/vulkan.rs index 4d0a40f..79624f3 100644 --- a/src/vulkan.rs +++ b/src/vulkan.rs @@ -1,42 +1,36 @@ -use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; -use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, AutoCommandBuffer}; -use vulkano::device::{Device, DeviceExtensions, Queue}; -use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract}; -use vulkano::image::{SwapchainImage, AttachmentImage, ImageUsage, ImmutableImage, Dimensions}; -use vulkano::instance::{Instance, PhysicalDevice, ApplicationInfo, Version, InstanceExtensions}; -use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract}; -use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule}; -use vulkano::pipeline::viewport::Viewport; -use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError, Surface}; -use vulkano::swapchain; -use vulkano::sync::{GpuFuture, FlushError}; -use vulkano::sync; -use vulkano::format::{Format, ClearValue}; -use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc}; -use vulkano::descriptor::descriptor_set::{FixedSizeDescriptorSetsPool, FixedSizeDescriptorSet, PersistentDescriptorSetBuf, PersistentDescriptorSetImg, PersistentDescriptorSetSampler}; -use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode}; - -use vulkano_win::VkSurfaceBuild; - -use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent}; - -use std::sync::{Arc, Mutex}; +use std::sync::{Arc}; use std::time::SystemTime; -use std::path::{PathBuf}; -use std::ffi::{CStr}; use cgmath::{Matrix4, SquareMatrix}; +use image::{ImageBuffer, ImageFormat, Rgb, Rgba}; +use image::buffer::ConvertBuffer; +use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; +use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState}; +use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet}; +use vulkano::descriptor::DescriptorSet; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::format::{ClearValue, Format}; +use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass}; +use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImmutableImage, SwapchainImage}; +use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version}; +use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType}; +use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc}; +use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract}; +use vulkano::pipeline::viewport::Viewport; +use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode}; +use vulkano::swapchain::{AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError}; +use vulkano::swapchain; +use vulkano::sync::{FlushError, GpuFuture}; +use vulkano::sync; +use vulkano_win::VkSurfaceBuild; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; +use winit::window::{Window, WindowBuilder}; -use shade_runner; -use shade_runner::{CompiledShaders, Entry}; -use shaderc; - -use vs::ty::PushConstants; use line_vs::ty::LinePushConstants; -use crate::mesh::{CPUMesh}; +use vs::ty::PushConstants; -use image::{ImageFormat, ConvertBuffer, ImageBuffer, Rgb, Rgba}; +use crate::mesh::CPUMesh; const VALIDATION_LAYERS: &[&str] = &[ "VK_LAYER_LUNARG_standard_validation" @@ -58,7 +52,9 @@ vulkano::impl_vertex!(LinePoint, position); pub trait Game { /// Returns true if event should be ignored by the vulkan handler - fn on_window_event(self: &mut Self, event: &Event); + fn on_window_event(self: &mut Self, event: &Event<()>); + + fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> vs::ty::UniformBufferObject; } pub struct Mesh { @@ -75,10 +71,6 @@ pub struct GameObject { pub(crate) type GameObjectHandle = usize; pub(crate) type MeshHandle = usize; -//type FixedGraphicsDescriptorSet = Arc, ((), PersistentDescriptorSetBuf>>)>>; -//type FixedGraphicsDescriptorSet = Arc, (((), PersistentDescriptorSetBuf>>), PersistentDescriptorSetImg>>)>>; -type FixedGraphicsDescriptorSet = Arc, ((((), PersistentDescriptorSetBuf>>), PersistentDescriptorSetImg>>), PersistentDescriptorSetSampler)>>; - pub struct GameData { pub start_time: SystemTime, pub line_vertices: Vec, @@ -92,36 +84,30 @@ pub struct GameData { pub textures: Vec>>, } +type Yeet = dyn DescriptorSet + Send + Sync; + pub struct VulkanRenderer { pub game_data: GameData, pub device: Arc, - pub framebuffers: Vec>, + pub framebuffers: Vec>, pub sampler: Arc, pub dynamic_state: DynamicState, - pub pipeline: Arc, - pub line_pipeline: Arc, + pub pipeline: Arc, + pub line_pipeline: Arc, pub line_vertex_buffer: Arc>>, pub surface: Arc>, pub swapchain: Arc>, - pub render_pass: Arc, + pub render_pass: Arc, pub queue: Arc, - pub events_loop: EventsLoop, pub recreate_swapchain: bool, pub debug_callback: Option, - pub previous_frame_end: Option>, + pub previous_frame_end: Option>, pub uniform_buffers: Vec>>, - pub descriptor_sets: Vec, -} - -pub enum RenderResult { - /// Contains buffer index and swapchain future - Ok, - Reload, - Quit, + pub descriptor_sets: Vec>, } impl VulkanRenderer { - pub fn init(line_vertices: Vec, enable_validation_layers: bool) -> VulkanRenderer { + pub fn init(line_vertices: Vec, enable_validation_layers: bool) -> (VulkanRenderer, EventLoop<()>) { let mut data = GameData { push_constants: PushConstants { model: Matrix4::identity().into(), @@ -147,7 +133,7 @@ impl VulkanRenderer { let instance = { let extensions = InstanceExtensions { - ext_debug_report: true, + ext_debug_utils: true, ..vulkano_win::required_extensions() }; @@ -176,20 +162,24 @@ impl VulkanRenderer { // lifetime of this is important, even tho it isn't used! let mut debug_callback = None; if enable_validation_layers { - let msg_types = MessageTypes { - error: true, + let msg_severity = MessageSeverity { + verbose: false, + information: true, warning: true, - performance_warning: true, - information: false, - debug: true, + error: true }; - debug_callback = DebugCallback::new(&instance, msg_types, |msg| { - let type_str = match (msg.ty.error, msg.ty.warning, msg.ty.performance_warning, msg.ty.information, msg.ty.debug) { - (true, _, _, _, _) => "!!", - (_, true, _, _, _) => "!", - (_, _, true, _, _) => "p", - (_, _, _, true, _) => "i", + let msg_types = MessageType { + general: true, + performance: true, + validation: true + }; + + debug_callback = DebugCallback::new(&instance, msg_severity, msg_types, |msg| { + let type_str = match (msg.severity.error, msg.severity.warning, msg.severity.information, msg.severity.verbose) { + (true, _, _, _) => "!!", + (_, true, _, _) => "!", + (_, _, _, true) => "i", _ => " " }; @@ -202,7 +192,7 @@ impl VulkanRenderer { let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); - let events_loop = EventsLoop::new(); + let events_loop = EventLoop::new(); let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap(); let window = surface.window(); @@ -222,19 +212,16 @@ impl VulkanRenderer { let usage = caps.supported_usage_flags; let alpha = caps.supported_composite_alpha.iter().next().unwrap(); let format = caps.supported_formats[0].0; - data.dimensions = if let Some(dimensions) = window.get_inner_size() { - let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - panic!("Couldn't get window dimensions!"); - }; + let inner_size = window.inner_size(); + data.dimensions = [inner_size.width, inner_size.height]; Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, data.dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha, - PresentMode::Fifo, true, None).unwrap() + PresentMode::Fifo, FullscreenExclusive::Default, true, ColorSpace::SrgbNonLinear).unwrap() }; - let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), data.line_vertices.iter().cloned()).unwrap(); + // what is host_cached + let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap(); let render_pass = Arc::new(vulkano::single_pass_renderpass!( device.clone(), @@ -264,14 +251,14 @@ impl VulkanRenderer { MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(); - let pipeline: Arc = - create_pipeline::(device.clone(), render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap(); - let line_pipeline: Arc = - create_pipeline::(device.clone(), render_pass.clone(), "shaders/line.vert", "shaders/line.frag", true).unwrap(); + let pipeline: Arc = + create_pipeline::(device.clone(), render_pass.clone(), false).unwrap(); + let line_pipeline: Arc = + create_pipeline::(device.clone(), render_pass.clone(), true).unwrap(); let default_tex = { let image = image::load_from_memory_with_format(include_bytes!("../models/missing-texture.jpg"), - ImageFormat::JPEG).unwrap().to_rgba(); + ImageFormat::Jpeg).unwrap().to_rgba(); let image_data = image.into_raw().clone(); let (image_view, future) = ImmutableImage::from_iter( @@ -288,7 +275,7 @@ impl VulkanRenderer { // Dynamic viewports allow us to recreate just the viewport when the window is resized // Otherwise we would have to recreate the whole pipeline. - let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None }; + let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: None }; // The render pass we created above only describes the layout of our framebuffers. Before we // can draw we also need to create the actual framebuffers. @@ -301,22 +288,21 @@ impl VulkanRenderer { uniform_buffers.push(CpuAccessibleBuffer::from_data( device.clone(), BufferUsage::uniform_buffer_transfer_destination(), + false, uniform_buffer, ).unwrap()); } - let descriptor_set_pool = Mutex::new(FixedSizeDescriptorSetsPool::new(pipeline.clone(), 0)); - let descriptor_sets = uniform_buffers - .iter() - .map(|uniform_buffer| { - Arc::new( - descriptor_set_pool - .lock().unwrap().next() - .add_buffer(uniform_buffer.clone()).unwrap() - .add_sampled_image(default_tex.clone(), sampler.clone()).unwrap() - .build().unwrap()) - }) - .collect(); + let descriptor_set_layout = pipeline.descriptor_set_layout(0).unwrap().clone(); + + let descriptor_sets = uniform_buffers.iter().map(|uniform_buffer| { + let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone()); + let result: Arc = Arc::new(builder + .add_buffer(uniform_buffer.clone()).unwrap() + .add_sampled_image(default_tex.clone(), sampler.clone()).unwrap() + .build().unwrap()); + result + }).collect(); data.textures.push(default_tex); @@ -328,38 +314,38 @@ impl VulkanRenderer { // that, we store the submission of the previous frame here. let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box); - VulkanRenderer { game_data: data, device, framebuffers, sampler, + (VulkanRenderer { game_data: data, device, framebuffers, sampler, dynamic_state, pipeline, line_pipeline, uniform_buffers, descriptor_sets, - surface, swapchain, render_pass, queue, line_vertex_buffer, events_loop, - recreate_swapchain: false, debug_callback, previous_frame_end } + surface, swapchain, render_pass, queue, line_vertex_buffer, + recreate_swapchain: false, debug_callback, previous_frame_end }, events_loop) } fn create_command_buffer(self: &mut Self, fb_index: usize, ubo: vs::ty::UniformBufferObject) -> Arc { - let mut cbb = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap() - .update_buffer(self.uniform_buffers[fb_index].clone(), ubo).unwrap() - .begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap(); + let mut builder = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap(); + builder.update_buffer(self.uniform_buffers[fb_index].clone(), ubo).unwrap(); + builder.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap(); for i in 0..self.game_data.game_objects.len() { let game_object = &self.game_data.game_objects[i]; let mesh = &self.game_data.meshes[game_object.mesh_index]; self.game_data.push_constants.model = game_object.model_matrix.into(); - cbb = cbb.draw_indexed( + + builder.draw_indexed( self.pipeline.clone(), &self.dynamic_state, vec![mesh.vertex_buffer.clone()], mesh.index_buffer.clone(), self.descriptor_sets[fb_index].clone(), - self.game_data.push_constants.clone()).unwrap() + self.game_data.push_constants.clone()).unwrap(); } - cbb = cbb.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap() + builder.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap() .end_render_pass().unwrap(); - Arc::new(cbb.build().unwrap()) + Arc::new(builder.build().unwrap()) } - /// Returns false if rendering should stop - pub fn render_loop(self: &mut Self, game: &mut dyn Game, new_ubo: vs::ty::UniformBufferObject) -> RenderResult { + pub fn render_loop(self: &mut Self, new_ubo: vs::ty::UniformBufferObject) { // It is important to call this function from time to time, otherwise resources will keep // accumulating and you will eventually reach an out of memory error. // Calling this function polls various fences in order to determine what the GPU has @@ -368,20 +354,16 @@ impl VulkanRenderer { if self.recreate_swapchain { let window = self.surface.window(); - self.game_data.dimensions = if let Some(dimensions) = window.get_inner_size() { - let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - panic!("Window no longer exists!"); - }; + let inner_size = window.inner_size(); + self.game_data.dimensions = [inner_size.width, inner_size.height]; - let (new_swapchain, new_images) = match self.swapchain.recreate_with_dimension(self.game_data.dimensions) { + let (new_swapchain, new_images) = match self.swapchain.recreate_with_dimensions(self.game_data.dimensions) { Ok(r) => r, // This error tends to happen when the user is manually resizing the window. // Simply restarting the loop is the easiest way to fix this issue. Err(SwapchainCreationError::UnsupportedDimensions) => { println!("Swapchain rejected: UnsupportedDimensions"); - return RenderResult::Reload; + return; } Err(err) => panic!("{:?}", err), }; @@ -395,7 +377,7 @@ impl VulkanRenderer { } if self.game_data.recreate_pipeline { - if let Some(pipeline_ok) = create_pipeline::(self.device.clone(), self.render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false) { + if let Some(pipeline_ok) = create_pipeline::(self.device.clone(), self.render_pass.clone(), false) { self.pipeline = pipeline_ok; println!("Updated pipeline."); } else { @@ -411,11 +393,11 @@ impl VulkanRenderer { // // This function can block if no image is available. The parameter is an optional timeout // after which the function call will return an error. - let (fb_index, acquire_future) = match swapchain::acquire_next_image(self.swapchain.clone(), None) { + let (fb_index, _, acquire_future) = match swapchain::acquire_next_image(self.swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { self.recreate_swapchain = true; - return RenderResult::Reload; + return; }, Err(err) => panic!("{:?}", err) }; @@ -451,33 +433,11 @@ impl VulkanRenderer { self.previous_frame_end = Some(Box::new(sync::now(self.device.clone())) as Box<_>); } }; - - // Note that in more complex programs it is likely that one of `acquire_next_image`, - // `command_buffer::submit`, or `present` will block for some time. This happens when the - // GPU's queue is full and the driver has to wait until the GPU finished some work. - // - // Unfortunately the Vulkan API doesn't provide any way to not wait or to detect when a - // wait would happen. Blocking may be the desired behavior, but if you don't want to - // block you should spawn a separate thread dedicated to submissions. - let mut window_closed = false; - let mut resized = false; - self.events_loop.poll_events(|ev| { - game.on_window_event(&ev); - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => window_closed = true, - Event::WindowEvent { event: WindowEvent::Resized(_), .. } => resized = true, - _ => {} - } - }); - if resized { self.recreate_swapchain = true } - if self.game_data.shutdown || window_closed { return RenderResult::Quit; } - - RenderResult::Ok } pub fn upload_mesh(self: &mut Self, mesh: CPUMesh) -> usize { - let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), mesh.vertices.into_iter()).unwrap(); - let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), mesh.indices.into_iter()).unwrap(); + let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), false, mesh.vertices.into_iter()).unwrap(); + let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), false, mesh.indices.into_iter()).unwrap(); self.game_data.meshes.push(Mesh { vertex_buffer, index_buffer }); self.game_data.meshes.len() - 1 } @@ -504,6 +464,27 @@ impl VulkanRenderer { } } +pub fn start_event_loop(mut renderer: VulkanRenderer, mut game: Box, event_loop: EventLoop<()>) { + let mut recreate_swapchain = false; + let ubo = game.update(&mut renderer); + + event_loop.run(move |event, _, control_flow| { + match event { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { + *control_flow = ControlFlow::Exit; + }, + Event::WindowEvent { event: WindowEvent::Resized(_), .. } => { + recreate_swapchain = true; + }, + Event::RedrawEventsCleared => { + game.update(&mut renderer); + renderer.render_loop(ubo); + }, + _ => {} + } + }); +} + /// This method is called once during initialization, then again whenever the window is resized fn window_size_dependent_setup(device: Arc, images: &[Arc>], render_pass: Arc, dynamic_state: &mut DynamicState) -> Vec> { let dimensions = images[0].dimensions(); @@ -554,93 +535,47 @@ pub mod line_fs { } } -fn create_pipeline(device: Arc, render_pass: Arc, vertex_shader_path: &str, fragment_shader_path: &str, is_line: bool) -> Option> { - if let Some((shader, shader_data)) = read_shader(vertex_shader_path, fragment_shader_path) { - let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap(); +fn create_pipeline(device: Arc, render_pass: Arc, is_line: bool) -> Option> { + let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap(); + let pipeline; - let vertex_shader_entry; - let fragment_shader_entry; - let vertex_shader_module; - let fragment_shader_module; + if is_line { + let vertex_shader = line_vs::Shader::load(device.clone()).unwrap(); + let fragment_shader = line_fs::Shader::load(device.clone()).unwrap(); - unsafe { - vertex_shader_module = ShaderModule::from_words(device.clone(), &shader.vertex).expect("Failed to load vertex shader."); - vertex_shader_entry = vertex_shader_module.graphics_entry_point( - CStr::from_bytes_with_nul_unchecked(b"main\0"), - shader_data.vert_input, - shader_data.vert_output, - shader_data.vert_layout, - GraphicsShaderType::Vertex); - fragment_shader_module = ShaderModule::from_words(device.clone(), &shader.fragment).expect("Failed to load fragment shader."); - fragment_shader_entry = fragment_shader_module.graphics_entry_point( - CStr::from_bytes_with_nul_unchecked(b"main\0"), - shader_data.frag_input, - shader_data.frag_output, - shader_data.frag_layout, - GraphicsShaderType::Fragment); - }; - - let pipeline; - if is_line { - pipeline = Arc::new(GraphicsPipeline::start() - .vertex_input_single_buffer::() - .vertex_shader(vertex_shader_entry.clone(), ()) - .line_list() - .viewports_dynamic_scissors_irrelevant(1) - .depth_stencil_simple_depth() - .fragment_shader(fragment_shader_entry.clone(), ()) - .render_pass(sub_pass.clone()) - .build(device.clone()) - .unwrap()); - } else { - pipeline = Arc::new(GraphicsPipeline::start() - .vertex_input_single_buffer::() - .vertex_shader(vertex_shader_entry.clone(), ()) - .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) - .depth_stencil_simple_depth() - .fragment_shader(fragment_shader_entry.clone(), ()) - .blend_alpha_blending() - .cull_mode_back() - .render_pass(sub_pass.clone()) - .build(device.clone()) - .unwrap()); - } - - return Some(pipeline); + pipeline = Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vertex_shader.main_entry_point(), ()) + .line_list() + .viewports_dynamic_scissors_irrelevant(1) + .depth_stencil_simple_depth() + .fragment_shader(fragment_shader.main_entry_point(), ()) + .render_pass(sub_pass.clone()) + .build(device.clone()) + .unwrap()); } else { - return None; + let vertex_shader = vs::Shader::load(device.clone()).unwrap(); + let fragment_shader = fs::Shader::load(device.clone()).unwrap(); + + pipeline = Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vertex_shader.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .depth_stencil_simple_depth() + .fragment_shader(fragment_shader.main_entry_point(), ()) + .blend_alpha_blending() + .cull_mode_back() + .render_pass(sub_pass.clone()) + .build(device.clone()) + .unwrap()); } + + return Some(pipeline); } impl GameObject { pub fn new(mesh: MeshHandle, texture_index: usize) -> GameObject { GameObject { mesh_index: mesh, texture_index, model_matrix: Matrix4::identity() } } -} - -fn read_shader(vert_path_relative: &str, frag_path_relative: &str) -> Option<(CompiledShaders, Entry)> { - let project_root = std::env::current_dir().expect("failed to get root directory"); - - let mut vert_path = project_root.clone(); - vert_path.push(PathBuf::from(vert_path_relative)); - - let mut frag_path = project_root.clone(); - frag_path.push(PathBuf::from(frag_path_relative)); - - let shader_result = shade_runner::load(vert_path, frag_path); - match shader_result { - Ok(shader) => { - let shader_data = shade_runner::parse(&shader).expect("Failed to parse"); - return Some((shader, shader_data)); - } - Err(shade_runner::error::Error::Compile(shade_runner::error::CompileError::Compile(shaderc::Error::CompilationError(line, error)))) => { - println!("Shader line {}: {:?}", line, error); - return None; - } - Err(error) => { - println!("Shader compilation error: {:?}", error); - return None; - } - } } \ No newline at end of file