diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index ebf08644..d2d3369d 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -105,6 +105,7 @@ unsafe impl SpecializationConstants for SimpleSpecializationConstants { pub struct VkProcessor<'a> { + pub shader_kernels: Option>>, pub compute_kernel: Option, pub vertex_shader_path: PathBuf, pub fragment_shader_path: PathBuf, @@ -121,8 +122,8 @@ pub struct VkProcessor<'a> { pub image_buffer: Vec, pub compute_image_buffers: Vec>>, pub settings_buffer: Option>>, - pub swapchain: Option>>, - pub images: Option>>>, +// pub swapchain: Option>>, +// pub images: Option>>>, pub xy: (u32, u32), pub render_pass: Option>, pub vertex_buffer: Option>, @@ -152,6 +153,7 @@ impl<'a> VkProcessor<'a> { let queue = queues.next().unwrap(); VkProcessor { + shader_kernels: Option::None, compute_kernel: Option::None, vertex_shader_path: Default::default(), fragment_shader_path: Default::default(), @@ -168,8 +170,6 @@ impl<'a> VkProcessor<'a> { image_buffer: Vec::new(), compute_image_buffers: Vec::new(), settings_buffer: Option::None, - swapchain: Option::None, - images: Option::None, xy: (0, 0), render_pass: Option::None, vertex_buffer: Option::None, @@ -184,189 +184,18 @@ impl<'a> VkProcessor<'a> { self.compute_pipeline = Some(self.compute_kernel.clone().unwrap().get_pipeline()); } - - pub fn compile_shaders(&mut self, filename: String, surface: &'a Arc>) { - - // Before we can draw on the surface, we have to create what is called a swapchain. Creating - // a swapchain allocates the color buffers that will contain the image that will ultimately - // be visible on the screen. These images are returned alongside with the swapchain. - let (mut swapchain, images) = { - let capabilities = surface.capabilities(self.physical).unwrap(); - let usage = capabilities.supported_usage_flags; - let alpha = capabilities.supported_composite_alpha.iter().next().unwrap(); - // Choosing the internal format that the images will have. - let format = capabilities.supported_formats[0].0; - - // Set the swapchains window dimensions - let initial_dimensions = if let Some(dimensions) = surface.window().get_inner_size() { - // convert to physical pixels - let dimensions: (u32, u32) = dimensions.to_physical(surface.window().get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - // The window no longer exists so exit the application. - return; - }; - - Swapchain::new(self.device.clone(), - surface.clone(), - capabilities.min_image_count, - format, - initial_dimensions, - 1, // Layers - usage, - &self.queue, - SurfaceTransform::Identity, - alpha, - PresentMode::Fifo, true, None).unwrap() - }; - - self.swapchain = Some(swapchain); - self.images = Some(images); - - let project_root = - std::env::current_dir() - .expect("failed to get root directory"); - - let mut shader_path = project_root.clone(); - shader_path.push(PathBuf::from("resources/shaders/")); - - let mut vertex_shader_path = project_root.clone(); - vertex_shader_path.push(PathBuf::from("resources/shaders/")); - vertex_shader_path.push(PathBuf::from(filename.clone() + ".vertex")); - - let mut fragment_shader_path = project_root.clone(); - fragment_shader_path.push(PathBuf::from("resources/shaders/")); - fragment_shader_path.push(PathBuf::from(filename.clone() + ".fragment")); - - let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap(); - options.add_macro_definition("SETTING_POS_X", Some("0")); - options.add_macro_definition("SETTING_POS_Y", Some("1")); - options.add_macro_definition("SETTING_BUCKETS_START", Some("2")); - options.add_macro_definition("SETTING_BUCKETS_LEN", Some("2")); - - // TODO: better compile message, run til successful compile - let shader = sr::load(vertex_shader_path, fragment_shader_path) - .expect("Shader didn't compile"); - - let vulkano_entry = - sr::parse(&shader) - .expect("failed to parse"); - - let x1: Arc = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &shader.fragment) - }.unwrap(); - - let x2 = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &shader.vertex) - }.unwrap(); - - let frag_entry_point: GraphicsEntryPoint = unsafe { - x1.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), - vulkano_entry.frag_input, - vulkano_entry.frag_output, - vulkano_entry.frag_layout, - GraphicsShaderType::Fragment) - }; - - let vert_entry_point: GraphicsEntryPoint = unsafe { - x2.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), - vulkano_entry.vert_input, - vulkano_entry.vert_output, - vulkano_entry.vert_layout, - GraphicsShaderType::Vertex) - }; - - // The next step is to create a *render pass*, which is an object that describes where the - // output of the graphics pipeline will go. It describes the layout of the images - // where the colors, depth and/or stencil information will be written. - let render_pass = Arc::new(vulkano::single_pass_renderpass!( - self.device.clone(), - attachments: { - // `color` is a custom name we give to the first and only attachment. - color: { - // `load: Clear` means that we ask the GPU to clear the content of this - // attachment at the start of the drawing. - load: Clear, - // `store: Store` means that we ask the GPU to store the output of the draw - // in the actual image. We could also ask it to discard the result. - store: Store, - // `format: ` indicates the type of the format of the image. This has to - // be one of the types of the `vulkano::format` module (or alternatively one - // of your structs that implements the `FormatDesc` trait). Here we use the - // same format as the swapchain. - format: self.swapchain.clone().unwrap().clone().format(), - // TODO: - samples: 1, - } - }, - pass: { - // We use the attachment named `color` as the one and only color attachment. - color: [color], - // No depth-stencil attachment is indicated with empty brackets. - depth_stencil: {} - } - ).unwrap()); - - self.render_pass = Some(render_pass); - - // 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 = GraphicsPipeline::start() - // We need to indicate the layout of the vertices. - // The type `SingleBufferDefinition` actually contains a template parameter corresponding - // to the type of each vertex. But in this code it is automatically inferred. - .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(vert_entry_point, SimpleSpecializationConstants { - first_constant: 0, - second_constant: 0, - third_constant: 0.0, - }) - // The content of the vertex buffer describes a list of triangles. - .triangle_fan() - // Use a resizable viewport set to draw over the entire window - .viewports_dynamic_scissors_irrelevant(1) - // See `vertex_shader`. - .fragment_shader(frag_entry_point, SimpleSpecializationConstants { - first_constant: 0, - second_constant: 0, - third_constant: 0.0, - }) - // 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(Subpass::from(self.render_pass.clone().unwrap().clone(), 0).unwrap()) - // Now that our builder is filled, we call `build()` to obtain an actual pipeline. - .build(self.device.clone()) - .unwrap(); - - self.graphics_pipeline = Some(Arc::new(pipeline)); - + self.shader_kernels = Some(Arc::new( + ShaderKernels::new(filename.clone(), + surface, self.queue.clone(), + self.physical, + self.device.clone()) + )); } - // On resizes we have to recreate the swapchain pub fn recreate_swapchain(&mut self, surface: &'a Arc>) { - let dimensions = if let Some(dimensions) = surface.window().get_inner_size() { - let dimensions: (u32, u32) = dimensions.to_physical(surface.window().get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - return; - }; - - let (new_swapchain, new_images) = match self.swapchain.clone().unwrap().recreate_with_dimension(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) => panic!("Uh oh"), - Err(err) => panic!("{:?}", err) - }; - - self.swapchain = Some(new_swapchain); - self.images = Some(new_images); + //self.shader_kernels.unwrap().recreate_swapchain(surface); } pub fn load_buffers(&mut self, image_filename: String) @@ -500,7 +329,7 @@ impl<'a> VkProcessor<'a> { pub fn run(&mut self, surface: &'a Arc>, mut frame_future: Box) -> Box { - let mut framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), + let mut framebuffers = window_size_dependent_setup(&self.shader_kernels.clone().unwrap().swapchain_images.clone(), self.render_pass.clone().unwrap().clone(), &mut self.dynamic_state); @@ -512,8 +341,8 @@ impl<'a> VkProcessor<'a> { // Whenever the window resizes we need to recreate everything dependent on the window size. // In this example that includes the swapchain, the framebuffers and the dynamic state viewport. if recreate_swapchain { - self.recreate_swapchain(surface); - framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), + //self.shader_kernels.unwrap().recreate_swapchain(surface); + framebuffers = window_size_dependent_setup(&self.shader_kernels.clone().unwrap().swapchain_images.clone(), self.render_pass.clone().unwrap().clone(), &mut self.dynamic_state); recreate_swapchain = false; @@ -522,7 +351,7 @@ impl<'a> VkProcessor<'a> { // 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 (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(self.swapchain.clone().unwrap().clone(), None) { + let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(self.shader_kernels.clone().unwrap().swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { recreate_swapchain = true; @@ -585,7 +414,7 @@ impl<'a> VkProcessor<'a> { // Wait on the previous frame, then execute the command buffer and present the image let future = frame_future.join(acquire_future) .then_execute(self.queue.clone(), command_buffer).unwrap() - .then_swapchain_present(self.queue.clone(), self.swapchain.clone().unwrap().clone(), image_num) + .then_swapchain_present(self.queue.clone(), self.shader_kernels.clone().unwrap().swapchain.clone(), image_num) .then_signal_fence_and_flush(); match future { diff --git a/src/vkprocessor/shader_kernels.rs b/src/vkprocessor/shader_kernels.rs index 2a5da587..21683eae 100644 --- a/src/vkprocessor/shader_kernels.rs +++ b/src/vkprocessor/shader_kernels.rs @@ -3,7 +3,7 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet, StdDescriptorPoolAlloc}; use vulkano::device::{Device, DeviceExtensions, QueuesIter, Queue}; use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice, QueueFamily}; -use vulkano::pipeline::{ComputePipeline, GraphicsPipeline, GraphicsPipelineAbstract}; +use vulkano::pipeline::{ComputePipeline, GraphicsPipeline, GraphicsPipelineAbstract, GraphicsPipelineBuilder}; use vulkano::sync::{GpuFuture, FlushError}; use vulkano::sync; use std::time::SystemTime; @@ -51,11 +51,11 @@ struct EntryPoint<'a> { struct tVertex { position: [f32; 2] } pub struct ShaderKernels<'a> { - swapchain : Arc>, - swapchain_images: Vec>>, // Surface which is drawn to + pub swapchain : Arc>, + pub swapchain_images: Vec>>, // Surface which is drawn to pub physical: PhysicalDevice<'a>, - shader: CompiledShaders, + // shader: CompiledShaders, options: CompileOptions<'a>, @@ -64,7 +64,7 @@ pub struct ShaderKernels<'a> { device: Arc, - entry_point: EntryPoint<'a>, + // entry_point: EntryPoint<'a>, } // return the frame buffers @@ -101,43 +101,33 @@ impl<'a> ShaderKernels<'a> { match self.graphics_pipeline.clone() { Some(t) => t, None => { - self.graphics_pipeline = Some(Arc::new( - GraphicsPipeline::start() - // We need to indicate the layout of the vertices. - // The type `SingleBufferDefinition` actually contains a template parameter corresponding - // to the type of each vertex. But in this code it is automatically inferred. - .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(self.entry_point.vertex_entry_point.clone().unwrap(), SimpleSpecializationConstants { - first_constant: 0, - second_constant: 0, - third_constant: 0.0, - }) - // The content of the vertex buffer describes a list of triangles. - .triangle_fan() - // Use a resizable viewport set to draw over the entire window - .viewports_dynamic_scissors_irrelevant(1) - // See `vertex_shader`. - .fragment_shader(self.entry_point.frag_entry_point.clone().unwrap(), SimpleSpecializationConstants { - first_constant: 0, - second_constant: 0, - third_constant: 0.0, - }) - // 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(Subpass::from(self.render_pass.clone(), 0).unwrap()) - // Now that our builder is filled, we call `build()` to obtain an actual pipeline. - .build(self.device.clone()) - .unwrap() - )); + // TODO: Create new graphics pipeline self.graphics_pipeline.clone().unwrap() } } } + // On resizes we have to recreate the swapchain + pub fn recreate_swapchain(&mut self, surface: &'a Arc>) { + let dimensions = if let Some(dimensions) = surface.window().get_inner_size() { + let dimensions: (u32, u32) = dimensions.to_physical(surface.window().get_hidpi_factor()).into(); + [dimensions.0, dimensions.1] + } else { + return; + }; + + let (new_swapchain, new_images) = match self.swapchain.clone().recreate_with_dimension(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) => panic!("Uh oh"), + Err(err) => panic!("{:?}", err) + }; + + self.swapchain = new_swapchain; + self.swapchain_images = new_images; + } + pub fn new(filename: String, surface: &'a Arc>, queue: Arc, @@ -185,33 +175,32 @@ impl<'a> ShaderKernels<'a> { .expect("failed to parse"); let fragment_shader_module: Arc = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.fragment.clone()) + let filenames1 = ShaderKernels::get_path(filename.clone()); + let shader1 = sr::load(filenames1.0, filenames1.1) + .expect("Shader didn't compile"); + vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader1.fragment.clone()) }.unwrap(); let vertex_shader_module: Arc = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.vertex.clone()) + let filenames1 = ShaderKernels::get_path(filename.clone()); + let shader1 = sr::load(filenames1.0, filenames1.1) + .expect("Shader didn't compile"); + vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader1.vertex.clone()) }.unwrap(); let filenames = ShaderKernels::get_path(filename.clone()); - let mut entry_point = EntryPoint { - compiled_shaders: sr::load(filenames.0, filenames.1) - .expect("Shader didn't compile"), - fragment_shader_module: fragment_shader_module, - vertex_shader_module: vertex_shader_module, - frag_entry_point: None, - vertex_entry_point: None, - }; - entry_point.frag_entry_point = unsafe { - Some(entry_point.fragment_shader_module.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), + + let frag_entry_point = unsafe { + Some(fragment_shader_module.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), vulkano_entry.frag_input, vulkano_entry.frag_output, vulkano_entry.frag_layout, GraphicsShaderType::Fragment)) }; - entry_point.vertex_entry_point = unsafe { - Some(entry_point.vertex_shader_module.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), + let vertex_entry_point = unsafe { + Some(vertex_shader_module.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), vulkano_entry.vert_input, vulkano_entry.vert_output, vulkano_entry.vert_layout, @@ -247,39 +236,6 @@ impl<'a> ShaderKernels<'a> { ).unwrap()); vulkano::impl_vertex!(tVertex, position); - // 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 = GraphicsPipeline::start() - // We need to indicate the layout of the vertices. - // The type `SingleBufferDefinition` actually contains a template parameter corresponding - // to the type of each vertex. But in this code it is automatically inferred. - .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(entry_point.vertex_entry_point.clone().unwrap(), SimpleSpecializationConstants { - first_constant: 0, - second_constant: 0, - third_constant: 0.0, - }) - // The content of the vertex buffer describes a list of triangles. - .triangle_fan() - // Use a resizable viewport set to draw over the entire window - .viewports_dynamic_scissors_irrelevant(1) - // See `vertex_shader`. - .fragment_shader(entry_point.frag_entry_point.clone().unwrap(), SimpleSpecializationConstants { - first_constant: 0, - second_constant: 0, - third_constant: 0.0, - }) - // 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(Subpass::from(render_pass.clone(), 0).unwrap()) - // Now that our builder is filled, we call `build()` to obtain an actual pipeline. - .build(device.clone()) - .unwrap(); - ShaderKernels { @@ -287,13 +243,41 @@ impl<'a> ShaderKernels<'a> { swapchain_images: images, physical: physical, - shader: shader, - options: CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap(), - render_pass: render_pass, - graphics_pipeline: Some(Arc::new(pipeline)), + + graphics_pipeline: Some(Arc::new(GraphicsPipeline::start() + // We need to indicate the layout of the vertices. + // The type `SingleBufferDefinition` actually contains a template parameter corresponding + // to the type of each vertex. But in this code it is automatically inferred. + .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(vertex_entry_point.clone().unwrap(), SimpleSpecializationConstants { + first_constant: 0, + second_constant: 0, + third_constant: 0.0, + }) + // The content of the vertex buffer describes a list of triangles. + .triangle_fan() + // Use a resizable viewport set to draw over the entire window + .viewports_dynamic_scissors_irrelevant(1) + // See `vertex_shader`. + .fragment_shader(frag_entry_point.clone().unwrap(), SimpleSpecializationConstants { + first_constant: 0, + second_constant: 0, + third_constant: 0.0, + }) + // 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(Subpass::from(render_pass.clone(), 0).unwrap()) + // Now that our builder is filled, we call `build()` to obtain an actual pipeline. + .build(device.clone()) + .unwrap())), + device: device, - entry_point: entry_point, + render_pass: render_pass, } }