From d0afc674c1f3216083834e18f1f6e19904faaa5a Mon Sep 17 00:00:00 2001 From: yanchith Date: Wed, 4 Apr 2018 13:15:00 +1000 Subject: [PATCH 01/10] Remove unused imports --- Cargo.toml | 8 + bloom/main.rs | 911 ++++++++++++++++++++++++++++++++++++++++++++ persistence/main.rs | 679 +++++++++++++++++++++++++++++++++ 3 files changed, 1598 insertions(+) create mode 100644 bloom/main.rs create mode 100644 persistence/main.rs diff --git a/Cargo.toml b/Cargo.toml index debb1f7..bd1c971 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,14 @@ path = "deferred/main.rs" name = "msaa-renderpass" path = "msaa-renderpass/main.rs" +[[bin]] +name = "persistence" +path = "persistence/main.rs" + +[[bin]] +name = "bloom" +path = "bloom/main.rs" + [[bin]] name = "triangle" path = "triangle/main.rs" diff --git a/bloom/main.rs b/bloom/main.rs new file mode 100644 index 0000000..685990c --- /dev/null +++ b/bloom/main.rs @@ -0,0 +1,911 @@ +// Copyright (c) 2018 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +/* + +TODO: +- sampling +- HDR textures +- optimize blur kernel + +*/ + +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate winit; +extern crate vulkano_win; +extern crate cgmath; + +use std::sync::Arc; +use std::mem; +use std::time::Instant; + +use cgmath::{Rad, Point3, Vector3, Matrix3, Matrix4}; + +use winit::{EventsLoop, WindowBuilder, Event, WindowEvent}; + +use vulkano_win::VkSurfaceBuild; + +use vulkano::{ + instance::{ + Instance, + PhysicalDevice, + }, + device::{ + Device, + DeviceExtensions, + }, + buffer::{ + BufferUsage, + CpuAccessibleBuffer, + CpuBufferPool, + }, + command_buffer::{ + AutoCommandBufferBuilder, + DynamicState, + }, + descriptor::descriptor_set::PersistentDescriptorSet, + image::{ + ImageUsage, + AttachmentImage, + ImageLayout, + }, + sampler::Sampler, + format::{ + Format, + ClearValue, + }, + framebuffer::{ + Framebuffer, + Subpass, + }, + pipeline::{ + GraphicsPipeline, + viewport::Viewport, + }, + swapchain::{ + self, + PresentMode, + SurfaceTransform, + Swapchain, + AcquireError, + SwapchainCreationError, + }, + sync::{ + self as vk_sync, + GpuFuture, + } +}; + +fn main() { + let instance = { + let extensions = vulkano_win::required_extensions(); + Instance::new(None, &extensions, None) + .expect("failed to create Vulkan instance") + }; + + let physical = PhysicalDevice::enumerate(&instance) + .next() + .expect("no device available"); + + println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); + + let mut events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window"); + + let queue_family = physical.queue_families() + .find(|&q| { + q.supports_graphics() && surface.is_supported(q).unwrap_or(false) + }) + .expect("couldn't find a graphical queue family"); + + let (device, mut queues) = { + let device_ext = DeviceExtensions { + khr_swapchain: true, + .. DeviceExtensions::none() + }; + + Device::new( + physical, + physical.supported_features(), + &device_ext, + [(queue_family, 0.5)].iter().cloned(), + ).expect("failed to create device") + }; + + let queue = queues.next().unwrap(); + + let mut dimensions; + let (mut swapchain, mut images) = { + let caps = surface.capabilities(physical) + .expect("failed to get surface capabilities"); + + dimensions = caps.current_extent.unwrap_or([1024, 768]); + let alpha = caps.supported_composite_alpha.iter().next().unwrap(); + let format = caps.supported_formats[0].0; + + Swapchain::new( + device.clone(), + surface.clone(), + caps.min_image_count, + format, + dimensions, + 1, + caps.supported_usage_flags, + &queue, + SurfaceTransform::Identity, + alpha, + PresentMode::Fifo, + true, + None, + ).expect("failed to create swapchain") + }; + let postprocess_dimensions = [dimensions[0] / 2, dimensions[0] / 2]; + + let sampler = Sampler::simple_repeat_linear_no_mipmap(device.clone()); + + // let color_format = Format::B8G8R8A8Unorm; + let color_format = swapchain.format(); + let depth_format = Format::D16Unorm; + let scene_color_attachment = AttachmentImage::with_usage( + device.clone(), + dimensions, + color_format, + ImageUsage { + storage: true, + color_attachment: true, + sampled: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let scene_depth_attachment = AttachmentImage::with_usage( + device.clone(), + dimensions, + depth_format, + ImageUsage { + storage: true, + depth_stencil_attachment: true, + sampled: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let sep_attachment = AttachmentImage::with_usage( + device.clone(), + postprocess_dimensions, + color_format, + ImageUsage { + storage: true, + color_attachment: true, + sampled: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let ping_attachment = AttachmentImage::with_usage( + device.clone(), + postprocess_dimensions, + color_format, + ImageUsage { + storage: true, + color_attachment: true, + sampled: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let pong_attachment = AttachmentImage::with_usage( + device.clone(), + postprocess_dimensions, + color_format, + ImageUsage { + storage: true, + color_attachment: true, + sampled: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let scene_vertex_buffer = { + #[derive(Debug, Clone)] + struct Vertex { a_position: [f32; 2] } + impl_vertex!(Vertex, a_position); + + CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ + Vertex { a_position: [-0.5, -0.25] }, + Vertex { a_position: [0.0, 0.5] }, + Vertex { a_position: [0.25, -0.1] }, + ].iter().cloned()).expect("failed to create buffer") + }; + + let postprocess_vertex_buffer = { + #[derive(Debug, Clone)] + struct VertexUv { a_position: [f32; 2], a_texcoord: [f32; 2] } + impl_vertex!(VertexUv, a_position, a_texcoord); + + CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ + VertexUv { a_position: [-1.0, 3.0], a_texcoord: [0.0, 2.0] }, + VertexUv { a_position: [-1.0, -1.0], a_texcoord: [0.0, 0.0] }, + VertexUv { a_position: [3.0, -1.0], a_texcoord: [2.0, 0.0] }, + ].iter().cloned()).expect("failed to create buffer") + }; + + let matrix_uniform_buffer = CpuBufferPool::::new( + device.clone(), + BufferUsage::all(), + ); + + let blur_direction_uniform_buffer = { + CpuAccessibleBuffer::from_data( + device.clone(), + BufferUsage::all(), + postprocess_blur_fs_mod::ty::BlurDirection { + direction: [1, 0], + } + ).expect("failed to create buffer") + }; + + let blur_kernel_uniform_buffer = { + CpuAccessibleBuffer::from_data( + device.clone(), + BufferUsage::all(), + postprocess_blur_fs_mod::ty::BlurKernel { + kernel: [ + 0.382925, + 0.24173, + 0.060598, + 0.005977, + 0.000229, + 0.000003, + ], + } + ).expect("failed to create buffer") + }; + + let proj = cgmath::perspective( + Rad(std::f32::consts::FRAC_PI_2), + { dimensions[0] as f32 / dimensions[1] as f32 }, + 0.01, + 100.0, + ); + + let view = Matrix4::look_at( + Point3::new(0.3, 0.3, 1.0), + Point3::new(0.0, 0.0, 0.0), + Vector3::new(0.0, -1.0, 0.0), + ); + + let scene_vs = scene_vs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + let scene_fs = scene_fs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + + let postprocess_vs = postprocess_vs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + let postprocess_sep_fs = postprocess_sep_fs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + let postprocess_blur_fs = postprocess_blur_fs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + let postprocess_tonemap_fs = postprocess_tonemap_fs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + + let scene_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + scene_color: { + load: Clear, + store: Store, + format: color_format, + samples: 1, + }, + scene_depth: { + load: Clear, + store: Store, + format: depth_format, + samples: 1, + } + }, + pass: { + color: [scene_color], + depth_stencil: {scene_depth} + } + ).unwrap() + }); + + let postprocess_sep_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + sep_color: { + load: DontCare, + store: Store, + format: color_format, + samples: 1, + } + }, + pass: { + color: [sep_color], + depth_stencil: {} + } + ).unwrap() + }); + + let postprocess_blur_ping_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + ping_color: { + load: DontCare, + store: Store, + format: color_format, + samples: 1, + } + }, + pass: { + color: [ping_color], + depth_stencil: {} + } + ).unwrap() + }); + + let postprocess_blur_pong_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + pong_color: { + load: DontCare, + store: Store, + format: color_format, + samples: 1, + } + }, + pass: { + color: [pong_color], + depth_stencil: {} + } + ).unwrap() + }); + + let postprocess_tonemap_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + output_color: { + load: DontCare, + store: Store, + format: swapchain.format(), + samples: 1, + } + }, + pass: { + color: [output_color], + depth_stencil: {} + } + ).unwrap() + }); + + let scene_framebuffer = Arc::new({ + Framebuffer::start(scene_renderpass.clone()) + .add(scene_color_attachment.clone()).unwrap() + .add(scene_depth_attachment.clone()).unwrap() + .build().unwrap() + }); + + let sep_framebuffer = Arc::new({ + Framebuffer::start(postprocess_sep_renderpass.clone()) + .add(sep_attachment.clone()).unwrap() + .build().unwrap() + }); + + let ping_framebuffer = Arc::new({ + Framebuffer::start(postprocess_blur_ping_renderpass.clone()) + .add(ping_attachment.clone()).unwrap() + .build().unwrap() + }); + + let pong_framebuffer = Arc::new({ + Framebuffer::start(postprocess_blur_pong_renderpass.clone()) + .add(pong_attachment.clone()).unwrap() + .build().unwrap() + }); + + + let scene_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(scene_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(scene_fs.main_entry_point(), ()) + .render_pass(Subpass::from(scene_renderpass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + }); + + let postprocess_sep_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(postprocess_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(postprocess_sep_fs.main_entry_point(), ()) + .render_pass(Subpass::from(postprocess_sep_renderpass.clone(), 0) + .unwrap()) + .build(device.clone()) + .unwrap() + }); + + let postprocess_blur_ping_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(postprocess_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(postprocess_blur_fs.main_entry_point(), ()) + .render_pass(Subpass::from( + postprocess_blur_ping_renderpass.clone(), + 0, + ) + .unwrap()) + .build(device.clone()) + .unwrap() + }); + + let postprocess_blur_pong_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(postprocess_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(postprocess_blur_fs.main_entry_point(), ()) + .render_pass(Subpass::from( + postprocess_blur_pong_renderpass.clone(), + 0, + ) + .unwrap()) + .build(device.clone()) + .unwrap() + }); + + let postprocess_tonemap_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(postprocess_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(postprocess_tonemap_fs.main_entry_point(), ()) + .render_pass(Subpass::from(postprocess_tonemap_renderpass.clone(), 0) + .unwrap()) + .build(device.clone()) + .unwrap() + }); + + let postprocess_sep_set = Arc::new({ + PersistentDescriptorSet::start(postprocess_sep_pipeline.clone(), 0) + .add_sampled_image(scene_color_attachment.clone(), sampler.clone()) + .unwrap() + .build() + .unwrap() + }); + + // Ping set is used to render to ping, therefore has to use pong attachment + let postprocess_blur_ping_set = Arc::new({ + PersistentDescriptorSet::start(postprocess_blur_ping_pipeline.clone(), 0) + .add_sampled_image(sep_attachment.clone(), sampler.clone()) + .unwrap() + .add_buffer(blur_direction_uniform_buffer.clone()) + .unwrap() + .add_buffer(blur_kernel_uniform_buffer.clone()) + .unwrap() + .build() + .unwrap() + }); + + // Pong set is used to render to pong, therefore has to use ping attachment + let postprocess_blur_pong_set = Arc::new({ + PersistentDescriptorSet::start(postprocess_blur_pong_pipeline.clone(), 0) + .add_sampled_image(ping_attachment.clone(), sampler.clone()) + .unwrap() + .add_buffer(blur_direction_uniform_buffer.clone()) + .unwrap() + .add_buffer(blur_kernel_uniform_buffer.clone()) + .unwrap() + .build() + .unwrap() + }); + + let postprocess_tonemap_set = Arc::new({ + PersistentDescriptorSet::start(postprocess_tonemap_pipeline.clone(), 0) + .add_sampled_image(scene_color_attachment.clone(), sampler.clone()) + .unwrap() + .add_sampled_image(pong_attachment.clone(), sampler.clone()) + .unwrap() + .build() + .unwrap() + }); + + let mut previous_frame_end: Box = Box::new(vk_sync::now(device.clone())); + + let mut framebuffers: Option>>> = None; + let mut recreate_swapchain = false; + + let time_start = Instant::now(); + loop { + previous_frame_end.cleanup_finished(); + + if recreate_swapchain { + dimensions = surface.capabilities(physical) + .expect("failed to get surface capabilities") + .current_extent.unwrap(); + + let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { + Ok(r) => r, + Err(SwapchainCreationError::UnsupportedDimensions) => continue, + Err(err) => panic!("{:?}", err), + }; + + mem::replace(&mut swapchain, new_swapchain); + mem::replace(&mut images, new_images); + + framebuffers = None; + recreate_swapchain = false; + } + + if framebuffers.is_none() { + let new_framebuffers = Some({ + images.iter() + .map(|image| Arc::new({ + Framebuffer::start(postprocess_tonemap_renderpass.clone()) + .add(image.clone()).unwrap() + .build().unwrap() + })) + .collect::>() + }); + mem::replace(&mut framebuffers, new_framebuffers); + } + + let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + recreate_swapchain = true; + continue; + }, + Err(err) => panic!("{:?}", err), + }; + + let matrix_uniform_buffer_subbuffer = { + let elapsed = time_start.elapsed(); + let rotation_factor = elapsed.as_secs() as f64 + + elapsed.subsec_nanos() as f64 * 1e-9; + let rotation = Matrix3::from_angle_z(Rad(rotation_factor as f32)); + + let uniform_data = scene_vs_mod::ty::Matrices { + model: Matrix4::from(rotation).into(), + view: view.into(), + proj: proj.into(), + }; + + matrix_uniform_buffer.next(uniform_data).unwrap() + }; + + let scene_set = Arc::new({ + PersistentDescriptorSet::start(scene_pipeline.clone(), 0) + .add_buffer(matrix_uniform_buffer_subbuffer).unwrap() + .build().unwrap() + }); + + let scene_dynamic_state = DynamicState { + viewports: Some(vec![Viewport { + origin: [0.0, 0.0], + dimensions: [dimensions[0] as f32, dimensions[1] as f32], + depth_range: 0.0 .. 1.0, + }]), + .. DynamicState::none() + }; + + let postprocess_dynamic_state = DynamicState { + viewports: Some(vec![Viewport { + origin: [0.0, 0.0], + dimensions: [ + postprocess_dimensions[0] as f32, + postprocess_dimensions[1] as f32, + ], + depth_range: 0.0 .. 1.0, + }]), + .. DynamicState::none() + }; + + let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit( + device.clone(), + queue.family() + ) + .unwrap() + // BEGIN SCENE + .begin_render_pass( + scene_framebuffer.clone(), + false, + vec![ + ClearValue::Float([0.0, 0.0, 0.0, 1.0]), + ClearValue::Depth(1.0), + ], + ) + .unwrap() + .draw( + scene_pipeline.clone(), + scene_dynamic_state.clone(), + scene_vertex_buffer.clone(), + scene_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + // END SCENE + // BEGIN SEP + .begin_render_pass( + sep_framebuffer.clone(), + false, + vec![ClearValue::None], + ) + .unwrap() + .draw( + postprocess_sep_pipeline.clone(), + postprocess_dynamic_state.clone(), + postprocess_vertex_buffer.clone(), + postprocess_sep_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + // END SEP + // BEGIN BLUR + .begin_render_pass( + ping_framebuffer.clone(), + false, + vec![ClearValue::None], + ) + .unwrap() + .draw( + postprocess_blur_ping_pipeline.clone(), + postprocess_dynamic_state.clone(), + postprocess_vertex_buffer.clone(), + postprocess_blur_ping_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + .begin_render_pass( + pong_framebuffer.clone(), + false, + vec![ClearValue::None], + ) + .unwrap() + .draw( + postprocess_blur_pong_pipeline.clone(), + postprocess_dynamic_state.clone(), + postprocess_vertex_buffer.clone(), + postprocess_blur_pong_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + // END BLUR + // BEGIN TONEMAP + .begin_render_pass( + framebuffers.as_ref().unwrap()[image_num].clone(), + false, + vec![ClearValue::None], + ) + .unwrap() + .draw( + postprocess_tonemap_pipeline.clone(), + scene_dynamic_state.clone(), + postprocess_vertex_buffer.clone(), + postprocess_tonemap_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + // END TONEMAP + .build() + .unwrap(); + + let future = previous_frame_end.join(acquire_future) + .then_execute(queue.clone(), command_buffer).unwrap() + .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => previous_frame_end = Box::new(future), + Err(vk_sync::FlushError::OutOfDate) => { + recreate_swapchain = true; + previous_frame_end = Box::new(vk_sync::now(device.clone())); + }, + Err(e) => { + println!("{:?}", e); + previous_frame_end = Box::new(vk_sync::now(device.clone())); + }, + } + + let mut done = false; + events_loop.poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::Closed, .. } => done = true, + _ => (), + } + }); + if done { return; } + } +} + +#[allow(dead_code)] +mod scene_vs_mod { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[src = " +#version 450 + +layout(set = 0, binding = 0) uniform Matrices { + mat4 model; + mat4 view; + mat4 proj; +} u_matrices; + +layout(location = 0) in vec2 a_position; + +void main() { + gl_Position = u_matrices.proj + * u_matrices.view + * u_matrices.model + * vec4(a_position, 0.0, 1.0); +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod scene_fs_mod { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[src = " +#version 450 + +layout(location = 0) out vec4 f_color; + +void main() { + f_color = vec4(0.2, 0.9, 0.9, 1.0); +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod postprocess_vs_mod { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[src = " +#version 450 + +layout(location = 0) in vec2 a_position; +layout(location = 1) in vec2 a_texcoord; + +layout(location = 0) out vec2 v_texcoord; + +void main() { + v_texcoord = a_texcoord; + gl_Position = vec4(a_position, 0.0, 1.0); +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod postprocess_sep_fs_mod { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[src = " +#version 450 + +layout(set = 0, binding = 0) uniform sampler2D u_image; + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 f_color; + +void main() { + vec4 color = texture(u_image, v_texcoord); + + // Convert to grayscale and compute brightness + float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); + f_color = brightness > 0.7 ? color : vec4(0.0, 0.0, 0.0, 1.0); +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod postprocess_blur_fs_mod { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[src = " +#version 450 + +#define KERNEL_LENGTH 6 + +layout(set = 0, binding = 0) uniform sampler2D u_image; +layout(set = 0, binding = 1) uniform BlurDirection { + ivec2 direction; +} u_blur_direction; +layout(set = 0, binding = 2) uniform BlurKernel { + float[KERNEL_LENGTH] kernel; +} u_blur_kernel; + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 f_color; + +void main() { + vec2 blur_direction = vec2(u_blur_direction.direction); + vec2 px_direction = vec2(1) / vec2(textureSize(u_image, 0)) * blur_direction; + vec4 color_sum = u_blur_kernel.kernel[0] * texture(u_image, v_texcoord); + for (int i = 1; i <= KERNEL_LENGTH; i++) { + float k = u_blur_kernel.kernel[i]; + color_sum += k * texture(u_image, px_direction * vec2(i) + v_texcoord); + color_sum += k * texture(u_image, -px_direction * vec2(i) + v_texcoord); + } + f_color = color_sum; +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod postprocess_tonemap_fs_mod { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[src = " +#version 450 + +layout(set = 0, binding = 0) uniform sampler2D u_image; +layout(set = 0, binding = 1) uniform sampler2D u_image_blur; + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 f_color; + +void main() { + vec3 color = texture(u_image, v_texcoord).rgb; + vec3 bloom = texture(u_image_blur, v_texcoord).rgb; + + const float gamma = 2.2; + + // Additive blending + color += bloom; + + // Reinhard tone mapping + vec3 mapped = color / (color + vec3(1.0)); + + // Gamma correction + mapped = pow(mapped, vec3(1.0 / gamma)); + + f_color = vec4(mapped, 1.0); +} +"] + struct Dummy; +} diff --git a/persistence/main.rs b/persistence/main.rs new file mode 100644 index 0000000..bb1a6cf --- /dev/null +++ b/persistence/main.rs @@ -0,0 +1,679 @@ +// Copyright (c) 2018 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + + +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate winit; +extern crate vulkano_win; +extern crate cgmath; + +use std::sync::Arc; +use std::mem; +use std::time::Instant; + +use cgmath::{Rad, Point3, Vector3, Matrix3, Matrix4}; + +use winit::{EventsLoop, WindowBuilder, Event, WindowEvent}; + +use vulkano_win::VkSurfaceBuild; + +use vulkano::{ + instance::{ + Instance, + PhysicalDevice, + }, + device::{ + Device, + DeviceExtensions, + }, + buffer::{ + BufferUsage, + CpuAccessibleBuffer, + CpuBufferPool, + }, + command_buffer::{ + AutoCommandBufferBuilder, + DynamicState, + }, + descriptor::descriptor_set::PersistentDescriptorSet, + image::{ + ImageUsage, + AttachmentImage, + ImageLayout, + }, + format::{ + Format, + ClearValue, + }, + framebuffer::{ + Framebuffer, + Subpass, + }, + pipeline::{ + GraphicsPipeline, + viewport::Viewport, + }, + swapchain::{ + self, + PresentMode, + SurfaceTransform, + Swapchain, + AcquireError, + SwapchainCreationError, + }, + sync::{ + self as vk_sync, + GpuFuture, + } +}; + +fn main() { + let instance = { + let extensions = vulkano_win::required_extensions(); + Instance::new(None, &extensions, None) + .expect("failed to create Vulkan instance") + }; + + let physical = PhysicalDevice::enumerate(&instance) + .next() + .expect("no device available"); + + println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); + + let mut events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window"); + + let queue_family = physical.queue_families() + .find(|&q| { + q.supports_graphics() && surface.is_supported(q).unwrap_or(false) + }) + .expect("couldn't find a graphical queue family"); + + let (device, mut queues) = { + let device_ext = DeviceExtensions { + khr_swapchain: true, + .. DeviceExtensions::none() + }; + + Device::new( + physical, + physical.supported_features(), + &device_ext, + [(queue_family, 0.5)].iter().cloned(), + ).expect("failed to create device") + }; + + let queue = queues.next().unwrap(); + + let mut dimensions; + let (mut swapchain, mut images) = { + let caps = surface.capabilities(physical) + .expect("failed to get surface capabilities"); + + dimensions = caps.current_extent.unwrap_or([1024, 768]); + let alpha = caps.supported_composite_alpha.iter().next().unwrap(); + let format = caps.supported_formats[0].0; + + Swapchain::new( + device.clone(), + surface.clone(), + caps.min_image_count, + format, + dimensions, + 1, + caps.supported_usage_flags, + &queue, + SurfaceTransform::Identity, + alpha, + PresentMode::Fifo, + true, + None, + ).expect("failed to create swapchain") + }; + + // let attachment_format = Format::B8G8R8A8Unorm; + let attachment_format = swapchain.format(); + let attachment_image_newframe = AttachmentImage::with_usage( + device.clone(), + dimensions, + attachment_format, + ImageUsage { + storage: true, + color_attachment: true, + transfer_destination: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let attachment_image_ping = AttachmentImage::with_usage( + device.clone(), + dimensions, + attachment_format, + ImageUsage { + storage: true, + color_attachment: true, + transfer_destination: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let attachment_image_pong = AttachmentImage::with_usage( + device.clone(), + dimensions, + attachment_format, + ImageUsage { + storage: true, + color_attachment: true, + transfer_destination: true, + transfer_source: true, + .. ImageUsage::none() + }, + ).expect("failed to create attachment image"); + + let scene_vertex_buffer = { + #[derive(Debug, Clone)] + struct Vertex { a_position: [f32; 2] } + impl_vertex!(Vertex, a_position); + + CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ + Vertex { a_position: [-0.5, -0.25] }, + Vertex { a_position: [0.0, 0.5] }, + Vertex { a_position: [0.25, -0.1] }, + ].iter().cloned()).expect("failed to create buffer") + }; + + let postprocess_vertex_buffer = { + #[derive(Debug, Clone)] + struct VertexUv { a_position: [f32; 2], a_texcoord: [f32; 2] } + impl_vertex!(VertexUv, a_position, a_texcoord); + + CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ + VertexUv { a_position: [-1.0, 3.0], a_texcoord: [0.0, 2.0] }, + VertexUv { a_position: [-1.0, -1.0], a_texcoord: [0.0, 0.0] }, + VertexUv { a_position: [3.0, -1.0], a_texcoord: [2.0, 0.0] }, + ].iter().cloned()).expect("failed to create buffer") + }; + + let uniform_buffer = CpuBufferPool::::new( + device.clone(), + BufferUsage::all(), + ); + + let proj = cgmath::perspective( + Rad(std::f32::consts::FRAC_PI_2), + { dimensions[0] as f32 / dimensions[1] as f32 }, + 0.01, + 100.0, + ); + + let view = Matrix4::look_at( + Point3::new(0.3, 0.3, 1.0), + Point3::new(0.0, 0.0, 0.0), + Vector3::new(0.0, -1.0, 0.0), + ); + + let scene_vs = scene_vs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + let scene_fs = scene_fs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + + let postprocess_vs = postprocess_vs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + let postprocess_fs = postprocess_fs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + + let copy_fs = copy_fs_mod::Shader::load(device.clone()) + .expect("failed to create shader module"); + + let scene_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + newframe_color: { + load: Clear, + store: Store, + format: attachment_format, + samples: 1, + initial_layout: ImageLayout::ColorAttachmentOptimal, + final_layout: ImageLayout::ColorAttachmentOptimal, + } + }, + pass: { + color: [newframe_color], + depth_stencil: {} + } + ).unwrap() + }); + + let postprocess_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + pong_color: { + load: DontCare, + store: Store, + format: attachment_format, + samples: 1, + initial_layout: ImageLayout::ColorAttachmentOptimal, + final_layout: ImageLayout::ColorAttachmentOptimal, + } + }, + pass: { + color: [pong_color], + depth_stencil: {} + } + ).unwrap() + }); + + let copy_renderpass = Arc::new({ + single_pass_renderpass!( + device.clone(), + attachments: { + output_color: { + load: DontCare, + store: Store, + format: swapchain.format(), + samples: 1, + initial_layout: ImageLayout::PresentSrc, + final_layout: ImageLayout::PresentSrc, + } + }, + pass: { + color: [output_color], + depth_stencil: {} + } + ).unwrap() + }); + + let newframe_framebuffer = Arc::new({ + Framebuffer::start(scene_renderpass.clone()) + .add(attachment_image_newframe.clone()).unwrap() + .build().unwrap() + }); + + let pong_framebuffer = Arc::new({ + Framebuffer::start(postprocess_renderpass.clone()) + .add(attachment_image_pong.clone()).unwrap() + .build().unwrap() + }); + + let scene_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(scene_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(scene_fs.main_entry_point(), ()) + .render_pass(Subpass::from(scene_renderpass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + }); + + let postprocess_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(postprocess_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(postprocess_fs.main_entry_point(), ()) + .render_pass(Subpass::from( + postprocess_renderpass.clone(), + 0, + ) + .unwrap()) + .build(device.clone()) + .unwrap() + }); + + let copy_pipeline = Arc::new({ + GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(postprocess_vs.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(copy_fs.main_entry_point(), ()) + .render_pass(Subpass::from(copy_renderpass.clone(), 0) + .unwrap()) + .build(device.clone()) + .unwrap() + }); + + println!("Building clear command buffer"); + let clear_command_buffer = AutoCommandBufferBuilder::primary_one_time_submit( + device.clone(), + queue.family(), + ) + .unwrap() + .clear_color_image( + attachment_image_newframe.clone(), + ClearValue::Float([0.0, 0.0, 0.0, 1.0]), + ) + .unwrap() + .clear_color_image( + attachment_image_ping.clone(), + ClearValue::Float([0.0, 0.0, 0.0, 1.0]), + ) + .unwrap() + .clear_color_image( + attachment_image_pong.clone(), + ClearValue::Float([0.0, 0.0, 1.0, 1.0]), + ) + .unwrap() + .build().unwrap(); + + let mut previous_frame_end: Box = Box::new({ + vk_sync::now(device.clone()) + .then_execute(queue.clone(), clear_command_buffer) + .unwrap() + }); + + // let mut previous_frame_end: Box = Box::new(vk_sync::now(device.clone())); + + let mut framebuffers: Option>>> = None; + let mut recreate_swapchain = false; + + + let time_start = Instant::now(); + loop { + previous_frame_end.cleanup_finished(); + + if recreate_swapchain { + dimensions = surface.capabilities(physical) + .expect("failed to get surface capabilities") + .current_extent.unwrap(); + + let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { + Ok(r) => r, + Err(SwapchainCreationError::UnsupportedDimensions) => continue, + Err(err) => panic!("{:?}", err), + }; + + mem::replace(&mut swapchain, new_swapchain); + mem::replace(&mut images, new_images); + + framebuffers = None; + recreate_swapchain = false; + } + + if framebuffers.is_none() { + let new_framebuffers = Some({ + images.iter() + .map(|image| Arc::new({ + Framebuffer::start(postprocess_renderpass.clone()) + .add(image.clone()).unwrap() + .build().unwrap() + })) + .collect::>() + }); + mem::replace(&mut framebuffers, new_framebuffers); + } + + let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + recreate_swapchain = true; + continue; + }, + Err(err) => panic!("{:?}", err), + }; + + let uniform_buffer_subbuffer = { + let elapsed = time_start.elapsed(); + let rotation_factor = elapsed.as_secs() as f64 + + elapsed.subsec_nanos() as f64 * 1e-9; + let rotation = Matrix3::from_angle_z(Rad(rotation_factor as f32)); + + let uniform_data = scene_vs_mod::ty::Matrices { + model: Matrix4::from(rotation).into(), + view: view.into(), + proj: proj.into(), + }; + + uniform_buffer.next(uniform_data).unwrap() + }; + + let scene_set = Arc::new({ + PersistentDescriptorSet::start(scene_pipeline.clone(), 0) + .add_buffer(uniform_buffer_subbuffer).unwrap() + .build().unwrap() + }); + + let postprocess_set = Arc::new({ + PersistentDescriptorSet::start(postprocess_pipeline.clone(), 0) + .add_image(attachment_image_newframe.clone()).unwrap() + .add_image(attachment_image_ping.clone()).unwrap() + .build().unwrap() + }); + + let copy_set = Arc::new({ + PersistentDescriptorSet::start(copy_pipeline.clone(), 0) + .add_image(attachment_image_pong.clone()).unwrap() + .build().unwrap() + }); + + let dynamic_state = DynamicState { + viewports: Some(vec![Viewport { + origin: [0.0, 0.0], + dimensions: [dimensions[0] as f32, dimensions[1] as f32], + depth_range: 0.0 .. 1.0, + }]), + .. DynamicState::none() + }; + + let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit( + device.clone(), + queue.family() + ) + .unwrap() + .begin_render_pass( + newframe_framebuffer.clone(), + false, + vec![[0.0, 0.0, 0.0, 1.0].into()], + ) + .unwrap() + .draw( + scene_pipeline.clone(), + dynamic_state.clone(), + scene_vertex_buffer.clone(), + scene_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + .copy_image( + attachment_image_pong.clone(), [0, 0, 0], 0, 0, + attachment_image_ping.clone(), [0, 0, 0], 0, 0, + [dimensions[0], dimensions[1], 1], 0, + ) + .unwrap() + .begin_render_pass( + pong_framebuffer.clone(), + false, + vec![ClearValue::None], + ) + .unwrap() + .draw( + postprocess_pipeline.clone(), + dynamic_state.clone(), + postprocess_vertex_buffer.clone(), + postprocess_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + .begin_render_pass( + framebuffers.as_ref().unwrap()[image_num].clone(), + false, + vec![ClearValue::None], + ) + .unwrap() + .draw( + copy_pipeline.clone(), + dynamic_state.clone(), + postprocess_vertex_buffer.clone(), + copy_set.clone(), + (), + ) + .unwrap() + .end_render_pass() + .unwrap() + // .copy_image( + // attachment_image_pong.clone(), [0, 0, 0], 0, 0, + // images[image_num].clone(), [0, 0, 0], 0, 0, + // [dimensions[0], dimensions[1], 1], 0, + // ) + // .unwrap() + .build() + .unwrap(); + + let future = previous_frame_end.join(acquire_future) + .then_execute(queue.clone(), command_buffer).unwrap() + .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => previous_frame_end = Box::new(future), + Err(vk_sync::FlushError::OutOfDate) => { + recreate_swapchain = true; + previous_frame_end = Box::new(vk_sync::now(device.clone())); + }, + Err(e) => { + println!("{:?}", e); + previous_frame_end = Box::new(vk_sync::now(device.clone())); + }, + } + + let mut done = false; + events_loop.poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::Closed, .. } => done = true, + _ => (), + } + }); + if done { return; } + } +} + +#[allow(dead_code)] +mod scene_vs_mod { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[src = " +#version 450 + +layout(set = 0, binding = 0) uniform Matrices { + mat4 model; + mat4 view; + mat4 proj; +} matrices; + +layout(location = 0) in vec2 a_position; + +void main() { + gl_Position = matrices.proj + * matrices.view + * matrices.model + * vec4(a_position, 0.0, 1.0); +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod scene_fs_mod { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[src = " +#version 450 + +layout(location = 0) out vec4 f_color; + +void main() { + f_color = vec4(1.0, 0.0, 0.0, 1.0); +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod postprocess_vs_mod { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[src = " +#version 450 + +layout(location = 0) in vec2 a_position; +layout(location = 1) in vec2 a_texcoord; + +layout(location = 0) out vec2 v_texcoord; + +void main() { + v_texcoord = a_texcoord; + gl_Position = vec4(a_position, 0.0, 1.0); +} +"] + struct Dummy; +} + +#[allow(dead_code)] +mod postprocess_fs_mod { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[src = " +#version 450 + +layout(set = 0, binding = 0, rgba8) uniform readonly image2D u_newframe; +layout(set = 0, binding = 1, rgba8) uniform readonly image2D u_prevframe; + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 f_color; + +vec4 blend_with_factor(vec4 src_color, vec4 dst_color, float factor) { + return (src_color * factor) + (dst_color * (1. - factor)); +} + +void main() { + ivec2 index = ivec2(gl_FragCoord.xy); + vec4 c1 = imageLoad(u_newframe, index); + vec4 c2 = imageLoad(u_prevframe, index); + f_color = blend_with_factor(c2, c1, 0.8); + // f_color = c1; +} +"] + struct Dummy; +} + +mod copy_fs_mod { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[src = " +#version 450 + +layout(set = 0, binding = 0, rgba8) uniform readonly image2D u_image; + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 f_color; + +void main() { + ivec2 index = ivec2(gl_FragCoord.xy); + f_color = imageLoad(u_image, index); +} +"] + struct Dummy; +} + From 45794cf7e272072ea4d7f6edb81c9c402b39d215 Mon Sep 17 00:00:00 2001 From: yanchith Date: Thu, 5 Apr 2018 14:54:55 +1000 Subject: [PATCH 02/10] Remove old persistence example, update TODO --- Cargo.toml | 4 - bloom/main.rs | 13 +- persistence/main.rs | 679 -------------------------------------------- 3 files changed, 8 insertions(+), 688 deletions(-) delete mode 100644 persistence/main.rs diff --git a/Cargo.toml b/Cargo.toml index bd1c971..03c9b7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,6 @@ path = "deferred/main.rs" name = "msaa-renderpass" path = "msaa-renderpass/main.rs" -[[bin]] -name = "persistence" -path = "persistence/main.rs" - [[bin]] name = "bloom" path = "bloom/main.rs" diff --git a/bloom/main.rs b/bloom/main.rs index 685990c..892da28 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -10,10 +10,14 @@ /* TODO: -- sampling -- HDR textures -- optimize blur kernel - +- Comments! +- Add a more visually plasing scene +- Refactor (this file is a bit too long) +- HDR image formats +- Optimizations + - some things can maybe be done in subpasses + - can we reuse some images? (vulkano currently protests very much against this) + * reusing would also make it possible to repeat the blurring process */ #[macro_use] @@ -56,7 +60,6 @@ use vulkano::{ image::{ ImageUsage, AttachmentImage, - ImageLayout, }, sampler::Sampler, format::{ diff --git a/persistence/main.rs b/persistence/main.rs deleted file mode 100644 index bb1a6cf..0000000 --- a/persistence/main.rs +++ /dev/null @@ -1,679 +0,0 @@ -// Copyright (c) 2018 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - - -#[macro_use] -extern crate vulkano; -#[macro_use] -extern crate vulkano_shader_derive; -extern crate winit; -extern crate vulkano_win; -extern crate cgmath; - -use std::sync::Arc; -use std::mem; -use std::time::Instant; - -use cgmath::{Rad, Point3, Vector3, Matrix3, Matrix4}; - -use winit::{EventsLoop, WindowBuilder, Event, WindowEvent}; - -use vulkano_win::VkSurfaceBuild; - -use vulkano::{ - instance::{ - Instance, - PhysicalDevice, - }, - device::{ - Device, - DeviceExtensions, - }, - buffer::{ - BufferUsage, - CpuAccessibleBuffer, - CpuBufferPool, - }, - command_buffer::{ - AutoCommandBufferBuilder, - DynamicState, - }, - descriptor::descriptor_set::PersistentDescriptorSet, - image::{ - ImageUsage, - AttachmentImage, - ImageLayout, - }, - format::{ - Format, - ClearValue, - }, - framebuffer::{ - Framebuffer, - Subpass, - }, - pipeline::{ - GraphicsPipeline, - viewport::Viewport, - }, - swapchain::{ - self, - PresentMode, - SurfaceTransform, - Swapchain, - AcquireError, - SwapchainCreationError, - }, - sync::{ - self as vk_sync, - GpuFuture, - } -}; - -fn main() { - let instance = { - let extensions = vulkano_win::required_extensions(); - Instance::new(None, &extensions, None) - .expect("failed to create Vulkan instance") - }; - - let physical = PhysicalDevice::enumerate(&instance) - .next() - .expect("no device available"); - - println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); - - let mut events_loop = EventsLoop::new(); - let surface = WindowBuilder::new() - .build_vk_surface(&events_loop, instance.clone()) - .expect("failed to create window"); - - let queue_family = physical.queue_families() - .find(|&q| { - q.supports_graphics() && surface.is_supported(q).unwrap_or(false) - }) - .expect("couldn't find a graphical queue family"); - - let (device, mut queues) = { - let device_ext = DeviceExtensions { - khr_swapchain: true, - .. DeviceExtensions::none() - }; - - Device::new( - physical, - physical.supported_features(), - &device_ext, - [(queue_family, 0.5)].iter().cloned(), - ).expect("failed to create device") - }; - - let queue = queues.next().unwrap(); - - let mut dimensions; - let (mut swapchain, mut images) = { - let caps = surface.capabilities(physical) - .expect("failed to get surface capabilities"); - - dimensions = caps.current_extent.unwrap_or([1024, 768]); - let alpha = caps.supported_composite_alpha.iter().next().unwrap(); - let format = caps.supported_formats[0].0; - - Swapchain::new( - device.clone(), - surface.clone(), - caps.min_image_count, - format, - dimensions, - 1, - caps.supported_usage_flags, - &queue, - SurfaceTransform::Identity, - alpha, - PresentMode::Fifo, - true, - None, - ).expect("failed to create swapchain") - }; - - // let attachment_format = Format::B8G8R8A8Unorm; - let attachment_format = swapchain.format(); - let attachment_image_newframe = AttachmentImage::with_usage( - device.clone(), - dimensions, - attachment_format, - ImageUsage { - storage: true, - color_attachment: true, - transfer_destination: true, - .. ImageUsage::none() - }, - ).expect("failed to create attachment image"); - - let attachment_image_ping = AttachmentImage::with_usage( - device.clone(), - dimensions, - attachment_format, - ImageUsage { - storage: true, - color_attachment: true, - transfer_destination: true, - .. ImageUsage::none() - }, - ).expect("failed to create attachment image"); - - let attachment_image_pong = AttachmentImage::with_usage( - device.clone(), - dimensions, - attachment_format, - ImageUsage { - storage: true, - color_attachment: true, - transfer_destination: true, - transfer_source: true, - .. ImageUsage::none() - }, - ).expect("failed to create attachment image"); - - let scene_vertex_buffer = { - #[derive(Debug, Clone)] - struct Vertex { a_position: [f32; 2] } - impl_vertex!(Vertex, a_position); - - CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ - Vertex { a_position: [-0.5, -0.25] }, - Vertex { a_position: [0.0, 0.5] }, - Vertex { a_position: [0.25, -0.1] }, - ].iter().cloned()).expect("failed to create buffer") - }; - - let postprocess_vertex_buffer = { - #[derive(Debug, Clone)] - struct VertexUv { a_position: [f32; 2], a_texcoord: [f32; 2] } - impl_vertex!(VertexUv, a_position, a_texcoord); - - CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ - VertexUv { a_position: [-1.0, 3.0], a_texcoord: [0.0, 2.0] }, - VertexUv { a_position: [-1.0, -1.0], a_texcoord: [0.0, 0.0] }, - VertexUv { a_position: [3.0, -1.0], a_texcoord: [2.0, 0.0] }, - ].iter().cloned()).expect("failed to create buffer") - }; - - let uniform_buffer = CpuBufferPool::::new( - device.clone(), - BufferUsage::all(), - ); - - let proj = cgmath::perspective( - Rad(std::f32::consts::FRAC_PI_2), - { dimensions[0] as f32 / dimensions[1] as f32 }, - 0.01, - 100.0, - ); - - let view = Matrix4::look_at( - Point3::new(0.3, 0.3, 1.0), - Point3::new(0.0, 0.0, 0.0), - Vector3::new(0.0, -1.0, 0.0), - ); - - let scene_vs = scene_vs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); - let scene_fs = scene_fs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); - - let postprocess_vs = postprocess_vs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); - let postprocess_fs = postprocess_fs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); - - let copy_fs = copy_fs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); - - let scene_renderpass = Arc::new({ - single_pass_renderpass!( - device.clone(), - attachments: { - newframe_color: { - load: Clear, - store: Store, - format: attachment_format, - samples: 1, - initial_layout: ImageLayout::ColorAttachmentOptimal, - final_layout: ImageLayout::ColorAttachmentOptimal, - } - }, - pass: { - color: [newframe_color], - depth_stencil: {} - } - ).unwrap() - }); - - let postprocess_renderpass = Arc::new({ - single_pass_renderpass!( - device.clone(), - attachments: { - pong_color: { - load: DontCare, - store: Store, - format: attachment_format, - samples: 1, - initial_layout: ImageLayout::ColorAttachmentOptimal, - final_layout: ImageLayout::ColorAttachmentOptimal, - } - }, - pass: { - color: [pong_color], - depth_stencil: {} - } - ).unwrap() - }); - - let copy_renderpass = Arc::new({ - single_pass_renderpass!( - device.clone(), - attachments: { - output_color: { - load: DontCare, - store: Store, - format: swapchain.format(), - samples: 1, - initial_layout: ImageLayout::PresentSrc, - final_layout: ImageLayout::PresentSrc, - } - }, - pass: { - color: [output_color], - depth_stencil: {} - } - ).unwrap() - }); - - let newframe_framebuffer = Arc::new({ - Framebuffer::start(scene_renderpass.clone()) - .add(attachment_image_newframe.clone()).unwrap() - .build().unwrap() - }); - - let pong_framebuffer = Arc::new({ - Framebuffer::start(postprocess_renderpass.clone()) - .add(attachment_image_pong.clone()).unwrap() - .build().unwrap() - }); - - let scene_pipeline = Arc::new({ - GraphicsPipeline::start() - .vertex_input_single_buffer() - .vertex_shader(scene_vs.main_entry_point(), ()) - .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) - .fragment_shader(scene_fs.main_entry_point(), ()) - .render_pass(Subpass::from(scene_renderpass.clone(), 0).unwrap()) - .build(device.clone()) - .unwrap() - }); - - let postprocess_pipeline = Arc::new({ - GraphicsPipeline::start() - .vertex_input_single_buffer() - .vertex_shader(postprocess_vs.main_entry_point(), ()) - .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) - .fragment_shader(postprocess_fs.main_entry_point(), ()) - .render_pass(Subpass::from( - postprocess_renderpass.clone(), - 0, - ) - .unwrap()) - .build(device.clone()) - .unwrap() - }); - - let copy_pipeline = Arc::new({ - GraphicsPipeline::start() - .vertex_input_single_buffer() - .vertex_shader(postprocess_vs.main_entry_point(), ()) - .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) - .fragment_shader(copy_fs.main_entry_point(), ()) - .render_pass(Subpass::from(copy_renderpass.clone(), 0) - .unwrap()) - .build(device.clone()) - .unwrap() - }); - - println!("Building clear command buffer"); - let clear_command_buffer = AutoCommandBufferBuilder::primary_one_time_submit( - device.clone(), - queue.family(), - ) - .unwrap() - .clear_color_image( - attachment_image_newframe.clone(), - ClearValue::Float([0.0, 0.0, 0.0, 1.0]), - ) - .unwrap() - .clear_color_image( - attachment_image_ping.clone(), - ClearValue::Float([0.0, 0.0, 0.0, 1.0]), - ) - .unwrap() - .clear_color_image( - attachment_image_pong.clone(), - ClearValue::Float([0.0, 0.0, 1.0, 1.0]), - ) - .unwrap() - .build().unwrap(); - - let mut previous_frame_end: Box = Box::new({ - vk_sync::now(device.clone()) - .then_execute(queue.clone(), clear_command_buffer) - .unwrap() - }); - - // let mut previous_frame_end: Box = Box::new(vk_sync::now(device.clone())); - - let mut framebuffers: Option>>> = None; - let mut recreate_swapchain = false; - - - let time_start = Instant::now(); - loop { - previous_frame_end.cleanup_finished(); - - if recreate_swapchain { - dimensions = surface.capabilities(physical) - .expect("failed to get surface capabilities") - .current_extent.unwrap(); - - let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { - Ok(r) => r, - Err(SwapchainCreationError::UnsupportedDimensions) => continue, - Err(err) => panic!("{:?}", err), - }; - - mem::replace(&mut swapchain, new_swapchain); - mem::replace(&mut images, new_images); - - framebuffers = None; - recreate_swapchain = false; - } - - if framebuffers.is_none() { - let new_framebuffers = Some({ - images.iter() - .map(|image| Arc::new({ - Framebuffer::start(postprocess_renderpass.clone()) - .add(image.clone()).unwrap() - .build().unwrap() - })) - .collect::>() - }); - mem::replace(&mut framebuffers, new_framebuffers); - } - - let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { - Ok(r) => r, - Err(AcquireError::OutOfDate) => { - recreate_swapchain = true; - continue; - }, - Err(err) => panic!("{:?}", err), - }; - - let uniform_buffer_subbuffer = { - let elapsed = time_start.elapsed(); - let rotation_factor = elapsed.as_secs() as f64 - + elapsed.subsec_nanos() as f64 * 1e-9; - let rotation = Matrix3::from_angle_z(Rad(rotation_factor as f32)); - - let uniform_data = scene_vs_mod::ty::Matrices { - model: Matrix4::from(rotation).into(), - view: view.into(), - proj: proj.into(), - }; - - uniform_buffer.next(uniform_data).unwrap() - }; - - let scene_set = Arc::new({ - PersistentDescriptorSet::start(scene_pipeline.clone(), 0) - .add_buffer(uniform_buffer_subbuffer).unwrap() - .build().unwrap() - }); - - let postprocess_set = Arc::new({ - PersistentDescriptorSet::start(postprocess_pipeline.clone(), 0) - .add_image(attachment_image_newframe.clone()).unwrap() - .add_image(attachment_image_ping.clone()).unwrap() - .build().unwrap() - }); - - let copy_set = Arc::new({ - PersistentDescriptorSet::start(copy_pipeline.clone(), 0) - .add_image(attachment_image_pong.clone()).unwrap() - .build().unwrap() - }); - - let dynamic_state = DynamicState { - viewports: Some(vec![Viewport { - origin: [0.0, 0.0], - dimensions: [dimensions[0] as f32, dimensions[1] as f32], - depth_range: 0.0 .. 1.0, - }]), - .. DynamicState::none() - }; - - let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit( - device.clone(), - queue.family() - ) - .unwrap() - .begin_render_pass( - newframe_framebuffer.clone(), - false, - vec![[0.0, 0.0, 0.0, 1.0].into()], - ) - .unwrap() - .draw( - scene_pipeline.clone(), - dynamic_state.clone(), - scene_vertex_buffer.clone(), - scene_set.clone(), - (), - ) - .unwrap() - .end_render_pass() - .unwrap() - .copy_image( - attachment_image_pong.clone(), [0, 0, 0], 0, 0, - attachment_image_ping.clone(), [0, 0, 0], 0, 0, - [dimensions[0], dimensions[1], 1], 0, - ) - .unwrap() - .begin_render_pass( - pong_framebuffer.clone(), - false, - vec![ClearValue::None], - ) - .unwrap() - .draw( - postprocess_pipeline.clone(), - dynamic_state.clone(), - postprocess_vertex_buffer.clone(), - postprocess_set.clone(), - (), - ) - .unwrap() - .end_render_pass() - .unwrap() - .begin_render_pass( - framebuffers.as_ref().unwrap()[image_num].clone(), - false, - vec![ClearValue::None], - ) - .unwrap() - .draw( - copy_pipeline.clone(), - dynamic_state.clone(), - postprocess_vertex_buffer.clone(), - copy_set.clone(), - (), - ) - .unwrap() - .end_render_pass() - .unwrap() - // .copy_image( - // attachment_image_pong.clone(), [0, 0, 0], 0, 0, - // images[image_num].clone(), [0, 0, 0], 0, 0, - // [dimensions[0], dimensions[1], 1], 0, - // ) - // .unwrap() - .build() - .unwrap(); - - let future = previous_frame_end.join(acquire_future) - .then_execute(queue.clone(), command_buffer).unwrap() - .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) - .then_signal_fence_and_flush(); - - match future { - Ok(future) => previous_frame_end = Box::new(future), - Err(vk_sync::FlushError::OutOfDate) => { - recreate_swapchain = true; - previous_frame_end = Box::new(vk_sync::now(device.clone())); - }, - Err(e) => { - println!("{:?}", e); - previous_frame_end = Box::new(vk_sync::now(device.clone())); - }, - } - - let mut done = false; - events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::Closed, .. } => done = true, - _ => (), - } - }); - if done { return; } - } -} - -#[allow(dead_code)] -mod scene_vs_mod { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[src = " -#version 450 - -layout(set = 0, binding = 0) uniform Matrices { - mat4 model; - mat4 view; - mat4 proj; -} matrices; - -layout(location = 0) in vec2 a_position; - -void main() { - gl_Position = matrices.proj - * matrices.view - * matrices.model - * vec4(a_position, 0.0, 1.0); -} -"] - struct Dummy; -} - -#[allow(dead_code)] -mod scene_fs_mod { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[src = " -#version 450 - -layout(location = 0) out vec4 f_color; - -void main() { - f_color = vec4(1.0, 0.0, 0.0, 1.0); -} -"] - struct Dummy; -} - -#[allow(dead_code)] -mod postprocess_vs_mod { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[src = " -#version 450 - -layout(location = 0) in vec2 a_position; -layout(location = 1) in vec2 a_texcoord; - -layout(location = 0) out vec2 v_texcoord; - -void main() { - v_texcoord = a_texcoord; - gl_Position = vec4(a_position, 0.0, 1.0); -} -"] - struct Dummy; -} - -#[allow(dead_code)] -mod postprocess_fs_mod { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[src = " -#version 450 - -layout(set = 0, binding = 0, rgba8) uniform readonly image2D u_newframe; -layout(set = 0, binding = 1, rgba8) uniform readonly image2D u_prevframe; - -layout(location = 0) in vec2 v_texcoord; - -layout(location = 0) out vec4 f_color; - -vec4 blend_with_factor(vec4 src_color, vec4 dst_color, float factor) { - return (src_color * factor) + (dst_color * (1. - factor)); -} - -void main() { - ivec2 index = ivec2(gl_FragCoord.xy); - vec4 c1 = imageLoad(u_newframe, index); - vec4 c2 = imageLoad(u_prevframe, index); - f_color = blend_with_factor(c2, c1, 0.8); - // f_color = c1; -} -"] - struct Dummy; -} - -mod copy_fs_mod { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[src = " -#version 450 - -layout(set = 0, binding = 0, rgba8) uniform readonly image2D u_image; - -layout(location = 0) in vec2 v_texcoord; - -layout(location = 0) out vec4 f_color; - -void main() { - ivec2 index = ivec2(gl_FragCoord.xy); - f_color = imageLoad(u_image, index); -} -"] - struct Dummy; -} - From 70e074b1d22a606813a7be871170748b1b3d79e8 Mon Sep 17 00:00:00 2001 From: yanchith Date: Sun, 15 Apr 2018 09:45:13 +1000 Subject: [PATCH 03/10] Blur both directions --- bloom/main.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bloom/main.rs b/bloom/main.rs index 892da28..bfb5efe 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -249,7 +249,7 @@ fn main() { BufferUsage::all(), ); - let blur_direction_uniform_buffer = { + let blur_direction_uniform_buffer_horizontal = { CpuAccessibleBuffer::from_data( device.clone(), BufferUsage::all(), @@ -259,6 +259,16 @@ fn main() { ).expect("failed to create buffer") }; + let blur_direction_uniform_buffer_vertical = { + CpuAccessibleBuffer::from_data( + device.clone(), + BufferUsage::all(), + postprocess_blur_fs_mod::ty::BlurDirection { + direction: [0, 1], + } + ).expect("failed to create buffer") + }; + let blur_kernel_uniform_buffer = { CpuAccessibleBuffer::from_data( device.clone(), @@ -508,7 +518,7 @@ fn main() { PersistentDescriptorSet::start(postprocess_blur_ping_pipeline.clone(), 0) .add_sampled_image(sep_attachment.clone(), sampler.clone()) .unwrap() - .add_buffer(blur_direction_uniform_buffer.clone()) + .add_buffer(blur_direction_uniform_buffer_horizontal.clone()) .unwrap() .add_buffer(blur_kernel_uniform_buffer.clone()) .unwrap() @@ -521,7 +531,7 @@ fn main() { PersistentDescriptorSet::start(postprocess_blur_pong_pipeline.clone(), 0) .add_sampled_image(ping_attachment.clone(), sampler.clone()) .unwrap() - .add_buffer(blur_direction_uniform_buffer.clone()) + .add_buffer(blur_direction_uniform_buffer_vertical.clone()) .unwrap() .add_buffer(blur_kernel_uniform_buffer.clone()) .unwrap() From c6b0dca0d0f3e3a5160151fa6aee401d65eb33c6 Mon Sep 17 00:00:00 2001 From: yanchith Date: Tue, 17 Apr 2018 12:19:27 +1000 Subject: [PATCH 04/10] Add example description and revert back to old style imports --- bloom/main.rs | 160 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 50 deletions(-) diff --git a/bloom/main.rs b/bloom/main.rs index bfb5efe..a794ab0 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -10,16 +10,97 @@ /* TODO: -- Comments! +- Code Comments! - Add a more visually plasing scene - Refactor (this file is a bit too long) - HDR image formats +- Do not call the last step "tonemap", as we do not use HDR attachments - Optimizations + - subpixel sampling with stride 2 - some things can maybe be done in subpasses - can we reuse some images? (vulkano currently protests very much against this) * reusing would also make it possible to repeat the blurring process */ +//! Bloom example, using multiple renderpasses +//! +//! # Introduction to Bloom +//! +//! Bloom (also called glow) is a postprocessing technique used to convey that +//! some objects in the rendered scene are really bright. Imagine a scene with +//! light sources. In classical rendering, the lights can be rendered using +//! its color or a brighter variant, but there is only so much that can be +//! done, as we cannot exceed white color. Bloom makes the color of bright +//! objects bleed out of their frame, adding a psychological effect of +//! brightness. +//! +//! # Implementing Bloom +//! +//! Bloom happens in the screenspace, and usually requires at lest 3-4 +//! rendering passes. Conceptually, the following happens: +//! 1. Scene is rendered to an image +//! 2. Bright colors are separated from the rendered scene to its own image +//! 3. Separated highlights are blurred +//! 4. Blurred highlights are merged back to the original image. +//! +//! Note that steps 1. and 2. can be merged in one using multiple render targets +//! for optimization. +//! +//! ## Separation Pass +//! +//! During separation, we copy bright pixels from one image to another. We +//! usually select the pixel based on brightness (eg. if grayscale +//! brightness exceeds a threshold). If needed, the pixels can also be picked +//! by beloging to a certain object (eg. only blur pixels coming from light +//! sources, but not other bright surfaces), but this requires additional +//! information to be passed. +//! +//! ## Blur Passes +//! +//! Once we have the image containing the bright areas, we can perform gaussian +//! blur on it. This is done by convoluting a gaussian kernel on the image's pixels. +//! +//! When applying this 3x3 gaussian kernel to a pixel, its value will be the its +//! original value multiplied by the kernel's middle cell, summed with the kernel's +//! outer cells multiplied with their corresponding pixels in our image. +//! +//! 0.077847 0.123317 0.077847 +//! 0.123317 0.195346 0.123317 +//! 0.077847 0.123317 0.077847 +//! +//! This gaussian kernel is already normalized, meaning its cells sum up to one, +//! so we don't end up with brighter pixels than we previously had. Note, that +//! for this 3x3 kernel we will need to perform 9 texture sample operations. +//! +//! To optimize, we can use 1d kernels instead of 2d, and blur in multiple render +//! passes (eg first horizontally, then vertically). +//! This reduces the number of sample operations from N ^ 2 to 2 * N, and is +//! a significant speedup for larger blur kernels. +//! +//! To achieve the right visual result, we can apply the pairs of blur passes +//! multiple times. +//! +//! ## Merge Pass +//! +//! In the final pass, we merge the blurred highlights back with the original +//! image. Bloom can sometimes be implemented together with HDR, but HDR itself +//! is not necessary, it only complements the bloom effect nicely. If we used HDR, +//! we would also apply tonemapping and gamma correcting here. +//! +//! # Optimizations +//! +//! Besides using 1d kernels for blur, we can also do the following. +//! +//! Use a fraction of the screen resolution for the blur images. Since we sample +//! the images anyway, they do not need to be the same size. This effectively +//! reduces the number of fragment shader runs. The resolution can easily be +//! halved before any visual degradation of output. +//! +//! Another optimization is sampling between two pixels and strinding +//! two pixels at once when blurring. This increases the blur's reach, and we +//! may potentially use a lesser number of passes achieve the same visual result. +//! + #[macro_use] extern crate vulkano; #[macro_use] @@ -38,55 +119,34 @@ use winit::{EventsLoop, WindowBuilder, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; -use vulkano::{ - instance::{ - Instance, - PhysicalDevice, - }, - device::{ - Device, - DeviceExtensions, - }, - buffer::{ - BufferUsage, - CpuAccessibleBuffer, - CpuBufferPool, - }, - command_buffer::{ - AutoCommandBufferBuilder, - DynamicState, - }, - descriptor::descriptor_set::PersistentDescriptorSet, - image::{ - ImageUsage, - AttachmentImage, - }, - sampler::Sampler, - format::{ - Format, - ClearValue, - }, - framebuffer::{ - Framebuffer, - Subpass, - }, - pipeline::{ - GraphicsPipeline, - viewport::Viewport, - }, - swapchain::{ - self, - PresentMode, - SurfaceTransform, - Swapchain, - AcquireError, - SwapchainCreationError, - }, - sync::{ - self as vk_sync, - GpuFuture, - } -}; +use vulkano::instance::Instance; +use vulkano::instance::PhysicalDevice; +use vulkano::device::Device; +use vulkano::device::DeviceExtensions; +use vulkano::buffer::BufferUsage; +use vulkano::buffer::CpuAccessibleBuffer; +use vulkano::buffer::CpuBufferPool; +use vulkano::command_buffer::AutoCommandBufferBuilder; +use vulkano::command_buffer::DynamicState; +use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; +use vulkano::image::ImageUsage; +use vulkano::image::AttachmentImage; +use vulkano::sampler::Sampler; +use vulkano::format::Format; +use vulkano::format::ClearValue; +use vulkano::framebuffer::Framebuffer; +use vulkano::framebuffer::Subpass; +use vulkano::pipeline::GraphicsPipeline; +use vulkano::pipeline::viewport::Viewport; +use vulkano::swapchain; +use vulkano::swapchain::Swapchain; +use vulkano::swapchain::PresentMode; +use vulkano::swapchain::SurfaceTransform; +use vulkano::swapchain::AcquireError; +use vulkano::swapchain::SwapchainCreationError; +use vulkano::sync as vk_sync; +use vulkano::sync::GpuFuture; + fn main() { let instance = { From 6511d7b3fc9b00c2ddfff98eadab6153b521e974 Mon Sep 17 00:00:00 2001 From: yanchith Date: Wed, 18 Apr 2018 12:06:30 +1000 Subject: [PATCH 05/10] Change the scene a bit --- bloom/cube.rs | 104 +++++++++++++++++++++++++++++++++++++++ bloom/main.rs | 132 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 189 insertions(+), 47 deletions(-) create mode 100644 bloom/cube.rs diff --git a/bloom/cube.rs b/bloom/cube.rs new file mode 100644 index 0000000..6a140d9 --- /dev/null +++ b/bloom/cube.rs @@ -0,0 +1,104 @@ +#[derive(Debug, Clone)] +pub struct Vertex { a_position: [f32; 3] } +impl_vertex!(Vertex, a_position); + +#[derive(Debug, Clone)] +pub struct Uv { a_uv: [f32; 2] } +impl_vertex!(Uv, a_uv); + +pub const VERTICES: [Vertex; 24] = [ + // back + Vertex { a_position: [-1.0, -1.0, 1.0] }, + Vertex { a_position: [ 1.0, -1.0, 1.0] }, + Vertex { a_position: [ 1.0, 1.0, 1.0] }, + Vertex { a_position: [-1.0, 1.0, 1.0] }, + + // front + Vertex { a_position: [-1.0, -1.0, -1.0] }, + Vertex { a_position: [-1.0, 1.0, -1.0] }, + Vertex { a_position: [ 1.0, 1.0, -1.0] }, + Vertex { a_position: [ 1.0, -1.0, -1.0] }, + + // top + Vertex { a_position: [-1.0, 1.0, -1.0] }, + Vertex { a_position: [-1.0, 1.0, 1.0] }, + Vertex { a_position: [ 1.0, 1.0, 1.0] }, + Vertex { a_position: [ 1.0, 1.0, -1.0] }, + + // bottom + Vertex { a_position: [-1.0, -1.0, -1.0] }, + Vertex { a_position: [ 1.0, -1.0, -1.0] }, + Vertex { a_position: [ 1.0, -1.0, 1.0] }, + Vertex { a_position: [-1.0, -1.0, 1.0] }, + + // left + Vertex { a_position: [ 1.0, -1.0, -1.0] }, + Vertex { a_position: [ 1.0, 1.0, -1.0] }, + Vertex { a_position: [ 1.0, 1.0, 1.0] }, + Vertex { a_position: [ 1.0, -1.0, 1.0] }, + + // right + Vertex { a_position: [-1.0, -1.0, -1.0] }, + Vertex { a_position: [-1.0, -1.0, 1.0] }, + Vertex { a_position: [-1.0, 1.0, 1.0] }, + Vertex { a_position: [-1.0, 1.0, -1.0] }, +]; + +pub const UVS: [Uv; 24] = [ + // back + Uv { a_uv: [0.0, 0.0] }, + Uv { a_uv: [1.0, 0.0] }, + Uv { a_uv: [1.0, 1.0] }, + Uv { a_uv: [0.0, 1.0] }, + + // front + Uv { a_uv: [0.0, 0.0] }, + Uv { a_uv: [1.0, 0.0] }, + Uv { a_uv: [1.0, 1.0] }, + Uv { a_uv: [0.0, 1.0] }, + + // top + Uv { a_uv: [0.0, 0.0] }, + Uv { a_uv: [1.0, 0.0] }, + Uv { a_uv: [1.0, 1.0] }, + Uv { a_uv: [0.0, 1.0] }, + + // bottom + Uv { a_uv: [0.0, 0.0] }, + Uv { a_uv: [1.0, 0.0] }, + Uv { a_uv: [1.0, 1.0] }, + Uv { a_uv: [0.0, 1.0] }, + + // left + Uv { a_uv: [0.0, 0.0] }, + Uv { a_uv: [1.0, 0.0] }, + Uv { a_uv: [1.0, 1.0] }, + Uv { a_uv: [0.0, 1.0] }, + + // right + Uv { a_uv: [0.0, 0.0] }, + Uv { a_uv: [1.0, 0.0] }, + Uv { a_uv: [1.0, 1.0] }, + Uv { a_uv: [0.0, 1.0] }, +]; + +pub const INDICES: [u16; 36] = [ + // back + 0, 1, 2, + 2, 3, 0, + // front + 4, 5, 6, + 6, 7, 4, + // top + 8, 9, 10, + 10, 11, 8, + // bottom + 12, 13, 14, + 14, 15, 12, + // left + 16, 17, 18, + 18, 19, 16, + // right + 20, 21, 22, + 22, 23, 20, +]; diff --git a/bloom/main.rs b/bloom/main.rs index a794ab0..7a7ac35 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -113,7 +113,7 @@ use std::sync::Arc; use std::mem; use std::time::Instant; -use cgmath::{Rad, Point3, Vector3, Matrix3, Matrix4}; +use cgmath::{Rad, Point3, Vector3, Matrix4}; use winit::{EventsLoop, WindowBuilder, Event, WindowEvent}; @@ -147,6 +147,7 @@ use vulkano::swapchain::SwapchainCreationError; use vulkano::sync as vk_sync; use vulkano::sync::GpuFuture; +mod cube; fn main() { let instance = { @@ -280,17 +281,23 @@ fn main() { }, ).expect("failed to create attachment image"); - let scene_vertex_buffer = { - #[derive(Debug, Clone)] - struct Vertex { a_position: [f32; 2] } - impl_vertex!(Vertex, a_position); + let scene_vertex_buffer = CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::all(), + cube::VERTICES.iter().cloned(), + ).expect("failed to create buffer"); - CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ - Vertex { a_position: [-0.5, -0.25] }, - Vertex { a_position: [0.0, 0.5] }, - Vertex { a_position: [0.25, -0.1] }, - ].iter().cloned()).expect("failed to create buffer") - }; + let scene_uv_buffer = CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::all(), + cube::UVS.iter().cloned(), + ).expect("failed to create buffer"); + + let scene_index_buffer = CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::all(), + cube::INDICES.iter().cloned(), + ).expect("failed to create buffer"); let postprocess_vertex_buffer = { #[derive(Debug, Clone)] @@ -309,6 +316,11 @@ fn main() { BufferUsage::all(), ); + let material_uniform_buffer = CpuBufferPool::::new( + device.clone(), + BufferUsage::all(), + ); + let blur_direction_uniform_buffer_horizontal = { CpuAccessibleBuffer::from_data( device.clone(), @@ -346,17 +358,17 @@ fn main() { ).expect("failed to create buffer") }; - let proj = cgmath::perspective( + let proj_matrix = cgmath::perspective( Rad(std::f32::consts::FRAC_PI_2), { dimensions[0] as f32 / dimensions[1] as f32 }, 0.01, 100.0, ); - let view = Matrix4::look_at( - Point3::new(0.3, 0.3, 1.0), + let view_matrix = Matrix4::look_at( + Point3::new(-2.0, -2.0, 5.0), Point3::new(0.0, 0.0, 0.0), - Vector3::new(0.0, -1.0, 0.0), + Vector3::new(0.0, 1.0, 0.0), ); let scene_vs = scene_vs_mod::Shader::load(device.clone()) @@ -497,11 +509,12 @@ fn main() { let scene_pipeline = Arc::new({ GraphicsPipeline::start() - .vertex_input_single_buffer() + .vertex_input(vulkano::pipeline::vertex::TwoBuffersDefinition::new()) .vertex_shader(scene_vs.main_entry_point(), ()) .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(scene_fs.main_entry_point(), ()) + .depth_stencil_simple_depth() .render_pass(Subpass::from(scene_renderpass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() @@ -658,24 +671,30 @@ fn main() { Err(err) => panic!("{:?}", err), }; - let matrix_uniform_buffer_subbuffer = { + let (matrix_uniform_subbuffer, material_uniform_subbuffer) = { let elapsed = time_start.elapsed(); - let rotation_factor = elapsed.as_secs() as f64 + + let factor = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9; - let rotation = Matrix3::from_angle_z(Rad(rotation_factor as f32)); + let matrix_data = scene_vs_mod::ty::Matrices { + model: Matrix4::from_angle_y(Rad(factor as f32)).into(), + view: view_matrix.into(), + proj: proj_matrix.into(), + }; + let matrix_subbuffer = matrix_uniform_buffer.next(matrix_data).unwrap(); - let uniform_data = scene_vs_mod::ty::Matrices { - model: Matrix4::from(rotation).into(), - view: view.into(), - proj: proj.into(), + let material_data = scene_fs_mod::ty::Material { + glow_strength: 10.0 * (factor.sin() + 1.0) as f32, }; + let material_subbuffer = material_uniform_buffer.next(material_data).unwrap(); - matrix_uniform_buffer.next(uniform_data).unwrap() + (matrix_subbuffer, material_subbuffer) }; let scene_set = Arc::new({ PersistentDescriptorSet::start(scene_pipeline.clone(), 0) - .add_buffer(matrix_uniform_buffer_subbuffer).unwrap() + .add_buffer(matrix_uniform_subbuffer).unwrap() + .add_buffer(material_uniform_subbuffer).unwrap() .build().unwrap() }); @@ -715,10 +734,11 @@ fn main() { ], ) .unwrap() - .draw( + .draw_indexed( scene_pipeline.clone(), scene_dynamic_state.clone(), - scene_vertex_buffer.clone(), + (scene_vertex_buffer.clone(), scene_uv_buffer.clone()), + scene_index_buffer.clone(), scene_set.clone(), (), ) @@ -834,19 +854,23 @@ mod scene_vs_mod { #[src = " #version 450 -layout(set = 0, binding = 0) uniform Matrices { +layout (set = 0, binding = 0) uniform Matrices { mat4 model; mat4 view; mat4 proj; } u_matrices; -layout(location = 0) in vec2 a_position; +layout (location = 0) in vec3 a_position; +layout (location = 1) in vec2 a_uv; + +layout (location = 0) out vec2 v_uv; void main() { + v_uv = a_uv; gl_Position = u_matrices.proj * u_matrices.view * u_matrices.model - * vec4(a_position, 0.0, 1.0); + * vec4(a_position, 1.0); } "] struct Dummy; @@ -859,10 +883,24 @@ mod scene_fs_mod { #[src = " #version 450 -layout(location = 0) out vec4 f_color; +layout (set = 0, binding = 1) uniform Material { + float glow_strength; +} u_material; + +layout (location = 0) in vec2 v_uv; + +layout (location = 0) out vec4 f_color; + +const vec3 color = vec3(0.1, 0.475, 0.811); +const float edge_thickness = 2.0; +const float edge_sharpness = 30.0; +const float edge_subtract = 0.3; void main() { - f_color = vec4(0.2, 0.9, 0.9, 1.0); + vec2 uv = abs(v_uv - 0.5) * edge_thickness; + uv = pow(uv, vec2(edge_sharpness)) - edge_subtract; + float c = clamp(uv.x + uv.y, 0.0, 1.0) * u_material.glow_strength; + f_color = vec4(color * c, 1.0); } "] struct Dummy; @@ -875,10 +913,10 @@ mod postprocess_vs_mod { #[src = " #version 450 -layout(location = 0) in vec2 a_position; -layout(location = 1) in vec2 a_texcoord; +layout (location = 0) in vec2 a_position; +layout (location = 1) in vec2 a_texcoord; -layout(location = 0) out vec2 v_texcoord; +layout (location = 0) out vec2 v_texcoord; void main() { v_texcoord = a_texcoord; @@ -895,11 +933,11 @@ mod postprocess_sep_fs_mod { #[src = " #version 450 -layout(set = 0, binding = 0) uniform sampler2D u_image; +layout (set = 0, binding = 0) uniform sampler2D u_image; -layout(location = 0) in vec2 v_texcoord; +layout (location = 0) in vec2 v_texcoord; -layout(location = 0) out vec4 f_color; +layout (location = 0) out vec4 f_color; void main() { vec4 color = texture(u_image, v_texcoord); @@ -921,17 +959,17 @@ mod postprocess_blur_fs_mod { #define KERNEL_LENGTH 6 -layout(set = 0, binding = 0) uniform sampler2D u_image; -layout(set = 0, binding = 1) uniform BlurDirection { +layout (set = 0, binding = 0) uniform sampler2D u_image; +layout (set = 0, binding = 1) uniform BlurDirection { ivec2 direction; } u_blur_direction; -layout(set = 0, binding = 2) uniform BlurKernel { +layout (set = 0, binding = 2) uniform BlurKernel { float[KERNEL_LENGTH] kernel; } u_blur_kernel; -layout(location = 0) in vec2 v_texcoord; +layout (location = 0) in vec2 v_texcoord; -layout(location = 0) out vec4 f_color; +layout (location = 0) out vec4 f_color; void main() { vec2 blur_direction = vec2(u_blur_direction.direction); @@ -955,12 +993,12 @@ mod postprocess_tonemap_fs_mod { #[src = " #version 450 -layout(set = 0, binding = 0) uniform sampler2D u_image; -layout(set = 0, binding = 1) uniform sampler2D u_image_blur; +layout (set = 0, binding = 0) uniform sampler2D u_image; +layout (set = 0, binding = 1) uniform sampler2D u_image_blur; -layout(location = 0) in vec2 v_texcoord; +layout (location = 0) in vec2 v_texcoord; -layout(location = 0) out vec4 f_color; +layout (location = 0) out vec4 f_color; void main() { vec3 color = texture(u_image, v_texcoord).rgb; From 009a19ca6523c70565925bc0b6ec11ebe76be069 Mon Sep 17 00:00:00 2001 From: yanchith Date: Wed, 18 Apr 2018 13:23:56 +1000 Subject: [PATCH 06/10] Add "interpixel" sampling --- bloom/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bloom/main.rs b/bloom/main.rs index 7a7ac35..4ce46fa 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -11,12 +11,9 @@ TODO: - Code Comments! -- Add a more visually plasing scene - Refactor (this file is a bit too long) - HDR image formats -- Do not call the last step "tonemap", as we do not use HDR attachments - Optimizations - - subpixel sampling with stride 2 - some things can maybe be done in subpasses - can we reuse some images? (vulkano currently protests very much against this) * reusing would also make it possible to repeat the blurring process @@ -973,12 +970,15 @@ layout (location = 0) out vec4 f_color; void main() { vec2 blur_direction = vec2(u_blur_direction.direction); - vec2 px_direction = vec2(1) / vec2(textureSize(u_image, 0)) * blur_direction; + vec2 two_px = blur_direction * vec2(2) / vec2(textureSize(u_image, 0)); + vec2 half_px = two_px / 4.0; + vec4 color_sum = u_blur_kernel.kernel[0] * texture(u_image, v_texcoord); for (int i = 1; i <= KERNEL_LENGTH; i++) { float k = u_blur_kernel.kernel[i]; - color_sum += k * texture(u_image, px_direction * vec2(i) + v_texcoord); - color_sum += k * texture(u_image, -px_direction * vec2(i) + v_texcoord); + vec2 offset = two_px * float(i) - half_px; + color_sum += k * texture(u_image, offset + v_texcoord); + color_sum += k * texture(u_image, -offset + v_texcoord); } f_color = color_sum; } From b3666247f31e6e0904fc790e311dfc16b95efa18 Mon Sep 17 00:00:00 2001 From: yanchith Date: Sat, 7 Jul 2018 11:11:47 +1000 Subject: [PATCH 07/10] Remove unwrap()s where possible, use failure::Error + ? instead --- Cargo.lock | 67 ++++++++++++++++++- Cargo.toml | 1 + bloom/main.rs | 177 ++++++++++++++++++-------------------------------- 3 files changed, 130 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77d92d9..10d05e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,27 @@ name = "approx" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "backtrace" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" @@ -208,6 +229,25 @@ dependencies = [ "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "failure" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fnv" version = "1.0.6" @@ -552,6 +592,11 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-demangle" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scoped_threadpool" version = "0.1.7" @@ -594,6 +639,15 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "synstructure" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempdir" version = "0.3.5" @@ -604,7 +658,7 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -659,6 +713,7 @@ name = "vulkano-examples" version = "0.1.0" dependencies = [ "cgmath 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "vulkano 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -755,7 +810,7 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-client 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-protocols 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -832,6 +887,8 @@ dependencies = [ "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" +"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" +"checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" @@ -858,6 +915,8 @@ dependencies = [ "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" "checksum either 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbee135e9245416869bf52bd6ccc9b59e2482651510784e089b874272f02a252" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" +"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" +"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" @@ -902,14 +961,16 @@ dependencies = [ "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" "checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" "checksum remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfc5b3ce5d5ea144bb04ebd093a9e14e9765bcfec866aecda9b6dec43b3d1e24" +"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" "checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a" "checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" "checksum shared_library 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "7822f9d0814224552cfd7e4ac72cd511740ccec0b811d1c0f9fa2a84c6509cee" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "439d9a7c00f98b1b5ee730039bf5b1f9203d508690e3c76b509e7ad59f8f7c99" +"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum token_store 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a686838375fc11103b9c1529c6508320b7bd5e2401cd62831ca51b3e82e61849" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" diff --git a/Cargo.toml b/Cargo.toml index 03c9b7e..5fb023a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ cgmath = "0.14.1" image = "0.14.0" winit = "0.11.0" time = "0.1.37" +failure = "0.1.1" [[bin]] name = "deferred" diff --git a/bloom/main.rs b/bloom/main.rs index 4ce46fa..5be6e01 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -7,17 +7,6 @@ // notice may not be copied, modified, or distributed except // according to those terms. -/* - -TODO: -- Code Comments! -- Refactor (this file is a bit too long) -- HDR image formats -- Optimizations - - some things can maybe be done in subpasses - - can we reuse some images? (vulkano currently protests very much against this) - * reusing would also make it possible to repeat the blurring process -*/ //! Bloom example, using multiple renderpasses //! @@ -105,6 +94,7 @@ extern crate vulkano_shader_derive; extern crate winit; extern crate vulkano_win; extern crate cgmath; +extern crate failure; use std::sync::Arc; use std::mem; @@ -144,9 +134,11 @@ use vulkano::swapchain::SwapchainCreationError; use vulkano::sync as vk_sync; use vulkano::sync::GpuFuture; +use failure::Error; + mod cube; -fn main() { +fn main() -> Result<(), Error> { let instance = { let extensions = vulkano_win::required_extensions(); Instance::new(None, &extensions, None) @@ -403,7 +395,7 @@ fn main() { color: [scene_color], depth_stencil: {scene_depth} } - ).unwrap() + )? }); let postprocess_sep_renderpass = Arc::new({ @@ -421,7 +413,7 @@ fn main() { color: [sep_color], depth_stencil: {} } - ).unwrap() + )? }); let postprocess_blur_ping_renderpass = Arc::new({ @@ -439,7 +431,7 @@ fn main() { color: [ping_color], depth_stencil: {} } - ).unwrap() + )? }); let postprocess_blur_pong_renderpass = Arc::new({ @@ -457,7 +449,7 @@ fn main() { color: [pong_color], depth_stencil: {} } - ).unwrap() + )? }); let postprocess_tonemap_renderpass = Arc::new({ @@ -475,32 +467,32 @@ fn main() { color: [output_color], depth_stencil: {} } - ).unwrap() + )? }); let scene_framebuffer = Arc::new({ Framebuffer::start(scene_renderpass.clone()) - .add(scene_color_attachment.clone()).unwrap() - .add(scene_depth_attachment.clone()).unwrap() - .build().unwrap() + .add(scene_color_attachment.clone())? + .add(scene_depth_attachment.clone())? + .build()? }); let sep_framebuffer = Arc::new({ Framebuffer::start(postprocess_sep_renderpass.clone()) - .add(sep_attachment.clone()).unwrap() - .build().unwrap() + .add(sep_attachment.clone())? + .build()? }); let ping_framebuffer = Arc::new({ Framebuffer::start(postprocess_blur_ping_renderpass.clone()) - .add(ping_attachment.clone()).unwrap() - .build().unwrap() + .add(ping_attachment.clone())? + .build()? }); let pong_framebuffer = Arc::new({ Framebuffer::start(postprocess_blur_pong_renderpass.clone()) - .add(pong_attachment.clone()).unwrap() - .build().unwrap() + .add(pong_attachment.clone())? + .build()? }); @@ -513,8 +505,7 @@ fn main() { .fragment_shader(scene_fs.main_entry_point(), ()) .depth_stencil_simple_depth() .render_pass(Subpass::from(scene_renderpass.clone(), 0).unwrap()) - .build(device.clone()) - .unwrap() + .build(device.clone())? }); let postprocess_sep_pipeline = Arc::new({ @@ -524,10 +515,8 @@ fn main() { .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(postprocess_sep_fs.main_entry_point(), ()) - .render_pass(Subpass::from(postprocess_sep_renderpass.clone(), 0) - .unwrap()) - .build(device.clone()) - .unwrap() + .render_pass(Subpass::from(postprocess_sep_renderpass.clone(), 0).unwrap()) + .build(device.clone())? }); let postprocess_blur_ping_pipeline = Arc::new({ @@ -540,10 +529,8 @@ fn main() { .render_pass(Subpass::from( postprocess_blur_ping_renderpass.clone(), 0, - ) - .unwrap()) - .build(device.clone()) - .unwrap() + ).unwrap()) + .build(device.clone())? }); let postprocess_blur_pong_pipeline = Arc::new({ @@ -556,10 +543,8 @@ fn main() { .render_pass(Subpass::from( postprocess_blur_pong_renderpass.clone(), 0, - ) - .unwrap()) - .build(device.clone()) - .unwrap() + ).unwrap()) + .build(device.clone())? }); let postprocess_tonemap_pipeline = Arc::new({ @@ -569,57 +554,42 @@ fn main() { .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(postprocess_tonemap_fs.main_entry_point(), ()) - .render_pass(Subpass::from(postprocess_tonemap_renderpass.clone(), 0) - .unwrap()) - .build(device.clone()) - .unwrap() + .render_pass(Subpass::from(postprocess_tonemap_renderpass.clone(), 0).unwrap()) + .build(device.clone())? }); let postprocess_sep_set = Arc::new({ PersistentDescriptorSet::start(postprocess_sep_pipeline.clone(), 0) - .add_sampled_image(scene_color_attachment.clone(), sampler.clone()) - .unwrap() - .build() - .unwrap() + .add_sampled_image(scene_color_attachment.clone(), sampler.clone())? + .build()? }); // Ping set is used to render to ping, therefore has to use pong attachment let postprocess_blur_ping_set = Arc::new({ PersistentDescriptorSet::start(postprocess_blur_ping_pipeline.clone(), 0) - .add_sampled_image(sep_attachment.clone(), sampler.clone()) - .unwrap() - .add_buffer(blur_direction_uniform_buffer_horizontal.clone()) - .unwrap() - .add_buffer(blur_kernel_uniform_buffer.clone()) - .unwrap() - .build() - .unwrap() + .add_sampled_image(sep_attachment.clone(), sampler.clone())? + .add_buffer(blur_direction_uniform_buffer_horizontal.clone())? + .add_buffer(blur_kernel_uniform_buffer.clone())? + .build()? }); // Pong set is used to render to pong, therefore has to use ping attachment let postprocess_blur_pong_set = Arc::new({ PersistentDescriptorSet::start(postprocess_blur_pong_pipeline.clone(), 0) - .add_sampled_image(ping_attachment.clone(), sampler.clone()) - .unwrap() - .add_buffer(blur_direction_uniform_buffer_vertical.clone()) - .unwrap() - .add_buffer(blur_kernel_uniform_buffer.clone()) - .unwrap() - .build() - .unwrap() + .add_sampled_image(ping_attachment.clone(), sampler.clone())? + .add_buffer(blur_direction_uniform_buffer_vertical.clone())? + .add_buffer(blur_kernel_uniform_buffer.clone())? + .build()? }); let postprocess_tonemap_set = Arc::new({ PersistentDescriptorSet::start(postprocess_tonemap_pipeline.clone(), 0) - .add_sampled_image(scene_color_attachment.clone(), sampler.clone()) - .unwrap() - .add_sampled_image(pong_attachment.clone(), sampler.clone()) - .unwrap() - .build() - .unwrap() + .add_sampled_image(scene_color_attachment.clone(), sampler.clone())? + .add_sampled_image(pong_attachment.clone(), sampler.clone())? + .build()? }); - let mut previous_frame_end: Box = Box::new(vk_sync::now(device.clone())); + let mut previous_frame_end: Box = Box::new(vk_sync::now(device.clone())); let mut framebuffers: Option>>> = None; let mut recreate_swapchain = false; @@ -678,21 +648,21 @@ fn main() { view: view_matrix.into(), proj: proj_matrix.into(), }; - let matrix_subbuffer = matrix_uniform_buffer.next(matrix_data).unwrap(); + let matrix_subbuffer = matrix_uniform_buffer.next(matrix_data)?; let material_data = scene_fs_mod::ty::Material { glow_strength: 10.0 * (factor.sin() + 1.0) as f32, }; - let material_subbuffer = material_uniform_buffer.next(material_data).unwrap(); + let material_subbuffer = material_uniform_buffer.next(material_data)?; (matrix_subbuffer, material_subbuffer) }; let scene_set = Arc::new({ PersistentDescriptorSet::start(scene_pipeline.clone(), 0) - .add_buffer(matrix_uniform_subbuffer).unwrap() - .add_buffer(material_uniform_subbuffer).unwrap() - .build().unwrap() + .add_buffer(matrix_uniform_subbuffer)? + .add_buffer(material_uniform_subbuffer)? + .build()? }); let scene_dynamic_state = DynamicState { @@ -719,8 +689,7 @@ fn main() { let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit( device.clone(), queue.family() - ) - .unwrap() + )? // BEGIN SCENE .begin_render_pass( scene_framebuffer.clone(), @@ -729,8 +698,7 @@ fn main() { ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0), ], - ) - .unwrap() + )? .draw_indexed( scene_pipeline.clone(), scene_dynamic_state.clone(), @@ -738,86 +706,71 @@ fn main() { scene_index_buffer.clone(), scene_set.clone(), (), - ) - .unwrap() - .end_render_pass() - .unwrap() + )? + .end_render_pass()? // END SCENE // BEGIN SEP .begin_render_pass( sep_framebuffer.clone(), false, vec![ClearValue::None], - ) - .unwrap() + )? .draw( postprocess_sep_pipeline.clone(), postprocess_dynamic_state.clone(), postprocess_vertex_buffer.clone(), postprocess_sep_set.clone(), (), - ) - .unwrap() - .end_render_pass() - .unwrap() + )? + .end_render_pass()? // END SEP // BEGIN BLUR .begin_render_pass( ping_framebuffer.clone(), false, vec![ClearValue::None], - ) - .unwrap() + )? .draw( postprocess_blur_ping_pipeline.clone(), postprocess_dynamic_state.clone(), postprocess_vertex_buffer.clone(), postprocess_blur_ping_set.clone(), (), - ) - .unwrap() - .end_render_pass() - .unwrap() + )? + .end_render_pass()? .begin_render_pass( pong_framebuffer.clone(), false, vec![ClearValue::None], - ) - .unwrap() + )? .draw( postprocess_blur_pong_pipeline.clone(), postprocess_dynamic_state.clone(), postprocess_vertex_buffer.clone(), postprocess_blur_pong_set.clone(), (), - ) - .unwrap() - .end_render_pass() - .unwrap() + )? + .end_render_pass()? // END BLUR // BEGIN TONEMAP .begin_render_pass( framebuffers.as_ref().unwrap()[image_num].clone(), false, vec![ClearValue::None], - ) - .unwrap() + )? .draw( postprocess_tonemap_pipeline.clone(), scene_dynamic_state.clone(), postprocess_vertex_buffer.clone(), postprocess_tonemap_set.clone(), (), - ) - .unwrap() - .end_render_pass() - .unwrap() + )? + .end_render_pass()? // END TONEMAP - .build() - .unwrap(); + .build()?; let future = previous_frame_end.join(acquire_future) - .then_execute(queue.clone(), command_buffer).unwrap() + .then_execute(queue.clone(), command_buffer)? .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) .then_signal_fence_and_flush(); @@ -840,7 +793,7 @@ fn main() { _ => (), } }); - if done { return; } + if done { return Ok(()); } } } From 9eceb5eb4717fdc01b44e94056199d7c64a14b99 Mon Sep 17 00:00:00 2001 From: yanchith Date: Sat, 7 Jul 2018 11:18:49 +1000 Subject: [PATCH 08/10] Edit comments --- bloom/main.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bloom/main.rs b/bloom/main.rs index 5be6e01..f89502f 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -22,7 +22,7 @@ //! //! # Implementing Bloom //! -//! Bloom happens in the screenspace, and usually requires at lest 3-4 +//! Bloom happens in the screenspace, and usually requires at least 3-4 //! rendering passes. Conceptually, the following happens: //! 1. Scene is rendered to an image //! 2. Bright colors are separated from the rendered scene to its own image @@ -46,8 +46,8 @@ //! Once we have the image containing the bright areas, we can perform gaussian //! blur on it. This is done by convoluting a gaussian kernel on the image's pixels. //! -//! When applying this 3x3 gaussian kernel to a pixel, its value will be the its -//! original value multiplied by the kernel's middle cell, summed with the kernel's +//! When applying this 3x3 gaussian kernel to a pixel, its value will be the +//! original value multiplied by the kernel's middle cell summed with the kernel's //! outer cells multiplied with their corresponding pixels in our image. //! //! 0.077847 0.123317 0.077847 @@ -59,11 +59,11 @@ //! for this 3x3 kernel we will need to perform 9 texture sample operations. //! //! To optimize, we can use 1d kernels instead of 2d, and blur in multiple render -//! passes (eg first horizontally, then vertically). +//! passes - first horizontally, then vertically. //! This reduces the number of sample operations from N ^ 2 to 2 * N, and is //! a significant speedup for larger blur kernels. //! -//! To achieve the right visual result, we can apply the pairs of blur passes +//! To achieve right visual results, we can apply the pairs of blur passes //! multiple times. //! //! ## Merge Pass @@ -78,13 +78,14 @@ //! Besides using 1d kernels for blur, we can also do the following. //! //! Use a fraction of the screen resolution for the blur images. Since we sample -//! the images anyway, they do not need to be the same size. This effectively -//! reduces the number of fragment shader runs. The resolution can easily be -//! halved before any visual degradation of output. +//! the images anyway, they do not need to be the same size. This can +//! reduce the number of fragment shader runs. The resolution can easily be +//! halved before any much degradation occurs. //! //! Another optimization is sampling between two pixels and strinding //! two pixels at once when blurring. This increases the blur's reach, and we -//! may potentially use a lesser number of passes achieve the same visual result. +//! may potentially use a lesser number of passes or smaller kernels to achieve +//! same visual results. //! #[macro_use] From d528260a45359cbbb43cbbfdbb998c78090bf874 Mon Sep 17 00:00:00 2001 From: yanchith Date: Fri, 24 Aug 2018 14:29:31 +1000 Subject: [PATCH 09/10] Remove mem::replace and format with rustfmt --- bloom/main.rs | 236 +++++++++++++++++++++++++------------------------- 1 file changed, 120 insertions(+), 116 deletions(-) diff --git a/bloom/main.rs b/bloom/main.rs index f89502f..e347701 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -7,7 +7,6 @@ // notice may not be copied, modified, or distributed except // according to those terms. - //! Bloom example, using multiple renderpasses //! //! # Introduction to Bloom @@ -92,81 +91,78 @@ extern crate vulkano; #[macro_use] extern crate vulkano_shader_derive; -extern crate winit; -extern crate vulkano_win; extern crate cgmath; extern crate failure; +extern crate vulkano_win; +extern crate winit; use std::sync::Arc; -use std::mem; use std::time::Instant; -use cgmath::{Rad, Point3, Vector3, Matrix4}; - -use winit::{EventsLoop, WindowBuilder, Event, WindowEvent}; - -use vulkano_win::VkSurfaceBuild; - -use vulkano::instance::Instance; -use vulkano::instance::PhysicalDevice; -use vulkano::device::Device; -use vulkano::device::DeviceExtensions; +use cgmath::{Matrix4, Point3, Rad, Vector3}; +use failure::Error; use vulkano::buffer::BufferUsage; use vulkano::buffer::CpuAccessibleBuffer; use vulkano::buffer::CpuBufferPool; use vulkano::command_buffer::AutoCommandBufferBuilder; use vulkano::command_buffer::DynamicState; use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; -use vulkano::image::ImageUsage; -use vulkano::image::AttachmentImage; -use vulkano::sampler::Sampler; -use vulkano::format::Format; +use vulkano::device::Device; +use vulkano::device::DeviceExtensions; use vulkano::format::ClearValue; +use vulkano::format::Format; use vulkano::framebuffer::Framebuffer; use vulkano::framebuffer::Subpass; -use vulkano::pipeline::GraphicsPipeline; +use vulkano::image::AttachmentImage; +use vulkano::image::ImageUsage; +use vulkano::instance::Instance; +use vulkano::instance::PhysicalDevice; use vulkano::pipeline::viewport::Viewport; +use vulkano::pipeline::GraphicsPipeline; +use vulkano::sampler::Sampler; use vulkano::swapchain; -use vulkano::swapchain::Swapchain; +use vulkano::swapchain::AcquireError; use vulkano::swapchain::PresentMode; use vulkano::swapchain::SurfaceTransform; -use vulkano::swapchain::AcquireError; +use vulkano::swapchain::Swapchain; use vulkano::swapchain::SwapchainCreationError; use vulkano::sync as vk_sync; use vulkano::sync::GpuFuture; - -use failure::Error; +use vulkano_win::VkSurfaceBuild; +use winit::{Event, EventsLoop, WindowBuilder, WindowEvent}; mod cube; fn main() -> Result<(), Error> { let instance = { let extensions = vulkano_win::required_extensions(); - Instance::new(None, &extensions, None) - .expect("failed to create Vulkan instance") + Instance::new(None, &extensions, None).expect("failed to create Vulkan instance") }; let physical = PhysicalDevice::enumerate(&instance) .next() .expect("no device available"); - println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); + println!( + "Using device: {} (type: {:?})", + physical.name(), + physical.ty() + ); let mut events_loop = EventsLoop::new(); let surface = WindowBuilder::new() .build_vk_surface(&events_loop, instance.clone()) .expect("failed to create window"); - let queue_family = physical.queue_families() - .find(|&q| { - q.supports_graphics() && surface.is_supported(q).unwrap_or(false) - }) + let queue_family = physical + .queue_families() + .find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false)) .expect("couldn't find a graphical queue family"); let (device, mut queues) = { let device_ext = DeviceExtensions { khr_swapchain: true, - .. DeviceExtensions::none() + ..DeviceExtensions::none() }; Device::new( @@ -181,7 +177,8 @@ fn main() -> Result<(), Error> { let mut dimensions; let (mut swapchain, mut images) = { - let caps = surface.capabilities(physical) + let caps = surface + .capabilities(physical) .expect("failed to get surface capabilities"); dimensions = caps.current_extent.unwrap_or([1024, 768]); @@ -219,7 +216,7 @@ fn main() -> Result<(), Error> { storage: true, color_attachment: true, sampled: true, - .. ImageUsage::none() + ..ImageUsage::none() }, ).expect("failed to create attachment image"); @@ -231,7 +228,7 @@ fn main() -> Result<(), Error> { storage: true, depth_stencil_attachment: true, sampled: true, - .. ImageUsage::none() + ..ImageUsage::none() }, ).expect("failed to create attachment image"); @@ -243,7 +240,7 @@ fn main() -> Result<(), Error> { storage: true, color_attachment: true, sampled: true, - .. ImageUsage::none() + ..ImageUsage::none() }, ).expect("failed to create attachment image"); @@ -255,7 +252,7 @@ fn main() -> Result<(), Error> { storage: true, color_attachment: true, sampled: true, - .. ImageUsage::none() + ..ImageUsage::none() }, ).expect("failed to create attachment image"); @@ -267,7 +264,7 @@ fn main() -> Result<(), Error> { storage: true, color_attachment: true, sampled: true, - .. ImageUsage::none() + ..ImageUsage::none() }, ).expect("failed to create attachment image"); @@ -291,33 +288,44 @@ fn main() -> Result<(), Error> { let postprocess_vertex_buffer = { #[derive(Debug, Clone)] - struct VertexUv { a_position: [f32; 2], a_texcoord: [f32; 2] } + struct VertexUv { + a_position: [f32; 2], + a_texcoord: [f32; 2], + } impl_vertex!(VertexUv, a_position, a_texcoord); - CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ - VertexUv { a_position: [-1.0, 3.0], a_texcoord: [0.0, 2.0] }, - VertexUv { a_position: [-1.0, -1.0], a_texcoord: [0.0, 0.0] }, - VertexUv { a_position: [3.0, -1.0], a_texcoord: [2.0, 0.0] }, - ].iter().cloned()).expect("failed to create buffer") + CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::all(), + [ + VertexUv { + a_position: [-1.0, 3.0], + a_texcoord: [0.0, 2.0], + }, + VertexUv { + a_position: [-1.0, -1.0], + a_texcoord: [0.0, 0.0], + }, + VertexUv { + a_position: [3.0, -1.0], + a_texcoord: [2.0, 0.0], + }, + ].iter() + .cloned(), + ).expect("failed to create buffer") }; - let matrix_uniform_buffer = CpuBufferPool::::new( - device.clone(), - BufferUsage::all(), - ); + let matrix_uniform_buffer = + CpuBufferPool::::new(device.clone(), BufferUsage::all()); - let material_uniform_buffer = CpuBufferPool::::new( - device.clone(), - BufferUsage::all(), - ); + let material_uniform_buffer = + CpuBufferPool::::new(device.clone(), BufferUsage::all()); let blur_direction_uniform_buffer_horizontal = { CpuAccessibleBuffer::from_data( device.clone(), BufferUsage::all(), - postprocess_blur_fs_mod::ty::BlurDirection { - direction: [1, 0], - } + postprocess_blur_fs_mod::ty::BlurDirection { direction: [1, 0] }, ).expect("failed to create buffer") }; @@ -325,9 +333,7 @@ fn main() -> Result<(), Error> { CpuAccessibleBuffer::from_data( device.clone(), BufferUsage::all(), - postprocess_blur_fs_mod::ty::BlurDirection { - direction: [0, 1], - } + postprocess_blur_fs_mod::ty::BlurDirection { direction: [0, 1] }, ).expect("failed to create buffer") }; @@ -336,15 +342,8 @@ fn main() -> Result<(), Error> { device.clone(), BufferUsage::all(), postprocess_blur_fs_mod::ty::BlurKernel { - kernel: [ - 0.382925, - 0.24173, - 0.060598, - 0.005977, - 0.000229, - 0.000003, - ], - } + kernel: [0.382925, 0.24173, 0.060598, 0.005977, 0.000229, 0.000003], + }, ).expect("failed to create buffer") }; @@ -361,13 +360,13 @@ fn main() -> Result<(), Error> { Vector3::new(0.0, 1.0, 0.0), ); - let scene_vs = scene_vs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); - let scene_fs = scene_fs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); + let scene_vs = + scene_vs_mod::Shader::load(device.clone()).expect("failed to create shader module"); + let scene_fs = + scene_fs_mod::Shader::load(device.clone()).expect("failed to create shader module"); - let postprocess_vs = postprocess_vs_mod::Shader::load(device.clone()) - .expect("failed to create shader module"); + let postprocess_vs = + postprocess_vs_mod::Shader::load(device.clone()).expect("failed to create shader module"); let postprocess_sep_fs = postprocess_sep_fs_mod::Shader::load(device.clone()) .expect("failed to create shader module"); let postprocess_blur_fs = postprocess_blur_fs_mod::Shader::load(device.clone()) @@ -496,7 +495,6 @@ fn main() -> Result<(), Error> { .build()? }); - let scene_pipeline = Arc::new({ GraphicsPipeline::start() .vertex_input(vulkano::pipeline::vertex::TwoBuffersDefinition::new()) @@ -527,10 +525,7 @@ fn main() -> Result<(), Error> { .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(postprocess_blur_fs.main_entry_point(), ()) - .render_pass(Subpass::from( - postprocess_blur_ping_renderpass.clone(), - 0, - ).unwrap()) + .render_pass(Subpass::from(postprocess_blur_ping_renderpass.clone(), 0).unwrap()) .build(device.clone())? }); @@ -541,10 +536,7 @@ fn main() -> Result<(), Error> { .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(postprocess_blur_fs.main_entry_point(), ()) - .render_pass(Subpass::from( - postprocess_blur_pong_renderpass.clone(), - 0, - ).unwrap()) + .render_pass(Subpass::from(postprocess_blur_pong_renderpass.clone(), 0).unwrap()) .build(device.clone())? }); @@ -592,7 +584,7 @@ fn main() -> Result<(), Error> { let mut previous_frame_end: Box = Box::new(vk_sync::now(device.clone())); - let mut framebuffers: Option>>> = None; + let mut framebuffers: Option>>> = None; let mut recreate_swapchain = false; let time_start = Instant::now(); @@ -600,9 +592,11 @@ fn main() -> Result<(), Error> { previous_frame_end.cleanup_finished(); if recreate_swapchain { - dimensions = surface.capabilities(physical) + dimensions = surface + .capabilities(physical) .expect("failed to get surface capabilities") - .current_extent.unwrap(); + .current_extent + .unwrap(); let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { Ok(r) => r, @@ -610,8 +604,8 @@ fn main() -> Result<(), Error> { Err(err) => panic!("{:?}", err), }; - mem::replace(&mut swapchain, new_swapchain); - mem::replace(&mut images, new_images); + swapchain = new_swapchain; + images = new_images; framebuffers = None; recreate_swapchain = false; @@ -619,31 +613,37 @@ fn main() -> Result<(), Error> { if framebuffers.is_none() { let new_framebuffers = Some({ - images.iter() - .map(|image| Arc::new({ - Framebuffer::start(postprocess_tonemap_renderpass.clone()) - .add(image.clone()).unwrap() - .build().unwrap() - })) + images + .iter() + .map(|image| { + Arc::new({ + Framebuffer::start(postprocess_tonemap_renderpass.clone()) + .add(image.clone()) + .unwrap() + .build() + .unwrap() + }) + }) .collect::>() }); - mem::replace(&mut framebuffers, new_framebuffers); + + framebuffers = new_framebuffers; } - let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { - Ok(r) => r, - Err(AcquireError::OutOfDate) => { - recreate_swapchain = true; - continue; - }, - Err(err) => panic!("{:?}", err), - }; + let (image_num, acquire_future) = + match swapchain::acquire_next_image(swapchain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + recreate_swapchain = true; + continue; + } + Err(err) => panic!("{:?}", err), + }; let (matrix_uniform_subbuffer, material_uniform_subbuffer) = { let elapsed = time_start.elapsed(); - let factor = elapsed.as_secs() as f64 - + elapsed.subsec_nanos() as f64 * 1e-9; + let factor = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9; let matrix_data = scene_vs_mod::ty::Matrices { model: Matrix4::from_angle_y(Rad(factor as f32)).into(), view: view_matrix.into(), @@ -670,9 +670,9 @@ fn main() -> Result<(), Error> { viewports: Some(vec![Viewport { origin: [0.0, 0.0], dimensions: [dimensions[0] as f32, dimensions[1] as f32], - depth_range: 0.0 .. 1.0, + depth_range: 0.0..1.0, }]), - .. DynamicState::none() + ..DynamicState::none() }; let postprocess_dynamic_state = DynamicState { @@ -682,9 +682,9 @@ fn main() -> Result<(), Error> { postprocess_dimensions[0] as f32, postprocess_dimensions[1] as f32, ], - depth_range: 0.0 .. 1.0, + depth_range: 0.0..1.0, }]), - .. DynamicState::none() + ..DynamicState::none() }; let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit( @@ -770,7 +770,8 @@ fn main() -> Result<(), Error> { // END TONEMAP .build()?; - let future = previous_frame_end.join(acquire_future) + let future = previous_frame_end + .join(acquire_future) .then_execute(queue.clone(), command_buffer)? .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) .then_signal_fence_and_flush(); @@ -780,21 +781,24 @@ fn main() -> Result<(), Error> { Err(vk_sync::FlushError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Box::new(vk_sync::now(device.clone())); - }, + } Err(e) => { println!("{:?}", e); previous_frame_end = Box::new(vk_sync::now(device.clone())); - }, + } } let mut done = false; - events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::Closed, .. } => done = true, - _ => (), - } + events_loop.poll_events(|ev| match ev { + Event::WindowEvent { + event: WindowEvent::Closed, + .. + } => done = true, + _ => (), }); - if done { return Ok(()); } + if done { + return Ok(()); + } } } From 55a1baa4aa54766defb9142fbcddb55f4c4e92f7 Mon Sep 17 00:00:00 2001 From: yanchith Date: Fri, 24 Aug 2018 15:50:23 +1000 Subject: [PATCH 10/10] Simplify cube --- bloom/cube.rs | 192 ++++++++++++++++++++++++++++---------------------- bloom/main.rs | 44 +++++------- 2 files changed, 126 insertions(+), 110 deletions(-) diff --git a/bloom/cube.rs b/bloom/cube.rs index 6a140d9..31cc96d 100644 --- a/bloom/cube.rs +++ b/bloom/cube.rs @@ -1,104 +1,126 @@ #[derive(Debug, Clone)] -pub struct Vertex { a_position: [f32; 3] } -impl_vertex!(Vertex, a_position); - -#[derive(Debug, Clone)] -pub struct Uv { a_uv: [f32; 2] } -impl_vertex!(Uv, a_uv); +pub struct Vertex { + a_position: [f32; 3], + a_uv: [f32; 2], +} +impl_vertex!(Vertex, a_position, a_uv); pub const VERTICES: [Vertex; 24] = [ // back - Vertex { a_position: [-1.0, -1.0, 1.0] }, - Vertex { a_position: [ 1.0, -1.0, 1.0] }, - Vertex { a_position: [ 1.0, 1.0, 1.0] }, - Vertex { a_position: [-1.0, 1.0, 1.0] }, - - // front - Vertex { a_position: [-1.0, -1.0, -1.0] }, - Vertex { a_position: [-1.0, 1.0, -1.0] }, - Vertex { a_position: [ 1.0, 1.0, -1.0] }, - Vertex { a_position: [ 1.0, -1.0, -1.0] }, - - // top - Vertex { a_position: [-1.0, 1.0, -1.0] }, - Vertex { a_position: [-1.0, 1.0, 1.0] }, - Vertex { a_position: [ 1.0, 1.0, 1.0] }, - Vertex { a_position: [ 1.0, 1.0, -1.0] }, - - // bottom - Vertex { a_position: [-1.0, -1.0, -1.0] }, - Vertex { a_position: [ 1.0, -1.0, -1.0] }, - Vertex { a_position: [ 1.0, -1.0, 1.0] }, - Vertex { a_position: [-1.0, -1.0, 1.0] }, - - // left - Vertex { a_position: [ 1.0, -1.0, -1.0] }, - Vertex { a_position: [ 1.0, 1.0, -1.0] }, - Vertex { a_position: [ 1.0, 1.0, 1.0] }, - Vertex { a_position: [ 1.0, -1.0, 1.0] }, - - // right - Vertex { a_position: [-1.0, -1.0, -1.0] }, - Vertex { a_position: [-1.0, -1.0, 1.0] }, - Vertex { a_position: [-1.0, 1.0, 1.0] }, - Vertex { a_position: [-1.0, 1.0, -1.0] }, -]; - -pub const UVS: [Uv; 24] = [ - // back - Uv { a_uv: [0.0, 0.0] }, - Uv { a_uv: [1.0, 0.0] }, - Uv { a_uv: [1.0, 1.0] }, - Uv { a_uv: [0.0, 1.0] }, - + Vertex { + a_position: [-1.0, -1.0, 1.0], + a_uv: [0.0, 0.0], + }, + Vertex { + a_position: [1.0, -1.0, 1.0], + a_uv: [1.0, 0.0], + }, + Vertex { + a_position: [1.0, 1.0, 1.0], + a_uv: [1.0, 1.0], + }, + Vertex { + a_position: [-1.0, 1.0, 1.0], + a_uv: [0.0, 1.0], + }, // front - Uv { a_uv: [0.0, 0.0] }, - Uv { a_uv: [1.0, 0.0] }, - Uv { a_uv: [1.0, 1.0] }, - Uv { a_uv: [0.0, 1.0] }, - + Vertex { + a_position: [-1.0, -1.0, -1.0], + a_uv: [0.0, 0.0], + }, + Vertex { + a_position: [-1.0, 1.0, -1.0], + a_uv: [1.0, 0.0], + }, + Vertex { + a_position: [1.0, 1.0, -1.0], + a_uv: [1.0, 1.0], + }, + Vertex { + a_position: [1.0, -1.0, -1.0], + a_uv: [0.0, 1.0], + }, // top - Uv { a_uv: [0.0, 0.0] }, - Uv { a_uv: [1.0, 0.0] }, - Uv { a_uv: [1.0, 1.0] }, - Uv { a_uv: [0.0, 1.0] }, - + Vertex { + a_position: [-1.0, 1.0, -1.0], + a_uv: [0.0, 0.0], + }, + Vertex { + a_position: [-1.0, 1.0, 1.0], + a_uv: [1.0, 0.0], + }, + Vertex { + a_position: [1.0, 1.0, 1.0], + a_uv: [1.0, 1.0], + }, + Vertex { + a_position: [1.0, 1.0, -1.0], + a_uv: [0.0, 1.0], + }, // bottom - Uv { a_uv: [0.0, 0.0] }, - Uv { a_uv: [1.0, 0.0] }, - Uv { a_uv: [1.0, 1.0] }, - Uv { a_uv: [0.0, 1.0] }, - + Vertex { + a_position: [-1.0, -1.0, -1.0], + a_uv: [0.0, 0.0], + }, + Vertex { + a_position: [1.0, -1.0, -1.0], + a_uv: [1.0, 0.0], + }, + Vertex { + a_position: [1.0, -1.0, 1.0], + a_uv: [1.0, 1.0], + }, + Vertex { + a_position: [-1.0, -1.0, 1.0], + a_uv: [0.0, 1.0], + }, // left - Uv { a_uv: [0.0, 0.0] }, - Uv { a_uv: [1.0, 0.0] }, - Uv { a_uv: [1.0, 1.0] }, - Uv { a_uv: [0.0, 1.0] }, - + Vertex { + a_position: [1.0, -1.0, -1.0], + a_uv: [0.0, 0.0], + }, + Vertex { + a_position: [1.0, 1.0, -1.0], + a_uv: [1.0, 0.0], + }, + Vertex { + a_position: [1.0, 1.0, 1.0], + a_uv: [1.0, 1.0], + }, + Vertex { + a_position: [1.0, -1.0, 1.0], + a_uv: [0.0, 1.0], + }, // right - Uv { a_uv: [0.0, 0.0] }, - Uv { a_uv: [1.0, 0.0] }, - Uv { a_uv: [1.0, 1.0] }, - Uv { a_uv: [0.0, 1.0] }, + Vertex { + a_position: [-1.0, -1.0, -1.0], + a_uv: [0.0, 0.0], + }, + Vertex { + a_position: [-1.0, -1.0, 1.0], + a_uv: [1.0, 0.0], + }, + Vertex { + a_position: [-1.0, 1.0, 1.0], + a_uv: [1.0, 1.0], + }, + Vertex { + a_position: [-1.0, 1.0, -1.0], + a_uv: [0.0, 1.0], + }, ]; pub const INDICES: [u16; 36] = [ // back - 0, 1, 2, - 2, 3, 0, + 0, 1, 2, 2, 3, 0, // front - 4, 5, 6, - 6, 7, 4, + 4, 5, 6, 6, 7, 4, // top - 8, 9, 10, - 10, 11, 8, + 8, 9, 10, 10, 11, 8, // bottom - 12, 13, 14, - 14, 15, 12, + 12, 13, 14, 14, 15, 12, // left - 16, 17, 18, - 18, 19, 16, + 16, 17, 18, 18, 19, 16, // right - 20, 21, 22, - 22, 23, 20, + 20, 21, 22, 22, 23, 20, ]; diff --git a/bloom/main.rs b/bloom/main.rs index e347701..b81821c 100644 --- a/bloom/main.rs +++ b/bloom/main.rs @@ -274,12 +274,6 @@ fn main() -> Result<(), Error> { cube::VERTICES.iter().cloned(), ).expect("failed to create buffer"); - let scene_uv_buffer = CpuAccessibleBuffer::from_iter( - device.clone(), - BufferUsage::all(), - cube::UVS.iter().cloned(), - ).expect("failed to create buffer"); - let scene_index_buffer = CpuAccessibleBuffer::from_iter( device.clone(), BufferUsage::all(), @@ -290,9 +284,9 @@ fn main() -> Result<(), Error> { #[derive(Debug, Clone)] struct VertexUv { a_position: [f32; 2], - a_texcoord: [f32; 2], + a_uv: [f32; 2], } - impl_vertex!(VertexUv, a_position, a_texcoord); + impl_vertex!(VertexUv, a_position, a_uv); CpuAccessibleBuffer::from_iter( device.clone(), @@ -300,15 +294,15 @@ fn main() -> Result<(), Error> { [ VertexUv { a_position: [-1.0, 3.0], - a_texcoord: [0.0, 2.0], + a_uv: [0.0, 2.0], }, VertexUv { a_position: [-1.0, -1.0], - a_texcoord: [0.0, 0.0], + a_uv: [0.0, 0.0], }, VertexUv { a_position: [3.0, -1.0], - a_texcoord: [2.0, 0.0], + a_uv: [2.0, 0.0], }, ].iter() .cloned(), @@ -497,7 +491,7 @@ fn main() -> Result<(), Error> { let scene_pipeline = Arc::new({ GraphicsPipeline::start() - .vertex_input(vulkano::pipeline::vertex::TwoBuffersDefinition::new()) + .vertex_input_single_buffer() .vertex_shader(scene_vs.main_entry_point(), ()) .triangle_list() .viewports_dynamic_scissors_irrelevant(1) @@ -703,7 +697,7 @@ fn main() -> Result<(), Error> { .draw_indexed( scene_pipeline.clone(), scene_dynamic_state.clone(), - (scene_vertex_buffer.clone(), scene_uv_buffer.clone()), + (scene_vertex_buffer.clone()), scene_index_buffer.clone(), scene_set.clone(), (), @@ -869,12 +863,12 @@ mod postprocess_vs_mod { #version 450 layout (location = 0) in vec2 a_position; -layout (location = 1) in vec2 a_texcoord; +layout (location = 1) in vec2 a_uv; -layout (location = 0) out vec2 v_texcoord; +layout (location = 0) out vec2 v_uv; void main() { - v_texcoord = a_texcoord; + v_uv = a_uv; gl_Position = vec4(a_position, 0.0, 1.0); } "] @@ -890,12 +884,12 @@ mod postprocess_sep_fs_mod { layout (set = 0, binding = 0) uniform sampler2D u_image; -layout (location = 0) in vec2 v_texcoord; +layout (location = 0) in vec2 v_uv; layout (location = 0) out vec4 f_color; void main() { - vec4 color = texture(u_image, v_texcoord); + vec4 color = texture(u_image, v_uv); // Convert to grayscale and compute brightness float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); @@ -922,7 +916,7 @@ layout (set = 0, binding = 2) uniform BlurKernel { float[KERNEL_LENGTH] kernel; } u_blur_kernel; -layout (location = 0) in vec2 v_texcoord; +layout (location = 0) in vec2 v_uv; layout (location = 0) out vec4 f_color; @@ -931,12 +925,12 @@ void main() { vec2 two_px = blur_direction * vec2(2) / vec2(textureSize(u_image, 0)); vec2 half_px = two_px / 4.0; - vec4 color_sum = u_blur_kernel.kernel[0] * texture(u_image, v_texcoord); + vec4 color_sum = u_blur_kernel.kernel[0] * texture(u_image, v_uv); for (int i = 1; i <= KERNEL_LENGTH; i++) { float k = u_blur_kernel.kernel[i]; vec2 offset = two_px * float(i) - half_px; - color_sum += k * texture(u_image, offset + v_texcoord); - color_sum += k * texture(u_image, -offset + v_texcoord); + color_sum += k * texture(u_image, offset + v_uv); + color_sum += k * texture(u_image, -offset + v_uv); } f_color = color_sum; } @@ -954,13 +948,13 @@ mod postprocess_tonemap_fs_mod { layout (set = 0, binding = 0) uniform sampler2D u_image; layout (set = 0, binding = 1) uniform sampler2D u_image_blur; -layout (location = 0) in vec2 v_texcoord; +layout (location = 0) in vec2 v_uv; layout (location = 0) out vec4 f_color; void main() { - vec3 color = texture(u_image, v_texcoord).rgb; - vec3 bloom = texture(u_image_blur, v_texcoord).rgb; + vec3 color = texture(u_image, v_uv).rgb; + vec3 bloom = texture(u_image_blur, v_uv).rgb; const float gamma = 2.2;