diff --git a/rust-engine.iml b/rust-engine.iml
index 7fe828a..d5ac164 100644
--- a/rust-engine.iml
+++ b/rust-engine.iml
@@ -7,6 +7,9 @@
+
+
+
diff --git a/src/main.rs b/src/main.rs
index 16c1436..6e59c79 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
use crate::vulkan::{Vertex, GameData};
-use winit::{Event, WindowEvent};
+use winit::{Event, WindowEvent, ElementState};
use std::time::SystemTime;
use std::iter::FromIterator;
@@ -7,7 +7,7 @@ mod vulkan;
impl GameData<'_> {
/// Returns true if event should be ignored by the vulkan handler
- fn on_window_event(self: &Self, event: &Event) -> bool {
+ fn on_window_event(self: &mut Self, event: &Event) -> bool {
match event {
Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input }, .. } => {
let mods = String::from_iter(
@@ -20,6 +20,10 @@ impl GameData<'_> {
} else {
println!("Keyboard {:?} input {:?} {:?}", device_id, input.state, input.scancode)
}
+
+ if input.state == ElementState::Released && input.modifiers.ctrl && input.scancode == 19 {
+ self.recreate_pipeline = true;
+ }
}
_ => {}
}
@@ -52,7 +56,8 @@ fn main() {
Vertex { position: [0.9, 0., 0.] },
],
push_constants: &mut pc,
- start_time: SystemTime::now()
+ start_time: SystemTime::now(),
+ recreate_pipeline: false
};
vulkan::init(data);
diff --git a/src/vulkan.rs b/src/vulkan.rs
index 0bea9ef..815cca4 100644
--- a/src/vulkan.rs
+++ b/src/vulkan.rs
@@ -50,6 +50,7 @@ pub struct GameData<'a> {
pub mesh_vertices: Vec,
pub line_vertices: Vec,
pub push_constants: &'a mut PushConstants,
+ pub recreate_pipeline: bool,
}
pub fn init(mut game: GameData) {
@@ -92,7 +93,7 @@ pub fn init(mut game: GameData) {
error: true,
warning: true,
performance_warning: true,
- information: true,
+ information: false,
debug: true,
};
@@ -237,13 +238,13 @@ pub fn init(mut game: GameData) {
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
- let pipeline = create_pipeline(device.clone(), sub_pass.clone());
+ let mut pipeline = create_pipeline(device.clone(), sub_pass.clone()).unwrap();
let line_shader_vertex_entry;
let line_shader_fragment_entry;
let line_shader_module_vertex;
let line_shader_module_fragment;
- let (line_shader, line_shader_data) = read_shader("shaders/line.vert", "shaders/line.frag");
+ let (line_shader, line_shader_data) = read_shader("shaders/line.vert", "shaders/line.frag").unwrap();
unsafe {
line_shader_module_vertex = ShaderModule::from_words(device.clone(), &line_shader.vertex).expect("Failed to load");
line_shader_vertex_entry = line_shader_module_vertex.graphics_entry_point(
@@ -281,7 +282,7 @@ pub fn init(mut game: GameData) {
// Since we need to draw to multiple images, we are going to create a different framebuffer for
// each image.
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
-
+
// In some situations, the swapchain will become invalid by it This includes for example
// when the window is resized (as the images of the swapchain will no longer match the
// window's) or, on Android, when the application went to the background and goes back to the
@@ -335,6 +336,16 @@ pub fn init(mut game: GameData) {
recreate_swapchain = false;
}
+ if game.recreate_pipeline {
+ if let Some(pipeline_ok) = create_pipeline(device.clone(), sub_pass.clone()) {
+ pipeline = pipeline_ok;
+ println!("Updated pipeline.");
+ } else {
+ println!("Failed to update pipeline.");
+ }
+ game.recreate_pipeline = false;
+ }
+
// Before we can draw on the output, we have to *acquire* an image from the swapchain. If
// no image is available (which happens if you submit draw commands too quickly), then the
// function will block.
@@ -464,55 +475,59 @@ fn window_size_dependent_setup(
}).collect::>()
}
-fn create_pipeline(device: Arc, sub_pass: Subpass>) -> Arc, Box, Arc>> {
- let mesh_shader_vertex_entry;
- let mesh_shader_fragment_entry;
- let mesh_shader_module_vertex;
- let mesh_shader_module_fragment;
- let (mesh_shader, mesh_shader_data) = read_shader("shaders/triangle.vert", "shaders/triangle.frag");
- unsafe {
- mesh_shader_module_vertex = ShaderModule::from_words(device.clone(), &mesh_shader.vertex).expect("Failed to load");
- mesh_shader_vertex_entry = mesh_shader_module_vertex.graphics_entry_point(
- CStr::from_bytes_with_nul_unchecked(b"main\0"),
- mesh_shader_data.vert_input,
- mesh_shader_data.vert_output,
- mesh_shader_data.vert_layout,
- GraphicsShaderType::Vertex);
- mesh_shader_module_fragment = ShaderModule::from_words(device.clone(), &mesh_shader.fragment).expect("Failed to load");
- mesh_shader_fragment_entry = mesh_shader_module_fragment.graphics_entry_point(
- CStr::from_bytes_with_nul_unchecked(b"main\0"),
- mesh_shader_data.frag_input,
- mesh_shader_data.frag_output,
- mesh_shader_data.frag_layout,
- GraphicsShaderType::Fragment);
- };
+fn create_pipeline(device: Arc, sub_pass: Subpass>) -> Option, Box, Arc>>> {
+ if let Some((mesh_shader, mesh_shader_data)) = read_shader("shaders/triangle.vert", "shaders/triangle.frag") {
+ let mesh_shader_vertex_entry;
+ let mesh_shader_fragment_entry;
+ let mesh_shader_module_vertex;
+ let mesh_shader_module_fragment;
- // Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
- // program, but much more specific.
- let pipeline = Arc::new(GraphicsPipeline::start()
- // We need to indicate the layout of the vertices.
- .vertex_input_single_buffer::()
- // A Vulkan shader can in theory contain multiple entry points, so we have to specify
- // which one. The `main` word of `main_entry_point` actually corresponds to the name of
- // the entry point.
- .vertex_shader(mesh_shader_vertex_entry.clone(), ())
- // The content of the vertex buffer describes a list of triangles.
- .triangle_list()
- // Use a resizable viewport set to draw over the entire window
- .viewports_dynamic_scissors_irrelevant(1)
- // See `vertex_shader`.
- .fragment_shader(mesh_shader_fragment_entry.clone(), ())
- // We have to indicate which subpass of which render pass this pipeline is going to be used
- // in. The pipeline will only be usable from this particular subpass.
- .render_pass(sub_pass.clone())
- // Now that our builder is filled, we call `build()` to obtain an actual pipeline.
- .build(device.clone())
- .unwrap());
+ unsafe {
+ mesh_shader_module_vertex = ShaderModule::from_words(device.clone(), &mesh_shader.vertex).expect("Failed to load");
+ mesh_shader_vertex_entry = mesh_shader_module_vertex.graphics_entry_point(
+ CStr::from_bytes_with_nul_unchecked(b"main\0"),
+ mesh_shader_data.vert_input,
+ mesh_shader_data.vert_output,
+ mesh_shader_data.vert_layout,
+ GraphicsShaderType::Vertex);
+ mesh_shader_module_fragment = ShaderModule::from_words(device.clone(), &mesh_shader.fragment).expect("Failed to load");
+ mesh_shader_fragment_entry = mesh_shader_module_fragment.graphics_entry_point(
+ CStr::from_bytes_with_nul_unchecked(b"main\0"),
+ mesh_shader_data.frag_input,
+ mesh_shader_data.frag_output,
+ mesh_shader_data.frag_layout,
+ GraphicsShaderType::Fragment);
+ };
- return pipeline;
+ // Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
+ // program, but much more specific.
+ let pipeline = Arc::new(GraphicsPipeline::start()
+ // We need to indicate the layout of the vertices.
+ .vertex_input_single_buffer::()
+ // A Vulkan shader can in theory contain multiple entry points, so we have to specify
+ // which one. The `main` word of `main_entry_point` actually corresponds to the name of
+ // the entry point.
+ .vertex_shader(mesh_shader_vertex_entry.clone(), ())
+ // The content of the vertex buffer describes a list of triangles.
+ .triangle_list()
+ // Use a resizable viewport set to draw over the entire window
+ .viewports_dynamic_scissors_irrelevant(1)
+ // See `vertex_shader`.
+ .fragment_shader(mesh_shader_fragment_entry.clone(), ())
+ // We have to indicate which subpass of which render pass this pipeline is going to be used
+ // in. The pipeline will only be usable from this particular subpass.
+ .render_pass(sub_pass.clone())
+ // Now that our builder is filled, we call `build()` to obtain an actual pipeline.
+ .build(device.clone())
+ .unwrap());
+
+ return Some(pipeline);
+ } else {
+ return None;
+ }
}
-fn read_shader(vert_path_relative: &str, frag_path_relative: &str) -> (CompiledShaders, Entry) {
+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();
@@ -525,11 +540,15 @@ fn read_shader(vert_path_relative: &str, frag_path_relative: &str) -> (CompiledS
match shader_result {
Ok(shader) => {
let shader_data = shade_runner::parse(&shader).expect("Failed to parse");
- return (shader, shader_data);
+ return Some((shader, shader_data));
}
Err(shade_runner::error::Error::Compile(shade_runner::error::CompileError::Compile(shaderc::Error::CompilationError(line, error)))) => {
- panic!("Shader line {}: {:?}", line, error);
+ println!("Shader line {}: {:?}", line, error);
+ return None;
+ }
+ Err(error) => {
+ println!("Shader compilation error: {:?}", error);
+ return None;
}
- Err(error) => panic!("Shader compilation error: {:?}", error)
}
}