From e7d4d6a8e2d3aaf49d33f305ffd8cf0eb8ff1ee8 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Tue, 2 Jul 2019 18:03:50 -0700 Subject: [PATCH] took out all the sfml shader stuff. will port the rest to vulkan if buffer swapping becomes a perf issue --- src/main.rs | 371 ++++++++++++++++++---------------------------------- 1 file changed, 124 insertions(+), 247 deletions(-) diff --git a/src/main.rs b/src/main.rs index c9c774a2..87a438a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,243 +47,140 @@ mod timer; mod input; mod util; -// The container trait for all the shaders -trait Effect: Drawable { - fn update(&mut self, t: f32, x: f32, y: f32); - fn name(&self) -> &str; - fn as_drawable(&self) -> &Drawable; -} - - -// ======= LARGE MULTISPRITE SHADER DEMO =========== -struct Edge<'t> { - surface: RenderTexture, - bg_sprite: Sprite<'t>, - entities: Vec>, - shader: Shader<'static>, -} - -impl<'t> Edge<'t> { - fn new(bg_texture: &'t Texture, entity_texture: &'t Texture) -> Self { - let mut surface = RenderTexture::new(800, 600, false).unwrap(); - surface.set_smooth(true); - let mut bg_sprite = Sprite::with_texture(bg_texture); - bg_sprite.set_position((0., 0.)); - let mut entities = Vec::new(); - - for i in 0..6 { - let mut entity = Sprite::with_texture(entity_texture); - entity.set_texture_rect(&IntRect::new(96 * i, 0, 96, 96)); - entities.push(entity); - } - - let mut shader = Shader::from_file(None, None, Some("resources/shaders/edge.frag")).unwrap(); - shader.set_uniform_current_texture("texture"); - - Self { - surface, - bg_sprite, - entities, - shader, - } - } -} - -impl<'t> Drawable for Edge<'t> { - fn draw<'a: 'shader, 'texture, 'shader, 'shader_texture>( - &'a self, - target: &mut RenderTarget, - mut states: RenderStates<'texture, 'shader, 'shader_texture>, - ) { - states.shader = Some(&self.shader); - target.draw_with_renderstates(&Sprite::with_texture(self.surface.texture()), states); - } -} - -impl<'t> Effect for Edge<'t> { - fn update(&mut self, t: f32, x: f32, y: f32) { - self.shader - .set_uniform_float("edge_threshold", 1. - (x + y) / 2.); - let entities_len = self.entities.len() as f32; - - for (i, en) in self.entities.iter_mut().enumerate() { - let pos = ( - (0.25 * (t * i as f32 + (entities_len - i as f32))).cos() * 300. + 350., - (0.25 * (t * (entities_len - i as f32) + i as f32)).cos() * 200. + 250., - ); - en.set_position(pos); - } - self.surface.clear(&Color::WHITE); - self.surface.draw(&self.bg_sprite); - for en in &self.entities { - self.surface.draw(en); - } - self.surface.display(); - } - fn as_drawable(&self) -> &Drawable { - self - } - fn name(&self) -> &str { - "edge post-effect" - } -} -// ================================================= - fn main() { - - // Create the vulkan instance, device, and device queue - let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); - let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); - let queue_family = physical.queue_families().find(|&q| q.supports_compute()).unwrap(); - let (device, mut queues) = Device::new(physical, - physical.supported_features(), - &DeviceExtensions::none(), - [(queue_family, 0.5)].iter().cloned()).unwrap(); - let queue = queues.next().unwrap(); - - println!("Device initialized"); - - 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/shaders/add.compute")); - - let shader = sr::load_compute(compute_path).expect("Failed to compile"); - let vulkano_entry = sr::parse_compute(&shader).expect("failed to parse"); - - let x = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.compute) - }.unwrap(); - - - // Compile the shader and add it to a pipeline - let pipeline = Arc::new({ - unsafe { - ComputePipeline::new(device.clone(), &x.compute_entry_point( - CStr::from_bytes_with_nul_unchecked(b"main\0"), - vulkano_entry.compute_layout), &() - ).unwrap() - } - }); - // Load up the input image, determine some details - let mut img = image::open("resources/images/test.png").unwrap(); + let mut img = image::open("resources/images/test2.png").unwrap(); let xy = img.dimensions(); - let data_length = xy.0*xy.1*4; - - let pixel_count = img.raw_pixels().len(); - println!("Pixel count {}", pixel_count); - + let data_length = xy.0 * xy.1 * 4; let mut image_buffer = Vec::new(); - if pixel_count != data_length as usize { - 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(); - } - - println!("Buffer length {}", image_buffer.len()); - println!("Size {:?}", xy); - println!("Allocating Buffers..."); { - - //CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), image_buffer.clone()).unwrap() - - - // 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(); - + // Create the vulkan instance, device, and device queue + let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); + let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); + let queue_family = physical.queue_families().find(|&q| q.supports_compute()).unwrap(); + let (device, mut queues) = Device::new(physical, + physical.supported_features(), + &DeviceExtensions::none(), + [(queue_family, 0.5)].iter().cloned()).unwrap(); + let queue = queues.next().unwrap(); + + println!("Device initialized"); + + 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/shaders/add.compute")); + + let shader = sr::load_compute(compute_path).expect("Failed to compile"); + let vulkano_entry = sr::parse_compute(&shader).expect("failed to parse"); + + let x = unsafe { + vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.compute) + }.unwrap(); + + // Compile the shader and add it to a pipeline + let pipeline = Arc::new({ unsafe { - let uninitialized = - CpuAccessibleBuffer::raw(device, data_length as usize, BufferUsage::all(), iter::empty()).unwrap(); + ComputePipeline::new(device.clone(), &x.compute_entry_point( + CStr::from_bytes_with_nul_unchecked(b"main\0"), + vulkano_entry.compute_layout), &() + ).unwrap() + } + }); - { - let mut mapping = uninitialized.write().unwrap(); - ptr::write(&mut *mapping, image_buffer.as_slice()) - } + let pixel_count = img.raw_pixels().len(); + println!("Pixel count {}", pixel_count); - uninitialized - } - }; - - // 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() -// let q = ImmutableBuffer::from_data(image_buffer.clone(), BufferUsage::all(), queue.clone()).unwrap(); -// q.1.flush(); -// q.0 - - //CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), image_buffer.clone()).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() - }; - - println!("Done"); - // Create the data descriptor set for our previously created shader pipeline - let mut set = PersistentDescriptorSet::start(pipeline.clone(), 0) - .add_buffer(write_buffer.clone()).unwrap() - .add_buffer(read_buffer.clone()).unwrap() - .add_buffer(settings_buffer.clone()).unwrap(); - - let mut set = Arc::new(set.build().unwrap()); - - println!("Running Kernel..."); - // The command buffer I think pretty much serves to define what runs where for how many times - let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap() - .dispatch([xy.0, xy.1, 1], pipeline.clone(), set.clone(), ()).unwrap() - .build().unwrap(); - - // Create a future for running the command buffer and then just fence it - let future = sync::now(device.clone()) - .then_execute(queue.clone(), command_buffer).unwrap() - .then_signal_fence_and_flush().unwrap(); - - // I think this is redundant and returns immediately - future.wait(None).unwrap(); - - println!("Done running kernel"); - println!("Reading output"); - // The buffer is sync'd so we can just read straight from the handle - let data_buffer_content = write_buffer.read().unwrap(); - - for y in 0 .. xy.1 { - for x in 0 .. xy.0 { - - let r = data_buffer_content[((xy.0 * y + x) * 4 + 0) as usize] as u8; - let g = data_buffer_content[((xy.0 * y + x) * 4 + 1) as usize] as u8; - let b = data_buffer_content[((xy.0 * y + x) * 4 + 2) as usize] as u8; - let a = data_buffer_content[((xy.0 * y + x) * 4 + 3) as usize] as u8; - - *image_buffer.get_mut(((xy.0 * y + x) * 4 + 0) as usize).unwrap() = r; - *image_buffer.get_mut(((xy.0 * y + x) * 4 + 1) as usize).unwrap() = g; - *image_buffer.get_mut(((xy.0 * y + x) * 4 + 2) as usize).unwrap() = b; - *image_buffer.get_mut(((xy.0 * y + x) * 4 + 3) as usize).unwrap() = a; - - img.put_pixel(x, y, image::Rgba([r, g, b, a])) + if pixel_count != data_length as usize { + 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(); } - } - println!("Saving output"); - img.save(format!("output/{}.png", SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs())); + println!("Buffer length {}", image_buffer.len()); + println!("Size {:?}", xy); + + println!("Allocating Buffers..."); + { + // 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() + }; + + println!("Done"); + // Create the data descriptor set for our previously created shader pipeline + let mut set = PersistentDescriptorSet::start(pipeline.clone(), 0) + .add_buffer(write_buffer.clone()).unwrap() + .add_buffer(read_buffer.clone()).unwrap() + .add_buffer(settings_buffer.clone()).unwrap(); + + let mut set = Arc::new(set.build().unwrap()); + + println!("Running Kernel..."); + // The command buffer I think pretty much serves to define what runs where for how many times + let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap() + .dispatch([xy.0, xy.1, 1], pipeline.clone(), set.clone(), ()).unwrap() + .build().unwrap(); + + // Create a future for running the command buffer and then just fence it + let future = sync::now(device.clone()) + .then_execute(queue.clone(), command_buffer).unwrap() + .then_signal_fence_and_flush().unwrap(); + + // I think this is redundant and returns immediately + future.wait(None).unwrap(); + + println!("Done running kernel"); + + // The buffer is sync'd so we can just read straight from the handle + let mut data_buffer_content = write_buffer.read().unwrap(); + + println!("Reading output"); + + for y in 0..xy.1 { + for x in 0..xy.0 { + let r = data_buffer_content[((xy.0 * y + x) * 4 + 0) as usize] as u8; + let g = data_buffer_content[((xy.0 * y + x) * 4 + 1) as usize] as u8; + let b = data_buffer_content[((xy.0 * y + x) * 4 + 2) as usize] as u8; + let a = data_buffer_content[((xy.0 * y + x) * 4 + 3) as usize] as u8; + + *image_buffer.get_mut(((xy.0 * y + x) * 4 + 0) as usize).unwrap() = r; + *image_buffer.get_mut(((xy.0 * y + x) * 4 + 1) as usize).unwrap() = g; + *image_buffer.get_mut(((xy.0 * y + x) * 4 + 2) as usize).unwrap() = b; + *image_buffer.get_mut(((xy.0 * y + x) * 4 + 3) as usize).unwrap() = a; + + img.put_pixel(x, y, image::Rgba([r, g, b, a])) + } + } + }// Currently bringing all this start shit outta scope to see if it stops my gpu from screaming + + println!("Saving output"); + img.save(format!("output/{}.png", SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs())); + } let mut window = RenderWindow::new( (900, 900), @@ -292,32 +189,16 @@ fn main() { &Default::default(), ); - let mut timer = Timer::new(); let mut input = Input::new(); - //========================================== let font = Font::from_file("resources/fonts/sansation.ttf").unwrap(); - let mut bg_texture = Texture::new(xy.0, xy.1).unwrap(); bg_texture.update_from_pixels(image_buffer.as_slice(), xy.0, xy.1, 0, 0); - //let mut bg_texture = Texture::from_file("resources/images/sfml.png").unwrap(); - //bg_texture.set_smooth(true); - let mut entity_texture = Texture::from_file("resources/images/devices.png").unwrap(); - entity_texture.set_smooth(true); - - let mut effects: [Box; 1] = [ - Box::new(Edge::new(&bg_texture, &entity_texture)), - ]; - let mut current = 0; - - let text_bg_texture = Texture::from_file("resources/images/text-background.png").unwrap(); - let mut text_bg = Sprite::with_texture(&text_bg_texture); - text_bg.set_position((0., 520.)); - text_bg.set_color(&Color::rgba(255, 255, 255, 200)); - //========================================== + let mut background_sprite = Sprite::with_texture(&bg_texture); + background_sprite.set_position((0., 0.)); let mut slider = Slider::new(40.0, None); @@ -363,13 +244,9 @@ fn main() { accumulator_time -= step_size; } - let x = 0.;//window.mouse_position().x as f32 / window.size().x as f32; - let y = 0.;//window.mouse_position().y as f32 / window.size().y as f32; - effects[current].update(elapsed_time*1.0, x, y); - window.clear(&Color::BLACK); - window.draw(effects[current].as_drawable()); + window.draw(&background_sprite); window.draw(&slider);