use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, DeviceLocalBuffer, ImmutableBuffer, BufferAccess}; 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::sync::{GpuFuture, FlushError}; use vulkano::sync; use std::time::SystemTime; use std::sync::Arc; use std::ffi::CStr; use std::path::PathBuf; use shade_runner as sr; use image::{DynamicImage, ImageBuffer}; use image::GenericImageView; use vulkano::descriptor::pipeline_layout::PipelineLayout; use image::GenericImage; use shade_runner::{ComputeLayout, CompileError, FragLayout, FragInput, FragOutput, VertInput, VertOutput, VertLayout, CompiledShaders, Entry}; use vulkano::descriptor::descriptor_set::{PersistentDescriptorSetBuf, PersistentDescriptorSetImg, PersistentDescriptorSetSampler}; use shaderc::CompileOptions; use vulkano::framebuffer::{Subpass, RenderPass, RenderPassAbstract, Framebuffer, FramebufferAbstract}; use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, GraphicsEntryPoint, SpecializationConstants, SpecializationMapEntry}; use vulkano::swapchain::{Swapchain, PresentMode, SurfaceTransform, Surface, SwapchainCreationError, AcquireError}; use vulkano::swapchain::acquire_next_image; use vulkano::image::swapchain::SwapchainImage; use winit::{EventsLoop, WindowBuilder, Window, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::pipeline::vertex::{SingleBufferDefinition, Vertex}; use vulkano::descriptor::PipelineLayoutAbstract; use std::alloc::Layout; use vulkano::pipeline::viewport::Viewport; use image::ImageFormat; use vulkano::image::immutable::ImmutableImage; use vulkano::image::attachment::AttachmentImage; use vulkano::image::{Dimensions, ImageUsage}; use vulkano::format::Format; use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode}; use image::flat::NormalForm::ColumnMajorPacked; use crate::vkprocessor::SimpleSpecializationConstants; struct EntryPoint<'a> { compiled_shaders: CompiledShaders, frag_entry_point: Option>, vertex_entry_point: Option>, vertex_shader_module: Arc, fragment_shader_module: Arc, } #[derive(Default, Debug, Clone)] struct tVertex { position: [f32; 2] } pub struct ShaderKernels<'a> { swapchain : Arc>, swapchain_images: Vec>>, // Surface which is drawn to pub physical: PhysicalDevice<'a>, shader: CompiledShaders, options: CompileOptions<'a>, pub render_pass: Arc, pub graphics_pipeline: Option>, device: Arc, entry_point: EntryPoint<'a>, } // return the frame buffers /* let mut framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), self.render_pass.clone().unwrap().clone(), &mut self.dynamic_state); */ impl<'a> ShaderKernels<'a> { fn get_path(filename: String) -> (PathBuf, PathBuf) { 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")); (vertex_shader_path, fragment_shader_path) } pub fn get_pipeline(&mut self) -> Arc { 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() )); self.graphics_pipeline.clone().unwrap() } } } pub fn new(filename: String, surface: &'a Arc>, queue: Arc, physical: PhysicalDevice<'a>, device: Arc) -> ShaderKernels<'a> { let (mut swapchain, images) = { let capabilities = surface.capabilities(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. panic!("window closed"); }; Swapchain::new(device.clone(), surface.clone(), capabilities.min_image_count, format, initial_dimensions, 1, // Layers usage, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, None).unwrap() }; let filenames = ShaderKernels::get_path(filename.clone()); // TODO: better compile message, run til successful compile let shader = sr::load(filenames.0, filenames.1) .expect("Shader didn't compile"); let vulkano_entry = sr::parse(&shader) .expect("failed to parse"); let fragment_shader_module: Arc = unsafe { vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.fragment.clone()) }.unwrap(); let vertex_shader_module: Arc = unsafe { vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.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"), 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"), vulkano_entry.vert_input, vulkano_entry.vert_output, vulkano_entry.vert_layout, GraphicsShaderType::Vertex)) }; let render_pass = Arc::new(vulkano::single_pass_renderpass!( 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: swapchain.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()); 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 { swapchain: swapchain, 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)), device: device, entry_point: entry_point, } } }