From 40cb0f5314fda72a6d5c6f15b8acf965377cde9b Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 19 Aug 2018 22:15:36 +0200 Subject: [PATCH 01/78] Create README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c86d5a4 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# vulkan-tutorial-rs +Rust version of https://github.com/Overv/VulkanTutorial. + +*Goal*: Rust port with code structure as similar as possible to the original C++, so the tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs). + +**Current State**: Very early, got up to [Swap chain](https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain) so far, but the code isn't yet split up by chapter. From a3e31bebf7a69b121a6a639b84db54f30eb1f559 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 19 Aug 2018 22:18:43 +0200 Subject: [PATCH 02/78] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c86d5a4..692790e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # vulkan-tutorial-rs Rust version of https://github.com/Overv/VulkanTutorial. -*Goal*: Rust port with code structure as similar as possible to the original C++, so the tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs). +**Goal**: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs)). **Current State**: Very early, got up to [Swap chain](https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain) so far, but the code isn't yet split up by chapter. From 6d72263f610f4222410ece2d1671403c6a4d871e Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Mon, 20 Aug 2018 03:29:35 +0200 Subject: [PATCH 03/78] shader modules --- .gitignore | 1 + src/main.rs | 30 ++++++++++++++++++++++++++++++ src/shaders/compile.bat | 2 ++ src/shaders/compile.sh | 4 ++++ src/shaders/shader.frag | 10 ++++++++++ src/shaders/shader.vert | 25 +++++++++++++++++++++++++ 6 files changed, 72 insertions(+) create mode 100755 src/shaders/compile.bat create mode 100755 src/shaders/compile.sh create mode 100644 src/shaders/shader.frag create mode 100644 src/shaders/shader.vert diff --git a/.gitignore b/.gitignore index 53eaa21..c144c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target **/*.rs.bk +*.spv diff --git a/src/main.rs b/src/main.rs index b5fbf62..b5aaf9d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ extern crate vulkano_win; use std::sync::Arc; use std::collections::HashSet; +use std::fs::File; +use std::io::Read; use vulkano::instance::{ Instance, @@ -29,6 +31,8 @@ use vulkano::image::ImageUsage; use vulkano::image::swapchain::SwapchainImage; use vulkano::sync::SharingMode; +use vulkano::pipeline::shader::ShaderModule; + use winit::WindowBuilder; use winit::dpi::LogicalSize; use vulkano_win::VkSurfaceBuild; @@ -111,6 +115,9 @@ impl HelloTriangleApplication { self.pick_physical_device(); self.create_logical_device(); self.create_swap_chain(); + // NOTE: image views are handled by Vulkano and can be accessed via the + // SwapchainImages created above + self.create_graphics_pipeline(); } fn create_instance(&mut self) { @@ -318,6 +325,29 @@ impl HelloTriangleApplication { println!("Swapchain created!"); } + fn create_graphics_pipeline(&self) { + let vert_shader_code = Self::read_file("src/shaders/vert.spv"); + let frag_shader_code = Self::read_file("src/shaders/frag.spv"); + + let vert_shader_module = self.create_shader_module(&vert_shader_code); + let frag_shader_module = self.create_shader_module(&frag_shader_code); + println!("created shader modules"); + } + + fn read_file(filename: &str) -> Vec { + let mut f = File::open(filename) + .expect("failed to open file!"); + let mut buffer = vec![]; + f.read_to_end(&mut buffer).unwrap(); + buffer + } + + fn create_shader_module(&self, code: &[u8]) -> Arc { + unsafe { + ShaderModule::new(self.device.as_ref().unwrap().clone(), &code) + }.expect("failed to create shader module!") + } + fn find_queue_families(device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? diff --git a/src/shaders/compile.bat b/src/shaders/compile.bat new file mode 100755 index 0000000..175ddf9 --- /dev/null +++ b/src/shaders/compile.bat @@ -0,0 +1,2 @@ +glslangValidator -V shader.vert +glslangValidator -V shader.frag diff --git a/src/shaders/compile.sh b/src/shaders/compile.sh new file mode 100755 index 0000000..326bd2a --- /dev/null +++ b/src/shaders/compile.sh @@ -0,0 +1,4 @@ +#!/bin/bash +source ../../mac-env.sh +glslangValidator -V shader.vert +glslangValidator -V shader.frag diff --git a/src/shaders/shader.frag b/src/shaders/shader.frag new file mode 100644 index 0000000..84daf5e --- /dev/null +++ b/src/shaders/shader.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/src/shaders/shader.vert b/src/shaders/shader.vert new file mode 100644 index 0000000..d38f815 --- /dev/null +++ b/src/shaders/shader.vert @@ -0,0 +1,25 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +out gl_PerVertex { + vec4 gl_Position; +}; + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} From 336b3b82583141673605480342e4df6d8ac23d86 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Mon, 20 Aug 2018 09:00:51 +0200 Subject: [PATCH 04/78] switch to vulkano_shader_derive for loading shaders --- src/main.rs | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index b5aaf9d..073b0c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,6 @@ extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; extern crate winit; extern crate vulkano_win; @@ -326,11 +328,21 @@ impl HelloTriangleApplication { } fn create_graphics_pipeline(&self) { - let vert_shader_code = Self::read_file("src/shaders/vert.spv"); - let frag_shader_code = Self::read_file("src/shaders/frag.spv"); - - let vert_shader_module = self.create_shader_module(&vert_shader_code); - let frag_shader_module = self.create_shader_module(&frag_shader_code); + // NOTE: the standard vulkano way is to load shaders as GLSL at + // compile-time via macros from the vulkano_shader_derive crate. + // Loading SPIR-V at runtime like in the C++ version is partially + // implemented, but currently unused. + + // let vert_shader_code = Self::read_file("src/shaders/vert.spv"); + // let frag_shader_code = Self::read_file("src/shaders/frag.spv"); + // let vert_shader_module = self.create_shader_module(&vert_shader_code); + // let frag_shader_module = self.create_shader_module(&frag_shader_code); + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create shader module!"); + let frag_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create shader module!"); println!("created shader modules"); } @@ -410,6 +422,23 @@ impl HelloTriangleApplication { } } +#[allow(unused)] +mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/shaders/shader.vert"] + struct Dummy; +} + +#[allow(unused)] +mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/shaders/shader.frag"] + struct Dummy; +} + + fn main() { let mut app = HelloTriangleApplication::new(); app.run(); From 2078b979b0980e7c916dcdb2385fd40f75fd671a Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Mon, 20 Aug 2018 22:04:34 +0200 Subject: [PATCH 05/78] create graphics pipeline --- README.md | 2 +- src/main.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 692790e..248e816 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,4 @@ Rust version of https://github.com/Overv/VulkanTutorial. **Goal**: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs)). -**Current State**: Very early, got up to [Swap chain](https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain) so far, but the code isn't yet split up by chapter. +**Current State**: Very early, got up to the end of [Graphics pipeline basics](https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics) so far, but the code isn't yet split up by chapter. diff --git a/src/main.rs b/src/main.rs index 073b0c5..a2e0c8d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#[macro_use] extern crate vulkano; #[macro_use] extern crate vulkano_shader_derive; @@ -29,11 +30,22 @@ use vulkano::swapchain::{ CompositeAlpha, }; use vulkano::format::{Format}; -use vulkano::image::ImageUsage; -use vulkano::image::swapchain::SwapchainImage; +use vulkano::image::{ + ImageUsage, + swapchain::SwapchainImage +}; use vulkano::sync::SharingMode; -use vulkano::pipeline::shader::ShaderModule; +use vulkano::pipeline::{ + shader::ShaderModule, + GraphicsPipeline, + GraphicsPipelineAbstract, + vertex::BufferlessDefinition, +}; +use vulkano::framebuffer::{ + Subpass, + RenderPassAbstract, +}; use winit::WindowBuilder; use winit::dpi::LogicalSize; @@ -90,8 +102,10 @@ struct HelloTriangleApplication { swap_chain_images: Option>>>, swap_chain_image_format: Option, swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + graphics_pipeline: Option>, } -#[allow(dead_code)] // TODO: TMP impl HelloTriangleApplication { pub fn new() -> Self { Default::default() @@ -117,8 +131,9 @@ impl HelloTriangleApplication { self.pick_physical_device(); self.create_logical_device(); self.create_swap_chain(); - // NOTE: image views are handled by Vulkano and can be accessed via the - // SwapchainImages created above + // NOTE: no `create_image_views` becayse image views are handled by + // Vulkano and can be accessed via the SwapchainImages created above + self.create_render_pass(); self.create_graphics_pipeline(); } @@ -324,10 +339,27 @@ impl HelloTriangleApplication { self.swap_chain_images = Some(images); self.swap_chain_image_format = Some(surface_format.0); self.swap_chain_extent = Some(extent); - println!("Swapchain created!"); } - fn create_graphics_pipeline(&self) { + fn create_render_pass(&mut self) { + let device = self.device.as_ref().unwrap(); + self.render_pass = Some(Arc::new(single_pass_renderpass!(device.clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { // NOTE: the standard vulkano way is to load shaders as GLSL at // compile-time via macros from the vulkano_shader_derive crate. // Loading SPIR-V at runtime like in the C++ version is partially @@ -341,11 +373,22 @@ impl HelloTriangleApplication { let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create shader module!"); - let frag_shader_module = vertex_shader::Shader::load(device.clone()) + let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create shader module!"); - println!("created shader modules"); + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap())); + println!("GraphicsPipeline created!"); } + #[allow(unused)] fn read_file(filename: &str) -> Vec { let mut f = File::open(filename) .expect("failed to open file!"); @@ -354,6 +397,7 @@ impl HelloTriangleApplication { buffer } + #[allow(unused)] fn create_shader_module(&self, code: &[u8]) -> Arc { unsafe { ShaderModule::new(self.device.as_ref().unwrap().clone(), &code) From d53750ccd6ee5da36c44fecf6da29fa6511e3e01 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Mon, 20 Aug 2018 22:41:01 +0200 Subject: [PATCH 06/78] create framebuffers --- src/main.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main.rs b/src/main.rs index a2e0c8d..38e1e2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,8 @@ use vulkano::pipeline::{ use vulkano::framebuffer::{ Subpass, RenderPassAbstract, + Framebuffer, + FramebufferAbstract, }; use winit::WindowBuilder; @@ -105,6 +107,7 @@ struct HelloTriangleApplication { render_pass: Option>, graphics_pipeline: Option>, + swap_chain_framebuffers: Vec>, } impl HelloTriangleApplication { pub fn new() -> Self { @@ -135,6 +138,7 @@ impl HelloTriangleApplication { // Vulkano and can be accessed via the SwapchainImages created above self.create_render_pass(); self.create_graphics_pipeline(); + self.create_framebuffers(); } fn create_instance(&mut self) { @@ -388,6 +392,18 @@ impl HelloTriangleApplication { println!("GraphicsPipeline created!"); } + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + println!("framebuffers created") + } + #[allow(unused)] fn read_file(filename: &str) -> Vec { let mut f = File::open(filename) From 9eadc94f2d8d3a02a8567b4a05163d1846dd24fd Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Mon, 20 Aug 2018 23:32:01 +0200 Subject: [PATCH 07/78] command pool "creation" --- src/main.rs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 38e1e2b..9b2c889 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,6 +48,7 @@ use vulkano::framebuffer::{ Framebuffer, FramebufferAbstract, }; +use vulkano::command_buffer::pool::StandardCommandPool; use winit::WindowBuilder; use winit::dpi::LogicalSize; @@ -108,6 +109,8 @@ struct HelloTriangleApplication { render_pass: Option>, graphics_pipeline: Option>, swap_chain_framebuffers: Vec>, + + command_pool: Option>, } impl HelloTriangleApplication { pub fn new() -> Self { @@ -139,6 +142,7 @@ impl HelloTriangleApplication { self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); + self.create_command_pool(); } fn create_instance(&mut self) { @@ -189,8 +193,7 @@ impl HelloTriangleApplication { } fn pick_physical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - self.physical_device_index = PhysicalDevice::enumerate(&instance) + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) .position(|device| self.is_device_suitable(&device)) .expect("failed to find a suitable GPU!"); } @@ -249,10 +252,8 @@ impl HelloTriangleApplication { } fn create_surface(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let /*mut*/ events_loop = winit::EventsLoop::new(); - self.surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()) + self.surface = WindowBuilder::new().build_vk_surface(&events_loop, self.instance().clone()) .expect("failed to create window surface!") .into(); } @@ -346,8 +347,7 @@ impl HelloTriangleApplication { } fn create_render_pass(&mut self) { - let device = self.device.as_ref().unwrap(); - self.render_pass = Some(Arc::new(single_pass_renderpass!(device.clone(), + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), attachments: { color: { load: Clear, @@ -404,6 +404,26 @@ impl HelloTriangleApplication { println!("framebuffers created") } + // TODO!!: remove because AutoCommandBufferBuilder uses it automatically? + fn create_command_pool(&mut self) { + let device = self.device().clone(); + self.command_pool = Some(Device::standard_command_pool(&device, + self.graphics_queue.as_ref().unwrap().family())); + println!("Command pool fetched") + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } + + // fn physical_device(&self) -> PhysicalDevice { + // PhysicalDevice::from_index(self.instance(), self.physical_device_index).unwrap() + // } + #[allow(unused)] fn read_file(filename: &str) -> Vec { let mut f = File::open(filename) From e1c3d25b42ad303169dcb98ee1635144de585b98 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 21 Aug 2018 09:15:58 +0200 Subject: [PATCH 08/78] start on command buffer creation (runtime error) --- src/main.rs | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9b2c889..c03c59e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,10 @@ use vulkano::image::{ swapchain::SwapchainImage }; use vulkano::sync::SharingMode; - +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder +}; use vulkano::pipeline::{ shader::ShaderModule, GraphicsPipeline, @@ -48,7 +51,6 @@ use vulkano::framebuffer::{ Framebuffer, FramebufferAbstract, }; -use vulkano::command_buffer::pool::StandardCommandPool; use winit::WindowBuilder; use winit::dpi::LogicalSize; @@ -106,11 +108,12 @@ struct HelloTriangleApplication { swap_chain_image_format: Option, swap_chain_extent: Option<[u32; 2]>, - render_pass: Option>, + render_pass: Option>, graphics_pipeline: Option>, - swap_chain_framebuffers: Vec>, + swap_chain_framebuffers: Vec>, - command_pool: Option>, + // command_pool: Option>, + command_buffers: Vec, } impl HelloTriangleApplication { pub fn new() -> Self { @@ -142,7 +145,11 @@ impl HelloTriangleApplication { self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); - self.create_command_pool(); + // NOTE: Vulkano has a `StandardCommandPool` that is used automatically, + // but it is possible to use custom pools. See the vulkano::command_buffer + // module docs for details + // self.create_command_pool(); + self.create_command_buffers(); } fn create_instance(&mut self) { @@ -395,7 +402,7 @@ impl HelloTriangleApplication { fn create_framebuffers(&mut self) { self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) .add(image.clone()).unwrap() .build().unwrap()); fba @@ -405,11 +412,26 @@ impl HelloTriangleApplication { } // TODO!!: remove because AutoCommandBufferBuilder uses it automatically? - fn create_command_pool(&mut self) { - let device = self.device().clone(); - self.command_pool = Some(Device::standard_command_pool(&device, - self.graphics_queue.as_ref().unwrap().family())); - println!("Command pool fetched") + // fn create_command_pool(&mut self) { + // let device = self.device().clone(); + // self.command_pool = Some(Device::standard_command_pool(&device, + // self.graphics_queue.as_ref().unwrap().family())); + // } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + // TODO!!!: continue here + .build() + .unwrap() + }) + .collect(); + println!("command buffers built.") } fn instance(&self) -> &Arc { From f689fefb5a7bb55ac92b2e240d753431688aa596 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 21 Aug 2018 20:25:13 +0200 Subject: [PATCH 09/78] finish command buffer creation --- src/main.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index c03c59e..d3ef1ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,13 +37,16 @@ use vulkano::image::{ use vulkano::sync::SharingMode; use vulkano::command_buffer::{ AutoCommandBuffer, - AutoCommandBufferBuilder + AutoCommandBufferBuilder, + DynamicState, }; use vulkano::pipeline::{ shader::ShaderModule, GraphicsPipeline, GraphicsPipelineAbstract, vertex::BufferlessDefinition, + vertex::BufferlessVertices, + viewport::Viewport, }; use vulkano::framebuffer::{ Subpass, @@ -109,7 +112,7 @@ struct HelloTriangleApplication { swap_chain_extent: Option<[u32; 2]>, render_pass: Option>, - graphics_pipeline: Option>, + graphics_pipeline: Option>, swap_chain_framebuffers: Vec>, // command_pool: Option>, @@ -143,7 +146,8 @@ impl HelloTriangleApplication { // NOTE: no `create_image_views` becayse image views are handled by // Vulkano and can be accessed via the SwapchainImages created above self.create_render_pass(); - self.create_graphics_pipeline(); + // See create_command_buffers + // self.create_graphics_pipeline(); self.create_framebuffers(); // NOTE: Vulkano has a `StandardCommandPool` that is used automatically, // but it is possible to use custom pools. See the vulkano::command_buffer @@ -370,6 +374,7 @@ impl HelloTriangleApplication { ).unwrap())); } + #[allow(unused)] fn create_graphics_pipeline(&mut self) { // NOTE: the standard vulkano way is to load shaders as GLSL at // compile-time via macros from the vulkano_shader_derive crate. @@ -419,14 +424,53 @@ impl HelloTriangleApplication { // } fn create_command_buffers(&mut self) { + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let dynamic_state = DynamicState { + viewports: Some(vec![Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }]), + .. DynamicState::none() + }; + + // HACK: + // We need to define the graphics_pipeline here instead of using + // self.graphics_pipeline, because `BufferlessVertices` below only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + // Hopefully this can be removed when getting to the `Vertex Buffers` chapter + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create shader module!"); + let graphics_pipeline = Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap()); + //// + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + // let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { + let vertices = BufferlessVertices { vertices: 3, instances: 0 }; AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - // TODO!!!: continue here + .draw(graphics_pipeline.clone(), &dynamic_state, + vertices, (), ()) + .unwrap() + .end_render_pass() + .unwrap() .build() .unwrap() }) From e1ed0e1279ab81dd681dedbf34158dacd032aa42 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 21 Aug 2018 23:35:49 +0200 Subject: [PATCH 10/78] rendering and presentation (black screen) --- src/main.rs | 152 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 101 insertions(+), 51 deletions(-) diff --git a/src/main.rs b/src/main.rs index d3ef1ac..1a7f152 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,7 @@ use vulkano::swapchain::{ SupportedPresentModes, PresentMode, Swapchain, CompositeAlpha, + acquire_next_image, }; use vulkano::format::{Format}; use vulkano::image::{ @@ -43,17 +44,18 @@ use vulkano::command_buffer::{ use vulkano::pipeline::{ shader::ShaderModule, GraphicsPipeline, - GraphicsPipelineAbstract, vertex::BufferlessDefinition, vertex::BufferlessVertices, viewport::Viewport, }; +use vulkano::descriptor::PipelineLayoutAbstract; use vulkano::framebuffer::{ Subpass, RenderPassAbstract, Framebuffer, FramebufferAbstract, }; +use vulkano::sync::GpuFuture; use winit::WindowBuilder; use winit::dpi::LogicalSize; @@ -94,10 +96,13 @@ impl QueueFamilyIndices { } } +type ConcreteGraphicsPipeline = Arc, Arc>>; + #[derive(Default)] struct HelloTriangleApplication { instance: Option>, debug_callback: Option, + events_loop: Option, surface: Option>>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) @@ -112,10 +117,19 @@ struct HelloTriangleApplication { swap_chain_extent: Option<[u32; 2]>, render_pass: Option>, - graphics_pipeline: Option>, + + // NOTE: We need to the full type of + // self.graphics_pipeline, because `BufferlessVertices` only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + // TODO: check if can be simplified later in tutorial + // graphics_pipeline: Option>, + graphics_pipeline: Option, + swap_chain_framebuffers: Vec>, // command_pool: Option>, + #[allow(dead_code)] command_buffers: Vec, } impl HelloTriangleApplication { @@ -143,17 +157,18 @@ impl HelloTriangleApplication { self.pick_physical_device(); self.create_logical_device(); self.create_swap_chain(); - // NOTE: no `create_image_views` becayse image views are handled by + // NOTE: no `create_image_views` because image views are handled by // Vulkano and can be accessed via the SwapchainImages created above self.create_render_pass(); - // See create_command_buffers - // self.create_graphics_pipeline(); + self.create_graphics_pipeline(); self.create_framebuffers(); - // NOTE: Vulkano has a `StandardCommandPool` that is used automatically, - // but it is possible to use custom pools. See the vulkano::command_buffer - // module docs for details - // self.create_command_pool(); - self.create_command_buffers(); + + // NOTE: No self.create_command_pool() - Vulkano has a `StandardCommandPool` + // that is used automatically, but it is possible to use custom pools. + // See the vulkano::command_buffer module docs for details + + // TODO!: replaced by create_command_buffer() in draw_frame() + // self.create_command_buffers(); } fn create_instance(&mut self) { @@ -263,8 +278,8 @@ impl HelloTriangleApplication { } fn create_surface(&mut self) { - let /*mut*/ events_loop = winit::EventsLoop::new(); - self.surface = WindowBuilder::new().build_vk_surface(&events_loop, self.instance().clone()) + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new().build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) .expect("failed to create window surface!") .into(); } @@ -401,7 +416,6 @@ impl HelloTriangleApplication { .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) .build(device.clone()) .unwrap())); - println!("GraphicsPipeline created!"); } fn create_framebuffers(&mut self) { @@ -413,16 +427,9 @@ impl HelloTriangleApplication { fba } ).collect::>(); - println!("framebuffers created") } - // TODO!!: remove because AutoCommandBufferBuilder uses it automatically? - // fn create_command_pool(&mut self) { - // let device = self.device().clone(); - // self.command_pool = Some(Device::standard_command_pool(&device, - // self.graphics_queue.as_ref().unwrap().family())); - // } - + #[allow(dead_code)] fn create_command_buffers(&mut self) { let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; @@ -435,36 +442,14 @@ impl HelloTriangleApplication { .. DynamicState::none() }; - // HACK: - // We need to define the graphics_pipeline here instead of using - // self.graphics_pipeline, because `BufferlessVertices` below only - // works when the concrete type of the graphics pipeline is visible - // to the command buffer. - // Hopefully this can be removed when getting to the `Vertex Buffers` chapter - let device = self.device.as_ref().unwrap(); - let vert_shader_module = vertex_shader::Shader::load(device.clone()) - .expect("failed to create shader module!"); - let frag_shader_module = fragment_shader::Shader::load(device.clone()) - .expect("failed to create shader module!"); - let graphics_pipeline = Arc::new(GraphicsPipeline::start() - .vertex_input(BufferlessDefinition {}) - .vertex_shader(vert_shader_module.main_entry_point(), ()) - .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) - .fragment_shader(frag_shader_module.main_entry_point(), ()) - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) - .build(device.clone()) - .unwrap()); - //// - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - // let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { let vertices = BufferlessVertices { vertices: 3, instances: 0 }; AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) .unwrap() - .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 1.0, 0.0, 1.0].into()]) .unwrap() .draw(graphics_pipeline.clone(), &dynamic_state, vertices, (), ()) @@ -475,21 +460,46 @@ impl HelloTriangleApplication { .unwrap() }) .collect(); - println!("command buffers built.") } + fn create_command_buffer(&self, image_index: usize) -> AutoCommandBuffer { + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let dynamic_state = DynamicState { + viewports: Some(vec![Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }]), + .. DynamicState::none() + }; + + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let framebuffer = &self.swap_chain_framebuffers[image_index]; + let vertices = BufferlessVertices { vertices: 3, instances: 0 }; + AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw(graphics_pipeline.clone(), &dynamic_state, vertices, (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap() + } + + #[inline] fn instance(&self) -> &Arc { self.instance.as_ref().unwrap() } + #[inline] fn device(&self) -> &Arc { self.device.as_ref().unwrap() } - // fn physical_device(&self) -> PhysicalDevice { - // PhysicalDevice::from_index(self.instance(), self.physical_device_index).unwrap() - // } - #[allow(unused)] fn read_file(filename: &str) -> Vec { let mut f = File::open(filename) @@ -558,8 +568,48 @@ impl HelloTriangleApplication { extensions } - fn main_loop(&self) { + fn main_loop(&mut self) { + loop { + self.draw_frame(); + + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + // TODO!: vkDeviceWaitIdle(device);? + return; + } + } + } + + fn draw_frame(&mut self) { + let swap_chain = self.swap_chain().clone(); + let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); + let queue = self.graphics_queue().clone(); + // TODO!?: command buffers are consumed by execution, so we can't really use the pre-build ones... + // let commmand_buffer = self.command_buffers.pop().unwrap(); + let command_buffer = self.create_command_buffer(image_index); + + // TODO!!: sync...last frame? + let _future = acquire_future + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + } + + #[inline] + fn swap_chain(&self) -> &Arc> { + self.swap_chain.as_ref().unwrap() + } + #[inline] + fn graphics_queue(&self) -> &Arc { + self.graphics_queue.as_ref().unwrap() } fn cleanup(&self) { From ed3a4288573a5ddca49eb8f024c425dcaf59f2db Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 21 Aug 2018 23:57:46 +0200 Subject: [PATCH 11/78] solve command buffer reuse problem --- src/main.rs | 84 +++++++++++++++-------------------------------------- 1 file changed, 24 insertions(+), 60 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1a7f152..3a81893 100644 --- a/src/main.rs +++ b/src/main.rs @@ -129,8 +129,7 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, // command_pool: Option>, - #[allow(dead_code)] - command_buffers: Vec, + command_buffers: Vec>, } impl HelloTriangleApplication { pub fn new() -> Self { @@ -167,8 +166,7 @@ impl HelloTriangleApplication { // that is used automatically, but it is possible to use custom pools. // See the vulkano::command_buffer module docs for details - // TODO!: replaced by create_command_buffer() in draw_frame() - // self.create_command_buffers(); + self.create_command_buffers(); } fn create_instance(&mut self) { @@ -429,7 +427,6 @@ impl HelloTriangleApplication { ).collect::>(); } - #[allow(dead_code)] fn create_command_buffers(&mut self) { let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; @@ -447,7 +444,7 @@ impl HelloTriangleApplication { self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { let vertices = BufferlessVertices { vertices: 3, instances: 0 }; - AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 1.0, 0.0, 1.0].into()]) .unwrap() @@ -457,49 +454,11 @@ impl HelloTriangleApplication { .end_render_pass() .unwrap() .build() - .unwrap() + .unwrap()) }) .collect(); } - fn create_command_buffer(&self, image_index: usize) -> AutoCommandBuffer { - let swap_chain_extent = self.swap_chain_extent.unwrap(); - let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; - let dynamic_state = DynamicState { - viewports: Some(vec![Viewport { - origin: [0.0, 0.0], - dimensions, - depth_range: 0.0 .. 1.0, - }]), - .. DynamicState::none() - }; - - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); - let framebuffer = &self.swap_chain_framebuffers[image_index]; - let vertices = BufferlessVertices { vertices: 3, instances: 0 }; - AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) - .unwrap() - .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) - .unwrap() - .draw(graphics_pipeline.clone(), &dynamic_state, vertices, (), ()) - .unwrap() - .end_render_pass() - .unwrap() - .build() - .unwrap() - } - - #[inline] - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - #[inline] - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } - #[allow(unused)] fn read_file(filename: &str) -> Vec { let mut f = File::open(filename) @@ -528,7 +487,6 @@ impl HelloTriangleApplication { indices.present_family = i as i32; } - if indices.is_complete() { break; } @@ -590,31 +548,38 @@ impl HelloTriangleApplication { let swap_chain = self.swap_chain().clone(); let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); let queue = self.graphics_queue().clone(); - // TODO!?: command buffers are consumed by execution, so we can't really use the pre-build ones... - // let commmand_buffer = self.command_buffers.pop().unwrap(); - let command_buffer = self.create_command_buffer(image_index); + let command_buffer = self.command_buffers[image_index].clone(); - // TODO!!: sync...last frame? - let _future = acquire_future + let future = acquire_future .then_execute(queue.clone(), command_buffer) .unwrap() .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) - .then_signal_fence_and_flush(); + .then_signal_fence_and_flush() + .unwrap(); + + // TODO!!: better syncing... + future.wait(None).unwrap(); } - #[inline] - fn swap_chain(&self) -> &Arc> { - self.swap_chain.as_ref().unwrap() + fn cleanup(&self) { + // TODO!: trust automatic drop and remove or use std::mem::drop here? (instance, device etc.) + // -> check with validation layers for issues with order... + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() } - #[inline] fn graphics_queue(&self) -> &Arc { self.graphics_queue.as_ref().unwrap() } - fn cleanup(&self) { - // TODO!: trust automatic drop and remove or use std::mem::drop here? (instance, device etc.) - // -> check with validation layers for issues with order... + fn swap_chain(&self) -> &Arc> { + self.swap_chain.as_ref().unwrap() } } @@ -634,7 +599,6 @@ mod fragment_shader { struct Dummy; } - fn main() { let mut app = HelloTriangleApplication::new(); app.run(); From 54aa3403bfb2987e1efb3c0305898c4712994f2c Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Wed, 22 Aug 2018 01:04:51 +0200 Subject: [PATCH 12/78] fix rendering & validation layer config --- README.md | 2 +- mac-env.sh | 1 + src/main.rs | 15 +++++++-------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 248e816..586752a 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,4 @@ Rust version of https://github.com/Overv/VulkanTutorial. **Goal**: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs)). -**Current State**: Very early, got up to the end of [Graphics pipeline basics](https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics) so far, but the code isn't yet split up by chapter. +**Current State**: Early, got up to the end of [Rendering and presentation](https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation) (the triangle renders!), but the code isn't yet split up by chapter. diff --git a/mac-env.sh b/mac-env.sh index ee63fd1..9d21e5f 100644 --- a/mac-env.sh +++ b/mac-env.sh @@ -3,3 +3,4 @@ export VULKAN_SDK=$HOME/Downloads/vulkansdk-macos-1.1.82.0/macOS export PATH=$VULKAN_SDK/bin:$PATH export DYLD_LIBRARY_PATH=$VULKAN_SDK/lib:$DYLD_LIBRARY_PATH export VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json +export VK_LAYER_PATH=$VULKAN_SDK/etc/vulkan/explicit_layer.d diff --git a/src/main.rs b/src/main.rs index 3a81893..83932cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,10 +76,9 @@ fn device_extensions() -> DeviceExtensions { } } -// MoltenVK doesn't have any layers by default -#[cfg(all(debug_assertions, not(target_os = "macos")))] +#[cfg(all(debug_assertions))] const ENABLE_VALIDATION_LAYERS: bool = true; -#[cfg(any(not(debug_assertions), target_os = "macos"))] +#[cfg(not(debug_assertions))] const ENABLE_VALIDATION_LAYERS: bool = false; struct QueueFamilyIndices { @@ -171,7 +170,7 @@ impl HelloTriangleApplication { fn create_instance(&mut self) { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { - panic!("validation layers requested, but not available!") + println!("Validation layers requested, but not available!") } let extensions = InstanceExtensions::supported_by_core() @@ -188,7 +187,7 @@ impl HelloTriangleApplication { let extensions = Self::get_required_extensions(); let instance = - if ENABLE_VALIDATION_LAYERS { + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { @@ -443,10 +442,10 @@ impl HelloTriangleApplication { let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { - let vertices = BufferlessVertices { vertices: 3, instances: 0 }; + let vertices = BufferlessVertices { vertices: 3, instances: 1 }; Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) .unwrap() - .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 1.0, 0.0, 1.0].into()]) + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() .draw(graphics_pipeline.clone(), &dynamic_state, vertices, (), ()) @@ -497,7 +496,7 @@ impl HelloTriangleApplication { fn check_validation_layer_support() -> bool { // println!("Available layers:"); - // for layer in instance::layers_list().unwrap() { + // for layer in layers_list().unwrap() { // println!("{}", layer.name()); // } for layer_name in VALIDATION_LAYERS.iter() { From 97f538e8b89784e8201d08ed804b4b20659ce506 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Wed, 22 Aug 2018 08:16:27 +0200 Subject: [PATCH 13/78] fix validation error (query present support on queue) --- src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 83932cf..e021ab4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -222,7 +222,7 @@ impl HelloTriangleApplication { } fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = Self::find_queue_families(device); + let indices = self.find_queue_families(device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { @@ -246,7 +246,7 @@ impl HelloTriangleApplication { let instance = self.instance.as_ref().unwrap(); let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - let indices = Self::find_queue_families(&physical_device); + let indices = self.find_queue_families(&physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -339,7 +339,7 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = Self::find_queue_families(&physical_device); + let indices = self.find_queue_families(&physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() @@ -474,15 +474,15 @@ impl HelloTriangleApplication { }.expect("failed to create shader module!") } - fn find_queue_families(device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { if queue_family.supports_graphics() { indices.graphics_family = i as i32; + } - // TODO: Vulkano doesn't seem to support querying 'present support' (vkGetPhysicalDeviceSurfaceSupportKHR) - // -> assuming it does if it supports graphics + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { indices.present_family = i as i32; } From e1eb042c8a822728b3dae59968123e883b980b50 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Thu, 23 Aug 2018 00:34:25 +0200 Subject: [PATCH 14/78] better syncing between frames --- src/main.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index e021ab4..3ee9546 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ use vulkano::image::{ ImageUsage, swapchain::SwapchainImage }; +use vulkano::sync; use vulkano::sync::SharingMode; use vulkano::command_buffer::{ AutoCommandBuffer, @@ -129,6 +130,10 @@ struct HelloTriangleApplication { // command_pool: Option>, command_buffers: Vec>, + + previous_frame_end: Option>, + + frame_count: u32, } impl HelloTriangleApplication { pub fn new() -> Self { @@ -166,6 +171,7 @@ impl HelloTriangleApplication { // See the vulkano::command_buffer module docs for details self.create_command_buffers(); + self.create_sync_objects(); } fn create_instance(&mut self) { @@ -458,6 +464,11 @@ impl HelloTriangleApplication { .collect(); } + fn create_sync_objects(&mut self) { + self.previous_frame_end = + Some(Box::new(sync::now(self.device().clone())) as Box); + } + #[allow(unused)] fn read_file(filename: &str) -> Vec { let mut f = File::open(filename) @@ -549,15 +560,25 @@ impl HelloTriangleApplication { let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); - let future = acquire_future + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) .then_execute(queue.clone(), command_buffer) .unwrap() .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) .then_signal_fence_and_flush() .unwrap(); - // TODO!!: better syncing... - future.wait(None).unwrap(); + self.frame_count += 1; + // print!("."); + // if (self.frame_count % 60 == 0) { + // print!("{}", self.frame_count); + // } + // use std::io::{self, Write}; + // io::stdout().flush().unwrap(); + + self.previous_frame_end = Some(Box::new(future) as Box<_>); } fn cleanup(&self) { From eb95e7f52c2a9020c3d7e1fb4682dcbe67d17ef5 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Thu, 23 Aug 2018 09:53:14 +0200 Subject: [PATCH 15/78] swap chain recreation --- src/main.rs | 77 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3ee9546..f7f3338 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,7 @@ use vulkano::swapchain::{ Swapchain, CompositeAlpha, acquire_next_image, + AcquireError, }; use vulkano::format::{Format}; use vulkano::image::{ @@ -132,6 +133,7 @@ struct HelloTriangleApplication { command_buffers: Vec>, previous_frame_end: Option>, + recreate_swap_chain: bool, frame_count: u32, } @@ -312,15 +314,22 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { - let mut actual_extent = [WIDTH, HEIGHT]; - actual_extent[0] = capabilities.min_image_extent[0] - .max(capabilities.max_image_extent[0].min(actual_extent[0])); - actual_extent[1] = capabilities.min_image_extent[1] - .max(capabilities.max_image_extent[1].min(actual_extent[1])); + let window = self.surface.as_ref().unwrap().window(); + let logical_size = window.get_inner_size().unwrap(); + let physcal_size = logical_size.to_physical(window.get_hidpi_factor()); + + let mut actual_extent = [physcal_size.width as u32, physcal_size.height as u32]; + + // old version for earlier tutorial chapter... + // let mut actual_extent = [WIDTH, HEIGHT]; + // actual_extent[0] = capabilities.min_image_extent[0] + // .max(capabilities.max_image_extent[0].min(actual_extent[0])); + // actual_extent[1] = capabilities.min_image_extent[1] + // .max(capabilities.max_image_extent[1].min(actual_extent[1])); actual_extent } } @@ -333,7 +342,7 @@ impl HelloTriangleApplication { let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = Self::choose_swap_extent(&capabilities); + let extent = self.choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -366,7 +375,7 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + self.swap_chain.as_ref(), // old_swapchain ).expect("failed to create swap chain!"); self.swap_chain = Some(swap_chain); @@ -555,20 +564,48 @@ impl HelloTriangleApplication { } fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + let swap_chain = self.swap_chain().clone(); - let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); + let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); - self.previous_frame_end.as_mut().unwrap().cleanup_finished(); - let future = self.previous_frame_end.take().unwrap() .join(acquire_future) .then_execute(queue.clone(), command_buffer) .unwrap() .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) - .then_signal_fence_and_flush() - .unwrap(); + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + } self.frame_count += 1; // print!("."); @@ -578,7 +615,19 @@ impl HelloTriangleApplication { // use std::io::{self, Write}; // io::stdout().flush().unwrap(); - self.previous_frame_end = Some(Box::new(future) as Box<_>); + // self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + + fn recreate_swap_chain(&mut self) { + unsafe { self.device().wait().unwrap(); } + + // NOTE: no cleanup_swap_chain() required - old resources will be dropped automatically + + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); } fn cleanup(&self) { From ab8253f245daf8aca9254e42c91ed8026c721c9d Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Fri, 24 Aug 2018 08:39:53 +0200 Subject: [PATCH 16/78] start on splitting up and notes (base code finished) --- README.md | 174 +++++++++++++++++++++++++++++++++++++++- mac-env.sh | 2 +- src/bin/00_base_code.rs | 56 +++++++++++++ src/main.rs | 12 +-- 4 files changed, 236 insertions(+), 8 deletions(-) create mode 100644 src/bin/00_base_code.rs diff --git a/README.md b/README.md index 586752a..ff74867 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,176 @@ Rust version of https://github.com/Overv/VulkanTutorial. **Goal**: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs)). -**Current State**: Early, got up to the end of [Rendering and presentation](https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation) (the triangle renders!), but the code isn't yet split up by chapter. +**Current State**: Early, got the code up to [Swap chain recreation](https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation) (the triangle renders!), but it isn't yet (fully) split up by chapter and the notes below are incomplete. + +--- +* [Introduction](#introduction) +* [Overview](#overview) +* [Development Environment](#development-environment) +* [Drawing a triangle](#drawing-a-triangle) + * [Setup](#setup) + * [Base code](#base-code) + * [General structure](#general-structure) + * [Resource management](#resource-management) + * [Integrating GLFW winit](#integrating-glfw-winit) + * [Instance](#instance) + * [Validation layers](#validation-layers) + * [Physical devices and queue families](#physical-devices-and-queue-families) + * [Logical device and queues](#logical-device-and-queues) + * [Presentation](#presentation) + * [Graphics pipeline basics](#graphics-pipeline-basics) + * [Drawing](#drawing) + * [Swapchain recreation](#swapchain-recreation) + +## Introduction +This tutorial consists of the the ported code and notes about the differences between the original C++ and the Rust code. +The [explanatory texts](https://vulkan-tutorial.com/Introduction) generally apply equally, although the Rust version is often shorter due to the use of [Vulkano](http://vulkano.rs/), a safe wrapper around the Vulkan API. + +## Overview +https://vulkan-tutorial.com/Overview + +(nothing to note here) + +## Development Environment +https://vulkan-tutorial.com/Development_environment + +Download the Vulkan SDK as described, but ignore everything about library and project setup. Instead, create a new Cargo project: +``` +cargo new vulkan-tutorial-rs +``` +Then add this to your `Cargo.toml`: +``` +[dependencies] +vulkano = "0.10.0" +``` + +On macOS, copy [mac-env.sh](mac-env.sh), adapt the `VULKAN_SDK` if necessary and `source` the file in your terminal. See also [vulkano-rs/vulkano#macos-and-ios-setup](https://github.com/vulkano-rs/vulkano#macos-and-ios-setup). + +## Drawing a triangle +### Setup +#### Base code +https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Base_code +##### General structure +```rust +extern crate vulkano; + +#[derive(Default)] +struct HelloTriangleApplication { + +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + self.main_loop(); + } + + fn init_vulkan(&mut self) { + + } + + fn main_loop(&mut self) { + + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} +``` + +##### Resource management +Vulkano handles calling `vkDestroyXXX`/`vkFreeXXX` in the `Drop` implementation of all wrapper objects, so we will skip all cleanup code. + +##### Integrating ~GLFW~ winit +Instead of GLFW we're using [winit](https://github.com/tomaka/winit), an alternative window managment library written in pure Rust. + +Add this to your Cargo.toml: +``` +winit = "0.17.1" +``` +And extend your main.rs: +```rust +extern crate winit; + +use winit::{ WindowBuilder, dpi::LogicalSize}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; +``` +```rust + pub fn run(&mut self) { + self.init_window(); + self.init_vulkan(); + self.main_loop(); + } + + fn init_window(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + let _window = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build(&self.events_loop.as_ref().unwrap()); + } +``` +```rust + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } +``` + +[Rust code](src/bin/00_base_code.rs) + + +#### Instance +https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance + +*TODO* + +#### Validation layers +https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers + +*TODO* + +#### Physical devices and queue families +https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families + +*TODO* + +#### Logical device and queues +https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues + +*TODO* + +### Presentation + +*TODO* + +### Graphics pipeline basics + +*TODO* + +### Drawing + +*TODO* + +### Swapchain recreation + +*TODO* + +[Rust code](src/main.rs) diff --git a/mac-env.sh b/mac-env.sh index 9d21e5f..573f85a 100644 --- a/mac-env.sh +++ b/mac-env.sh @@ -1,5 +1,5 @@ #!/bin/bash -export VULKAN_SDK=$HOME/Downloads/vulkansdk-macos-1.1.82.0/macOS +export VULKAN_SDK=$HOME/vulkansdk-macos-1.1.82.0/macOS export PATH=$VULKAN_SDK/bin:$PATH export DYLD_LIBRARY_PATH=$VULKAN_SDK/lib:$DYLD_LIBRARY_PATH export VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json diff --git a/src/bin/00_base_code.rs b/src/bin/00_base_code.rs new file mode 100644 index 0000000..be4b710 --- /dev/null +++ b/src/bin/00_base_code.rs @@ -0,0 +1,56 @@ +extern crate vulkano; +extern crate winit; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +#[derive(Default)] +struct HelloTriangleApplication { + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_window(); + self.init_vulkan(); + self.main_loop(); + } + + fn init_window(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + let _window = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build(&self.events_loop.as_ref().unwrap()); + } + + fn init_vulkan(&mut self) { + + } + + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/main.rs b/src/main.rs index f7f3338..8bc997a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -143,17 +143,17 @@ impl HelloTriangleApplication { } pub fn run(&mut self) { - self.init_window(); + // self.init_window(); self.init_vulkan(); self.main_loop(); self.cleanup(); } - fn init_window(&self) { - WindowBuilder::new() - .with_title("Vulkan") - .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); - } + // fn init_window(&self) { + // WindowBuilder::new() + // .with_title("Vulkan") + // .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); + // } fn init_vulkan(&mut self) { self.create_instance(); From e3d45d592fb92ac02d7fe538a7bec934fc11d052 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Fri, 24 Aug 2018 11:25:06 +0200 Subject: [PATCH 17/78] split off/document instance creation --- README.md | 45 ++++++++++++++++- src/bin/01_instance_creation.rs | 87 +++++++++++++++++++++++++++++++++ src/bin/diff.sh | 2 + 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/bin/01_instance_creation.rs create mode 100755 src/bin/diff.sh diff --git a/README.md b/README.md index ff74867..445e441 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,48 @@ const HEIGHT: u32 = 600; #### Instance https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance -*TODO* +```rust +extern crate vulkano_win; +``` +```rust +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, +}; +``` +```rust +struct HelloTriangleApplication { + instance: Option>, + ... +} +``` +```rust + fn init_vulkan(&mut self) { + self.create_instance(); + } +``` +```rust + fn create_instance(&mut self) { + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = vulkano_win::required_extensions(); + self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance")) + } +``` + +[Complete code](src/bin/01_instance_creation.rs) #### Validation layers https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers @@ -175,4 +216,4 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues *TODO* -[Rust code](src/main.rs) +[Complete code](src/main.rs) diff --git a/src/bin/01_instance_creation.rs b/src/bin/01_instance_creation.rs new file mode 100644 index 0000000..2270f12 --- /dev/null +++ b/src/bin/01_instance_creation.rs @@ -0,0 +1,87 @@ +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_window(); + self.init_vulkan(); + // self.main_loop(); + } + + fn init_window(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + let _window_builder = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); + // .build(&self.events_loop.as_ref().unwrap()); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + } + + fn create_instance(&mut self) { + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = vulkano_win::required_extensions(); + self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance")) + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/bin/diff.sh b/src/bin/diff.sh new file mode 100755 index 0000000..2009354 --- /dev/null +++ b/src/bin/diff.sh @@ -0,0 +1,2 @@ +#!/bin/bash +git diff --color-words --no-index "$1" "$2" From 1f16783418caeb2cfb4525d1477c66988883e2c2 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Fri, 24 Aug 2018 17:03:43 +0200 Subject: [PATCH 18/78] validation layers --- README.md | 106 ++++++++++++++++++++++- src/bin/02_validation_layers.rs | 146 ++++++++++++++++++++++++++++++++ src/main.rs | 4 - 3 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 src/bin/02_validation_layers.rs diff --git a/README.md b/README.md index 445e441..e8af791 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ https://vulkan-tutorial.com/Development_environment Download the Vulkan SDK as described, but ignore everything about library and project setup. Instead, create a new Cargo project: ``` -cargo new vulkan-tutorial-rs +$ cargo new vulkan-tutorial-rs ``` Then add this to your `Cargo.toml`: ``` @@ -136,7 +136,7 @@ const HEIGHT: u32 = 600; } ``` -[Rust code](src/bin/00_base_code.rs) +[Complete code](src/bin/00_base_code.rs) #### Instance @@ -187,8 +187,108 @@ struct HelloTriangleApplication { #### Validation layers https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers +```diff +--- a/01_instance_creation.rs ++++ b/02_validation_layers.rs +@@ -10,14 +10,26 @@ use vulkano::instance::{ + InstanceExtensions, + ApplicationInfo, + Version, ++ layers_list, + }; ++use vulkano::instance::debug::{DebugCallback, MessageTypes}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; + ++const VALIDATION_LAYERS: &[&str] = &[ ++ "VK_LAYER_LUNARG_standard_validation" ++]; ++ ++#[cfg(all(debug_assertions))] ++const ENABLE_VALIDATION_LAYERS: bool = true; ++#[cfg(not(debug_assertions))] ++const ENABLE_VALIDATION_LAYERS: bool = false; ++ + #[derive(Default)] + struct HelloTriangleApplication { + instance: Option>, ++ debug_callback: Option, + + events_loop: Option, + } +@@ -45,9 +57,14 @@ impl HelloTriangleApplication { + + fn init_vulkan(&mut self) { + self.create_instance(); ++ self.setup_debug_callback(); + } + + fn create_instance(&mut self) { ++ if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { ++ println!("Validation layers requested, but not available!") ++ } ++ + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); +@@ -59,9 +76,51 @@ impl HelloTriangleApplication { + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + +- let required_extensions = vulkano_win::required_extensions(); +- self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) +- .expect("failed to create Vulkan instance")) ++ let required_extensions = Self::get_required_extensions(); ++ ++ let instance = ++ if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { ++ Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) ++ .expect("failed to create Vulkan instance") ++ } else { ++ Instance::new(Some(&app_info), &required_extensions, None) ++ .expect("failed to create Vulkan instance") ++ }; ++ self.instance = Some(instance); ++ } ++ ++ fn check_validation_layer_support() -> bool { ++ let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); ++ VALIDATION_LAYERS.iter() ++ .all(|layer_name| layers.contains(&layer_name.to_string())) ++ } ++ ++ fn get_required_extensions() -> InstanceExtensions { ++ let mut extensions = vulkano_win::required_extensions(); ++ if ENABLE_VALIDATION_LAYERS { ++ // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano ++ extensions.ext_debug_report = true; ++ } ++ ++ extensions ++ } ++ ++ fn setup_debug_callback(&mut self) { ++ if !ENABLE_VALIDATION_LAYERS { ++ return; ++ } ++ ++ let instance = self.instance.as_ref().unwrap(); ++ let msg_types = MessageTypes { ++ error: true, ++ warning: true, ++ performance_warning: true, ++ information: false, ++ debug: true, ++ }; ++ self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { ++ println!("validation layer: {:?}", msg.description); ++ }).ok(); + } +``` + +[Complete code](src/bin/02_validation_layers.rs) -*TODO* #### Physical devices and queue families https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families diff --git a/src/bin/02_validation_layers.rs b/src/bin/02_validation_layers.rs new file mode 100644 index 0000000..178e94a --- /dev/null +++ b/src/bin/02_validation_layers.rs @@ -0,0 +1,146 @@ +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_window(); + self.init_vulkan(); + // self.main_loop(); + } + + fn init_window(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + let _window_builder = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); + // .build(&self.events_loop.as_ref().unwrap()); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/main.rs b/src/main.rs index 8bc997a..400e481 100644 --- a/src/main.rs +++ b/src/main.rs @@ -515,10 +515,6 @@ impl HelloTriangleApplication { } fn check_validation_layer_support() -> bool { - // println!("Available layers:"); - // for layer in layers_list().unwrap() { - // println!("{}", layer.name()); - // } for layer_name in VALIDATION_LAYERS.iter() { let mut layer_found = false; for layer_properties in layers_list().unwrap() { From 863abc146f91c606978b4cad56696c711b521f1e Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 02:49:44 +0200 Subject: [PATCH 19/78] physical device selection --- README.md | 94 +++++++++++- src/bin/03_physical_device_selection.rs | 194 ++++++++++++++++++++++++ 2 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 src/bin/03_physical_device_selection.rs diff --git a/README.md b/README.md index e8af791..1ac164f 100644 --- a/README.md +++ b/README.md @@ -293,7 +293,99 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers #### Physical devices and queue families https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families -*TODO* +```diff +--- a/02_validation_layers.rs ++++ b/03_physical_device_selection.rs +@@ -11,6 +11,7 @@ use vulkano::instance::{ + ApplicationInfo, + Version, + layers_list, ++ PhysicalDevice, + }; + use vulkano::instance::debug::{DebugCallback, MessageTypes}; + +@@ -26,10 +27,25 @@ const ENABLE_VALIDATION_LAYERS: bool = true; + #[cfg(not(debug_assertions))] + const ENABLE_VALIDATION_LAYERS: bool = false; + ++struct QueueFamilyIndices { ++ graphics_family: i32, ++ present_family: i32, ++} ++impl QueueFamilyIndices { ++ fn new() -> Self { ++ Self { graphics_family: -1, present_family: -1 } ++ } ++ ++ fn is_complete(&self) -> bool { ++ self.graphics_family >= 0 && self.present_family >= 0 ++ } ++} ++ + #[derive(Default)] + struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, ++ physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + + events_loop: Option, + } +@@ -58,6 +74,7 @@ impl HelloTriangleApplication { + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); ++ self.pick_physical_device(); + } + + fn create_instance(&mut self) { +@@ -123,6 +140,33 @@ impl HelloTriangleApplication { + }).ok(); + } + ++ fn pick_physical_device(&mut self) { ++ self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) ++ .position(|device| self.is_device_suitable(&device)) ++ .expect("failed to find a suitable GPU!"); ++ } ++ ++ fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { ++ let indices = self.find_queue_families(device); ++ indices.is_complete() ++ } ++ ++ fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { ++ let mut indices = QueueFamilyIndices::new(); ++ // TODO: replace index with id to simplify? ++ for (i, queue_family) in device.queue_families().enumerate() { ++ if queue_family.supports_graphics() { ++ indices.graphics_family = i as i32; ++ } ++ ++ if indices.is_complete() { ++ break; ++ } ++ } ++ ++ indices ++ } ++ + #[allow(unused)] + fn main_loop(&mut self) { + loop { +@@ -138,6 +182,10 @@ impl HelloTriangleApplication { + } + } + } ++ ++ fn instance(&self) -> &Arc { ++ self.instance.as_ref().unwrap() ++ } + } + + fn main() { +``` +[Complete code](src/bin/03_physical_device_selection.rs) + #### Logical device and queues https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues diff --git a/src/bin/03_physical_device_selection.rs b/src/bin/03_physical_device_selection.rs new file mode 100644 index 0000000..d75d963 --- /dev/null +++ b/src/bin/03_physical_device_selection.rs @@ -0,0 +1,194 @@ +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_window(); + self.init_vulkan(); + // self.main_loop(); + } + + fn init_window(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + let _window_builder = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); + // .build(&self.events_loop.as_ref().unwrap()); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.pick_physical_device(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + indices.is_complete() + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From c053875a0915c9fe3b87cf333d79b7482a7b82c4 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 03:20:11 +0200 Subject: [PATCH 20/78] logical device and queues --- README.md | 62 ++++++- src/bin/03_physical_device_selection.rs | 5 +- src/bin/04_logical_device.rs | 219 ++++++++++++++++++++++++ 3 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 src/bin/04_logical_device.rs diff --git a/README.md b/README.md index 1ac164f..4d36925 100644 --- a/README.md +++ b/README.md @@ -390,7 +390,67 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_ #### Logical device and queues https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues -*TODO* +```diff +--- a/03_physical_device_selection.rs ++++ b/04_logical_device.rs +@@ -12,8 +12,10 @@ use vulkano::instance::{ + Version, + layers_list, + PhysicalDevice, ++ Features + }; + use vulkano::instance::debug::{DebugCallback, MessageTypes}; ++use vulkano::device::{Device, DeviceExtensions, Queue}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -45,6 +47,9 @@ struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) ++ device: Option>, ++ ++ graphics_queue: Option>, + + events_loop: Option, + } +@@ -74,6 +79,7 @@ impl HelloTriangleApplication { + self.create_instance(); + self.setup_debug_callback(); + self.pick_physical_device(); ++ self.create_logical_device(); + } + + fn create_instance(&mut self) { +@@ -166,6 +172,26 @@ impl HelloTriangleApplication { + indices + } + ++ fn create_logical_device(&mut self) { ++ let instance = self.instance.as_ref().unwrap(); ++ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); ++ let indices = self.find_queue_families(&physical_device); ++ let queue_family = physical_device.queue_families() ++ .nth(indices.graphics_family as usize).unwrap(); ++ let queue_priority = 1.0; ++ ++ // NOTE: the tutorial recommends passing the validation layers as well ++ // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that ++ // for us internally. ++ ++ let (device, mut queues) = Device::new(physical_device, &Features::none(), &DeviceExtensions::none(), ++ [(queue_family, queue_priority)].iter().cloned()) ++ .expect("failed to create logical device!"); ++ ++ self.device = Some(device); ++ self.graphics_queue = queues.next(); ++ } ++ + #[allow(unused)] + fn main_loop(&mut self) { + loop { +``` +[Complete code](src/bin/04_logical_device.rs) ### Presentation diff --git a/src/bin/03_physical_device_selection.rs b/src/bin/03_physical_device_selection.rs index d75d963..1cb9481 100644 --- a/src/bin/03_physical_device_selection.rs +++ b/src/bin/03_physical_device_selection.rs @@ -29,15 +29,14 @@ const ENABLE_VALIDATION_LAYERS: bool = false; struct QueueFamilyIndices { graphics_family: i32, - present_family: i32, } impl QueueFamilyIndices { fn new() -> Self { - Self { graphics_family: -1, present_family: -1 } + Self { graphics_family: -1 } } fn is_complete(&self) -> bool { - self.graphics_family >= 0 && self.present_family >= 0 + self.graphics_family >= 0 } } diff --git a/src/bin/04_logical_device.rs b/src/bin/04_logical_device.rs new file mode 100644 index 0000000..85a3291 --- /dev/null +++ b/src/bin/04_logical_device.rs @@ -0,0 +1,219 @@ +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_window(); + self.init_vulkan(); + // self.main_loop(); + } + + fn init_window(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + let _window_builder = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); + // .build(&self.events_loop.as_ref().unwrap()); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.pick_physical_device(); + self.create_logical_device(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + indices.is_complete() + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + let indices = self.find_queue_families(&physical_device); + let queue_family = physical_device.queue_families() + .nth(indices.graphics_family as usize).unwrap(); + let queue_priority = 1.0; + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), &DeviceExtensions::none(), + [(queue_family, queue_priority)].iter().cloned()) + .expect("failed to create logical device!"); + + self.device = Some(device); + self.graphics_queue = queues.next(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From cede8840bf4f2dbddd61764e4a1ff84af0f114ca Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 11:46:11 +0200 Subject: [PATCH 21/78] collapse diffs in readme --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 4d36925..474a749 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,10 @@ struct HelloTriangleApplication { #### Validation layers https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers + +
+Diff + ```diff --- a/01_instance_creation.rs +++ b/02_validation_layers.rs @@ -286,6 +290,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers + }).ok(); } ``` +
[Complete code](src/bin/02_validation_layers.rs) @@ -293,6 +298,9 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers #### Physical devices and queue families https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families +
+Diff + ```diff --- a/02_validation_layers.rs +++ b/03_physical_device_selection.rs @@ -384,12 +392,17 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_ fn main() { ``` +
+ [Complete code](src/bin/03_physical_device_selection.rs) #### Logical device and queues https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues +
+Diff + ```diff --- a/03_physical_device_selection.rs +++ b/04_logical_device.rs @@ -450,6 +463,8 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues fn main_loop(&mut self) { loop { ``` +
+ [Complete code](src/bin/04_logical_device.rs) ### Presentation From d8cbb2abecff958a59638a11e1b487e56c735b3f Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 12:27:04 +0200 Subject: [PATCH 22/78] window surface --- README.md | 160 ++++++++++++++++++++++- src/bin/05_window_surface.rs | 245 +++++++++++++++++++++++++++++++++++ 2 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 src/bin/05_window_surface.rs diff --git a/README.md b/README.md index 474a749..24c89d9 100644 --- a/README.md +++ b/README.md @@ -468,8 +468,156 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues [Complete code](src/bin/04_logical_device.rs) ### Presentation +#### Window surface +
+Diff + +```diff +--- a/04_logical_device.rs ++++ b/05_window_surface.rs +@@ -3,8 +3,11 @@ extern crate vulkano_win; + extern crate winit; + + use std::sync::Arc; ++use std::collections::HashSet; + + use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; ++use vulkano_win::VkSurfaceBuild; ++ + use vulkano::instance::{ + Instance, + InstanceExtensions, +@@ -16,6 +19,9 @@ use vulkano::instance::{ + }; + use vulkano::instance::debug::{DebugCallback, MessageTypes}; + use vulkano::device::{Device, DeviceExtensions, Queue}; ++use vulkano::swapchain::{ ++ Surface, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -31,14 +37,15 @@ const ENABLE_VALIDATION_LAYERS: bool = false; + + struct QueueFamilyIndices { + graphics_family: i32, ++ present_family: i32, + } + impl QueueFamilyIndices { + fn new() -> Self { +- Self { graphics_family: -1 } ++ Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { +- self.graphics_family >= 0 ++ self.graphics_family >= 0 && self.present_family >= 0 + } + } + +@@ -46,10 +53,13 @@ impl QueueFamilyIndices { + struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, ++ surface: Option>>, ++ + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, ++ present_queue: Option>, + + events_loop: Option, + } +@@ -60,24 +70,14 @@ impl HelloTriangleApplication { + } + + pub fn run(&mut self) { +- self.init_window(); + self.init_vulkan(); + // self.main_loop(); + } + +- fn init_window(&mut self) { +- self.events_loop = Some(winit::EventsLoop::new()); +- // We'll leave this and the main loop commented out until we actually +- // have something to show on screen. +- let _window_builder = WindowBuilder::new() +- .with_title("Vulkan") +- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); +- // .build(&self.events_loop.as_ref().unwrap()); +- } +- + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); ++ self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + } +@@ -164,6 +164,10 @@ impl HelloTriangleApplication { + indices.graphics_family = i as i32; + } + ++ if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { ++ indices.present_family = i as i32; ++ } ++ + if indices.is_complete() { + break; + } +@@ -175,21 +179,43 @@ impl HelloTriangleApplication { + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); ++ + let indices = self.find_queue_families(&physical_device); +- let queue_family = physical_device.queue_families() +- .nth(indices.graphics_family as usize).unwrap(); ++ ++ let families = [indices.graphics_family, indices.present_family]; ++ use std::iter::FromIterator; ++ let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); ++ + let queue_priority = 1.0; ++ let queue_families = unique_queue_families.iter().map(|i| { ++ (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) ++ }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + +- let (device, mut queues) = Device::new(physical_device, &Features::none(), &DeviceExtensions::none(), +- [(queue_family, queue_priority)].iter().cloned()) ++ let (device, mut queues) = Device::new(physical_device, &Features::none(), ++ &DeviceExtensions::none(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); +- self.graphics_queue = queues.next(); ++ ++ // TODO!: simplify ++ self.graphics_queue = queues ++ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); ++ self.present_queue = queues ++ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); ++ } ++ ++ fn create_surface(&mut self) { ++ self.events_loop = Some(winit::EventsLoop::new()); ++ self.surface = WindowBuilder::new() ++ .with_title("Vulkan") ++ .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) ++ .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) ++ .expect("failed to create window surface!") ++ .into(); + } +``` +
+ +[Complete code](src/bin/05_window_surface.rs) -*TODO* ### Graphics pipeline basics @@ -484,3 +632,13 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues *TODO* [Complete code](src/main.rs) + +--- +
+Diff + +```diff +``` +
+ +[Complete code](src/bin/XXX.rs) diff --git a/src/bin/05_window_surface.rs b/src/bin/05_window_surface.rs new file mode 100644 index 0000000..e11e765 --- /dev/null +++ b/src/bin/05_window_surface.rs @@ -0,0 +1,245 @@ +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + indices.is_complete() + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &DeviceExtensions::none(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From 322de3be8b0b4fa1aa9cd3d0fb13ae2423630347 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 12:49:38 +0200 Subject: [PATCH 23/78] update toc --- README.md | 75 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 24c89d9..e1b9f3c 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,37 @@ Rust version of https://github.com/Overv/VulkanTutorial. * [Overview](#overview) * [Development Environment](#development-environment) * [Drawing a triangle](#drawing-a-triangle) - * [Setup](#setup) - * [Base code](#base-code) - * [General structure](#general-structure) - * [Resource management](#resource-management) - * [Integrating GLFW winit](#integrating-glfw-winit) - * [Instance](#instance) - * [Validation layers](#validation-layers) - * [Physical devices and queue families](#physical-devices-and-queue-families) - * [Logical device and queues](#logical-device-and-queues) - * [Presentation](#presentation) - * [Graphics pipeline basics](#graphics-pipeline-basics) - * [Drawing](#drawing) - * [Swapchain recreation](#swapchain-recreation) + * [Setup](#setup) + * [Base code](#base-code) + * [General structure](#general-structure) + * [Resource management](#resource-management) + * [Integrating GLFW winit](#integrating-glfw-winit) + * [Instance](#instance) + * [Validation layers](#validation-layers) + * [Physical devices and queue families](#physical-devices-and-queue-families) + * [Logical device and queues](#logical-device-and-queues) + * [Presentation](#presentation) + * [Window surface](#window-surface) + * [Swap chain](#swap-chain) + * [Image views](#image-views) + * [Graphics pipeline basics (TODO)](#graphics-pipeline-basics-todo) + * [Introduction](#introduction-1) + * [Shader Modules](#shader-modules) + * [Fixed functions](#fixed-functions) + * [Render passes](#render-passes) + * [Conclusion](#conclusion) + * [Drawing (TODO)](#drawing-todo) + * [Framebuffers](#framebuffers) + * [Command buffers](#command-buffers) + * [Rendering and presentation](#rendering-and-presentation) + * [Swapchain recreation (TODO)](#swapchain-recreation-todo) +* [Vertex buffers (TODO)](#vertex-buffers-todo) +* [Uniform buffers (TODO)](#uniform-buffers-todo) +* [Texture mapping (TODO)](#texture-mapping-todo) +* [Depth buffering (TODO)](#depth-buffering-todo) +* [Loading models (TODO)](#loading-models-todo) +* [Generating Mipmaps (TODO)](#generating-mipmaps-todo) +* [Multisampling (TODO)](#multisampling-todo) ## Introduction This tutorial consists of the the ported code and notes about the differences between the original C++ and the Rust code. @@ -468,7 +486,9 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues [Complete code](src/bin/04_logical_device.rs) ### Presentation + #### Window surface +https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface
Diff @@ -618,21 +638,34 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues [Complete code](src/bin/05_window_surface.rs) +#### Swap chain -### Graphics pipeline basics - -*TODO* +#### Image views -### Drawing +### Graphics pipeline basics (*TODO*) -*TODO* +#### Introduction +#### Shader Modules +#### Fixed functions +#### Render passes +#### Conclusion -### Swapchain recreation - -*TODO* +### Drawing (*TODO*) +#### Framebuffers +#### Command buffers +#### Rendering and presentation +### Swapchain recreation (*TODO*) [Complete code](src/main.rs) +## Vertex buffers (*TODO*) +## Uniform buffers (*TODO*) +## Texture mapping (*TODO*) +## Depth buffering (*TODO*) +## Loading models (*TODO*) +## Generating Mipmaps (*TODO*) +## Multisampling (*TODO*) + ---
Diff From 729ac77d8bfde99fb90a850649cc847637bb924b Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 13:32:10 +0200 Subject: [PATCH 24/78] swap chain creation --- README.md | 184 +++++++++++++++ src/bin/06_swap_chain_creation.rs | 372 ++++++++++++++++++++++++++++++ src/main.rs | 2 +- 3 files changed, 557 insertions(+), 1 deletion(-) create mode 100644 src/bin/06_swap_chain_creation.rs diff --git a/README.md b/README.md index e1b9f3c..a701860 100644 --- a/README.md +++ b/README.md @@ -639,6 +639,190 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface [Complete code](src/bin/05_window_surface.rs) #### Swap chain +
+Diff + +```diff +--- a/05_window_surface.rs ++++ b/06_swap_chain_creation.rs +@@ -21,7 +21,16 @@ use vulkano::instance::debug::{DebugCallback, MessageTypes}; + use vulkano::device::{Device, DeviceExtensions, Queue}; + use vulkano::swapchain::{ + Surface, ++ Capabilities, ++ ColorSpace, ++ SupportedPresentModes, ++ PresentMode, ++ Swapchain, ++ CompositeAlpha, + }; ++use vulkano::format::Format; ++use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; ++use vulkano::sync::SharingMode; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -30,6 +39,14 @@ const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" + ]; + ++/// Required device extensions ++fn device_extensions() -> DeviceExtensions { ++ DeviceExtensions { ++ khr_swapchain: true, ++ .. vulkano::device::DeviceExtensions::none() ++ } ++} ++ + #[cfg(all(debug_assertions))] + const ENABLE_VALIDATION_LAYERS: bool = true; + #[cfg(not(debug_assertions))] +@@ -61,6 +78,11 @@ struct HelloTriangleApplication { + graphics_queue: Option>, + present_queue: Option>, + ++ swap_chain: Option>>, ++ swap_chain_images: Option>>>, ++ swap_chain_image_format: Option, ++ swap_chain_extent: Option<[u32; 2]>, ++ + events_loop: Option, + } + +@@ -80,6 +102,7 @@ impl HelloTriangleApplication { + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); ++ self.create_swap_chain(); + } + + fn create_instance(&mut self) { +@@ -153,7 +176,111 @@ impl HelloTriangleApplication { + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); +- indices.is_complete() ++ let extensions_supported = Self::check_device_extension_support(device); ++ ++ let swap_chain_adequate = if extensions_supported { ++ let capabilities = self.query_swap_chain_support(device); ++ !capabilities.supported_formats.is_empty() && ++ capabilities.present_modes.iter().next().is_some() ++ } else { ++ false ++ }; ++ ++ indices.is_complete() && extensions_supported && swap_chain_adequate ++ } ++ ++ fn check_device_extension_support(device: &PhysicalDevice) -> bool { ++ let available_extensions = DeviceExtensions::supported_by_device(*device); ++ let device_extensions = device_extensions(); ++ available_extensions.intersection(&device_extensions) == device_extensions ++ } ++ ++ fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { ++ self.surface.as_ref().unwrap().capabilities(*device) ++ .expect("failed to get surface capabilities") ++ } ++ ++ fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { ++ // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be ++ // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) ++ *available_formats.iter() ++ .find(|(format, color_space)| ++ *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear ++ ) ++ .unwrap_or_else(|| &available_formats[0]) ++ } ++ ++ fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { ++ if available_present_modes.mailbox { ++ PresentMode::Mailbox ++ } else if available_present_modes.immediate { ++ PresentMode::Immediate ++ } else { ++ PresentMode::Fifo ++ } ++ } ++ ++ fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { ++ if let Some(current_extent) = capabilities.current_extent { ++ return current_extent ++ } else { ++ let mut actual_extent = [WIDTH, HEIGHT]; ++ actual_extent[0] = capabilities.min_image_extent[0] ++ .max(capabilities.max_image_extent[0].min(actual_extent[0])); ++ actual_extent[1] = capabilities.min_image_extent[1] ++ .max(capabilities.max_image_extent[1].min(actual_extent[1])); ++ actual_extent ++ } ++ } ++ ++ fn create_swap_chain(&mut self) { ++ let instance = self.instance.as_ref().unwrap(); ++ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); ++ ++ let capabilities = self.query_swap_chain_support(&physical_device); ++ ++ let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); ++ let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); ++ let extent = self.choose_swap_extent(&capabilities); ++ ++ let mut image_count = capabilities.min_image_count + 1; ++ if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { ++ image_count = capabilities.max_image_count.unwrap(); ++ } ++ ++ let image_usage = ImageUsage { ++ color_attachment: true, ++ .. ImageUsage::none() ++ }; ++ ++ let indices = self.find_queue_families(&physical_device); ++ ++ let sharing: SharingMode = if indices.graphics_family != indices.present_family { ++ vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() ++ } else { ++ self.graphics_queue.as_ref().unwrap().into() ++ }; ++ ++ let (swap_chain, images) = Swapchain::new( ++ self.device.as_ref().unwrap().clone(), ++ self.surface.as_ref().unwrap().clone(), ++ image_count, ++ surface_format.0, // TODO: color space? ++ extent, ++ 1, // layers ++ image_usage, ++ sharing, ++ capabilities.current_transform, ++ CompositeAlpha::Opaque, ++ present_mode, ++ true, // clipped ++ None, // old_swapchain ++ ).expect("failed to create swap chain!"); ++ ++ self.swap_chain = Some(swap_chain); ++ self.swap_chain_images = Some(images); ++ self.swap_chain_image_format = Some(surface_format.0); ++ self.swap_chain_extent = Some(extent); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { +@@ -196,7 +323,7 @@ impl HelloTriangleApplication { + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), +- &DeviceExtensions::none(), queue_families) ++ &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); +``` +
+ +[Complete code](src/bin/06_swap_chain_creation.rs) #### Image views diff --git a/src/bin/06_swap_chain_creation.rs b/src/bin/06_swap_chain_creation.rs new file mode 100644 index 0000000..6a50a2d --- /dev/null +++ b/src/bin/06_swap_chain_creation.rs @@ -0,0 +1,372 @@ +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/main.rs b/src/main.rs index 400e481..cad361b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -375,7 +375,7 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - self.swap_chain.as_ref(), // old_swapchain + None, // old_swapchain ).expect("failed to create swap chain!"); self.swap_chain = Some(swap_chain); From 76412a15dd9a0daedd2765933d07710ae85e01a5 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 13:36:54 +0200 Subject: [PATCH 25/78] Create LICENSE --- LICENSE | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cf1ab25 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to From 16f2cd5f7119af040111ef47009fac467f6f5710 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 13:52:33 +0200 Subject: [PATCH 26/78] graphics pipeline intro --- README.md | 35 ++- src/bin/08_graphics_pipeline.rs | 377 ++++++++++++++++++++++++++++++++ src/main.rs | 3 +- 3 files changed, 411 insertions(+), 4 deletions(-) create mode 100644 src/bin/08_graphics_pipeline.rs diff --git a/README.md b/README.md index a701860..43eb746 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Rust version of https://github.com/Overv/VulkanTutorial. * [Window surface](#window-surface) * [Swap chain](#swap-chain) * [Image views](#image-views) - * [Graphics pipeline basics (TODO)](#graphics-pipeline-basics-todo) + * [Graphics pipeline basics (WIP)](#graphics-pipeline-basics-wip) * [Introduction](#introduction-1) * [Shader Modules](#shader-modules) * [Fixed functions](#fixed-functions) @@ -639,6 +639,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface [Complete code](src/bin/05_window_surface.rs) #### Swap chain +https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain
Diff @@ -825,10 +826,40 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface [Complete code](src/bin/06_swap_chain_creation.rs) #### Image views +https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Image_views -### Graphics pipeline basics (*TODO*) +We're skipping this section because image because image views are handled by Vulkano and can be accessed via the SwapchainImages created in the last section. + +### Graphics pipeline basics (*WIP*) #### Introduction +https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics +
+Diff + +```diff +--- a/06_swap_chain_creation.rs ++++ b/08_graphics_pipeline.rs +@@ -103,6 +103,7 @@ impl HelloTriangleApplication { + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); ++ self.create_graphics_pipeline(); + } + + fn create_instance(&mut self) { +@@ -283,6 +284,10 @@ impl HelloTriangleApplication { + self.swap_chain_extent = Some(extent); + } + ++ fn create_graphics_pipeline(&mut self) { ++ ++ } +``` +
+ +[Complete code](src/bin/08_graphics_pipeline.rs) + #### Shader Modules #### Fixed functions #### Render passes diff --git a/src/bin/08_graphics_pipeline.rs b/src/bin/08_graphics_pipeline.rs new file mode 100644 index 0000000..25f49f1 --- /dev/null +++ b/src/bin/08_graphics_pipeline.rs @@ -0,0 +1,377 @@ +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_graphics_pipeline(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_graphics_pipeline(&mut self) { + + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/main.rs b/src/main.rs index cad361b..0cf9304 100644 --- a/src/main.rs +++ b/src/main.rs @@ -375,7 +375,7 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + self.swap_chain.as_ref(), // old_swapchain ).expect("failed to create swap chain!"); self.swap_chain = Some(swap_chain); @@ -401,7 +401,6 @@ impl HelloTriangleApplication { ).unwrap())); } - #[allow(unused)] fn create_graphics_pipeline(&mut self) { // NOTE: the standard vulkano way is to load shaders as GLSL at // compile-time via macros from the vulkano_shader_derive crate. From 970f968cf96dea1520c724acf5da02fe87244a7a Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 14:19:22 +0200 Subject: [PATCH 27/78] shader modules --- README.md | 47 +++++ src/bin/09_shader_base.frag | 10 + src/bin/09_shader_base.vert | 25 +++ src/bin/09_shader_modules.rs | 399 +++++++++++++++++++++++++++++++++++ 4 files changed, 481 insertions(+) create mode 100644 src/bin/09_shader_base.frag create mode 100644 src/bin/09_shader_base.vert create mode 100644 src/bin/09_shader_modules.rs diff --git a/README.md b/README.md index 43eb746..d5d0eb3 100644 --- a/README.md +++ b/README.md @@ -861,6 +861,53 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics [Complete code](src/bin/08_graphics_pipeline.rs) #### Shader Modules +https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules + +Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use [vulkano-shader-derive](https://docs.rs/crate/vulkano-shader-derive/) to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the [runtime shaders](https://github.com/vulkano-rs/vulkano/blob/master/examples/src/bin/runtime-shader.rs) example of Vulkano. +
+Diff + +```diff +--- a/08_graphics_pipeline.rs ++++ b/09_shader_modules.rs +@@ -1,4 +1,6 @@ + extern crate vulkano; ++#[macro_use] ++extern crate vulkano_shader_derive; + extern crate vulkano_win; + extern crate winit; + +@@ -285,7 +287,27 @@ impl HelloTriangleApplication { + } + + fn create_graphics_pipeline(&mut self) { ++ #[allow(unused)] ++ mod vertex_shader { ++ #[derive(VulkanoShader)] ++ #[ty = "vertex"] ++ #[path = "src/bin/09_shader_base.vert"] ++ struct Dummy; ++ } ++ ++ #[allow(unused)] ++ mod fragment_shader { ++ #[derive(VulkanoShader)] ++ #[ty = "fragment"] ++ #[path = "src/bin/09_shader_base.frag"] ++ struct Dummy; ++ } + ++ let device = self.device.as_ref().unwrap(); ++ let _vert_shader_module = vertex_shader::Shader::load(device.clone()) ++ .expect("failed to create vertex shader module!"); ++ let _frag_shader_module = fragment_shader::Shader::load(device.clone()) ++ .expect("failed to create fragment shader module!"); + } +``` +
+ +[Rust code](src/bin/09_shader_modules.rs) / [Vertex shader](src/bin/09_shader_base.vert) / [Fragment shader](src/bin/09_shader_base.frag) + #### Fixed functions #### Render passes #### Conclusion diff --git a/src/bin/09_shader_base.frag b/src/bin/09_shader_base.frag new file mode 100644 index 0000000..84daf5e --- /dev/null +++ b/src/bin/09_shader_base.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/src/bin/09_shader_base.vert b/src/bin/09_shader_base.vert new file mode 100644 index 0000000..d38f815 --- /dev/null +++ b/src/bin/09_shader_base.vert @@ -0,0 +1,25 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +out gl_PerVertex { + vec4 gl_Position; +}; + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} diff --git a/src/bin/09_shader_modules.rs b/src/bin/09_shader_modules.rs new file mode 100644 index 0000000..2c005db --- /dev/null +++ b/src/bin/09_shader_modules.rs @@ -0,0 +1,399 @@ +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_graphics_pipeline(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let _vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let _frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From b7d79bb05db005064b0c80abaddaf89c45214802 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 16:06:34 +0200 Subject: [PATCH 28/78] fixed functions --- README.md | 61 +++++ src/bin/10_fixed_functions.rs | 429 ++++++++++++++++++++++++++++++++++ 2 files changed, 490 insertions(+) create mode 100644 src/bin/10_fixed_functions.rs diff --git a/README.md b/README.md index d5d0eb3..92c6985 100644 --- a/README.md +++ b/README.md @@ -909,6 +909,67 @@ Instead of compiling the shaders to SPIR-V manually and loading them at runtime, [Rust code](src/bin/09_shader_modules.rs) / [Vertex shader](src/bin/09_shader_base.vert) / [Fragment shader](src/bin/09_shader_base.frag) #### Fixed functions +https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Fixed_functions + +
+Diff + +```diff +--- a/09_shader_modules.rs ++++ b/10_fixed_functions.rs +@@ -33,6 +33,11 @@ use vulkano::swapchain::{ + use vulkano::format::Format; + use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; + use vulkano::sync::SharingMode; ++use vulkano::pipeline::{ ++ GraphicsPipeline, ++ vertex::BufferlessDefinition, ++ viewport::Viewport, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -304,10 +309,35 @@ impl HelloTriangleApplication { + } + + let device = self.device.as_ref().unwrap(); +- let _vert_shader_module = vertex_shader::Shader::load(device.clone()) ++ let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); +- let _frag_shader_module = fragment_shader::Shader::load(device.clone()) ++ let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); ++ ++ let swap_chain_extent = self.swap_chain_extent.unwrap(); ++ let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; ++ let viewport = Viewport { ++ origin: [0.0, 0.0], ++ dimensions, ++ depth_range: 0.0 .. 1.0, ++ }; ++ ++ let _pipeline_builder = Arc::new(GraphicsPipeline::start() ++ .vertex_input(BufferlessDefinition {}) ++ .vertex_shader(vert_shader_module.main_entry_point(), ()) ++ .triangle_list() ++ .primitive_restart(false) ++ .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport ++ .depth_clamp(false) ++ // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... ++ .polygon_mode_fill() // = default ++ .line_width(1.0) // = default ++ .cull_mode_back() ++ .front_face_clockwise() ++ // NOTE: no depth_bias here, but on pipeline::raster::Rasterization ++ .blend_pass_through() // = default ++ .fragment_shader(frag_shader_module.main_entry_point(), ()) ++ ); + } +``` +
+ +[Complete code](src/bin/10_fixed_functions.rs) + #### Render passes #### Conclusion diff --git a/src/bin/10_fixed_functions.rs b/src/bin/10_fixed_functions.rs new file mode 100644 index 0000000..259c8c6 --- /dev/null +++ b/src/bin/10_fixed_functions.rs @@ -0,0 +1,429 @@ +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; +use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, + viewport::Viewport, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_graphics_pipeline(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + let _pipeline_builder = Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .fragment_shader(frag_shader_module.main_entry_point(), ()) + ); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From 7c8a0c34c61a6d7beee443b7cc916771361fce3e Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 16:27:42 +0200 Subject: [PATCH 29/78] render passes --- README.md | 77 ++++++ src/bin/11_render_passes.rs | 457 ++++++++++++++++++++++++++++++++++++ 2 files changed, 534 insertions(+) create mode 100644 src/bin/11_render_passes.rs diff --git a/README.md b/README.md index 92c6985..03ad89c 100644 --- a/README.md +++ b/README.md @@ -971,6 +971,83 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Fixed_fu [Complete code](src/bin/10_fixed_functions.rs) #### Render passes +https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Render_passes + +
+Diff + +```diff +--- a/10_fixed_functions.rs ++++ b/11_render_passes.rs +@@ -1,3 +1,4 @@ ++#[macro_use] + extern crate vulkano; + #[macro_use] + extern crate vulkano_shader_derive; +@@ -38,6 +39,9 @@ use vulkano::pipeline::{ + vertex::BufferlessDefinition, + viewport::Viewport, + }; ++use vulkano::framebuffer::{ ++ RenderPassAbstract, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -90,6 +94,8 @@ struct HelloTriangleApplication { + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + ++ render_pass: Option>, ++ + events_loop: Option, + } + +@@ -110,6 +116,7 @@ impl HelloTriangleApplication { + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); ++ self.create_render_pass(); + self.create_graphics_pipeline(); + } + +@@ -291,6 +298,23 @@ impl HelloTriangleApplication { + self.swap_chain_extent = Some(extent); + } + ++ fn create_render_pass(&mut self) { ++ self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), ++ attachments: { ++ color: { ++ load: Clear, ++ store: Store, ++ format: self.swap_chain.as_ref().unwrap().format(), ++ samples: 1, ++ } ++ }, ++ pass: { ++ color: [color], ++ depth_stencil: {} ++ } ++ ).unwrap())); ++ } ++ + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { +@@ -421,6 +445,10 @@ impl HelloTriangleApplication { + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } ++ ++ fn device(&self) -> &Arc { ++ self.device.as_ref().unwrap() ++ } + } +``` +
+ +[Complete code](src/bin/11_render_passes.rs) #### Conclusion ### Drawing (*TODO*) diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs new file mode 100644 index 0000000..35f14f3 --- /dev/null +++ b/src/bin/11_render_passes.rs @@ -0,0 +1,457 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; +use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + let _pipeline_builder = Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .fragment_shader(frag_shader_module.main_entry_point(), ()) + ); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From e816c491af3781524da98a48933f1eb338fa9f21 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 20:24:38 +0200 Subject: [PATCH 30/78] graphics pipeline --- .gitignore | 1 + README.md | 77 +++- src/bin/12_graphics_pipeline_complete.rs | 471 +++++++++++++++++++++++ src/bin/diff.sh | 1 + 4 files changed, 547 insertions(+), 3 deletions(-) create mode 100644 src/bin/12_graphics_pipeline_complete.rs diff --git a/.gitignore b/.gitignore index c144c9d..87f2adb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk *.spv +*.diff diff --git a/README.md b/README.md index 03ad89c..6d72d6c 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Rust version of https://github.com/Overv/VulkanTutorial. * [Window surface](#window-surface) * [Swap chain](#swap-chain) * [Image views](#image-views) - * [Graphics pipeline basics (WIP)](#graphics-pipeline-basics-wip) + * [Graphics pipeline basics](#graphics-pipeline-basics) * [Introduction](#introduction-1) * [Shader Modules](#shader-modules) * [Fixed functions](#fixed-functions) @@ -830,8 +830,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Image_views We're skipping this section because image because image views are handled by Vulkano and can be accessed via the SwapchainImages created in the last section. -### Graphics pipeline basics (*WIP*) - +### Graphics pipeline basics #### Introduction https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics
@@ -1049,6 +1048,78 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Render_p [Complete code](src/bin/11_render_passes.rs) #### Conclusion +https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Conclusion + +
+Diff + +```diff +--- a/11_render_passes.rs ++++ b/12_graphics_pipeline_complete.rs +@@ -41,7 +41,9 @@ use vulkano::pipeline::{ + }; + use vulkano::framebuffer::{ + RenderPassAbstract, ++ Subpass, + }; ++use vulkano::descriptor::PipelineLayoutAbstract; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -77,6 +79,8 @@ impl QueueFamilyIndices { + } + } + ++type ConcreteGraphicsPipeline = Arc, Arc>>; ++ + #[derive(Default)] + struct HelloTriangleApplication { + instance: Option>, +@@ -95,6 +99,13 @@ struct HelloTriangleApplication { + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, ++ // NOTE: We need to the full type of ++ // self.graphics_pipeline, because `BufferlessVertices` only ++ // works when the concrete type of the graphics pipeline is visible ++ // to the command buffer. ++ // TODO: check if can be simplified later in tutorial ++ // graphics_pipeline: Option>, ++ graphics_pipeline: Option, + + events_loop: Option, + } +@@ -346,12 +357,13 @@ impl HelloTriangleApplication { + depth_range: 0.0 .. 1.0, + }; + +- let _pipeline_builder = Arc::new(GraphicsPipeline::start() ++ self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport ++ .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default +@@ -360,8 +372,10 @@ impl HelloTriangleApplication { + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default +- .fragment_shader(frag_shader_module.main_entry_point(), ()) +- ); ++ .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) ++ .build(device.clone()) ++ .unwrap() ++ )); + } +``` +
+ +[Complete code](src/bin/12_graphics_pipeline_complete.rs) + ### Drawing (*TODO*) #### Framebuffers diff --git a/src/bin/12_graphics_pipeline_complete.rs b/src/bin/12_graphics_pipeline_complete.rs new file mode 100644 index 0000000..81fb93f --- /dev/null +++ b/src/bin/12_graphics_pipeline_complete.rs @@ -0,0 +1,471 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; +use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, +}; +use vulkano::descriptor::PipelineLayoutAbstract; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +type ConcreteGraphicsPipeline = Arc, Arc>>; + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + // NOTE: We need to the full type of + // self.graphics_pipeline, because `BufferlessVertices` only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + // TODO: check if can be simplified later in tutorial + // graphics_pipeline: Option>, + graphics_pipeline: Option, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/bin/diff.sh b/src/bin/diff.sh index 2009354..a37d93e 100755 --- a/src/bin/diff.sh +++ b/src/bin/diff.sh @@ -1,2 +1,3 @@ #!/bin/bash git diff --color-words --no-index "$1" "$2" +git diff --no-index "$1" "$2" > "$2".diff From f758449c8bda2dc473a162ba41a7132ecd5641a5 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 20:33:02 +0200 Subject: [PATCH 31/78] framebuffers --- README.md | 54 ++++ src/bin/13_framebuffers.rs | 487 +++++++++++++++++++++++++++++++++++++ 2 files changed, 541 insertions(+) create mode 100644 src/bin/13_framebuffers.rs diff --git a/README.md b/README.md index 6d72d6c..7d51468 100644 --- a/README.md +++ b/README.md @@ -1123,6 +1123,60 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Conclusi ### Drawing (*TODO*) #### Framebuffers +https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Framebuffers + +
+Diff + +```diff +--- a/12_graphics_pipeline_complete.rs ++++ b/13_framebuffers.rs +@@ -42,6 +42,8 @@ use vulkano::pipeline::{ + use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, ++ FramebufferAbstract, ++ Framebuffer, + }; + use vulkano::descriptor::PipelineLayoutAbstract; + +@@ -107,6 +109,8 @@ struct HelloTriangleApplication { + // graphics_pipeline: Option>, + graphics_pipeline: Option, + ++ swap_chain_framebuffers: Vec>, ++ + events_loop: Option, + } + +@@ -129,6 +133,7 @@ impl HelloTriangleApplication { + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); ++ self.create_framebuffers(); + } + + fn create_instance(&mut self) { +@@ -378,6 +383,17 @@ impl HelloTriangleApplication { + )); + } + ++ fn create_framebuffers(&mut self) { ++ self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() ++ .map(|image| { ++ let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) ++ .add(image.clone()).unwrap() ++ .build().unwrap()); ++ fba ++ } ++ ).collect::>(); ++ } ++ +``` +
+ +[Complete code](src/bin/13_framebuffers.rs) + #### Command buffers #### Rendering and presentation diff --git a/src/bin/13_framebuffers.rs b/src/bin/13_framebuffers.rs new file mode 100644 index 0000000..43dd8c2 --- /dev/null +++ b/src/bin/13_framebuffers.rs @@ -0,0 +1,487 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; +use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::descriptor::PipelineLayoutAbstract; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +type ConcreteGraphicsPipeline = Arc, Arc>>; + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + // NOTE: We need to the full type of + // self.graphics_pipeline, because `BufferlessVertices` only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + // TODO: check if can be simplified later in tutorial + // graphics_pipeline: Option>, + graphics_pipeline: Option, + + swap_chain_framebuffers: Vec>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From 243f390dbe8632a2cf7eac6eae7ce3038e08385f Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 20:57:20 +0200 Subject: [PATCH 32/78] command buffers --- README.md | 77 +++++ src/bin/14_command_buffers.rs | 517 ++++++++++++++++++++++++++++++++++ 2 files changed, 594 insertions(+) create mode 100644 src/bin/14_command_buffers.rs diff --git a/README.md b/README.md index 7d51468..89824cf 100644 --- a/README.md +++ b/README.md @@ -1178,6 +1178,83 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Framebuffers [Complete code](src/bin/13_framebuffers.rs) #### Command buffers +https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Command_buffers + +We're skipping the first part because Vulkano maintains a [`StandardCommandPool`].(https://docs.rs/vulkano/0.10.0/vulkano/command_buffer/pool/standard/struct.StandardCommandPool.html) + +
+Diff + +```diff +--- a/13_framebuffers.rs ++++ b/14_command_buffers.rs +@@ -37,6 +37,7 @@ use vulkano::sync::SharingMode; + use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, ++ vertex::BufferlessVertices, + viewport::Viewport, + }; + use vulkano::framebuffer::{ +@@ -46,6 +47,11 @@ use vulkano::framebuffer::{ + Framebuffer, + }; + use vulkano::descriptor::PipelineLayoutAbstract; ++use vulkano::command_buffer::{ ++ AutoCommandBuffer, ++ AutoCommandBufferBuilder, ++ DynamicState, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -111,6 +117,8 @@ struct HelloTriangleApplication { + + swap_chain_framebuffers: Vec>, + ++ command_buffers: Vec>, ++ + events_loop: Option, + } + +@@ -134,6 +142,7 @@ impl HelloTriangleApplication { + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); ++ self.create_command_buffers(); + } + + fn create_instance(&mut self) { +@@ -394,6 +403,27 @@ impl HelloTriangleApplication { + ).collect::>(); + } + ++ fn create_command_buffers(&mut self) { ++ let queue_family = self.graphics_queue.as_ref().unwrap().family(); ++ let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); ++ self.command_buffers = self.swap_chain_framebuffers.iter() ++ .map(|framebuffer| { ++ let vertices = BufferlessVertices { vertices: 3, instances: 1 }; ++ Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) ++ .unwrap() ++ .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) ++ .unwrap() ++ .draw(graphics_pipeline.clone(), &DynamicState::none(), ++ vertices, (), ()) ++ .unwrap() ++ .end_render_pass() ++ .unwrap() ++ .build() ++ .unwrap()) ++ }) ++ .collect(); ++ } ++ +``` +
+ +[Complete code](src/bin/14_command_buffers.rs) + #### Rendering and presentation ### Swapchain recreation (*TODO*) diff --git a/src/bin/14_command_buffers.rs b/src/bin/14_command_buffers.rs new file mode 100644 index 0000000..a743a75 --- /dev/null +++ b/src/bin/14_command_buffers.rs @@ -0,0 +1,517 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::SharingMode; +use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, + vertex::BufferlessVertices, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::descriptor::PipelineLayoutAbstract; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +type ConcreteGraphicsPipeline = Arc, Arc>>; + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + // NOTE: We need to the full type of + // self.graphics_pipeline, because `BufferlessVertices` only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + // TODO: check if can be simplified later in tutorial + // graphics_pipeline: Option>, + graphics_pipeline: Option, + + swap_chain_framebuffers: Vec>, + + command_buffers: Vec>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + // self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + let vertices = BufferlessVertices { vertices: 3, instances: 1 }; + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw(graphics_pipeline.clone(), &DynamicState::none(), + vertices, (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From f5d962213587095d5910f0b2162ca94f33210276 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 21:12:09 +0200 Subject: [PATCH 33/78] rendering and presentation --- README.md | 85 +++++- src/bin/15_hello_triangle.rs | 544 +++++++++++++++++++++++++++++++++++ 2 files changed, 626 insertions(+), 3 deletions(-) create mode 100644 src/bin/15_hello_triangle.rs diff --git a/README.md b/README.md index 89824cf..76a03c3 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Rust version of https://github.com/Overv/VulkanTutorial. * [Fixed functions](#fixed-functions) * [Render passes](#render-passes) * [Conclusion](#conclusion) - * [Drawing (TODO)](#drawing-todo) + * [Drawing](#drawing) * [Framebuffers](#framebuffers) * [Command buffers](#command-buffers) * [Rendering and presentation](#rendering-and-presentation) @@ -1121,7 +1121,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Conclusi [Complete code](src/bin/12_graphics_pipeline_complete.rs) -### Drawing (*TODO*) +### Drawing #### Framebuffers https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Framebuffers @@ -1180,7 +1180,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Framebuffers #### Command buffers https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Command_buffers -We're skipping the first part because Vulkano maintains a [`StandardCommandPool`].(https://docs.rs/vulkano/0.10.0/vulkano/command_buffer/pool/standard/struct.StandardCommandPool.html) +We're skipping the first part because Vulkano maintains a [`StandardCommandPool`](https://docs.rs/vulkano/0.10.0/vulkano/command_buffer/pool/standard/struct.StandardCommandPool.html).
Diff @@ -1256,6 +1256,85 @@ We're skipping the first part because Vulkano maintains a [`StandardCommandPool` [Complete code](src/bin/14_command_buffers.rs) #### Rendering and presentation +https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation + +
+Diff + +```diff +--- a/14_command_buffers.rs ++++ b/15_hello_triangle.rs +@@ -30,10 +30,11 @@ use vulkano::swapchain::{ + PresentMode, + Swapchain, + CompositeAlpha, ++ acquire_next_image + }; + use vulkano::format::Format; + use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +-use vulkano::sync::SharingMode; ++use vulkano::sync::{SharingMode, GpuFuture}; + use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, +@@ -129,7 +130,7 @@ impl HelloTriangleApplication { + + pub fn run(&mut self) { + self.init_vulkan(); +- // self.main_loop(); ++ self.main_loop(); + } + + fn init_vulkan(&mut self) { +@@ -489,6 +490,8 @@ impl HelloTriangleApplication { + #[allow(unused)] + fn main_loop(&mut self) { + loop { ++ self.draw_frame(); ++ + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { +@@ -502,6 +505,22 @@ impl HelloTriangleApplication { + } + } + ++ fn draw_frame(&mut self) { ++ let swap_chain = self.swap_chain().clone(); ++ let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); ++ ++ let queue = self.graphics_queue().clone(); ++ let command_buffer = self.command_buffers[image_index].clone(); ++ ++ let future = acquire_future ++ .then_execute(queue.clone(), command_buffer) ++ .unwrap() ++ .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) ++ .then_signal_fence_and_flush() ++ .unwrap(); ++ future.wait(None).unwrap(); ++ } ++ + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +@@ -509,6 +528,14 @@ impl HelloTriangleApplication { + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } ++ ++ fn graphics_queue(&self) -> &Arc { ++ self.graphics_queue.as_ref().unwrap() ++ } ++ ++ fn swap_chain(&self) -> &Arc> { ++ self.swap_chain.as_ref().unwrap() ++ } + } +``` +
+ +[Complete code](src/bin/15_hello_triangle.rs) ### Swapchain recreation (*TODO*) [Complete code](src/main.rs) diff --git a/src/bin/15_hello_triangle.rs b/src/bin/15_hello_triangle.rs new file mode 100644 index 0000000..7dd5351 --- /dev/null +++ b/src/bin/15_hello_triangle.rs @@ -0,0 +1,544 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, + vertex::BufferlessVertices, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::descriptor::PipelineLayoutAbstract; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +type ConcreteGraphicsPipeline = Arc, Arc>>; + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + // NOTE: We need to the full type of + // self.graphics_pipeline, because `BufferlessVertices` only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + // TODO: check if can be simplified later in tutorial + // graphics_pipeline: Option>, + graphics_pipeline: Option, + + swap_chain_framebuffers: Vec>, + + command_buffers: Vec>, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + None, // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + let vertices = BufferlessVertices { vertices: 3, instances: 1 }; + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw(graphics_pipeline.clone(), &DynamicState::none(), + vertices, (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.draw_frame(); + + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + let swap_chain = self.swap_chain().clone(); + let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); + + let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + + let future = acquire_future + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_signal_fence_and_flush() + .unwrap(); + future.wait(None).unwrap(); + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } + + fn graphics_queue(&self) -> &Arc { + self.graphics_queue.as_ref().unwrap() + } + + fn swap_chain(&self) -> &Arc> { + self.swap_chain.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From 0fa55a4551c37052c8f5cc242f26b3376585278e Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 21:31:18 +0200 Subject: [PATCH 34/78] swap chain recreation --- README.md | 133 ++++++- src/bin/16_swap_chain_recreation.rs | 593 ++++++++++++++++++++++++++++ 2 files changed, 723 insertions(+), 3 deletions(-) create mode 100644 src/bin/16_swap_chain_recreation.rs diff --git a/README.md b/README.md index 76a03c3..4b28f59 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Rust version of https://github.com/Overv/VulkanTutorial. * [Framebuffers](#framebuffers) * [Command buffers](#command-buffers) * [Rendering and presentation](#rendering-and-presentation) - * [Swapchain recreation (TODO)](#swapchain-recreation-todo) + * [Swapchain recreation](#swapchain-recreation) * [Vertex buffers (TODO)](#vertex-buffers-todo) * [Uniform buffers (TODO)](#uniform-buffers-todo) * [Texture mapping (TODO)](#texture-mapping-todo) @@ -1336,8 +1336,135 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentatio [Complete code](src/bin/15_hello_triangle.rs) -### Swapchain recreation (*TODO*) -[Complete code](src/main.rs) +### Swapchain recreation +https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation + +
+Diff + +```diff +--- a/15_hello_triangle.rs ++++ b/16_swap_chain_recreation.rs +@@ -30,11 +30,12 @@ use vulkano::swapchain::{ + PresentMode, + Swapchain, + CompositeAlpha, +- acquire_next_image ++ acquire_next_image, ++ AcquireError, + }; + use vulkano::format::Format; + use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +-use vulkano::sync::{SharingMode, GpuFuture}; ++use vulkano::sync::{self, SharingMode, GpuFuture}; + use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, +@@ -120,6 +121,9 @@ struct HelloTriangleApplication { + + command_buffers: Vec>, + ++ previous_frame_end: Option>, ++ recreate_swap_chain: bool, ++ + events_loop: Option, + } + +@@ -144,6 +148,7 @@ impl HelloTriangleApplication { + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); ++ self.create_sync_objects(); + } + + fn create_instance(&mut self) { +@@ -315,7 +320,7 @@ impl HelloTriangleApplication { + CompositeAlpha::Opaque, + present_mode, + true, // clipped +- None, // old_swapchain ++ self.swap_chain.as_ref(), // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); +@@ -425,6 +430,11 @@ impl HelloTriangleApplication { + .collect(); + } + ++ fn create_sync_objects(&mut self) { ++ self.previous_frame_end = ++ Some(Box::new(sync::now(self.device().clone())) as Box); ++ } ++ + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? +@@ -506,19 +516,58 @@ impl HelloTriangleApplication { + } + + fn draw_frame(&mut self) { ++ self.previous_frame_end.as_mut().unwrap().cleanup_finished(); ++ ++ if self.recreate_swap_chain { ++ self.recreate_swap_chain(); ++ self.recreate_swap_chain = false; ++ } ++ + let swap_chain = self.swap_chain().clone(); +- let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); ++ let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { ++ Ok(r) => r, ++ Err(AcquireError::OutOfDate) => { ++ self.recreate_swap_chain = true; ++ return; ++ }, ++ Err(err) => panic!("{:?}", err) ++ }; + + let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + +- let future = acquire_future ++ let future = self.previous_frame_end.take().unwrap() ++ .join(acquire_future) + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) +- .then_signal_fence_and_flush() +- .unwrap(); +- future.wait(None).unwrap(); ++ .then_signal_fence_and_flush(); ++ ++ match future { ++ Ok(future) => { ++ self.previous_frame_end = Some(Box::new(future) as Box<_>); ++ } ++ Err(vulkano::sync::FlushError::OutOfDate) => { ++ self.recreate_swap_chain = true; ++ self.previous_frame_end ++ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); ++ } ++ Err(e) => { ++ println!("{:?}", e); ++ self.previous_frame_end ++ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); ++ } ++ } ++ } ++ ++ fn recreate_swap_chain(&mut self) { ++ unsafe { self.device().wait().unwrap(); } ++ ++ self.create_swap_chain(); ++ self.create_render_pass(); ++ self.create_graphics_pipeline(); ++ self.create_framebuffers(); ++ self.create_command_buffers(); + } +``` +
+ +[Complete code](src/bin/16_swap_chain_recreation.rs) ## Vertex buffers (*TODO*) ## Uniform buffers (*TODO*) diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs new file mode 100644 index 0000000..98e80eb --- /dev/null +++ b/src/bin/16_swap_chain_recreation.rs @@ -0,0 +1,593 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image, + AcquireError, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{self, SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, + vertex::BufferlessVertices, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::descriptor::PipelineLayoutAbstract; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +type ConcreteGraphicsPipeline = Arc, Arc>>; + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + // NOTE: We need to the full type of + // self.graphics_pipeline, because `BufferlessVertices` only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + // TODO: check if can be simplified later in tutorial + // graphics_pipeline: Option>, + graphics_pipeline: Option, + + swap_chain_framebuffers: Vec>, + + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); + self.create_sync_objects(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + self.swap_chain.as_ref(), // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + let vertices = BufferlessVertices { vertices: 3, instances: 1 }; + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw(graphics_pipeline.clone(), &DynamicState::none(), + vertices, (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn create_sync_objects(&mut self) { + self.previous_frame_end = + Some(Box::new(sync::now(self.device().clone())) as Box); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.draw_frame(); + + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + + let swap_chain = self.swap_chain().clone(); + let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + + let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + } + } + + fn recreate_swap_chain(&mut self) { + unsafe { self.device().wait().unwrap(); } + + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } + + fn graphics_queue(&self) -> &Arc { + self.graphics_queue.as_ref().unwrap() + } + + fn swap_chain(&self) -> &Arc> { + self.swap_chain.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From 5e4c7d88814b83c628d526a62fedc1c5842a5321 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sat, 25 Aug 2018 21:49:02 +0200 Subject: [PATCH 35/78] replace main.rs with refactored version --- Cargo.toml | 3 + README.md | 2 +- src/main.rs | 324 ++++++++++++++++++++-------------------------------- 3 files changed, 128 insertions(+), 201 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f89cbda..902eef5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,6 @@ vulkano-shader-derive = "0.10.0" image = "0.19.0" vulkano-win = "0.10.0" winit = "0.17.1" + +# [[bin]] +# name = "main" diff --git a/README.md b/README.md index 4b28f59..ae3acce 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Rust version of https://github.com/Overv/VulkanTutorial. **Goal**: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs)). -**Current State**: Early, got the code up to [Swap chain recreation](https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation) (the triangle renders!), but it isn't yet (fully) split up by chapter and the notes below are incomplete. +**Current State**: The first major part, `Drawing a triangle`, is complete. --- * [Introduction](#introduction) diff --git a/src/main.rs b/src/main.rs index 0cf9304..98e80eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,22 +2,23 @@ extern crate vulkano; #[macro_use] extern crate vulkano_shader_derive; -extern crate winit; extern crate vulkano_win; +extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use std::fs::File; -use std::io::Read; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ Instance, InstanceExtensions, - layers_list, ApplicationInfo, Version, + layers_list, PhysicalDevice, - Features, + Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; use vulkano::device::{Device, DeviceExtensions, Queue}; @@ -25,43 +26,34 @@ use vulkano::swapchain::{ Surface, Capabilities, ColorSpace, - SupportedPresentModes, PresentMode, + SupportedPresentModes, + PresentMode, Swapchain, CompositeAlpha, acquire_next_image, AcquireError, }; -use vulkano::format::{Format}; -use vulkano::image::{ - ImageUsage, - swapchain::SwapchainImage -}; -use vulkano::sync; -use vulkano::sync::SharingMode; -use vulkano::command_buffer::{ - AutoCommandBuffer, - AutoCommandBufferBuilder, - DynamicState, -}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{self, SharingMode, GpuFuture}; use vulkano::pipeline::{ - shader::ShaderModule, GraphicsPipeline, vertex::BufferlessDefinition, vertex::BufferlessVertices, viewport::Viewport, }; -use vulkano::descriptor::PipelineLayoutAbstract; use vulkano::framebuffer::{ - Subpass, RenderPassAbstract, - Framebuffer, + Subpass, FramebufferAbstract, + Framebuffer, +}; +use vulkano::descriptor::PipelineLayoutAbstract; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, }; -use vulkano::sync::GpuFuture; - -use winit::WindowBuilder; -use winit::dpi::LogicalSize; -use vulkano_win::VkSurfaceBuild; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; @@ -103,7 +95,6 @@ type ConcreteGraphicsPipeline = Arc>, debug_callback: Option, - events_loop: Option, surface: Option>>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) @@ -118,7 +109,6 @@ struct HelloTriangleApplication { swap_chain_extent: Option<[u32; 2]>, render_pass: Option>, - // NOTE: We need to the full type of // self.graphics_pipeline, because `BufferlessVertices` only // works when the concrete type of the graphics pipeline is visible @@ -129,32 +119,24 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, - // command_pool: Option>, command_buffers: Vec>, previous_frame_end: Option>, recreate_swap_chain: bool, - frame_count: u32, + events_loop: Option, } + impl HelloTriangleApplication { pub fn new() -> Self { Default::default() } pub fn run(&mut self) { - // self.init_window(); self.init_vulkan(); self.main_loop(); - self.cleanup(); } - // fn init_window(&self) { - // WindowBuilder::new() - // .with_title("Vulkan") - // .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); - // } - fn init_vulkan(&mut self) { self.create_instance(); self.setup_debug_callback(); @@ -162,16 +144,9 @@ impl HelloTriangleApplication { self.pick_physical_device(); self.create_logical_device(); self.create_swap_chain(); - // NOTE: no `create_image_views` because image views are handled by - // Vulkano and can be accessed via the SwapchainImages created above self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); - - // NOTE: No self.create_command_pool() - Vulkano has a `StandardCommandPool` - // that is used automatically, but it is possible to use custom pools. - // See the vulkano::command_buffer module docs for details - self.create_command_buffers(); self.create_sync_objects(); } @@ -181,9 +156,9 @@ impl HelloTriangleApplication { println!("Validation layers requested, but not available!") } - let extensions = InstanceExtensions::supported_by_core() + let supported_extensions = InstanceExtensions::supported_by_core() .expect("failed to retrieve supported extensions"); - println!("Supported extensions: {:?}", extensions); + println!("Supported extensions: {:?}", supported_extensions); let app_info = ApplicationInfo { application_name: Some("Hello Triangle".into()), @@ -192,19 +167,35 @@ impl HelloTriangleApplication { engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), }; - let extensions = Self::get_required_extensions(); + let required_extensions = Self::get_required_extensions(); let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { - Instance::new(Some(&app_info), &extensions, None) + Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") }; self.instance = Some(instance); } + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + fn setup_debug_callback(&mut self) { if !ENABLE_VALIDATION_LAYERS { return; @@ -250,45 +241,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); - - let families = [indices.graphics_family, indices.present_family]; - use std::iter::FromIterator; - let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); - - let queue_priority = 1.0; - let queue_families = unique_queue_families.iter().map(|i| { - (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) - }); - - // NOTE: the tutorial recommends passing the validation layers as well - // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that - // for us internally. - - let (device, mut queues) = Device::new(physical_device, &Features::none(), - &device_extensions(), queue_families) - .expect("failed to create logical device!"); - - self.device = Some(device); - - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); - } - - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new().build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); - } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { self.surface.as_ref().unwrap().capabilities(*device) .expect("failed to get surface capabilities") @@ -318,18 +270,11 @@ impl HelloTriangleApplication { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { - let window = self.surface.as_ref().unwrap().window(); - let logical_size = window.get_inner_size().unwrap(); - let physcal_size = logical_size.to_physical(window.get_hidpi_factor()); - - let mut actual_extent = [physcal_size.width as u32, physcal_size.height as u32]; - - // old version for earlier tutorial chapter... - // let mut actual_extent = [WIDTH, HEIGHT]; - // actual_extent[0] = capabilities.min_image_extent[0] - // .max(capabilities.max_image_extent[0].min(actual_extent[0])); - // actual_extent[1] = capabilities.min_image_extent[1] - // .max(capabilities.max_image_extent[1].min(actual_extent[1])); + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); actual_extent } } @@ -366,7 +311,7 @@ impl HelloTriangleApplication { self.device.as_ref().unwrap().clone(), self.surface.as_ref().unwrap().clone(), image_count, - surface_format.0, // TODO!? (color space?) + surface_format.0, // TODO: color space? extent, 1, // layers image_usage, @@ -402,31 +347,55 @@ impl HelloTriangleApplication { } fn create_graphics_pipeline(&mut self) { - // NOTE: the standard vulkano way is to load shaders as GLSL at - // compile-time via macros from the vulkano_shader_derive crate. - // Loading SPIR-V at runtime like in the C++ version is partially - // implemented, but currently unused. + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/09_shader_base.vert"] + struct Dummy; + } - // let vert_shader_code = Self::read_file("src/shaders/vert.spv"); - // let frag_shader_code = Self::read_file("src/shaders/frag.spv"); - // let vert_shader_module = self.create_shader_module(&vert_shader_code); - // let frag_shader_module = self.create_shader_module(&frag_shader_code); + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/09_shader_base.frag"] + struct Dummy; + } let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) - .expect("failed to create shader module!"); + .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) - .expect("failed to create shader module!"); + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) .build(device.clone()) - .unwrap())); + .unwrap() + )); } fn create_framebuffers(&mut self) { @@ -441,17 +410,6 @@ impl HelloTriangleApplication { } fn create_command_buffers(&mut self) { - let swap_chain_extent = self.swap_chain_extent.unwrap(); - let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; - let dynamic_state = DynamicState { - viewports: Some(vec![Viewport { - origin: [0.0, 0.0], - dimensions, - depth_range: 0.0 .. 1.0, - }]), - .. DynamicState::none() - }; - let queue_family = self.graphics_queue.as_ref().unwrap().family(); let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); self.command_buffers = self.swap_chain_framebuffers.iter() @@ -461,7 +419,7 @@ impl HelloTriangleApplication { .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &dynamic_state, + .draw(graphics_pipeline.clone(), &DynamicState::none(), vertices, (), ()) .unwrap() .end_render_pass() @@ -477,22 +435,6 @@ impl HelloTriangleApplication { Some(Box::new(sync::now(self.device().clone())) as Box); } - #[allow(unused)] - fn read_file(filename: &str) -> Vec { - let mut f = File::open(filename) - .expect("failed to open file!"); - let mut buffer = vec![]; - f.read_to_end(&mut buffer).unwrap(); - buffer - } - - #[allow(unused)] - fn create_shader_module(&self, code: &[u8]) -> Arc { - unsafe { - ShaderModule::new(self.device.as_ref().unwrap().clone(), &code) - }.expect("failed to create shader module!") - } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? @@ -513,33 +455,49 @@ impl HelloTriangleApplication { indices } - fn check_validation_layer_support() -> bool { - for layer_name in VALIDATION_LAYERS.iter() { - let mut layer_found = false; - for layer_properties in layers_list().unwrap() { - if *layer_name == layer_properties.name() { - layer_found = true; - break - } - } - if !layer_found { - return false; - } - } + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - true - } + let indices = self.find_queue_families(&physical_device); - fn get_required_extensions() -> InstanceExtensions { - let mut extensions = vulkano_win::required_extensions(); - if ENABLE_VALIDATION_LAYERS { - // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano - extensions.ext_debug_report = true; - } + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); - extensions + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); } + #[allow(unused)] fn main_loop(&mut self) { loop { self.draw_frame(); @@ -547,12 +505,11 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.as_mut().unwrap().poll_events(|ev| { match ev { - winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true, + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () } }); if done { - // TODO!: vkDeviceWaitIdle(device);? return; } } @@ -601,23 +558,11 @@ impl HelloTriangleApplication { = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); } } - - self.frame_count += 1; - // print!("."); - // if (self.frame_count % 60 == 0) { - // print!("{}", self.frame_count); - // } - // use std::io::{self, Write}; - // io::stdout().flush().unwrap(); - - // self.previous_frame_end = Some(Box::new(future) as Box<_>); } fn recreate_swap_chain(&mut self) { unsafe { self.device().wait().unwrap(); } - // NOTE: no cleanup_swap_chain() required - old resources will be dropped automatically - self.create_swap_chain(); self.create_render_pass(); self.create_graphics_pipeline(); @@ -625,11 +570,6 @@ impl HelloTriangleApplication { self.create_command_buffers(); } - fn cleanup(&self) { - // TODO!: trust automatic drop and remove or use std::mem::drop here? (instance, device etc.) - // -> check with validation layers for issues with order... - } - fn instance(&self) -> &Arc { self.instance.as_ref().unwrap() } @@ -647,22 +587,6 @@ impl HelloTriangleApplication { } } -#[allow(unused)] -mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/shaders/shader.vert"] - struct Dummy; -} - -#[allow(unused)] -mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/shaders/shader.frag"] - struct Dummy; -} - fn main() { let mut app = HelloTriangleApplication::new(); app.run(); From 48eb09f4bddf7c398550011738528068f5054506 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 26 Aug 2018 10:01:46 +0200 Subject: [PATCH 36/78] Update README.md relates to #1 --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ae3acce..e965315 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # vulkan-tutorial-rs -Rust version of https://github.com/Overv/VulkanTutorial. +Rust version of https://github.com/Overv/VulkanTutorial using [Vulkano](http://vulkano.rs/). **Goal**: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs)). @@ -44,7 +44,9 @@ Rust version of https://github.com/Overv/VulkanTutorial. ## Introduction This tutorial consists of the the ported code and notes about the differences between the original C++ and the Rust code. -The [explanatory texts](https://vulkan-tutorial.com/Introduction) generally apply equally, although the Rust version is often shorter due to the use of [Vulkano](http://vulkano.rs/), a safe wrapper around the Vulkan API. +The [explanatory texts](https://vulkan-tutorial.com/Introduction) generally apply equally, although the Rust version is often shorter due to the use of [Vulkano](http://vulkano.rs/), a safe wrapper around the Vulkan API with some convencience methods (the final triangle example is about 600 lines, compared to 950 lines in C++). + +If you prefer a lower-level API closer to the Vulkan C API, have a look at [Ash](https://github.com/MaikKlein/ash) and [vulkan-tutorial-rust](https://github.com/Usami-Renko/vulkan-tutorial-rust). ## Overview https://vulkan-tutorial.com/Overview @@ -64,7 +66,7 @@ Then add this to your `Cargo.toml`: vulkano = "0.10.0" ``` -On macOS, copy [mac-env.sh](mac-env.sh), adapt the `VULKAN_SDK` if necessary and `source` the file in your terminal. See also [vulkano-rs/vulkano#macos-and-ios-setup](https://github.com/vulkano-rs/vulkano#macos-and-ios-setup). +On macOS, copy [mac-env.sh](mac-env.sh), adapt the `VULKAN_SDK` path if necessary and `source` the file in your terminal. See also [vulkano-rs/vulkano#macos-and-ios-setup](https://github.com/vulkano-rs/vulkano#macos-and-ios-setup). ## Drawing a triangle ### Setup From 2af563f4d798e0750dc7025bd6dd21afc44eb5a1 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 26 Aug 2018 18:10:08 +0200 Subject: [PATCH 37/78] readme: small fixes/improvements --- README.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index e965315..0aba408 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Rust version of https://github.com/Overv/VulkanTutorial using [Vulkano](http://v ## Introduction This tutorial consists of the the ported code and notes about the differences between the original C++ and the Rust code. -The [explanatory texts](https://vulkan-tutorial.com/Introduction) generally apply equally, although the Rust version is often shorter due to the use of [Vulkano](http://vulkano.rs/), a safe wrapper around the Vulkan API with some convencience methods (the final triangle example is about 600 lines, compared to 950 lines in C++). +The [explanatory texts](https://vulkan-tutorial.com/Introduction) generally apply equally, although the Rust version is often shorter due to the use of [Vulkano](http://vulkano.rs/), a safe wrapper around the Vulkan API with some convencience functionality (the final triangle example is about 600 lines, compared to 950 lines in C++). If you prefer a lower-level API closer to the Vulkan C API, have a look at [Ash](https://github.com/MaikKlein/ash) and [vulkan-tutorial-rust](https://github.com/Usami-Renko/vulkan-tutorial-rust). @@ -120,7 +120,7 @@ And extend your main.rs: ```rust extern crate winit; -use winit::{ WindowBuilder, dpi::LogicalSize}; +use winit::{WindowBuilder, dpi::LogicalSize}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; @@ -142,16 +142,17 @@ const HEIGHT: u32 = 600; ``` ```rust fn main_loop(&mut self) { - loop { - let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + loop { + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; } - }); - if done { - return; } } ``` @@ -162,10 +163,16 @@ const HEIGHT: u32 = 600; #### Instance https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance +Cargo.toml: +``` +vulkano-win = "0.10.0" +``` +main.rs: ```rust extern crate vulkano_win; ``` ```rust +use std::sync::Arc; use vulkano::instance::{ Instance, InstanceExtensions, @@ -409,8 +416,6 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_ + self.instance.as_ref().unwrap() + } } - - fn main() { ```
@@ -479,9 +484,6 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues + self.graphics_queue = queues.next(); + } + - #[allow(unused)] - fn main_loop(&mut self) { - loop { ```
@@ -830,7 +832,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain #### Image views https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Image_views -We're skipping this section because image because image views are handled by Vulkano and can be accessed via the SwapchainImages created in the last section. +We're skipping this section because image views are handled by Vulkano and can be accessed via the `SwapchainImage`s created in the last section. ### Graphics pipeline basics #### Introduction @@ -1476,12 +1478,11 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation ## Generating Mipmaps (*TODO*) ## Multisampling (*TODO*) ---- + From ec52f1af33c9b4d7ebb2a2fb1eadc35a7ff41123 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 26 Aug 2018 20:40:17 +0200 Subject: [PATCH 38/78] vertex buffers with immutable buffer --- Cargo.toml | 7 +++-- src/main.rs | 57 +++++++++++++++++++++++++++++------------ src/shaders/shader.vert | 24 ++++++----------- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 902eef5..ef096a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "vulkan-tutorial-rs" version = "0.1.0" authors = ["Benjamin Wasty "] +autobins = false # TODO: TMP [dependencies] vulkano = "0.10.0" @@ -10,5 +11,7 @@ image = "0.19.0" vulkano-win = "0.10.0" winit = "0.17.1" -# [[bin]] -# name = "main" +# TODO: TMP +[[bin]] +name = "main" +path = "src/main.rs" diff --git a/src/main.rs b/src/main.rs index 98e80eb..02ce9fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,8 +38,7 @@ use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; use vulkano::sync::{self, SharingMode, GpuFuture}; use vulkano::pipeline::{ GraphicsPipeline, - vertex::BufferlessDefinition, - vertex::BufferlessVertices, + GraphicsPipelineAbstract, viewport::Viewport, }; use vulkano::framebuffer::{ @@ -48,12 +47,16 @@ use vulkano::framebuffer::{ FramebufferAbstract, Framebuffer, }; -use vulkano::descriptor::PipelineLayoutAbstract; use vulkano::command_buffer::{ AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState, }; +use vulkano::buffer::{ + immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, +}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; @@ -89,7 +92,25 @@ impl QueueFamilyIndices { } } -type ConcreteGraphicsPipeline = Arc, Arc>>; +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} +impl Vertex { + fn new(pos: [f32; 2], color: [f32; 3]) -> Self { + Self { pos, color } + } +} +impl_vertex!(Vertex, pos, color); + +fn vertices() -> [Vertex; 3] { + [ + Vertex::new([0.0, -0.5], [1.0, 1.0, 1.0]), + Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), + Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.]) + ] +} #[derive(Default)] struct HelloTriangleApplication { @@ -109,16 +130,11 @@ struct HelloTriangleApplication { swap_chain_extent: Option<[u32; 2]>, render_pass: Option>, - // NOTE: We need to the full type of - // self.graphics_pipeline, because `BufferlessVertices` only - // works when the concrete type of the graphics pipeline is visible - // to the command buffer. - // TODO: check if can be simplified later in tutorial - // graphics_pipeline: Option>, - graphics_pipeline: Option, + graphics_pipeline: Option>, swap_chain_framebuffers: Vec>, + vertex_buffer: Option>, command_buffers: Vec>, previous_frame_end: Option>, @@ -147,6 +163,7 @@ impl HelloTriangleApplication { self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); + self.create_vertex_buffer(); self.create_command_buffers(); self.create_sync_objects(); } @@ -351,7 +368,7 @@ impl HelloTriangleApplication { mod vertex_shader { #[derive(VulkanoShader)] #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] + #[path = "src/shaders/shader.vert"] struct Dummy; } @@ -359,7 +376,7 @@ impl HelloTriangleApplication { mod fragment_shader { #[derive(VulkanoShader)] #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] + #[path = "src/shaders/shader.frag"] struct Dummy; } @@ -378,7 +395,7 @@ impl HelloTriangleApplication { }; self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() - .vertex_input(BufferlessDefinition {}) + .vertex_input_single_buffer::() .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() .primitive_restart(false) @@ -409,18 +426,26 @@ impl HelloTriangleApplication { ).collect::>(); } + fn create_vertex_buffer(&mut self) { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), + self.graphics_queue().clone()) + .unwrap(); + future.flush().unwrap(); + self.vertex_buffer = Some(buffer); + } + fn create_command_buffers(&mut self) { let queue_family = self.graphics_queue.as_ref().unwrap().family(); let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { - let vertices = BufferlessVertices { vertices: 3, instances: 1 }; Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() .draw(graphics_pipeline.clone(), &DynamicState::none(), - vertices, (), ()) + vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) .unwrap() .end_render_pass() .unwrap() diff --git a/src/shaders/shader.vert b/src/shaders/shader.vert index d38f815..3b48be4 100644 --- a/src/shaders/shader.vert +++ b/src/shaders/shader.vert @@ -1,25 +1,17 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable -out gl_PerVertex { - vec4 gl_Position; -}; +// NOTE: names must match the `Vertex` struct in Rust +layout(location = 0) in vec2 pos; +layout(location = 1) in vec3 color; layout(location = 0) out vec3 fragColor; -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); - -vec3 colors[3] = vec3[]( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0) -); +out gl_PerVertex { + vec4 gl_Position; +}; void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; + gl_Position = vec4(pos, 0.0, 1.0); + fragColor = color; } From 11c8e88150f965d47a6c39dd1c86b93b15a623c3 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 26 Aug 2018 21:16:30 +0200 Subject: [PATCH 39/78] vertex buffer / staging buffer --- Cargo.toml | 4 +- src/bin/17_shader_vertexbuffer.frag | 10 + src/bin/17_shader_vertexbuffer.vert | 17 + src/bin/18_vertex_buffer.rs | 614 +++++++++++++++++++++++++++ src/bin/19_staging_buffer.rs | 618 ++++++++++++++++++++++++++++ 5 files changed, 1262 insertions(+), 1 deletion(-) create mode 100644 src/bin/17_shader_vertexbuffer.frag create mode 100644 src/bin/17_shader_vertexbuffer.vert create mode 100644 src/bin/18_vertex_buffer.rs create mode 100644 src/bin/19_staging_buffer.rs diff --git a/Cargo.toml b/Cargo.toml index ef096a7..c27f75d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,6 @@ winit = "0.17.1" # TODO: TMP [[bin]] name = "main" -path = "src/main.rs" +# path = "src/main.rs" +# path = "src/bin/18_vertex_buffer.rs" +path = "src/bin/19_staging_buffer.rs" diff --git a/src/bin/17_shader_vertexbuffer.frag b/src/bin/17_shader_vertexbuffer.frag new file mode 100644 index 0000000..84daf5e --- /dev/null +++ b/src/bin/17_shader_vertexbuffer.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/src/bin/17_shader_vertexbuffer.vert b/src/bin/17_shader_vertexbuffer.vert new file mode 100644 index 0000000..3b48be4 --- /dev/null +++ b/src/bin/17_shader_vertexbuffer.vert @@ -0,0 +1,17 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +// NOTE: names must match the `Vertex` struct in Rust +layout(location = 0) in vec2 pos; +layout(location = 1) in vec3 color; + +layout(location = 0) out vec3 fragColor; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = vec4(pos, 0.0, 1.0); + fragColor = color; +} diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs new file mode 100644 index 0000000..2a3b975 --- /dev/null +++ b/src/bin/18_vertex_buffer.rs @@ -0,0 +1,614 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image, + AcquireError, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{self, SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + GraphicsPipelineAbstract, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; +use vulkano::buffer::{ + cpu_access::CpuAccessibleBuffer, + BufferUsage, + BufferAccess, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} +impl Vertex { + fn new(pos: [f32; 2], color: [f32; 3]) -> Self { + Self { pos, color } + } +} +impl_vertex!(Vertex, pos, color); + +fn vertices() -> [Vertex; 3] { + [ + Vertex::new([0.0, -0.5], [1.0, 1.0, 1.0]), + Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), + Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.]) + ] +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + graphics_pipeline: Option>, + + swap_chain_framebuffers: Vec>, + + vertex_buffer: Option>, + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_vertex_buffer(); + self.create_command_buffers(); + self.create_sync_objects(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + self.swap_chain.as_ref(), // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/17_shader_vertexbuffer.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/17_shader_vertexbuffer.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + } + + fn create_vertex_buffer(&mut self) { + self.vertex_buffer = Some(CpuAccessibleBuffer::from_iter(self.device().clone(), + BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap()); + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw(graphics_pipeline.clone(), &DynamicState::none(), + vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn create_sync_objects(&mut self) { + self.previous_frame_end = + Some(Box::new(sync::now(self.device().clone())) as Box); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.draw_frame(); + + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + + let swap_chain = self.swap_chain().clone(); + let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + + let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + } + } + + fn recreate_swap_chain(&mut self) { + unsafe { self.device().wait().unwrap(); } + + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } + + fn graphics_queue(&self) -> &Arc { + self.graphics_queue.as_ref().unwrap() + } + + fn swap_chain(&self) -> &Arc> { + self.swap_chain.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs new file mode 100644 index 0000000..67cba9a --- /dev/null +++ b/src/bin/19_staging_buffer.rs @@ -0,0 +1,618 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image, + AcquireError, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{self, SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + GraphicsPipelineAbstract, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; +use vulkano::buffer::{ + immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} +impl Vertex { + fn new(pos: [f32; 2], color: [f32; 3]) -> Self { + Self { pos, color } + } +} +impl_vertex!(Vertex, pos, color); + +fn vertices() -> [Vertex; 3] { + [ + Vertex::new([0.0, -0.5], [1.0, 1.0, 1.0]), + Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), + Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.]) + ] +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + graphics_pipeline: Option>, + + swap_chain_framebuffers: Vec>, + + vertex_buffer: Option>, + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_vertex_buffer(); + self.create_command_buffers(); + self.create_sync_objects(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + self.swap_chain.as_ref(), // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/17_shader_vertexbuffer.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/17_shader_vertexbuffer.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + } + + fn create_vertex_buffer(&mut self) { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), + self.graphics_queue().clone()) + .unwrap(); + future.flush().unwrap(); + self.vertex_buffer = Some(buffer); + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw(graphics_pipeline.clone(), &DynamicState::none(), + vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn create_sync_objects(&mut self) { + self.previous_frame_end = + Some(Box::new(sync::now(self.device().clone())) as Box); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.draw_frame(); + + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + + let swap_chain = self.swap_chain().clone(); + let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + + let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + } + } + + fn recreate_swap_chain(&mut self) { + unsafe { self.device().wait().unwrap(); } + + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } + + fn graphics_queue(&self) -> &Arc { + self.graphics_queue.as_ref().unwrap() + } + + fn swap_chain(&self) -> &Arc> { + self.swap_chain.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} From f340ff3d8ac423ffd8bb98d85c275c17055043a1 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 26 Aug 2018 21:45:47 +0200 Subject: [PATCH 40/78] index buffer --- Cargo.toml | 9 +- src/bin/20_index_buffer.rs | 636 +++++++++++++++++++++++++++++++++++++ src/main.rs | 30 +- 3 files changed, 663 insertions(+), 12 deletions(-) create mode 100644 src/bin/20_index_buffer.rs diff --git a/Cargo.toml b/Cargo.toml index c27f75d..78199ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "vulkan-tutorial-rs" version = "0.1.0" authors = ["Benjamin Wasty "] -autobins = false # TODO: TMP +autobins = true [dependencies] vulkano = "0.10.0" @@ -11,9 +11,6 @@ image = "0.19.0" vulkano-win = "0.10.0" winit = "0.17.1" -# TODO: TMP -[[bin]] -name = "main" +# [[bin]] +# name = "main" # path = "src/main.rs" -# path = "src/bin/18_vertex_buffer.rs" -path = "src/bin/19_staging_buffer.rs" diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs new file mode 100644 index 0000000..1d65a94 --- /dev/null +++ b/src/bin/20_index_buffer.rs @@ -0,0 +1,636 @@ +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; + +use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, + Features +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image, + AcquireError, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{self, SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + GraphicsPipelineAbstract, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; +use vulkano::buffer::{ + immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, + TypedBufferAccess, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} +impl Vertex { + fn new(pos: [f32; 2], color: [f32; 3]) -> Self { + Self { pos, color } + } +} +impl_vertex!(Vertex, pos, color); + +fn vertices() -> [Vertex; 4] { + [ + Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), + Vertex::new([0.5, -0.5], [0.0, 1.0, 0.0]), + Vertex::new([0.5, 0.5], [0.0, 0.0, 1.0]), + Vertex::new([-0.5, 0.5], [1.0, 1.0, 1.0]) + ] +} + +fn indices() -> [u16; 6] { + [0, 1, 2, 2, 3, 0] +} + +#[derive(Default)] +struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + surface: Option>>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, + present_queue: Option>, + + swap_chain: Option>>, + swap_chain_images: Option>>>, + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, + graphics_pipeline: Option>, + + swap_chain_framebuffers: Vec>, + + vertex_buffer: Option>, + index_buffer: Option + Send + Sync>>, + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, + + events_loop: Option, +} + +impl HelloTriangleApplication { + pub fn new() -> Self { + Default::default() + } + + pub fn run(&mut self) { + self.init_vulkan(); + self.main_loop(); + } + + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_vertex_buffer(); + self.create_index_buffer(); + self.create_command_buffers(); + self.create_sync_objects(); + } + + fn create_instance(&mut self) { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + let instance = + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + }; + self.instance = Some(instance); + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(&mut self) { + if !ENABLE_VALIDATION_LAYERS { + return; + } + + let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok(); + } + + fn pick_physical_device(&mut self) { + self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) + .position(|device| self.is_device_suitable(&device)) + .expect("failed to find a suitable GPU!"); + } + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = self.query_swap_chain_support(device); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { + self.surface.as_ref().unwrap().capabilities(*device) + .expect("failed to get surface capabilities") + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let capabilities = self.query_swap_chain_support(&physical_device); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = self.choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = self.find_queue_families(&physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + } else { + self.graphics_queue.as_ref().unwrap().into() + }; + + let (swap_chain, images) = Swapchain::new( + self.device.as_ref().unwrap().clone(), + self.surface.as_ref().unwrap().clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + self.swap_chain.as_ref(), // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); + self.swap_chain_images = Some(images); + self.swap_chain_image_format = Some(surface_format.0); + self.swap_chain_extent = Some(extent); + } + + fn create_render_pass(&mut self) { + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: self.swap_chain.as_ref().unwrap().format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap())); + } + + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[path = "src/bin/17_shader_vertexbuffer.vert"] + struct Dummy; + } + + #[allow(unused)] + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] + #[path = "src/bin/17_shader_vertexbuffer.frag"] + struct Dummy; + } + + let device = self.device.as_ref().unwrap(); + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + )); + } + + fn create_framebuffers(&mut self) { + self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>(); + } + + fn create_vertex_buffer(&mut self) { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), + self.graphics_queue().clone()) + .unwrap(); + future.flush().unwrap(); + self.vertex_buffer = Some(buffer); + } + + fn create_index_buffer(&mut self) { + let (buffer, future) = ImmutableBuffer::from_iter( + indices().iter().cloned(), BufferUsage::index_buffer(), + self.graphics_queue().clone()) + .unwrap(); + future.flush().unwrap(); + self.index_buffer = Some(buffer); + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw_indexed(graphics_pipeline.clone(), &DynamicState::none(), + vec![self.vertex_buffer.as_ref().unwrap().clone()], + self.index_buffer.as_ref().unwrap().clone(), (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn create_sync_objects(&mut self) { + self.previous_frame_end = + Some(Box::new(sync::now(self.device().clone())) as Box); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); + + let indices = self.find_queue_families(&physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); + + // TODO!: simplify + self.graphics_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); + self.present_queue = queues + .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + } + + fn create_surface(&mut self) { + self.events_loop = Some(winit::EventsLoop::new()); + self.surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) + .expect("failed to create window surface!") + .into(); + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.draw_frame(); + + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + + let swap_chain = self.swap_chain().clone(); + let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + + let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + } + } + } + + fn recreate_swap_chain(&mut self) { + unsafe { self.device().wait().unwrap(); } + + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); + } + + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } + + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } + + fn graphics_queue(&self) -> &Arc { + self.graphics_queue.as_ref().unwrap() + } + + fn swap_chain(&self) -> &Arc> { + self.swap_chain.as_ref().unwrap() + } +} + +fn main() { + let mut app = HelloTriangleApplication::new(); + app.run(); +} diff --git a/src/main.rs b/src/main.rs index 02ce9fe..5a3f856 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,7 @@ use vulkano::buffer::{ immutable::ImmutableBuffer, BufferUsage, BufferAccess, + TypedBufferAccess, }; const WIDTH: u32 = 800; @@ -104,14 +105,19 @@ impl Vertex { } impl_vertex!(Vertex, pos, color); -fn vertices() -> [Vertex; 3] { +fn vertices() -> [Vertex; 4] { [ - Vertex::new([0.0, -0.5], [1.0, 1.0, 1.0]), - Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), - Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.]) + Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), + Vertex::new([0.5, -0.5], [0.0, 1.0, 0.0]), + Vertex::new([0.5, 0.5], [0.0, 0.0, 1.0]), + Vertex::new([-0.5, 0.5], [1.0, 1.0, 1.0]) ] } +fn indices() -> [u16; 6] { + [0, 1, 2, 2, 3, 0] +} + #[derive(Default)] struct HelloTriangleApplication { instance: Option>, @@ -135,6 +141,7 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, vertex_buffer: Option>, + index_buffer: Option + Send + Sync>>, command_buffers: Vec>, previous_frame_end: Option>, @@ -164,6 +171,7 @@ impl HelloTriangleApplication { self.create_graphics_pipeline(); self.create_framebuffers(); self.create_vertex_buffer(); + self.create_index_buffer(); self.create_command_buffers(); self.create_sync_objects(); } @@ -435,6 +443,15 @@ impl HelloTriangleApplication { self.vertex_buffer = Some(buffer); } + fn create_index_buffer(&mut self) { + let (buffer, future) = ImmutableBuffer::from_iter( + indices().iter().cloned(), BufferUsage::index_buffer(), + self.graphics_queue().clone()) + .unwrap(); + future.flush().unwrap(); + self.index_buffer = Some(buffer); + } + fn create_command_buffers(&mut self) { let queue_family = self.graphics_queue.as_ref().unwrap().family(); let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); @@ -444,8 +461,9 @@ impl HelloTriangleApplication { .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &DynamicState::none(), - vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) + .draw_indexed(graphics_pipeline.clone(), &DynamicState::none(), + vec![self.vertex_buffer.as_ref().unwrap().clone()], + self.index_buffer.as_ref().unwrap().clone(), (), ()) .unwrap() .end_render_pass() .unwrap() From b59e324ab18ea754728ce088849781ca5f7b7de3 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Mon, 27 Aug 2018 22:16:43 +0200 Subject: [PATCH 41/78] add diffs as files --- .gitignore | 1 - src/bin/02_validation_layers.rs.diff | 99 ++++++++++ src/bin/03_physical_device_selection.rs.diff | 88 +++++++++ src/bin/04_logical_device.rs.diff | 58 ++++++ src/bin/05_window_surface.rs.diff | 142 ++++++++++++++ src/bin/06_swap_chain_creation.rs.diff | 176 ++++++++++++++++++ src/bin/08_graphics_pipeline.rs.diff | 21 +++ src/bin/09_shader_modules.rs.diff | 37 ++++ src/bin/10_fixed_functions.rs.diff | 52 ++++++ src/bin/11_render_passes.rs.diff | 69 +++++++ src/bin/12_graphics_pipeline_complete.rs.diff | 63 +++++++ src/bin/13_framebuffers.rs.diff | 46 +++++ src/bin/14_command_buffers.rs.diff | 67 +++++++ src/bin/15_hello_triangle.rs.diff | 71 +++++++ src/bin/16_swap_chain_recreation.rs.diff | 120 ++++++++++++ src/bin/17_shader_vertexbuffer.vert.diff | 36 ++++ src/bin/18_vertex_buffer.rs.diff | 136 ++++++++++++++ src/bin/19_staging_buffer.rs.diff | 26 +++ src/bin/20_index_buffer.rs.diff | 78 ++++++++ src/bin/diff.sh | 2 +- 20 files changed, 1386 insertions(+), 2 deletions(-) create mode 100644 src/bin/02_validation_layers.rs.diff create mode 100644 src/bin/03_physical_device_selection.rs.diff create mode 100644 src/bin/04_logical_device.rs.diff create mode 100644 src/bin/05_window_surface.rs.diff create mode 100644 src/bin/06_swap_chain_creation.rs.diff create mode 100644 src/bin/08_graphics_pipeline.rs.diff create mode 100644 src/bin/09_shader_modules.rs.diff create mode 100644 src/bin/10_fixed_functions.rs.diff create mode 100644 src/bin/11_render_passes.rs.diff create mode 100644 src/bin/12_graphics_pipeline_complete.rs.diff create mode 100644 src/bin/13_framebuffers.rs.diff create mode 100644 src/bin/14_command_buffers.rs.diff create mode 100644 src/bin/15_hello_triangle.rs.diff create mode 100644 src/bin/16_swap_chain_recreation.rs.diff create mode 100644 src/bin/17_shader_vertexbuffer.vert.diff create mode 100644 src/bin/18_vertex_buffer.rs.diff create mode 100644 src/bin/19_staging_buffer.rs.diff create mode 100644 src/bin/20_index_buffer.rs.diff diff --git a/.gitignore b/.gitignore index 87f2adb..c144c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ /target **/*.rs.bk *.spv -*.diff diff --git a/src/bin/02_validation_layers.rs.diff b/src/bin/02_validation_layers.rs.diff new file mode 100644 index 0000000..d7b096f --- /dev/null +++ b/src/bin/02_validation_layers.rs.diff @@ -0,0 +1,99 @@ +--- a/01_instance_creation.rs ++++ b/02_validation_layers.rs +@@ -10,14 +10,26 @@ use vulkano::instance::{ + InstanceExtensions, + ApplicationInfo, + Version, ++ layers_list, + }; ++use vulkano::instance::debug::{DebugCallback, MessageTypes}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; + ++const VALIDATION_LAYERS: &[&str] = &[ ++ "VK_LAYER_LUNARG_standard_validation" ++]; ++ ++#[cfg(all(debug_assertions))] ++const ENABLE_VALIDATION_LAYERS: bool = true; ++#[cfg(not(debug_assertions))] ++const ENABLE_VALIDATION_LAYERS: bool = false; ++ + #[derive(Default)] + struct HelloTriangleApplication { + instance: Option>, ++ debug_callback: Option, + + events_loop: Option, + } +@@ -45,9 +57,14 @@ impl HelloTriangleApplication { + + fn init_vulkan(&mut self) { + self.create_instance(); ++ self.setup_debug_callback(); + } + + fn create_instance(&mut self) { ++ if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { ++ println!("Validation layers requested, but not available!") ++ } ++ + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); +@@ -59,9 +76,51 @@ impl HelloTriangleApplication { + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + +- let required_extensions = vulkano_win::required_extensions(); +- self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) +- .expect("failed to create Vulkan instance")) ++ let required_extensions = Self::get_required_extensions(); ++ ++ let instance = ++ if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { ++ Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) ++ .expect("failed to create Vulkan instance") ++ } else { ++ Instance::new(Some(&app_info), &required_extensions, None) ++ .expect("failed to create Vulkan instance") ++ }; ++ self.instance = Some(instance); ++ } ++ ++ fn check_validation_layer_support() -> bool { ++ let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); ++ VALIDATION_LAYERS.iter() ++ .all(|layer_name| layers.contains(&layer_name.to_string())) ++ } ++ ++ fn get_required_extensions() -> InstanceExtensions { ++ let mut extensions = vulkano_win::required_extensions(); ++ if ENABLE_VALIDATION_LAYERS { ++ // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano ++ extensions.ext_debug_report = true; ++ } ++ ++ extensions ++ } ++ ++ fn setup_debug_callback(&mut self) { ++ if !ENABLE_VALIDATION_LAYERS { ++ return; ++ } ++ ++ let instance = self.instance.as_ref().unwrap(); ++ let msg_types = MessageTypes { ++ error: true, ++ warning: true, ++ performance_warning: true, ++ information: false, ++ debug: true, ++ }; ++ self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { ++ println!("validation layer: {:?}", msg.description); ++ }).ok(); + } + + #[allow(unused)] diff --git a/src/bin/03_physical_device_selection.rs.diff b/src/bin/03_physical_device_selection.rs.diff new file mode 100644 index 0000000..672538d --- /dev/null +++ b/src/bin/03_physical_device_selection.rs.diff @@ -0,0 +1,88 @@ +--- a/02_validation_layers.rs ++++ b/03_physical_device_selection.rs +@@ -11,6 +11,7 @@ use vulkano::instance::{ + ApplicationInfo, + Version, + layers_list, ++ PhysicalDevice, + }; + use vulkano::instance::debug::{DebugCallback, MessageTypes}; + +@@ -26,10 +27,24 @@ const ENABLE_VALIDATION_LAYERS: bool = true; + #[cfg(not(debug_assertions))] + const ENABLE_VALIDATION_LAYERS: bool = false; + ++struct QueueFamilyIndices { ++ graphics_family: i32, ++} ++impl QueueFamilyIndices { ++ fn new() -> Self { ++ Self { graphics_family: -1 } ++ } ++ ++ fn is_complete(&self) -> bool { ++ self.graphics_family >= 0 ++ } ++} ++ + #[derive(Default)] + struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, ++ physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + + events_loop: Option, + } +@@ -58,6 +73,7 @@ impl HelloTriangleApplication { + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); ++ self.pick_physical_device(); + } + + fn create_instance(&mut self) { +@@ -123,6 +139,33 @@ impl HelloTriangleApplication { + }).ok(); + } + ++ fn pick_physical_device(&mut self) { ++ self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) ++ .position(|device| self.is_device_suitable(&device)) ++ .expect("failed to find a suitable GPU!"); ++ } ++ ++ fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { ++ let indices = self.find_queue_families(device); ++ indices.is_complete() ++ } ++ ++ fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { ++ let mut indices = QueueFamilyIndices::new(); ++ // TODO: replace index with id to simplify? ++ for (i, queue_family) in device.queue_families().enumerate() { ++ if queue_family.supports_graphics() { ++ indices.graphics_family = i as i32; ++ } ++ ++ if indices.is_complete() { ++ break; ++ } ++ } ++ ++ indices ++ } ++ + #[allow(unused)] + fn main_loop(&mut self) { + loop { +@@ -138,6 +181,10 @@ impl HelloTriangleApplication { + } + } + } ++ ++ fn instance(&self) -> &Arc { ++ self.instance.as_ref().unwrap() ++ } + } + + fn main() { diff --git a/src/bin/04_logical_device.rs.diff b/src/bin/04_logical_device.rs.diff new file mode 100644 index 0000000..51abdac --- /dev/null +++ b/src/bin/04_logical_device.rs.diff @@ -0,0 +1,58 @@ +--- a/03_physical_device_selection.rs ++++ b/04_logical_device.rs +@@ -12,8 +12,10 @@ use vulkano::instance::{ + Version, + layers_list, + PhysicalDevice, ++ Features + }; + use vulkano::instance::debug::{DebugCallback, MessageTypes}; ++use vulkano::device::{Device, DeviceExtensions, Queue}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -45,6 +47,9 @@ struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) ++ device: Option>, ++ ++ graphics_queue: Option>, + + events_loop: Option, + } +@@ -74,6 +79,7 @@ impl HelloTriangleApplication { + self.create_instance(); + self.setup_debug_callback(); + self.pick_physical_device(); ++ self.create_logical_device(); + } + + fn create_instance(&mut self) { +@@ -166,6 +172,26 @@ impl HelloTriangleApplication { + indices + } + ++ fn create_logical_device(&mut self) { ++ let instance = self.instance.as_ref().unwrap(); ++ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); ++ let indices = self.find_queue_families(&physical_device); ++ let queue_family = physical_device.queue_families() ++ .nth(indices.graphics_family as usize).unwrap(); ++ let queue_priority = 1.0; ++ ++ // NOTE: the tutorial recommends passing the validation layers as well ++ // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that ++ // for us internally. ++ ++ let (device, mut queues) = Device::new(physical_device, &Features::none(), &DeviceExtensions::none(), ++ [(queue_family, queue_priority)].iter().cloned()) ++ .expect("failed to create logical device!"); ++ ++ self.device = Some(device); ++ self.graphics_queue = queues.next(); ++ } ++ + #[allow(unused)] + fn main_loop(&mut self) { + loop { diff --git a/src/bin/05_window_surface.rs.diff b/src/bin/05_window_surface.rs.diff new file mode 100644 index 0000000..be655b9 --- /dev/null +++ b/src/bin/05_window_surface.rs.diff @@ -0,0 +1,142 @@ +--- a/04_logical_device.rs ++++ b/05_window_surface.rs +@@ -3,8 +3,11 @@ extern crate vulkano_win; + extern crate winit; + + use std::sync::Arc; ++use std::collections::HashSet; + + use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; ++use vulkano_win::VkSurfaceBuild; ++ + use vulkano::instance::{ + Instance, + InstanceExtensions, +@@ -16,6 +19,9 @@ use vulkano::instance::{ + }; + use vulkano::instance::debug::{DebugCallback, MessageTypes}; + use vulkano::device::{Device, DeviceExtensions, Queue}; ++use vulkano::swapchain::{ ++ Surface, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -31,14 +37,15 @@ const ENABLE_VALIDATION_LAYERS: bool = false; + + struct QueueFamilyIndices { + graphics_family: i32, ++ present_family: i32, + } + impl QueueFamilyIndices { + fn new() -> Self { +- Self { graphics_family: -1 } ++ Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { +- self.graphics_family >= 0 ++ self.graphics_family >= 0 && self.present_family >= 0 + } + } + +@@ -46,10 +53,13 @@ impl QueueFamilyIndices { + struct HelloTriangleApplication { + instance: Option>, + debug_callback: Option, ++ surface: Option>>, ++ + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Option>, + + graphics_queue: Option>, ++ present_queue: Option>, + + events_loop: Option, + } +@@ -60,24 +70,14 @@ impl HelloTriangleApplication { + } + + pub fn run(&mut self) { +- self.init_window(); + self.init_vulkan(); + // self.main_loop(); + } + +- fn init_window(&mut self) { +- self.events_loop = Some(winit::EventsLoop::new()); +- // We'll leave this and the main loop commented out until we actually +- // have something to show on screen. +- let _window_builder = WindowBuilder::new() +- .with_title("Vulkan") +- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); +- // .build(&self.events_loop.as_ref().unwrap()); +- } +- + fn init_vulkan(&mut self) { + self.create_instance(); + self.setup_debug_callback(); ++ self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); + } +@@ -164,6 +164,10 @@ impl HelloTriangleApplication { + indices.graphics_family = i as i32; + } + ++ if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { ++ indices.present_family = i as i32; ++ } ++ + if indices.is_complete() { + break; + } +@@ -175,21 +179,43 @@ impl HelloTriangleApplication { + fn create_logical_device(&mut self) { + let instance = self.instance.as_ref().unwrap(); + let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); ++ + let indices = self.find_queue_families(&physical_device); +- let queue_family = physical_device.queue_families() +- .nth(indices.graphics_family as usize).unwrap(); ++ ++ let families = [indices.graphics_family, indices.present_family]; ++ use std::iter::FromIterator; ++ let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); ++ + let queue_priority = 1.0; ++ let queue_families = unique_queue_families.iter().map(|i| { ++ (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) ++ }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + +- let (device, mut queues) = Device::new(physical_device, &Features::none(), &DeviceExtensions::none(), +- [(queue_family, queue_priority)].iter().cloned()) ++ let (device, mut queues) = Device::new(physical_device, &Features::none(), ++ &DeviceExtensions::none(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); +- self.graphics_queue = queues.next(); ++ ++ // TODO!: simplify ++ self.graphics_queue = queues ++ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); ++ self.present_queue = queues ++ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); ++ } ++ ++ fn create_surface(&mut self) { ++ self.events_loop = Some(winit::EventsLoop::new()); ++ self.surface = WindowBuilder::new() ++ .with_title("Vulkan") ++ .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) ++ .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) ++ .expect("failed to create window surface!") ++ .into(); + } + + #[allow(unused)] diff --git a/src/bin/06_swap_chain_creation.rs.diff b/src/bin/06_swap_chain_creation.rs.diff new file mode 100644 index 0000000..4eea71f --- /dev/null +++ b/src/bin/06_swap_chain_creation.rs.diff @@ -0,0 +1,176 @@ +--- a/05_window_surface.rs ++++ b/06_swap_chain_creation.rs +@@ -21,7 +21,16 @@ use vulkano::instance::debug::{DebugCallback, MessageTypes}; + use vulkano::device::{Device, DeviceExtensions, Queue}; + use vulkano::swapchain::{ + Surface, ++ Capabilities, ++ ColorSpace, ++ SupportedPresentModes, ++ PresentMode, ++ Swapchain, ++ CompositeAlpha, + }; ++use vulkano::format::Format; ++use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; ++use vulkano::sync::SharingMode; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -30,6 +39,14 @@ const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" + ]; + ++/// Required device extensions ++fn device_extensions() -> DeviceExtensions { ++ DeviceExtensions { ++ khr_swapchain: true, ++ .. vulkano::device::DeviceExtensions::none() ++ } ++} ++ + #[cfg(all(debug_assertions))] + const ENABLE_VALIDATION_LAYERS: bool = true; + #[cfg(not(debug_assertions))] +@@ -61,6 +78,11 @@ struct HelloTriangleApplication { + graphics_queue: Option>, + present_queue: Option>, + ++ swap_chain: Option>>, ++ swap_chain_images: Option>>>, ++ swap_chain_image_format: Option, ++ swap_chain_extent: Option<[u32; 2]>, ++ + events_loop: Option, + } + +@@ -80,6 +102,7 @@ impl HelloTriangleApplication { + self.create_surface(); + self.pick_physical_device(); + self.create_logical_device(); ++ self.create_swap_chain(); + } + + fn create_instance(&mut self) { +@@ -153,7 +176,111 @@ impl HelloTriangleApplication { + + fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { + let indices = self.find_queue_families(device); +- indices.is_complete() ++ let extensions_supported = Self::check_device_extension_support(device); ++ ++ let swap_chain_adequate = if extensions_supported { ++ let capabilities = self.query_swap_chain_support(device); ++ !capabilities.supported_formats.is_empty() && ++ capabilities.present_modes.iter().next().is_some() ++ } else { ++ false ++ }; ++ ++ indices.is_complete() && extensions_supported && swap_chain_adequate ++ } ++ ++ fn check_device_extension_support(device: &PhysicalDevice) -> bool { ++ let available_extensions = DeviceExtensions::supported_by_device(*device); ++ let device_extensions = device_extensions(); ++ available_extensions.intersection(&device_extensions) == device_extensions ++ } ++ ++ fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { ++ self.surface.as_ref().unwrap().capabilities(*device) ++ .expect("failed to get surface capabilities") ++ } ++ ++ fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { ++ // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be ++ // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) ++ *available_formats.iter() ++ .find(|(format, color_space)| ++ *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear ++ ) ++ .unwrap_or_else(|| &available_formats[0]) ++ } ++ ++ fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { ++ if available_present_modes.mailbox { ++ PresentMode::Mailbox ++ } else if available_present_modes.immediate { ++ PresentMode::Immediate ++ } else { ++ PresentMode::Fifo ++ } ++ } ++ ++ fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { ++ if let Some(current_extent) = capabilities.current_extent { ++ return current_extent ++ } else { ++ let mut actual_extent = [WIDTH, HEIGHT]; ++ actual_extent[0] = capabilities.min_image_extent[0] ++ .max(capabilities.max_image_extent[0].min(actual_extent[0])); ++ actual_extent[1] = capabilities.min_image_extent[1] ++ .max(capabilities.max_image_extent[1].min(actual_extent[1])); ++ actual_extent ++ } ++ } ++ ++ fn create_swap_chain(&mut self) { ++ let instance = self.instance.as_ref().unwrap(); ++ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); ++ ++ let capabilities = self.query_swap_chain_support(&physical_device); ++ ++ let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); ++ let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); ++ let extent = self.choose_swap_extent(&capabilities); ++ ++ let mut image_count = capabilities.min_image_count + 1; ++ if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { ++ image_count = capabilities.max_image_count.unwrap(); ++ } ++ ++ let image_usage = ImageUsage { ++ color_attachment: true, ++ .. ImageUsage::none() ++ }; ++ ++ let indices = self.find_queue_families(&physical_device); ++ ++ let sharing: SharingMode = if indices.graphics_family != indices.present_family { ++ vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() ++ } else { ++ self.graphics_queue.as_ref().unwrap().into() ++ }; ++ ++ let (swap_chain, images) = Swapchain::new( ++ self.device.as_ref().unwrap().clone(), ++ self.surface.as_ref().unwrap().clone(), ++ image_count, ++ surface_format.0, // TODO: color space? ++ extent, ++ 1, // layers ++ image_usage, ++ sharing, ++ capabilities.current_transform, ++ CompositeAlpha::Opaque, ++ present_mode, ++ true, // clipped ++ None, // old_swapchain ++ ).expect("failed to create swap chain!"); ++ ++ self.swap_chain = Some(swap_chain); ++ self.swap_chain_images = Some(images); ++ self.swap_chain_image_format = Some(surface_format.0); ++ self.swap_chain_extent = Some(extent); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { +@@ -196,7 +323,7 @@ impl HelloTriangleApplication { + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), +- &DeviceExtensions::none(), queue_families) ++ &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + self.device = Some(device); diff --git a/src/bin/08_graphics_pipeline.rs.diff b/src/bin/08_graphics_pipeline.rs.diff new file mode 100644 index 0000000..2f053e8 --- /dev/null +++ b/src/bin/08_graphics_pipeline.rs.diff @@ -0,0 +1,21 @@ +--- a/06_swap_chain_creation.rs ++++ b/08_graphics_pipeline.rs +@@ -103,6 +103,7 @@ impl HelloTriangleApplication { + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); ++ self.create_graphics_pipeline(); + } + + fn create_instance(&mut self) { +@@ -283,6 +284,10 @@ impl HelloTriangleApplication { + self.swap_chain_extent = Some(extent); + } + ++ fn create_graphics_pipeline(&mut self) { ++ ++ } ++ + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? diff --git a/src/bin/09_shader_modules.rs.diff b/src/bin/09_shader_modules.rs.diff new file mode 100644 index 0000000..f1bb759 --- /dev/null +++ b/src/bin/09_shader_modules.rs.diff @@ -0,0 +1,37 @@ +--- a/08_graphics_pipeline.rs ++++ b/09_shader_modules.rs +@@ -1,4 +1,6 @@ + extern crate vulkano; ++#[macro_use] ++extern crate vulkano_shader_derive; + extern crate vulkano_win; + extern crate winit; + +@@ -285,7 +287,27 @@ impl HelloTriangleApplication { + } + + fn create_graphics_pipeline(&mut self) { ++ #[allow(unused)] ++ mod vertex_shader { ++ #[derive(VulkanoShader)] ++ #[ty = "vertex"] ++ #[path = "src/bin/09_shader_base.vert"] ++ struct Dummy; ++ } ++ ++ #[allow(unused)] ++ mod fragment_shader { ++ #[derive(VulkanoShader)] ++ #[ty = "fragment"] ++ #[path = "src/bin/09_shader_base.frag"] ++ struct Dummy; ++ } + ++ let device = self.device.as_ref().unwrap(); ++ let _vert_shader_module = vertex_shader::Shader::load(device.clone()) ++ .expect("failed to create vertex shader module!"); ++ let _frag_shader_module = fragment_shader::Shader::load(device.clone()) ++ .expect("failed to create fragment shader module!"); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { diff --git a/src/bin/10_fixed_functions.rs.diff b/src/bin/10_fixed_functions.rs.diff new file mode 100644 index 0000000..3f2dd69 --- /dev/null +++ b/src/bin/10_fixed_functions.rs.diff @@ -0,0 +1,52 @@ +--- a/09_shader_modules.rs ++++ b/10_fixed_functions.rs +@@ -33,6 +33,11 @@ use vulkano::swapchain::{ + use vulkano::format::Format; + use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; + use vulkano::sync::SharingMode; ++use vulkano::pipeline::{ ++ GraphicsPipeline, ++ vertex::BufferlessDefinition, ++ viewport::Viewport, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -304,10 +309,35 @@ impl HelloTriangleApplication { + } + + let device = self.device.as_ref().unwrap(); +- let _vert_shader_module = vertex_shader::Shader::load(device.clone()) ++ let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); +- let _frag_shader_module = fragment_shader::Shader::load(device.clone()) ++ let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); ++ ++ let swap_chain_extent = self.swap_chain_extent.unwrap(); ++ let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; ++ let viewport = Viewport { ++ origin: [0.0, 0.0], ++ dimensions, ++ depth_range: 0.0 .. 1.0, ++ }; ++ ++ let _pipeline_builder = Arc::new(GraphicsPipeline::start() ++ .vertex_input(BufferlessDefinition {}) ++ .vertex_shader(vert_shader_module.main_entry_point(), ()) ++ .triangle_list() ++ .primitive_restart(false) ++ .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport ++ .depth_clamp(false) ++ // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... ++ .polygon_mode_fill() // = default ++ .line_width(1.0) // = default ++ .cull_mode_back() ++ .front_face_clockwise() ++ // NOTE: no depth_bias here, but on pipeline::raster::Rasterization ++ .blend_pass_through() // = default ++ .fragment_shader(frag_shader_module.main_entry_point(), ()) ++ ); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { diff --git a/src/bin/11_render_passes.rs.diff b/src/bin/11_render_passes.rs.diff new file mode 100644 index 0000000..0939604 --- /dev/null +++ b/src/bin/11_render_passes.rs.diff @@ -0,0 +1,69 @@ +--- a/10_fixed_functions.rs ++++ b/11_render_passes.rs +@@ -1,3 +1,4 @@ ++#[macro_use] + extern crate vulkano; + #[macro_use] + extern crate vulkano_shader_derive; +@@ -38,6 +39,9 @@ use vulkano::pipeline::{ + vertex::BufferlessDefinition, + viewport::Viewport, + }; ++use vulkano::framebuffer::{ ++ RenderPassAbstract, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -90,6 +94,8 @@ struct HelloTriangleApplication { + swap_chain_image_format: Option, + swap_chain_extent: Option<[u32; 2]>, + ++ render_pass: Option>, ++ + events_loop: Option, + } + +@@ -110,6 +116,7 @@ impl HelloTriangleApplication { + self.pick_physical_device(); + self.create_logical_device(); + self.create_swap_chain(); ++ self.create_render_pass(); + self.create_graphics_pipeline(); + } + +@@ -291,6 +298,23 @@ impl HelloTriangleApplication { + self.swap_chain_extent = Some(extent); + } + ++ fn create_render_pass(&mut self) { ++ self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), ++ attachments: { ++ color: { ++ load: Clear, ++ store: Store, ++ format: self.swap_chain.as_ref().unwrap().format(), ++ samples: 1, ++ } ++ }, ++ pass: { ++ color: [color], ++ depth_stencil: {} ++ } ++ ).unwrap())); ++ } ++ + fn create_graphics_pipeline(&mut self) { + #[allow(unused)] + mod vertex_shader { +@@ -421,6 +445,10 @@ impl HelloTriangleApplication { + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } ++ ++ fn device(&self) -> &Arc { ++ self.device.as_ref().unwrap() ++ } + } + + fn main() { diff --git a/src/bin/12_graphics_pipeline_complete.rs.diff b/src/bin/12_graphics_pipeline_complete.rs.diff new file mode 100644 index 0000000..e997fb2 --- /dev/null +++ b/src/bin/12_graphics_pipeline_complete.rs.diff @@ -0,0 +1,63 @@ +--- a/11_render_passes.rs ++++ b/12_graphics_pipeline_complete.rs +@@ -41,7 +41,9 @@ use vulkano::pipeline::{ + }; + use vulkano::framebuffer::{ + RenderPassAbstract, ++ Subpass, + }; ++use vulkano::descriptor::PipelineLayoutAbstract; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -77,6 +79,8 @@ impl QueueFamilyIndices { + } + } + ++type ConcreteGraphicsPipeline = Arc, Arc>>; ++ + #[derive(Default)] + struct HelloTriangleApplication { + instance: Option>, +@@ -95,6 +99,13 @@ struct HelloTriangleApplication { + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, ++ // NOTE: We need to the full type of ++ // self.graphics_pipeline, because `BufferlessVertices` only ++ // works when the concrete type of the graphics pipeline is visible ++ // to the command buffer. ++ // TODO: check if can be simplified later in tutorial ++ // graphics_pipeline: Option>, ++ graphics_pipeline: Option, + + events_loop: Option, + } +@@ -346,12 +357,13 @@ impl HelloTriangleApplication { + depth_range: 0.0 .. 1.0, + }; + +- let _pipeline_builder = Arc::new(GraphicsPipeline::start() ++ self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport ++ .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default +@@ -360,8 +372,10 @@ impl HelloTriangleApplication { + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default +- .fragment_shader(frag_shader_module.main_entry_point(), ()) +- ); ++ .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) ++ .build(device.clone()) ++ .unwrap() ++ )); + } + + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { diff --git a/src/bin/13_framebuffers.rs.diff b/src/bin/13_framebuffers.rs.diff new file mode 100644 index 0000000..0de266a --- /dev/null +++ b/src/bin/13_framebuffers.rs.diff @@ -0,0 +1,46 @@ +--- a/12_graphics_pipeline_complete.rs ++++ b/13_framebuffers.rs +@@ -42,6 +42,8 @@ use vulkano::pipeline::{ + use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, ++ FramebufferAbstract, ++ Framebuffer, + }; + use vulkano::descriptor::PipelineLayoutAbstract; + +@@ -107,6 +109,8 @@ struct HelloTriangleApplication { + // graphics_pipeline: Option>, + graphics_pipeline: Option, + ++ swap_chain_framebuffers: Vec>, ++ + events_loop: Option, + } + +@@ -129,6 +133,7 @@ impl HelloTriangleApplication { + self.create_swap_chain(); + self.create_render_pass(); + self.create_graphics_pipeline(); ++ self.create_framebuffers(); + } + + fn create_instance(&mut self) { +@@ -378,6 +383,17 @@ impl HelloTriangleApplication { + )); + } + ++ fn create_framebuffers(&mut self) { ++ self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() ++ .map(|image| { ++ let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) ++ .add(image.clone()).unwrap() ++ .build().unwrap()); ++ fba ++ } ++ ).collect::>(); ++ } ++ + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? diff --git a/src/bin/14_command_buffers.rs.diff b/src/bin/14_command_buffers.rs.diff new file mode 100644 index 0000000..a552a16 --- /dev/null +++ b/src/bin/14_command_buffers.rs.diff @@ -0,0 +1,67 @@ +--- a/13_framebuffers.rs ++++ b/14_command_buffers.rs +@@ -37,6 +37,7 @@ use vulkano::sync::SharingMode; + use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, ++ vertex::BufferlessVertices, + viewport::Viewport, + }; + use vulkano::framebuffer::{ +@@ -46,6 +47,11 @@ use vulkano::framebuffer::{ + Framebuffer, + }; + use vulkano::descriptor::PipelineLayoutAbstract; ++use vulkano::command_buffer::{ ++ AutoCommandBuffer, ++ AutoCommandBufferBuilder, ++ DynamicState, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -111,6 +117,8 @@ struct HelloTriangleApplication { + + swap_chain_framebuffers: Vec>, + ++ command_buffers: Vec>, ++ + events_loop: Option, + } + +@@ -134,6 +142,7 @@ impl HelloTriangleApplication { + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); ++ self.create_command_buffers(); + } + + fn create_instance(&mut self) { +@@ -394,6 +403,27 @@ impl HelloTriangleApplication { + ).collect::>(); + } + ++ fn create_command_buffers(&mut self) { ++ let queue_family = self.graphics_queue.as_ref().unwrap().family(); ++ let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); ++ self.command_buffers = self.swap_chain_framebuffers.iter() ++ .map(|framebuffer| { ++ let vertices = BufferlessVertices { vertices: 3, instances: 1 }; ++ Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) ++ .unwrap() ++ .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) ++ .unwrap() ++ .draw(graphics_pipeline.clone(), &DynamicState::none(), ++ vertices, (), ()) ++ .unwrap() ++ .end_render_pass() ++ .unwrap() ++ .build() ++ .unwrap()) ++ }) ++ .collect(); ++ } ++ + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? diff --git a/src/bin/15_hello_triangle.rs.diff b/src/bin/15_hello_triangle.rs.diff new file mode 100644 index 0000000..ff796b7 --- /dev/null +++ b/src/bin/15_hello_triangle.rs.diff @@ -0,0 +1,71 @@ +--- a/14_command_buffers.rs ++++ b/15_hello_triangle.rs +@@ -30,10 +30,11 @@ use vulkano::swapchain::{ + PresentMode, + Swapchain, + CompositeAlpha, ++ acquire_next_image + }; + use vulkano::format::Format; + use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +-use vulkano::sync::SharingMode; ++use vulkano::sync::{SharingMode, GpuFuture}; + use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, +@@ -129,7 +130,7 @@ impl HelloTriangleApplication { + + pub fn run(&mut self) { + self.init_vulkan(); +- // self.main_loop(); ++ self.main_loop(); + } + + fn init_vulkan(&mut self) { +@@ -489,6 +490,8 @@ impl HelloTriangleApplication { + #[allow(unused)] + fn main_loop(&mut self) { + loop { ++ self.draw_frame(); ++ + let mut done = false; + self.events_loop.as_mut().unwrap().poll_events(|ev| { + match ev { +@@ -502,6 +505,22 @@ impl HelloTriangleApplication { + } + } + ++ fn draw_frame(&mut self) { ++ let swap_chain = self.swap_chain().clone(); ++ let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); ++ ++ let queue = self.graphics_queue().clone(); ++ let command_buffer = self.command_buffers[image_index].clone(); ++ ++ let future = acquire_future ++ .then_execute(queue.clone(), command_buffer) ++ .unwrap() ++ .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) ++ .then_signal_fence_and_flush() ++ .unwrap(); ++ future.wait(None).unwrap(); ++ } ++ + fn instance(&self) -> &Arc { + self.instance.as_ref().unwrap() + } +@@ -509,6 +528,14 @@ impl HelloTriangleApplication { + fn device(&self) -> &Arc { + self.device.as_ref().unwrap() + } ++ ++ fn graphics_queue(&self) -> &Arc { ++ self.graphics_queue.as_ref().unwrap() ++ } ++ ++ fn swap_chain(&self) -> &Arc> { ++ self.swap_chain.as_ref().unwrap() ++ } + } + + fn main() { diff --git a/src/bin/16_swap_chain_recreation.rs.diff b/src/bin/16_swap_chain_recreation.rs.diff new file mode 100644 index 0000000..4da6774 --- /dev/null +++ b/src/bin/16_swap_chain_recreation.rs.diff @@ -0,0 +1,120 @@ +--- a/15_hello_triangle.rs ++++ b/16_swap_chain_recreation.rs +@@ -30,11 +30,12 @@ use vulkano::swapchain::{ + PresentMode, + Swapchain, + CompositeAlpha, +- acquire_next_image ++ acquire_next_image, ++ AcquireError, + }; + use vulkano::format::Format; + use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +-use vulkano::sync::{SharingMode, GpuFuture}; ++use vulkano::sync::{self, SharingMode, GpuFuture}; + use vulkano::pipeline::{ + GraphicsPipeline, + vertex::BufferlessDefinition, +@@ -120,6 +121,9 @@ struct HelloTriangleApplication { + + command_buffers: Vec>, + ++ previous_frame_end: Option>, ++ recreate_swap_chain: bool, ++ + events_loop: Option, + } + +@@ -144,6 +148,7 @@ impl HelloTriangleApplication { + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_command_buffers(); ++ self.create_sync_objects(); + } + + fn create_instance(&mut self) { +@@ -315,7 +320,7 @@ impl HelloTriangleApplication { + CompositeAlpha::Opaque, + present_mode, + true, // clipped +- None, // old_swapchain ++ self.swap_chain.as_ref(), // old_swapchain + ).expect("failed to create swap chain!"); + + self.swap_chain = Some(swap_chain); +@@ -425,6 +430,11 @@ impl HelloTriangleApplication { + .collect(); + } + ++ fn create_sync_objects(&mut self) { ++ self.previous_frame_end = ++ Some(Box::new(sync::now(self.device().clone())) as Box); ++ } ++ + fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? +@@ -506,19 +516,58 @@ impl HelloTriangleApplication { + } + + fn draw_frame(&mut self) { ++ self.previous_frame_end.as_mut().unwrap().cleanup_finished(); ++ ++ if self.recreate_swap_chain { ++ self.recreate_swap_chain(); ++ self.recreate_swap_chain = false; ++ } ++ + let swap_chain = self.swap_chain().clone(); +- let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); ++ let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { ++ Ok(r) => r, ++ Err(AcquireError::OutOfDate) => { ++ self.recreate_swap_chain = true; ++ return; ++ }, ++ Err(err) => panic!("{:?}", err) ++ }; + + let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + +- let future = acquire_future ++ let future = self.previous_frame_end.take().unwrap() ++ .join(acquire_future) + .then_execute(queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) +- .then_signal_fence_and_flush() +- .unwrap(); +- future.wait(None).unwrap(); ++ .then_signal_fence_and_flush(); ++ ++ match future { ++ Ok(future) => { ++ self.previous_frame_end = Some(Box::new(future) as Box<_>); ++ } ++ Err(vulkano::sync::FlushError::OutOfDate) => { ++ self.recreate_swap_chain = true; ++ self.previous_frame_end ++ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); ++ } ++ Err(e) => { ++ println!("{:?}", e); ++ self.previous_frame_end ++ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); ++ } ++ } ++ } ++ ++ fn recreate_swap_chain(&mut self) { ++ unsafe { self.device().wait().unwrap(); } ++ ++ self.create_swap_chain(); ++ self.create_render_pass(); ++ self.create_graphics_pipeline(); ++ self.create_framebuffers(); ++ self.create_command_buffers(); + } + + fn instance(&self) -> &Arc { diff --git a/src/bin/17_shader_vertexbuffer.vert.diff b/src/bin/17_shader_vertexbuffer.vert.diff new file mode 100644 index 0000000..c0150dc --- /dev/null +++ b/src/bin/17_shader_vertexbuffer.vert.diff @@ -0,0 +1,36 @@ +--- a/09_shader_base.vert ++++ b/17_shader_vertexbuffer.vert +@@ -1,25 +1,17 @@ + #version 450 + #extension GL_ARB_separate_shader_objects : enable + +-out gl_PerVertex { +- vec4 gl_Position; +-}; ++// NOTE: names must match the `Vertex` struct in Rust ++layout(location = 0) in vec2 pos; ++layout(location = 1) in vec3 color; + + layout(location = 0) out vec3 fragColor; + +-vec2 positions[3] = vec2[]( +- vec2(0.0, -0.5), +- vec2(0.5, 0.5), +- vec2(-0.5, 0.5) +-); +- +-vec3 colors[3] = vec3[]( +- vec3(1.0, 0.0, 0.0), +- vec3(0.0, 1.0, 0.0), +- vec3(0.0, 0.0, 1.0) +-); ++out gl_PerVertex { ++ vec4 gl_Position; ++}; + + void main() { +- gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); +- fragColor = colors[gl_VertexIndex]; ++ gl_Position = vec4(pos, 0.0, 1.0); ++ fragColor = color; + } diff --git a/src/bin/18_vertex_buffer.rs.diff b/src/bin/18_vertex_buffer.rs.diff new file mode 100644 index 0000000..8832b54 --- /dev/null +++ b/src/bin/18_vertex_buffer.rs.diff @@ -0,0 +1,136 @@ +--- a/16_swap_chain_recreation.rs ++++ b/18_vertex_buffer.rs +@@ -38,8 +38,7 @@ use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; + use vulkano::sync::{self, SharingMode, GpuFuture}; + use vulkano::pipeline::{ + GraphicsPipeline, +- vertex::BufferlessDefinition, +- vertex::BufferlessVertices, ++ GraphicsPipelineAbstract, + viewport::Viewport, + }; + use vulkano::framebuffer::{ +@@ -48,12 +47,16 @@ use vulkano::framebuffer::{ + FramebufferAbstract, + Framebuffer, + }; +-use vulkano::descriptor::PipelineLayoutAbstract; + use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, + }; ++use vulkano::buffer::{ ++ cpu_access::CpuAccessibleBuffer, ++ BufferUsage, ++ BufferAccess, ++}; + + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; +@@ -89,7 +92,25 @@ impl QueueFamilyIndices { + } + } + +-type ConcreteGraphicsPipeline = Arc, Arc>>; ++#[derive(Copy, Clone)] ++struct Vertex { ++ pos: [f32; 2], ++ color: [f32; 3], ++} ++impl Vertex { ++ fn new(pos: [f32; 2], color: [f32; 3]) -> Self { ++ Self { pos, color } ++ } ++} ++impl_vertex!(Vertex, pos, color); ++ ++fn vertices() -> [Vertex; 3] { ++ [ ++ Vertex::new([0.0, -0.5], [1.0, 1.0, 1.0]), ++ Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), ++ Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.]) ++ ] ++} + + #[derive(Default)] + struct HelloTriangleApplication { +@@ -109,16 +130,11 @@ struct HelloTriangleApplication { + swap_chain_extent: Option<[u32; 2]>, + + render_pass: Option>, +- // NOTE: We need to the full type of +- // self.graphics_pipeline, because `BufferlessVertices` only +- // works when the concrete type of the graphics pipeline is visible +- // to the command buffer. +- // TODO: check if can be simplified later in tutorial +- // graphics_pipeline: Option>, +- graphics_pipeline: Option, ++ graphics_pipeline: Option>, + + swap_chain_framebuffers: Vec>, + ++ vertex_buffer: Option>, + command_buffers: Vec>, + + previous_frame_end: Option>, +@@ -147,6 +163,7 @@ impl HelloTriangleApplication { + self.create_render_pass(); + self.create_graphics_pipeline(); + self.create_framebuffers(); ++ self.create_vertex_buffer(); + self.create_command_buffers(); + self.create_sync_objects(); + } +@@ -351,7 +368,7 @@ impl HelloTriangleApplication { + mod vertex_shader { + #[derive(VulkanoShader)] + #[ty = "vertex"] +- #[path = "src/bin/09_shader_base.vert"] ++ #[path = "src/bin/17_shader_vertexbuffer.vert"] + struct Dummy; + } + +@@ -359,7 +376,7 @@ impl HelloTriangleApplication { + mod fragment_shader { + #[derive(VulkanoShader)] + #[ty = "fragment"] +- #[path = "src/bin/09_shader_base.frag"] ++ #[path = "src/bin/17_shader_vertexbuffer.frag"] + struct Dummy; + } + +@@ -378,7 +395,7 @@ impl HelloTriangleApplication { + }; + + self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() +- .vertex_input(BufferlessDefinition {}) ++ .vertex_input_single_buffer::() + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) +@@ -409,18 +426,22 @@ impl HelloTriangleApplication { + ).collect::>(); + } + ++ fn create_vertex_buffer(&mut self) { ++ self.vertex_buffer = Some(CpuAccessibleBuffer::from_iter(self.device().clone(), ++ BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap()); ++ } ++ + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { +- let vertices = BufferlessVertices { vertices: 3, instances: 1 }; + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw(graphics_pipeline.clone(), &DynamicState::none(), +- vertices, (), ()) ++ vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) + .unwrap() + .end_render_pass() + .unwrap() diff --git a/src/bin/19_staging_buffer.rs.diff b/src/bin/19_staging_buffer.rs.diff new file mode 100644 index 0000000..8aad681 --- /dev/null +++ b/src/bin/19_staging_buffer.rs.diff @@ -0,0 +1,26 @@ +--- a/18_vertex_buffer.rs ++++ b/19_staging_buffer.rs +@@ -53,7 +53,7 @@ use vulkano::command_buffer::{ + DynamicState, + }; + use vulkano::buffer::{ +- cpu_access::CpuAccessibleBuffer, ++ immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, + }; +@@ -427,8 +427,12 @@ impl HelloTriangleApplication { + } + + fn create_vertex_buffer(&mut self) { +- self.vertex_buffer = Some(CpuAccessibleBuffer::from_iter(self.device().clone(), +- BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap()); ++ let (buffer, future) = ImmutableBuffer::from_iter( ++ vertices().iter().cloned(), BufferUsage::vertex_buffer(), ++ self.graphics_queue().clone()) ++ .unwrap(); ++ future.flush().unwrap(); ++ self.vertex_buffer = Some(buffer); + } + + fn create_command_buffers(&mut self) { diff --git a/src/bin/20_index_buffer.rs.diff b/src/bin/20_index_buffer.rs.diff new file mode 100644 index 0000000..7da6eff --- /dev/null +++ b/src/bin/20_index_buffer.rs.diff @@ -0,0 +1,78 @@ +--- a/19_staging_buffer.rs ++++ b/20_index_buffer.rs +@@ -56,6 +56,7 @@ use vulkano::buffer::{ + immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, ++ TypedBufferAccess, + }; + + const WIDTH: u32 = 800; +@@ -104,14 +105,19 @@ impl Vertex { + } + impl_vertex!(Vertex, pos, color); + +-fn vertices() -> [Vertex; 3] { ++fn vertices() -> [Vertex; 4] { + [ +- Vertex::new([0.0, -0.5], [1.0, 1.0, 1.0]), +- Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), +- Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.]) ++ Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), ++ Vertex::new([0.5, -0.5], [0.0, 1.0, 0.0]), ++ Vertex::new([0.5, 0.5], [0.0, 0.0, 1.0]), ++ Vertex::new([-0.5, 0.5], [1.0, 1.0, 1.0]) + ] + } + ++fn indices() -> [u16; 6] { ++ [0, 1, 2, 2, 3, 0] ++} ++ + #[derive(Default)] + struct HelloTriangleApplication { + instance: Option>, +@@ -135,6 +141,7 @@ struct HelloTriangleApplication { + swap_chain_framebuffers: Vec>, + + vertex_buffer: Option>, ++ index_buffer: Option + Send + Sync>>, + command_buffers: Vec>, + + previous_frame_end: Option>, +@@ -164,6 +171,7 @@ impl HelloTriangleApplication { + self.create_graphics_pipeline(); + self.create_framebuffers(); + self.create_vertex_buffer(); ++ self.create_index_buffer(); + self.create_command_buffers(); + self.create_sync_objects(); + } +@@ -435,6 +443,15 @@ impl HelloTriangleApplication { + self.vertex_buffer = Some(buffer); + } + ++ fn create_index_buffer(&mut self) { ++ let (buffer, future) = ImmutableBuffer::from_iter( ++ indices().iter().cloned(), BufferUsage::index_buffer(), ++ self.graphics_queue().clone()) ++ .unwrap(); ++ future.flush().unwrap(); ++ self.index_buffer = Some(buffer); ++ } ++ + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); +@@ -444,8 +461,9 @@ impl HelloTriangleApplication { + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() +- .draw(graphics_pipeline.clone(), &DynamicState::none(), +- vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) ++ .draw_indexed(graphics_pipeline.clone(), &DynamicState::none(), ++ vec![self.vertex_buffer.as_ref().unwrap().clone()], ++ self.index_buffer.as_ref().unwrap().clone(), (), ()) + .unwrap() + .end_render_pass() + .unwrap() diff --git a/src/bin/diff.sh b/src/bin/diff.sh index a37d93e..b40d668 100755 --- a/src/bin/diff.sh +++ b/src/bin/diff.sh @@ -1,3 +1,3 @@ #!/bin/bash git diff --color-words --no-index "$1" "$2" -git diff --no-index "$1" "$2" > "$2".diff +git diff --no-index "$1" "$2" | tail -n+3 > "$2".diff From df5e2df11b0372d3fa8c0562310f9955d361ef3c Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 00:23:16 +0200 Subject: [PATCH 42/78] partially get rid of Options --- Cargo.toml | 8 +- src/bin/20_index_buffer.rs | 207 ++++++++++++++++++++----------------- 2 files changed, 115 insertions(+), 100 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 78199ca..0286b78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "vulkan-tutorial-rs" version = "0.1.0" authors = ["Benjamin Wasty "] -autobins = true +autobins = false [dependencies] vulkano = "0.10.0" @@ -11,6 +11,6 @@ image = "0.19.0" vulkano-win = "0.10.0" winit = "0.17.1" -# [[bin]] -# name = "main" -# path = "src/main.rs" +[[bin]] +name = "main" +path = "src/bin/20_index_buffer.rs" diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index 1d65a94..ba1a3e9 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -118,17 +118,19 @@ fn indices() -> [u16; 6] { [0, 1, 2, 2, 3, 0] } -#[derive(Default)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, + #[allow(unused)] debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, swap_chain: Option>>, swap_chain_images: Option>>>, @@ -146,13 +148,50 @@ struct HelloTriangleApplication { previous_frame_end: Option>, recreate_swap_chain: bool, - - events_loop: Option, } impl HelloTriangleApplication { pub fn new() -> Self { - Default::default() + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); + + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + // self.create_swap_chain(instance.clone()); + + Self { + instance, + debug_callback, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain: None, + swap_chain_images: None, + swap_chain_image_format: None, + swap_chain_extent: None, + + render_pass: None, + graphics_pipeline: None, + + swap_chain_framebuffers: vec![], + + vertex_buffer: None, + index_buffer: None, + command_buffers: vec![], + + previous_frame_end: None, + recreate_swap_chain: false, + + events_loop, + } } pub fn run(&mut self) { @@ -161,12 +200,9 @@ impl HelloTriangleApplication { } fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); + let instance = self.instance.clone(); + let surface = self.surface.clone(); + self.create_swap_chain(&instance, &surface); self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); @@ -176,7 +212,7 @@ impl HelloTriangleApplication { self.create_sync_objects(); } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -194,15 +230,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -221,12 +255,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -234,23 +267,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -266,11 +300,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -304,11 +333,10 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain(&mut self, instance: &Arc, surface: &Arc>) { + let physical_device = PhysicalDevice::from_index(&instance, self.physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); @@ -324,17 +352,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![&self.graphics_queue, &self.present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + (&self.graphics_queue).into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + self.device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -355,7 +383,7 @@ impl HelloTriangleApplication { } fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device.clone(), attachments: { color: { load: Clear, @@ -388,10 +416,9 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); - let vert_shader_module = vertex_shader::Shader::load(device.clone()) + let vert_shader_module = vertex_shader::Shader::load(self.device.clone()) .expect("failed to create vertex shader module!"); - let frag_shader_module = fragment_shader::Shader::load(device.clone()) + let frag_shader_module = fragment_shader::Shader::load(self.device.clone()) .expect("failed to create fragment shader module!"); let swap_chain_extent = self.swap_chain_extent.unwrap(); @@ -418,7 +445,7 @@ impl HelloTriangleApplication { // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) - .build(device.clone()) + .build(self.device.clone()) .unwrap() )); } @@ -437,7 +464,7 @@ impl HelloTriangleApplication { fn create_vertex_buffer(&mut self) { let (buffer, future) = ImmutableBuffer::from_iter( vertices().iter().cloned(), BufferUsage::vertex_buffer(), - self.graphics_queue().clone()) + self.graphics_queue.clone()) .unwrap(); future.flush().unwrap(); self.vertex_buffer = Some(buffer); @@ -446,18 +473,18 @@ impl HelloTriangleApplication { fn create_index_buffer(&mut self) { let (buffer, future) = ImmutableBuffer::from_iter( indices().iter().cloned(), BufferUsage::index_buffer(), - self.graphics_queue().clone()) + self.graphics_queue.clone()) .unwrap(); future.flush().unwrap(); self.index_buffer = Some(buffer); } fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); + let queue_family = self.graphics_queue.family(); let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() @@ -475,10 +502,10 @@ impl HelloTriangleApplication { fn create_sync_objects(&mut self) { self.previous_frame_end = - Some(Box::new(sync::now(self.device().clone())) as Box); + Some(Box::new(sync::now(self.device.clone())) as Box); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -486,7 +513,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -498,11 +525,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -521,23 +550,20 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] @@ -546,7 +572,7 @@ impl HelloTriangleApplication { self.draw_frame(); let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -576,14 +602,13 @@ impl HelloTriangleApplication { Err(err) => panic!("{:?}", err) }; - let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); let future = self.previous_frame_end.take().unwrap() .join(acquire_future) - .then_execute(queue.clone(), command_buffer) + .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), swap_chain.clone(), image_index) .then_signal_fence_and_flush(); match future { @@ -593,38 +618,28 @@ impl HelloTriangleApplication { Err(vulkano::sync::FlushError::OutOfDate) => { self.recreate_swap_chain = true; self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } Err(e) => { println!("{:?}", e); self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } } } fn recreate_swap_chain(&mut self) { - unsafe { self.device().wait().unwrap(); } + unsafe { self.device.wait().unwrap(); } - self.create_swap_chain(); + let instance = self.instance.clone(); + let surface = self.surface.clone(); + self.create_swap_chain(&instance, &surface); self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); self.create_command_buffers(); } - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } - - fn graphics_queue(&self) -> &Arc { - self.graphics_queue.as_ref().unwrap() - } - fn swap_chain(&self) -> &Arc> { self.swap_chain.as_ref().unwrap() } From 048cf2f8ca88b1f19f873c7cbd00bece97845ecf Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 01:17:51 +0200 Subject: [PATCH 43/78] make swapchain non-optional --- src/bin/20_index_buffer.rs | 76 ++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index ba1a3e9..eecb1af 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -132,10 +132,8 @@ struct HelloTriangleApplication { graphics_queue: Arc, present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, render_pass: Option>, graphics_pipeline: Option>, @@ -160,11 +158,14 @@ impl HelloTriangleApplication { let (device, graphics_queue, present_queue) = Self::create_logical_device( &instance, &surface, physical_device_index); - // self.create_swap_chain(instance.clone()); + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); Self { instance, debug_callback, + + events_loop, surface, physical_device_index, @@ -173,10 +174,8 @@ impl HelloTriangleApplication { graphics_queue, present_queue, - swap_chain: None, - swap_chain_images: None, - swap_chain_image_format: None, - swap_chain_extent: None, + swap_chain, + swap_chain_images, render_pass: None, graphics_pipeline: None, @@ -189,9 +188,7 @@ impl HelloTriangleApplication { previous_frame_end: None, recreate_swap_chain: false, - - events_loop, - } + } } pub fn run(&mut self) { @@ -200,9 +197,6 @@ impl HelloTriangleApplication { } fn init_vulkan(&mut self) { - let instance = self.instance.clone(); - let surface = self.surface.clone(); - self.create_swap_chain(&instance, &surface); self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); @@ -320,7 +314,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -333,14 +327,22 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self, instance: &Arc, surface: &Arc>) { - let physical_device = PhysicalDevice::from_index(&instance, self.physical_device_index).unwrap(); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); let capabilities = surface.capabilities(physical_device) .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -355,13 +357,13 @@ impl HelloTriangleApplication { let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![&self.graphics_queue, &self.present_queue].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - (&self.graphics_queue).into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.clone(), + device.clone(), surface.clone(), image_count, surface_format.0, // TODO: color space? @@ -373,13 +375,10 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - self.swap_chain.as_ref(), // old_swapchain + old_swapchain.as_ref() ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } fn create_render_pass(&mut self) { @@ -388,7 +387,7 @@ impl HelloTriangleApplication { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: self.swap_chain.format(), samples: 1, } }, @@ -421,7 +420,7 @@ impl HelloTriangleApplication { let frag_shader_module = fragment_shader::Shader::load(self.device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); + let swap_chain_extent = self.swap_chain.dimensions(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -451,7 +450,7 @@ impl HelloTriangleApplication { } fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + self.swap_chain_framebuffers = self.swap_chain_images.iter() .map(|image| { let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) .add(image.clone()).unwrap() @@ -592,8 +591,7 @@ impl HelloTriangleApplication { self.recreate_swap_chain = false; } - let swap_chain = self.swap_chain().clone(); - let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { self.recreate_swap_chain = true; @@ -608,7 +606,7 @@ impl HelloTriangleApplication { .join(acquire_future) .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(self.present_queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) .then_signal_fence_and_flush(); match future { @@ -631,18 +629,16 @@ impl HelloTriangleApplication { fn recreate_swap_chain(&mut self) { unsafe { self.device.wait().unwrap(); } - let instance = self.instance.clone(); - let surface = self.surface.clone(); - self.create_swap_chain(&instance, &surface); + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; + self.create_render_pass(); self.create_graphics_pipeline(); self.create_framebuffers(); self.create_command_buffers(); } - - fn swap_chain(&self) -> &Arc> { - self.swap_chain.as_ref().unwrap() - } } fn main() { From f03bbfa79e2c151f21475e8ae1a39dcbb28417e7 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 01:30:12 +0200 Subject: [PATCH 44/78] make render pass and graphics pipeline non-optional --- src/bin/20_index_buffer.rs | 50 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index eecb1af..e0ab235 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -135,8 +135,8 @@ struct HelloTriangleApplication { swap_chain: Arc>, swap_chain_images: Vec>>, - render_pass: Option>, - graphics_pipeline: Option>, + render_pass: Arc, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, @@ -161,6 +161,9 @@ impl HelloTriangleApplication { let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, &device, &graphics_queue, &present_queue, None); + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + Self { instance, debug_callback, @@ -177,8 +180,8 @@ impl HelloTriangleApplication { swap_chain, swap_chain_images, - render_pass: None, - graphics_pipeline: None, + render_pass, + graphics_pipeline, swap_chain_framebuffers: vec![], @@ -197,8 +200,6 @@ impl HelloTriangleApplication { } fn init_vulkan(&mut self) { - self.create_render_pass(); - self.create_graphics_pipeline(); self.create_framebuffers(); self.create_vertex_buffer(); self.create_index_buffer(); @@ -381,13 +382,13 @@ impl HelloTriangleApplication { (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device.clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.format(), + format: color_format, samples: 1, } }, @@ -395,10 +396,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -415,12 +420,11 @@ impl HelloTriangleApplication { struct Dummy; } - let vert_shader_module = vertex_shader::Shader::load(self.device.clone()) + let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); - let frag_shader_module = fragment_shader::Shader::load(self.device.clone()) + let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain.dimensions(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -428,7 +432,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer::() .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -443,16 +447,16 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) - .build(self.device.clone()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) + .build(device.clone()) .unwrap() - )); + ) } fn create_framebuffers(&mut self) { self.swap_chain_framebuffers = self.swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba @@ -480,14 +484,13 @@ impl HelloTriangleApplication { fn create_command_buffers(&mut self) { let queue_family = self.graphics_queue.family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw_indexed(graphics_pipeline.clone(), &DynamicState::none(), + .draw_indexed(self.graphics_pipeline.clone(), &DynamicState::none(), vec![self.vertex_buffer.as_ref().unwrap().clone()], self.index_buffer.as_ref().unwrap().clone(), (), ()) .unwrap() @@ -634,8 +637,9 @@ impl HelloTriangleApplication { self.swap_chain = swap_chain; self.swap_chain_images = images; - self.create_render_pass(); - self.create_graphics_pipeline(); + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); self.create_framebuffers(); self.create_command_buffers(); } From d0caa5cc1c6dfeb1b85f506f4a2a204dc49e2ad3 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 09:09:49 +0200 Subject: [PATCH 45/78] remove rest of unnecessary options --- src/bin/20_index_buffer.rs | 77 +++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index e0ab235..738801f 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -140,8 +140,8 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, - vertex_buffer: Option>, - index_buffer: Option + Send + Sync>>, + vertex_buffer: Arc, + index_buffer: Arc + Send + Sync>, command_buffers: Vec>, previous_frame_end: Option>, @@ -149,7 +149,7 @@ struct HelloTriangleApplication { } impl HelloTriangleApplication { - pub fn new() -> Self { + pub fn initialize() -> Self { let instance = Self::create_instance(); let debug_callback = Self::setup_debug_callback(&instance); let (events_loop, surface) = Self::create_surface(&instance); @@ -164,7 +164,14 @@ impl HelloTriangleApplication { let render_pass = Self::create_render_pass(&device, swap_chain.format()); let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); - Self { + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + let index_buffer = Self::create_index_buffer(&graphics_queue); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { instance, debug_callback, @@ -183,28 +190,18 @@ impl HelloTriangleApplication { render_pass, graphics_pipeline, - swap_chain_framebuffers: vec![], + swap_chain_framebuffers, - vertex_buffer: None, - index_buffer: None, + vertex_buffer, + index_buffer, command_buffers: vec![], - previous_frame_end: None, + previous_frame_end, recreate_swap_chain: false, - } - } - - pub fn run(&mut self) { - self.init_vulkan(); - self.main_loop(); - } + }; - fn init_vulkan(&mut self) { - self.create_framebuffers(); - self.create_vertex_buffer(); - self.create_index_buffer(); - self.create_command_buffers(); - self.create_sync_objects(); + app.create_command_buffers(); + app } fn create_instance() -> Arc { @@ -453,33 +450,36 @@ impl HelloTriangleApplication { ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } - fn create_vertex_buffer(&mut self) { + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { let (buffer, future) = ImmutableBuffer::from_iter( vertices().iter().cloned(), BufferUsage::vertex_buffer(), - self.graphics_queue.clone()) + graphics_queue.clone()) .unwrap(); future.flush().unwrap(); - self.vertex_buffer = Some(buffer); + buffer } - fn create_index_buffer(&mut self) { + fn create_index_buffer(graphics_queue: &Arc) -> Arc + Send + Sync> { let (buffer, future) = ImmutableBuffer::from_iter( indices().iter().cloned(), BufferUsage::index_buffer(), - self.graphics_queue.clone()) + graphics_queue.clone()) .unwrap(); future.flush().unwrap(); - self.index_buffer = Some(buffer); + buffer } fn create_command_buffers(&mut self) { @@ -491,8 +491,8 @@ impl HelloTriangleApplication { .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() .draw_indexed(self.graphics_pipeline.clone(), &DynamicState::none(), - vec![self.vertex_buffer.as_ref().unwrap().clone()], - self.index_buffer.as_ref().unwrap().clone(), (), ()) + vec![self.vertex_buffer.clone()], + self.index_buffer.clone(), (), ()) .unwrap() .end_render_pass() .unwrap() @@ -502,9 +502,8 @@ impl HelloTriangleApplication { .collect(); } - fn create_sync_objects(&mut self) { - self.previous_frame_end = - Some(Box::new(sync::now(self.device.clone())) as Box); + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box } fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { @@ -640,12 +639,12 @@ impl HelloTriangleApplication { self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), &self.render_pass); - self.create_framebuffers(); + Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); self.create_command_buffers(); } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); } From 396aed33db09be4eeed61ab422914afb6f733d34 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 19:16:47 +0200 Subject: [PATCH 46/78] rework staging buffers --- Cargo.toml | 2 +- src/bin/19_staging_buffer.rs | 311 +++++++++++++++++--------------- src/bin/20_index_buffer.rs.diff | 58 +++--- 3 files changed, 196 insertions(+), 175 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0286b78..03e755f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/20_index_buffer.rs" +path = "src/bin/19_staging_buffer.rs" diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs index 67cba9a..c951196 100644 --- a/src/bin/19_staging_buffer.rs +++ b/src/bin/19_staging_buffer.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -112,63 +112,90 @@ fn vertices() -> [Vertex; 3] { ] } -#[derive(Default)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, + #[allow(unused)] debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, - graphics_pipeline: Option>, + render_pass: Arc, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, - vertex_buffer: Option>, + vertex_buffer: Arc, command_buffers: Vec>, previous_frame_end: Option>, recreate_swap_chain: bool, - - events_loop: Option, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_vertex_buffer(); - self.create_command_buffers(); - self.create_sync_objects(); + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + vertex_buffer, + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, + }; + + app.create_command_buffers(); + app } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -186,15 +213,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -213,12 +238,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -226,23 +250,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -258,11 +283,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -283,7 +303,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -296,15 +316,22 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -316,17 +343,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -337,22 +364,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - self.swap_chain.as_ref(), // old_swapchain + old_swapchain.as_ref() ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -360,10 +384,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -380,13 +408,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -394,7 +420,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer::() .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -409,43 +435,45 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } - fn create_vertex_buffer(&mut self) { + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { let (buffer, future) = ImmutableBuffer::from_iter( vertices().iter().cloned(), BufferUsage::vertex_buffer(), - self.graphics_queue().clone()) + graphics_queue.clone()) .unwrap(); future.flush().unwrap(); - self.vertex_buffer = Some(buffer); + buffer } fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &DynamicState::none(), - vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) + .draw(self.graphics_pipeline.clone(), &DynamicState::none(), + vec![self.vertex_buffer.clone()], (), ()) .unwrap() .end_render_pass() .unwrap() @@ -455,12 +483,11 @@ impl HelloTriangleApplication { .collect(); } - fn create_sync_objects(&mut self) { - self.previous_frame_end = - Some(Box::new(sync::now(self.device().clone())) as Box); + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -468,7 +495,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -480,11 +507,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -503,23 +532,20 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] @@ -528,7 +554,7 @@ impl HelloTriangleApplication { self.draw_frame(); let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -548,8 +574,7 @@ impl HelloTriangleApplication { self.recreate_swap_chain = false; } - let swap_chain = self.swap_chain().clone(); - let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { self.recreate_swap_chain = true; @@ -558,14 +583,13 @@ impl HelloTriangleApplication { Err(err) => panic!("{:?}", err) }; - let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); let future = self.previous_frame_end.take().unwrap() .join(acquire_future) - .then_execute(queue.clone(), command_buffer) + .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) .then_signal_fence_and_flush(); match future { @@ -575,44 +599,33 @@ impl HelloTriangleApplication { Err(vulkano::sync::FlushError::OutOfDate) => { self.recreate_swap_chain = true; self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } Err(e) => { println!("{:?}", e); self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } } } fn recreate_swap_chain(&mut self) { - unsafe { self.device().wait().unwrap(); } + unsafe { self.device.wait().unwrap(); } - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); - } + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } - - fn graphics_queue(&self) -> &Arc { - self.graphics_queue.as_ref().unwrap() - } - - fn swap_chain(&self) -> &Arc> { - self.swap_chain.as_ref().unwrap() + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); + Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); } diff --git a/src/bin/20_index_buffer.rs.diff b/src/bin/20_index_buffer.rs.diff index 7da6eff..1f967e2 100644 --- a/src/bin/20_index_buffer.rs.diff +++ b/src/bin/20_index_buffer.rs.diff @@ -29,50 +29,58 @@ + [0, 1, 2, 2, 3, 0] +} + - #[derive(Default)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, + #[allow(unused)] @@ -135,6 +141,7 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, - vertex_buffer: Option>, -+ index_buffer: Option + Send + Sync>>, + vertex_buffer: Arc, ++ index_buffer: Arc + Send + Sync>, command_buffers: Vec>, previous_frame_end: Option>, -@@ -164,6 +171,7 @@ impl HelloTriangleApplication { - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_vertex_buffer(); -+ self.create_index_buffer(); - self.create_command_buffers(); - self.create_sync_objects(); - } -@@ -435,6 +443,15 @@ impl HelloTriangleApplication { - self.vertex_buffer = Some(buffer); +@@ -160,6 +167,7 @@ impl HelloTriangleApplication { + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); ++ let index_buffer = Self::create_index_buffer(&graphics_queue); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + +@@ -185,6 +193,7 @@ impl HelloTriangleApplication { + swap_chain_framebuffers, + + vertex_buffer, ++ index_buffer, + command_buffers: vec![], + + previous_frame_end, +@@ -464,6 +473,15 @@ impl HelloTriangleApplication { + buffer } -+ fn create_index_buffer(&mut self) { ++ fn create_index_buffer(graphics_queue: &Arc) -> Arc + Send + Sync> { + let (buffer, future) = ImmutableBuffer::from_iter( + indices().iter().cloned(), BufferUsage::index_buffer(), -+ self.graphics_queue().clone()) ++ graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); -+ self.index_buffer = Some(buffer); ++ buffer + } + fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); -@@ -444,8 +461,9 @@ impl HelloTriangleApplication { + let queue_family = self.graphics_queue.family(); + self.command_buffers = self.swap_chain_framebuffers.iter() +@@ -472,8 +490,9 @@ impl HelloTriangleApplication { .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() -- .draw(graphics_pipeline.clone(), &DynamicState::none(), -- vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) -+ .draw_indexed(graphics_pipeline.clone(), &DynamicState::none(), -+ vec![self.vertex_buffer.as_ref().unwrap().clone()], -+ self.index_buffer.as_ref().unwrap().clone(), (), ()) +- .draw(self.graphics_pipeline.clone(), &DynamicState::none(), +- vec![self.vertex_buffer.clone()], (), ()) ++ .draw_indexed(self.graphics_pipeline.clone(), &DynamicState::none(), ++ vec![self.vertex_buffer.clone()], ++ self.index_buffer.clone(), (), ()) .unwrap() .end_render_pass() .unwrap() From b9b70a1bcaa74f52ac3a7741e783ed48fc197bfd Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 19:23:19 +0200 Subject: [PATCH 47/78] rework vertex buffers --- Cargo.toml | 2 +- src/bin/18_vertex_buffer.rs | 311 ++++++++++++++++-------------- src/bin/19_staging_buffer.rs.diff | 23 ++- 3 files changed, 180 insertions(+), 156 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 03e755f..f4ea5cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/19_staging_buffer.rs" +path = "src/bin/18_vertex_buffer.rs" diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs index 2a3b975..8d4ed0d 100644 --- a/src/bin/18_vertex_buffer.rs +++ b/src/bin/18_vertex_buffer.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -112,63 +112,90 @@ fn vertices() -> [Vertex; 3] { ] } -#[derive(Default)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, + #[allow(unused)] debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, - graphics_pipeline: Option>, + render_pass: Arc, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, - vertex_buffer: Option>, + vertex_buffer: Arc, command_buffers: Vec>, previous_frame_end: Option>, recreate_swap_chain: bool, - - events_loop: Option, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_vertex_buffer(); - self.create_command_buffers(); - self.create_sync_objects(); + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let vertex_buffer = Self::create_vertex_buffer(&device); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + vertex_buffer, + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, + }; + + app.create_command_buffers(); + app } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -186,15 +213,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -213,12 +238,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -226,23 +250,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -258,11 +283,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -283,7 +303,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -296,15 +316,22 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -316,17 +343,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -337,22 +364,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - self.swap_chain.as_ref(), // old_swapchain + old_swapchain.as_ref() ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -360,10 +384,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -380,13 +408,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -394,7 +420,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer::() .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -409,39 +435,41 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } - fn create_vertex_buffer(&mut self) { - self.vertex_buffer = Some(CpuAccessibleBuffer::from_iter(self.device().clone(), - BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap()); + fn create_vertex_buffer(device: &Arc) -> Arc { + CpuAccessibleBuffer::from_iter(device.clone(), + BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap() } fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &DynamicState::none(), - vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) + .draw(self.graphics_pipeline.clone(), &DynamicState::none(), + vec![self.vertex_buffer.clone()], (), ()) .unwrap() .end_render_pass() .unwrap() @@ -451,12 +479,11 @@ impl HelloTriangleApplication { .collect(); } - fn create_sync_objects(&mut self) { - self.previous_frame_end = - Some(Box::new(sync::now(self.device().clone())) as Box); + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -464,7 +491,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -476,11 +503,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -499,23 +528,20 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] @@ -524,7 +550,7 @@ impl HelloTriangleApplication { self.draw_frame(); let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -544,8 +570,7 @@ impl HelloTriangleApplication { self.recreate_swap_chain = false; } - let swap_chain = self.swap_chain().clone(); - let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { self.recreate_swap_chain = true; @@ -554,14 +579,13 @@ impl HelloTriangleApplication { Err(err) => panic!("{:?}", err) }; - let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); let future = self.previous_frame_end.take().unwrap() .join(acquire_future) - .then_execute(queue.clone(), command_buffer) + .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) .then_signal_fence_and_flush(); match future { @@ -571,44 +595,33 @@ impl HelloTriangleApplication { Err(vulkano::sync::FlushError::OutOfDate) => { self.recreate_swap_chain = true; self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } Err(e) => { println!("{:?}", e); self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } } } fn recreate_swap_chain(&mut self) { - unsafe { self.device().wait().unwrap(); } + unsafe { self.device.wait().unwrap(); } - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); - } + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } - - fn graphics_queue(&self) -> &Arc { - self.graphics_queue.as_ref().unwrap() - } - - fn swap_chain(&self) -> &Arc> { - self.swap_chain.as_ref().unwrap() + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); + Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); } diff --git a/src/bin/19_staging_buffer.rs.diff b/src/bin/19_staging_buffer.rs.diff index 8aad681..296017b 100644 --- a/src/bin/19_staging_buffer.rs.diff +++ b/src/bin/19_staging_buffer.rs.diff @@ -9,18 +9,29 @@ BufferUsage, BufferAccess, }; -@@ -427,8 +427,12 @@ impl HelloTriangleApplication { +@@ -159,7 +159,7 @@ impl HelloTriangleApplication { + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + +- let vertex_buffer = Self::create_vertex_buffer(&device); ++ let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + +@@ -455,9 +455,13 @@ impl HelloTriangleApplication { + ).collect::>() } - fn create_vertex_buffer(&mut self) { -- self.vertex_buffer = Some(CpuAccessibleBuffer::from_iter(self.device().clone(), -- BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap()); +- fn create_vertex_buffer(device: &Arc) -> Arc { +- CpuAccessibleBuffer::from_iter(device.clone(), +- BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap() ++ fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), -+ self.graphics_queue().clone()) ++ graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); -+ self.vertex_buffer = Some(buffer); ++ buffer } fn create_command_buffers(&mut self) { From dd6e3114be4a8a2b4b1b1c021da0c31272cc6814 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 19:38:35 +0200 Subject: [PATCH 48/78] rework swap chain recreation --- Cargo.toml | 2 +- src/bin/16_swap_chain_recreation.rs | 301 ++++++++++++++-------------- src/bin/18_vertex_buffer.rs.diff | 83 +++++--- 3 files changed, 208 insertions(+), 178 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f4ea5cb..1186fdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/18_vertex_buffer.rs" +path = "src/bin/16_swap_chain_recreation.rs" diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs index 98e80eb..69f7c16 100644 --- a/src/bin/16_swap_chain_recreation.rs +++ b/src/bin/16_swap_chain_recreation.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -89,33 +89,31 @@ impl QueueFamilyIndices { } } -type ConcreteGraphicsPipeline = Arc, Arc>>; +type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; -#[derive(Default)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, + #[allow(unused)] debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, + render_pass: Arc, // NOTE: We need to the full type of // self.graphics_pipeline, because `BufferlessVertices` only // works when the concrete type of the graphics pipeline is visible // to the command buffer. - // TODO: check if can be simplified later in tutorial - // graphics_pipeline: Option>, - graphics_pipeline: Option, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, @@ -123,35 +121,60 @@ struct HelloTriangleApplication { previous_frame_end: Option>, recreate_swap_chain: bool, - - events_loop: Option, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); - self.create_sync_objects(); + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, + }; + + app.create_command_buffers(); + app } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -169,15 +192,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -196,12 +217,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -209,23 +229,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -241,11 +262,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -266,7 +282,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -279,15 +295,22 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -299,17 +322,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -320,22 +343,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - self.swap_chain.as_ref(), // old_swapchain + old_swapchain.as_ref() ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -343,10 +363,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -363,13 +387,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -377,7 +399,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -392,34 +414,36 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { let vertices = BufferlessVertices { vertices: 3, instances: 1 }; - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &DynamicState::none(), + .draw(self.graphics_pipeline.clone(), &DynamicState::none(), vertices, (), ()) .unwrap() .end_render_pass() @@ -430,12 +454,11 @@ impl HelloTriangleApplication { .collect(); } - fn create_sync_objects(&mut self) { - self.previous_frame_end = - Some(Box::new(sync::now(self.device().clone())) as Box); + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -443,7 +466,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -455,11 +478,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -478,23 +503,20 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] @@ -503,7 +525,7 @@ impl HelloTriangleApplication { self.draw_frame(); let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -523,8 +545,7 @@ impl HelloTriangleApplication { self.recreate_swap_chain = false; } - let swap_chain = self.swap_chain().clone(); - let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { self.recreate_swap_chain = true; @@ -533,14 +554,13 @@ impl HelloTriangleApplication { Err(err) => panic!("{:?}", err) }; - let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); let future = self.previous_frame_end.take().unwrap() .join(acquire_future) - .then_execute(queue.clone(), command_buffer) + .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) .then_signal_fence_and_flush(); match future { @@ -550,44 +570,33 @@ impl HelloTriangleApplication { Err(vulkano::sync::FlushError::OutOfDate) => { self.recreate_swap_chain = true; self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } Err(e) => { println!("{:?}", e); self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } } } fn recreate_swap_chain(&mut self) { - unsafe { self.device().wait().unwrap(); } + unsafe { self.device.wait().unwrap(); } - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); - } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } - - fn graphics_queue(&self) -> &Arc { - self.graphics_queue.as_ref().unwrap() - } + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; - fn swap_chain(&self) -> &Arc> { - self.swap_chain.as_ref().unwrap() + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); + Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); } diff --git a/src/bin/18_vertex_buffer.rs.diff b/src/bin/18_vertex_buffer.rs.diff index 8832b54..973b3c9 100644 --- a/src/bin/18_vertex_buffer.rs.diff +++ b/src/bin/18_vertex_buffer.rs.diff @@ -32,7 +32,7 @@ } } --type ConcreteGraphicsPipeline = Arc, Arc>>; +-type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], @@ -53,36 +53,58 @@ + ] +} - #[derive(Default)] struct HelloTriangleApplication { -@@ -109,16 +130,11 @@ struct HelloTriangleApplication { - swap_chain_extent: Option<[u32; 2]>, + instance: Arc, +@@ -109,14 +130,11 @@ struct HelloTriangleApplication { + swap_chain_images: Vec>>, - render_pass: Option>, + render_pass: Arc, - // NOTE: We need to the full type of - // self.graphics_pipeline, because `BufferlessVertices` only - // works when the concrete type of the graphics pipeline is visible - // to the command buffer. -- // TODO: check if can be simplified later in tutorial -- // graphics_pipeline: Option>, -- graphics_pipeline: Option, -+ graphics_pipeline: Option>, +- graphics_pipeline: Arc, ++ graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, -+ vertex_buffer: Option>, ++ vertex_buffer: Arc, command_buffers: Vec>, previous_frame_end: Option>, -@@ -147,6 +163,7 @@ impl HelloTriangleApplication { - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); -+ self.create_vertex_buffer(); - self.create_command_buffers(); - self.create_sync_objects(); +@@ -141,6 +159,8 @@ impl HelloTriangleApplication { + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + ++ let vertex_buffer = Self::create_vertex_buffer(&device); ++ + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { +@@ -164,6 +184,7 @@ impl HelloTriangleApplication { + + swap_chain_framebuffers, + ++ vertex_buffer, + command_buffers: vec![], + + previous_frame_end, +@@ -198,7 +219,7 @@ impl HelloTriangleApplication { + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") +- } ++ } } -@@ -351,7 +368,7 @@ impl HelloTriangleApplication { + + fn check_validation_layer_support() -> bool { +@@ -370,12 +391,12 @@ impl HelloTriangleApplication { + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, +- ) -> Arc { ++ ) -> Arc { + #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] #[ty = "vertex"] @@ -91,7 +113,7 @@ struct Dummy; } -@@ -359,7 +376,7 @@ impl HelloTriangleApplication { +@@ -383,7 +404,7 @@ impl HelloTriangleApplication { mod fragment_shader { #[derive(VulkanoShader)] #[ty = "fragment"] @@ -100,37 +122,36 @@ struct Dummy; } -@@ -378,7 +395,7 @@ impl HelloTriangleApplication { +@@ -400,7 +421,7 @@ impl HelloTriangleApplication { }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() - .vertex_input(BufferlessDefinition {}) + .vertex_input_single_buffer::() .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() .primitive_restart(false) -@@ -409,18 +426,22 @@ impl HelloTriangleApplication { - ).collect::>(); +@@ -434,17 +455,21 @@ impl HelloTriangleApplication { + ).collect::>() } -+ fn create_vertex_buffer(&mut self) { -+ self.vertex_buffer = Some(CpuAccessibleBuffer::from_iter(self.device().clone(), -+ BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap()); ++ fn create_vertex_buffer(device: &Arc) -> Arc { ++ CpuAccessibleBuffer::from_iter(device.clone(), ++ BufferUsage::vertex_buffer(), vertices().iter().cloned()).unwrap() + } + fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { - let vertices = BufferlessVertices { vertices: 3, instances: 1 }; - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &DynamicState::none(), + .draw(self.graphics_pipeline.clone(), &DynamicState::none(), - vertices, (), ()) -+ vec![self.vertex_buffer.as_ref().unwrap().clone()], (), ()) ++ vec![self.vertex_buffer.clone()], (), ()) .unwrap() .end_render_pass() .unwrap() From 4a6f90e53880aeb80f41a256c53fbdebc469d503 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 19:46:08 +0200 Subject: [PATCH 49/78] rework hello triangle --- Cargo.toml | 2 +- src/bin/15_hello_triangle.rs | 273 ++++++++++++----------- src/bin/16_swap_chain_recreation.rs.diff | 118 ++++++---- 3 files changed, 216 insertions(+), 177 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1186fdf..cc18d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/16_swap_chain_recreation.rs" +path = "src/bin/15_hello_triangle.rs" diff --git a/src/bin/15_hello_triangle.rs b/src/bin/15_hello_triangle.rs index 7dd5351..31dcc12 100644 --- a/src/bin/15_hello_triangle.rs +++ b/src/bin/15_hello_triangle.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -30,7 +30,7 @@ use vulkano::swapchain::{ PresentMode, Swapchain, CompositeAlpha, - acquire_next_image + acquire_next_image, }; use vulkano::format::Format; use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; @@ -88,65 +88,84 @@ impl QueueFamilyIndices { } } -type ConcreteGraphicsPipeline = Arc, Arc>>; +type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, + render_pass: Arc, // NOTE: We need to the full type of // self.graphics_pipeline, because `BufferlessVertices` only // works when the concrete type of the graphics pipeline is visible // to the command buffer. - // TODO: check if can be simplified later in tutorial - // graphics_pipeline: Option>, - graphics_pipeline: Option, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, command_buffers: Vec>, - - events_loop: Option, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + command_buffers: vec![], + }; - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); + app.create_command_buffers(); + app } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -164,15 +183,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -191,12 +208,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -204,23 +220,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -236,11 +253,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -261,7 +273,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -274,15 +286,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -294,17 +312,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -315,22 +333,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -338,10 +353,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -358,13 +377,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -372,7 +389,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -387,34 +404,36 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { let vertices = BufferlessVertices { vertices: 3, instances: 1 }; - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &DynamicState::none(), + .draw(self.graphics_pipeline.clone(), &DynamicState::none(), vertices, (), ()) .unwrap() .end_render_pass() @@ -425,7 +444,7 @@ impl HelloTriangleApplication { .collect(); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -433,7 +452,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -445,11 +464,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -468,23 +489,20 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] @@ -493,7 +511,7 @@ impl HelloTriangleApplication { self.draw_frame(); let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -506,39 +524,22 @@ impl HelloTriangleApplication { } fn draw_frame(&mut self) { - let swap_chain = self.swap_chain().clone(); - let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); + let (image_index, acquire_future) = acquire_next_image(self.swap_chain.clone(), None).unwrap(); - let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); let future = acquire_future - .then_execute(queue.clone(), command_buffer) + .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) .then_signal_fence_and_flush() .unwrap(); - future.wait(None).unwrap(); - } - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } - - fn graphics_queue(&self) -> &Arc { - self.graphics_queue.as_ref().unwrap() - } - - fn swap_chain(&self) -> &Arc> { - self.swap_chain.as_ref().unwrap() + future.wait(None).unwrap(); } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); } diff --git a/src/bin/16_swap_chain_recreation.rs.diff b/src/bin/16_swap_chain_recreation.rs.diff index 4da6774..727a85d 100644 --- a/src/bin/16_swap_chain_recreation.rs.diff +++ b/src/bin/16_swap_chain_recreation.rs.diff @@ -1,11 +1,9 @@ --- a/15_hello_triangle.rs +++ b/16_swap_chain_recreation.rs -@@ -30,11 +30,12 @@ use vulkano::swapchain::{ - PresentMode, +@@ -31,10 +31,11 @@ use vulkano::swapchain::{ Swapchain, CompositeAlpha, -- acquire_next_image -+ acquire_next_image, + acquire_next_image, + AcquireError, }; use vulkano::format::Format; @@ -15,49 +13,87 @@ use vulkano::pipeline::{ GraphicsPipeline, vertex::BufferlessDefinition, -@@ -120,6 +121,9 @@ struct HelloTriangleApplication { +@@ -90,9 +91,9 @@ impl QueueFamilyIndices { - command_buffers: Vec>, + type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; + +-#[allow(unused)] + struct HelloTriangleApplication { + instance: Arc, ++ #[allow(unused)] + debug_callback: Option, + + events_loop: EventsLoop, +@@ -117,6 +118,9 @@ struct HelloTriangleApplication { + swap_chain_framebuffers: Vec>, + command_buffers: Vec>, ++ + previous_frame_end: Option>, + recreate_swap_chain: bool, -+ - events_loop: Option, } -@@ -144,6 +148,7 @@ impl HelloTriangleApplication { - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); -+ self.create_sync_objects(); - } + impl HelloTriangleApplication { +@@ -130,13 +134,15 @@ impl HelloTriangleApplication { + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, +- &device, &graphics_queue, &present_queue); ++ &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); - fn create_instance(&mut self) { -@@ -315,7 +320,7 @@ impl HelloTriangleApplication { + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + ++ let previous_frame_end = Some(Self::create_sync_objects(&device)); ++ + let mut app = Self { + instance, + debug_callback, +@@ -159,6 +165,9 @@ impl HelloTriangleApplication { + swap_chain_framebuffers, + + command_buffers: vec![], ++ ++ previous_frame_end, ++ recreate_swap_chain: false, + }; + + app.create_command_buffers(); +@@ -293,6 +302,7 @@ impl HelloTriangleApplication { + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, ++ old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) +@@ -333,7 +343,7 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped -- None, // old_swapchain -+ self.swap_chain.as_ref(), // old_swapchain +- None, ++ old_swapchain.as_ref() ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); -@@ -425,6 +430,11 @@ impl HelloTriangleApplication { + (swap_chain, images) +@@ -444,6 +454,10 @@ impl HelloTriangleApplication { .collect(); } -+ fn create_sync_objects(&mut self) { -+ self.previous_frame_end = -+ Some(Box::new(sync::now(self.device().clone())) as Box); ++ fn create_sync_objects(device: &Arc) -> Box { ++ Box::new(sync::now(device.clone())) as Box + } + - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? -@@ -506,19 +516,58 @@ impl HelloTriangleApplication { +@@ -524,18 +538,61 @@ impl HelloTriangleApplication { } fn draw_frame(&mut self) { +- let (image_index, acquire_future) = acquire_next_image(self.swap_chain.clone(), None).unwrap(); + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { @@ -65,9 +101,7 @@ + self.recreate_swap_chain = false; + } + - let swap_chain = self.swap_chain().clone(); -- let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); -+ let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { ++ let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; @@ -76,18 +110,16 @@ + Err(err) => panic!("{:?}", err) + }; - let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); - let future = acquire_future + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) - .then_execute(queue.clone(), command_buffer) + .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) - .then_signal_fence_and_flush() - .unwrap(); -- future.wait(None).unwrap(); + .then_signal_fence_and_flush(); + + match future { @@ -97,24 +129,30 @@ + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end -+ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); ++ = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end -+ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); ++ = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + } + } + + fn recreate_swap_chain(&mut self) { -+ unsafe { self.device().wait().unwrap(); } ++ unsafe { self.device.wait().unwrap(); } + -+ self.create_swap_chain(); -+ self.create_render_pass(); -+ self.create_graphics_pipeline(); -+ self.create_framebuffers(); ++ let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, ++ &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); ++ self.swap_chain = swap_chain; ++ self.swap_chain_images = images; + +- future.wait(None).unwrap(); ++ self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); ++ self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), ++ &self.render_pass); ++ Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); } + } - fn instance(&self) -> &Arc { From 4d436c1c4b53ea83d6252631b797ea6f41e11ab5 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 20:08:58 +0200 Subject: [PATCH 50/78] rework command buffers --- Cargo.toml | 2 +- src/bin/14_command_buffers.rs | 254 ++++++++++++++++-------------- src/bin/15_hello_triangle.rs.diff | 50 ++---- 3 files changed, 148 insertions(+), 158 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc18d77..417f89f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/15_hello_triangle.rs" +path = "src/bin/14_command_buffers.rs" diff --git a/src/bin/14_command_buffers.rs b/src/bin/14_command_buffers.rs index a743a75..5d8f190 100644 --- a/src/bin/14_command_buffers.rs +++ b/src/bin/14_command_buffers.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -87,65 +87,84 @@ impl QueueFamilyIndices { } } -type ConcreteGraphicsPipeline = Arc, Arc>>; +type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, + render_pass: Arc, // NOTE: We need to the full type of // self.graphics_pipeline, because `BufferlessVertices` only // works when the concrete type of the graphics pipeline is visible // to the command buffer. - // TODO: check if can be simplified later in tutorial - // graphics_pipeline: Option>, - graphics_pipeline: Option, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, command_buffers: Vec>, - - events_loop: Option, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); + swap_chain_framebuffers, + + command_buffers: vec![], + }; + + app.create_command_buffers(); + app } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -163,15 +182,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -190,12 +207,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -203,23 +219,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -235,11 +252,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -260,7 +272,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -273,15 +285,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -293,17 +311,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -314,22 +332,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -337,10 +352,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -357,13 +376,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -371,7 +388,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -386,34 +403,36 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { let vertices = BufferlessVertices { vertices: 3, instances: 1 }; - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw(graphics_pipeline.clone(), &DynamicState::none(), + .draw(self.graphics_pipeline.clone(), &DynamicState::none(), vertices, (), ()) .unwrap() .end_render_pass() @@ -424,7 +443,7 @@ impl HelloTriangleApplication { .collect(); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -432,7 +451,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -444,11 +463,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -467,30 +488,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -501,17 +519,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/15_hello_triangle.rs.diff b/src/bin/15_hello_triangle.rs.diff index ff796b7..2f82768 100644 --- a/src/bin/15_hello_triangle.rs.diff +++ b/src/bin/15_hello_triangle.rs.diff @@ -4,7 +4,7 @@ PresentMode, Swapchain, CompositeAlpha, -+ acquire_next_image ++ acquire_next_image, }; use vulkano::format::Format; use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; @@ -13,59 +13,39 @@ use vulkano::pipeline::{ GraphicsPipeline, vertex::BufferlessDefinition, -@@ -129,7 +130,7 @@ impl HelloTriangleApplication { - - pub fn run(&mut self) { - self.init_vulkan(); -- // self.main_loop(); -+ self.main_loop(); - } - - fn init_vulkan(&mut self) { -@@ -489,6 +490,8 @@ impl HelloTriangleApplication { +@@ -507,6 +508,8 @@ impl HelloTriangleApplication { #[allow(unused)] fn main_loop(&mut self) { loop { + self.draw_frame(); + let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { -@@ -502,6 +505,22 @@ impl HelloTriangleApplication { +@@ -519,9 +522,24 @@ impl HelloTriangleApplication { + } } } - ++ + fn draw_frame(&mut self) { -+ let swap_chain = self.swap_chain().clone(); -+ let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); ++ let (image_index, acquire_future) = acquire_next_image(self.swap_chain.clone(), None).unwrap(); + -+ let queue = self.graphics_queue().clone(); + let command_buffer = self.command_buffers[image_index].clone(); + + let future = acquire_future -+ .then_execute(queue.clone(), command_buffer) ++ .then_execute(self.graphics_queue.clone(), command_buffer) + .unwrap() -+ .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) ++ .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) + .then_signal_fence_and_flush() + .unwrap(); -+ future.wait(None).unwrap(); -+ } + - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } -@@ -509,6 +528,14 @@ impl HelloTriangleApplication { - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } -+ -+ fn graphics_queue(&self) -> &Arc { -+ self.graphics_queue.as_ref().unwrap() -+ } -+ -+ fn swap_chain(&self) -> &Arc> { -+ self.swap_chain.as_ref().unwrap() ++ future.wait(None).unwrap(); + } } fn main() { +- let mut _app = HelloTriangleApplication::initialize(); +- // app.main_loop(); ++ let mut app = HelloTriangleApplication::initialize(); ++ app.main_loop(); + } From 0c7bb9c082dd2ac2185eb8836eb99eb3ea0fb9da Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 20:12:24 +0200 Subject: [PATCH 51/78] rework framebuffers --- Cargo.toml | 2 +- src/bin/13_framebuffers.rs | 241 +++++++++++++++-------------- src/bin/14_command_buffers.rs.diff | 48 ++++-- 3 files changed, 156 insertions(+), 135 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 417f89f..4cd0276 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/14_command_buffers.rs" +path = "src/bin/13_framebuffers.rs" diff --git a/src/bin/13_framebuffers.rs b/src/bin/13_framebuffers.rs index 43dd8c2..6605fea 100644 --- a/src/bin/13_framebuffers.rs +++ b/src/bin/13_framebuffers.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -81,62 +81,77 @@ impl QueueFamilyIndices { } } -type ConcreteGraphicsPipeline = Arc, Arc>>; +type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, + render_pass: Arc, // NOTE: We need to the full type of // self.graphics_pipeline, because `BufferlessVertices` only // works when the concrete type of the graphics pipeline is visible // to the command buffer. - // TODO: check if can be simplified later in tutorial - // graphics_pipeline: Option>, - graphics_pipeline: Option, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, - - events_loop: Option, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -154,15 +169,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -181,12 +194,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -194,23 +206,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -226,11 +239,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -251,7 +259,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -264,15 +272,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -284,17 +298,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -305,22 +319,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -328,10 +339,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -348,13 +363,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -362,7 +375,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -377,24 +390,27 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -402,7 +418,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -414,11 +430,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -437,30 +455,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -471,17 +486,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/14_command_buffers.rs.diff b/src/bin/14_command_buffers.rs.diff index a552a16..50f433e 100644 --- a/src/bin/14_command_buffers.rs.diff +++ b/src/bin/14_command_buffers.rs.diff @@ -20,38 +20,52 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -111,6 +117,8 @@ struct HelloTriangleApplication { +@@ -108,6 +114,8 @@ struct HelloTriangleApplication { + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, - -+ command_buffers: Vec>, + - events_loop: Option, ++ command_buffers: Vec>, } -@@ -134,6 +142,7 @@ impl HelloTriangleApplication { - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); -+ self.create_command_buffers(); + impl HelloTriangleApplication { +@@ -128,7 +136,7 @@ impl HelloTriangleApplication { + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + +- Self { ++ let mut app = Self { + instance, + debug_callback, + +@@ -148,7 +156,12 @@ impl HelloTriangleApplication { + graphics_pipeline, + + swap_chain_framebuffers, +- } ++ ++ command_buffers: vec![], ++ }; ++ ++ app.create_command_buffers(); ++ app } - fn create_instance(&mut self) { -@@ -394,6 +403,27 @@ impl HelloTriangleApplication { - ).collect::>(); + fn create_instance() -> Arc { +@@ -410,6 +423,26 @@ impl HelloTriangleApplication { + ).collect::>() } + fn create_command_buffers(&mut self) { -+ let queue_family = self.graphics_queue.as_ref().unwrap().family(); -+ let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); ++ let queue_family = self.graphics_queue.family(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + let vertices = BufferlessVertices { vertices: 3, instances: 1 }; -+ Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) ++ Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() -+ .draw(graphics_pipeline.clone(), &DynamicState::none(), ++ .draw(self.graphics_pipeline.clone(), &DynamicState::none(), + vertices, (), ()) + .unwrap() + .end_render_pass() @@ -62,6 +76,6 @@ + .collect(); + } + - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? From 6f601f7bbe46e9809f472a5b2cec136f5216ffba Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 20:18:26 +0200 Subject: [PATCH 52/78] rework render passes, graphics pipeline --- Cargo.toml | 2 +- src/bin/11_render_passes.rs | 214 ++++++++--------- src/bin/12_graphics_pipeline_complete.rs | 225 +++++++++--------- src/bin/12_graphics_pipeline_complete.rs.diff | 67 ++++-- src/bin/13_framebuffers.rs.diff | 51 ++-- 5 files changed, 297 insertions(+), 262 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4cd0276..63b0b83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/13_framebuffers.rs" +path = "src/bin/11_render_passes.rs" diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs index 35f14f3..cf0801f 100644 --- a/src/bin/11_render_passes.rs +++ b/src/bin/11_render_passes.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -77,50 +77,63 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + events_loop: EventsLoop, + surface: Arc>, - graphics_queue: Option>, - present_queue: Option>, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + graphics_queue: Arc, + present_queue: Arc, - render_pass: Option>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - events_loop: Option, + render_pass: Arc, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); + Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -138,15 +151,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -165,12 +176,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -178,23 +188,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -210,11 +221,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -235,7 +241,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -248,15 +254,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -268,17 +280,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -289,22 +301,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -312,10 +321,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + _render_pass: &Arc, + ) { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -332,13 +345,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -352,6 +363,7 @@ impl HelloTriangleApplication { .triangle_list() .primitive_restart(false) .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) .depth_clamp(false) // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... .polygon_mode_fill() // = default @@ -360,11 +372,10 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .fragment_shader(frag_shader_module.main_entry_point(), ()) ); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -372,7 +383,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -384,11 +395,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -407,30 +420,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -441,17 +451,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/12_graphics_pipeline_complete.rs b/src/bin/12_graphics_pipeline_complete.rs index 81fb93f..a4f2e59 100644 --- a/src/bin/12_graphics_pipeline_complete.rs +++ b/src/bin/12_graphics_pipeline_complete.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -79,59 +79,71 @@ impl QueueFamilyIndices { } } -type ConcreteGraphicsPipeline = Arc, Arc>>; +type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, + render_pass: Arc, // NOTE: We need to the full type of // self.graphics_pipeline, because `BufferlessVertices` only // works when the concrete type of the graphics pipeline is visible // to the command buffer. - // TODO: check if can be simplified later in tutorial - // graphics_pipeline: Option>, - graphics_pipeline: Option, - - events_loop: Option, + graphics_pipeline: Arc, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); + render_pass, + graphics_pipeline, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -149,15 +161,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -176,12 +186,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -189,23 +198,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -221,11 +231,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -246,7 +251,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -259,15 +264,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -279,17 +290,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -300,22 +311,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -323,10 +331,14 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -343,13 +355,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -357,7 +367,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -372,13 +382,13 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -386,7 +396,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -398,11 +408,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -421,30 +433,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -455,17 +464,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/12_graphics_pipeline_complete.rs.diff b/src/bin/12_graphics_pipeline_complete.rs.diff index e997fb2..abfcbe3 100644 --- a/src/bin/12_graphics_pipeline_complete.rs.diff +++ b/src/bin/12_graphics_pipeline_complete.rs.diff @@ -14,50 +14,69 @@ } } -+type ConcreteGraphicsPipeline = Arc, Arc>>; ++type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; + - #[derive(Default)] + #[allow(unused)] struct HelloTriangleApplication { - instance: Option>, -@@ -95,6 +99,13 @@ struct HelloTriangleApplication { - swap_chain_extent: Option<[u32; 2]>, + instance: Arc, +@@ -95,6 +99,11 @@ struct HelloTriangleApplication { + swap_chain_images: Vec>>, - render_pass: Option>, + render_pass: Arc, + // NOTE: We need to the full type of + // self.graphics_pipeline, because `BufferlessVertices` only + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. -+ // TODO: check if can be simplified later in tutorial -+ // graphics_pipeline: Option>, -+ graphics_pipeline: Option, - - events_loop: Option, ++ graphics_pipeline: Arc, } -@@ -346,12 +357,13 @@ impl HelloTriangleApplication { + + impl HelloTriangleApplication { +@@ -111,7 +120,7 @@ impl HelloTriangleApplication { + &device, &graphics_queue, &present_queue); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); +- Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); ++ let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + Self { + instance, +@@ -130,6 +139,7 @@ impl HelloTriangleApplication { + swap_chain_images, + + render_pass, ++ graphics_pipeline, + } + } + +@@ -327,8 +337,8 @@ impl HelloTriangleApplication { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], +- _render_pass: &Arc, +- ) { ++ render_pass: &Arc, ++ ) -> Arc { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] +@@ -357,7 +367,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - let _pipeline_builder = Arc::new(GraphicsPipeline::start() -+ self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() ++ Arc::new(GraphicsPipeline::start() .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() - .primitive_restart(false) - .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport -+ .fragment_shader(frag_shader_module.main_entry_point(), ()) - .depth_clamp(false) - // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... - .polygon_mode_fill() // = default -@@ -360,8 +372,10 @@ impl HelloTriangleApplication { +@@ -372,7 +382,10 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default -- .fragment_shader(frag_shader_module.main_entry_point(), ()) - ); -+ .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) ++ .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() -+ )); ++ ) } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { diff --git a/src/bin/13_framebuffers.rs.diff b/src/bin/13_framebuffers.rs.diff index 0de266a..3f81dd6 100644 --- a/src/bin/13_framebuffers.rs.diff +++ b/src/bin/13_framebuffers.rs.diff @@ -9,38 +9,51 @@ }; use vulkano::descriptor::PipelineLayoutAbstract; -@@ -107,6 +109,8 @@ struct HelloTriangleApplication { - // graphics_pipeline: Option>, - graphics_pipeline: Option, - -+ swap_chain_framebuffers: Vec>, +@@ -104,6 +106,8 @@ struct HelloTriangleApplication { + // works when the concrete type of the graphics pipeline is visible + // to the command buffer. + graphics_pipeline: Arc, + - events_loop: Option, ++ swap_chain_framebuffers: Vec>, } -@@ -129,6 +133,7 @@ impl HelloTriangleApplication { - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); -+ self.create_framebuffers(); + impl HelloTriangleApplication { +@@ -122,6 +126,8 @@ impl HelloTriangleApplication { + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + ++ let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); ++ + Self { + instance, + debug_callback, +@@ -140,6 +146,8 @@ impl HelloTriangleApplication { + + render_pass, + graphics_pipeline, ++ ++ swap_chain_framebuffers, + } } - fn create_instance(&mut self) { -@@ -378,6 +383,17 @@ impl HelloTriangleApplication { - )); +@@ -388,6 +396,20 @@ impl HelloTriangleApplication { + ) } -+ fn create_framebuffers(&mut self) { -+ self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() ++ fn create_framebuffers( ++ swap_chain_images: &Vec>>, ++ render_pass: &Arc ++ ) -> Vec> { ++ swap_chain_images.iter() + .map(|image| { -+ let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) ++ let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } -+ ).collect::>(); ++ ).collect::>() + } + - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? From 74b946c4d2d0476fd4605d53624633c209042011 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 20:34:49 +0200 Subject: [PATCH 53/78] rework 05, 06, 08, 09, 10 --- Cargo.toml | 2 +- src/bin/05_window_surface.rs | 125 ++++++++-------- src/bin/06_swap_chain_creation.rs | 183 +++++++++++------------ src/bin/06_swap_chain_creation.rs.diff | 95 ++++++------ src/bin/08_graphics_pipeline.rs | 188 ++++++++++++------------ src/bin/08_graphics_pipeline.rs.diff | 23 +-- src/bin/09_shader_modules.rs | 191 ++++++++++++------------ src/bin/09_shader_modules.rs.diff | 11 +- src/bin/10_fixed_functions.rs | 195 +++++++++++++------------ src/bin/10_fixed_functions.rs.diff | 26 +++- src/bin/11_render_passes.rs | 1 - src/bin/11_render_passes.rs.diff | 62 ++++---- 12 files changed, 569 insertions(+), 533 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 63b0b83..db2ffd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/11_render_passes.rs" +path = "src/bin/05_window_surface.rs" diff --git a/src/bin/05_window_surface.rs b/src/bin/05_window_surface.rs index e11e765..b60973b 100644 --- a/src/bin/05_window_surface.rs +++ b/src/bin/05_window_surface.rs @@ -5,7 +5,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -49,40 +49,47 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + events_loop: EventsLoop, + surface: Arc>, - graphics_queue: Option>, - present_queue: Option>, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, - events_loop: Option, + graphics_queue: Arc, + present_queue: Arc, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + Self { + instance, + debug_callback, + + events_loop, + surface, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); + physical_device_index, + device, + + graphics_queue, + present_queue, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -100,15 +107,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -127,12 +132,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -140,23 +144,23 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); indices.is_complete() } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -164,7 +168,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -176,11 +180,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -199,30 +205,27 @@ impl HelloTriangleApplication { &DeviceExtensions::none(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -233,13 +236,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/06_swap_chain_creation.rs b/src/bin/06_swap_chain_creation.rs index 6a50a2d..b1afee9 100644 --- a/src/bin/06_swap_chain_creation.rs +++ b/src/bin/06_swap_chain_creation.rs @@ -5,7 +5,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -66,46 +66,56 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + events_loop: EventsLoop, + surface: Arc>, - graphics_queue: Option>, - present_queue: Option>, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + graphics_queue: Arc, + present_queue: Arc, - events_loop: Option, + swap_chain: Arc>, + swap_chain_images: Vec>>, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); + swap_chain, + swap_chain_images, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -123,15 +133,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -150,12 +158,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -163,23 +170,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -195,11 +203,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -220,7 +223,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -233,15 +236,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -253,17 +262,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -274,16 +283,13 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -291,7 +297,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -303,11 +309,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -326,30 +334,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -360,13 +365,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/06_swap_chain_creation.rs.diff b/src/bin/06_swap_chain_creation.rs.diff index 4eea71f..7df3053 100644 --- a/src/bin/06_swap_chain_creation.rs.diff +++ b/src/bin/06_swap_chain_creation.rs.diff @@ -32,35 +32,46 @@ #[cfg(all(debug_assertions))] const ENABLE_VALIDATION_LAYERS: bool = true; #[cfg(not(debug_assertions))] -@@ -61,6 +78,11 @@ struct HelloTriangleApplication { - graphics_queue: Option>, - present_queue: Option>, +@@ -62,6 +79,9 @@ struct HelloTriangleApplication { -+ swap_chain: Option>>, -+ swap_chain_images: Option>>>, -+ swap_chain_image_format: Option, -+ swap_chain_extent: Option<[u32; 2]>, + graphics_queue: Arc, + present_queue: Arc, + - events_loop: Option, ++ swap_chain: Arc>, ++ swap_chain_images: Vec>>, } -@@ -80,6 +102,7 @@ impl HelloTriangleApplication { - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); -+ self.create_swap_chain(); + impl HelloTriangleApplication { +@@ -74,6 +94,9 @@ impl HelloTriangleApplication { + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + ++ let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, ++ &device, &graphics_queue, &present_queue); ++ + Self { + instance, + debug_callback, +@@ -86,6 +109,9 @@ impl HelloTriangleApplication { + + graphics_queue, + present_queue, ++ ++ swap_chain, ++ swap_chain_images, + } } - fn create_instance(&mut self) { -@@ -153,7 +176,111 @@ impl HelloTriangleApplication { +@@ -157,7 +183,110 @@ impl HelloTriangleApplication { - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); - indices.is_complete() + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { -+ let capabilities = self.query_swap_chain_support(device); ++ let capabilities = surface.capabilities(*device) ++ .expect("failed to get surface capabilities"); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { @@ -76,11 +87,6 @@ + available_extensions.intersection(&device_extensions) == device_extensions + } + -+ fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { -+ self.surface.as_ref().unwrap().capabilities(*device) -+ .expect("failed to get surface capabilities") -+ } -+ + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -101,7 +107,7 @@ + } + } + -+ fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { ++ fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { @@ -114,15 +120,21 @@ + } + } + -+ fn create_swap_chain(&mut self) { -+ let instance = self.instance.as_ref().unwrap(); -+ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); -+ -+ let capabilities = self.query_swap_chain_support(&physical_device); ++ fn create_swap_chain( ++ instance: &Arc, ++ surface: &Arc>, ++ physical_device_index: usize, ++ device: &Arc, ++ graphics_queue: &Arc, ++ present_queue: &Arc, ++ ) -> (Arc>, Vec>>) { ++ let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); ++ let capabilities = surface.capabilities(physical_device) ++ .expect("failed to get surface capabilities"); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); -+ let extent = self.choose_swap_extent(&capabilities); ++ let extent = Self::choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -134,17 +146,17 @@ + .. ImageUsage::none() + }; + -+ let indices = self.find_queue_families(&physical_device); ++ let indices = Self::find_queue_families(&surface, &physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { -+ vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() ++ vec![graphics_queue, present_queue].as_slice().into() + } else { -+ self.graphics_queue.as_ref().unwrap().into() ++ graphics_queue.into() + }; + + let (swap_chain, images) = Swapchain::new( -+ self.device.as_ref().unwrap().clone(), -+ self.surface.as_ref().unwrap().clone(), ++ device.clone(), ++ surface.clone(), + image_count, + surface_format.0, // TODO: color space? + extent, @@ -155,17 +167,14 @@ + CompositeAlpha::Opaque, + present_mode, + true, // clipped -+ None, // old_swapchain ++ None, + ).expect("failed to create swap chain!"); + -+ self.swap_chain = Some(swap_chain); -+ self.swap_chain_images = Some(images); -+ self.swap_chain_image_format = Some(surface_format.0); -+ self.swap_chain_extent = Some(extent); ++ (swap_chain, images) } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { -@@ -196,7 +323,7 @@ impl HelloTriangleApplication { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { +@@ -202,7 +331,7 @@ impl HelloTriangleApplication { // for us internally. let (device, mut queues) = Device::new(physical_device, &Features::none(), @@ -173,4 +182,4 @@ + &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); diff --git a/src/bin/08_graphics_pipeline.rs b/src/bin/08_graphics_pipeline.rs index 25f49f1..945b549 100644 --- a/src/bin/08_graphics_pipeline.rs +++ b/src/bin/08_graphics_pipeline.rs @@ -5,7 +5,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -66,47 +66,58 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + events_loop: EventsLoop, + surface: Arc>, - graphics_queue: Option>, - present_queue: Option>, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + graphics_queue: Arc, + present_queue: Arc, - events_loop: Option, + swap_chain: Arc>, + swap_chain_images: Vec>>, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + Self::create_graphics_pipeline(&device); + + Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_graphics_pipeline(); + swap_chain, + swap_chain_images, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -124,15 +135,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -151,12 +160,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -164,23 +172,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -196,11 +205,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -221,7 +225,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -234,15 +238,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -254,17 +264,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -275,20 +285,17 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline(_device: &Arc) { } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -296,7 +303,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -308,11 +315,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -331,30 +340,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -365,13 +371,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/08_graphics_pipeline.rs.diff b/src/bin/08_graphics_pipeline.rs.diff index 2f053e8..31295aa 100644 --- a/src/bin/08_graphics_pipeline.rs.diff +++ b/src/bin/08_graphics_pipeline.rs.diff @@ -1,21 +1,22 @@ --- a/06_swap_chain_creation.rs +++ b/08_graphics_pipeline.rs -@@ -103,6 +103,7 @@ impl HelloTriangleApplication { - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); -+ self.create_graphics_pipeline(); - } +@@ -97,6 +97,8 @@ impl HelloTriangleApplication { + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); - fn create_instance(&mut self) { -@@ -283,6 +284,10 @@ impl HelloTriangleApplication { - self.swap_chain_extent = Some(extent); ++ Self::create_graphics_pipeline(&device); ++ + Self { + instance, + debug_callback, +@@ -289,6 +291,10 @@ impl HelloTriangleApplication { + (swap_chain, images) } -+ fn create_graphics_pipeline(&mut self) { ++ fn create_graphics_pipeline(_device: &Arc) { + + } + - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? diff --git a/src/bin/09_shader_modules.rs b/src/bin/09_shader_modules.rs index 2c005db..3a6a9ca 100644 --- a/src/bin/09_shader_modules.rs +++ b/src/bin/09_shader_modules.rs @@ -7,7 +7,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -68,47 +68,58 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + events_loop: EventsLoop, + surface: Arc>, - graphics_queue: Option>, - present_queue: Option>, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + graphics_queue: Arc, + present_queue: Arc, - events_loop: Option, + swap_chain: Arc>, + swap_chain_images: Vec>>, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + Self::create_graphics_pipeline(&device); + + Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_graphics_pipeline(); + swap_chain, + swap_chain_images, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -126,15 +137,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -153,12 +162,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -166,23 +174,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -198,11 +207,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -223,7 +227,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -236,15 +240,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -256,17 +266,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -277,16 +287,15 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + ) { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -303,14 +312,13 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let _vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let _frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -318,7 +326,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -330,11 +338,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -353,30 +363,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -387,13 +394,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/09_shader_modules.rs.diff b/src/bin/09_shader_modules.rs.diff index f1bb759..53ac2cf 100644 --- a/src/bin/09_shader_modules.rs.diff +++ b/src/bin/09_shader_modules.rs.diff @@ -7,10 +7,14 @@ extern crate vulkano_win; extern crate winit; -@@ -285,7 +287,27 @@ impl HelloTriangleApplication { +@@ -291,8 +293,29 @@ impl HelloTriangleApplication { + (swap_chain, images) } - fn create_graphics_pipeline(&mut self) { +- fn create_graphics_pipeline(device: &Arc) { ++ fn create_graphics_pipeline( ++ device: &Arc, ++ ) { + #[allow(unused)] + mod vertex_shader { + #[derive(VulkanoShader)] @@ -27,11 +31,10 @@ + struct Dummy; + } -+ let device = self.device.as_ref().unwrap(); + let _vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let _frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { diff --git a/src/bin/10_fixed_functions.rs b/src/bin/10_fixed_functions.rs index 259c8c6..cae0b66 100644 --- a/src/bin/10_fixed_functions.rs +++ b/src/bin/10_fixed_functions.rs @@ -7,7 +7,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -73,47 +73,58 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - surface: Option>>, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + events_loop: EventsLoop, + surface: Arc>, - graphics_queue: Option>, - present_queue: Option>, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + graphics_queue: Arc, + present_queue: Arc, - events_loop: Option, + swap_chain: Arc>, + swap_chain_images: Vec>>, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - // self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + + Self::create_graphics_pipeline(&device, swap_chain.dimensions()); - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_graphics_pipeline(); + Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + } } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -131,15 +142,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + } } fn check_validation_layer_support() -> bool { @@ -158,12 +167,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -171,23 +179,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -203,11 +212,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -228,7 +232,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -241,15 +245,21 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -261,17 +271,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -282,16 +292,16 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, // old_swapchain + None, ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + ) { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] @@ -308,13 +318,11 @@ impl HelloTriangleApplication { struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -328,6 +336,7 @@ impl HelloTriangleApplication { .triangle_list() .primitive_restart(false) .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) .depth_clamp(false) // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... .polygon_mode_fill() // = default @@ -336,11 +345,10 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .fragment_shader(frag_shader_module.main_entry_point(), ()) ); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -348,7 +356,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -360,11 +368,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -383,30 +393,27 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -417,13 +424,9 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // app.main_loop(); } diff --git a/src/bin/10_fixed_functions.rs.diff b/src/bin/10_fixed_functions.rs.diff index 3f2dd69..a721eda 100644 --- a/src/bin/10_fixed_functions.rs.diff +++ b/src/bin/10_fixed_functions.rs.diff @@ -12,10 +12,27 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -304,10 +309,35 @@ impl HelloTriangleApplication { +@@ -99,7 +104,7 @@ impl HelloTriangleApplication { + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + +- Self::create_graphics_pipeline(&device); ++ Self::create_graphics_pipeline(&device, swap_chain.dimensions()); + + Self { + instance, +@@ -295,6 +300,7 @@ impl HelloTriangleApplication { + + fn create_graphics_pipeline( + device: &Arc, ++ swap_chain_extent: [u32; 2], + ) { + #[allow(unused)] + mod vertex_shader { +@@ -312,10 +318,34 @@ impl HelloTriangleApplication { + struct Dummy; } - let device = self.device.as_ref().unwrap(); - let _vert_shader_module = vertex_shader::Shader::load(device.clone()) + let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); @@ -23,7 +40,6 @@ + let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); + -+ let swap_chain_extent = self.swap_chain_extent.unwrap(); + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], @@ -37,6 +53,7 @@ + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport ++ .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default @@ -45,8 +62,7 @@ + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default -+ .fragment_shader(frag_shader_module.main_entry_point(), ()) + ); } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs index cf0801f..a012958 100644 --- a/src/bin/11_render_passes.rs +++ b/src/bin/11_render_passes.rs @@ -327,7 +327,6 @@ impl HelloTriangleApplication { fn create_graphics_pipeline( device: &Arc, swap_chain_extent: [u32; 2], - _render_pass: &Arc, ) { #[allow(unused)] mod vertex_shader { diff --git a/src/bin/11_render_passes.rs.diff b/src/bin/11_render_passes.rs.diff index 0939604..4a15fe8 100644 --- a/src/bin/11_render_passes.rs.diff +++ b/src/bin/11_render_passes.rs.diff @@ -15,34 +15,45 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -90,6 +94,8 @@ struct HelloTriangleApplication { - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, +@@ -89,6 +93,8 @@ struct HelloTriangleApplication { -+ render_pass: Option>, + swap_chain: Arc>, + swap_chain_images: Vec>>, + - events_loop: Option, ++ render_pass: Arc, } -@@ -110,6 +116,7 @@ impl HelloTriangleApplication { - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); -+ self.create_render_pass(); - self.create_graphics_pipeline(); + impl HelloTriangleApplication { +@@ -104,7 +110,8 @@ impl HelloTriangleApplication { + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue); + +- Self::create_graphics_pipeline(&device, swap_chain.dimensions()); ++ let render_pass = Self::create_render_pass(&device, swap_chain.format()); ++ Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + Self { + instance, +@@ -121,6 +128,8 @@ impl HelloTriangleApplication { + + swap_chain, + swap_chain_images, ++ ++ render_pass, + } } -@@ -291,6 +298,23 @@ impl HelloTriangleApplication { - self.swap_chain_extent = Some(extent); +@@ -298,6 +307,23 @@ impl HelloTriangleApplication { + (swap_chain, images) } -+ fn create_render_pass(&mut self) { -+ self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), ++ fn create_render_pass(device: &Arc, color_format: Format) -> Arc { ++ Arc::new(single_pass_renderpass!(device.clone(), + attachments: { + color: { + load: Clear, + store: Store, -+ format: self.swap_chain.as_ref().unwrap().format(), ++ format: color_format, + samples: 1, + } + }, @@ -50,20 +61,9 @@ + color: [color], + depth_stencil: {} + } -+ ).unwrap())); ++ ).unwrap()) + } + - fn create_graphics_pipeline(&mut self) { - #[allow(unused)] - mod vertex_shader { -@@ -421,6 +445,10 @@ impl HelloTriangleApplication { - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } -+ -+ fn device(&self) -> &Arc { -+ self.device.as_ref().unwrap() -+ } - } - - fn main() { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], From d1ff49fe10c93a28fbcb4da6a996096f5f74e16b Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 20:53:30 +0200 Subject: [PATCH 54/78] 04 logical device, fix indentation error everywhere --- Cargo.toml | 2 +- src/bin/04_logical_device.rs | 135 +++++++++--------- src/bin/05_window_surface.rs | 14 +- src/bin/05_window_surface.rs.diff | 173 +++++++++++++++-------- src/bin/06_swap_chain_creation.rs | 14 +- src/bin/08_graphics_pipeline.rs | 14 +- src/bin/09_shader_modules.rs | 14 +- src/bin/10_fixed_functions.rs | 14 +- src/bin/11_render_passes.rs | 14 +- src/bin/12_graphics_pipeline_complete.rs | 14 +- src/bin/13_framebuffers.rs | 14 +- src/bin/14_command_buffers.rs | 14 +- src/bin/15_hello_triangle.rs | 14 +- src/bin/16_swap_chain_recreation.rs | 14 +- src/bin/18_vertex_buffer.rs | 12 +- src/bin/19_staging_buffer.rs | 12 +- src/bin/20_index_buffer.rs | 12 +- 17 files changed, 279 insertions(+), 221 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index db2ffd7..188301e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ winit = "0.17.1" [[bin]] name = "main" -path = "src/bin/05_window_surface.rs" +path = "src/bin/04_logical_device.rs" diff --git a/src/bin/04_logical_device.rs b/src/bin/04_logical_device.rs index 85a3291..32a0a48 100644 --- a/src/bin/04_logical_device.rs +++ b/src/bin/04_logical_device.rs @@ -4,7 +4,8 @@ extern crate winit; use std::sync::Arc; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; + use vulkano::instance::{ Instance, InstanceExtensions, @@ -42,47 +43,53 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, - graphics_queue: Option>, + events_loop: EventsLoop, - events_loop: Option, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, + + graphics_queue: Arc, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); - pub fn run(&mut self) { - self.init_window(); - self.init_vulkan(); - // self.main_loop(); - } + let events_loop = Self::init_window(); - fn init_window(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. - let _window_builder = WindowBuilder::new() - .with_title("Vulkan") - .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); - // .build(&self.events_loop.as_ref().unwrap()); - } + let physical_device_index = Self::pick_physical_device(&instance); + let (device, graphics_queue) = Self::create_logical_device( + &instance, physical_device_index); + + Self { + instance, + debug_callback, + + events_loop, + + physical_device_index, + device, - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.pick_physical_device(); - self.create_logical_device(); + graphics_queue, + } } - fn create_instance(&mut self) { +fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); + let _window_builder = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); + // .build(&self.events_loop.as_ref().unwrap()); + events_loop +} + +fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -100,15 +107,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { @@ -127,12 +132,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -140,23 +144,23 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(&device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(device); indices.is_complete() } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -172,12 +176,16 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + physical_device_index: usize, + ) -> (Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&physical_device); + let queue_family = physical_device.queue_families() .nth(indices.graphics_family as usize).unwrap(); + let queue_priority = 1.0; // NOTE: the tutorial recommends passing the validation layers as well @@ -188,15 +196,16 @@ impl HelloTriangleApplication { [(queue_family, queue_priority)].iter().cloned()) .expect("failed to create logical device!"); - self.device = Some(device); - self.graphics_queue = queues.next(); + let graphics_queue = queues.next().unwrap(); + + (device, graphics_queue) } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -207,13 +216,11 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + // app.main_loop(); } diff --git a/src/bin/05_window_surface.rs b/src/bin/05_window_surface.rs index b60973b..7e3ddf9 100644 --- a/src/bin/05_window_surface.rs +++ b/src/bin/05_window_surface.rs @@ -107,13 +107,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/05_window_surface.rs.diff b/src/bin/05_window_surface.rs.diff index be655b9..75f49b1 100644 --- a/src/bin/05_window_surface.rs.diff +++ b/src/bin/05_window_surface.rs.diff @@ -1,18 +1,18 @@ --- a/04_logical_device.rs +++ b/05_window_surface.rs -@@ -3,8 +3,11 @@ extern crate vulkano_win; +@@ -3,8 +3,10 @@ extern crate vulkano_win; extern crate winit; use std::sync::Arc; +use std::collections::HashSet; - use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +-use winit::{EventsLoop, WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; ++use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; -+ + use vulkano::instance::{ Instance, - InstanceExtensions, -@@ -16,6 +19,9 @@ use vulkano::instance::{ +@@ -17,6 +19,9 @@ use vulkano::instance::{ }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; use vulkano::device::{Device, DeviceExtensions, Queue}; @@ -22,7 +22,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -31,14 +37,15 @@ const ENABLE_VALIDATION_LAYERS: bool = false; +@@ -32,14 +37,15 @@ const ENABLE_VALIDATION_LAYERS: bool = false; struct QueueFamilyIndices { graphics_family: i32, @@ -40,70 +40,116 @@ } } -@@ -46,10 +53,13 @@ impl QueueFamilyIndices { - struct HelloTriangleApplication { - instance: Option>, +@@ -49,47 +55,41 @@ struct HelloTriangleApplication { debug_callback: Option, -+ surface: Option>>, -+ - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, - graphics_queue: Option>, -+ present_queue: Option>, + events_loop: EventsLoop, ++ surface: Arc>, - events_loop: Option, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, + + graphics_queue: Arc, ++ present_queue: Arc, } -@@ -60,24 +70,14 @@ impl HelloTriangleApplication { - } - pub fn run(&mut self) { -- self.init_window(); - self.init_vulkan(); - // self.main_loop(); + impl HelloTriangleApplication { + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); ++ let (events_loop, surface) = Self::create_surface(&instance); + +- let events_loop = Self::init_window(); +- +- let physical_device_index = Self::pick_physical_device(&instance); +- let (device, graphics_queue) = Self::create_logical_device( +- &instance, physical_device_index); ++ let physical_device_index = Self::pick_physical_device(&instance, &surface); ++ let (device, graphics_queue, present_queue) = Self::create_logical_device( ++ &instance, &surface, physical_device_index); + + Self { + instance, + debug_callback, + + events_loop, ++ surface, + + physical_device_index, + device, + + graphics_queue, ++ present_queue, + } } -- fn init_window(&mut self) { -- self.events_loop = Some(winit::EventsLoop::new()); -- // We'll leave this and the main loop commented out until we actually -- // have something to show on screen. -- let _window_builder = WindowBuilder::new() -- .with_title("Vulkan") -- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); -- // .build(&self.events_loop.as_ref().unwrap()); -- } +-fn init_window() -> EventsLoop { +- let events_loop = EventsLoop::new(); +- let _window_builder = WindowBuilder::new() +- .with_title("Vulkan") +- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); +- // .build(&self.events_loop.as_ref().unwrap()); +- events_loop +-} - - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); -+ self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); +-fn create_instance() -> Arc { ++ fn create_instance() -> Arc { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } +@@ -149,18 +149,18 @@ fn create_instance() -> Arc { + }).ok() + } + +- fn pick_physical_device(instance: &Arc) -> usize { ++ fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) +- .position(|device| Self::is_device_suitable(&device)) ++ .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") + } + +- fn is_device_suitable(device: &PhysicalDevice) -> bool { +- let indices = Self::find_queue_families(device); ++ fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { ++ let indices = Self::find_queue_families(surface, device); + indices.is_complete() } -@@ -164,6 +164,10 @@ impl HelloTriangleApplication { + +- fn find_queue_families(device: &PhysicalDevice) -> QueueFamilyIndices { ++ fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { +@@ -168,6 +168,10 @@ fn create_instance() -> Arc { indices.graphics_family = i as i32; } -+ if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { ++ if surface.is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + if indices.is_complete() { break; } -@@ -175,21 +179,43 @@ impl HelloTriangleApplication { - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); -+ - let indices = self.find_queue_families(&physical_device); +@@ -178,27 +182,43 @@ fn create_instance() -> Arc { + + fn create_logical_device( + instance: &Arc, ++ surface: &Arc>, + physical_device_index: usize, +- ) -> (Arc, Arc) { ++ ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); +- let indices = Self::find_queue_families(&physical_device); ++ let indices = Self::find_queue_families(&surface, &physical_device); + - let queue_family = physical_device.queue_families() - .nth(indices.graphics_family as usize).unwrap(); -+ + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); -+ + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) @@ -119,24 +165,29 @@ + &DeviceExtensions::none(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); -- self.graphics_queue = queues.next(); + let graphics_queue = queues.next().unwrap(); ++ let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); + -+ // TODO!: simplify -+ self.graphics_queue = queues -+ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); -+ self.present_queue = queues -+ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); ++ (device, graphics_queue, present_queue) + } -+ -+ fn create_surface(&mut self) { -+ self.events_loop = Some(winit::EventsLoop::new()); -+ self.surface = WindowBuilder::new() + +- (device, graphics_queue) ++ fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { ++ let events_loop = EventsLoop::new(); ++ let surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) -+ .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) -+ .expect("failed to create window surface!") -+ .into(); ++ .build_vk_surface(&events_loop, instance.clone()) ++ .expect("failed to create window surface!"); ++ (events_loop, surface) } #[allow(unused)] +@@ -220,7 +240,5 @@ fn create_instance() -> Arc { + + fn main() { + let mut _app = HelloTriangleApplication::initialize(); +- // We'll leave this and the main loop commented out until we actually +- // have something to show on screen. + // app.main_loop(); + } diff --git a/src/bin/06_swap_chain_creation.rs b/src/bin/06_swap_chain_creation.rs index b1afee9..81dda19 100644 --- a/src/bin/06_swap_chain_creation.rs +++ b/src/bin/06_swap_chain_creation.rs @@ -133,13 +133,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/08_graphics_pipeline.rs b/src/bin/08_graphics_pipeline.rs index 945b549..5eae536 100644 --- a/src/bin/08_graphics_pipeline.rs +++ b/src/bin/08_graphics_pipeline.rs @@ -135,13 +135,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/09_shader_modules.rs b/src/bin/09_shader_modules.rs index 3a6a9ca..207e695 100644 --- a/src/bin/09_shader_modules.rs +++ b/src/bin/09_shader_modules.rs @@ -137,13 +137,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/10_fixed_functions.rs b/src/bin/10_fixed_functions.rs index cae0b66..e0b2bcb 100644 --- a/src/bin/10_fixed_functions.rs +++ b/src/bin/10_fixed_functions.rs @@ -142,13 +142,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs index a012958..1bc166d 100644 --- a/src/bin/11_render_passes.rs +++ b/src/bin/11_render_passes.rs @@ -151,13 +151,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/12_graphics_pipeline_complete.rs b/src/bin/12_graphics_pipeline_complete.rs index a4f2e59..0ebe6c4 100644 --- a/src/bin/12_graphics_pipeline_complete.rs +++ b/src/bin/12_graphics_pipeline_complete.rs @@ -161,13 +161,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/13_framebuffers.rs b/src/bin/13_framebuffers.rs index 6605fea..77f3cae 100644 --- a/src/bin/13_framebuffers.rs +++ b/src/bin/13_framebuffers.rs @@ -169,13 +169,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/14_command_buffers.rs b/src/bin/14_command_buffers.rs index 5d8f190..63a4d38 100644 --- a/src/bin/14_command_buffers.rs +++ b/src/bin/14_command_buffers.rs @@ -182,13 +182,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/15_hello_triangle.rs b/src/bin/15_hello_triangle.rs index 31dcc12..454c3d1 100644 --- a/src/bin/15_hello_triangle.rs +++ b/src/bin/15_hello_triangle.rs @@ -183,13 +183,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs index 69f7c16..38811b8 100644 --- a/src/bin/16_swap_chain_recreation.rs +++ b/src/bin/16_swap_chain_recreation.rs @@ -192,13 +192,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - } + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs index 8d4ed0d..6110058 100644 --- a/src/bin/18_vertex_buffer.rs +++ b/src/bin/18_vertex_buffer.rs @@ -213,12 +213,12 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") } } diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs index c951196..9d70bff 100644 --- a/src/bin/19_staging_buffer.rs +++ b/src/bin/19_staging_buffer.rs @@ -213,12 +213,12 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") } } diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index 738801f..7c0444b 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -222,12 +222,12 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") } } From d66840b58104b0542fbc31d77217075d1c518600 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 21:11:09 +0200 Subject: [PATCH 55/78] rework rest --- Cargo.toml | 8 +- src/bin/00_base_code.rs | 35 +- src/bin/01_instance_creation.rs | 49 ++- src/bin/01_instance_creation.rs.diff | 86 +++++ src/bin/02_validation_layers.rs | 74 ++-- src/bin/02_validation_layers.rs.diff | 62 ++-- src/bin/03_physical_device_selection.rs | 100 +++--- src/bin/03_physical_device_selection.rs.diff | 64 ++-- src/bin/04_logical_device.rs | 18 +- src/bin/04_logical_device.rs.diff | 58 ++-- src/main.rs | 340 ++++++++++--------- 11 files changed, 503 insertions(+), 391 deletions(-) create mode 100644 src/bin/01_instance_creation.rs.diff diff --git a/Cargo.toml b/Cargo.toml index 188301e..503a9ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "vulkan-tutorial-rs" version = "0.1.0" authors = ["Benjamin Wasty "] -autobins = false +autobins = true [dependencies] vulkano = "0.10.0" @@ -11,6 +11,6 @@ image = "0.19.0" vulkano-win = "0.10.0" winit = "0.17.1" -[[bin]] -name = "main" -path = "src/bin/04_logical_device.rs" +# [[bin]] +# name = "main" +# path = "src/bin/00_base_code.rs" diff --git a/src/bin/00_base_code.rs b/src/bin/00_base_code.rs index be4b710..f8c5804 100644 --- a/src/bin/00_base_code.rs +++ b/src/bin/00_base_code.rs @@ -1,43 +1,38 @@ extern crate vulkano; extern crate winit; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - events_loop: Option, + events_loop: EventsLoop, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let events_loop = Self::init_window(); - pub fn run(&mut self) { - self.init_window(); - self.init_vulkan(); - self.main_loop(); + Self { + events_loop, + } } - fn init_window(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); + fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); let _window = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build(&self.events_loop.as_ref().unwrap()); - } - - fn init_vulkan(&mut self) { - + .build(&events_loop); + events_loop } fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -51,6 +46,6 @@ impl HelloTriangleApplication { } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); } diff --git a/src/bin/01_instance_creation.rs b/src/bin/01_instance_creation.rs index 2270f12..b453652 100644 --- a/src/bin/01_instance_creation.rs +++ b/src/bin/01_instance_creation.rs @@ -4,7 +4,8 @@ extern crate winit; use std::sync::Arc; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; + use vulkano::instance::{ Instance, InstanceExtensions, @@ -15,39 +16,33 @@ use vulkano::instance::{ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, - - events_loop: Option, + instance: Arc, + events_loop: EventsLoop, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let events_loop = Self::init_window(); - pub fn run(&mut self) { - self.init_window(); - self.init_vulkan(); - // self.main_loop(); + Self { + instance, + events_loop, + } } - fn init_window(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. + fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); let _window_builder = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); // .build(&self.events_loop.as_ref().unwrap()); + events_loop } - fn init_vulkan(&mut self) { - self.create_instance(); - } - - fn create_instance(&mut self) { + fn create_instance() -> Arc { let supported_extensions = InstanceExtensions::supported_by_core() .expect("failed to retrieve supported extensions"); println!("Supported extensions: {:?}", supported_extensions); @@ -60,15 +55,15 @@ impl HelloTriangleApplication { }; let required_extensions = vulkano_win::required_extensions(); - self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance")) + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -82,6 +77,8 @@ impl HelloTriangleApplication { } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + // app.main_loop(); } diff --git a/src/bin/01_instance_creation.rs.diff b/src/bin/01_instance_creation.rs.diff new file mode 100644 index 0000000..11836a8 --- /dev/null +++ b/src/bin/01_instance_creation.rs.diff @@ -0,0 +1,86 @@ +--- a/00_base_code.rs ++++ b/01_instance_creation.rs +@@ -1,34 +1,65 @@ + extern crate vulkano; ++extern crate vulkano_win; + extern crate winit; + ++use std::sync::Arc; ++ + use winit::{EventsLoop, WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; + ++use vulkano::instance::{ ++ Instance, ++ InstanceExtensions, ++ ApplicationInfo, ++ Version, ++}; ++ + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; + + #[allow(unused)] + struct HelloTriangleApplication { ++ instance: Arc, + events_loop: EventsLoop, + } + + impl HelloTriangleApplication { + pub fn initialize() -> Self { ++ let instance = Self::create_instance(); + let events_loop = Self::init_window(); + + Self { ++ instance, + events_loop, + } + } + +- fn init_window() -> EventsLoop { +- let events_loop = EventsLoop::new(); +- let _window = WindowBuilder::new() +- .with_title("Vulkan") +- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) +- .build(&events_loop); +- events_loop ++fn init_window() -> EventsLoop { ++ let events_loop = EventsLoop::new(); ++ let _window_builder = WindowBuilder::new() ++ .with_title("Vulkan") ++ .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); ++ // .build(&self.events_loop.as_ref().unwrap()); ++ events_loop ++} ++ ++fn create_instance() -> Arc { ++ let supported_extensions = InstanceExtensions::supported_by_core() ++ .expect("failed to retrieve supported extensions"); ++ println!("Supported extensions: {:?}", supported_extensions); ++ ++ let app_info = ApplicationInfo { ++ application_name: Some("Hello Triangle".into()), ++ application_version: Some(Version { major: 1, minor: 0, patch: 0 }), ++ engine_name: Some("No Engine".into()), ++ engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), ++ }; ++ ++ let required_extensions = vulkano_win::required_extensions(); ++ Instance::new(Some(&app_info), &required_extensions, None) ++ .expect("failed to create Vulkan instance") + } + ++ #[allow(unused)] + fn main_loop(&mut self) { + loop { + let mut done = false; +@@ -46,6 +77,8 @@ impl HelloTriangleApplication { + } + + fn main() { +- let mut app = HelloTriangleApplication::initialize(); +- app.main_loop(); ++ let mut _app = HelloTriangleApplication::initialize(); ++ // We'll leave this and the main loop commented out until we actually ++ // have something to show on screen. ++ // app.main_loop(); + } diff --git a/src/bin/02_validation_layers.rs b/src/bin/02_validation_layers.rs index 178e94a..77fb7c5 100644 --- a/src/bin/02_validation_layers.rs +++ b/src/bin/02_validation_layers.rs @@ -4,7 +4,8 @@ extern crate winit; use std::sync::Arc; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; + use vulkano::instance::{ Instance, InstanceExtensions, @@ -26,41 +27,39 @@ const ENABLE_VALIDATION_LAYERS: bool = true; #[cfg(not(debug_assertions))] const ENABLE_VALIDATION_LAYERS: bool = false; -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - events_loop: Option, + events_loop: EventsLoop, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + + let events_loop = Self::init_window(); + + Self { + instance, + debug_callback, - pub fn run(&mut self) { - self.init_window(); - self.init_vulkan(); - // self.main_loop(); + events_loop, + } } - fn init_window(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. + fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); let _window_builder = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); // .build(&self.events_loop.as_ref().unwrap()); + events_loop } - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - } - - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -78,15 +77,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { @@ -105,12 +102,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -118,16 +114,16 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } #[allow(unused)] fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -141,6 +137,8 @@ impl HelloTriangleApplication { } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + // app.main_loop(); } diff --git a/src/bin/02_validation_layers.rs.diff b/src/bin/02_validation_layers.rs.diff index d7b096f..e102e45 100644 --- a/src/bin/02_validation_layers.rs.diff +++ b/src/bin/02_validation_layers.rs.diff @@ -1,6 +1,6 @@ --- a/01_instance_creation.rs +++ b/02_validation_layers.rs -@@ -10,14 +10,26 @@ use vulkano::instance::{ +@@ -11,24 +11,41 @@ use vulkano::instance::{ InstanceExtensions, ApplicationInfo, Version, @@ -20,21 +20,32 @@ +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + - #[derive(Default)] + #[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, + debug_callback: Option, - - events_loop: Option, ++ + events_loop: EventsLoop, } -@@ -45,9 +57,14 @@ impl HelloTriangleApplication { - fn init_vulkan(&mut self) { - self.create_instance(); -+ self.setup_debug_callback(); + impl HelloTriangleApplication { + pub fn initialize() -> Self { + let instance = Self::create_instance(); ++ let debug_callback = Self::setup_debug_callback(&instance); ++ + let events_loop = Self::init_window(); + + Self { + instance, ++ debug_callback, ++ + events_loop, + } + } +@@ -43,6 +60,10 @@ impl HelloTriangleApplication { } - fn create_instance(&mut self) { + fn create_instance() -> Arc { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } @@ -42,24 +53,22 @@ let supported_extensions = InstanceExtensions::supported_by_core() .expect("failed to retrieve supported extensions"); println!("Supported extensions: {:?}", supported_extensions); -@@ -59,9 +76,51 @@ impl HelloTriangleApplication { +@@ -54,9 +75,48 @@ impl HelloTriangleApplication { engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), }; - let required_extensions = vulkano_win::required_extensions(); -- self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) -- .expect("failed to create Vulkan instance")) +- Instance::new(Some(&app_info), &required_extensions, None) +- .expect("failed to create Vulkan instance") + let required_extensions = Self::get_required_extensions(); + -+ let instance = -+ if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { -+ Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) -+ .expect("failed to create Vulkan instance") -+ } else { -+ Instance::new(Some(&app_info), &required_extensions, None) -+ .expect("failed to create Vulkan instance") -+ }; -+ self.instance = Some(instance); ++ if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { ++ Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) ++ .expect("failed to create Vulkan instance") ++ } else { ++ Instance::new(Some(&app_info), &required_extensions, None) ++ .expect("failed to create Vulkan instance") ++ } + } + + fn check_validation_layer_support() -> bool { @@ -78,12 +87,11 @@ + extensions + } + -+ fn setup_debug_callback(&mut self) { ++ fn setup_debug_callback(instance: &Arc) -> Option { + if !ENABLE_VALIDATION_LAYERS { -+ return; ++ return None; + } + -+ let instance = self.instance.as_ref().unwrap(); + let msg_types = MessageTypes { + error: true, + warning: true, @@ -91,9 +99,9 @@ + information: false, + debug: true, + }; -+ self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { ++ DebugCallback::new(&instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); -+ }).ok(); ++ }).ok() } #[allow(unused)] diff --git a/src/bin/03_physical_device_selection.rs b/src/bin/03_physical_device_selection.rs index 1cb9481..af72ac9 100644 --- a/src/bin/03_physical_device_selection.rs +++ b/src/bin/03_physical_device_selection.rs @@ -4,7 +4,8 @@ extern crate winit; use std::sync::Arc; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; + use vulkano::instance::{ Instance, InstanceExtensions, @@ -40,43 +41,45 @@ impl QueueFamilyIndices { } } -#[derive(Default)] +#[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - events_loop: Option, + events_loop: EventsLoop, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + + let events_loop = Self::init_window(); + + let physical_device_index = Self::pick_physical_device(&instance); + + Self { + instance, + debug_callback, - pub fn run(&mut self) { - self.init_window(); - self.init_vulkan(); - // self.main_loop(); + events_loop, + + physical_device_index, + } } - fn init_window(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. + fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); let _window_builder = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); // .build(&self.events_loop.as_ref().unwrap()); + events_loop } - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.pick_physical_device(); - } - - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -94,15 +97,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { @@ -121,12 +122,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -134,23 +134,23 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(&device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(device); indices.is_complete() } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -170,7 +170,7 @@ impl HelloTriangleApplication { fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -181,13 +181,11 @@ impl HelloTriangleApplication { } } } - - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut _app = HelloTriangleApplication::initialize(); + // We'll leave this and the main loop commented out until we actually + // have something to show on screen. + // app.main_loop(); } diff --git a/src/bin/03_physical_device_selection.rs.diff b/src/bin/03_physical_device_selection.rs.diff index 672538d..eee3881 100644 --- a/src/bin/03_physical_device_selection.rs.diff +++ b/src/bin/03_physical_device_selection.rs.diff @@ -1,6 +1,6 @@ --- a/02_validation_layers.rs +++ b/03_physical_device_selection.rs -@@ -11,6 +11,7 @@ use vulkano::instance::{ +@@ -12,6 +12,7 @@ use vulkano::instance::{ ApplicationInfo, Version, layers_list, @@ -8,7 +8,7 @@ }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -@@ -26,10 +27,24 @@ const ENABLE_VALIDATION_LAYERS: bool = true; +@@ -27,12 +28,27 @@ const ENABLE_VALIDATION_LAYERS: bool = true; #[cfg(not(debug_assertions))] const ENABLE_VALIDATION_LAYERS: bool = false; @@ -25,38 +25,49 @@ + } +} + - #[derive(Default)] + #[allow(unused)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, debug_callback: Option, -+ physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - events_loop: Option, + events_loop: EventsLoop, ++ ++ physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) } -@@ -58,6 +73,7 @@ impl HelloTriangleApplication { - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); -+ self.pick_physical_device(); + + impl HelloTriangleApplication { +@@ -42,11 +58,15 @@ impl HelloTriangleApplication { + + let events_loop = Self::init_window(); + ++ let physical_device_index = Self::pick_physical_device(&instance); ++ + Self { + instance, + debug_callback, + + events_loop, ++ ++ physical_device_index, + } } - fn create_instance(&mut self) { -@@ -123,6 +139,33 @@ impl HelloTriangleApplication { - }).ok(); +@@ -119,6 +139,33 @@ impl HelloTriangleApplication { + }).ok() } -+ fn pick_physical_device(&mut self) { -+ self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) -+ .position(|device| self.is_device_suitable(&device)) -+ .expect("failed to find a suitable GPU!"); ++ fn pick_physical_device(instance: &Arc) -> usize { ++ PhysicalDevice::enumerate(&instance) ++ .position(|device| Self::is_device_suitable(&device)) ++ .expect("failed to find a suitable GPU!") + } + -+ fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { -+ let indices = self.find_queue_families(device); ++ fn is_device_suitable(device: &PhysicalDevice) -> bool { ++ let indices = Self::find_queue_families(device); + indices.is_complete() + } + -+ fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { ++ fn find_queue_families(device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { @@ -75,14 +86,3 @@ #[allow(unused)] fn main_loop(&mut self) { loop { -@@ -138,6 +181,10 @@ impl HelloTriangleApplication { - } - } - } -+ -+ fn instance(&self) -> &Arc { -+ self.instance.as_ref().unwrap() -+ } - } - - fn main() { diff --git a/src/bin/04_logical_device.rs b/src/bin/04_logical_device.rs index 32a0a48..d66abb4 100644 --- a/src/bin/04_logical_device.rs +++ b/src/bin/04_logical_device.rs @@ -80,16 +80,16 @@ impl HelloTriangleApplication { } } -fn init_window() -> EventsLoop { - let events_loop = EventsLoop::new(); - let _window_builder = WindowBuilder::new() - .with_title("Vulkan") - .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); - // .build(&self.events_loop.as_ref().unwrap()); - events_loop -} + fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); + let _window_builder = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); + // .build(&self.events_loop.as_ref().unwrap()); + events_loop + } -fn create_instance() -> Arc { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } diff --git a/src/bin/04_logical_device.rs.diff b/src/bin/04_logical_device.rs.diff index 51abdac..2673387 100644 --- a/src/bin/04_logical_device.rs.diff +++ b/src/bin/04_logical_device.rs.diff @@ -1,6 +1,6 @@ --- a/03_physical_device_selection.rs +++ b/04_logical_device.rs -@@ -12,8 +12,10 @@ use vulkano::instance::{ +@@ -13,8 +13,10 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, @@ -11,34 +11,49 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -45,6 +47,9 @@ struct HelloTriangleApplication { - instance: Option>, - debug_callback: Option, +@@ -49,6 +51,9 @@ struct HelloTriangleApplication { + events_loop: EventsLoop, + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) -+ device: Option>, ++ device: Arc, + -+ graphics_queue: Option>, - - events_loop: Option, ++ graphics_queue: Arc, } -@@ -74,6 +79,7 @@ impl HelloTriangleApplication { - self.create_instance(); - self.setup_debug_callback(); - self.pick_physical_device(); -+ self.create_logical_device(); + + impl HelloTriangleApplication { +@@ -59,6 +64,8 @@ impl HelloTriangleApplication { + let events_loop = Self::init_window(); + + let physical_device_index = Self::pick_physical_device(&instance); ++ let (device, graphics_queue) = Self::create_logical_device( ++ &instance, physical_device_index); + + Self { + instance, +@@ -67,6 +74,9 @@ impl HelloTriangleApplication { + events_loop, + + physical_device_index, ++ device, ++ ++ graphics_queue, + } } - fn create_instance(&mut self) { -@@ -166,6 +172,26 @@ impl HelloTriangleApplication { +@@ -166,6 +176,31 @@ impl HelloTriangleApplication { indices } -+ fn create_logical_device(&mut self) { -+ let instance = self.instance.as_ref().unwrap(); -+ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); -+ let indices = self.find_queue_families(&physical_device); ++ fn create_logical_device( ++ instance: &Arc, ++ physical_device_index: usize, ++ ) -> (Arc, Arc) { ++ let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); ++ let indices = Self::find_queue_families(&physical_device); ++ + let queue_family = physical_device.queue_families() + .nth(indices.graphics_family as usize).unwrap(); ++ + let queue_priority = 1.0; + + // NOTE: the tutorial recommends passing the validation layers as well @@ -49,8 +64,9 @@ + [(queue_family, queue_priority)].iter().cloned()) + .expect("failed to create logical device!"); + -+ self.device = Some(device); -+ self.graphics_queue = queues.next(); ++ let graphics_queue = queues.next().unwrap(); ++ ++ (device, graphics_queue) + } + #[allow(unused)] diff --git a/src/main.rs b/src/main.rs index 5a3f856..7c0444b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ extern crate winit; use std::sync::Arc; use std::collections::HashSet; -use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; use vulkano::instance::{ @@ -118,65 +118,93 @@ fn indices() -> [u16; 6] { [0, 1, 2, 2, 3, 0] } -#[derive(Default)] struct HelloTriangleApplication { - instance: Option>, + instance: Arc, + #[allow(unused)] debug_callback: Option, - surface: Option>>, + + events_loop: EventsLoop, + surface: Arc>, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, + device: Arc, - graphics_queue: Option>, - present_queue: Option>, + graphics_queue: Arc, + present_queue: Arc, - swap_chain: Option>>, - swap_chain_images: Option>>>, - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, + swap_chain: Arc>, + swap_chain_images: Vec>>, - render_pass: Option>, - graphics_pipeline: Option>, + render_pass: Arc, + graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, - vertex_buffer: Option>, - index_buffer: Option + Send + Sync>>, + vertex_buffer: Arc, + index_buffer: Arc + Send + Sync>, command_buffers: Vec>, previous_frame_end: Option>, recreate_swap_chain: bool, - - events_loop: Option, } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); - pub fn run(&mut self) { - self.init_vulkan(); - self.main_loop(); - } + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_vertex_buffer(); - self.create_index_buffer(); - self.create_command_buffers(); - self.create_sync_objects(); + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + let index_buffer = Self::create_index_buffer(&graphics_queue); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + vertex_buffer, + index_buffer, + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, + }; + + app.create_command_buffers(); + app } - fn create_instance(&mut self) { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") } @@ -194,15 +222,13 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); - let instance = - if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) - .expect("failed to create Vulkan instance") - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") - }; - self.instance = Some(instance); + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } } fn check_validation_layer_support() -> bool { @@ -221,12 +247,11 @@ impl HelloTriangleApplication { extensions } - fn setup_debug_callback(&mut self) { + fn setup_debug_callback(instance: &Arc) -> Option { if !ENABLE_VALIDATION_LAYERS { - return; + return None; } - let instance = self.instance.as_ref().unwrap(); let msg_types = MessageTypes { error: true, warning: true, @@ -234,23 +259,24 @@ impl HelloTriangleApplication { information: false, debug: true, }; - self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { + DebugCallback::new(&instance, msg_types, |msg| { println!("validation layer: {:?}", msg.description); - }).ok(); + }).ok() } - fn pick_physical_device(&mut self) { - self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) - .position(|device| self.is_device_suitable(&device)) - .expect("failed to find a suitable GPU!"); + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") } - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); let extensions_supported = Self::check_device_extension_support(device); let swap_chain_adequate = if extensions_supported { - let capabilities = self.query_swap_chain_support(device); + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); !capabilities.supported_formats.is_empty() && capabilities.present_modes.iter().next().is_some() } else { @@ -266,11 +292,6 @@ impl HelloTriangleApplication { available_extensions.intersection(&device_extensions) == device_extensions } - fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { - self.surface.as_ref().unwrap().capabilities(*device) - .expect("failed to get surface capabilities") - } - fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) @@ -291,7 +312,7 @@ impl HelloTriangleApplication { } } - fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { if let Some(current_extent) = capabilities.current_extent { return current_extent } else { @@ -304,15 +325,22 @@ impl HelloTriangleApplication { } } - fn create_swap_chain(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let capabilities = self.query_swap_chain_support(&physical_device); + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); - let extent = self.choose_swap_extent(&capabilities); + let extent = Self::choose_swap_extent(&capabilities); let mut image_count = capabilities.min_image_count + 1; if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { @@ -324,17 +352,17 @@ impl HelloTriangleApplication { .. ImageUsage::none() }; - let indices = self.find_queue_families(&physical_device); + let indices = Self::find_queue_families(&surface, &physical_device); let sharing: SharingMode = if indices.graphics_family != indices.present_family { - vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() + vec![graphics_queue, present_queue].as_slice().into() } else { - self.graphics_queue.as_ref().unwrap().into() + graphics_queue.into() }; let (swap_chain, images) = Swapchain::new( - self.device.as_ref().unwrap().clone(), - self.surface.as_ref().unwrap().clone(), + device.clone(), + surface.clone(), image_count, surface_format.0, // TODO: color space? extent, @@ -345,22 +373,19 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - self.swap_chain.as_ref(), // old_swapchain + old_swapchain.as_ref() ).expect("failed to create swap chain!"); - self.swap_chain = Some(swap_chain); - self.swap_chain_images = Some(images); - self.swap_chain_image_format = Some(surface_format.0); - self.swap_chain_extent = Some(extent); + (swap_chain, images) } - fn create_render_pass(&mut self) { - self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), attachments: { color: { load: Clear, store: Store, - format: self.swap_chain.as_ref().unwrap().format(), + format: color_format, samples: 1, } }, @@ -368,15 +393,19 @@ impl HelloTriangleApplication { color: [color], depth_stencil: {} } - ).unwrap())); + ).unwrap()) } - fn create_graphics_pipeline(&mut self) { + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { #[allow(unused)] mod vertex_shader { #[derive(VulkanoShader)] #[ty = "vertex"] - #[path = "src/shaders/shader.vert"] + #[path = "src/bin/17_shader_vertexbuffer.vert"] struct Dummy; } @@ -384,17 +413,15 @@ impl HelloTriangleApplication { mod fragment_shader { #[derive(VulkanoShader)] #[ty = "fragment"] - #[path = "src/shaders/shader.frag"] + #[path = "src/bin/17_shader_vertexbuffer.frag"] struct Dummy; } - let device = self.device.as_ref().unwrap(); let vert_shader_module = vertex_shader::Shader::load(device.clone()) .expect("failed to create vertex shader module!"); let frag_shader_module = fragment_shader::Shader::load(device.clone()) .expect("failed to create fragment shader module!"); - let swap_chain_extent = self.swap_chain_extent.unwrap(); let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; let viewport = Viewport { origin: [0.0, 0.0], @@ -402,7 +429,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; - self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() + Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer::() .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() @@ -417,53 +444,55 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default - .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap() - )); + ) } - fn create_framebuffers(&mut self) { - self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() .map(|image| { - let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap()); fba } - ).collect::>(); + ).collect::>() } - fn create_vertex_buffer(&mut self) { + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { let (buffer, future) = ImmutableBuffer::from_iter( vertices().iter().cloned(), BufferUsage::vertex_buffer(), - self.graphics_queue().clone()) + graphics_queue.clone()) .unwrap(); future.flush().unwrap(); - self.vertex_buffer = Some(buffer); + buffer } - fn create_index_buffer(&mut self) { + fn create_index_buffer(graphics_queue: &Arc) -> Arc + Send + Sync> { let (buffer, future) = ImmutableBuffer::from_iter( indices().iter().cloned(), BufferUsage::index_buffer(), - self.graphics_queue().clone()) + graphics_queue.clone()) .unwrap(); future.flush().unwrap(); - self.index_buffer = Some(buffer); + buffer } fn create_command_buffers(&mut self) { - let queue_family = self.graphics_queue.as_ref().unwrap().family(); - let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); + let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() .map(|framebuffer| { - Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() - .draw_indexed(graphics_pipeline.clone(), &DynamicState::none(), - vec![self.vertex_buffer.as_ref().unwrap().clone()], - self.index_buffer.as_ref().unwrap().clone(), (), ()) + .draw_indexed(self.graphics_pipeline.clone(), &DynamicState::none(), + vec![self.vertex_buffer.clone()], + self.index_buffer.clone(), (), ()) .unwrap() .end_render_pass() .unwrap() @@ -473,12 +502,11 @@ impl HelloTriangleApplication { .collect(); } - fn create_sync_objects(&mut self) { - self.previous_frame_end = - Some(Box::new(sync::now(self.device().clone())) as Box); + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { @@ -486,7 +514,7 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } - if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { + if surface.is_supported(queue_family).unwrap() { indices.present_family = i as i32; } @@ -498,11 +526,13 @@ impl HelloTriangleApplication { indices } - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); - - let indices = self.find_queue_families(&physical_device); + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); let families = [indices.graphics_family, indices.present_family]; use std::iter::FromIterator; @@ -521,23 +551,20 @@ impl HelloTriangleApplication { &device_extensions(), queue_families) .expect("failed to create logical device!"); - self.device = Some(device); + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); - // TODO!: simplify - self.graphics_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); - self.present_queue = queues - .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); + (device, graphics_queue, present_queue) } - fn create_surface(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); - self.surface = WindowBuilder::new() + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) - .expect("failed to create window surface!") - .into(); + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) } #[allow(unused)] @@ -546,7 +573,7 @@ impl HelloTriangleApplication { self.draw_frame(); let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -566,8 +593,7 @@ impl HelloTriangleApplication { self.recreate_swap_chain = false; } - let swap_chain = self.swap_chain().clone(); - let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { self.recreate_swap_chain = true; @@ -576,14 +602,13 @@ impl HelloTriangleApplication { Err(err) => panic!("{:?}", err) }; - let queue = self.graphics_queue().clone(); let command_buffer = self.command_buffers[image_index].clone(); let future = self.previous_frame_end.take().unwrap() .join(acquire_future) - .then_execute(queue.clone(), command_buffer) + .then_execute(self.graphics_queue.clone(), command_buffer) .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) .then_signal_fence_and_flush(); match future { @@ -593,44 +618,33 @@ impl HelloTriangleApplication { Err(vulkano::sync::FlushError::OutOfDate) => { self.recreate_swap_chain = true; self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } Err(e) => { println!("{:?}", e); self.previous_frame_end - = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); } } } fn recreate_swap_chain(&mut self) { - unsafe { self.device().wait().unwrap(); } + unsafe { self.device.wait().unwrap(); } - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); - } + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } - - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } - - fn graphics_queue(&self) -> &Arc { - self.graphics_queue.as_ref().unwrap() - } - - fn swap_chain(&self) -> &Arc> { - self.swap_chain.as_ref().unwrap() + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); + Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); } } fn main() { - let mut app = HelloTriangleApplication::new(); - app.run(); + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); } From c538770920f68741152376b68764fd8c31e39b06 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 21:31:48 +0200 Subject: [PATCH 56/78] rework readme --- README.md | 1242 +------------------------- src/bin/01_instance_creation.rs.diff | 31 +- src/bin/11_render_passes.rs | 2 +- 3 files changed, 62 insertions(+), 1213 deletions(-) diff --git a/README.md b/README.md index 0aba408..c550bd5 100644 --- a/README.md +++ b/README.md @@ -76,23 +76,15 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Base_code ```rust extern crate vulkano; -#[derive(Default)] struct HelloTriangleApplication { } impl HelloTriangleApplication { - pub fn new() -> Self { - Default::default() - } - - pub fn run(&mut self) { - self.init_vulkan(); - self.main_loop(); - } - - fn init_vulkan(&mut self) { + pub fn initialize() -> Self { + Self { + } } fn main_loop(&mut self) { @@ -102,7 +94,7 @@ impl HelloTriangleApplication { fn main() { let mut app = HelloTriangleApplication::new(); - app.run(); + app.main_loop(); } ``` @@ -124,27 +116,34 @@ use winit::{WindowBuilder, dpi::LogicalSize}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; + +struct HelloTriangleApplication { + events_loop: EventsLoop, +} ``` ```rust - pub fn run(&mut self) { - self.init_window(); - self.init_vulkan(); - self.main_loop(); + pub fn initialize() -> Self { + let events_loop = Self::init_window(); + + Self { + events_loop, + } } - fn init_window(&mut self) { - self.events_loop = Some(winit::EventsLoop::new()); + fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); let _window = WindowBuilder::new() .with_title("Vulkan") .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build(&self.events_loop.as_ref().unwrap()); + .build(&events_loop); + events_loop } ``` ```rust fn main_loop(&mut self) { loop { let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { + self.events_loop.poll_events(|ev| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, _ => () @@ -183,16 +182,22 @@ use vulkano::instance::{ ```rust struct HelloTriangleApplication { instance: Option>, - ... + events_loop: EventsLoop, } ``` ```rust - fn init_vulkan(&mut self) { - self.create_instance(); - } + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let events_loop = Self::init_window(); + + Self { + instance, + events_loop, + } + } ``` ```rust - fn create_instance(&mut self) { + fn create_instance() -> Arc { let supported_extensions = InstanceExtensions::supported_by_core() .expect("failed to retrieve supported extensions"); println!("Supported extensions: {:?}", supported_extensions); @@ -205,8 +210,8 @@ struct HelloTriangleApplication { }; let required_extensions = vulkano_win::required_extensions(); - self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance")) + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") } ``` @@ -215,109 +220,7 @@ struct HelloTriangleApplication { #### Validation layers https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers -
-Diff - -```diff ---- a/01_instance_creation.rs -+++ b/02_validation_layers.rs -@@ -10,14 +10,26 @@ use vulkano::instance::{ - InstanceExtensions, - ApplicationInfo, - Version, -+ layers_list, - }; -+use vulkano::instance::debug::{DebugCallback, MessageTypes}; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; - -+const VALIDATION_LAYERS: &[&str] = &[ -+ "VK_LAYER_LUNARG_standard_validation" -+]; -+ -+#[cfg(all(debug_assertions))] -+const ENABLE_VALIDATION_LAYERS: bool = true; -+#[cfg(not(debug_assertions))] -+const ENABLE_VALIDATION_LAYERS: bool = false; -+ - #[derive(Default)] - struct HelloTriangleApplication { - instance: Option>, -+ debug_callback: Option, - - events_loop: Option, - } -@@ -45,9 +57,14 @@ impl HelloTriangleApplication { - - fn init_vulkan(&mut self) { - self.create_instance(); -+ self.setup_debug_callback(); - } - - fn create_instance(&mut self) { -+ if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { -+ println!("Validation layers requested, but not available!") -+ } -+ - let supported_extensions = InstanceExtensions::supported_by_core() - .expect("failed to retrieve supported extensions"); - println!("Supported extensions: {:?}", supported_extensions); -@@ -59,9 +76,51 @@ impl HelloTriangleApplication { - engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), - }; - -- let required_extensions = vulkano_win::required_extensions(); -- self.instance = Some(Instance::new(Some(&app_info), &required_extensions, None) -- .expect("failed to create Vulkan instance")) -+ let required_extensions = Self::get_required_extensions(); -+ -+ let instance = -+ if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { -+ Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) -+ .expect("failed to create Vulkan instance") -+ } else { -+ Instance::new(Some(&app_info), &required_extensions, None) -+ .expect("failed to create Vulkan instance") -+ }; -+ self.instance = Some(instance); -+ } -+ -+ fn check_validation_layer_support() -> bool { -+ let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); -+ VALIDATION_LAYERS.iter() -+ .all(|layer_name| layers.contains(&layer_name.to_string())) -+ } -+ -+ fn get_required_extensions() -> InstanceExtensions { -+ let mut extensions = vulkano_win::required_extensions(); -+ if ENABLE_VALIDATION_LAYERS { -+ // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano -+ extensions.ext_debug_report = true; -+ } -+ -+ extensions -+ } -+ -+ fn setup_debug_callback(&mut self) { -+ if !ENABLE_VALIDATION_LAYERS { -+ return; -+ } -+ -+ let instance = self.instance.as_ref().unwrap(); -+ let msg_types = MessageTypes { -+ error: true, -+ warning: true, -+ performance_warning: true, -+ information: false, -+ debug: true, -+ }; -+ self.debug_callback = DebugCallback::new(instance, msg_types, |msg| { -+ println!("validation layer: {:?}", msg.description); -+ }).ok(); - } -``` -
+[Diff](src/bin/02_validation_layers.rs.diff) [Complete code](src/bin/02_validation_layers.rs) @@ -325,99 +228,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers #### Physical devices and queue families https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families -
-Diff - -```diff ---- a/02_validation_layers.rs -+++ b/03_physical_device_selection.rs -@@ -11,6 +11,7 @@ use vulkano::instance::{ - ApplicationInfo, - Version, - layers_list, -+ PhysicalDevice, - }; - use vulkano::instance::debug::{DebugCallback, MessageTypes}; - -@@ -26,10 +27,25 @@ const ENABLE_VALIDATION_LAYERS: bool = true; - #[cfg(not(debug_assertions))] - const ENABLE_VALIDATION_LAYERS: bool = false; - -+struct QueueFamilyIndices { -+ graphics_family: i32, -+ present_family: i32, -+} -+impl QueueFamilyIndices { -+ fn new() -> Self { -+ Self { graphics_family: -1, present_family: -1 } -+ } -+ -+ fn is_complete(&self) -> bool { -+ self.graphics_family >= 0 && self.present_family >= 0 -+ } -+} -+ - #[derive(Default)] - struct HelloTriangleApplication { - instance: Option>, - debug_callback: Option, -+ physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - - events_loop: Option, - } -@@ -58,6 +74,7 @@ impl HelloTriangleApplication { - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); -+ self.pick_physical_device(); - } - - fn create_instance(&mut self) { -@@ -123,6 +140,33 @@ impl HelloTriangleApplication { - }).ok(); - } - -+ fn pick_physical_device(&mut self) { -+ self.physical_device_index = PhysicalDevice::enumerate(&self.instance()) -+ .position(|device| self.is_device_suitable(&device)) -+ .expect("failed to find a suitable GPU!"); -+ } -+ -+ fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { -+ let indices = self.find_queue_families(device); -+ indices.is_complete() -+ } -+ -+ fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { -+ let mut indices = QueueFamilyIndices::new(); -+ // TODO: replace index with id to simplify? -+ for (i, queue_family) in device.queue_families().enumerate() { -+ if queue_family.supports_graphics() { -+ indices.graphics_family = i as i32; -+ } -+ -+ if indices.is_complete() { -+ break; -+ } -+ } -+ -+ indices -+ } -+ - #[allow(unused)] - fn main_loop(&mut self) { - loop { -@@ -138,6 +182,10 @@ impl HelloTriangleApplication { - } - } - } -+ -+ fn instance(&self) -> &Arc { -+ self.instance.as_ref().unwrap() -+ } - } -``` -
+[Diff](src/bin/03_physical_device_selection.rs.diff) [Complete code](src/bin/03_physical_device_selection.rs) @@ -425,67 +236,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_ #### Logical device and queues https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues -
-Diff - -```diff ---- a/03_physical_device_selection.rs -+++ b/04_logical_device.rs -@@ -12,8 +12,10 @@ use vulkano::instance::{ - Version, - layers_list, - PhysicalDevice, -+ Features - }; - use vulkano::instance::debug::{DebugCallback, MessageTypes}; -+use vulkano::device::{Device, DeviceExtensions, Queue}; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; -@@ -45,6 +47,9 @@ struct HelloTriangleApplication { - instance: Option>, - debug_callback: Option, - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) -+ device: Option>, -+ -+ graphics_queue: Option>, - - events_loop: Option, - } -@@ -74,6 +79,7 @@ impl HelloTriangleApplication { - self.create_instance(); - self.setup_debug_callback(); - self.pick_physical_device(); -+ self.create_logical_device(); - } - - fn create_instance(&mut self) { -@@ -166,6 +172,26 @@ impl HelloTriangleApplication { - indices - } - -+ fn create_logical_device(&mut self) { -+ let instance = self.instance.as_ref().unwrap(); -+ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); -+ let indices = self.find_queue_families(&physical_device); -+ let queue_family = physical_device.queue_families() -+ .nth(indices.graphics_family as usize).unwrap(); -+ let queue_priority = 1.0; -+ -+ // NOTE: the tutorial recommends passing the validation layers as well -+ // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that -+ // for us internally. -+ -+ let (device, mut queues) = Device::new(physical_device, &Features::none(), &DeviceExtensions::none(), -+ [(queue_family, queue_priority)].iter().cloned()) -+ .expect("failed to create logical device!"); -+ -+ self.device = Some(device); -+ self.graphics_queue = queues.next(); -+ } -+ -``` -
+[Diff](src/bin/04_logical_device.rs.diff) [Complete code](src/bin/04_logical_device.rs) @@ -493,339 +244,15 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues #### Window surface https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface -
-Diff - -```diff ---- a/04_logical_device.rs -+++ b/05_window_surface.rs -@@ -3,8 +3,11 @@ extern crate vulkano_win; - extern crate winit; - - use std::sync::Arc; -+use std::collections::HashSet; - - use winit::{ WindowBuilder, dpi::LogicalSize, Event, WindowEvent}; -+use vulkano_win::VkSurfaceBuild; -+ - use vulkano::instance::{ - Instance, - InstanceExtensions, -@@ -16,6 +19,9 @@ use vulkano::instance::{ - }; - use vulkano::instance::debug::{DebugCallback, MessageTypes}; - use vulkano::device::{Device, DeviceExtensions, Queue}; -+use vulkano::swapchain::{ -+ Surface, -+}; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; -@@ -31,14 +37,15 @@ const ENABLE_VALIDATION_LAYERS: bool = false; - - struct QueueFamilyIndices { - graphics_family: i32, -+ present_family: i32, - } - impl QueueFamilyIndices { - fn new() -> Self { -- Self { graphics_family: -1 } -+ Self { graphics_family: -1, present_family: -1 } - } - - fn is_complete(&self) -> bool { -- self.graphics_family >= 0 -+ self.graphics_family >= 0 && self.present_family >= 0 - } - } - -@@ -46,10 +53,13 @@ impl QueueFamilyIndices { - struct HelloTriangleApplication { - instance: Option>, - debug_callback: Option, -+ surface: Option>>, -+ - physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) - device: Option>, - - graphics_queue: Option>, -+ present_queue: Option>, - - events_loop: Option, - } -@@ -60,24 +70,14 @@ impl HelloTriangleApplication { - } - pub fn run(&mut self) { -- self.init_window(); - self.init_vulkan(); - // self.main_loop(); - } - -- fn init_window(&mut self) { -- self.events_loop = Some(winit::EventsLoop::new()); -- // We'll leave this and the main loop commented out until we actually -- // have something to show on screen. -- let _window_builder = WindowBuilder::new() -- .with_title("Vulkan") -- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); -- // .build(&self.events_loop.as_ref().unwrap()); -- } -- - fn init_vulkan(&mut self) { - self.create_instance(); - self.setup_debug_callback(); -+ self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); - } -@@ -164,6 +164,10 @@ impl HelloTriangleApplication { - indices.graphics_family = i as i32; - } - -+ if self.surface.as_ref().unwrap().is_supported(queue_family).unwrap() { -+ indices.present_family = i as i32; -+ } -+ - if indices.is_complete() { - break; - } -@@ -175,21 +179,43 @@ impl HelloTriangleApplication { - fn create_logical_device(&mut self) { - let instance = self.instance.as_ref().unwrap(); - let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); -+ - let indices = self.find_queue_families(&physical_device); -- let queue_family = physical_device.queue_families() -- .nth(indices.graphics_family as usize).unwrap(); -+ -+ let families = [indices.graphics_family, indices.present_family]; -+ use std::iter::FromIterator; -+ let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); -+ - let queue_priority = 1.0; -+ let queue_families = unique_queue_families.iter().map(|i| { -+ (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) -+ }); - - // NOTE: the tutorial recommends passing the validation layers as well - // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that - // for us internally. - -- let (device, mut queues) = Device::new(physical_device, &Features::none(), &DeviceExtensions::none(), -- [(queue_family, queue_priority)].iter().cloned()) -+ let (device, mut queues) = Device::new(physical_device, &Features::none(), -+ &DeviceExtensions::none(), queue_families) - .expect("failed to create logical device!"); - - self.device = Some(device); -- self.graphics_queue = queues.next(); -+ -+ // TODO!: simplify -+ self.graphics_queue = queues -+ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.graphics_family as usize).unwrap().id()); -+ self.present_queue = queues -+ .find(|q| q.family().id() == physical_device.queue_families().nth(indices.present_family as usize).unwrap().id()); -+ } -+ -+ fn create_surface(&mut self) { -+ self.events_loop = Some(winit::EventsLoop::new()); -+ self.surface = WindowBuilder::new() -+ .with_title("Vulkan") -+ .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) -+ .build_vk_surface(&self.events_loop.as_ref().unwrap(), self.instance().clone()) -+ .expect("failed to create window surface!") -+ .into(); - } -``` -
+[Diff](src/bin/05_window_surface.rs.diff) [Complete code](src/bin/05_window_surface.rs) #### Swap chain https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain -
-Diff - -```diff ---- a/05_window_surface.rs -+++ b/06_swap_chain_creation.rs -@@ -21,7 +21,16 @@ use vulkano::instance::debug::{DebugCallback, MessageTypes}; - use vulkano::device::{Device, DeviceExtensions, Queue}; - use vulkano::swapchain::{ - Surface, -+ Capabilities, -+ ColorSpace, -+ SupportedPresentModes, -+ PresentMode, -+ Swapchain, -+ CompositeAlpha, - }; -+use vulkano::format::Format; -+use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; -+use vulkano::sync::SharingMode; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; -@@ -30,6 +39,14 @@ const VALIDATION_LAYERS: &[&str] = &[ - "VK_LAYER_LUNARG_standard_validation" - ]; - -+/// Required device extensions -+fn device_extensions() -> DeviceExtensions { -+ DeviceExtensions { -+ khr_swapchain: true, -+ .. vulkano::device::DeviceExtensions::none() -+ } -+} -+ - #[cfg(all(debug_assertions))] - const ENABLE_VALIDATION_LAYERS: bool = true; - #[cfg(not(debug_assertions))] -@@ -61,6 +78,11 @@ struct HelloTriangleApplication { - graphics_queue: Option>, - present_queue: Option>, - -+ swap_chain: Option>>, -+ swap_chain_images: Option>>>, -+ swap_chain_image_format: Option, -+ swap_chain_extent: Option<[u32; 2]>, -+ - events_loop: Option, - } - -@@ -80,6 +102,7 @@ impl HelloTriangleApplication { - self.create_surface(); - self.pick_physical_device(); - self.create_logical_device(); -+ self.create_swap_chain(); - } - - fn create_instance(&mut self) { -@@ -153,7 +176,111 @@ impl HelloTriangleApplication { - - fn is_device_suitable(&self, device: &PhysicalDevice) -> bool { - let indices = self.find_queue_families(device); -- indices.is_complete() -+ let extensions_supported = Self::check_device_extension_support(device); -+ -+ let swap_chain_adequate = if extensions_supported { -+ let capabilities = self.query_swap_chain_support(device); -+ !capabilities.supported_formats.is_empty() && -+ capabilities.present_modes.iter().next().is_some() -+ } else { -+ false -+ }; -+ -+ indices.is_complete() && extensions_supported && swap_chain_adequate -+ } -+ -+ fn check_device_extension_support(device: &PhysicalDevice) -> bool { -+ let available_extensions = DeviceExtensions::supported_by_device(*device); -+ let device_extensions = device_extensions(); -+ available_extensions.intersection(&device_extensions) == device_extensions -+ } -+ -+ fn query_swap_chain_support(&self, device: &PhysicalDevice) -> Capabilities { -+ self.surface.as_ref().unwrap().capabilities(*device) -+ .expect("failed to get surface capabilities") -+ } -+ -+ fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { -+ // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be -+ // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) -+ *available_formats.iter() -+ .find(|(format, color_space)| -+ *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear -+ ) -+ .unwrap_or_else(|| &available_formats[0]) -+ } -+ -+ fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { -+ if available_present_modes.mailbox { -+ PresentMode::Mailbox -+ } else if available_present_modes.immediate { -+ PresentMode::Immediate -+ } else { -+ PresentMode::Fifo -+ } -+ } -+ -+ fn choose_swap_extent(&self, capabilities: &Capabilities) -> [u32; 2] { -+ if let Some(current_extent) = capabilities.current_extent { -+ return current_extent -+ } else { -+ let mut actual_extent = [WIDTH, HEIGHT]; -+ actual_extent[0] = capabilities.min_image_extent[0] -+ .max(capabilities.max_image_extent[0].min(actual_extent[0])); -+ actual_extent[1] = capabilities.min_image_extent[1] -+ .max(capabilities.max_image_extent[1].min(actual_extent[1])); -+ actual_extent -+ } -+ } -+ -+ fn create_swap_chain(&mut self) { -+ let instance = self.instance.as_ref().unwrap(); -+ let physical_device = PhysicalDevice::from_index(instance, self.physical_device_index).unwrap(); -+ -+ let capabilities = self.query_swap_chain_support(&physical_device); -+ -+ let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); -+ let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); -+ let extent = self.choose_swap_extent(&capabilities); -+ -+ let mut image_count = capabilities.min_image_count + 1; -+ if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { -+ image_count = capabilities.max_image_count.unwrap(); -+ } -+ -+ let image_usage = ImageUsage { -+ color_attachment: true, -+ .. ImageUsage::none() -+ }; -+ -+ let indices = self.find_queue_families(&physical_device); -+ -+ let sharing: SharingMode = if indices.graphics_family != indices.present_family { -+ vec![self.graphics_queue.as_ref().unwrap(), self.present_queue.as_ref().unwrap()].as_slice().into() -+ } else { -+ self.graphics_queue.as_ref().unwrap().into() -+ }; -+ -+ let (swap_chain, images) = Swapchain::new( -+ self.device.as_ref().unwrap().clone(), -+ self.surface.as_ref().unwrap().clone(), -+ image_count, -+ surface_format.0, // TODO: color space? -+ extent, -+ 1, // layers -+ image_usage, -+ sharing, -+ capabilities.current_transform, -+ CompositeAlpha::Opaque, -+ present_mode, -+ true, // clipped -+ None, // old_swapchain -+ ).expect("failed to create swap chain!"); -+ -+ self.swap_chain = Some(swap_chain); -+ self.swap_chain_images = Some(images); -+ self.swap_chain_image_format = Some(surface_format.0); -+ self.swap_chain_extent = Some(extent); - } - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { -@@ -196,7 +323,7 @@ impl HelloTriangleApplication { - // for us internally. - - let (device, mut queues) = Device::new(physical_device, &Features::none(), -- &DeviceExtensions::none(), queue_families) -+ &device_extensions(), queue_families) - .expect("failed to create logical device!"); - - self.device = Some(device); -``` -
+[Diff](src/bin/06_swap_chain_creation.rs.diff) [Complete code](src/bin/06_swap_chain_creation.rs) @@ -837,29 +264,8 @@ We're skipping this section because image views are handled by Vulkano and can b ### Graphics pipeline basics #### Introduction https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics -
-Diff - -```diff ---- a/06_swap_chain_creation.rs -+++ b/08_graphics_pipeline.rs -@@ -103,6 +103,7 @@ impl HelloTriangleApplication { - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); -+ self.create_graphics_pipeline(); - } - - fn create_instance(&mut self) { -@@ -283,6 +284,10 @@ impl HelloTriangleApplication { - self.swap_chain_extent = Some(extent); - } -+ fn create_graphics_pipeline(&mut self) { -+ -+ } -``` -
+[Diff](src/bin/08_graphics_pipeline.rs.diff) [Complete code](src/bin/08_graphics_pipeline.rs) @@ -867,260 +273,29 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use [vulkano-shader-derive](https://docs.rs/crate/vulkano-shader-derive/) to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the [runtime shaders](https://github.com/vulkano-rs/vulkano/blob/master/examples/src/bin/runtime-shader.rs) example of Vulkano. -
-Diff - -```diff ---- a/08_graphics_pipeline.rs -+++ b/09_shader_modules.rs -@@ -1,4 +1,6 @@ - extern crate vulkano; -+#[macro_use] -+extern crate vulkano_shader_derive; - extern crate vulkano_win; - extern crate winit; - -@@ -285,7 +287,27 @@ impl HelloTriangleApplication { - } - fn create_graphics_pipeline(&mut self) { -+ #[allow(unused)] -+ mod vertex_shader { -+ #[derive(VulkanoShader)] -+ #[ty = "vertex"] -+ #[path = "src/bin/09_shader_base.vert"] -+ struct Dummy; -+ } -+ -+ #[allow(unused)] -+ mod fragment_shader { -+ #[derive(VulkanoShader)] -+ #[ty = "fragment"] -+ #[path = "src/bin/09_shader_base.frag"] -+ struct Dummy; -+ } - -+ let device = self.device.as_ref().unwrap(); -+ let _vert_shader_module = vertex_shader::Shader::load(device.clone()) -+ .expect("failed to create vertex shader module!"); -+ let _frag_shader_module = fragment_shader::Shader::load(device.clone()) -+ .expect("failed to create fragment shader module!"); - } -``` -
+[Diff](src/bin/09_shader_modules.rs.diff) [Rust code](src/bin/09_shader_modules.rs) / [Vertex shader](src/bin/09_shader_base.vert) / [Fragment shader](src/bin/09_shader_base.frag) #### Fixed functions https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Fixed_functions -
-Diff - -```diff ---- a/09_shader_modules.rs -+++ b/10_fixed_functions.rs -@@ -33,6 +33,11 @@ use vulkano::swapchain::{ - use vulkano::format::Format; - use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; - use vulkano::sync::SharingMode; -+use vulkano::pipeline::{ -+ GraphicsPipeline, -+ vertex::BufferlessDefinition, -+ viewport::Viewport, -+}; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; -@@ -304,10 +309,35 @@ impl HelloTriangleApplication { - } - - let device = self.device.as_ref().unwrap(); -- let _vert_shader_module = vertex_shader::Shader::load(device.clone()) -+ let vert_shader_module = vertex_shader::Shader::load(device.clone()) - .expect("failed to create vertex shader module!"); -- let _frag_shader_module = fragment_shader::Shader::load(device.clone()) -+ let frag_shader_module = fragment_shader::Shader::load(device.clone()) - .expect("failed to create fragment shader module!"); -+ -+ let swap_chain_extent = self.swap_chain_extent.unwrap(); -+ let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; -+ let viewport = Viewport { -+ origin: [0.0, 0.0], -+ dimensions, -+ depth_range: 0.0 .. 1.0, -+ }; -+ -+ let _pipeline_builder = Arc::new(GraphicsPipeline::start() -+ .vertex_input(BufferlessDefinition {}) -+ .vertex_shader(vert_shader_module.main_entry_point(), ()) -+ .triangle_list() -+ .primitive_restart(false) -+ .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport -+ .depth_clamp(false) -+ // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... -+ .polygon_mode_fill() // = default -+ .line_width(1.0) // = default -+ .cull_mode_back() -+ .front_face_clockwise() -+ // NOTE: no depth_bias here, but on pipeline::raster::Rasterization -+ .blend_pass_through() // = default -+ .fragment_shader(frag_shader_module.main_entry_point(), ()) -+ ); - } -``` -
+[Diff](src/bin/10_fixed_functions.rs.diff) [Complete code](src/bin/10_fixed_functions.rs) #### Render passes https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Render_passes -
-Diff - -```diff ---- a/10_fixed_functions.rs -+++ b/11_render_passes.rs -@@ -1,3 +1,4 @@ -+#[macro_use] - extern crate vulkano; - #[macro_use] - extern crate vulkano_shader_derive; -@@ -38,6 +39,9 @@ use vulkano::pipeline::{ - vertex::BufferlessDefinition, - viewport::Viewport, - }; -+use vulkano::framebuffer::{ -+ RenderPassAbstract, -+}; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; -@@ -90,6 +94,8 @@ struct HelloTriangleApplication { - swap_chain_image_format: Option, - swap_chain_extent: Option<[u32; 2]>, - -+ render_pass: Option>, -+ - events_loop: Option, - } - -@@ -110,6 +116,7 @@ impl HelloTriangleApplication { - self.pick_physical_device(); - self.create_logical_device(); - self.create_swap_chain(); -+ self.create_render_pass(); - self.create_graphics_pipeline(); - } - -@@ -291,6 +298,23 @@ impl HelloTriangleApplication { - self.swap_chain_extent = Some(extent); - } - -+ fn create_render_pass(&mut self) { -+ self.render_pass = Some(Arc::new(single_pass_renderpass!(self.device().clone(), -+ attachments: { -+ color: { -+ load: Clear, -+ store: Store, -+ format: self.swap_chain.as_ref().unwrap().format(), -+ samples: 1, -+ } -+ }, -+ pass: { -+ color: [color], -+ depth_stencil: {} -+ } -+ ).unwrap())); -+ } -+ - fn create_graphics_pipeline(&mut self) { - #[allow(unused)] - mod vertex_shader { -@@ -421,6 +445,10 @@ impl HelloTriangleApplication { - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } -+ -+ fn device(&self) -> &Arc { -+ self.device.as_ref().unwrap() -+ } - } -``` -
+[Diff](src/bin/11_render_passes.rs.diff) [Complete code](src/bin/11_render_passes.rs) + #### Conclusion https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Conclusion -
-Diff - -```diff ---- a/11_render_passes.rs -+++ b/12_graphics_pipeline_complete.rs -@@ -41,7 +41,9 @@ use vulkano::pipeline::{ - }; - use vulkano::framebuffer::{ - RenderPassAbstract, -+ Subpass, - }; -+use vulkano::descriptor::PipelineLayoutAbstract; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; -@@ -77,6 +79,8 @@ impl QueueFamilyIndices { - } - } - -+type ConcreteGraphicsPipeline = Arc, Arc>>; -+ - #[derive(Default)] - struct HelloTriangleApplication { - instance: Option>, -@@ -95,6 +99,13 @@ struct HelloTriangleApplication { - swap_chain_extent: Option<[u32; 2]>, - - render_pass: Option>, -+ // NOTE: We need to the full type of -+ // self.graphics_pipeline, because `BufferlessVertices` only -+ // works when the concrete type of the graphics pipeline is visible -+ // to the command buffer. -+ // TODO: check if can be simplified later in tutorial -+ // graphics_pipeline: Option>, -+ graphics_pipeline: Option, - - events_loop: Option, - } -@@ -346,12 +357,13 @@ impl HelloTriangleApplication { - depth_range: 0.0 .. 1.0, - }; - -- let _pipeline_builder = Arc::new(GraphicsPipeline::start() -+ self.graphics_pipeline = Some(Arc::new(GraphicsPipeline::start() - .vertex_input(BufferlessDefinition {}) - .vertex_shader(vert_shader_module.main_entry_point(), ()) - .triangle_list() - .primitive_restart(false) - .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport -+ .fragment_shader(frag_shader_module.main_entry_point(), ()) - .depth_clamp(false) - // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... - .polygon_mode_fill() // = default -@@ -360,8 +372,10 @@ impl HelloTriangleApplication { - .front_face_clockwise() - // NOTE: no depth_bias here, but on pipeline::raster::Rasterization - .blend_pass_through() // = default -- .fragment_shader(frag_shader_module.main_entry_point(), ()) -- ); -+ .render_pass(Subpass::from(self.render_pass.as_ref().unwrap().clone(), 0).unwrap()) -+ .build(device.clone()) -+ .unwrap() -+ )); - } -``` -
+[Diff](src/bin/12_graphics_pipeline_complete.rs.diff) [Complete code](src/bin/12_graphics_pipeline_complete.rs) @@ -1129,55 +304,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Conclusi #### Framebuffers https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Framebuffers -
-Diff - -```diff ---- a/12_graphics_pipeline_complete.rs -+++ b/13_framebuffers.rs -@@ -42,6 +42,8 @@ use vulkano::pipeline::{ - use vulkano::framebuffer::{ - RenderPassAbstract, - Subpass, -+ FramebufferAbstract, -+ Framebuffer, - }; - use vulkano::descriptor::PipelineLayoutAbstract; - -@@ -107,6 +109,8 @@ struct HelloTriangleApplication { - // graphics_pipeline: Option>, - graphics_pipeline: Option, - -+ swap_chain_framebuffers: Vec>, -+ - events_loop: Option, - } - -@@ -129,6 +133,7 @@ impl HelloTriangleApplication { - self.create_swap_chain(); - self.create_render_pass(); - self.create_graphics_pipeline(); -+ self.create_framebuffers(); - } - - fn create_instance(&mut self) { -@@ -378,6 +383,17 @@ impl HelloTriangleApplication { - )); - } - -+ fn create_framebuffers(&mut self) { -+ self.swap_chain_framebuffers = self.swap_chain_images.as_ref().unwrap().iter() -+ .map(|image| { -+ let fba: Arc = Arc::new(Framebuffer::start(self.render_pass.as_ref().unwrap().clone()) -+ .add(image.clone()).unwrap() -+ .build().unwrap()); -+ fba -+ } -+ ).collect::>(); -+ } -+ -``` -
+[Diff](src/bin/13_framebuffers.rs.diff) [Complete code](src/bin/13_framebuffers.rs) @@ -1186,287 +313,21 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Command_buffers We're skipping the first part because Vulkano maintains a [`StandardCommandPool`](https://docs.rs/vulkano/0.10.0/vulkano/command_buffer/pool/standard/struct.StandardCommandPool.html). -
-Diff - -```diff ---- a/13_framebuffers.rs -+++ b/14_command_buffers.rs -@@ -37,6 +37,7 @@ use vulkano::sync::SharingMode; - use vulkano::pipeline::{ - GraphicsPipeline, - vertex::BufferlessDefinition, -+ vertex::BufferlessVertices, - viewport::Viewport, - }; - use vulkano::framebuffer::{ -@@ -46,6 +47,11 @@ use vulkano::framebuffer::{ - Framebuffer, - }; - use vulkano::descriptor::PipelineLayoutAbstract; -+use vulkano::command_buffer::{ -+ AutoCommandBuffer, -+ AutoCommandBufferBuilder, -+ DynamicState, -+}; - - const WIDTH: u32 = 800; - const HEIGHT: u32 = 600; -@@ -111,6 +117,8 @@ struct HelloTriangleApplication { - - swap_chain_framebuffers: Vec>, - -+ command_buffers: Vec>, -+ - events_loop: Option, - } - -@@ -134,6 +142,7 @@ impl HelloTriangleApplication { - self.create_render_pass(); - self.create_graphics_pipeline(); - self.create_framebuffers(); -+ self.create_command_buffers(); - } - - fn create_instance(&mut self) { -@@ -394,6 +403,27 @@ impl HelloTriangleApplication { - ).collect::>(); - } - -+ fn create_command_buffers(&mut self) { -+ let queue_family = self.graphics_queue.as_ref().unwrap().family(); -+ let graphics_pipeline = self.graphics_pipeline.as_ref().unwrap(); -+ self.command_buffers = self.swap_chain_framebuffers.iter() -+ .map(|framebuffer| { -+ let vertices = BufferlessVertices { vertices: 3, instances: 1 }; -+ Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device().clone(), queue_family) -+ .unwrap() -+ .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) -+ .unwrap() -+ .draw(graphics_pipeline.clone(), &DynamicState::none(), -+ vertices, (), ()) -+ .unwrap() -+ .end_render_pass() -+ .unwrap() -+ .build() -+ .unwrap()) -+ }) -+ .collect(); -+ } -+ -``` -
+[Diff](src/bin/14_command_buffers.rs.diff) [Complete code](src/bin/14_command_buffers.rs) #### Rendering and presentation https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation -
-Diff - -```diff ---- a/14_command_buffers.rs -+++ b/15_hello_triangle.rs -@@ -30,10 +30,11 @@ use vulkano::swapchain::{ - PresentMode, - Swapchain, - CompositeAlpha, -+ acquire_next_image - }; - use vulkano::format::Format; - use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; --use vulkano::sync::SharingMode; -+use vulkano::sync::{SharingMode, GpuFuture}; - use vulkano::pipeline::{ - GraphicsPipeline, - vertex::BufferlessDefinition, -@@ -129,7 +130,7 @@ impl HelloTriangleApplication { - - pub fn run(&mut self) { - self.init_vulkan(); -- // self.main_loop(); -+ self.main_loop(); - } - - fn init_vulkan(&mut self) { -@@ -489,6 +490,8 @@ impl HelloTriangleApplication { - #[allow(unused)] - fn main_loop(&mut self) { - loop { -+ self.draw_frame(); -+ - let mut done = false; - self.events_loop.as_mut().unwrap().poll_events(|ev| { - match ev { -@@ -502,6 +505,22 @@ impl HelloTriangleApplication { - } - } - -+ fn draw_frame(&mut self) { -+ let swap_chain = self.swap_chain().clone(); -+ let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); -+ -+ let queue = self.graphics_queue().clone(); -+ let command_buffer = self.command_buffers[image_index].clone(); -+ -+ let future = acquire_future -+ .then_execute(queue.clone(), command_buffer) -+ .unwrap() -+ .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) -+ .then_signal_fence_and_flush() -+ .unwrap(); -+ future.wait(None).unwrap(); -+ } -+ - fn instance(&self) -> &Arc { - self.instance.as_ref().unwrap() - } -@@ -509,6 +528,14 @@ impl HelloTriangleApplication { - fn device(&self) -> &Arc { - self.device.as_ref().unwrap() - } -+ -+ fn graphics_queue(&self) -> &Arc { -+ self.graphics_queue.as_ref().unwrap() -+ } -+ -+ fn swap_chain(&self) -> &Arc> { -+ self.swap_chain.as_ref().unwrap() -+ } - } -``` -
+[Diff](src/bin/15_hello_triangle.rs.diff) [Complete code](src/bin/15_hello_triangle.rs) ### Swapchain recreation https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation -
-Diff - -```diff ---- a/15_hello_triangle.rs -+++ b/16_swap_chain_recreation.rs -@@ -30,11 +30,12 @@ use vulkano::swapchain::{ - PresentMode, - Swapchain, - CompositeAlpha, -- acquire_next_image -+ acquire_next_image, -+ AcquireError, - }; - use vulkano::format::Format; - use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; --use vulkano::sync::{SharingMode, GpuFuture}; -+use vulkano::sync::{self, SharingMode, GpuFuture}; - use vulkano::pipeline::{ - GraphicsPipeline, - vertex::BufferlessDefinition, -@@ -120,6 +121,9 @@ struct HelloTriangleApplication { - - command_buffers: Vec>, - -+ previous_frame_end: Option>, -+ recreate_swap_chain: bool, -+ - events_loop: Option, - } - -@@ -144,6 +148,7 @@ impl HelloTriangleApplication { - self.create_graphics_pipeline(); - self.create_framebuffers(); - self.create_command_buffers(); -+ self.create_sync_objects(); - } - - fn create_instance(&mut self) { -@@ -315,7 +320,7 @@ impl HelloTriangleApplication { - CompositeAlpha::Opaque, - present_mode, - true, // clipped -- None, // old_swapchain -+ self.swap_chain.as_ref(), // old_swapchain - ).expect("failed to create swap chain!"); - - self.swap_chain = Some(swap_chain); -@@ -425,6 +430,11 @@ impl HelloTriangleApplication { - .collect(); - } - -+ fn create_sync_objects(&mut self) { -+ self.previous_frame_end = -+ Some(Box::new(sync::now(self.device().clone())) as Box); -+ } -+ - fn find_queue_families(&self, device: &PhysicalDevice) -> QueueFamilyIndices { - let mut indices = QueueFamilyIndices::new(); - // TODO: replace index with id to simplify? -@@ -506,19 +516,58 @@ impl HelloTriangleApplication { - } - - fn draw_frame(&mut self) { -+ self.previous_frame_end.as_mut().unwrap().cleanup_finished(); -+ -+ if self.recreate_swap_chain { -+ self.recreate_swap_chain(); -+ self.recreate_swap_chain = false; -+ } -+ - let swap_chain = self.swap_chain().clone(); -- let (image_index, acquire_future) = acquire_next_image(swap_chain.clone(), None).unwrap(); -+ let (image_index, acquire_future) = match acquire_next_image(swap_chain.clone(), None) { -+ Ok(r) => r, -+ Err(AcquireError::OutOfDate) => { -+ self.recreate_swap_chain = true; -+ return; -+ }, -+ Err(err) => panic!("{:?}", err) -+ }; - - let queue = self.graphics_queue().clone(); - let command_buffer = self.command_buffers[image_index].clone(); - -- let future = acquire_future -+ let future = self.previous_frame_end.take().unwrap() -+ .join(acquire_future) - .then_execute(queue.clone(), command_buffer) - .unwrap() - .then_swapchain_present(queue.clone(), swap_chain.clone(), image_index) -- .then_signal_fence_and_flush() -- .unwrap(); -- future.wait(None).unwrap(); -+ .then_signal_fence_and_flush(); -+ -+ match future { -+ Ok(future) => { -+ self.previous_frame_end = Some(Box::new(future) as Box<_>); -+ } -+ Err(vulkano::sync::FlushError::OutOfDate) => { -+ self.recreate_swap_chain = true; -+ self.previous_frame_end -+ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); -+ } -+ Err(e) => { -+ println!("{:?}", e); -+ self.previous_frame_end -+ = Some(Box::new(vulkano::sync::now(self.device().clone())) as Box<_>); -+ } -+ } -+ } -+ -+ fn recreate_swap_chain(&mut self) { -+ unsafe { self.device().wait().unwrap(); } -+ -+ self.create_swap_chain(); -+ self.create_render_pass(); -+ self.create_graphics_pipeline(); -+ self.create_framebuffers(); -+ self.create_command_buffers(); - } -``` -
+[Diff](src/bin/16_swap_chain_recreation.rs.diff) [Complete code](src/bin/16_swap_chain_recreation.rs) @@ -1477,12 +338,3 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation ## Loading models (*TODO*) ## Generating Mipmaps (*TODO*) ## Multisampling (*TODO*) - - diff --git a/src/bin/01_instance_creation.rs.diff b/src/bin/01_instance_creation.rs.diff index 11836a8..bde4224 100644 --- a/src/bin/01_instance_creation.rs.diff +++ b/src/bin/01_instance_creation.rs.diff @@ -19,7 +19,8 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; - #[allow(unused)] +-// #[allow(unused)] ++#[allow(unused)] struct HelloTriangleApplication { + instance: Arc, events_loop: EventsLoop, @@ -36,23 +37,19 @@ } } -- fn init_window() -> EventsLoop { -- let events_loop = EventsLoop::new(); + fn init_window() -> EventsLoop { + let events_loop = EventsLoop::new(); - let _window = WindowBuilder::new() -- .with_title("Vulkan") ++ let _window_builder = WindowBuilder::new() + .with_title("Vulkan") - .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) - .build(&events_loop); -- events_loop -+fn init_window() -> EventsLoop { -+ let events_loop = EventsLoop::new(); -+ let _window_builder = WindowBuilder::new() -+ .with_title("Vulkan") -+ .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); -+ // .build(&self.events_loop.as_ref().unwrap()); -+ events_loop -+} -+ -+fn create_instance() -> Arc { ++ .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); ++ // .build(&self.events_loop.as_ref().unwrap()); + events_loop + } + ++ fn create_instance() -> Arc { + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); @@ -67,8 +64,8 @@ + let required_extensions = vulkano_win::required_extensions(); + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") - } - ++ } ++ + #[allow(unused)] fn main_loop(&mut self) { loop { diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs index 1bc166d..085431c 100644 --- a/src/bin/11_render_passes.rs +++ b/src/bin/11_render_passes.rs @@ -111,7 +111,7 @@ impl HelloTriangleApplication { &device, &graphics_queue, &present_queue); let render_pass = Self::create_render_pass(&device, swap_chain.format()); - Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + Self::create_graphics_pipeline(&device, swap_chain.dimensions()); Self { instance, From 32c6ba500c39de16042293d854fd8e89fed70719 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 21:38:48 +0200 Subject: [PATCH 57/78] readme formatting --- README.md | 68 ++++++++++++++++--------------------------------------- 1 file changed, 20 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index c550bd5..1c9cdd1 100644 --- a/README.md +++ b/README.md @@ -186,15 +186,15 @@ struct HelloTriangleApplication { } ``` ```rust - pub fn initialize() -> Self { + pub fn initialize() -> Self { let instance = Self::create_instance(); - let events_loop = Self::init_window(); + let events_loop = Self::init_window(); - Self { + Self { instance, - events_loop, - } - } + events_loop, + } + } ``` ```rust fn create_instance() -> Arc { @@ -220,41 +220,31 @@ struct HelloTriangleApplication { #### Validation layers https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers -[Diff](src/bin/02_validation_layers.rs.diff) - -[Complete code](src/bin/02_validation_layers.rs) +[Diff](src/bin/02_validation_layers.rs.diff) / [Complete code](src/bin/02_validation_layers.rs) #### Physical devices and queue families https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families -[Diff](src/bin/03_physical_device_selection.rs.diff) - -[Complete code](src/bin/03_physical_device_selection.rs) +[Diff](src/bin/03_physical_device_selection.rs.diff) / [Complete code](src/bin/03_physical_device_selection.rs) #### Logical device and queues https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues -[Diff](src/bin/04_logical_device.rs.diff) - -[Complete code](src/bin/04_logical_device.rs) +[Diff](src/bin/04_logical_device.rs.diff) / [Complete code](src/bin/04_logical_device.rs) ### Presentation #### Window surface https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface -[Diff](src/bin/05_window_surface.rs.diff) - -[Complete code](src/bin/05_window_surface.rs) +[Diff](src/bin/05_window_surface.rs.diff) / [Complete code](src/bin/05_window_surface.rs) #### Swap chain https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain -[Diff](src/bin/06_swap_chain_creation.rs.diff) - -[Complete code](src/bin/06_swap_chain_creation.rs) +[Diff](src/bin/06_swap_chain_creation.rs.diff) / [Complete code](src/bin/06_swap_chain_creation.rs) #### Image views https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Image_views @@ -265,71 +255,53 @@ We're skipping this section because image views are handled by Vulkano and can b #### Introduction https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics -[Diff](src/bin/08_graphics_pipeline.rs.diff) - -[Complete code](src/bin/08_graphics_pipeline.rs) +[Diff](src/bin/08_graphics_pipeline.rs.diff) / [Complete code](src/bin/08_graphics_pipeline.rs) #### Shader Modules https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use [vulkano-shader-derive](https://docs.rs/crate/vulkano-shader-derive/) to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the [runtime shaders](https://github.com/vulkano-rs/vulkano/blob/master/examples/src/bin/runtime-shader.rs) example of Vulkano. -[Diff](src/bin/09_shader_modules.rs.diff) - -[Rust code](src/bin/09_shader_modules.rs) / [Vertex shader](src/bin/09_shader_base.vert) / [Fragment shader](src/bin/09_shader_base.frag) +[Diff](src/bin/09_shader_modules.rs.diff) / [Rust code](src/bin/09_shader_modules.rs) / [Vertex shader](src/bin/09_shader_base.vert) / [Fragment shader](src/bin/09_shader_base.frag) #### Fixed functions https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Fixed_functions -[Diff](src/bin/10_fixed_functions.rs.diff) - -[Complete code](src/bin/10_fixed_functions.rs) +[Diff](src/bin/10_fixed_functions.rs.diff) / [Complete code](src/bin/10_fixed_functions.rs) #### Render passes https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Render_passes -[Diff](src/bin/11_render_passes.rs.diff) - -[Complete code](src/bin/11_render_passes.rs) +[Diff](src/bin/11_render_passes.rs.diff) / [Complete code](src/bin/11_render_passes.rs) #### Conclusion https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Conclusion -[Diff](src/bin/12_graphics_pipeline_complete.rs.diff) - -[Complete code](src/bin/12_graphics_pipeline_complete.rs) +[Diff](src/bin/12_graphics_pipeline_complete.rs.diff) / [Complete code](src/bin/12_graphics_pipeline_complete.rs) ### Drawing #### Framebuffers https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Framebuffers -[Diff](src/bin/13_framebuffers.rs.diff) - -[Complete code](src/bin/13_framebuffers.rs) +[Diff](src/bin/13_framebuffers.rs.diff) / [Complete code](src/bin/13_framebuffers.rs) #### Command buffers https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Command_buffers We're skipping the first part because Vulkano maintains a [`StandardCommandPool`](https://docs.rs/vulkano/0.10.0/vulkano/command_buffer/pool/standard/struct.StandardCommandPool.html). -[Diff](src/bin/14_command_buffers.rs.diff) - -[Complete code](src/bin/14_command_buffers.rs) +[Diff](src/bin/14_command_buffers.rs.diff) / [Complete code](src/bin/14_command_buffers.rs) #### Rendering and presentation https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation -[Diff](src/bin/15_hello_triangle.rs.diff) - -[Complete code](src/bin/15_hello_triangle.rs) +[Diff](src/bin/15_hello_triangle.rs.diff) / [Complete code](src/bin/15_hello_triangle.rs) ### Swapchain recreation https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation -[Diff](src/bin/16_swap_chain_recreation.rs.diff) - -[Complete code](src/bin/16_swap_chain_recreation.rs) +[Diff](src/bin/16_swap_chain_recreation.rs.diff) / [Complete code](src/bin/16_swap_chain_recreation.rs) ## Vertex buffers (*TODO*) ## Uniform buffers (*TODO*) From d487cb27365d2ad13140bdb2f7a96b48c9e51697 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 21:45:42 +0200 Subject: [PATCH 58/78] minor code/diff changes --- src/bin/01_instance_creation.rs | 2 -- src/bin/01_instance_creation.rs.diff | 7 ++--- src/bin/02_validation_layers.rs | 2 -- src/bin/03_physical_device_selection.rs | 2 -- src/bin/04_logical_device.rs | 2 -- src/bin/05_window_surface.rs.diff | 36 +++++++++---------------- 6 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/bin/01_instance_creation.rs b/src/bin/01_instance_creation.rs index b453652..85b32d7 100644 --- a/src/bin/01_instance_creation.rs +++ b/src/bin/01_instance_creation.rs @@ -78,7 +78,5 @@ impl HelloTriangleApplication { fn main() { let mut _app = HelloTriangleApplication::initialize(); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. // app.main_loop(); } diff --git a/src/bin/01_instance_creation.rs.diff b/src/bin/01_instance_creation.rs.diff index bde4224..e0904ee 100644 --- a/src/bin/01_instance_creation.rs.diff +++ b/src/bin/01_instance_creation.rs.diff @@ -19,8 +19,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; --// #[allow(unused)] -+#[allow(unused)] + #[allow(unused)] struct HelloTriangleApplication { + instance: Arc, events_loop: EventsLoop, @@ -70,14 +69,12 @@ fn main_loop(&mut self) { loop { let mut done = false; -@@ -46,6 +77,8 @@ impl HelloTriangleApplication { +@@ -46,6 +77,6 @@ impl HelloTriangleApplication { } fn main() { - let mut app = HelloTriangleApplication::initialize(); - app.main_loop(); + let mut _app = HelloTriangleApplication::initialize(); -+ // We'll leave this and the main loop commented out until we actually -+ // have something to show on screen. + // app.main_loop(); } diff --git a/src/bin/02_validation_layers.rs b/src/bin/02_validation_layers.rs index 77fb7c5..921a850 100644 --- a/src/bin/02_validation_layers.rs +++ b/src/bin/02_validation_layers.rs @@ -138,7 +138,5 @@ impl HelloTriangleApplication { fn main() { let mut _app = HelloTriangleApplication::initialize(); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. // app.main_loop(); } diff --git a/src/bin/03_physical_device_selection.rs b/src/bin/03_physical_device_selection.rs index af72ac9..a2f6f07 100644 --- a/src/bin/03_physical_device_selection.rs +++ b/src/bin/03_physical_device_selection.rs @@ -185,7 +185,5 @@ impl HelloTriangleApplication { fn main() { let mut _app = HelloTriangleApplication::initialize(); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. // app.main_loop(); } diff --git a/src/bin/04_logical_device.rs b/src/bin/04_logical_device.rs index d66abb4..9546cd5 100644 --- a/src/bin/04_logical_device.rs +++ b/src/bin/04_logical_device.rs @@ -220,7 +220,5 @@ impl HelloTriangleApplication { fn main() { let mut _app = HelloTriangleApplication::initialize(); - // We'll leave this and the main loop commented out until we actually - // have something to show on screen. // app.main_loop(); } diff --git a/src/bin/05_window_surface.rs.diff b/src/bin/05_window_surface.rs.diff index 75f49b1..c28365f 100644 --- a/src/bin/05_window_surface.rs.diff +++ b/src/bin/05_window_surface.rs.diff @@ -40,7 +40,7 @@ } } -@@ -49,47 +55,41 @@ struct HelloTriangleApplication { +@@ -49,46 +55,40 @@ struct HelloTriangleApplication { debug_callback: Option, events_loop: EventsLoop, @@ -83,21 +83,19 @@ } } --fn init_window() -> EventsLoop { -- let events_loop = EventsLoop::new(); -- let _window_builder = WindowBuilder::new() -- .with_title("Vulkan") -- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); -- // .build(&self.events_loop.as_ref().unwrap()); -- events_loop --} +- fn init_window() -> EventsLoop { +- let events_loop = EventsLoop::new(); +- let _window_builder = WindowBuilder::new() +- .with_title("Vulkan") +- .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))); +- // .build(&self.events_loop.as_ref().unwrap()); +- events_loop +- } - --fn create_instance() -> Arc { -+ fn create_instance() -> Arc { + fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") - } -@@ -149,18 +149,18 @@ fn create_instance() -> Arc { +@@ -149,18 +149,18 @@ impl HelloTriangleApplication { }).ok() } @@ -121,7 +119,7 @@ let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { -@@ -168,6 +168,10 @@ fn create_instance() -> Arc { +@@ -168,6 +168,10 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } @@ -132,7 +130,7 @@ if indices.is_complete() { break; } -@@ -178,27 +182,43 @@ fn create_instance() -> Arc { +@@ -178,27 +182,43 @@ impl HelloTriangleApplication { fn create_logical_device( instance: &Arc, @@ -183,11 +181,3 @@ } #[allow(unused)] -@@ -220,7 +240,5 @@ fn create_instance() -> Arc { - - fn main() { - let mut _app = HelloTriangleApplication::initialize(); -- // We'll leave this and the main loop commented out until we actually -- // have something to show on screen. - // app.main_loop(); - } From d52a824780dac5eb19a4a42c65c45ce1f6c82f7e Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 22:12:12 +0200 Subject: [PATCH 59/78] add vertex buffers chapter to readme --- README.md | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c9cdd1..9a130e7 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,11 @@ Rust version of https://github.com/Overv/VulkanTutorial using [Vulkano](http://v * [Command buffers](#command-buffers) * [Rendering and presentation](#rendering-and-presentation) * [Swapchain recreation](#swapchain-recreation) -* [Vertex buffers (TODO)](#vertex-buffers-todo) +* [Vertex buffers](#vertex-buffers) + * [Vertex input description](#vertex-input-description) + * [Vertex buffer creation](#vertex-buffer-creation) + * [Staging buffer](#staging-buffer) + * [Index buffer](#index-buffer) * [Uniform buffers (TODO)](#uniform-buffers-todo) * [Texture mapping (TODO)](#texture-mapping-todo) * [Depth buffering (TODO)](#depth-buffering-todo) @@ -303,7 +307,31 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation [Diff](src/bin/16_swap_chain_recreation.rs.diff) / [Complete code](src/bin/16_swap_chain_recreation.rs) -## Vertex buffers (*TODO*) +## Vertex buffers +### Vertex input description +https://vulkan-tutorial.com/Vertex_buffers/Vertex_input_description + +[Vertex shader diff](src/bin/17_shader_vertexbuffer.vert.diff) / [Vertex shader](src/bin/17_shader_vertexbuffer.vert) + +(Rust code combined with next section, since this alone won't compile) + +### Vertex buffer creation +https://vulkan-tutorial.com/Vertex_buffers/Vertex_buffer_creation + +[Diff](src/bin/18_vertex_buffer.rs.diff) / [Complete code](src/bin/18_vertex_buffer.rs) + +### Staging buffer +https://vulkan-tutorial.com/Vertex_buffers/Staging_buffer + +We're just replacing `CpuAccessibleBuffer` with `ImmutableBuffer`, which uses a staging buffer internally. See [`vulkano::buffer`](https://docs.rs/vulkano/0.10.0/vulkano/buffer/index.html) for an overview of Vulkano's buffer types. + +[Diff](src/bin/19_staging_buffer.rs.diff) / [Complete code](src/bin/19_staging_buffer.rs) + +### Index buffer +https://vulkan-tutorial.com/Vertex_buffers/Index_buffer + +[Diff](src/bin/20_index_buffer.rs.diff) / [Complete code](src/bin/20_index_buffer.rs) + ## Uniform buffers (*TODO*) ## Texture mapping (*TODO*) ## Depth buffering (*TODO*) From 978e5f362072105a8d0b7d86881124a8158d32a5 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Tue, 28 Aug 2018 22:21:29 +0200 Subject: [PATCH 60/78] update current state --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a130e7..90c71ab 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Rust version of https://github.com/Overv/VulkanTutorial using [Vulkano](http://v **Goal**: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to [learn-opengl-rs](https://github.com/bwasty/learn-opengl-rs)). -**Current State**: The first major part, `Drawing a triangle`, is complete. +**Current State**: The chapters `Drawing a triangle` and `Vertex buffers` are complete. --- * [Introduction](#introduction) From 0d507702a8998be08e4f3f686ee2f1449a7c0377 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Fri, 31 Aug 2018 08:34:31 +0200 Subject: [PATCH 61/78] fix swapchain recreation (#3) --- src/bin/16_swap_chain_recreation.rs | 2 +- src/bin/18_vertex_buffer.rs | 2 +- src/bin/19_staging_buffer.rs | 2 +- src/bin/20_index_buffer.rs | 2 +- src/main.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs index 38811b8..2a7dd5d 100644 --- a/src/bin/16_swap_chain_recreation.rs +++ b/src/bin/16_swap_chain_recreation.rs @@ -591,7 +591,7 @@ impl HelloTriangleApplication { self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), &self.render_pass); - Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); self.create_command_buffers(); } } diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs index 6110058..0b9d5a5 100644 --- a/src/bin/18_vertex_buffer.rs +++ b/src/bin/18_vertex_buffer.rs @@ -616,7 +616,7 @@ impl HelloTriangleApplication { self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), &self.render_pass); - Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); self.create_command_buffers(); } } diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs index 9d70bff..62391c1 100644 --- a/src/bin/19_staging_buffer.rs +++ b/src/bin/19_staging_buffer.rs @@ -620,7 +620,7 @@ impl HelloTriangleApplication { self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), &self.render_pass); - Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); self.create_command_buffers(); } } diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index 7c0444b..850c085 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -639,7 +639,7 @@ impl HelloTriangleApplication { self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), &self.render_pass); - Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); self.create_command_buffers(); } } diff --git a/src/main.rs b/src/main.rs index 7c0444b..850c085 100644 --- a/src/main.rs +++ b/src/main.rs @@ -639,7 +639,7 @@ impl HelloTriangleApplication { self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), &self.render_pass); - Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); self.create_command_buffers(); } } From 14786dcc697692d0f8646423fd37fa93e5123e9e Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Fri, 31 Aug 2018 08:54:00 +0200 Subject: [PATCH 62/78] small fixes --- README.md | 2 +- src/bin/16_swap_chain_recreation.rs.diff | 2 +- src/bin/18_vertex_buffer.rs.diff | 9 --------- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 90c71ab..95406fc 100644 --- a/README.md +++ b/README.md @@ -264,7 +264,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics #### Shader Modules https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules -Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use [vulkano-shader-derive](https://docs.rs/crate/vulkano-shader-derive/) to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the [runtime shaders](https://github.com/vulkano-rs/vulkano/blob/master/examples/src/bin/runtime-shader.rs) example of Vulkano. +Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use [vulkano-shader-derive](https://docs.rs/crate/vulkano-shader-derive/) to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the [runtime shader](https://github.com/vulkano-rs/vulkano/blob/master/examples/src/bin/runtime-shader/main.rs) example of Vulkano. [Diff](src/bin/09_shader_modules.rs.diff) / [Rust code](src/bin/09_shader_modules.rs) / [Vertex shader](src/bin/09_shader_base.vert) / [Fragment shader](src/bin/09_shader_base.frag) diff --git a/src/bin/16_swap_chain_recreation.rs.diff b/src/bin/16_swap_chain_recreation.rs.diff index 727a85d..a5663ac 100644 --- a/src/bin/16_swap_chain_recreation.rs.diff +++ b/src/bin/16_swap_chain_recreation.rs.diff @@ -151,7 +151,7 @@ + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); -+ Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); ++ self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); } } diff --git a/src/bin/18_vertex_buffer.rs.diff b/src/bin/18_vertex_buffer.rs.diff index 973b3c9..9ebd450 100644 --- a/src/bin/18_vertex_buffer.rs.diff +++ b/src/bin/18_vertex_buffer.rs.diff @@ -89,15 +89,6 @@ command_buffers: vec![], previous_frame_end, -@@ -198,7 +219,7 @@ impl HelloTriangleApplication { - } else { - Instance::new(Some(&app_info), &required_extensions, None) - .expect("failed to create Vulkan instance") -- } -+ } - } - - fn check_validation_layer_support() -> bool { @@ -370,12 +391,12 @@ impl HelloTriangleApplication { device: &Arc, swap_chain_extent: [u32; 2], From a37389453cd88e4a3f82d1bdaa0dd2e3cde9162d Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Fri, 31 Aug 2018 19:12:54 +0200 Subject: [PATCH 63/78] remove device wait on swap chain recreation --- src/bin/16_swap_chain_recreation.rs | 2 -- src/bin/16_swap_chain_recreation.rs.diff | 38 +++++++++++------------- src/bin/18_vertex_buffer.rs | 2 -- src/bin/19_staging_buffer.rs | 2 -- src/bin/20_index_buffer.rs | 2 -- src/main.rs | 2 -- 6 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs index 2a7dd5d..39b6a59 100644 --- a/src/bin/16_swap_chain_recreation.rs +++ b/src/bin/16_swap_chain_recreation.rs @@ -581,8 +581,6 @@ impl HelloTriangleApplication { } fn recreate_swap_chain(&mut self) { - unsafe { self.device.wait().unwrap(); } - let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); self.swap_chain = swap_chain; diff --git a/src/bin/16_swap_chain_recreation.rs.diff b/src/bin/16_swap_chain_recreation.rs.diff index a5663ac..c8d4184 100644 --- a/src/bin/16_swap_chain_recreation.rs.diff +++ b/src/bin/16_swap_chain_recreation.rs.diff @@ -14,38 +14,38 @@ GraphicsPipeline, vertex::BufferlessDefinition, @@ -90,9 +91,9 @@ impl QueueFamilyIndices { - + type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; - + -#[allow(unused)] struct HelloTriangleApplication { instance: Arc, + #[allow(unused)] debug_callback: Option, - + events_loop: EventsLoop, @@ -117,6 +118,9 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, - + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, } - + impl HelloTriangleApplication { @@ -130,13 +134,15 @@ impl HelloTriangleApplication { &instance, &surface, physical_device_index); - + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, - &device, &graphics_queue, &present_queue); + &device, &graphics_queue, &present_queue, None); - + let render_pass = Self::create_render_pass(&device, swap_chain.format()); let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); - + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); - + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + let mut app = Self { @@ -53,13 +53,13 @@ debug_callback, @@ -159,6 +165,9 @@ impl HelloTriangleApplication { swap_chain_framebuffers, - + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, }; - + app.create_command_buffers(); @@ -293,6 +302,7 @@ impl HelloTriangleApplication { device: &Arc, @@ -76,12 +76,12 @@ - None, + old_swapchain.as_ref() ).expect("failed to create swap chain!"); - + (swap_chain, images) @@ -444,6 +454,10 @@ impl HelloTriangleApplication { .collect(); } - + + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box + } @@ -91,7 +91,7 @@ // TODO: replace index with id to simplify? @@ -524,18 +538,61 @@ impl HelloTriangleApplication { } - + fn draw_frame(&mut self) { - let (image_index, acquire_future) = acquire_next_image(self.swap_chain.clone(), None).unwrap(); + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); @@ -109,9 +109,9 @@ + }, + Err(err) => panic!("{:?}", err) + }; - + let command_buffer = self.command_buffers[image_index].clone(); - + - let future = acquire_future + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) @@ -140,13 +140,11 @@ + } + + fn recreate_swap_chain(&mut self) { -+ unsafe { self.device.wait().unwrap(); } -+ + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; - + - future.wait(None).unwrap(); + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), @@ -155,4 +153,4 @@ + self.create_command_buffers(); } } - + diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs index 0b9d5a5..58c741d 100644 --- a/src/bin/18_vertex_buffer.rs +++ b/src/bin/18_vertex_buffer.rs @@ -606,8 +606,6 @@ impl HelloTriangleApplication { } fn recreate_swap_chain(&mut self) { - unsafe { self.device.wait().unwrap(); } - let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); self.swap_chain = swap_chain; diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs index 62391c1..acdbba3 100644 --- a/src/bin/19_staging_buffer.rs +++ b/src/bin/19_staging_buffer.rs @@ -610,8 +610,6 @@ impl HelloTriangleApplication { } fn recreate_swap_chain(&mut self) { - unsafe { self.device.wait().unwrap(); } - let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); self.swap_chain = swap_chain; diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index 850c085..23b9829 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -629,8 +629,6 @@ impl HelloTriangleApplication { } fn recreate_swap_chain(&mut self) { - unsafe { self.device.wait().unwrap(); } - let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); self.swap_chain = swap_chain; diff --git a/src/main.rs b/src/main.rs index 850c085..23b9829 100644 --- a/src/main.rs +++ b/src/main.rs @@ -629,8 +629,6 @@ impl HelloTriangleApplication { } fn recreate_swap_chain(&mut self) { - unsafe { self.device.wait().unwrap(); } - let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); self.swap_chain = swap_chain; From ee5a050b68a8f4f34f3368c940eb60b5358523de Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 2 Feb 2019 16:14:56 -0500 Subject: [PATCH 64/78] updates dependencies --- .gitignore | 1 + Cargo.lock | 744 ++++++++++++++--------- Cargo.toml | 10 +- src/bin/04_logical_device.rs | 3 +- src/bin/05_window_surface.rs | 3 +- src/bin/06_swap_chain_creation.rs | 3 +- src/bin/08_graphics_pipeline.rs | 3 +- src/bin/09_shader_modules.rs | 22 +- src/bin/10_fixed_functions.rs | 22 +- src/bin/11_render_passes.rs | 22 +- src/bin/12_graphics_pipeline_complete.rs | 22 +- src/bin/13_framebuffers.rs | 22 +- src/bin/14_command_buffers.rs | 22 +- src/bin/15_hello_triangle.rs | 22 +- src/bin/16_swap_chain_recreation.rs | 22 +- src/bin/18_vertex_buffer.rs | 22 +- src/bin/19_staging_buffer.rs | 22 +- src/bin/20_index_buffer.rs | 22 +- src/main.rs | 22 +- 19 files changed, 586 insertions(+), 445 deletions(-) diff --git a/.gitignore b/.gitignore index c144c9d..cd487fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk *.spv +.idea/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d7cde3b..5ae7730 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,15 +3,31 @@ name = "adler32" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "andrew" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rusttype 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "android_glue" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "arrayref" -version = "0.3.5" +name = "approx" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "arrayvec" @@ -22,27 +38,39 @@ dependencies = [ ] [[package]] -name = "bitflags" -version = "1.0.3" +name = "autocfg" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "block" -version = "0.1.6" +name = "backtrace" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "block-buffer" -version = "0.3.3" +name = "backtrace-sys" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "byte-tools" -version = "0.2.0" +name = "bitflags" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -78,25 +106,15 @@ dependencies = [ [[package]] name = "cocoa" -version = "0.13.0" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cocoa" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -105,30 +123,13 @@ name = "color_quant" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "core-foundation" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "core-foundation" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation-sys" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -138,46 +139,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "core-graphics" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-graphics" -version = "0.16.0" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-channel" -version = "0.2.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -192,11 +183,11 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.5.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -215,12 +206,25 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.5.2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -236,8 +240,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.5.0" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "deflate" @@ -248,14 +256,6 @@ dependencies = [ "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "digest" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dlib" version = "0.4.1" @@ -274,11 +274,6 @@ name = "either" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fnv" version = "1.0.6" @@ -297,6 +292,11 @@ name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fuchsia-cprng" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -316,14 +316,6 @@ name = "gcc" version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "gif" version = "0.10.0" @@ -333,16 +325,6 @@ dependencies = [ "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "glsl-to-spirv" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "half" version = "1.1.2" @@ -350,19 +332,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "image" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -392,7 +374,7 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.43" +version = "0.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -401,7 +383,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "line_drawing" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -431,16 +421,16 @@ name = "malloc_buf" version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memmap" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -449,15 +439,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "metal-rs" -version = "0.6.6" +name = "metal" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "cocoa 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -466,13 +457,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -487,8 +478,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -511,7 +502,7 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.1.42" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -528,7 +519,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -566,6 +557,14 @@ dependencies = [ "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ordered-float" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "owning_ref" version = "0.3.3" @@ -576,22 +575,44 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.6.3" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.2.14" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -617,7 +638,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.4.13" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -625,32 +646,49 @@ dependencies = [ [[package]] name = "quote" -version = "0.6.6" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.4.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.5.5" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -658,6 +696,75 @@ name = "rand_core" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rayon" version = "1.0.2" @@ -675,21 +782,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "redox_syscall" -version = "0.1.40" +name = "rdrand" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "remove_dir_all" -version = "0.5.1" +name = "rustc-demangle" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rusttype" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "same-file" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -703,14 +837,25 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "sha2" -version = "0.7.1" +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "shaderc" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -719,7 +864,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -732,19 +877,19 @@ dependencies = [ [[package]] name = "smithay-client-toolkit" -version = "0.2.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "andrew 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-commons 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-protocols 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-commons 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-protocols 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -752,32 +897,44 @@ name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stb_truetype" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tempfile" -version = "3.0.3" +name = "syn" +version = "0.15.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "typenum" -version = "1.10.0" +name = "tiff" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "unicode-xid" @@ -799,7 +956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vk-sys" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -811,101 +968,108 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vulkan-tutorial-rs" version = "0.1.0" dependencies = [ - "image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vulkano 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vulkano-shader-derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vulkano-win 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winit 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", + "vulkano 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "vulkano-shaders 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "vulkano-win 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "vulkano" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "half 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vk-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "vk-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "vulkano-shader-derive" -version = "0.10.0" +name = "vulkano-shaders" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "glsl-to-spirv 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)", - "vulkano-shaders 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "shaderc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "vulkano-shaders" -version = "0.10.0" +name = "vulkano-win" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "glsl-to-spirv 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", + "metal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vulkano 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "vulkano-win" -version = "0.10.0" +name = "walkdir" +version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cocoa 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "metal-rs 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vulkano 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winit 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-client" -version = "0.20.12" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-commons 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-scanner 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-sys 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", + "downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-commons 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-scanner 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-sys 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-commons" -version = "0.20.12" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-sys 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-sys 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-protocols" -version = "0.20.12" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-commons 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-scanner 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-sys 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-commons 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-scanner 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-sys 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-scanner" -version = "0.20.12" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wayland-sys" -version = "0.20.12" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -914,7 +1078,7 @@ dependencies = [ [[package]] name = "winapi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -926,6 +1090,14 @@ name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -933,22 +1105,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winit" -version = "0.17.1" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cocoa 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smithay-client-toolkit 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "wayland-client 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smithay-client-toolkit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wayland-client 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -958,132 +1131,151 @@ version = "2.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "xml-rs" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +"checksum andrew 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "142e9e6a99ad0d63a4cf6ce58a4c979f472c5815cbf7e5ca4e47b26a10dc728e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c57ff1a5b00753647aebbbcf4ea67fa1e711a65ea7a30eb90dbf07de2485aee" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum backtrace 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eff3830839471718ef8522b9025b399bfb713e25bc220da721364efb660d7d" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" "checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "704fbf3bb5149daab0afb255dbea24a1f08d2f4099cedb9baab6d470d4c5eefb" -"checksum cocoa 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac0d785ff4faf0ff23d7b5561346bb50dc7ef9a11cb0e65e07ef776b7752938f" -"checksum cocoa 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5cd1afb83b2de9c41e5dfedb2bcccb779d433b958404876009ae4b01746ff23" +"checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b" "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" -"checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e" "checksum core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc3532ec724375c7cb7ff0a097b714fde180bb1f6ed2ab27cfcd99ffca873cd2" -"checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5" "checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9" -"checksum core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8de78908c558a9ba526877d165635c9eaed0818a785a93efddde1c5bfd2ce5d1" -"checksum core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92801c908ea6301ae619ed842a72e01098085fc321b9c2f3f833dad555bba055" -"checksum crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7408247b1b87f480890f28b670c5f8d9a8a4274833433fe74dc0dfd46d33650" -"checksum crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6c0a94250b0278d7fc5a894c3d276b11ea164edc8bf8feb10ca1ea517b44a649" +"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" +"checksum crossbeam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d1c92ff2d7a202d592f5a412d75cf421495c913817781c1cb383bf12a77e185f" +"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7792c4a9b5a4222f654e3728a3dd945aacc24d2c3a1a096ed265d80e4929cb9a" +"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" +"checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31" -"checksum digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b29c278aa8fd30796bd977169e8004b4aa88cdcd2f32a6eb22bc2d5d38df94a" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" "checksum downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "18df8ce4470c189d18aa926022da57544f31e154631eb4cfe796aea97051fe6c" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "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" +"checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" -"checksum glsl-to-spirv 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "605de660ba1c76e66ffb94ef480f5f6b8c00f5a586fc5cebca1af9ac3e92ab08" "checksum half 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a581f551b77eb3e177584e922a8c057e14311a857f859fd39d9574d97d3547da" -"checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a" +"checksum image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44665b4395d1844c96e7dc8ed5754782a1cdfd9ef458a80bbe45702681450504" "checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245" "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" "checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" -"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" +"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" +"checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" +"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum metal-rs 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4b77b2a59798a094aa3b06df84ca3618f63ca63abfd6e270a17777fd53f38d6b" -"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" +"checksum metal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7de9c2b83c946ab01c9942928388f911d93486b97636d9927541345905fea65d" +"checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" +"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9833ab0efe5361b1e2122a0544a5d3359576911a42cb098c2e59be8650807367" "checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" "checksum objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" "checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +"checksum ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0015e9e8e28ee20c581cfbfe47c650cedeb9ed0721090e0b7ebb10b9cdbcc2" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69376b761943787ebd5cc85a5bc95958651a22609c5c1c2b65de21786baec72b" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" +"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "104630aa1c83213cbc76db0703630fcb0421dac3585063be4ce9a8a2feeaa745" "checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b" -"checksum proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5697238f0d893c7f0ecc59c0999f18d2af85e424de441178bcacc9f9e6cf67" -"checksum quote 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ed7d650913520df631972f21e104a4fa2f9c82a14afc65d17b388a2e29731e7c" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" +"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" +"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rusttype 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ae90f66c7ca5fb2c566d373c9ccb3ce1ae1aeebf236b74ad0d413196facb31b3" +"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum shaderc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "a2e5612a0be921f736036765b7d3e778ad80e345329d5ceb96c6b9eb9db0285b" "checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" "checksum smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "211a489e65e94b103926d2054ae515a1cdb5d515ea0ef414fee23b7e043ce748" -"checksum smithay-client-toolkit 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2051bffc6cbf271176e8ba1527f801b6444567daee15951ff5152aaaf7777b2f" +"checksum smithay-client-toolkit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d858330eeed4efaf71c560555e2a6a0597d01b7d52685c3cc964ab1cc360f8c6" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b7bfcbb0c068d0f642a0ffbd5c604965a360a61f99e8add013cef23a838614f3" -"checksum tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b103c6d08d323b92ff42c8ce62abcd83ca8efa7fd5bf7927efefec75f58c76" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a2cc6c4fd13cb1cfd20abdb196e794ceccb29371855b7e7f575945f920a5b3c2" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" -"checksum vk-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9567ee6b79b72dfe50201817a9b903de91a1deb091b41c165c2c3679884d8103" +"checksum vk-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36f5fd4a7d6d5d19808610583131c0aed271556527cad4cb71c436831a28e059" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum vulkano 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9e3da53f262560934db346d11d91d3323f9f0ed9ba18b77e5d1a5d4a8bf8278" -"checksum vulkano-shader-derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7bdaad27dedc3cd506d4b58b4bbdd04dce6b5858c04c0e4abec9831e51e5c" -"checksum vulkano-shaders 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f137af3bdb733db9a9a1e5874937037c12ba7fa592485880746e78cd83e41c2" -"checksum vulkano-win 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d88fcf9015174883872c130565d58611a72e9b55ce45a5fa42981d66656b09" -"checksum wayland-client 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e7516a23419a55bd2e6d466c75a6a52c85718e5013660603289c2b8bee794b12" -"checksum wayland-commons 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)" = "d8609d59b95bf198bae4f3b064d55a712f2d529eec6aac98cc1f6e9cc911d47a" -"checksum wayland-protocols 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd4d31a96be6ecdbaddbf35200f5af2daee01be592afecd8feaf443d417e9230" -"checksum wayland-scanner 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e674d85ae9c67cbbc590374d8f2e20a7a02fff87ce3a31fc52213afece8d05ad" -"checksum wayland-sys 0.20.12 (registry+https://github.com/rust-lang/crates.io-index)" = "87c82ee658aa657fdfd7061f22e442030d921cfefc5bad68bcf41973e67922f7" -"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum vulkano 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "715b3528d50119f2b7088479a79ff9d95416a6613d18c853d87ad98185ca43d1" +"checksum vulkano-shaders 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce289d8dd668d4c5ba28d1af09e40a09947f138f1cee447f087f771b5ff0030a" +"checksum vulkano-win 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07fffe247f37c8b051e8210ecfb6fe9a13bbb69e05ea61aceb1def5f709320ae" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" +"checksum wayland-client 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "96041810afa07e7953867d46f8f03c41cbca49ebd1e840eef6abefde8b458b30" +"checksum wayland-commons 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "92af0c5dc724c049e9bd927f8563d9a6abaa94893c5305ef0a6d2805e661f3d3" +"checksum wayland-protocols 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fd94211387fa8ff50df1e4ff7a5529b5a9aebe68ba88acc48e5b7f5fd98f6eef" +"checksum wayland-scanner 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3611f231e675e15c2feb7623103e6449edc6f10b0598cafb3e16e590a0561355" +"checksum wayland-sys 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2a69d729a1747a5bf40ae05b94c7904b64fbf2381e365c046d872ce4a34aa826" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum winit 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "681133266a330e2df4c76644554d1037401013218ce3293de0c6b795d64ab100" +"checksum winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c57c15bd4c0ef18dff33e263e452abe32d00e2e05771cacaa410a14cc1c0776" "checksum x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)" = "940586acb859ea05c53971ac231685799a7ec1dee66ac0bccc0e6ad96e06b4e3" -"checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" +"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" +"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" diff --git a/Cargo.toml b/Cargo.toml index 503a9ad..c9dadb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,11 @@ authors = ["Benjamin Wasty "] autobins = true [dependencies] -vulkano = "0.10.0" -vulkano-shader-derive = "0.10.0" -image = "0.19.0" -vulkano-win = "0.10.0" -winit = "0.17.1" +vulkano = "0.11.1" +vulkano-shaders = "0.11.1" +image = "0.20.1" +vulkano-win = "0.11.1" +winit = "0.18.0" # [[bin]] # name = "main" diff --git a/src/bin/04_logical_device.rs b/src/bin/04_logical_device.rs index 9546cd5..c15d820 100644 --- a/src/bin/04_logical_device.rs +++ b/src/bin/04_logical_device.rs @@ -13,10 +13,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; diff --git a/src/bin/05_window_surface.rs b/src/bin/05_window_surface.rs index 7e3ddf9..60ee006 100644 --- a/src/bin/05_window_surface.rs +++ b/src/bin/05_window_surface.rs @@ -15,10 +15,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, }; diff --git a/src/bin/06_swap_chain_creation.rs b/src/bin/06_swap_chain_creation.rs index 81dda19..4aa086f 100644 --- a/src/bin/06_swap_chain_creation.rs +++ b/src/bin/06_swap_chain_creation.rs @@ -15,10 +15,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, diff --git a/src/bin/08_graphics_pipeline.rs b/src/bin/08_graphics_pipeline.rs index 5eae536..b5266b3 100644 --- a/src/bin/08_graphics_pipeline.rs +++ b/src/bin/08_graphics_pipeline.rs @@ -15,10 +15,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, diff --git a/src/bin/09_shader_modules.rs b/src/bin/09_shader_modules.rs index 207e695..ad1ad9a 100644 --- a/src/bin/09_shader_modules.rs +++ b/src/bin/09_shader_modules.rs @@ -1,6 +1,5 @@ extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -17,10 +16,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -296,20 +294,18 @@ impl HelloTriangleApplication { fn create_graphics_pipeline( device: &Arc, ) { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let _vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/10_fixed_functions.rs b/src/bin/10_fixed_functions.rs index e0b2bcb..07c5f87 100644 --- a/src/bin/10_fixed_functions.rs +++ b/src/bin/10_fixed_functions.rs @@ -1,6 +1,5 @@ extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -17,10 +16,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -302,20 +300,18 @@ impl HelloTriangleApplication { device: &Arc, swap_chain_extent: [u32; 2], ) { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs index 085431c..18a00bb 100644 --- a/src/bin/11_render_passes.rs +++ b/src/bin/11_render_passes.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -328,20 +326,18 @@ impl HelloTriangleApplication { device: &Arc, swap_chain_extent: [u32; 2], ) { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/12_graphics_pipeline_complete.rs b/src/bin/12_graphics_pipeline_complete.rs index 0ebe6c4..8ffb4ef 100644 --- a/src/bin/12_graphics_pipeline_complete.rs +++ b/src/bin/12_graphics_pipeline_complete.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -339,20 +337,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/13_framebuffers.rs b/src/bin/13_framebuffers.rs index 77f3cae..2966b33 100644 --- a/src/bin/13_framebuffers.rs +++ b/src/bin/13_framebuffers.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -347,20 +345,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/14_command_buffers.rs b/src/bin/14_command_buffers.rs index 63a4d38..51be210 100644 --- a/src/bin/14_command_buffers.rs +++ b/src/bin/14_command_buffers.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -360,20 +358,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/15_hello_triangle.rs b/src/bin/15_hello_triangle.rs index 454c3d1..929d3c3 100644 --- a/src/bin/15_hello_triangle.rs +++ b/src/bin/15_hello_triangle.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -361,20 +359,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs index 39b6a59..e8b8dbc 100644 --- a/src/bin/16_swap_chain_recreation.rs +++ b/src/bin/16_swap_chain_recreation.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -371,20 +369,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/09_shader_base.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/09_shader_base.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/09_shader_base.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/09_shader_base.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs index 58c741d..db5d3eb 100644 --- a/src/bin/18_vertex_buffer.rs +++ b/src/bin/18_vertex_buffer.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -392,20 +390,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/17_shader_vertexbuffer.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/17_shader_vertexbuffer.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/17_shader_vertexbuffer.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/17_shader_vertexbuffer.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs index acdbba3..e0a743f 100644 --- a/src/bin/19_staging_buffer.rs +++ b/src/bin/19_staging_buffer.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -392,20 +390,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/17_shader_vertexbuffer.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/17_shader_vertexbuffer.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/17_shader_vertexbuffer.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/17_shader_vertexbuffer.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index 23b9829..3f2a464 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -401,20 +399,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/17_shader_vertexbuffer.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/17_shader_vertexbuffer.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/17_shader_vertexbuffer.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/17_shader_vertexbuffer.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/main.rs b/src/main.rs index 23b9829..3f2a464 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate vulkano; #[macro_use] -extern crate vulkano_shader_derive; extern crate vulkano_win; extern crate winit; @@ -18,10 +17,9 @@ use vulkano::instance::{ Version, layers_list, PhysicalDevice, - Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -use vulkano::device::{Device, DeviceExtensions, Queue}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, Capabilities, @@ -401,20 +399,18 @@ impl HelloTriangleApplication { swap_chain_extent: [u32; 2], render_pass: &Arc, ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] - #[path = "src/bin/17_shader_vertexbuffer.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/17_shader_vertexbuffer.vert" + } } - #[allow(unused)] mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] - #[path = "src/bin/17_shader_vertexbuffer.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/17_shader_vertexbuffer.frag" + } } let vert_shader_module = vertex_shader::Shader::load(device.clone()) From 16bb1d4c1390d97772d2fa872304c1a98672726b Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Mon, 4 Feb 2019 19:20:57 -0500 Subject: [PATCH 65/78] updates all diffs and README to reflect new versions --- README.md | 8 +-- src/bin/04_logical_device.rs.diff | 15 ++--- src/bin/05_window_surface.rs.diff | 14 ++--- src/bin/06_swap_chain_creation.rs.diff | 16 ++--- src/bin/08_graphics_pipeline.rs.diff | 4 +- src/bin/09_shader_modules.rs | 1 - src/bin/09_shader_modules.rs.diff | 29 ++++------ src/bin/10_fixed_functions.rs | 1 - src/bin/10_fixed_functions.rs.diff | 14 ++--- src/bin/11_render_passes.rs | 1 - src/bin/11_render_passes.rs.diff | 18 +++--- src/bin/12_graphics_pipeline_complete.rs | 1 - src/bin/12_graphics_pipeline_complete.rs.diff | 23 ++++---- src/bin/13_framebuffers.rs | 1 - src/bin/13_framebuffers.rs.diff | 10 ++-- src/bin/14_command_buffers.rs | 1 - src/bin/14_command_buffers.rs.diff | 12 ++-- src/bin/15_hello_triangle.rs | 1 - src/bin/15_hello_triangle.rs.diff | 6 +- src/bin/16_swap_chain_recreation.rs | 1 - src/bin/16_swap_chain_recreation.rs.diff | 58 +++++++++---------- src/bin/18_vertex_buffer.rs | 1 - src/bin/18_vertex_buffer.rs.diff | 40 ++++++------- src/bin/19_staging_buffer.rs | 1 - src/bin/19_staging_buffer.rs.diff | 6 +- src/bin/20_index_buffer.rs | 1 - src/bin/20_index_buffer.rs.diff | 14 ++--- src/main.rs | 1 - 28 files changed, 135 insertions(+), 164 deletions(-) diff --git a/README.md b/README.md index 95406fc..dbca5a2 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ $ cargo new vulkan-tutorial-rs Then add this to your `Cargo.toml`: ``` [dependencies] -vulkano = "0.10.0" +vulkano = "0.11.1" ``` On macOS, copy [mac-env.sh](mac-env.sh), adapt the `VULKAN_SDK` path if necessary and `source` the file in your terminal. See also [vulkano-rs/vulkano#macos-and-ios-setup](https://github.com/vulkano-rs/vulkano#macos-and-ios-setup). @@ -110,7 +110,7 @@ Instead of GLFW we're using [winit](https://github.com/tomaka/winit), an alterna Add this to your Cargo.toml: ``` -winit = "0.17.1" +winit = "0.18.0" ``` And extend your main.rs: ```rust @@ -168,7 +168,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance Cargo.toml: ``` -vulkano-win = "0.10.0" +vulkano-win = "0.11.1" ``` main.rs: ```rust @@ -264,7 +264,7 @@ https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics #### Shader Modules https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules -Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use [vulkano-shader-derive](https://docs.rs/crate/vulkano-shader-derive/) to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the [runtime shader](https://github.com/vulkano-rs/vulkano/blob/master/examples/src/bin/runtime-shader/main.rs) example of Vulkano. +Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use [vulkano_shaders](https://docs.rs/vulkano-shaders/0.11.1/vulkano_shaders) to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the [runtime shader](https://github.com/vulkano-rs/vulkano/blob/master/examples/src/bin/runtime-shader/main.rs) example of Vulkano. [Diff](src/bin/09_shader_modules.rs.diff) / [Rust code](src/bin/09_shader_modules.rs) / [Vertex shader](src/bin/09_shader_base.vert) / [Fragment shader](src/bin/09_shader_base.frag) diff --git a/src/bin/04_logical_device.rs.diff b/src/bin/04_logical_device.rs.diff index 2673387..bfebbc8 100644 --- a/src/bin/04_logical_device.rs.diff +++ b/src/bin/04_logical_device.rs.diff @@ -1,17 +1,14 @@ --- a/03_physical_device_selection.rs +++ b/04_logical_device.rs -@@ -13,8 +13,10 @@ use vulkano::instance::{ - Version, - layers_list, +@@ -15,6 +15,7 @@ use vulkano::instance::{ PhysicalDevice, -+ Features }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; -+use vulkano::device::{Device, DeviceExtensions, Queue}; ++use vulkano::device::{Device, DeviceExtensions, Queue, Features}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -49,6 +51,9 @@ struct HelloTriangleApplication { +@@ -49,6 +50,9 @@ struct HelloTriangleApplication { events_loop: EventsLoop, physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) @@ -21,7 +18,7 @@ } impl HelloTriangleApplication { -@@ -59,6 +64,8 @@ impl HelloTriangleApplication { +@@ -59,6 +63,8 @@ impl HelloTriangleApplication { let events_loop = Self::init_window(); let physical_device_index = Self::pick_physical_device(&instance); @@ -30,7 +27,7 @@ Self { instance, -@@ -67,6 +74,9 @@ impl HelloTriangleApplication { +@@ -67,6 +73,9 @@ impl HelloTriangleApplication { events_loop, physical_device_index, @@ -40,7 +37,7 @@ } } -@@ -166,6 +176,31 @@ impl HelloTriangleApplication { +@@ -166,6 +175,31 @@ impl HelloTriangleApplication { indices } diff --git a/src/bin/05_window_surface.rs.diff b/src/bin/05_window_surface.rs.diff index c28365f..72b1cd8 100644 --- a/src/bin/05_window_surface.rs.diff +++ b/src/bin/05_window_surface.rs.diff @@ -12,17 +12,17 @@ use vulkano::instance::{ Instance, -@@ -17,6 +19,9 @@ use vulkano::instance::{ +@@ -16,6 +18,9 @@ use vulkano::instance::{ }; use vulkano::instance::debug::{DebugCallback, MessageTypes}; - use vulkano::device::{Device, DeviceExtensions, Queue}; + use vulkano::device::{Device, DeviceExtensions, Queue, Features}; +use vulkano::swapchain::{ + Surface, +}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -32,14 +37,15 @@ const ENABLE_VALIDATION_LAYERS: bool = false; +@@ -31,14 +36,15 @@ const ENABLE_VALIDATION_LAYERS: bool = false; struct QueueFamilyIndices { graphics_family: i32, @@ -40,7 +40,7 @@ } } -@@ -49,46 +55,40 @@ struct HelloTriangleApplication { +@@ -48,46 +54,40 @@ struct HelloTriangleApplication { debug_callback: Option, events_loop: EventsLoop, @@ -95,7 +95,7 @@ fn create_instance() -> Arc { if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { println!("Validation layers requested, but not available!") -@@ -149,18 +149,18 @@ impl HelloTriangleApplication { +@@ -148,18 +148,18 @@ impl HelloTriangleApplication { }).ok() } @@ -119,7 +119,7 @@ let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? for (i, queue_family) in device.queue_families().enumerate() { -@@ -168,6 +168,10 @@ impl HelloTriangleApplication { +@@ -167,6 +167,10 @@ impl HelloTriangleApplication { indices.graphics_family = i as i32; } @@ -130,7 +130,7 @@ if indices.is_complete() { break; } -@@ -178,27 +182,43 @@ impl HelloTriangleApplication { +@@ -177,27 +181,43 @@ impl HelloTriangleApplication { fn create_logical_device( instance: &Arc, diff --git a/src/bin/06_swap_chain_creation.rs.diff b/src/bin/06_swap_chain_creation.rs.diff index 7df3053..525e0c6 100644 --- a/src/bin/06_swap_chain_creation.rs.diff +++ b/src/bin/06_swap_chain_creation.rs.diff @@ -1,7 +1,7 @@ --- a/05_window_surface.rs +++ b/06_swap_chain_creation.rs -@@ -21,7 +21,16 @@ use vulkano::instance::debug::{DebugCallback, MessageTypes}; - use vulkano::device::{Device, DeviceExtensions, Queue}; +@@ -20,7 +20,16 @@ use vulkano::instance::debug::{DebugCallback, MessageTypes}; + use vulkano::device::{Device, DeviceExtensions, Queue, Features}; use vulkano::swapchain::{ Surface, + Capabilities, @@ -17,7 +17,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -30,6 +39,14 @@ const VALIDATION_LAYERS: &[&str] = &[ +@@ -29,6 +38,14 @@ const VALIDATION_LAYERS: &[&str] = &[ "VK_LAYER_LUNARG_standard_validation" ]; @@ -32,7 +32,7 @@ #[cfg(all(debug_assertions))] const ENABLE_VALIDATION_LAYERS: bool = true; #[cfg(not(debug_assertions))] -@@ -62,6 +79,9 @@ struct HelloTriangleApplication { +@@ -61,6 +78,9 @@ struct HelloTriangleApplication { graphics_queue: Arc, present_queue: Arc, @@ -42,7 +42,7 @@ } impl HelloTriangleApplication { -@@ -74,6 +94,9 @@ impl HelloTriangleApplication { +@@ -73,6 +93,9 @@ impl HelloTriangleApplication { let (device, graphics_queue, present_queue) = Self::create_logical_device( &instance, &surface, physical_device_index); @@ -52,7 +52,7 @@ Self { instance, debug_callback, -@@ -86,6 +109,9 @@ impl HelloTriangleApplication { +@@ -85,6 +108,9 @@ impl HelloTriangleApplication { graphics_queue, present_queue, @@ -62,7 +62,7 @@ } } -@@ -157,7 +183,110 @@ impl HelloTriangleApplication { +@@ -156,7 +182,110 @@ impl HelloTriangleApplication { fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { let indices = Self::find_queue_families(surface, device); @@ -174,7 +174,7 @@ } fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { -@@ -202,7 +331,7 @@ impl HelloTriangleApplication { +@@ -201,7 +330,7 @@ impl HelloTriangleApplication { // for us internally. let (device, mut queues) = Device::new(physical_device, &Features::none(), diff --git a/src/bin/08_graphics_pipeline.rs.diff b/src/bin/08_graphics_pipeline.rs.diff index 31295aa..b748cf5 100644 --- a/src/bin/08_graphics_pipeline.rs.diff +++ b/src/bin/08_graphics_pipeline.rs.diff @@ -1,6 +1,6 @@ --- a/06_swap_chain_creation.rs +++ b/08_graphics_pipeline.rs -@@ -97,6 +97,8 @@ impl HelloTriangleApplication { +@@ -96,6 +96,8 @@ impl HelloTriangleApplication { let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, &device, &graphics_queue, &present_queue); @@ -9,7 +9,7 @@ Self { instance, debug_callback, -@@ -289,6 +291,10 @@ impl HelloTriangleApplication { +@@ -288,6 +290,10 @@ impl HelloTriangleApplication { (swap_chain, images) } diff --git a/src/bin/09_shader_modules.rs b/src/bin/09_shader_modules.rs index ad1ad9a..d03d721 100644 --- a/src/bin/09_shader_modules.rs +++ b/src/bin/09_shader_modules.rs @@ -1,5 +1,4 @@ extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/09_shader_modules.rs.diff b/src/bin/09_shader_modules.rs.diff index 53ac2cf..66da05e 100644 --- a/src/bin/09_shader_modules.rs.diff +++ b/src/bin/09_shader_modules.rs.diff @@ -1,34 +1,25 @@ --- a/08_graphics_pipeline.rs +++ b/09_shader_modules.rs -@@ -1,4 +1,6 @@ - extern crate vulkano; -+#[macro_use] -+extern crate vulkano_shader_derive; - extern crate vulkano_win; - extern crate winit; - -@@ -291,8 +293,29 @@ impl HelloTriangleApplication { +@@ -290,8 +290,27 @@ impl HelloTriangleApplication { (swap_chain, images) } -- fn create_graphics_pipeline(device: &Arc) { +- fn create_graphics_pipeline(_device: &Arc) { + fn create_graphics_pipeline( + device: &Arc, + ) { -+ #[allow(unused)] + mod vertex_shader { -+ #[derive(VulkanoShader)] -+ #[ty = "vertex"] -+ #[path = "src/bin/09_shader_base.vert"] -+ struct Dummy; ++ vulkano_shaders::shader! { ++ ty: "vertex", ++ path: "src/bin/09_shader_base.vert" ++ } + } + -+ #[allow(unused)] + mod fragment_shader { -+ #[derive(VulkanoShader)] -+ #[ty = "fragment"] -+ #[path = "src/bin/09_shader_base.frag"] -+ struct Dummy; ++ vulkano_shaders::shader! { ++ ty: "fragment", ++ path: "src/bin/09_shader_base.frag" ++ } + } + let _vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/10_fixed_functions.rs b/src/bin/10_fixed_functions.rs index 07c5f87..bc11a88 100644 --- a/src/bin/10_fixed_functions.rs +++ b/src/bin/10_fixed_functions.rs @@ -1,5 +1,4 @@ extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/10_fixed_functions.rs.diff b/src/bin/10_fixed_functions.rs.diff index a721eda..0f0a547 100644 --- a/src/bin/10_fixed_functions.rs.diff +++ b/src/bin/10_fixed_functions.rs.diff @@ -1,6 +1,6 @@ ---- a/09_shader_modules.rs +--- a/./09_shader_modules.rs +++ b/10_fixed_functions.rs -@@ -33,6 +33,11 @@ use vulkano::swapchain::{ +@@ -30,6 +30,11 @@ use vulkano::swapchain::{ use vulkano::format::Format; use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; use vulkano::sync::SharingMode; @@ -12,7 +12,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -99,7 +104,7 @@ impl HelloTriangleApplication { +@@ -96,7 +101,7 @@ impl HelloTriangleApplication { let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, &device, &graphics_queue, &present_queue); @@ -21,16 +21,16 @@ Self { instance, -@@ -295,6 +300,7 @@ impl HelloTriangleApplication { +@@ -292,6 +297,7 @@ impl HelloTriangleApplication { fn create_graphics_pipeline( device: &Arc, + swap_chain_extent: [u32; 2], ) { - #[allow(unused)] mod vertex_shader { -@@ -312,10 +318,34 @@ impl HelloTriangleApplication { - struct Dummy; + vulkano_shaders::shader! { +@@ -307,10 +313,34 @@ impl HelloTriangleApplication { + } } - let _vert_shader_module = vertex_shader::Shader::load(device.clone()) diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs index 18a00bb..f4a7a0b 100644 --- a/src/bin/11_render_passes.rs +++ b/src/bin/11_render_passes.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/11_render_passes.rs.diff b/src/bin/11_render_passes.rs.diff index 4a15fe8..6dd7f4e 100644 --- a/src/bin/11_render_passes.rs.diff +++ b/src/bin/11_render_passes.rs.diff @@ -3,9 +3,9 @@ @@ -1,3 +1,4 @@ +#[macro_use] extern crate vulkano; - #[macro_use] - extern crate vulkano_shader_derive; -@@ -38,6 +39,9 @@ use vulkano::pipeline::{ + extern crate vulkano_win; + extern crate winit; +@@ -35,6 +36,9 @@ use vulkano::pipeline::{ vertex::BufferlessDefinition, viewport::Viewport, }; @@ -15,7 +15,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -89,6 +93,8 @@ struct HelloTriangleApplication { +@@ -86,6 +90,8 @@ struct HelloTriangleApplication { swap_chain: Arc>, swap_chain_images: Vec>>, @@ -24,17 +24,15 @@ } impl HelloTriangleApplication { -@@ -104,7 +110,8 @@ impl HelloTriangleApplication { +@@ -101,6 +107,7 @@ impl HelloTriangleApplication { let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, &device, &graphics_queue, &present_queue); -- Self::create_graphics_pipeline(&device, swap_chain.dimensions()); + let render_pass = Self::create_render_pass(&device, swap_chain.format()); -+ Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + Self::create_graphics_pipeline(&device, swap_chain.dimensions()); Self { - instance, -@@ -121,6 +128,8 @@ impl HelloTriangleApplication { +@@ -118,6 +125,8 @@ impl HelloTriangleApplication { swap_chain, swap_chain_images, @@ -43,7 +41,7 @@ } } -@@ -298,6 +307,23 @@ impl HelloTriangleApplication { +@@ -295,6 +304,23 @@ impl HelloTriangleApplication { (swap_chain, images) } diff --git a/src/bin/12_graphics_pipeline_complete.rs b/src/bin/12_graphics_pipeline_complete.rs index 8ffb4ef..638279d 100644 --- a/src/bin/12_graphics_pipeline_complete.rs +++ b/src/bin/12_graphics_pipeline_complete.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/12_graphics_pipeline_complete.rs.diff b/src/bin/12_graphics_pipeline_complete.rs.diff index abfcbe3..f231198 100644 --- a/src/bin/12_graphics_pipeline_complete.rs.diff +++ b/src/bin/12_graphics_pipeline_complete.rs.diff @@ -1,6 +1,6 @@ --- a/11_render_passes.rs +++ b/12_graphics_pipeline_complete.rs -@@ -41,7 +41,9 @@ use vulkano::pipeline::{ +@@ -38,7 +38,9 @@ use vulkano::pipeline::{ }; use vulkano::framebuffer::{ RenderPassAbstract, @@ -10,7 +10,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -77,6 +79,8 @@ impl QueueFamilyIndices { +@@ -74,6 +76,8 @@ impl QueueFamilyIndices { } } @@ -19,7 +19,7 @@ #[allow(unused)] struct HelloTriangleApplication { instance: Arc, -@@ -95,6 +99,11 @@ struct HelloTriangleApplication { +@@ -92,6 +96,11 @@ struct HelloTriangleApplication { swap_chain_images: Vec>>, render_pass: Arc, @@ -31,16 +31,16 @@ } impl HelloTriangleApplication { -@@ -111,7 +120,7 @@ impl HelloTriangleApplication { +@@ -108,7 +117,7 @@ impl HelloTriangleApplication { &device, &graphics_queue, &present_queue); let render_pass = Self::create_render_pass(&device, swap_chain.format()); -- Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); +- Self::create_graphics_pipeline(&device, swap_chain.dimensions()); + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); Self { instance, -@@ -130,6 +139,7 @@ impl HelloTriangleApplication { +@@ -127,6 +136,7 @@ impl HelloTriangleApplication { swap_chain_images, render_pass, @@ -48,18 +48,17 @@ } } -@@ -327,8 +337,8 @@ impl HelloTriangleApplication { +@@ -324,7 +334,8 @@ impl HelloTriangleApplication { fn create_graphics_pipeline( device: &Arc, swap_chain_extent: [u32; 2], -- _render_pass: &Arc, - ) { + render_pass: &Arc, + ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] -@@ -357,7 +367,7 @@ impl HelloTriangleApplication { + vulkano_shaders::shader! { + ty: "vertex", +@@ -351,7 +362,7 @@ impl HelloTriangleApplication { depth_range: 0.0 .. 1.0, }; @@ -68,7 +67,7 @@ .vertex_input(BufferlessDefinition {}) .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() -@@ -372,7 +382,10 @@ impl HelloTriangleApplication { +@@ -366,7 +377,10 @@ impl HelloTriangleApplication { .front_face_clockwise() // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default diff --git a/src/bin/13_framebuffers.rs b/src/bin/13_framebuffers.rs index 2966b33..e049890 100644 --- a/src/bin/13_framebuffers.rs +++ b/src/bin/13_framebuffers.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/13_framebuffers.rs.diff b/src/bin/13_framebuffers.rs.diff index 3f81dd6..1fed988 100644 --- a/src/bin/13_framebuffers.rs.diff +++ b/src/bin/13_framebuffers.rs.diff @@ -1,6 +1,6 @@ --- a/12_graphics_pipeline_complete.rs +++ b/13_framebuffers.rs -@@ -42,6 +42,8 @@ use vulkano::pipeline::{ +@@ -39,6 +39,8 @@ use vulkano::pipeline::{ use vulkano::framebuffer::{ RenderPassAbstract, Subpass, @@ -9,7 +9,7 @@ }; use vulkano::descriptor::PipelineLayoutAbstract; -@@ -104,6 +106,8 @@ struct HelloTriangleApplication { +@@ -101,6 +103,8 @@ struct HelloTriangleApplication { // works when the concrete type of the graphics pipeline is visible // to the command buffer. graphics_pipeline: Arc, @@ -18,7 +18,7 @@ } impl HelloTriangleApplication { -@@ -122,6 +126,8 @@ impl HelloTriangleApplication { +@@ -119,6 +123,8 @@ impl HelloTriangleApplication { let render_pass = Self::create_render_pass(&device, swap_chain.format()); let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); @@ -27,7 +27,7 @@ Self { instance, debug_callback, -@@ -140,6 +146,8 @@ impl HelloTriangleApplication { +@@ -137,6 +143,8 @@ impl HelloTriangleApplication { render_pass, graphics_pipeline, @@ -36,7 +36,7 @@ } } -@@ -388,6 +396,20 @@ impl HelloTriangleApplication { +@@ -383,6 +391,20 @@ impl HelloTriangleApplication { ) } diff --git a/src/bin/14_command_buffers.rs b/src/bin/14_command_buffers.rs index 51be210..64a54c6 100644 --- a/src/bin/14_command_buffers.rs +++ b/src/bin/14_command_buffers.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/14_command_buffers.rs.diff b/src/bin/14_command_buffers.rs.diff index 50f433e..021a5ef 100644 --- a/src/bin/14_command_buffers.rs.diff +++ b/src/bin/14_command_buffers.rs.diff @@ -1,6 +1,6 @@ --- a/13_framebuffers.rs +++ b/14_command_buffers.rs -@@ -37,6 +37,7 @@ use vulkano::sync::SharingMode; +@@ -34,6 +34,7 @@ use vulkano::sync::SharingMode; use vulkano::pipeline::{ GraphicsPipeline, vertex::BufferlessDefinition, @@ -8,7 +8,7 @@ viewport::Viewport, }; use vulkano::framebuffer::{ -@@ -46,6 +47,11 @@ use vulkano::framebuffer::{ +@@ -43,6 +44,11 @@ use vulkano::framebuffer::{ Framebuffer, }; use vulkano::descriptor::PipelineLayoutAbstract; @@ -20,7 +20,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -108,6 +114,8 @@ struct HelloTriangleApplication { +@@ -105,6 +111,8 @@ struct HelloTriangleApplication { graphics_pipeline: Arc, swap_chain_framebuffers: Vec>, @@ -29,7 +29,7 @@ } impl HelloTriangleApplication { -@@ -128,7 +136,7 @@ impl HelloTriangleApplication { +@@ -125,7 +133,7 @@ impl HelloTriangleApplication { let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); @@ -38,7 +38,7 @@ instance, debug_callback, -@@ -148,7 +156,12 @@ impl HelloTriangleApplication { +@@ -145,7 +153,12 @@ impl HelloTriangleApplication { graphics_pipeline, swap_chain_framebuffers, @@ -52,7 +52,7 @@ } fn create_instance() -> Arc { -@@ -410,6 +423,26 @@ impl HelloTriangleApplication { +@@ -405,6 +418,26 @@ impl HelloTriangleApplication { ).collect::>() } diff --git a/src/bin/15_hello_triangle.rs b/src/bin/15_hello_triangle.rs index 929d3c3..6924baf 100644 --- a/src/bin/15_hello_triangle.rs +++ b/src/bin/15_hello_triangle.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/15_hello_triangle.rs.diff b/src/bin/15_hello_triangle.rs.diff index 2f82768..e3a97a1 100644 --- a/src/bin/15_hello_triangle.rs.diff +++ b/src/bin/15_hello_triangle.rs.diff @@ -1,6 +1,6 @@ --- a/14_command_buffers.rs +++ b/15_hello_triangle.rs -@@ -30,10 +30,11 @@ use vulkano::swapchain::{ +@@ -27,10 +27,11 @@ use vulkano::swapchain::{ PresentMode, Swapchain, CompositeAlpha, @@ -13,7 +13,7 @@ use vulkano::pipeline::{ GraphicsPipeline, vertex::BufferlessDefinition, -@@ -507,6 +508,8 @@ impl HelloTriangleApplication { +@@ -502,6 +503,8 @@ impl HelloTriangleApplication { #[allow(unused)] fn main_loop(&mut self) { loop { @@ -22,7 +22,7 @@ let mut done = false; self.events_loop.poll_events(|ev| { match ev { -@@ -519,9 +522,24 @@ impl HelloTriangleApplication { +@@ -514,9 +517,24 @@ impl HelloTriangleApplication { } } } diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs index e8b8dbc..4051bc5 100644 --- a/src/bin/16_swap_chain_recreation.rs +++ b/src/bin/16_swap_chain_recreation.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/16_swap_chain_recreation.rs.diff b/src/bin/16_swap_chain_recreation.rs.diff index c8d4184..6465600 100644 --- a/src/bin/16_swap_chain_recreation.rs.diff +++ b/src/bin/16_swap_chain_recreation.rs.diff @@ -1,6 +1,6 @@ --- a/15_hello_triangle.rs +++ b/16_swap_chain_recreation.rs -@@ -31,10 +31,11 @@ use vulkano::swapchain::{ +@@ -28,10 +28,11 @@ use vulkano::swapchain::{ Swapchain, CompositeAlpha, acquire_next_image, @@ -13,55 +13,55 @@ use vulkano::pipeline::{ GraphicsPipeline, vertex::BufferlessDefinition, -@@ -90,9 +91,9 @@ impl QueueFamilyIndices { - +@@ -87,9 +88,9 @@ impl QueueFamilyIndices { + type ConcreteGraphicsPipeline = GraphicsPipeline, Arc>; - + -#[allow(unused)] struct HelloTriangleApplication { instance: Arc, + #[allow(unused)] debug_callback: Option, - + events_loop: EventsLoop, -@@ -117,6 +118,9 @@ struct HelloTriangleApplication { +@@ -114,6 +115,9 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, - + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, } - + impl HelloTriangleApplication { -@@ -130,13 +134,15 @@ impl HelloTriangleApplication { +@@ -127,13 +131,15 @@ impl HelloTriangleApplication { &instance, &surface, physical_device_index); - + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, - &device, &graphics_queue, &present_queue); + &device, &graphics_queue, &present_queue, None); - + let render_pass = Self::create_render_pass(&device, swap_chain.format()); let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); - + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); - + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + let mut app = Self { instance, debug_callback, -@@ -159,6 +165,9 @@ impl HelloTriangleApplication { +@@ -156,6 +162,9 @@ impl HelloTriangleApplication { swap_chain_framebuffers, - + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, }; - + app.create_command_buffers(); -@@ -293,6 +302,7 @@ impl HelloTriangleApplication { +@@ -290,6 +299,7 @@ impl HelloTriangleApplication { device: &Arc, graphics_queue: &Arc, present_queue: &Arc, @@ -69,19 +69,19 @@ ) -> (Arc>, Vec>>) { let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); let capabilities = surface.capabilities(physical_device) -@@ -333,7 +343,7 @@ impl HelloTriangleApplication { +@@ -330,7 +340,7 @@ impl HelloTriangleApplication { CompositeAlpha::Opaque, present_mode, true, // clipped - None, + old_swapchain.as_ref() ).expect("failed to create swap chain!"); - + (swap_chain, images) -@@ -444,6 +454,10 @@ impl HelloTriangleApplication { +@@ -439,6 +449,10 @@ impl HelloTriangleApplication { .collect(); } - + + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box + } @@ -89,9 +89,9 @@ fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? -@@ -524,18 +538,61 @@ impl HelloTriangleApplication { +@@ -519,18 +533,59 @@ impl HelloTriangleApplication { } - + fn draw_frame(&mut self) { - let (image_index, acquire_future) = acquire_next_image(self.swap_chain.clone(), None).unwrap(); + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); @@ -109,9 +109,9 @@ + }, + Err(err) => panic!("{:?}", err) + }; - + let command_buffer = self.command_buffers[image_index].clone(); - + - let future = acquire_future + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) @@ -138,14 +138,14 @@ + } + } + } -+ + +- future.wait(None).unwrap(); + fn recreate_swap_chain(&mut self) { + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; - -- future.wait(None).unwrap(); ++ + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); @@ -153,4 +153,4 @@ + self.create_command_buffers(); } } - + diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs index db5d3eb..b61ff5a 100644 --- a/src/bin/18_vertex_buffer.rs +++ b/src/bin/18_vertex_buffer.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/18_vertex_buffer.rs.diff b/src/bin/18_vertex_buffer.rs.diff index 9ebd450..97d8193 100644 --- a/src/bin/18_vertex_buffer.rs.diff +++ b/src/bin/18_vertex_buffer.rs.diff @@ -1,6 +1,6 @@ --- a/16_swap_chain_recreation.rs +++ b/18_vertex_buffer.rs -@@ -38,8 +38,7 @@ use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +@@ -35,8 +35,7 @@ use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; use vulkano::sync::{self, SharingMode, GpuFuture}; use vulkano::pipeline::{ GraphicsPipeline, @@ -10,7 +10,7 @@ viewport::Viewport, }; use vulkano::framebuffer::{ -@@ -48,12 +47,16 @@ use vulkano::framebuffer::{ +@@ -45,12 +44,16 @@ use vulkano::framebuffer::{ FramebufferAbstract, Framebuffer, }; @@ -28,7 +28,7 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -89,7 +92,25 @@ impl QueueFamilyIndices { +@@ -86,7 +89,25 @@ impl QueueFamilyIndices { } } @@ -55,7 +55,7 @@ struct HelloTriangleApplication { instance: Arc, -@@ -109,14 +130,11 @@ struct HelloTriangleApplication { +@@ -106,14 +127,11 @@ struct HelloTriangleApplication { swap_chain_images: Vec>>, render_pass: Arc, @@ -72,7 +72,7 @@ command_buffers: Vec>, previous_frame_end: Option>, -@@ -141,6 +159,8 @@ impl HelloTriangleApplication { +@@ -138,6 +156,8 @@ impl HelloTriangleApplication { let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); @@ -81,7 +81,7 @@ let previous_frame_end = Some(Self::create_sync_objects(&device)); let mut app = Self { -@@ -164,6 +184,7 @@ impl HelloTriangleApplication { +@@ -161,6 +181,7 @@ impl HelloTriangleApplication { swap_chain_framebuffers, @@ -89,31 +89,29 @@ command_buffers: vec![], previous_frame_end, -@@ -370,12 +391,12 @@ impl HelloTriangleApplication { +@@ -367,18 +388,18 @@ impl HelloTriangleApplication { device: &Arc, swap_chain_extent: [u32; 2], render_pass: &Arc, - ) -> Arc { + ) -> Arc { - #[allow(unused)] mod vertex_shader { - #[derive(VulkanoShader)] - #[ty = "vertex"] -- #[path = "src/bin/09_shader_base.vert"] -+ #[path = "src/bin/17_shader_vertexbuffer.vert"] - struct Dummy; + vulkano_shaders::shader! { + ty: "vertex", +- path: "src/bin/09_shader_base.vert" ++ path: "src/bin/17_shader_vertexbuffer.vert" + } } -@@ -383,7 +404,7 @@ impl HelloTriangleApplication { mod fragment_shader { - #[derive(VulkanoShader)] - #[ty = "fragment"] -- #[path = "src/bin/09_shader_base.frag"] -+ #[path = "src/bin/17_shader_vertexbuffer.frag"] - struct Dummy; + vulkano_shaders::shader! { + ty: "fragment", +- path: "src/bin/09_shader_base.frag" ++ path: "src/bin/17_shader_vertexbuffer.frag" + } } -@@ -400,7 +421,7 @@ impl HelloTriangleApplication { +@@ -395,7 +416,7 @@ impl HelloTriangleApplication { }; Arc::new(GraphicsPipeline::start() @@ -122,7 +120,7 @@ .vertex_shader(vert_shader_module.main_entry_point(), ()) .triangle_list() .primitive_restart(false) -@@ -434,17 +455,21 @@ impl HelloTriangleApplication { +@@ -429,17 +450,21 @@ impl HelloTriangleApplication { ).collect::>() } diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs index e0a743f..4d5447c 100644 --- a/src/bin/19_staging_buffer.rs +++ b/src/bin/19_staging_buffer.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/19_staging_buffer.rs.diff b/src/bin/19_staging_buffer.rs.diff index 296017b..85fe09e 100644 --- a/src/bin/19_staging_buffer.rs.diff +++ b/src/bin/19_staging_buffer.rs.diff @@ -1,6 +1,6 @@ --- a/18_vertex_buffer.rs +++ b/19_staging_buffer.rs -@@ -53,7 +53,7 @@ use vulkano::command_buffer::{ +@@ -50,7 +50,7 @@ use vulkano::command_buffer::{ DynamicState, }; use vulkano::buffer::{ @@ -9,7 +9,7 @@ BufferUsage, BufferAccess, }; -@@ -159,7 +159,7 @@ impl HelloTriangleApplication { +@@ -156,7 +156,7 @@ impl HelloTriangleApplication { let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); @@ -18,7 +18,7 @@ let previous_frame_end = Some(Self::create_sync_objects(&device)); -@@ -455,9 +455,13 @@ impl HelloTriangleApplication { +@@ -450,9 +450,13 @@ impl HelloTriangleApplication { ).collect::>() } diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index 3f2a464..d12c154 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; diff --git a/src/bin/20_index_buffer.rs.diff b/src/bin/20_index_buffer.rs.diff index 1f967e2..808ad3b 100644 --- a/src/bin/20_index_buffer.rs.diff +++ b/src/bin/20_index_buffer.rs.diff @@ -1,6 +1,6 @@ --- a/19_staging_buffer.rs +++ b/20_index_buffer.rs -@@ -56,6 +56,7 @@ use vulkano::buffer::{ +@@ -53,6 +53,7 @@ use vulkano::buffer::{ immutable::ImmutableBuffer, BufferUsage, BufferAccess, @@ -8,7 +8,7 @@ }; const WIDTH: u32 = 800; -@@ -104,14 +105,19 @@ impl Vertex { +@@ -101,14 +102,19 @@ impl Vertex { } impl_vertex!(Vertex, pos, color); @@ -32,7 +32,7 @@ struct HelloTriangleApplication { instance: Arc, #[allow(unused)] -@@ -135,6 +141,7 @@ struct HelloTriangleApplication { +@@ -132,6 +138,7 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, vertex_buffer: Arc, @@ -40,7 +40,7 @@ command_buffers: Vec>, previous_frame_end: Option>, -@@ -160,6 +167,7 @@ impl HelloTriangleApplication { +@@ -157,6 +164,7 @@ impl HelloTriangleApplication { let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); @@ -48,7 +48,7 @@ let previous_frame_end = Some(Self::create_sync_objects(&device)); -@@ -185,6 +193,7 @@ impl HelloTriangleApplication { +@@ -182,6 +190,7 @@ impl HelloTriangleApplication { swap_chain_framebuffers, vertex_buffer, @@ -56,7 +56,7 @@ command_buffers: vec![], previous_frame_end, -@@ -464,6 +473,15 @@ impl HelloTriangleApplication { +@@ -459,6 +468,15 @@ impl HelloTriangleApplication { buffer } @@ -72,7 +72,7 @@ fn create_command_buffers(&mut self) { let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() -@@ -472,8 +490,9 @@ impl HelloTriangleApplication { +@@ -467,8 +485,9 @@ impl HelloTriangleApplication { .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() diff --git a/src/main.rs b/src/main.rs index 3f2a464..d12c154 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,5 @@ #[macro_use] extern crate vulkano; -#[macro_use] extern crate vulkano_win; extern crate winit; From a2b90324233093ca657f93d547c376ab879dd952 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sun, 3 Feb 2019 13:11:56 -0500 Subject: [PATCH 66/78] adds chapter section 21 -- adds uniform buffer to shader, struct in rust code, method to create uniform buffer for each image, and method to update uniform buffer per frame --- Cargo.lock | 203 +++++ Cargo.toml | 1 + README.md | 23 +- src/bin/21_descriptor_layout_and_buffer.rs | 723 ++++++++++++++++++ .../21_descriptor_layout_and_buffer.rs.diff | 188 +++++ src/bin/21_shader_uniformbuffer.frag | 10 + src/bin/21_shader_uniformbuffer.vert | 23 + src/bin/21_shader_uniformbuffer.vert.diff | 25 + 8 files changed, 1194 insertions(+), 2 deletions(-) create mode 100644 src/bin/21_descriptor_layout_and_buffer.rs create mode 100644 src/bin/21_descriptor_layout_and_buffer.rs.diff create mode 100644 src/bin/21_shader_uniformbuffer.frag create mode 100644 src/bin/21_shader_uniformbuffer.vert create mode 100644 src/bin/21_shader_uniformbuffer.vert.diff diff --git a/Cargo.lock b/Cargo.lock index 5ae7730..2c4d0b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,14 @@ name = "adler32" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "aho-corasick" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "andrew" version = "0.1.6" @@ -274,6 +282,15 @@ name = "either" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "env_logger" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fnv" version = "1.0.6" @@ -325,6 +342,16 @@ dependencies = [ "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "glm" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "quickcheck 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "half" version = "1.1.2" @@ -364,6 +391,15 @@ dependencies = [ "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.1.0" @@ -403,6 +439,14 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.4" @@ -424,6 +468,14 @@ dependencies = [ "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "memmap" version = "0.7.0" @@ -472,6 +524,39 @@ name = "nodrop" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-derive" version = "0.2.2" @@ -500,6 +585,17 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-rational" version = "0.2.1" @@ -644,6 +740,16 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quickcheck" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.6.11" @@ -652,6 +758,27 @@ dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.5.5" @@ -794,11 +921,33 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc-demangle" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -925,6 +1074,23 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tiff" version = "0.2.1" @@ -949,6 +1115,11 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.1.4" @@ -968,6 +1139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vulkan-tutorial-rs" version = "0.1.0" dependencies = [ + "glm 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", "vulkano 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "vulkano-shaders 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1076,6 +1248,11 @@ dependencies = [ "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.6" @@ -1085,6 +1262,11 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1147,6 +1329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum andrew 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "142e9e6a99ad0d63a4cf6ce58a4c979f472c5815cbf7e5ca4e47b26a10dc728e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" "checksum approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c57ff1a5b00753647aebbbcf4ea67fa1e711a65ea7a30eb90dbf07de2485aee" @@ -1179,6 +1362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" "checksum downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "18df8ce4470c189d18aa926022da57544f31e154631eb4cfe796aea97051fe6c" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" +"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "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" @@ -1187,26 +1371,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" +"checksum glm 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1c702ce44565c0a09122e1c1d806bffef6528ff5de7bd0bcf636776a32953c7a" "checksum half 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a581f551b77eb3e177584e922a8c057e14311a857f859fd39d9574d97d3547da" "checksum image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44665b4395d1844c96e7dc8ed5754782a1cdfd9ef458a80bbe45702681450504" "checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245" "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" +"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum metal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7de9c2b83c946ab01c9942928388f911d93486b97636d9927541345905fea65d" "checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" +"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" "checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" +"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" @@ -1224,7 +1416,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "104630aa1c83213cbc76db0703630fcb0421dac3585063be4ce9a8a2feeaa745" "checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum quickcheck 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d086a75fc7bdfbadd649f7c1fa524f39be4979b15506f621b3742b752f5364ed" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -1240,7 +1435,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" +"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusttype 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ae90f66c7ca5fb2c566d373c9ccb3ce1ae1aeebf236b74ad0d413196facb31b3" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" @@ -1256,9 +1454,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b7bfcbb0c068d0f642a0ffbd5c604965a360a61f99e8add013cef23a838614f3" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a2cc6c4fd13cb1cfd20abdb196e794ceccb29371855b7e7f575945f920a5b3c2" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum vk-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36f5fd4a7d6d5d19808610583131c0aed271556527cad4cb71c436831a28e059" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" @@ -1271,7 +1472,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wayland-protocols 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fd94211387fa8ff50df1e4ff7a5529b5a9aebe68ba88acc48e5b7f5fd98f6eef" "checksum wayland-scanner 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3611f231e675e15c2feb7623103e6449edc6f10b0598cafb3e16e590a0561355" "checksum wayland-sys 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2a69d729a1747a5bf40ae05b94c7904b64fbf2381e365c046d872ce4a34aa826" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index c9dadb8..48e276c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ vulkano-shaders = "0.11.1" image = "0.20.1" vulkano-win = "0.11.1" winit = "0.18.0" +glm = "0.2.3" # [[bin]] # name = "main" diff --git a/README.md b/README.md index dbca5a2..a8e1265 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Rust version of https://github.com/Overv/VulkanTutorial using [Vulkano](http://v * [Vertex buffer creation](#vertex-buffer-creation) * [Staging buffer](#staging-buffer) * [Index buffer](#index-buffer) -* [Uniform buffers (TODO)](#uniform-buffers-todo) +* [Uniform buffers](#uniform-buffers) * [Texture mapping (TODO)](#texture-mapping-todo) * [Depth buffering (TODO)](#depth-buffering-todo) * [Loading models (TODO)](#loading-models-todo) @@ -332,7 +332,26 @@ https://vulkan-tutorial.com/Vertex_buffers/Index_buffer [Diff](src/bin/20_index_buffer.rs.diff) / [Complete code](src/bin/20_index_buffer.rs) -## Uniform buffers (*TODO*) +## Uniform buffers +### Uniform Buffer Object +https://vulkan-tutorial.com/Uniform_buffers + +In this section we change the vertex shader to take a uniform buffer object consisting of a model, view, and projection matrix. +The shader now outputs the final position as the result of multiplying these three matrices with the original vertex position. + +We add a new type of buffer, the CpuAccessibleBuffer, which allows us to update its contents without needing to rebuild +the entire buffer. In order to actually be able to write to this buffer we need to specify its usage as a uniform buffer and +also the destination of a memory transfer. + +Note that unlike the original tutorial we did **not** need to create any layout binding. This is handled internally by vulkano when creating +a descriptor set, as we'll see in the next section. + +At this point our program will compile and run but immediately panic because we specify a binding in our shader but do not +include a matching descriptor set. + +[Vertex Shader Diff](src/bin/21_shader_uniformbuffer.vert.diff) / [Vertex Shader](src/bin/21_shader_uniformbuffer.vert) + +[Diff](src/bin/21_descriptor_layout_and_buffer.rs) / [Complete code](src/bin/21_descriptor_layout_and_buffer.rs) ## Texture mapping (*TODO*) ## Depth buffering (*TODO*) ## Loading models (*TODO*) diff --git a/src/bin/21_descriptor_layout_and_buffer.rs b/src/bin/21_descriptor_layout_and_buffer.rs new file mode 100644 index 0000000..c4b39b9 --- /dev/null +++ b/src/bin/21_descriptor_layout_and_buffer.rs @@ -0,0 +1,723 @@ +#[macro_use] +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::Arc; +use std::collections::HashSet; +use std::time::Instant; + +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image, + AcquireError, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{self, SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + GraphicsPipelineAbstract, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; +use vulkano::buffer::{ + immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, + TypedBufferAccess, + CpuAccessibleBuffer, +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} +impl Vertex { + fn new(pos: [f32; 2], color: [f32; 3]) -> Self { + Self { pos, color } + } +} +impl_vertex!(Vertex, pos, color); + +#[derive(Copy, Clone)] +struct UniformBufferObject { + model: glm::Mat4, + view: glm::Mat4, + proj: glm::Mat4, +} + +fn vertices() -> [Vertex; 4] { + [ + Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), + Vertex::new([0.5, -0.5], [0.0, 1.0, 0.0]), + Vertex::new([0.5, 0.5], [0.0, 0.0, 1.0]), + Vertex::new([-0.5, 0.5], [1.0, 1.0, 1.0]) + ] +} + +fn indices() -> [u16; 6] { + [0, 1, 2, 2, 3, 0] +} + +struct HelloTriangleApplication { + instance: Arc, + #[allow(unused)] + debug_callback: Option, + + events_loop: EventsLoop, + surface: Arc>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, + + graphics_queue: Arc, + present_queue: Arc, + + swap_chain: Arc>, + swap_chain_images: Vec>>, + + render_pass: Arc, + graphics_pipeline: Arc, + + swap_chain_framebuffers: Vec>, + + vertex_buffer: Arc, + index_buffer: Arc + Send + Sync>, + uniform_buffers: Vec>>, + + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, + + start_time: Instant, +} + +impl HelloTriangleApplication { + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); + + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let start_time = Instant::now(); + + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + let index_buffer = Self::create_index_buffer(&graphics_queue); + let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + vertex_buffer, + index_buffer, + uniform_buffers, + + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, + + start_time + }; + + app.create_command_buffers(); + app + } + + fn create_instance() -> Arc { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(instance: &Arc) -> Option { + if !ENABLE_VALIDATION_LAYERS { + return None; + } + + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + DebugCallback::new(&instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok() + } + + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") + } + + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = Self::choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = Self::find_queue_families(&surface, &physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![graphics_queue, present_queue].as_slice().into() + } else { + graphics_queue.into() + }; + + let (swap_chain, images) = Swapchain::new( + device.clone(), + surface.clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + old_swapchain.as_ref() + ).expect("failed to create swap chain!"); + + (swap_chain, images) + } + + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: color_format, + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap()) + } + + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { + mod vertex_shader { + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/21_shader_uniformbuffer.vert" + } + } + + mod fragment_shader { + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/21_shader_uniformbuffer.frag" + } + } + + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + ) + } + + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>() + } + + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), + graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); + buffer + } + + fn create_index_buffer(graphics_queue: &Arc) -> Arc + Send + Sync> { + let (buffer, future) = ImmutableBuffer::from_iter( + indices().iter().cloned(), BufferUsage::index_buffer(), + graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); + buffer + } + + fn create_uniform_buffers( + device: &Arc, + num_buffers: usize, + start_time: Instant, + dimensions_u32: [u32; 2] + ) -> Vec>> { + let mut buffers = Vec::new(); + + let dimensions = [dimensions_u32[0] as f32, dimensions_u32[1] as f32]; + + let uniform_buffer = Self::update_uniform_buffer(start_time, dimensions); + + for _ in 0..num_buffers { + let buffer = CpuAccessibleBuffer::from_data( + device.clone(), + BufferUsage::uniform_buffer_transfer_destination(), + uniform_buffer, + ).unwrap(); + + buffers.push(buffer); + } + + buffers + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.family(); + self.command_buffers = self.swap_chain_framebuffers.iter() + .map(|framebuffer| { + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw_indexed( + self.graphics_pipeline.clone(), + &DynamicState::none(), + vec![self.vertex_buffer.clone()], + self.index_buffer.clone(), + (), + ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box + } + + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if surface.is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); + + (device, graphics_queue, present_queue) + } + + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.draw_frame(); + + let mut done = false; + self.events_loop.poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + + let command_buffer = self.command_buffers[image_index].clone(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) + .then_execute(self.graphics_queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + } + } + + fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { + let duration = Instant::now().duration_since(start_time); + let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; + + let identity_matrix = glm::mat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + ); + + let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); + + let view = glm::ext::look_at( + glm::vec3(2.0, 2.0, 2.0), + glm::vec3(0.0, 0.0, 0.0), + glm::vec3(0.0, 0.0, 1.0) + ); + let mut proj = glm::ext::perspective( + glm::radians(45.0,), + dimensions[0] as f32 / dimensions[1] as f32, + 0.1, + 10.0 + ); + + proj.c1.y *= -1.0; + + UniformBufferObject { model, view, proj } + } + + fn recreate_swap_chain(&mut self) { + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; + + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); + } +} + +fn main() { + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); +} \ No newline at end of file diff --git a/src/bin/21_descriptor_layout_and_buffer.rs.diff b/src/bin/21_descriptor_layout_and_buffer.rs.diff new file mode 100644 index 0000000..f8edb19 --- /dev/null +++ b/src/bin/21_descriptor_layout_and_buffer.rs.diff @@ -0,0 +1,188 @@ +--- a/20_index_buffer.rs ++++ b/21_descriptor_layout_and_buffer.rs +@@ -5,6 +5,7 @@ extern crate winit; + + use std::sync::Arc; + use std::collections::HashSet; ++use std::time::Instant; + + use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; + use vulkano_win::VkSurfaceBuild; +@@ -54,6 +55,7 @@ use vulkano::buffer::{ + BufferUsage, + BufferAccess, + TypedBufferAccess, ++ CpuAccessibleBuffer, + }; + + const WIDTH: u32 = 800; +@@ -102,6 +104,13 @@ impl Vertex { + } + impl_vertex!(Vertex, pos, color); + ++#[derive(Copy, Clone)] ++struct UniformBufferObject { ++ model: glm::Mat4, ++ view: glm::Mat4, ++ proj: glm::Mat4, ++} ++ + fn vertices() -> [Vertex; 4] { + [ + Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), +@@ -139,10 +148,14 @@ struct HelloTriangleApplication { + + vertex_buffer: Arc, + index_buffer: Arc + Send + Sync>, ++ uniform_buffers: Vec>>, ++ + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, ++ ++ start_time: Instant, + } + + impl HelloTriangleApplication { +@@ -159,12 +172,16 @@ impl HelloTriangleApplication { + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); ++ + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + ++ let start_time = Instant::now(); ++ + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + let index_buffer = Self::create_index_buffer(&graphics_queue); ++ let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + +@@ -191,10 +208,14 @@ impl HelloTriangleApplication { + + vertex_buffer, + index_buffer, ++ uniform_buffers, ++ + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, ++ ++ start_time + }; + + app.create_command_buffers(); +@@ -401,14 +422,14 @@ impl HelloTriangleApplication { + mod vertex_shader { + vulkano_shaders::shader! { + ty: "vertex", +- path: "src/bin/17_shader_vertexbuffer.vert" ++ path: "src/bin/21_shader_uniformbuffer.vert" + } + } + + mod fragment_shader { + vulkano_shaders::shader! { + ty: "fragment", +- path: "src/bin/17_shader_vertexbuffer.frag" ++ path: "src/bin/21_shader_uniformbuffer.frag" + } + } + +@@ -477,6 +498,31 @@ impl HelloTriangleApplication { + buffer + } + ++ fn create_uniform_buffers( ++ device: &Arc, ++ num_buffers: usize, ++ start_time: Instant, ++ dimensions_u32: [u32; 2] ++ ) -> Vec>> { ++ let mut buffers = Vec::new(); ++ ++ let dimensions = [dimensions_u32[0] as f32, dimensions_u32[1] as f32]; ++ ++ let uniform_buffer = Self::update_uniform_buffer(start_time, dimensions); ++ ++ for _ in 0..num_buffers { ++ let buffer = CpuAccessibleBuffer::from_data( ++ device.clone(), ++ BufferUsage::uniform_buffer_transfer_destination(), ++ uniform_buffer, ++ ).unwrap(); ++ ++ buffers.push(buffer); ++ } ++ ++ buffers ++ } ++ + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.family(); + self.command_buffers = self.swap_chain_framebuffers.iter() +@@ -485,9 +531,13 @@ impl HelloTriangleApplication { + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() +- .draw_indexed(self.graphics_pipeline.clone(), &DynamicState::none(), ++ .draw_indexed( ++ self.graphics_pipeline.clone(), ++ &DynamicState::none(), + vec![self.vertex_buffer.clone()], +- self.index_buffer.clone(), (), ()) ++ self.index_buffer.clone(), ++ (), ++ ()) + .unwrap() + .end_render_pass() + .unwrap() +@@ -623,6 +673,36 @@ impl HelloTriangleApplication { + } + } + ++ fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { ++ let duration = Instant::now().duration_since(start_time); ++ let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; ++ ++ let identity_matrix = glm::mat4( ++ 1.0, 0.0, 0.0, 0.0, ++ 0.0, 1.0, 0.0, 0.0, ++ 0.0, 0.0, 1.0, 0.0, ++ 0.0, 0.0, 0.0, 1.0, ++ ); ++ ++ let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); ++ ++ let view = glm::ext::look_at( ++ glm::vec3(2.0, 2.0, 2.0), ++ glm::vec3(0.0, 0.0, 0.0), ++ glm::vec3(0.0, 0.0, 1.0) ++ ); ++ let mut proj = glm::ext::perspective( ++ glm::radians(45.0,), ++ dimensions[0] as f32 / dimensions[1] as f32, ++ 0.1, ++ 10.0 ++ ); ++ ++ proj.c1.y *= -1.0; ++ ++ UniformBufferObject { model, view, proj } ++ } ++ + fn recreate_swap_chain(&mut self) { + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); +@@ -640,4 +720,4 @@ impl HelloTriangleApplication { + fn main() { + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); +-} ++} +\ No newline at end of file diff --git a/src/bin/21_shader_uniformbuffer.frag b/src/bin/21_shader_uniformbuffer.frag new file mode 100644 index 0000000..84daf5e --- /dev/null +++ b/src/bin/21_shader_uniformbuffer.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/src/bin/21_shader_uniformbuffer.vert b/src/bin/21_shader_uniformbuffer.vert new file mode 100644 index 0000000..36af825 --- /dev/null +++ b/src/bin/21_shader_uniformbuffer.vert @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + +// NOTE: names must match the `Vertex` struct in Rust +layout(location = 0) in vec2 pos; +layout(location = 1) in vec3 color; + +layout(location = 0) out vec3 fragColor; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(pos, 0.0, 1.0); + fragColor = color; +} \ No newline at end of file diff --git a/src/bin/21_shader_uniformbuffer.vert.diff b/src/bin/21_shader_uniformbuffer.vert.diff new file mode 100644 index 0000000..d6aad1b --- /dev/null +++ b/src/bin/21_shader_uniformbuffer.vert.diff @@ -0,0 +1,25 @@ +--- a/17_shader_vertexbuffer.vert ++++ b/21_shader_uniformbuffer.vert +@@ -1,6 +1,12 @@ + #version 450 + #extension GL_ARB_separate_shader_objects : enable + ++layout(binding = 0) uniform UniformBufferObject { ++ mat4 model; ++ mat4 view; ++ mat4 proj; ++} ubo; ++ + // NOTE: names must match the `Vertex` struct in Rust + layout(location = 0) in vec2 pos; + layout(location = 1) in vec3 color; +@@ -12,6 +18,6 @@ out gl_PerVertex { + }; + + void main() { +- gl_Position = vec4(pos, 0.0, 1.0); ++ gl_Position = ubo.proj * ubo.view * ubo.model * vec4(pos, 0.0, 1.0); + fragColor = color; +-} ++} +\ No newline at end of file From 69889c100ce5a0e8732728f9ac073bd18d6cb14b Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 9 Feb 2019 13:56:11 -0500 Subject: [PATCH 67/78] fixes diff in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8e1265..45fb7c6 100644 --- a/README.md +++ b/README.md @@ -351,7 +351,7 @@ include a matching descriptor set. [Vertex Shader Diff](src/bin/21_shader_uniformbuffer.vert.diff) / [Vertex Shader](src/bin/21_shader_uniformbuffer.vert) -[Diff](src/bin/21_descriptor_layout_and_buffer.rs) / [Complete code](src/bin/21_descriptor_layout_and_buffer.rs) +[Diff](src/bin/21_descriptor_layout_and_buffer.rs.diff) / [Complete code](src/bin/21_descriptor_layout_and_buffer.rs) ## Texture mapping (*TODO*) ## Depth buffering (*TODO*) ## Loading models (*TODO*) From 6f8a7e8e048e20c1bad5f15460b2b5cdd3738f31 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 9 Feb 2019 21:55:28 -0500 Subject: [PATCH 68/78] fix clippy errors --- src/bin/00_base_code.rs | 5 ++--- src/bin/01_instance_creation.rs | 5 ++--- src/bin/02_validation_layers.rs | 7 +++---- src/bin/03_physical_device_selection.rs | 7 +++---- src/bin/04_logical_device.rs | 7 +++---- src/bin/05_window_surface.rs | 7 +++---- src/bin/06_swap_chain_creation.rs | 7 +++---- src/bin/08_graphics_pipeline.rs | 7 +++---- src/bin/09_shader_modules.rs | 7 +++---- src/bin/10_fixed_functions.rs | 7 +++---- src/bin/11_render_passes.rs | 7 +++---- src/bin/12_graphics_pipeline_complete.rs | 7 +++---- src/bin/13_framebuffers.rs | 9 ++++----- src/bin/14_command_buffers.rs | 9 ++++----- src/bin/15_hello_triangle.rs | 9 ++++----- src/bin/16_swap_chain_recreation.rs | 9 ++++----- src/bin/18_vertex_buffer.rs | 9 ++++----- src/bin/19_staging_buffer.rs | 9 ++++----- src/bin/20_index_buffer.rs | 9 ++++----- src/bin/21_descriptor_layout_and_buffer.rs | 17 +++++++++++------ src/main.rs | 9 ++++----- 21 files changed, 77 insertions(+), 92 deletions(-) diff --git a/src/bin/00_base_code.rs b/src/bin/00_base_code.rs index f8c5804..dcd5ed7 100644 --- a/src/bin/00_base_code.rs +++ b/src/bin/00_base_code.rs @@ -33,9 +33,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/01_instance_creation.rs b/src/bin/01_instance_creation.rs index 85b32d7..a00d39c 100644 --- a/src/bin/01_instance_creation.rs +++ b/src/bin/01_instance_creation.rs @@ -64,9 +64,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/02_validation_layers.rs b/src/bin/02_validation_layers.rs index 921a850..2cc4024 100644 --- a/src/bin/02_validation_layers.rs +++ b/src/bin/02_validation_layers.rs @@ -78,7 +78,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -124,9 +124,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/03_physical_device_selection.rs b/src/bin/03_physical_device_selection.rs index a2f6f07..4456a44 100644 --- a/src/bin/03_physical_device_selection.rs +++ b/src/bin/03_physical_device_selection.rs @@ -98,7 +98,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -171,9 +171,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/04_logical_device.rs b/src/bin/04_logical_device.rs index c15d820..c74b0fe 100644 --- a/src/bin/04_logical_device.rs +++ b/src/bin/04_logical_device.rs @@ -107,7 +107,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -205,9 +205,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/05_window_surface.rs b/src/bin/05_window_surface.rs index 60ee006..b02d00c 100644 --- a/src/bin/05_window_surface.rs +++ b/src/bin/05_window_surface.rs @@ -107,7 +107,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -225,9 +225,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/06_swap_chain_creation.rs b/src/bin/06_swap_chain_creation.rs index 4aa086f..044566d 100644 --- a/src/bin/06_swap_chain_creation.rs +++ b/src/bin/06_swap_chain_creation.rs @@ -133,7 +133,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -354,9 +354,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/08_graphics_pipeline.rs b/src/bin/08_graphics_pipeline.rs index b5266b3..a30b410 100644 --- a/src/bin/08_graphics_pipeline.rs +++ b/src/bin/08_graphics_pipeline.rs @@ -135,7 +135,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -360,9 +360,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/09_shader_modules.rs b/src/bin/09_shader_modules.rs index d03d721..29da4dc 100644 --- a/src/bin/09_shader_modules.rs +++ b/src/bin/09_shader_modules.rs @@ -135,7 +135,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -379,9 +379,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/10_fixed_functions.rs b/src/bin/10_fixed_functions.rs index bc11a88..a86a3e3 100644 --- a/src/bin/10_fixed_functions.rs +++ b/src/bin/10_fixed_functions.rs @@ -140,7 +140,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -409,9 +409,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/11_render_passes.rs b/src/bin/11_render_passes.rs index f4a7a0b..5cac78e 100644 --- a/src/bin/11_render_passes.rs +++ b/src/bin/11_render_passes.rs @@ -149,7 +149,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -435,9 +435,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/12_graphics_pipeline_complete.rs b/src/bin/12_graphics_pipeline_complete.rs index 638279d..41795be 100644 --- a/src/bin/12_graphics_pipeline_complete.rs +++ b/src/bin/12_graphics_pipeline_complete.rs @@ -159,7 +159,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -449,9 +449,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/13_framebuffers.rs b/src/bin/13_framebuffers.rs index e049890..1de5b6b 100644 --- a/src/bin/13_framebuffers.rs +++ b/src/bin/13_framebuffers.rs @@ -167,7 +167,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -392,7 +392,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -471,9 +471,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/14_command_buffers.rs b/src/bin/14_command_buffers.rs index 64a54c6..f2b2144 100644 --- a/src/bin/14_command_buffers.rs +++ b/src/bin/14_command_buffers.rs @@ -180,7 +180,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -405,7 +405,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -504,9 +504,8 @@ impl HelloTriangleApplication { loop { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/15_hello_triangle.rs b/src/bin/15_hello_triangle.rs index 6924baf..fdd4e34 100644 --- a/src/bin/15_hello_triangle.rs +++ b/src/bin/15_hello_triangle.rs @@ -181,7 +181,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -406,7 +406,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -507,9 +507,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/16_swap_chain_recreation.rs b/src/bin/16_swap_chain_recreation.rs index 4051bc5..bab788b 100644 --- a/src/bin/16_swap_chain_recreation.rs +++ b/src/bin/16_swap_chain_recreation.rs @@ -190,7 +190,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -416,7 +416,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -521,9 +521,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/18_vertex_buffer.rs b/src/bin/18_vertex_buffer.rs index b61ff5a..a73cd7c 100644 --- a/src/bin/18_vertex_buffer.rs +++ b/src/bin/18_vertex_buffer.rs @@ -211,7 +211,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -437,7 +437,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -546,9 +546,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/19_staging_buffer.rs b/src/bin/19_staging_buffer.rs index 4d5447c..5c93ffc 100644 --- a/src/bin/19_staging_buffer.rs +++ b/src/bin/19_staging_buffer.rs @@ -211,7 +211,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -437,7 +437,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -550,9 +550,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/20_index_buffer.rs b/src/bin/20_index_buffer.rs index d12c154..715a636 100644 --- a/src/bin/20_index_buffer.rs +++ b/src/bin/20_index_buffer.rs @@ -220,7 +220,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -446,7 +446,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -569,9 +569,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { diff --git a/src/bin/21_descriptor_layout_and_buffer.rs b/src/bin/21_descriptor_layout_and_buffer.rs index c4b39b9..f4af214 100644 --- a/src/bin/21_descriptor_layout_and_buffer.rs +++ b/src/bin/21_descriptor_layout_and_buffer.rs @@ -102,8 +102,11 @@ impl Vertex { Self { pos, color } } } + +#[allow(clippy:ref_in_deref)] impl_vertex!(Vertex, pos, color); +#[allow(dead_code)] #[derive(Copy, Clone)] struct UniformBufferObject { model: glm::Mat4, @@ -148,6 +151,8 @@ struct HelloTriangleApplication { vertex_buffer: Arc, index_buffer: Arc + Send + Sync>, + + #[allow(dead_code)] uniform_buffers: Vec>>, command_buffers: Vec>, @@ -155,6 +160,7 @@ struct HelloTriangleApplication { previous_frame_end: Option>, recreate_swap_chain: bool, + #[allow(dead_code)] start_time: Instant, } @@ -241,7 +247,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -467,7 +473,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -619,9 +625,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { @@ -675,7 +680,7 @@ impl HelloTriangleApplication { fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { let duration = Instant::now().duration_since(start_time); - let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; + let elapsed = (duration.as_secs() * 1000) + u64::from(duration.subsec_millis()); let identity_matrix = glm::mat4( 1.0, 0.0, 0.0, 0.0, diff --git a/src/main.rs b/src/main.rs index d12c154..715a636 100644 --- a/src/main.rs +++ b/src/main.rs @@ -220,7 +220,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -446,7 +446,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -569,9 +569,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { From 9c70c33bebdc7c05683d4204b58bbbe9c0605f96 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 9 Feb 2019 22:10:43 -0500 Subject: [PATCH 69/78] updates diffs from clippy fixes --- src/bin/01_instance_creation.rs.diff | 2 +- src/bin/02_validation_layers.rs.diff | 2 +- src/bin/09_shader_modules.rs.diff | 31 -------------- src/bin/10_fixed_functions.rs.diff | 41 +++++++++++-------- src/bin/13_framebuffers.rs.diff | 2 +- src/bin/15_hello_triangle.rs.diff | 4 +- src/bin/16_swap_chain_recreation.rs.diff | 2 +- .../21_descriptor_layout_and_buffer.rs.diff | 28 ++++++++----- 8 files changed, 49 insertions(+), 63 deletions(-) delete mode 100644 src/bin/09_shader_modules.rs.diff diff --git a/src/bin/01_instance_creation.rs.diff b/src/bin/01_instance_creation.rs.diff index e0904ee..445a8e0 100644 --- a/src/bin/01_instance_creation.rs.diff +++ b/src/bin/01_instance_creation.rs.diff @@ -69,7 +69,7 @@ fn main_loop(&mut self) { loop { let mut done = false; -@@ -46,6 +77,6 @@ impl HelloTriangleApplication { +@@ -45,6 +76,6 @@ impl HelloTriangleApplication { } fn main() { diff --git a/src/bin/02_validation_layers.rs.diff b/src/bin/02_validation_layers.rs.diff index e102e45..bbf3b43 100644 --- a/src/bin/02_validation_layers.rs.diff +++ b/src/bin/02_validation_layers.rs.diff @@ -63,7 +63,7 @@ + let required_extensions = Self::get_required_extensions(); + + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { -+ Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) ++ Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) diff --git a/src/bin/09_shader_modules.rs.diff b/src/bin/09_shader_modules.rs.diff deleted file mode 100644 index 66da05e..0000000 --- a/src/bin/09_shader_modules.rs.diff +++ /dev/null @@ -1,31 +0,0 @@ ---- a/08_graphics_pipeline.rs -+++ b/09_shader_modules.rs -@@ -290,8 +290,27 @@ impl HelloTriangleApplication { - (swap_chain, images) - } - -- fn create_graphics_pipeline(_device: &Arc) { -+ fn create_graphics_pipeline( -+ device: &Arc, -+ ) { -+ mod vertex_shader { -+ vulkano_shaders::shader! { -+ ty: "vertex", -+ path: "src/bin/09_shader_base.vert" -+ } -+ } -+ -+ mod fragment_shader { -+ vulkano_shaders::shader! { -+ ty: "fragment", -+ path: "src/bin/09_shader_base.frag" -+ } -+ } - -+ let _vert_shader_module = vertex_shader::Shader::load(device.clone()) -+ .expect("failed to create vertex shader module!"); -+ let _frag_shader_module = fragment_shader::Shader::load(device.clone()) -+ .expect("failed to create fragment shader module!"); - } - - fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { diff --git a/src/bin/10_fixed_functions.rs.diff b/src/bin/10_fixed_functions.rs.diff index 0f0a547..f798e53 100644 --- a/src/bin/10_fixed_functions.rs.diff +++ b/src/bin/10_fixed_functions.rs.diff @@ -1,4 +1,4 @@ ---- a/./09_shader_modules.rs +--- a/08_graphics_pipeline.rs +++ b/10_fixed_functions.rs @@ -30,6 +30,11 @@ use vulkano::swapchain::{ use vulkano::format::Format; @@ -21,24 +21,33 @@ Self { instance, -@@ -292,6 +297,7 @@ impl HelloTriangleApplication { +@@ -290,8 +295,52 @@ impl HelloTriangleApplication { + (swap_chain, images) + } - fn create_graphics_pipeline( - device: &Arc, +- fn create_graphics_pipeline(_device: &Arc) { ++ fn create_graphics_pipeline( ++ device: &Arc, + swap_chain_extent: [u32; 2], - ) { - mod vertex_shader { - vulkano_shaders::shader! { -@@ -307,10 +313,34 @@ impl HelloTriangleApplication { - } - } - -- let _vert_shader_module = vertex_shader::Shader::load(device.clone()) ++ ) { ++ mod vertex_shader { ++ vulkano_shaders::shader! { ++ ty: "vertex", ++ path: "src/bin/09_shader_base.vert" ++ } ++ } ++ ++ mod fragment_shader { ++ vulkano_shaders::shader! { ++ ty: "fragment", ++ path: "src/bin/09_shader_base.frag" ++ } ++ } ++ + let vert_shader_module = vertex_shader::Shader::load(device.clone()) - .expect("failed to create vertex shader module!"); -- let _frag_shader_module = fragment_shader::Shader::load(device.clone()) ++ .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) - .expect("failed to create fragment shader module!"); ++ .expect("failed to create fragment shader module!"); + + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { @@ -46,7 +55,7 @@ + dimensions, + depth_range: 0.0 .. 1.0, + }; -+ + + let _pipeline_builder = Arc::new(GraphicsPipeline::start() + .vertex_input(BufferlessDefinition {}) + .vertex_shader(vert_shader_module.main_entry_point(), ()) diff --git a/src/bin/13_framebuffers.rs.diff b/src/bin/13_framebuffers.rs.diff index 1fed988..4cf0506 100644 --- a/src/bin/13_framebuffers.rs.diff +++ b/src/bin/13_framebuffers.rs.diff @@ -41,7 +41,7 @@ } + fn create_framebuffers( -+ swap_chain_images: &Vec>>, ++ swap_chain_images: &[Arc>], + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() diff --git a/src/bin/15_hello_triangle.rs.diff b/src/bin/15_hello_triangle.rs.diff index e3a97a1..1c8d321 100644 --- a/src/bin/15_hello_triangle.rs.diff +++ b/src/bin/15_hello_triangle.rs.diff @@ -21,8 +21,8 @@ + let mut done = false; self.events_loop.poll_events(|ev| { - match ev { -@@ -514,9 +517,24 @@ impl HelloTriangleApplication { + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { +@@ -513,9 +516,24 @@ impl HelloTriangleApplication { } } } diff --git a/src/bin/16_swap_chain_recreation.rs.diff b/src/bin/16_swap_chain_recreation.rs.diff index 6465600..85e6b36 100644 --- a/src/bin/16_swap_chain_recreation.rs.diff +++ b/src/bin/16_swap_chain_recreation.rs.diff @@ -89,7 +89,7 @@ fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { let mut indices = QueueFamilyIndices::new(); // TODO: replace index with id to simplify? -@@ -519,18 +533,59 @@ impl HelloTriangleApplication { +@@ -518,18 +532,59 @@ impl HelloTriangleApplication { } fn draw_frame(&mut self) { diff --git a/src/bin/21_descriptor_layout_and_buffer.rs.diff b/src/bin/21_descriptor_layout_and_buffer.rs.diff index f8edb19..3188d1a 100644 --- a/src/bin/21_descriptor_layout_and_buffer.rs.diff +++ b/src/bin/21_descriptor_layout_and_buffer.rs.diff @@ -16,10 +16,15 @@ }; const WIDTH: u32 = 800; -@@ -102,6 +104,13 @@ impl Vertex { +@@ -100,8 +102,18 @@ impl Vertex { + Self { pos, color } + } } ++ ++#[allow(clippy:ref_in_deref)] impl_vertex!(Vertex, pos, color); ++#[allow(dead_code)] +#[derive(Copy, Clone)] +struct UniformBufferObject { + model: glm::Mat4, @@ -30,10 +35,12 @@ fn vertices() -> [Vertex; 4] { [ Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), -@@ -139,10 +148,14 @@ struct HelloTriangleApplication { +@@ -139,10 +151,17 @@ struct HelloTriangleApplication { vertex_buffer: Arc, index_buffer: Arc + Send + Sync>, ++ ++ #[allow(dead_code)] + uniform_buffers: Vec>>, + command_buffers: Vec>, @@ -41,11 +48,12 @@ previous_frame_end: Option>, recreate_swap_chain: bool, + ++ #[allow(dead_code)] + start_time: Instant, } impl HelloTriangleApplication { -@@ -159,12 +172,16 @@ impl HelloTriangleApplication { +@@ -159,12 +178,16 @@ impl HelloTriangleApplication { &device, &graphics_queue, &present_queue, None); let render_pass = Self::create_render_pass(&device, swap_chain.format()); @@ -62,7 +70,7 @@ let previous_frame_end = Some(Self::create_sync_objects(&device)); -@@ -191,10 +208,14 @@ impl HelloTriangleApplication { +@@ -191,10 +214,14 @@ impl HelloTriangleApplication { vertex_buffer, index_buffer, @@ -77,7 +85,7 @@ }; app.create_command_buffers(); -@@ -401,14 +422,14 @@ impl HelloTriangleApplication { +@@ -401,14 +428,14 @@ impl HelloTriangleApplication { mod vertex_shader { vulkano_shaders::shader! { ty: "vertex", @@ -94,7 +102,7 @@ } } -@@ -477,6 +498,31 @@ impl HelloTriangleApplication { +@@ -477,6 +504,31 @@ impl HelloTriangleApplication { buffer } @@ -126,7 +134,7 @@ fn create_command_buffers(&mut self) { let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() -@@ -485,9 +531,13 @@ impl HelloTriangleApplication { +@@ -485,9 +537,13 @@ impl HelloTriangleApplication { .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() @@ -142,13 +150,13 @@ .unwrap() .end_render_pass() .unwrap() -@@ -623,6 +673,36 @@ impl HelloTriangleApplication { +@@ -622,6 +678,36 @@ impl HelloTriangleApplication { } } + fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { + let duration = Instant::now().duration_since(start_time); -+ let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; ++ let elapsed = (duration.as_secs() * 1000) + u64::from(duration.subsec_millis()); + + let identity_matrix = glm::mat4( + 1.0, 0.0, 0.0, 0.0, @@ -179,7 +187,7 @@ fn recreate_swap_chain(&mut self) { let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); -@@ -640,4 +720,4 @@ impl HelloTriangleApplication { +@@ -639,4 +725,4 @@ impl HelloTriangleApplication { fn main() { let mut app = HelloTriangleApplication::initialize(); app.main_loop(); From d9a7ae0b9e2d1e87fbfca2d8c487ff824c0b6d66 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Wed, 13 Feb 2019 22:36:07 -0500 Subject: [PATCH 70/78] switches from glm to cgmath; --- Cargo.lock | 215 +----------------- Cargo.toml | 2 +- src/bin/21_descriptor_layout_and_buffer.rs | 38 ++-- .../21_descriptor_layout_and_buffer.rs.diff | 63 ++--- 4 files changed, 67 insertions(+), 251 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c4d0b4..4b345e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,14 +3,6 @@ name = "adler32" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "aho-corasick" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "andrew" version = "0.1.6" @@ -96,6 +88,16 @@ name = "cfg-if" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cgmath" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -282,15 +284,6 @@ name = "either" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "env_logger" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fnv" version = "1.0.6" @@ -342,16 +335,6 @@ dependencies = [ "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "glm" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "half" version = "1.1.2" @@ -391,15 +374,6 @@ dependencies = [ "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lazy_static" version = "1.1.0" @@ -439,14 +413,6 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" version = "0.4.4" @@ -468,14 +434,6 @@ dependencies = [ "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memmap" version = "0.7.0" @@ -524,39 +482,6 @@ name = "nodrop" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "num" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-derive" version = "0.2.2" @@ -585,17 +510,6 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num-rational" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-rational" version = "0.2.1" @@ -740,16 +654,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quickcheck" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "0.6.11" @@ -758,27 +662,6 @@ dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand" version = "0.5.5" @@ -921,33 +804,11 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc-demangle" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc_version" version = "0.2.3" @@ -1074,23 +935,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "thread-id" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tiff" version = "0.2.1" @@ -1115,11 +959,6 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "utf8-ranges" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "version_check" version = "0.1.4" @@ -1139,7 +978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vulkan-tutorial-rs" version = "0.1.0" dependencies = [ - "glm 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", "vulkano 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "vulkano-shaders 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1248,11 +1087,6 @@ dependencies = [ "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi" version = "0.3.6" @@ -1262,11 +1096,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1329,7 +1158,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum andrew 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "142e9e6a99ad0d63a4cf6ce58a4c979f472c5815cbf7e5ca4e47b26a10dc728e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" "checksum approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c57ff1a5b00753647aebbbcf4ea67fa1e711a65ea7a30eb90dbf07de2485aee" @@ -1342,6 +1170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" "checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" +"checksum cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "704fbf3bb5149daab0afb255dbea24a1f08d2f4099cedb9baab6d470d4c5eefb" "checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b" @@ -1362,7 +1191,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" "checksum downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "18df8ce4470c189d18aa926022da57544f31e154631eb4cfe796aea97051fe6c" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "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" @@ -1371,34 +1199,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" -"checksum glm 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1c702ce44565c0a09122e1c1d806bffef6528ff5de7bd0bcf636776a32953c7a" "checksum half 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a581f551b77eb3e177584e922a8c057e14311a857f859fd39d9574d97d3547da" "checksum image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44665b4395d1844c96e7dc8ed5754782a1cdfd9ef458a80bbe45702681450504" "checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245" "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum metal 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7de9c2b83c946ab01c9942928388f911d93486b97636d9927541345905fea65d" "checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" -"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" "checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" @@ -1416,10 +1236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "104630aa1c83213cbc76db0703630fcb0421dac3585063be4ce9a8a2feeaa745" "checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" -"checksum quickcheck 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d086a75fc7bdfbadd649f7c1fa524f39be4979b15506f621b3742b752f5364ed" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -1435,10 +1252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" -"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rusttype 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ae90f66c7ca5fb2c566d373c9ccb3ce1ae1aeebf236b74ad0d413196facb31b3" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" @@ -1454,12 +1268,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b7bfcbb0c068d0f642a0ffbd5c604965a360a61f99e8add013cef23a838614f3" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" -"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a2cc6c4fd13cb1cfd20abdb196e794ceccb29371855b7e7f575945f920a5b3c2" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum vk-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36f5fd4a7d6d5d19808610583131c0aed271556527cad4cb71c436831a28e059" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" @@ -1472,9 +1283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wayland-protocols 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fd94211387fa8ff50df1e4ff7a5529b5a9aebe68ba88acc48e5b7f5fd98f6eef" "checksum wayland-scanner 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3611f231e675e15c2feb7623103e6449edc6f10b0598cafb3e16e590a0561355" "checksum wayland-sys 0.21.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2a69d729a1747a5bf40ae05b94c7904b64fbf2381e365c046d872ce4a34aa826" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 48e276c..a494ae3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ vulkano-shaders = "0.11.1" image = "0.20.1" vulkano-win = "0.11.1" winit = "0.18.0" -glm = "0.2.3" +cgmath = "0.17.0" # [[bin]] # name = "main" diff --git a/src/bin/21_descriptor_layout_and_buffer.rs b/src/bin/21_descriptor_layout_and_buffer.rs index f4af214..960d742 100644 --- a/src/bin/21_descriptor_layout_and_buffer.rs +++ b/src/bin/21_descriptor_layout_and_buffer.rs @@ -2,6 +2,7 @@ extern crate vulkano; extern crate vulkano_win; extern crate winit; +extern crate cgmath; use std::sync::Arc; use std::collections::HashSet; @@ -57,6 +58,13 @@ use vulkano::buffer::{ TypedBufferAccess, CpuAccessibleBuffer, }; +use cgmath::{ + Rad, + Deg, + Matrix4, + Vector3, + Point3 +}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; @@ -109,9 +117,9 @@ impl_vertex!(Vertex, pos, color); #[allow(dead_code)] #[derive(Copy, Clone)] struct UniformBufferObject { - model: glm::Mat4, - view: glm::Mat4, - proj: glm::Mat4, + model: Matrix4, + view: Matrix4, + proj: Matrix4, } fn vertices() -> [Vertex; 4] { @@ -682,28 +690,22 @@ impl HelloTriangleApplication { let duration = Instant::now().duration_since(start_time); let elapsed = (duration.as_secs() * 1000) + u64::from(duration.subsec_millis()); - let identity_matrix = glm::mat4( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - ); - - let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); + let model = Matrix4::from_angle_z(Rad::from(Deg(elapsed as f32 * 0.180))); - let view = glm::ext::look_at( - glm::vec3(2.0, 2.0, 2.0), - glm::vec3(0.0, 0.0, 0.0), - glm::vec3(0.0, 0.0, 1.0) + let view = Matrix4::look_at( + Point3::new(2.0, 2.0, 2.0), + Point3::new(0.0, 0.0, 0.0), + Vector3::new(0.0, 0.0, 1.0) ); - let mut proj = glm::ext::perspective( - glm::radians(45.0,), + + let mut proj = cgmath::perspective( + Rad::from(Deg(45.0)), dimensions[0] as f32 / dimensions[1] as f32, 0.1, 10.0 ); - proj.c1.y *= -1.0; + proj.y.y *= -1.0; UniformBufferObject { model, view, proj } } diff --git a/src/bin/21_descriptor_layout_and_buffer.rs.diff b/src/bin/21_descriptor_layout_and_buffer.rs.diff index 3188d1a..f8cbca4 100644 --- a/src/bin/21_descriptor_layout_and_buffer.rs.diff +++ b/src/bin/21_descriptor_layout_and_buffer.rs.diff @@ -1,6 +1,10 @@ --- a/20_index_buffer.rs +++ b/21_descriptor_layout_and_buffer.rs -@@ -5,6 +5,7 @@ extern crate winit; +@@ -2,9 +2,11 @@ + extern crate vulkano; + extern crate vulkano_win; + extern crate winit; ++extern crate cgmath; use std::sync::Arc; use std::collections::HashSet; @@ -8,15 +12,22 @@ use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; use vulkano_win::VkSurfaceBuild; -@@ -54,6 +55,7 @@ use vulkano::buffer::{ +@@ -54,6 +56,14 @@ use vulkano::buffer::{ BufferUsage, BufferAccess, TypedBufferAccess, + CpuAccessibleBuffer, ++}; ++use cgmath::{ ++ Rad, ++ Deg, ++ Matrix4, ++ Vector3, ++ Point3 }; const WIDTH: u32 = 800; -@@ -100,8 +102,18 @@ impl Vertex { +@@ -100,8 +110,18 @@ impl Vertex { Self { pos, color } } } @@ -27,15 +38,15 @@ +#[allow(dead_code)] +#[derive(Copy, Clone)] +struct UniformBufferObject { -+ model: glm::Mat4, -+ view: glm::Mat4, -+ proj: glm::Mat4, ++ model: Matrix4, ++ view: Matrix4, ++ proj: Matrix4, +} + fn vertices() -> [Vertex; 4] { [ Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), -@@ -139,10 +151,17 @@ struct HelloTriangleApplication { +@@ -139,10 +159,17 @@ struct HelloTriangleApplication { vertex_buffer: Arc, index_buffer: Arc + Send + Sync>, @@ -53,7 +64,7 @@ } impl HelloTriangleApplication { -@@ -159,12 +178,16 @@ impl HelloTriangleApplication { +@@ -159,12 +186,16 @@ impl HelloTriangleApplication { &device, &graphics_queue, &present_queue, None); let render_pass = Self::create_render_pass(&device, swap_chain.format()); @@ -70,7 +81,7 @@ let previous_frame_end = Some(Self::create_sync_objects(&device)); -@@ -191,10 +214,14 @@ impl HelloTriangleApplication { +@@ -191,10 +222,14 @@ impl HelloTriangleApplication { vertex_buffer, index_buffer, @@ -85,7 +96,7 @@ }; app.create_command_buffers(); -@@ -401,14 +428,14 @@ impl HelloTriangleApplication { +@@ -401,14 +436,14 @@ impl HelloTriangleApplication { mod vertex_shader { vulkano_shaders::shader! { ty: "vertex", @@ -102,7 +113,7 @@ } } -@@ -477,6 +504,31 @@ impl HelloTriangleApplication { +@@ -477,6 +512,31 @@ impl HelloTriangleApplication { buffer } @@ -134,7 +145,7 @@ fn create_command_buffers(&mut self) { let queue_family = self.graphics_queue.family(); self.command_buffers = self.swap_chain_framebuffers.iter() -@@ -485,9 +537,13 @@ impl HelloTriangleApplication { +@@ -485,9 +545,13 @@ impl HelloTriangleApplication { .unwrap() .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() @@ -150,7 +161,7 @@ .unwrap() .end_render_pass() .unwrap() -@@ -622,6 +678,36 @@ impl HelloTriangleApplication { +@@ -622,6 +686,30 @@ impl HelloTriangleApplication { } } @@ -158,28 +169,22 @@ + let duration = Instant::now().duration_since(start_time); + let elapsed = (duration.as_secs() * 1000) + u64::from(duration.subsec_millis()); + -+ let identity_matrix = glm::mat4( -+ 1.0, 0.0, 0.0, 0.0, -+ 0.0, 1.0, 0.0, 0.0, -+ 0.0, 0.0, 1.0, 0.0, -+ 0.0, 0.0, 0.0, 1.0, -+ ); -+ -+ let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); ++ let model = Matrix4::from_angle_z(Rad::from(Deg(elapsed as f32 * 0.180))); + -+ let view = glm::ext::look_at( -+ glm::vec3(2.0, 2.0, 2.0), -+ glm::vec3(0.0, 0.0, 0.0), -+ glm::vec3(0.0, 0.0, 1.0) ++ let view = Matrix4::look_at( ++ Point3::new(2.0, 2.0, 2.0), ++ Point3::new(0.0, 0.0, 0.0), ++ Vector3::new(0.0, 0.0, 1.0) + ); -+ let mut proj = glm::ext::perspective( -+ glm::radians(45.0,), ++ ++ let mut proj = cgmath::perspective( ++ Rad::from(Deg(45.0)), + dimensions[0] as f32 / dimensions[1] as f32, + 0.1, + 10.0 + ); + -+ proj.c1.y *= -1.0; ++ proj.y.y *= -1.0; + + UniformBufferObject { model, view, proj } + } @@ -187,7 +192,7 @@ fn recreate_swap_chain(&mut self) { let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); -@@ -639,4 +725,4 @@ impl HelloTriangleApplication { +@@ -639,4 +727,4 @@ impl HelloTriangleApplication { fn main() { let mut app = HelloTriangleApplication::initialize(); app.main_loop(); From 5ad79f6188c01245f5cc25c2994e4e5aa23769c4 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sun, 3 Feb 2019 16:56:39 -0500 Subject: [PATCH 71/78] adds chapter section 22 -- adds descriptor set pool and descriptor set creation, updates create_command_buffers to map memory to our uniform buffer, reverses the order of vertices drawn --- README.md | 16 + src/bin/22_descriptor_pools_and_sets.rs | 773 +++++++++++++++++++ src/bin/22_descriptor_pools_and_sets.rs.diff | 131 ++++ 3 files changed, 920 insertions(+) create mode 100644 src/bin/22_descriptor_pools_and_sets.rs create mode 100644 src/bin/22_descriptor_pools_and_sets.rs.diff diff --git a/README.md b/README.md index 45fb7c6..5e28d2e 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,22 @@ include a matching descriptor set. [Vertex Shader Diff](src/bin/21_shader_uniformbuffer.vert.diff) / [Vertex Shader](src/bin/21_shader_uniformbuffer.vert) [Diff](src/bin/21_descriptor_layout_and_buffer.rs.diff) / [Complete code](src/bin/21_descriptor_layout_and_buffer.rs) + +### Descriptor Pool and Sets +https://vulkan-tutorial.com/Uniform_buffers/Descriptor_pool_and_sets + +In this section we introduce a new resource, Descriptor Sets, which allow us to specify what buffer resources to transfer to the GPU. +In the last section we made a change to our vertex shader to expect a buffer in binding 0 and descriptor sets allow us to specify +the actual memory that will occupy that binding. + +For each uniform buffer we created in the last section, we create a descriptor set with the buffer bound to it, giving us the same +number of descriptor sets as swap chain images. At the beginning of each frame we now recreate the command buffer, which +includes a new command to copy our updated UniformBufferObject into the respective uniform buffer before the render pass. + +Note that due to the flipping of the Y axis in the projection matrix, we now need to tell vulkan to draw the vertices in +the opposite direction. + +[Diff](src/bin/22_descriptor_pools_and_sets.rs.diff) / [Complete code](src/bin/22_descriptor_pools_and_sets.rs) ## Texture mapping (*TODO*) ## Depth buffering (*TODO*) ## Loading models (*TODO*) diff --git a/src/bin/22_descriptor_pools_and_sets.rs b/src/bin/22_descriptor_pools_and_sets.rs new file mode 100644 index 0000000..e8e61c4 --- /dev/null +++ b/src/bin/22_descriptor_pools_and_sets.rs @@ -0,0 +1,773 @@ +#[macro_use] +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; + +use std::sync::{Arc, Mutex}; +use std::collections::HashSet; +use std::time::Instant; + +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image, + AcquireError, +}; +use vulkano::format::Format; +use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; +use vulkano::sync::{self, SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + GraphicsPipelineAbstract, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; +use vulkano::buffer::{ + immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, + TypedBufferAccess, + CpuAccessibleBuffer +}; +use vulkano::descriptor::descriptor_set::{ + FixedSizeDescriptorSetsPool, + FixedSizeDescriptorSet +}; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} +impl Vertex { + fn new(pos: [f32; 2], color: [f32; 3]) -> Self { + Self { pos, color } + } +} +impl_vertex!(Vertex, pos, color); + +#[derive(Copy, Clone)] +struct UniformBufferObject { + model: glm::Mat4, + view: glm::Mat4, + proj: glm::Mat4, +} + +fn vertices() -> [Vertex; 4] { + [ + Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), + Vertex::new([0.5, -0.5], [0.0, 1.0, 0.0]), + Vertex::new([0.5, 0.5], [0.0, 0.0, 1.0]), + Vertex::new([-0.5, 0.5], [1.0, 1.0, 1.0]) + ] +} + +fn indices() -> [u16; 6] { + [0, 1, 2, 2, 3, 0] +} + +struct HelloTriangleApplication { + instance: Arc, + #[allow(unused)] + debug_callback: Option, + + events_loop: EventsLoop, + surface: Arc>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, + + graphics_queue: Arc, + present_queue: Arc, + + swap_chain: Arc>, + swap_chain_images: Vec>>, + + render_pass: Arc, + graphics_pipeline: Arc, + + swap_chain_framebuffers: Vec>, + + vertex_buffer: Arc, + index_buffer: Arc + Send + Sync>, + uniform_buffers: Vec>>, + + descriptor_sets: Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>>, + + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, + + start_time: Instant, +} + +impl HelloTriangleApplication { + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); + + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let start_time = Instant::now(); + + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + let index_buffer = Self::create_index_buffer(&graphics_queue); + let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); + + let descriptor_sets_pool = Self::create_descriptor_pool(&graphics_pipeline); + let descriptor_sets = Self::create_descriptor_sets(&descriptor_sets_pool, &uniform_buffers); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + vertex_buffer, + index_buffer, + uniform_buffers, + + descriptor_sets, + + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, + + start_time + }; + + app.create_command_buffers(); + app + } + + fn create_instance() -> Arc { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(instance: &Arc) -> Option { + if !ENABLE_VALIDATION_LAYERS { + return None; + } + + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + DebugCallback::new(&instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok() + } + + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") + } + + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = Self::choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = Self::find_queue_families(&surface, &physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![graphics_queue, present_queue].as_slice().into() + } else { + graphics_queue.into() + }; + + let (swap_chain, images) = Swapchain::new( + device.clone(), + surface.clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + old_swapchain.as_ref() + ).expect("failed to create swap chain!"); + + (swap_chain, images) + } + + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: color_format, + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap()) + } + + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { + mod vertex_shader { + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/21_shader_uniformbuffer.vert" + } + } + + mod fragment_shader { + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/21_shader_uniformbuffer.frag" + } + } + + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_counter_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + ) + } + + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>() + } + + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), + graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); + buffer + } + + fn create_index_buffer(graphics_queue: &Arc) -> Arc + Send + Sync> { + let (buffer, future) = ImmutableBuffer::from_iter( + indices().iter().cloned(), BufferUsage::index_buffer(), + graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); + buffer + } + + fn create_uniform_buffers( + device: &Arc, + num_buffers: usize, + start_time: Instant, + dimensions_u32: [u32; 2] + ) -> Vec>> { + let mut buffers = Vec::new(); + + let dimensions = [dimensions_u32[0] as f32, dimensions_u32[1] as f32]; + + let uniform_buffer = Self::update_uniform_buffer(start_time, dimensions); + + for _ in 0..num_buffers { + let buffer = CpuAccessibleBuffer::from_data( + device.clone(), + BufferUsage::uniform_buffer_transfer_destination(), + uniform_buffer, + ).unwrap(); + + buffers.push(buffer); + } + + buffers + } + + fn create_descriptor_pool(graphics_pipeline: &Arc) + -> Arc>>> + { + Arc::new( + Mutex::new( + FixedSizeDescriptorSetsPool::new(graphics_pipeline.clone(), 0) + ) + ) + } + + fn create_descriptor_sets( + pool: &Arc>>>, + uniform_buffers: &Vec>>, + ) -> Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>> + { + uniform_buffers + .iter() + .map(|uniform_buffer| + Arc::new( + pool + .lock() + .unwrap() + .next() + .add_buffer(uniform_buffer.clone()) + .unwrap() + .build() + .unwrap() + ) + ) + .collect() + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.family(); + let dimensions = [self.swap_chain.dimensions()[0] as f32, self.swap_chain.dimensions()[1] as f32]; + + self.command_buffers = self.swap_chain_framebuffers + .iter() + .enumerate() + .map(|(i, framebuffer)| { + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) + .unwrap() + .update_buffer(self.uniform_buffers[i].clone(), Self::update_uniform_buffer(self.start_time, dimensions)) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw_indexed( + self.graphics_pipeline.clone(), + &DynamicState::none(), + vec![self.vertex_buffer.clone()], + self.index_buffer.clone(), + self.descriptor_sets[i].clone(), + ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box + } + + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if surface.is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); + + (device, graphics_queue, present_queue) + } + + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.create_command_buffers(); + self.draw_frame(); + + let mut done = false; + self.events_loop.poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + + let command_buffer = self.command_buffers[image_index].clone(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) + .then_execute(self.graphics_queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + } + } + + fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { + let duration = Instant::now().duration_since(start_time); + let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; + + let identity_matrix = glm::mat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + ); + + let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); + + let view = glm::ext::look_at( + glm::vec3(2.0, 2.0, 2.0), + glm::vec3(0.0, 0.0, 0.0), + glm::vec3(0.0, 0.0, 1.0) + ); + let mut proj = glm::ext::perspective( + glm::radians(45.0,), + dimensions[0] as f32 / dimensions[1] as f32, + 0.1, + 10.0 + ); + + proj.c1.y *= -1.0; + + UniformBufferObject { model, view, proj } + } + + fn recreate_swap_chain(&mut self) { + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; + + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); + } +} + +fn main() { + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); +} \ No newline at end of file diff --git a/src/bin/22_descriptor_pools_and_sets.rs.diff b/src/bin/22_descriptor_pools_and_sets.rs.diff new file mode 100644 index 0000000..a0e3dcb --- /dev/null +++ b/src/bin/22_descriptor_pools_and_sets.rs.diff @@ -0,0 +1,131 @@ +--- a/21_descriptor_layout_and_buffer.rs ++++ b/22_descriptor_pools_and_sets.rs +@@ -3,7 +3,7 @@ extern crate vulkano; + extern crate vulkano_win; + extern crate winit; + +-use std::sync::Arc; ++use std::sync::{Arc, Mutex}; + use std::collections::HashSet; + use std::time::Instant; + +@@ -55,7 +55,11 @@ use vulkano::buffer::{ + BufferUsage, + BufferAccess, + TypedBufferAccess, +- CpuAccessibleBuffer, ++ CpuAccessibleBuffer ++}; ++use vulkano::descriptor::descriptor_set::{ ++ FixedSizeDescriptorSetsPool, ++ FixedSizeDescriptorSet + }; + + const WIDTH: u32 = 800; +@@ -150,6 +154,8 @@ struct HelloTriangleApplication { + index_buffer: Arc + Send + Sync>, + uniform_buffers: Vec>>, + ++ descriptor_sets: Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>>, ++ + command_buffers: Vec>, + + previous_frame_end: Option>, +@@ -183,6 +189,9 @@ impl HelloTriangleApplication { + let index_buffer = Self::create_index_buffer(&graphics_queue); + let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); + ++ let descriptor_sets_pool = Self::create_descriptor_pool(&graphics_pipeline); ++ let descriptor_sets = Self::create_descriptor_sets(&descriptor_sets_pool, &uniform_buffers); ++ + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { +@@ -210,6 +219,8 @@ impl HelloTriangleApplication { + index_buffer, + uniform_buffers, + ++ descriptor_sets, ++ + command_buffers: vec![], + + previous_frame_end, +@@ -457,7 +468,7 @@ impl HelloTriangleApplication { + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() +- .front_face_clockwise() ++ .front_face_counter_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) +@@ -523,12 +534,50 @@ impl HelloTriangleApplication { + buffers + } + ++ fn create_descriptor_pool(graphics_pipeline: &Arc) ++ -> Arc>>> ++ { ++ Arc::new( ++ Mutex::new( ++ FixedSizeDescriptorSetsPool::new(graphics_pipeline.clone(), 0) ++ ) ++ ) ++ } ++ ++ fn create_descriptor_sets( ++ pool: &Arc>>>, ++ uniform_buffers: &Vec>>, ++ ) -> Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>> ++ { ++ uniform_buffers ++ .iter() ++ .map(|uniform_buffer| ++ Arc::new( ++ pool ++ .lock() ++ .unwrap() ++ .next() ++ .add_buffer(uniform_buffer.clone()) ++ .unwrap() ++ .build() ++ .unwrap() ++ ) ++ ) ++ .collect() ++ } ++ + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.family(); +- self.command_buffers = self.swap_chain_framebuffers.iter() +- .map(|framebuffer| { ++ let dimensions = [self.swap_chain.dimensions()[0] as f32, self.swap_chain.dimensions()[1] as f32]; ++ ++ self.command_buffers = self.swap_chain_framebuffers ++ .iter() ++ .enumerate() ++ .map(|(i, framebuffer)| { + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) + .unwrap() ++ .update_buffer(self.uniform_buffers[i].clone(), Self::update_uniform_buffer(self.start_time, dimensions)) ++ .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw_indexed( +@@ -536,7 +585,7 @@ impl HelloTriangleApplication { + &DynamicState::none(), + vec![self.vertex_buffer.clone()], + self.index_buffer.clone(), +- (), ++ self.descriptor_sets[i].clone(), + ()) + .unwrap() + .end_render_pass() +@@ -615,6 +664,7 @@ impl HelloTriangleApplication { + #[allow(unused)] + fn main_loop(&mut self) { + loop { ++ self.create_command_buffers(); + self.draw_frame(); + + let mut done = false; From 7b0aae78a23689c8337d86e04dacee19a089089e Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 9 Feb 2019 22:01:47 -0500 Subject: [PATCH 72/78] fixes clippy issues --- src/bin/22_descriptor_pools_and_sets.rs | 14 ++++---- src/bin/22_descriptor_pools_and_sets.rs.diff | 35 +++++++++++++++----- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/bin/22_descriptor_pools_and_sets.rs b/src/bin/22_descriptor_pools_and_sets.rs index e8e61c4..662d45d 100644 --- a/src/bin/22_descriptor_pools_and_sets.rs +++ b/src/bin/22_descriptor_pools_and_sets.rs @@ -108,6 +108,7 @@ impl Vertex { } impl_vertex!(Vertex, pos, color); +#[allow(dead_code)] #[derive(Copy, Clone)] struct UniformBufferObject { model: glm::Mat4, @@ -252,7 +253,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -478,7 +479,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -546,7 +547,7 @@ impl HelloTriangleApplication { fn create_descriptor_sets( pool: &Arc>>>, - uniform_buffers: &Vec>>, + uniform_buffers: &[Arc>], ) -> Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>> { uniform_buffers @@ -669,9 +670,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { @@ -725,7 +725,7 @@ impl HelloTriangleApplication { fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { let duration = Instant::now().duration_since(start_time); - let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; + let elapsed = (duration.as_secs() * 1000) + u64::from(duration.subsec_millis()); let identity_matrix = glm::mat4( 1.0, 0.0, 0.0, 0.0, diff --git a/src/bin/22_descriptor_pools_and_sets.rs.diff b/src/bin/22_descriptor_pools_and_sets.rs.diff index a0e3dcb..abe610d 100644 --- a/src/bin/22_descriptor_pools_and_sets.rs.diff +++ b/src/bin/22_descriptor_pools_and_sets.rs.diff @@ -22,8 +22,21 @@ }; const WIDTH: u32 = 800; -@@ -150,6 +154,8 @@ struct HelloTriangleApplication { +@@ -102,8 +106,6 @@ impl Vertex { + Self { pos, color } + } + } +- +-#[allow(clippy:ref_in_deref)] + impl_vertex!(Vertex, pos, color); + + #[allow(dead_code)] +@@ -151,16 +153,15 @@ struct HelloTriangleApplication { + + vertex_buffer: Arc, index_buffer: Arc + Send + Sync>, +- +- #[allow(dead_code)] uniform_buffers: Vec>>, + descriptor_sets: Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>>, @@ -31,7 +44,13 @@ command_buffers: Vec>, previous_frame_end: Option>, -@@ -183,6 +189,9 @@ impl HelloTriangleApplication { + recreate_swap_chain: bool, + +- #[allow(dead_code)] + start_time: Instant, + } + +@@ -189,6 +190,9 @@ impl HelloTriangleApplication { let index_buffer = Self::create_index_buffer(&graphics_queue); let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); @@ -41,7 +60,7 @@ let previous_frame_end = Some(Self::create_sync_objects(&device)); let mut app = Self { -@@ -210,6 +219,8 @@ impl HelloTriangleApplication { +@@ -216,6 +220,8 @@ impl HelloTriangleApplication { index_buffer, uniform_buffers, @@ -50,7 +69,7 @@ command_buffers: vec![], previous_frame_end, -@@ -457,7 +468,7 @@ impl HelloTriangleApplication { +@@ -463,7 +469,7 @@ impl HelloTriangleApplication { .polygon_mode_fill() // = default .line_width(1.0) // = default .cull_mode_back() @@ -59,7 +78,7 @@ // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) -@@ -523,12 +534,50 @@ impl HelloTriangleApplication { +@@ -529,12 +535,50 @@ impl HelloTriangleApplication { buffers } @@ -75,7 +94,7 @@ + + fn create_descriptor_sets( + pool: &Arc>>>, -+ uniform_buffers: &Vec>>, ++ uniform_buffers: &[Arc>], + ) -> Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>> + { + uniform_buffers @@ -112,7 +131,7 @@ .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() .draw_indexed( -@@ -536,7 +585,7 @@ impl HelloTriangleApplication { +@@ -542,7 +586,7 @@ impl HelloTriangleApplication { &DynamicState::none(), vec![self.vertex_buffer.clone()], self.index_buffer.clone(), @@ -121,7 +140,7 @@ ()) .unwrap() .end_render_pass() -@@ -615,6 +664,7 @@ impl HelloTriangleApplication { +@@ -621,6 +665,7 @@ impl HelloTriangleApplication { #[allow(unused)] fn main_loop(&mut self) { loop { From 239ac0ba67e2360cc591371d4b51946b0f5fb7fb Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Wed, 13 Feb 2019 22:54:43 -0500 Subject: [PATCH 73/78] adds cgmath --- src/bin/22_descriptor_pools_and_sets.rs | 38 ++++++++++---------- src/bin/22_descriptor_pools_and_sets.rs.diff | 26 +++++++------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/bin/22_descriptor_pools_and_sets.rs b/src/bin/22_descriptor_pools_and_sets.rs index 662d45d..6e20f14 100644 --- a/src/bin/22_descriptor_pools_and_sets.rs +++ b/src/bin/22_descriptor_pools_and_sets.rs @@ -2,6 +2,7 @@ extern crate vulkano; extern crate vulkano_win; extern crate winit; +extern crate cgmath; use std::sync::{Arc, Mutex}; use std::collections::HashSet; @@ -61,6 +62,13 @@ use vulkano::descriptor::descriptor_set::{ FixedSizeDescriptorSetsPool, FixedSizeDescriptorSet }; +use cgmath::{ + Rad, + Deg, + Matrix4, + Vector3, + Point3 +}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; @@ -111,9 +119,9 @@ impl_vertex!(Vertex, pos, color); #[allow(dead_code)] #[derive(Copy, Clone)] struct UniformBufferObject { - model: glm::Mat4, - view: glm::Mat4, - proj: glm::Mat4, + model: Matrix4, + view: Matrix4, + proj: Matrix4, } fn vertices() -> [Vertex; 4] { @@ -727,28 +735,22 @@ impl HelloTriangleApplication { let duration = Instant::now().duration_since(start_time); let elapsed = (duration.as_secs() * 1000) + u64::from(duration.subsec_millis()); - let identity_matrix = glm::mat4( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - ); - - let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); + let model = Matrix4::from_angle_z(Rad::from(Deg(elapsed as f32 * 0.180))); - let view = glm::ext::look_at( - glm::vec3(2.0, 2.0, 2.0), - glm::vec3(0.0, 0.0, 0.0), - glm::vec3(0.0, 0.0, 1.0) + let view = Matrix4::look_at( + Point3::new(2.0, 2.0, 2.0), + Point3::new(0.0, 0.0, 0.0), + Vector3::new(0.0, 0.0, 1.0) ); - let mut proj = glm::ext::perspective( - glm::radians(45.0,), + + let mut proj = cgmath::perspective( + Rad::from(Deg(45.0)), dimensions[0] as f32 / dimensions[1] as f32, 0.1, 10.0 ); - proj.c1.y *= -1.0; + proj.y.y *= -1.0; UniformBufferObject { model, view, proj } } diff --git a/src/bin/22_descriptor_pools_and_sets.rs.diff b/src/bin/22_descriptor_pools_and_sets.rs.diff index abe610d..94fb496 100644 --- a/src/bin/22_descriptor_pools_and_sets.rs.diff +++ b/src/bin/22_descriptor_pools_and_sets.rs.diff @@ -1,15 +1,15 @@ --- a/21_descriptor_layout_and_buffer.rs +++ b/22_descriptor_pools_and_sets.rs -@@ -3,7 +3,7 @@ extern crate vulkano; - extern crate vulkano_win; +@@ -4,7 +4,7 @@ extern crate vulkano_win; extern crate winit; + extern crate cgmath; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::collections::HashSet; use std::time::Instant; -@@ -55,7 +55,11 @@ use vulkano::buffer::{ +@@ -56,7 +56,11 @@ use vulkano::buffer::{ BufferUsage, BufferAccess, TypedBufferAccess, @@ -20,9 +20,9 @@ + FixedSizeDescriptorSetsPool, + FixedSizeDescriptorSet }; - - const WIDTH: u32 = 800; -@@ -102,8 +106,6 @@ impl Vertex { + use cgmath::{ + Rad, +@@ -110,8 +114,6 @@ impl Vertex { Self { pos, color } } } @@ -31,7 +31,7 @@ impl_vertex!(Vertex, pos, color); #[allow(dead_code)] -@@ -151,16 +153,15 @@ struct HelloTriangleApplication { +@@ -159,16 +161,15 @@ struct HelloTriangleApplication { vertex_buffer: Arc, index_buffer: Arc + Send + Sync>, @@ -50,7 +50,7 @@ start_time: Instant, } -@@ -189,6 +190,9 @@ impl HelloTriangleApplication { +@@ -197,6 +198,9 @@ impl HelloTriangleApplication { let index_buffer = Self::create_index_buffer(&graphics_queue); let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); @@ -60,7 +60,7 @@ let previous_frame_end = Some(Self::create_sync_objects(&device)); let mut app = Self { -@@ -216,6 +220,8 @@ impl HelloTriangleApplication { +@@ -224,6 +228,8 @@ impl HelloTriangleApplication { index_buffer, uniform_buffers, @@ -69,7 +69,7 @@ command_buffers: vec![], previous_frame_end, -@@ -463,7 +469,7 @@ impl HelloTriangleApplication { +@@ -471,7 +477,7 @@ impl HelloTriangleApplication { .polygon_mode_fill() // = default .line_width(1.0) // = default .cull_mode_back() @@ -78,7 +78,7 @@ // NOTE: no depth_bias here, but on pipeline::raster::Rasterization .blend_pass_through() // = default .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) -@@ -529,12 +535,50 @@ impl HelloTriangleApplication { +@@ -537,12 +543,50 @@ impl HelloTriangleApplication { buffers } @@ -131,7 +131,7 @@ .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) .unwrap() .draw_indexed( -@@ -542,7 +586,7 @@ impl HelloTriangleApplication { +@@ -550,7 +594,7 @@ impl HelloTriangleApplication { &DynamicState::none(), vec![self.vertex_buffer.clone()], self.index_buffer.clone(), @@ -140,7 +140,7 @@ ()) .unwrap() .end_render_pass() -@@ -621,6 +665,7 @@ impl HelloTriangleApplication { +@@ -629,6 +673,7 @@ impl HelloTriangleApplication { #[allow(unused)] fn main_loop(&mut self) { loop { From a96545eaeca7a6dfabdded0bc4655ee58ce0d383 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 16 Feb 2019 15:33:44 -0500 Subject: [PATCH 74/78] fixes MacOS stutter --- src/bin/22_descriptor_pools_and_sets.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bin/22_descriptor_pools_and_sets.rs b/src/bin/22_descriptor_pools_and_sets.rs index 6e20f14..9bb9cf5 100644 --- a/src/bin/22_descriptor_pools_and_sets.rs +++ b/src/bin/22_descriptor_pools_and_sets.rs @@ -707,6 +707,10 @@ impl HelloTriangleApplication { let command_buffer = self.command_buffers[image_index].clone(); + // we're joining on the previous future but the CPU is running faster than the GPU so + // eventually it stutters, and jumps ahead to the newer frames. + // + // See vulkano issue 1135: https://github.com/vulkano-rs/vulkano/issues/1135 let future = self.previous_frame_end.take().unwrap() .join(acquire_future) .then_execute(self.graphics_queue.clone(), command_buffer) @@ -716,6 +720,11 @@ impl HelloTriangleApplication { match future { Ok(future) => { + // This makes sure the CPU stays in sync with the GPU + // Not sure if this means we don't need to store the previous_frame_end since we're + // explicitly waiting for it? + future.wait(None); + self.previous_frame_end = Some(Box::new(future) as Box<_>); } Err(vulkano::sync::FlushError::OutOfDate) => { @@ -772,4 +781,4 @@ impl HelloTriangleApplication { fn main() { let mut app = HelloTriangleApplication::initialize(); app.main_loop(); -} \ No newline at end of file +} From 64756f2338837890ed73edc6d416d7087180d8e4 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sun, 24 Feb 2019 21:15:34 -0500 Subject: [PATCH 75/78] adds mac only CPU/GPU explicit sync, updates mac env script for latest vulkan version --- mac-env.sh | 2 +- src/bin/22_descriptor_pools_and_sets.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) mode change 100644 => 100755 mac-env.sh diff --git a/mac-env.sh b/mac-env.sh old mode 100644 new mode 100755 index 573f85a..9766cc0 --- a/mac-env.sh +++ b/mac-env.sh @@ -1,5 +1,5 @@ #!/bin/bash -export VULKAN_SDK=$HOME/vulkansdk-macos-1.1.82.0/macOS +export VULKAN_SDK=$HOME/vulkansdk-macos-1.1.97.0/macOS export PATH=$VULKAN_SDK/bin:$PATH export DYLD_LIBRARY_PATH=$VULKAN_SDK/lib:$DYLD_LIBRARY_PATH export VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json diff --git a/src/bin/22_descriptor_pools_and_sets.rs b/src/bin/22_descriptor_pools_and_sets.rs index 9bb9cf5..117d66a 100644 --- a/src/bin/22_descriptor_pools_and_sets.rs +++ b/src/bin/22_descriptor_pools_and_sets.rs @@ -720,10 +720,10 @@ impl HelloTriangleApplication { match future { Ok(future) => { - // This makes sure the CPU stays in sync with the GPU - // Not sure if this means we don't need to store the previous_frame_end since we're - // explicitly waiting for it? - future.wait(None); + // This makes sure the CPU stays in sync with the GPU in situations when the CPU is + // running "too fast" + #[cfg(target_os = "macos")] + future.wait(None).unwrap(); self.previous_frame_end = Some(Box::new(future) as Box<_>); } From 8750b633b2bdfcf85463957a720376fdb5456949 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Mon, 4 Feb 2019 22:51:33 -0500 Subject: [PATCH 76/78] adds 23_images and formatted statue jpeg --- README.md | 10 +- src/bin/23_images.rs | 809 ++++++++++++++++++++++++++++++++++++++ src/bin/23_images.rs.diff | 96 +++++ src/bin/23_statue.jpg | Bin 0 -> 93643 bytes 4 files changed, 914 insertions(+), 1 deletion(-) create mode 100644 src/bin/23_images.rs create mode 100644 src/bin/23_images.rs.diff create mode 100644 src/bin/23_statue.jpg diff --git a/README.md b/README.md index 5e28d2e..a7b91bd 100644 --- a/README.md +++ b/README.md @@ -368,7 +368,15 @@ Note that due to the flipping of the Y axis in the projection matrix, we now nee the opposite direction. [Diff](src/bin/22_descriptor_pools_and_sets.rs.diff) / [Complete code](src/bin/22_descriptor_pools_and_sets.rs) -## Texture mapping (*TODO*) +## Texture mapping +### Images +https://vulkan-tutorial.com/Texture_mapping/Images + +This section is much simpler than the C++ counterpart due to the image library we use and Vulkano's internal +representation of images. The image library handles converting the image to a buffer in the right format, and then all we +need to do is pass this buffer into the appropriate constructor. + +[Diff](src/bin/23_images.rs.diff) / [Complete code](src/bin/23_images.rs) ## Depth buffering (*TODO*) ## Loading models (*TODO*) ## Generating Mipmaps (*TODO*) diff --git a/src/bin/23_images.rs b/src/bin/23_images.rs new file mode 100644 index 0000000..b2d3eb9 --- /dev/null +++ b/src/bin/23_images.rs @@ -0,0 +1,809 @@ +#[macro_use] +extern crate vulkano; +extern crate vulkano_win; +extern crate winit; +extern crate image; + +use std::sync::{Arc, Mutex}; +use std::collections::HashSet; +use std::time::Instant; + +use winit::{EventsLoop, WindowBuilder, Window, dpi::LogicalSize, Event, WindowEvent}; +use vulkano_win::VkSurfaceBuild; + +use vulkano::instance::{ + Instance, + InstanceExtensions, + ApplicationInfo, + Version, + layers_list, + PhysicalDevice, +}; +use vulkano::instance::debug::{DebugCallback, MessageTypes}; +use vulkano::device::{Device, DeviceExtensions, Queue, Features}; +use vulkano::swapchain::{ + Surface, + Capabilities, + ColorSpace, + SupportedPresentModes, + PresentMode, + Swapchain, + CompositeAlpha, + acquire_next_image, + AcquireError, +}; +use vulkano::format::Format; +use vulkano::image::{ + ImageUsage, + swapchain::SwapchainImage, + ImmutableImage, + Dimensions +}; +use vulkano::sync::{self, SharingMode, GpuFuture}; +use vulkano::pipeline::{ + GraphicsPipeline, + GraphicsPipelineAbstract, + viewport::Viewport, +}; +use vulkano::framebuffer::{ + RenderPassAbstract, + Subpass, + FramebufferAbstract, + Framebuffer, +}; +use vulkano::command_buffer::{ + AutoCommandBuffer, + AutoCommandBufferBuilder, + DynamicState, +}; +use vulkano::buffer::{ + immutable::ImmutableBuffer, + BufferUsage, + BufferAccess, + TypedBufferAccess, + CpuAccessibleBuffer +}; +use vulkano::descriptor::descriptor_set::{ + FixedSizeDescriptorSetsPool, + FixedSizeDescriptorSet +}; + +use image::GenericImageView; + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; + +const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" +]; + +const TEXTURE_PATH: &'static str = "src/bin/23_statue.jpg"; + +/// Required device extensions +fn device_extensions() -> DeviceExtensions { + DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + } +} + +#[cfg(all(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = true; +#[cfg(not(debug_assertions))] +const ENABLE_VALIDATION_LAYERS: bool = false; + +struct QueueFamilyIndices { + graphics_family: i32, + present_family: i32, +} +impl QueueFamilyIndices { + fn new() -> Self { + Self { graphics_family: -1, present_family: -1 } + } + + fn is_complete(&self) -> bool { + self.graphics_family >= 0 && self.present_family >= 0 + } +} + +#[derive(Copy, Clone)] +struct Vertex { + pos: [f32; 2], + color: [f32; 3], +} +impl Vertex { + fn new(pos: [f32; 2], color: [f32; 3]) -> Self { + Self { pos, color } + } +} +impl_vertex!(Vertex, pos, color); + +#[derive(Copy, Clone)] +struct UniformBufferObject { + model: glm::Mat4, + view: glm::Mat4, + proj: glm::Mat4, +} + +fn vertices() -> [Vertex; 4] { + [ + Vertex::new([-0.5, -0.5], [1.0, 0.0, 0.0]), + Vertex::new([0.5, -0.5], [0.0, 1.0, 0.0]), + Vertex::new([0.5, 0.5], [0.0, 0.0, 1.0]), + Vertex::new([-0.5, 0.5], [1.0, 1.0, 1.0]) + ] +} + +fn indices() -> [u16; 6] { + [0, 1, 2, 2, 3, 0] +} + +struct HelloTriangleApplication { + instance: Arc, + #[allow(unused)] + debug_callback: Option, + + events_loop: EventsLoop, + surface: Arc>, + + physical_device_index: usize, // can't store PhysicalDevice directly (lifetime issues) + device: Arc, + + graphics_queue: Arc, + present_queue: Arc, + + swap_chain: Arc>, + swap_chain_images: Vec>>, + + render_pass: Arc, + graphics_pipeline: Arc, + + swap_chain_framebuffers: Vec>, + + texture_image: Arc>, + + vertex_buffer: Arc, + index_buffer: Arc + Send + Sync>, + uniform_buffers: Vec>>, + + descriptor_sets: Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>>, + + command_buffers: Vec>, + + previous_frame_end: Option>, + recreate_swap_chain: bool, + + start_time: Instant, +} + +impl HelloTriangleApplication { + pub fn initialize() -> Self { + let instance = Self::create_instance(); + let debug_callback = Self::setup_debug_callback(&instance); + let (events_loop, surface) = Self::create_surface(&instance); + + let physical_device_index = Self::pick_physical_device(&instance, &surface); + let (device, graphics_queue, present_queue) = Self::create_logical_device( + &instance, &surface, physical_device_index); + + let (swap_chain, swap_chain_images) = Self::create_swap_chain(&instance, &surface, physical_device_index, + &device, &graphics_queue, &present_queue, None); + + let render_pass = Self::create_render_pass(&device, swap_chain.format()); + + let graphics_pipeline = Self::create_graphics_pipeline(&device, swap_chain.dimensions(), &render_pass); + + let swap_chain_framebuffers = Self::create_framebuffers(&swap_chain_images, &render_pass); + + let start_time = Instant::now(); + + let texture_image = Self::create_texture_image(&graphics_queue); + + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + let index_buffer = Self::create_index_buffer(&graphics_queue); + let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); + + let descriptor_sets_pool = Self::create_descriptor_pool(&graphics_pipeline); + let descriptor_sets = Self::create_descriptor_sets(&descriptor_sets_pool, &uniform_buffers); + + let previous_frame_end = Some(Self::create_sync_objects(&device)); + + let mut app = Self { + instance, + debug_callback, + + events_loop, + surface, + + physical_device_index, + device, + + graphics_queue, + present_queue, + + swap_chain, + swap_chain_images, + + render_pass, + graphics_pipeline, + + swap_chain_framebuffers, + + texture_image, + + vertex_buffer, + index_buffer, + uniform_buffers, + + descriptor_sets, + + command_buffers: vec![], + + previous_frame_end, + recreate_swap_chain: false, + + start_time + }; + + app.create_command_buffers(); + app + } + + fn create_instance() -> Arc { + if ENABLE_VALIDATION_LAYERS && !Self::check_validation_layer_support() { + println!("Validation layers requested, but not available!") + } + + let supported_extensions = InstanceExtensions::supported_by_core() + .expect("failed to retrieve supported extensions"); + println!("Supported extensions: {:?}", supported_extensions); + + let app_info = ApplicationInfo { + application_name: Some("Hello Triangle".into()), + application_version: Some(Version { major: 1, minor: 0, patch: 0 }), + engine_name: Some("No Engine".into()), + engine_version: Some(Version { major: 1, minor: 0, patch: 0 }), + }; + + let required_extensions = Self::get_required_extensions(); + + if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + .expect("failed to create Vulkan instance") + } else { + Instance::new(Some(&app_info), &required_extensions, None) + .expect("failed to create Vulkan instance") + } + } + + fn check_validation_layer_support() -> bool { + let layers: Vec<_> = layers_list().unwrap().map(|l| l.name().to_owned()).collect(); + VALIDATION_LAYERS.iter() + .all(|layer_name| layers.contains(&layer_name.to_string())) + } + + fn get_required_extensions() -> InstanceExtensions { + let mut extensions = vulkano_win::required_extensions(); + if ENABLE_VALIDATION_LAYERS { + // TODO!: this should be ext_debug_utils (_report is deprecated), but that doesn't exist yet in vulkano + extensions.ext_debug_report = true; + } + + extensions + } + + fn setup_debug_callback(instance: &Arc) -> Option { + if !ENABLE_VALIDATION_LAYERS { + return None; + } + + let msg_types = MessageTypes { + error: true, + warning: true, + performance_warning: true, + information: false, + debug: true, + }; + DebugCallback::new(&instance, msg_types, |msg| { + println!("validation layer: {:?}", msg.description); + }).ok() + } + + fn pick_physical_device(instance: &Arc, surface: &Arc>) -> usize { + PhysicalDevice::enumerate(&instance) + .position(|device| Self::is_device_suitable(surface, &device)) + .expect("failed to find a suitable GPU!") + } + + fn is_device_suitable(surface: &Arc>, device: &PhysicalDevice) -> bool { + let indices = Self::find_queue_families(surface, device); + let extensions_supported = Self::check_device_extension_support(device); + + let swap_chain_adequate = if extensions_supported { + let capabilities = surface.capabilities(*device) + .expect("failed to get surface capabilities"); + !capabilities.supported_formats.is_empty() && + capabilities.present_modes.iter().next().is_some() + } else { + false + }; + + indices.is_complete() && extensions_supported && swap_chain_adequate + } + + fn check_device_extension_support(device: &PhysicalDevice) -> bool { + let available_extensions = DeviceExtensions::supported_by_device(*device); + let device_extensions = device_extensions(); + available_extensions.intersection(&device_extensions) == device_extensions + } + + fn choose_swap_surface_format(available_formats: &[(Format, ColorSpace)]) -> (Format, ColorSpace) { + // NOTE: the 'preferred format' mentioned in the tutorial doesn't seem to be + // queryable in Vulkano (no VK_FORMAT_UNDEFINED enum) + *available_formats.iter() + .find(|(format, color_space)| + *format == Format::B8G8R8A8Unorm && *color_space == ColorSpace::SrgbNonLinear + ) + .unwrap_or_else(|| &available_formats[0]) + } + + fn choose_swap_present_mode(available_present_modes: SupportedPresentModes) -> PresentMode { + if available_present_modes.mailbox { + PresentMode::Mailbox + } else if available_present_modes.immediate { + PresentMode::Immediate + } else { + PresentMode::Fifo + } + } + + fn choose_swap_extent(capabilities: &Capabilities) -> [u32; 2] { + if let Some(current_extent) = capabilities.current_extent { + return current_extent + } else { + let mut actual_extent = [WIDTH, HEIGHT]; + actual_extent[0] = capabilities.min_image_extent[0] + .max(capabilities.max_image_extent[0].min(actual_extent[0])); + actual_extent[1] = capabilities.min_image_extent[1] + .max(capabilities.max_image_extent[1].min(actual_extent[1])); + actual_extent + } + } + + fn create_swap_chain( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + device: &Arc, + graphics_queue: &Arc, + present_queue: &Arc, + old_swapchain: Option>>, + ) -> (Arc>, Vec>>) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let capabilities = surface.capabilities(physical_device) + .expect("failed to get surface capabilities"); + + let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats); + let present_mode = Self::choose_swap_present_mode(capabilities.present_modes); + let extent = Self::choose_swap_extent(&capabilities); + + let mut image_count = capabilities.min_image_count + 1; + if capabilities.max_image_count.is_some() && image_count > capabilities.max_image_count.unwrap() { + image_count = capabilities.max_image_count.unwrap(); + } + + let image_usage = ImageUsage { + color_attachment: true, + .. ImageUsage::none() + }; + + let indices = Self::find_queue_families(&surface, &physical_device); + + let sharing: SharingMode = if indices.graphics_family != indices.present_family { + vec![graphics_queue, present_queue].as_slice().into() + } else { + graphics_queue.into() + }; + + let (swap_chain, images) = Swapchain::new( + device.clone(), + surface.clone(), + image_count, + surface_format.0, // TODO: color space? + extent, + 1, // layers + image_usage, + sharing, + capabilities.current_transform, + CompositeAlpha::Opaque, + present_mode, + true, // clipped + old_swapchain.as_ref() + ).expect("failed to create swap chain!"); + + (swap_chain, images) + } + + fn create_render_pass(device: &Arc, color_format: Format) -> Arc { + Arc::new(single_pass_renderpass!(device.clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: color_format, + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap()) + } + + fn create_graphics_pipeline( + device: &Arc, + swap_chain_extent: [u32; 2], + render_pass: &Arc, + ) -> Arc { + mod vertex_shader { + vulkano_shaders::shader! { + ty: "vertex", + path: "src/bin/21_shader_uniformbuffer.vert" + } + } + + mod fragment_shader { + vulkano_shaders::shader! { + ty: "fragment", + path: "src/bin/21_shader_uniformbuffer.frag" + } + } + + let vert_shader_module = vertex_shader::Shader::load(device.clone()) + .expect("failed to create vertex shader module!"); + let frag_shader_module = fragment_shader::Shader::load(device.clone()) + .expect("failed to create fragment shader module!"); + + let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32]; + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vert_shader_module.main_entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) // NOTE: also sets scissor to cover whole viewport + .fragment_shader(frag_shader_module.main_entry_point(), ()) + .depth_clamp(false) + // NOTE: there's an outcommented .rasterizer_discard() in Vulkano... + .polygon_mode_fill() // = default + .line_width(1.0) // = default + .cull_mode_back() + .front_face_counter_clockwise() + // NOTE: no depth_bias here, but on pipeline::raster::Rasterization + .blend_pass_through() // = default + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap() + ) + } + + fn create_framebuffers( + swap_chain_images: &Vec>>, + render_pass: &Arc + ) -> Vec> { + swap_chain_images.iter() + .map(|image| { + let fba: Arc = Arc::new(Framebuffer::start(render_pass.clone()) + .add(image.clone()).unwrap() + .build().unwrap()); + fba + } + ).collect::>() + } + + fn create_texture_image(graphics_queue: &Arc) -> Arc> { + let image = image::open(TEXTURE_PATH).unwrap(); + + let width = image.width(); + let height = image.height(); + + let image_rgba = image.to_rgba(); + + let (image_view, future) = ImmutableImage::from_iter( + image_rgba.into_raw().iter().cloned(), + Dimensions::Dim2d{ width, height }, + Format::R8G8B8A8Unorm, + graphics_queue.clone() + ).unwrap(); + + future.flush().unwrap(); + + return image_view; + } + + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), + graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); + buffer + } + + fn create_index_buffer(graphics_queue: &Arc) -> Arc + Send + Sync> { + let (buffer, future) = ImmutableBuffer::from_iter( + indices().iter().cloned(), BufferUsage::index_buffer(), + graphics_queue.clone()) + .unwrap(); + future.flush().unwrap(); + buffer + } + + fn create_uniform_buffers( + device: &Arc, + num_buffers: usize, + start_time: Instant, + dimensions_u32: [u32; 2] + ) -> Vec>> { + let mut buffers = Vec::new(); + + let dimensions = [dimensions_u32[0] as f32, dimensions_u32[1] as f32]; + + let uniform_buffer = Self::update_uniform_buffer(start_time, dimensions); + + for _ in 0..num_buffers { + let buffer = CpuAccessibleBuffer::from_data( + device.clone(), + BufferUsage::uniform_buffer_transfer_destination(), + uniform_buffer, + ).unwrap(); + + buffers.push(buffer); + } + + buffers + } + + fn create_descriptor_pool(graphics_pipeline: &Arc) + -> Arc>>> + { + Arc::new( + Mutex::new( + FixedSizeDescriptorSetsPool::new(graphics_pipeline.clone(), 0) + ) + ) + } + + fn create_descriptor_sets( + pool: &Arc>>>, + uniform_buffers: &Vec>>, + ) -> Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>> + { + uniform_buffers + .iter() + .map(|uniform_buffer| + Arc::new( + pool + .lock() + .unwrap() + .next() + .add_buffer(uniform_buffer.clone()) + .unwrap() + .build() + .unwrap() + ) + ) + .collect() + } + + fn create_command_buffers(&mut self) { + let queue_family = self.graphics_queue.family(); + let dimensions = [self.swap_chain.dimensions()[0] as f32, self.swap_chain.dimensions()[1] as f32]; + + self.command_buffers = self.swap_chain_framebuffers + .iter() + .enumerate() + .map(|(i, framebuffer)| { + Arc::new(AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), queue_family) + .unwrap() + .update_buffer(self.uniform_buffers[i].clone(), Self::update_uniform_buffer(self.start_time, dimensions)) + .unwrap() + .begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()]) + .unwrap() + .draw_indexed( + self.graphics_pipeline.clone(), + &DynamicState::none(), + vec![self.vertex_buffer.clone()], + self.index_buffer.clone(), + self.descriptor_sets[i].clone(), + ()) + .unwrap() + .end_render_pass() + .unwrap() + .build() + .unwrap()) + }) + .collect(); + } + + fn create_sync_objects(device: &Arc) -> Box { + Box::new(sync::now(device.clone())) as Box + } + + fn find_queue_families(surface: &Arc>, device: &PhysicalDevice) -> QueueFamilyIndices { + let mut indices = QueueFamilyIndices::new(); + // TODO: replace index with id to simplify? + for (i, queue_family) in device.queue_families().enumerate() { + if queue_family.supports_graphics() { + indices.graphics_family = i as i32; + } + + if surface.is_supported(queue_family).unwrap() { + indices.present_family = i as i32; + } + + if indices.is_complete() { + break; + } + } + + indices + } + + fn create_logical_device( + instance: &Arc, + surface: &Arc>, + physical_device_index: usize, + ) -> (Arc, Arc, Arc) { + let physical_device = PhysicalDevice::from_index(&instance, physical_device_index).unwrap(); + let indices = Self::find_queue_families(&surface, &physical_device); + + let families = [indices.graphics_family, indices.present_family]; + use std::iter::FromIterator; + let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter()); + + let queue_priority = 1.0; + let queue_families = unique_queue_families.iter().map(|i| { + (physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority) + }); + + // NOTE: the tutorial recommends passing the validation layers as well + // for legacy reasons (if ENABLE_VALIDATION_LAYERS is true). Vulkano handles that + // for us internally. + + let (device, mut queues) = Device::new(physical_device, &Features::none(), + &device_extensions(), queue_families) + .expect("failed to create logical device!"); + + let graphics_queue = queues.next().unwrap(); + let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone()); + + (device, graphics_queue, present_queue) + } + + fn create_surface(instance: &Arc) -> (EventsLoop, Arc>) { + let events_loop = EventsLoop::new(); + let surface = WindowBuilder::new() + .with_title("Vulkan") + .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT))) + .build_vk_surface(&events_loop, instance.clone()) + .expect("failed to create window surface!"); + (events_loop, surface) + } + + #[allow(unused)] + fn main_loop(&mut self) { + loop { + self.create_command_buffers(); + self.draw_frame(); + + let mut done = false; + self.events_loop.poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { + return; + } + } + } + + fn draw_frame(&mut self) { + self.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if self.recreate_swap_chain { + self.recreate_swap_chain(); + self.recreate_swap_chain = false; + } + + let (image_index, acquire_future) = match acquire_next_image(self.swap_chain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.recreate_swap_chain = true; + return; + }, + Err(err) => panic!("{:?}", err) + }; + + let command_buffer = self.command_buffers[image_index].clone(); + + let future = self.previous_frame_end.take().unwrap() + .join(acquire_future) + .then_execute(self.graphics_queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present(self.present_queue.clone(), self.swap_chain.clone(), image_index) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + self.previous_frame_end = Some(Box::new(future) as Box<_>); + } + Err(vulkano::sync::FlushError::OutOfDate) => { + self.recreate_swap_chain = true; + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + Err(e) => { + println!("{:?}", e); + self.previous_frame_end + = Some(Box::new(vulkano::sync::now(self.device.clone())) as Box<_>); + } + } + } + + fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { + let duration = Instant::now().duration_since(start_time); + let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; + + let identity_matrix = glm::mat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + ); + + let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); + + let view = glm::ext::look_at( + glm::vec3(2.0, 2.0, 2.0), + glm::vec3(0.0, 0.0, 0.0), + glm::vec3(0.0, 0.0, 1.0) + ); + let mut proj = glm::ext::perspective( + glm::radians(45.0,), + dimensions[0] as f32 / dimensions[1] as f32, + 0.1, + 10.0 + ); + + proj.c1.y *= -1.0; + + UniformBufferObject { model, view, proj } + } + + fn recreate_swap_chain(&mut self) { + let (swap_chain, images) = Self::create_swap_chain(&self.instance, &self.surface, self.physical_device_index, + &self.device, &self.graphics_queue, &self.present_queue, Some(self.swap_chain.clone())); + self.swap_chain = swap_chain; + self.swap_chain_images = images; + + self.render_pass = Self::create_render_pass(&self.device, self.swap_chain.format()); + self.graphics_pipeline = Self::create_graphics_pipeline(&self.device, self.swap_chain.dimensions(), + &self.render_pass); + self.swap_chain_framebuffers = Self::create_framebuffers(&self.swap_chain_images, &self.render_pass); + self.create_command_buffers(); + } +} + +fn main() { + let mut app = HelloTriangleApplication::initialize(); + app.main_loop(); +} \ No newline at end of file diff --git a/src/bin/23_images.rs.diff b/src/bin/23_images.rs.diff new file mode 100644 index 0000000..bc86c6b --- /dev/null +++ b/src/bin/23_images.rs.diff @@ -0,0 +1,96 @@ +--- a/22_descriptor_pools_and_sets.rs ++++ b/23_images.rs +@@ -2,6 +2,7 @@ + extern crate vulkano; + extern crate vulkano_win; + extern crate winit; ++extern crate image; + + use std::sync::{Arc, Mutex}; + use std::collections::HashSet; +@@ -32,7 +33,12 @@ use vulkano::swapchain::{ + AcquireError, + }; + use vulkano::format::Format; +-use vulkano::image::{ImageUsage, swapchain::SwapchainImage}; ++use vulkano::image::{ ++ ImageUsage, ++ swapchain::SwapchainImage, ++ ImmutableImage, ++ Dimensions ++}; + use vulkano::sync::{self, SharingMode, GpuFuture}; + use vulkano::pipeline::{ + GraphicsPipeline, +@@ -62,6 +68,8 @@ use vulkano::descriptor::descriptor_set::{ + FixedSizeDescriptorSet + }; + ++use image::GenericImageView; ++ + const WIDTH: u32 = 800; + const HEIGHT: u32 = 600; + +@@ -69,6 +77,8 @@ const VALIDATION_LAYERS: &[&str] = &[ + "VK_LAYER_LUNARG_standard_validation" + ]; + ++const TEXTURE_PATH: &'static str = "src/bin/23_statue.jpg"; ++ + /// Required device extensions + fn device_extensions() -> DeviceExtensions { + DeviceExtensions { +@@ -150,6 +160,8 @@ struct HelloTriangleApplication { + + swap_chain_framebuffers: Vec>, + ++ texture_image: Arc>, ++ + vertex_buffer: Arc, + index_buffer: Arc + Send + Sync>, + uniform_buffers: Vec>>, +@@ -185,6 +197,8 @@ impl HelloTriangleApplication { + + let start_time = Instant::now(); + ++ let texture_image = Self::create_texture_image(&graphics_queue); ++ + let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); + let index_buffer = Self::create_index_buffer(&graphics_queue); + let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); +@@ -215,6 +229,8 @@ impl HelloTriangleApplication { + + swap_chain_framebuffers, + ++ texture_image, ++ + vertex_buffer, + index_buffer, + uniform_buffers, +@@ -491,6 +507,26 @@ impl HelloTriangleApplication { + ).collect::>() + } + ++ fn create_texture_image(graphics_queue: &Arc) -> Arc> { ++ let image = image::open(TEXTURE_PATH).unwrap(); ++ ++ let width = image.width(); ++ let height = image.height(); ++ ++ let image_rgba = image.to_rgba(); ++ ++ let (image_view, future) = ImmutableImage::from_iter( ++ image_rgba.into_raw().iter().cloned(), ++ Dimensions::Dim2d{ width, height }, ++ Format::R8G8B8A8Unorm, ++ graphics_queue.clone() ++ ).unwrap(); ++ ++ future.flush().unwrap(); ++ ++ return image_view; ++ } ++ + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { + let (buffer, future) = ImmutableBuffer::from_iter( + vertices().iter().cloned(), BufferUsage::vertex_buffer(), diff --git a/src/bin/23_statue.jpg b/src/bin/23_statue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ce168676c085fb023df1e8207053e656d64bd82c GIT binary patch literal 93643 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 literal 0 HcmV?d00001 From 4525ba3cd07ee89f127485f5c03fa363f207bbb3 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 9 Feb 2019 22:40:30 -0500 Subject: [PATCH 77/78] fixes clippy warnings --- src/bin/23_images.rs | 67 +++++++++++++++++++++------------------ src/bin/23_images.rs.diff | 61 ++++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 41 deletions(-) diff --git a/src/bin/23_images.rs b/src/bin/23_images.rs index b2d3eb9..3f768dc 100644 --- a/src/bin/23_images.rs +++ b/src/bin/23_images.rs @@ -3,6 +3,7 @@ extern crate vulkano; extern crate vulkano_win; extern crate winit; extern crate image; +extern crate cgmath; use std::sync::{Arc, Mutex}; use std::collections::HashSet; @@ -65,7 +66,15 @@ use vulkano::buffer::{ }; use vulkano::descriptor::descriptor_set::{ FixedSizeDescriptorSetsPool, - FixedSizeDescriptorSet + FixedSizeDescriptorSet, + PersistentDescriptorSetBuf +}; +use cgmath::{ + Rad, + Deg, + Matrix4, + Vector3, + Point3 }; use image::GenericImageView; @@ -77,7 +86,7 @@ const VALIDATION_LAYERS: &[&str] = &[ "VK_LAYER_LUNARG_standard_validation" ]; -const TEXTURE_PATH: &'static str = "src/bin/23_statue.jpg"; +const TEXTURE_PATH: &str = "src/bin/23_statue.jpg"; /// Required device extensions fn device_extensions() -> DeviceExtensions { @@ -118,11 +127,12 @@ impl Vertex { } impl_vertex!(Vertex, pos, color); +#[allow(dead_code)] #[derive(Copy, Clone)] struct UniformBufferObject { - model: glm::Mat4, - view: glm::Mat4, - proj: glm::Mat4, + model: Matrix4, + view: Matrix4, + proj: Matrix4, } fn vertices() -> [Vertex; 4] { @@ -138,6 +148,8 @@ fn indices() -> [u16; 6] { [0, 1, 2, 2, 3, 0] } +type DescriptorSetResources = ((), PersistentDescriptorSetBuf>>); + struct HelloTriangleApplication { instance: Arc, #[allow(unused)] @@ -160,13 +172,14 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, + #[allow(dead_code)] texture_image: Arc>, vertex_buffer: Arc, index_buffer: Arc + Send + Sync>, uniform_buffers: Vec>>, - descriptor_sets: Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>>, + descriptor_sets: Vec, DescriptorSetResources>>>, command_buffers: Vec>, @@ -268,7 +281,7 @@ impl HelloTriangleApplication { let required_extensions = Self::get_required_extensions(); if ENABLE_VALIDATION_LAYERS && Self::check_validation_layer_support() { - Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().map(|s| *s)) + Instance::new(Some(&app_info), &required_extensions, VALIDATION_LAYERS.iter().cloned()) .expect("failed to create Vulkan instance") } else { Instance::new(Some(&app_info), &required_extensions, None) @@ -494,7 +507,7 @@ impl HelloTriangleApplication { } fn create_framebuffers( - swap_chain_images: &Vec>>, + swap_chain_images: &[Arc>], render_pass: &Arc ) -> Vec> { swap_chain_images.iter() @@ -524,7 +537,7 @@ impl HelloTriangleApplication { future.flush().unwrap(); - return image_view; + image_view } fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { @@ -580,10 +593,11 @@ impl HelloTriangleApplication { ) } + fn create_descriptor_sets( pool: &Arc>>>, - uniform_buffers: &Vec>>, - ) -> Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>> + uniform_buffers: &[Arc>], + ) -> Vec, DescriptorSetResources>>> { uniform_buffers .iter() @@ -705,9 +719,8 @@ impl HelloTriangleApplication { let mut done = false; self.events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - _ => () + if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev { + done = true } }); if done { @@ -761,30 +774,24 @@ impl HelloTriangleApplication { fn update_uniform_buffer(start_time: Instant, dimensions: [f32; 2]) -> UniformBufferObject { let duration = Instant::now().duration_since(start_time); - let elapsed = (duration.as_secs() * 1000) + duration.subsec_millis() as u64; + let elapsed = (duration.as_secs() * 1000) + u64::from(duration.subsec_millis()); - let identity_matrix = glm::mat4( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - ); - - let model = glm::ext::rotate(&identity_matrix, (elapsed as f32) * glm::radians(0.180), glm::vec3(0.0, 0.0, 1.00)); + let model = Matrix4::from_angle_z(Rad::from(Deg(elapsed as f32 * 0.180))); - let view = glm::ext::look_at( - glm::vec3(2.0, 2.0, 2.0), - glm::vec3(0.0, 0.0, 0.0), - glm::vec3(0.0, 0.0, 1.0) + let view = Matrix4::look_at( + Point3::new(2.0, 2.0, 2.0), + Point3::new(0.0, 0.0, 0.0), + Vector3::new(0.0, 0.0, 1.0) ); - let mut proj = glm::ext::perspective( - glm::radians(45.0,), + + let mut proj = cgmath::perspective( + Rad::from(Deg(45.0)), dimensions[0] as f32 / dimensions[1] as f32, 0.1, 10.0 ); - proj.c1.y *= -1.0; + proj.y.y *= -1.0; UniformBufferObject { model, view, proj } } diff --git a/src/bin/23_images.rs.diff b/src/bin/23_images.rs.diff index bc86c6b..f976d0c 100644 --- a/src/bin/23_images.rs.diff +++ b/src/bin/23_images.rs.diff @@ -5,10 +5,10 @@ extern crate vulkano_win; extern crate winit; +extern crate image; + extern crate cgmath; use std::sync::{Arc, Mutex}; - use std::collections::HashSet; -@@ -32,7 +33,12 @@ use vulkano::swapchain::{ +@@ -33,7 +34,12 @@ use vulkano::swapchain::{ AcquireError, }; use vulkano::format::Format; @@ -22,8 +22,18 @@ use vulkano::sync::{self, SharingMode, GpuFuture}; use vulkano::pipeline::{ GraphicsPipeline, -@@ -62,6 +68,8 @@ use vulkano::descriptor::descriptor_set::{ - FixedSizeDescriptorSet +@@ -60,7 +66,8 @@ use vulkano::buffer::{ + }; + use vulkano::descriptor::descriptor_set::{ + FixedSizeDescriptorSetsPool, +- FixedSizeDescriptorSet ++ FixedSizeDescriptorSet, ++ PersistentDescriptorSetBuf + }; + use cgmath::{ + Rad, +@@ -70,6 +77,8 @@ use cgmath::{ + Point3 }; +use image::GenericImageView; @@ -31,25 +41,41 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -@@ -69,6 +77,8 @@ const VALIDATION_LAYERS: &[&str] = &[ +@@ -77,6 +86,8 @@ const VALIDATION_LAYERS: &[&str] = &[ "VK_LAYER_LUNARG_standard_validation" ]; -+const TEXTURE_PATH: &'static str = "src/bin/23_statue.jpg"; ++const TEXTURE_PATH: &str = "src/bin/23_statue.jpg"; + /// Required device extensions fn device_extensions() -> DeviceExtensions { DeviceExtensions { -@@ -150,6 +160,8 @@ struct HelloTriangleApplication { +@@ -137,6 +148,8 @@ fn indices() -> [u16; 6] { + [0, 1, 2, 2, 3, 0] + } + ++type DescriptorSetResources = ((), PersistentDescriptorSetBuf>>); ++ + struct HelloTriangleApplication { + instance: Arc, + #[allow(unused)] +@@ -159,11 +172,14 @@ struct HelloTriangleApplication { swap_chain_framebuffers: Vec>, ++ #[allow(dead_code)] + texture_image: Arc>, + vertex_buffer: Arc, index_buffer: Arc + Send + Sync>, uniform_buffers: Vec>>, -@@ -185,6 +197,8 @@ impl HelloTriangleApplication { + +- descriptor_sets: Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>>, ++ descriptor_sets: Vec, DescriptorSetResources>>>, + + command_buffers: Vec>, + +@@ -194,6 +210,8 @@ impl HelloTriangleApplication { let start_time = Instant::now(); @@ -58,7 +84,7 @@ let vertex_buffer = Self::create_vertex_buffer(&graphics_queue); let index_buffer = Self::create_index_buffer(&graphics_queue); let uniform_buffers = Self::create_uniform_buffers(&device, swap_chain_images.len(), start_time, swap_chain.dimensions()); -@@ -215,6 +229,8 @@ impl HelloTriangleApplication { +@@ -224,6 +242,8 @@ impl HelloTriangleApplication { swap_chain_framebuffers, @@ -67,7 +93,7 @@ vertex_buffer, index_buffer, uniform_buffers, -@@ -491,6 +507,26 @@ impl HelloTriangleApplication { +@@ -500,6 +520,26 @@ impl HelloTriangleApplication { ).collect::>() } @@ -88,9 +114,22 @@ + + future.flush().unwrap(); + -+ return image_view; ++ image_view + } + fn create_vertex_buffer(graphics_queue: &Arc) -> Arc { let (buffer, future) = ImmutableBuffer::from_iter( vertices().iter().cloned(), BufferUsage::vertex_buffer(), +@@ -553,10 +593,11 @@ impl HelloTriangleApplication { + ) + } + ++ + fn create_descriptor_sets( + pool: &Arc>>>, + uniform_buffers: &[Arc>], +- ) -> Vec, ((), vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf>>)>>> ++ ) -> Vec, DescriptorSetResources>>> + { + uniform_buffers + .iter() From b596ed74e11a7b8f5d4ad016fd0264c95d8e280a Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sun, 24 Feb 2019 21:18:50 -0500 Subject: [PATCH 78/78] adds macos explicity CPU/GPU sync --- src/bin/23_images.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bin/23_images.rs b/src/bin/23_images.rs index 3f768dc..a9ba17b 100644 --- a/src/bin/23_images.rs +++ b/src/bin/23_images.rs @@ -748,6 +748,10 @@ impl HelloTriangleApplication { let command_buffer = self.command_buffers[image_index].clone(); + // we're joining on the previous future but the CPU is running faster than the GPU so + // eventually it stutters, and jumps ahead to the newer frames. + // + // See vulkano issue 1135: https://github.com/vulkano-rs/vulkano/issues/1135 let future = self.previous_frame_end.take().unwrap() .join(acquire_future) .then_execute(self.graphics_queue.clone(), command_buffer) @@ -757,6 +761,11 @@ impl HelloTriangleApplication { match future { Ok(future) => { + // This makes sure the CPU stays in sync with the GPU in situations when the CPU is + // running "too fast" + #[cfg(target_os = "macos")] + future.wait(None).unwrap(); + self.previous_frame_end = Some(Box::new(future) as Box<_>); } Err(vulkano::sync::FlushError::OutOfDate) => {