From 40cb0f5314fda72a6d5c6f15b8acf965377cde9b Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 19 Aug 2018 22:15:36 +0200 Subject: [PATCH 01/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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 9a38252c9330a65b482599407f3e228c19ede56a Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Wed, 2 Jan 2019 09:13:26 -0600 Subject: [PATCH 64/84] update: vulkan version number to latest --- mac-env.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac-env.sh b/mac-env.sh index 573f85a..e23e07b 100644 --- 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.92.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 From a98c6c96af6d463494f292a367c476c1ef3a0723 Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Wed, 2 Jan 2019 09:18:19 -0600 Subject: [PATCH 65/84] add: missing 1 --- mac-env.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mac-env.sh b/mac-env.sh index e23e07b..457dbb5 100644 --- a/mac-env.sh +++ b/mac-env.sh @@ -1,5 +1,5 @@ #!/bin/bash -export VULKAN_SDK=$HOME/vulkansdk-macos-1.1.92.0/macOS +export VULKAN_SDK=$HOME/vulkansdk-macos-1.1.92.1/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 From ee5a050b68a8f4f34f3368c940eb60b5358523de Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sat, 2 Feb 2019 16:14:56 -0500 Subject: [PATCH 66/84] 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 c938f1700c3069e568364581a5b56a8350ea3e2d Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Mon, 4 Feb 2019 20:58:18 +0100 Subject: [PATCH 67/84] readme: fix code snipped (resolves #8) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 95406fc..431fbf5 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ impl HelloTriangleApplication { } fn main() { - let mut app = HelloTriangleApplication::new(); + let mut app = HelloTriangleApplication::initialize(); app.main_loop(); } ``` From 16bb1d4c1390d97772d2fa872304c1a98672726b Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Mon, 4 Feb 2019 19:20:57 -0500 Subject: [PATCH 68/84] 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 69/84] 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 70/84] 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 71/84] 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 72/84] 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 348a2df4769fff641bff720c3d91812d6a82a5e7 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 10 Feb 2019 18:27:42 +0100 Subject: [PATCH 73/84] create github action (build & lint) --- .github/main.workflow | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/main.workflow diff --git a/.github/main.workflow b/.github/main.workflow new file mode 100644 index 0000000..8249bab --- /dev/null +++ b/.github/main.workflow @@ -0,0 +1,9 @@ +workflow "CI" { + on = "push" + resolves = ["Build & Lint"] +} + +action "Build & Lint" { + uses = "icepuma/rust-action@master" + args = "cargo build && cargo clippy -- -Dwarnings" +} From a3a3e5fd18f23fee81f6da970ded4d84a8d585ae Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 10 Feb 2019 18:32:56 +0100 Subject: [PATCH 74/84] readme: apply clippy fix from #6 --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 53614b2..a53cb0d 100644 --- a/README.md +++ b/README.md @@ -148,9 +148,8 @@ struct 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 { From d961f240fa735621831524dc37a2883a7208712b Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 10 Feb 2019 19:01:47 +0100 Subject: [PATCH 75/84] switch to rust-action fork (for cmake) --- .github/main.workflow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/main.workflow b/.github/main.workflow index 8249bab..ee326d7 100644 --- a/.github/main.workflow +++ b/.github/main.workflow @@ -4,6 +4,6 @@ workflow "CI" { } action "Build & Lint" { - uses = "icepuma/rust-action@master" + uses = "bwasty/rust-action@master" args = "cargo build && cargo clippy -- -Dwarnings" } From f403dde261a5ffc630f634c5b93e4886b939233a Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 10 Feb 2019 23:56:08 +0100 Subject: [PATCH 76/84] allow clippy issue in vulkano macro (impl_vertex) --- .github/main.workflow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/main.workflow b/.github/main.workflow index ee326d7..6533d66 100644 --- a/.github/main.workflow +++ b/.github/main.workflow @@ -5,5 +5,5 @@ workflow "CI" { action "Build & Lint" { uses = "bwasty/rust-action@master" - args = "cargo build && cargo clippy -- -Dwarnings" + args = "cargo build && cargo clippy -- -D warnings -A clippy::ref_in_deref" } From d9a7ae0b9e2d1e87fbfca2d8c487ff824c0b6d66 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Wed, 13 Feb 2019 22:36:07 -0500 Subject: [PATCH 77/84] 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 78/84] 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 79/84] 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 80/84] 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 81/84] 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 2d8d44fd7b27398eeda6354ef9bd3aecd7b0133e Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 17 Feb 2019 09:03:39 +0100 Subject: [PATCH 82/84] readme: fix link for macOS setup --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a53cb0d..b55aa85 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Then add this to your `Cargo.toml`: 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). +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-specific-setup](https://github.com/vulkano-rs/vulkano#macos-and-ios-specific-setup). ## Drawing a triangle ### Setup From 887dac070e856f88ee0fe49ca9f7c38ef0cbd4a7 Mon Sep 17 00:00:00 2001 From: Benjamin Wasty Date: Sun, 17 Feb 2019 09:14:01 +0100 Subject: [PATCH 83/84] readme: minor tweaks (diffs) --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b55aa85..268d93a 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ fn main() { 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. +Instead of GLFW we'll be using [winit](https://github.com/tomaka/winit), an alternative window managment library written in pure Rust. Add this to your Cargo.toml: ``` @@ -218,11 +218,13 @@ struct HelloTriangleApplication { } ``` -[Complete code](src/bin/01_instance_creation.rs) +[Diff](src/bin/01_instance_creation.rs.diff) / [Complete code](src/bin/01_instance_creation.rs) #### Validation layers https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers +From here on we'll just link to the code instead of putting everything in the README: + [Diff](src/bin/02_validation_layers.rs.diff) / [Complete code](src/bin/02_validation_layers.rs) From 64756f2338837890ed73edc6d416d7087180d8e4 Mon Sep 17 00:00:00 2001 From: Matthew Russo Date: Sun, 24 Feb 2019 21:15:34 -0500 Subject: [PATCH 84/84] 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<_>); }