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, Capabilities}; 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::vertex_2d::ColoredVertex2D; /* Shaderkernel holds the pipeline and render pass for the inputted shader source */ #[derive(Clone)] pub struct ShaderKernels { pub render_pass: Arc, 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 { self.graphics_pipeline.clone().unwrap() } pub fn new(filename: String, capabilities: Capabilities, queue: Arc, physical: PhysicalDevice, device: Arc) -> ShaderKernels { 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 { graphics_pipeline: Some(Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer::() .vertex_shader(vertex_entry_point.clone().unwrap(), ShaderSpecializationConstants { first_constant: 0, second_constant: 0, third_constant: 0.0, }) .triangle_fan() // Use a resizable viewport set to draw over the entire window .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(frag_entry_point.clone().unwrap(), ShaderSpecializationConstants { 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()) .build(device.clone()) .unwrap())), device: device, render_pass: render_pass, } } } #[repr(C)] #[derive(Default, Debug, Clone)] // TODO: This needs to be duplicated and moved into their respective containers shaderkenrels copute struct ShaderSpecializationConstants { first_constant: i32, second_constant: u32, third_constant: f32, } unsafe impl SpecializationConstants for ShaderSpecializationConstants { fn descriptors() -> &'static [SpecializationMapEntry] { static DESCRIPTORS: [SpecializationMapEntry; 3] = [ SpecializationMapEntry { constant_id: 0, offset: 0, size: 4, }, SpecializationMapEntry { constant_id: 1, offset: 4, size: 4, }, SpecializationMapEntry { constant_id: 2, offset: 8, size: 4, }, ]; &DESCRIPTORS } }