use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, DeviceLocalBuffer, ImmutableBuffer, BufferAccess}; use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet, StdDescriptorPoolAlloc, DescriptorSetDesc}; use vulkano::device::{Device, DeviceExtensions, QueuesIter, Queue}; use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice, QueueFamily}; use vulkano::pipeline::{ComputePipeline, GraphicsPipeline, GraphicsPipelineAbstract, GraphicsPipelineBuilder}; 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, RenderPassDesc}; 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, DescriptorSet}; 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; use crate::vertex_2d::ColoredVertex2D; struct EntryPoint<'a> { compiled_shaders: CompiledShaders, frag_entry_point: Option>, vertex_entry_point: Option>, vertex_shader_module: Arc, fragment_shader_module: Arc, } #[derive(Clone)] pub struct ShaderKernels { // pub swapchain : Arc>, // pub swapchain_images: Vec>>, // Surface which is drawn to pub render_pass: Arc, pub graphics_pipeline: Option>, device: Arc, } impl ShaderKernels { 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 => { // 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: &Arc>) -> Self { // 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 self; // }; // // 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; // self // } pub fn new(filename: String, surface: &Arc>, queue: Arc, physical: PhysicalDevice, device: Arc) -> ShaderKernels { // 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 capabilities = surface.capabilities(physical).unwrap(); let format = capabilities.supported_formats[0].0; 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 { 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 { 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 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)) }; 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, 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: 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()); ShaderKernels { // swapchain: swapchain, // swapchain_images: images, //physical: physical, //options: CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap(), 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, render_pass: render_pass, } } }