From a91e071909a36d299835c0bcfa08a994dee5d7a7 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Sat, 3 Aug 2019 23:02:26 -0700 Subject: [PATCH] refactored the compute image --- src/vkprocessor.rs | 143 +++++++++++++++-------- src/vkprocessor/compute_image.rs | 184 ++++++++++++++++++++++++++++++ src/vkprocessor/shader_kernels.rs | 4 +- 3 files changed, 281 insertions(+), 50 deletions(-) create mode 100644 src/vkprocessor/compute_image.rs diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index f3928192..409d7de5 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -43,6 +43,10 @@ use crate::vkprocessor::compute_kernel::ComputeKernel; mod shader_kernels; use crate::vkprocessor::shader_kernels::ShaderKernels; + +mod compute_image; +use crate::vkprocessor::compute_image::ComputeImage; + use vulkano::descriptor::descriptor::DescriptorDesc; // @@ -80,18 +84,6 @@ use vulkano::descriptor::descriptor::DescriptorDesc; - - - - - - - - - - - - #[derive(Default, Debug, Clone)] struct tVertex { position: [f32; 2] } @@ -174,11 +166,15 @@ pub struct VkProcessor<'a> { pub xy: (u32, u32), pub render_pass: Option>, pub vertex_buffer: Option>, + pub vertex_buffer2: Option>, pub dynamic_state: DynamicState, - pub graphics_image_swap_buffer: Option>, + pub graphics_image_swap_buffer: Option>, + pub textures: Vec>>, pub image_buffer_store : Vec>, + pub compute_image: Option, + // pub image_buffers_obj : ImageBuffers, } @@ -224,12 +220,16 @@ impl<'a> VkProcessor<'a> { settings_buffer: Option::None, xy: (0, 0), render_pass: Option::None, + vertex_buffer: Option::None, + vertex_buffer2: None, + dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None }, graphics_image_swap_buffer: None, + textures: vec![], image_buffer_store: vec![], - //image_buffers_obj: ImageBuffers::new(), + compute_image: None } } @@ -253,15 +253,63 @@ impl<'a> VkProcessor<'a> { self.shader_kernels = Some(self.shader_kernels.take().unwrap().recreate_swapchain(surface)); } + fn get_texture_from_file(image_filename: String, queue: Arc) -> Arc> { + + let project_root = + std::env::current_dir() + .expect("failed to get root directory"); + + let mut compute_path = project_root.clone(); + compute_path.push(PathBuf::from("resources/images/")); + compute_path.push(PathBuf::from(image_filename)); + + let img = image::open(compute_path).expect("Couldn't find image"); + + let xy = img.dimensions(); + + let data_length = xy.0 * xy.1 * 4; + let pixel_count = img.raw_pixels().len(); + + let mut image_buffer = Vec::new(); + + if pixel_count != data_length as usize { + println!("Creating apha channel..."); + for i in img.raw_pixels().iter() { + if (image_buffer.len() + 1) % 4 == 0 { + image_buffer.push(255); + } + image_buffer.push(*i); + } + image_buffer.push(255); + } else { + image_buffer = img.raw_pixels(); + } + + let (texture, tex_future) = ImmutableImage::from_iter( + image_buffer.iter().cloned(), + Dimensions::Dim2d { width: xy.0, height: xy.1 }, + Format::R8G8B8A8Srgb, + queue.clone() + ).unwrap(); + + texture + } + + pub fn load_compute_image(&mut self, image_filename: String) { + self.compute_image = Some(ComputeImage::new(self.device.clone(), image_filename.clone())); + } + pub fn load_buffers(&mut self, image_filename: String) { + self.load_compute_image(image_filename.clone()); + let project_root = std::env::current_dir() .expect("failed to get root directory"); let mut compute_path = project_root.clone(); compute_path.push(PathBuf::from("resources/images/")); - compute_path.push(PathBuf::from(image_filename)); + compute_path.push(PathBuf::from(image_filename.clone())); let img = image::open(compute_path).expect("Couldn't find image"); @@ -343,18 +391,20 @@ impl<'a> VkProcessor<'a> { ].iter().cloned()).unwrap() }; - self.vertex_buffer = Some(vertex_buffer); + let vertex_buffer2 = { - let (texture, tex_future) = { - ImmutableImage::from_iter( - self.image_buffer.iter().cloned(), - Dimensions::Dim2d { width: self.xy.0, height: self.xy.1 }, - Format::R8G8B8A8Srgb, - self.queue.clone() - ).unwrap() + CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::all(), [ + tVertex { position: [-1.0, -1.0 ] }, + tVertex { position: [-1.0, -0.5 ] }, + tVertex { position: [-0.5, 0.5 ] }, + tVertex { position: [-0.5, -1.0 ] }, + ].iter().cloned()).unwrap() }; + self.vertex_buffer = Some(vertex_buffer); + self.vertex_buffer2 = Some(vertex_buffer2); + let compute_transfer_image = { let mut usage = ImageUsage::none(); @@ -368,13 +418,15 @@ impl<'a> VkProcessor<'a> { usage) }; - self.image_buffer_store.push(Box::new(texture.clone())); - - self.graphics_image_buffer = Some(texture.clone()); self.graphics_image_swap_buffer = Some(compute_transfer_image.clone().unwrap()); - } + let texture = VkProcessor::get_texture_from_file(image_filename.clone(), self.queue.clone()); + self.textures.push(texture); + + + + } // The image set is the containing object for all texture and image hooks. @@ -385,18 +437,12 @@ impl<'a> VkProcessor<'a> { MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(); - let mut descriptor_sets = PersistentDescriptorSet::start( - self.shader_kernels.clone().unwrap().graphics_pipeline.clone().unwrap().clone(), 0 - ); - - let descriptor_sets = descriptor_sets.add_sampled_image(self.graphics_image_buffer.clone().unwrap().clone(), sampler.clone()).unwrap(); - let o : Box = Box::new( PersistentDescriptorSet::start( self.shader_kernels.clone().unwrap().graphics_pipeline.clone().unwrap().clone(), 0 ) - .add_sampled_image(self.graphics_image_buffer.clone().unwrap().clone(), sampler.clone()).unwrap() - .add_image(self.graphics_image_swap_buffer.clone().unwrap().clone()).unwrap() + .add_sampled_image(self.textures.get(0).unwrap().clone(), sampler.clone()).unwrap() + .add_image(self.compute_image.clone().unwrap().clone().get_swap_buffer().clone()).unwrap() .build().unwrap()); o } @@ -452,16 +498,22 @@ impl<'a> VkProcessor<'a> { let mut v = Vec::new(); v.push(self.vertex_buffer.clone().unwrap().clone()); + let mut v2 = Vec::new(); + v2.push(self.vertex_buffer2.clone().unwrap().clone()); + + let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(self.device.clone(), self.queue.family()) .unwrap() .dispatch([self.xy.0, self.xy.1, 1], self.compute_pipeline.clone().unwrap().clone(), - self.compute_set.clone().unwrap().clone(), ()).unwrap() + self.compute_image.clone().unwrap().clone().get_descriptor_set(self.compute_pipeline.clone().unwrap().clone()).clone(), ()).unwrap() + //self.compute_set.clone().unwrap().clone(), ()).unwrap() + + .copy_buffer_to_image(self.compute_image.clone().unwrap().clone().rw_buffers.get(0).unwrap().clone(), + self.compute_image.clone().unwrap().clone().get_swap_buffer().clone()).unwrap() - .copy_buffer_to_image(self.compute_image_buffers.get(0).unwrap().clone(), - self.graphics_image_swap_buffer.clone().unwrap()).unwrap() .begin_render_pass(framebuffers[image_num].clone(), false, clear_values) .unwrap() @@ -470,21 +522,16 @@ impl<'a> VkProcessor<'a> { vec![self.get_image_set()], ()) .unwrap() +// .draw(self.shader_kernels.clone().unwrap().graphics_pipeline.clone().unwrap().clone(), +// &self.dynamic_state.clone(), v2, +// vec![self.get_image_set()], ()) +// .unwrap() + .end_render_pass() .unwrap() .build().unwrap(); - let mut data_buffer_content = self.compute_image_buffers.get(0).unwrap().read().unwrap(); - let img = ImageBuffer::from_fn(self.xy.0, self.xy.1, |x, y| { - let r = data_buffer_content[((self.xy.0 * y + x) * 4 + 0) as usize] as u8; - let g = data_buffer_content[((self.xy.0 * y + x) * 4 + 1) as usize] as u8; - let b = data_buffer_content[((self.xy.0 * y + x) * 4 + 2) as usize] as u8; - let a = data_buffer_content[((self.xy.0 * y + x) * 4 + 3) as usize] as u8; - - image::Rgba([r, g, b, 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() diff --git a/src/vkprocessor/compute_image.rs b/src/vkprocessor/compute_image.rs new file mode 100644 index 00000000..78daac67 --- /dev/null +++ b/src/vkprocessor/compute_image.rs @@ -0,0 +1,184 @@ +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, 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}; +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 image::Rgba; +use crate::vkprocessor::SimpleSpecializationConstants; + + +#[derive(Default, Debug, Clone)] +struct tVertex { position: [f32; 2] } + +#[derive(Clone)] +pub struct ComputeImage { + + device: Arc, + + compute_graphics_swap_buffer: std::sync::Arc, + + image_buffer: Vec, + + xy: (u32, u32), + + pub rw_buffers: Vec>>, + pub settings_buffer: Arc>, +} + + +impl ComputeImage { + + fn load_raw(filename: String) -> (Vec, (u32,u32)) { + + let project_root = + std::env::current_dir() + .expect("failed to get root directory"); + + let mut compute_path = project_root.clone(); + compute_path.push(PathBuf::from("resources/images/")); + compute_path.push(PathBuf::from(filename.clone())); + + let img = image::open(compute_path).expect("Couldn't find image"); + + let xy = img.dimensions(); + + let data_length = xy.0 * xy.1 * 4; + let pixel_count = img.raw_pixels().len(); + + let mut image_buffer = Vec::new(); + + if pixel_count != data_length as usize { + println!("Creating apha channel..."); + for i in img.raw_pixels().iter() { + if (image_buffer.len() + 1) % 4 == 0 { + image_buffer.push(255); + } + image_buffer.push(*i); + } + image_buffer.push(255); + } else { + image_buffer = img.raw_pixels(); + } + + (image_buffer, xy) + } + + pub fn new(device: Arc, image_filename: String) -> ComputeImage { + + let (image_buffer, xy) = ComputeImage::load_raw(image_filename); + + let compute_graphics_swap_buffer = { + + let mut usage = ImageUsage::none(); + usage.transfer_destination = true; + usage.storage = true; + + AttachmentImage::with_usage( + device.clone(), + [xy.0, xy.1], + Format::R8G8B8A8Uint, + usage) + }; + + let data_length = xy.0 * xy.1 * 4; + + // Pull out the image data and place it in a buffer for the kernel to write to and for us to read from + let write_buffer = { + let mut buff = image_buffer.iter(); + let data_iter = (0..data_length).map(|n| *(buff.next().unwrap())); + CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), data_iter).unwrap() + }; + + + // Pull out the image data and place it in a buffer for the kernel to read from + let read_buffer = { + let mut buff = image_buffer.iter(); + let data_iter = (0..data_length).map(|n| *(buff.next().unwrap())); + CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), data_iter).unwrap() + }; + + + // A buffer to hold many i32 values to use as settings + let settings_buffer = { + let vec = vec![xy.0, xy.1]; + let mut buff = vec.iter(); + let data_iter = + (0..2).map(|n| *(buff.next().unwrap())); + CpuAccessibleBuffer::from_iter(device.clone(), + BufferUsage::all(), + data_iter).unwrap() + }; + + ComputeImage{ + device: device.clone(), + compute_graphics_swap_buffer: compute_graphics_swap_buffer.unwrap(), + image_buffer: image_buffer, + xy: (0, 0), + rw_buffers: vec![write_buffer, read_buffer], + settings_buffer: settings_buffer + } + } + + pub fn get_swap_buffer(&mut self) -> Arc { + self.compute_graphics_swap_buffer.clone() + } + + pub fn read_read_buffer(&mut self) -> ImageBuffer, Vec>{ + + let data_buffer_content = self.rw_buffers.get(0).unwrap().read().unwrap(); + ImageBuffer::from_fn(self.xy.0, self.xy.1, |x, y| { + let r = data_buffer_content[((self.xy.0 * y + x) * 4 + 0) as usize] as u8; + let g = data_buffer_content[((self.xy.0 * y + x) * 4 + 1) as usize] as u8; + let b = data_buffer_content[((self.xy.0 * y + x) * 4 + 2) as usize] as u8; + let a = data_buffer_content[((self.xy.0 * y + x) * 4 + 3) as usize] as u8; + + image::Rgba([r, g, b, a]) + }) + } + + pub fn get_descriptor_set(&self, compute_pipeline: std::sync::Arc>>) + -> Arc>>, ((((), + PersistentDescriptorSetBuf>>), + PersistentDescriptorSetBuf>>), + PersistentDescriptorSetBuf>>)>> { + + Arc::new(PersistentDescriptorSet::start(compute_pipeline.clone(), 0) + .add_buffer(self.rw_buffers.get(0).unwrap().clone()).unwrap() + .add_buffer(self.rw_buffers.get(1).unwrap().clone()).unwrap() + .add_buffer(self.settings_buffer.clone()).unwrap() + .build().unwrap()) + } +} \ No newline at end of file diff --git a/src/vkprocessor/shader_kernels.rs b/src/vkprocessor/shader_kernels.rs index 41fee098..ee7b7bd4 100644 --- a/src/vkprocessor/shader_kernels.rs +++ b/src/vkprocessor/shader_kernels.rs @@ -56,7 +56,7 @@ pub struct ShaderKernels { pub swapchain_images: Vec>>, // Surface which is drawn to //pub physical: PhysicalDevice<'a>, - // shader: CompiledShaders, + //shader: CompiledShaders, //options: CompileOptions<'a>, @@ -65,7 +65,7 @@ pub struct ShaderKernels { device: Arc, - // entry_point: EntryPoint<'a>, + // entry_point: EntryPoint<'a>, } // return the frame buffers