reload shaders
This commit is contained in:
@@ -7,6 +7,9 @@
|
|||||||
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/../rust-engine\examples" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/../rust-engine\tests" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/../rust-engine\benches" isTestSource="true" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@@ -1,5 +1,5 @@
|
|||||||
use crate::vulkan::{Vertex, GameData};
|
use crate::vulkan::{Vertex, GameData};
|
||||||
use winit::{Event, WindowEvent};
|
use winit::{Event, WindowEvent, ElementState};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ mod vulkan;
|
|||||||
|
|
||||||
impl GameData<'_> {
|
impl GameData<'_> {
|
||||||
/// Returns true if event should be ignored by the vulkan handler
|
/// 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 {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input }, .. } => {
|
Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input }, .. } => {
|
||||||
let mods = String::from_iter(
|
let mods = String::from_iter(
|
||||||
@@ -20,6 +20,10 @@ impl GameData<'_> {
|
|||||||
} else {
|
} else {
|
||||||
println!("Keyboard {:?} input {:?} {:?}", device_id, input.state, input.scancode)
|
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.] },
|
Vertex { position: [0.9, 0., 0.] },
|
||||||
],
|
],
|
||||||
push_constants: &mut pc,
|
push_constants: &mut pc,
|
||||||
start_time: SystemTime::now()
|
start_time: SystemTime::now(),
|
||||||
|
recreate_pipeline: false
|
||||||
};
|
};
|
||||||
|
|
||||||
vulkan::init(data);
|
vulkan::init(data);
|
||||||
|
|||||||
123
src/vulkan.rs
123
src/vulkan.rs
@@ -50,6 +50,7 @@ pub struct GameData<'a> {
|
|||||||
pub mesh_vertices: Vec<Vertex>,
|
pub mesh_vertices: Vec<Vertex>,
|
||||||
pub line_vertices: Vec<Vertex>,
|
pub line_vertices: Vec<Vertex>,
|
||||||
pub push_constants: &'a mut PushConstants,
|
pub push_constants: &'a mut PushConstants,
|
||||||
|
pub recreate_pipeline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(mut game: GameData) {
|
pub fn init(mut game: GameData) {
|
||||||
@@ -92,7 +93,7 @@ pub fn init(mut game: GameData) {
|
|||||||
error: true,
|
error: true,
|
||||||
warning: true,
|
warning: true,
|
||||||
performance_warning: true,
|
performance_warning: true,
|
||||||
information: true,
|
information: false,
|
||||||
debug: true,
|
debug: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -237,13 +238,13 @@ pub fn init(mut game: GameData) {
|
|||||||
|
|
||||||
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
|
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_vertex_entry;
|
||||||
let line_shader_fragment_entry;
|
let line_shader_fragment_entry;
|
||||||
let line_shader_module_vertex;
|
let line_shader_module_vertex;
|
||||||
let line_shader_module_fragment;
|
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 {
|
unsafe {
|
||||||
line_shader_module_vertex = ShaderModule::from_words(device.clone(), &line_shader.vertex).expect("Failed to load");
|
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(
|
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
|
// Since we need to draw to multiple images, we are going to create a different framebuffer for
|
||||||
// each image.
|
// each image.
|
||||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
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
|
// 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
|
// 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
|
// 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;
|
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
|
// 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
|
// no image is available (which happens if you submit draw commands too quickly), then the
|
||||||
// function will block.
|
// function will block.
|
||||||
@@ -464,55 +475,59 @@ fn window_size_dependent_setup(
|
|||||||
}).collect::<Vec<_>>()
|
}).collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_pipeline<T: RenderPassAbstract>(device: Arc<Device>, sub_pass: Subpass<Arc<T>>) -> Arc<GraphicsPipeline<SingleBufferDefinition<Vertex>, Box<dyn PipelineLayoutAbstract + Send + Sync>, Arc<T>>> {
|
fn create_pipeline<T: RenderPassAbstract>(device: Arc<Device>, sub_pass: Subpass<Arc<T>>) -> Option<Arc<GraphicsPipeline<SingleBufferDefinition<Vertex>, Box<dyn PipelineLayoutAbstract + Send + Sync>, Arc<T>>>> {
|
||||||
let mesh_shader_vertex_entry;
|
if let Some((mesh_shader, mesh_shader_data)) = read_shader("shaders/triangle.vert", "shaders/triangle.frag") {
|
||||||
let mesh_shader_fragment_entry;
|
let mesh_shader_vertex_entry;
|
||||||
let mesh_shader_module_vertex;
|
let mesh_shader_fragment_entry;
|
||||||
let mesh_shader_module_fragment;
|
let mesh_shader_module_vertex;
|
||||||
let (mesh_shader, mesh_shader_data) = read_shader("shaders/triangle.vert", "shaders/triangle.frag");
|
let mesh_shader_module_fragment;
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
|
unsafe {
|
||||||
// program, but much more specific.
|
mesh_shader_module_vertex = ShaderModule::from_words(device.clone(), &mesh_shader.vertex).expect("Failed to load");
|
||||||
let pipeline = Arc::new(GraphicsPipeline::start()
|
mesh_shader_vertex_entry = mesh_shader_module_vertex.graphics_entry_point(
|
||||||
// We need to indicate the layout of the vertices.
|
CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||||
.vertex_input_single_buffer::<Vertex>()
|
mesh_shader_data.vert_input,
|
||||||
// A Vulkan shader can in theory contain multiple entry points, so we have to specify
|
mesh_shader_data.vert_output,
|
||||||
// which one. The `main` word of `main_entry_point` actually corresponds to the name of
|
mesh_shader_data.vert_layout,
|
||||||
// the entry point.
|
GraphicsShaderType::Vertex);
|
||||||
.vertex_shader(mesh_shader_vertex_entry.clone(), ())
|
mesh_shader_module_fragment = ShaderModule::from_words(device.clone(), &mesh_shader.fragment).expect("Failed to load");
|
||||||
// The content of the vertex buffer describes a list of triangles.
|
mesh_shader_fragment_entry = mesh_shader_module_fragment.graphics_entry_point(
|
||||||
.triangle_list()
|
CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||||
// Use a resizable viewport set to draw over the entire window
|
mesh_shader_data.frag_input,
|
||||||
.viewports_dynamic_scissors_irrelevant(1)
|
mesh_shader_data.frag_output,
|
||||||
// See `vertex_shader`.
|
mesh_shader_data.frag_layout,
|
||||||
.fragment_shader(mesh_shader_fragment_entry.clone(), ())
|
GraphicsShaderType::Fragment);
|
||||||
// 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 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::<Vertex>()
|
||||||
|
// 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 project_root = std::env::current_dir().expect("failed to get root directory");
|
||||||
|
|
||||||
let mut vert_path = project_root.clone();
|
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 {
|
match shader_result {
|
||||||
Ok(shader) => {
|
Ok(shader) => {
|
||||||
let shader_data = shade_runner::parse(&shader).expect("Failed to parse");
|
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)))) => {
|
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user