Fix and module update

This commit is contained in:
2020-06-25 00:59:10 +02:00
parent ae8b82c84d
commit e755d3b1d8
4 changed files with 235 additions and 293 deletions

View File

@@ -5,16 +5,14 @@ authors = ["Till <asuro@posteo.de>"]
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"
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"

View File

@@ -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)]

View File

@@ -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);
}

View File

@@ -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<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((), PersistentDescriptorSetBuf<Arc<vulkano::buffer::cpu_access::CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>)>>;
//type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, (((), PersistentDescriptorSetBuf<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>)>>;
type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((((), PersistentDescriptorSetBuf<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>), PersistentDescriptorSetSampler)>>;
pub struct GameData {
pub start_time: SystemTime,
pub line_vertices: Vec<LinePoint>,
@@ -92,36 +84,30 @@ pub struct GameData {
pub textures: Vec<Arc<ImmutableImage<Format>>>,
}
type Yeet = dyn DescriptorSet + Send + Sync;
pub struct VulkanRenderer {
pub game_data: GameData,
pub device: Arc<Device>,
pub framebuffers: Vec<Arc<FramebufferAbstract + Send + Sync>>,
pub framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
pub sampler: Arc<Sampler>,
pub dynamic_state: DynamicState,
pub pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
pub line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
pub pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
pub line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
pub line_vertex_buffer: Arc<CpuAccessibleBuffer<[LinePoint], PotentialDedicatedAllocation<StdMemoryPoolAlloc>>>,
pub surface: Arc<Surface<Window>>,
pub swapchain: Arc<Swapchain<Window>>,
pub render_pass: Arc<RenderPassAbstract + Send + Sync>,
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
pub queue: Arc<Queue>,
pub events_loop: EventsLoop,
pub recreate_swapchain: bool,
pub debug_callback: Option<DebugCallback>,
pub previous_frame_end: Option<Box<GpuFuture>>,
pub previous_frame_end: Option<Box<dyn GpuFuture>>,
pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>,
pub descriptor_sets: Vec<FixedGraphicsDescriptorSet>,
}
pub enum RenderResult {
/// Contains buffer index and swapchain future
Ok,
Reload,
Quit,
pub descriptor_sets: Vec<Arc<Yeet>>,
}
impl VulkanRenderer {
pub fn init(line_vertices: Vec<LinePoint>, enable_validation_layers: bool) -> VulkanRenderer {
pub fn init(line_vertices: Vec<LinePoint>, 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<GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap();
let line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<LinePoint>(device.clone(), render_pass.clone(), "shaders/line.vert", "shaders/line.frag", true).unwrap();
let pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), false).unwrap();
let line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<LinePoint>(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<Yeet> = 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<dyn GpuFuture>);
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<AutoCommandBuffer> {
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::<Vertex>(self.device.clone(), self.render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false) {
if let Some(pipeline_ok) = create_pipeline::<Vertex>(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<dyn Game>, 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<Device>, images: &[Arc<SwapchainImage<Window>>], render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, dynamic_state: &mut DynamicState) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();
@@ -554,93 +535,47 @@ pub mod line_fs {
}
}
fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, render_pass: Arc<RenderPassAbstract + Send + Sync>, vertex_shader_path: &str, fragment_shader_path: &str, is_line: bool) -> Option<Arc<GraphicsPipelineAbstract + Send + Sync>> {
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<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, is_line: bool) -> Option<Arc<dyn GraphicsPipelineAbstract + Send + Sync>> {
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::<V>()
.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::<V>()
.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::<V>()
.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::<V>()
.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;
}
}
}