mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Fix wayland resize issue (#1089)
Some drivers dont enforce a swapchain extent, so you need to check for resize events from the os and then recreate the swapchain. I took this opportunity to refactor the examples a bunch. I want to do some more refactoring to make things consistent but I'll leave that for a follow up PR.
This commit is contained in:
parent
753ee299d8
commit
2153177210
@ -64,6 +64,7 @@ fn main() {
|
|||||||
|
|
||||||
let mut events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||||
|
let window = surface.window();
|
||||||
|
|
||||||
let queue_family = physical.queue_families().find(|&q| {
|
let queue_family = physical.queue_families().find(|&q| {
|
||||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||||
@ -86,7 +87,12 @@ fn main() {
|
|||||||
let (mut swapchain, mut images) = {
|
let (mut swapchain, mut images) = {
|
||||||
let caps = surface.capabilities(physical)
|
let caps = surface.capabilities(physical)
|
||||||
.expect("failed to get surface capabilities");
|
.expect("failed to get surface capabilities");
|
||||||
dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
let dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||||
let format = caps.supported_formats[0].0;
|
let format = caps.supported_formats[0].0;
|
||||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||||
@ -108,9 +114,12 @@ fn main() {
|
|||||||
previous_frame_end.cleanup_finished();
|
previous_frame_end.cleanup_finished();
|
||||||
|
|
||||||
if recreate_swapchain {
|
if recreate_swapchain {
|
||||||
dimensions = surface.capabilities(physical)
|
dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
.expect("failed to get surface capabilities")
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
.current_extent.unwrap();
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
@ -125,8 +134,7 @@ fn main() {
|
|||||||
recreate_swapchain = false;
|
recreate_swapchain = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
|
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||||
None) {
|
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(AcquireError::OutOfDate) => {
|
Err(AcquireError::OutOfDate) => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
@ -179,6 +187,7 @@ fn main() {
|
|||||||
events_loop.poll_events(|ev| {
|
events_loop.poll_events(|ev| {
|
||||||
match ev {
|
match ev {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -19,6 +19,12 @@ extern crate vulkano_win;
|
|||||||
use vulkano_win::VkSurfaceBuild;
|
use vulkano_win::VkSurfaceBuild;
|
||||||
use vulkano::sync::GpuFuture;
|
use vulkano::sync::GpuFuture;
|
||||||
use vulkano_shaders::vulkano_shader;
|
use vulkano_shaders::vulkano_shader;
|
||||||
|
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract};
|
||||||
|
use vulkano::command_buffer::DynamicState;
|
||||||
|
use vulkano::image::SwapchainImage;
|
||||||
|
use vulkano::pipeline::viewport::Viewport;
|
||||||
|
|
||||||
|
use winit::Window;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -35,8 +41,7 @@ fn main() {
|
|||||||
|
|
||||||
let mut events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||||
|
let window = surface.window();
|
||||||
let mut dimensions;
|
|
||||||
|
|
||||||
let queue_family = physical.queue_families().find(|&q| q.supports_graphics() &&
|
let queue_family = physical.queue_families().find(|&q| q.supports_graphics() &&
|
||||||
surface.is_supported(q).unwrap_or(false))
|
surface.is_supported(q).unwrap_or(false))
|
||||||
@ -51,10 +56,17 @@ fn main() {
|
|||||||
.expect("failed to create device");
|
.expect("failed to create device");
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
let (mut swapchain, mut images) = {
|
let (mut swapchain, images) = {
|
||||||
let caps = surface.capabilities(physical).expect("failed to get surface capabilities");
|
let caps = surface.capabilities(physical).expect("failed to get surface capabilities");
|
||||||
|
|
||||||
dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
let dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
|
// convert to physical pixels
|
||||||
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
// The window no longer exists so exit the application.
|
||||||
|
return;
|
||||||
|
};
|
||||||
let usage = caps.supported_usage_flags;
|
let usage = caps.supported_usage_flags;
|
||||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||||
let format = caps.supported_formats[0].0;
|
let format = caps.supported_formats[0].0;
|
||||||
@ -83,7 +95,7 @@ fn main() {
|
|||||||
let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
|
let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
|
||||||
let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");
|
let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");
|
||||||
|
|
||||||
let renderpass = Arc::new(
|
let render_pass = Arc::new(
|
||||||
single_pass_renderpass!(device.clone(),
|
single_pass_renderpass!(device.clone(),
|
||||||
attachments: {
|
attachments: {
|
||||||
color: {
|
color: {
|
||||||
@ -127,7 +139,7 @@ fn main() {
|
|||||||
.viewports_dynamic_scissors_irrelevant(1)
|
.viewports_dynamic_scissors_irrelevant(1)
|
||||||
.fragment_shader(fs.main_entry_point(), ())
|
.fragment_shader(fs.main_entry_point(), ())
|
||||||
.blend_alpha_blending()
|
.blend_alpha_blending()
|
||||||
.render_pass(vulkano::framebuffer::Subpass::from(renderpass.clone(), 0).unwrap())
|
.render_pass(vulkano::framebuffer::Subpass::from(render_pass.clone(), 0).unwrap())
|
||||||
.build(device.clone())
|
.build(device.clone())
|
||||||
.unwrap());
|
.unwrap());
|
||||||
|
|
||||||
@ -136,74 +148,48 @@ fn main() {
|
|||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
|
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
|
||||||
|
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||||
|
|
||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
|
|
||||||
let mut previous_frame_end = Box::new(tex_future) as Box<GpuFuture>;
|
let mut previous_frame_end = Box::new(tex_future) as Box<GpuFuture>;
|
||||||
|
|
||||||
let mut dynamic_state = vulkano::command_buffer::DynamicState {
|
|
||||||
line_width: None,
|
|
||||||
viewports: Some(vec![vulkano::pipeline::viewport::Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]),
|
|
||||||
scissors: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
previous_frame_end.cleanup_finished();
|
previous_frame_end.cleanup_finished();
|
||||||
if recreate_swapchain {
|
if recreate_swapchain {
|
||||||
|
let dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
dimensions = surface.capabilities(physical)
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
.expect("failed to get surface capabilities")
|
[dimensions.0, dimensions.1]
|
||||||
.current_extent.unwrap_or([1024, 768]);
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => {
|
Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||||
continue;
|
|
||||||
},
|
|
||||||
Err(err) => panic!("{:?}", err)
|
Err(err) => panic!("{:?}", err)
|
||||||
};
|
};
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
swapchain = new_swapchain;
|
||||||
images = new_images;
|
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||||
|
|
||||||
framebuffers = None;
|
|
||||||
|
|
||||||
dynamic_state.viewports = Some(vec![vulkano::pipeline::viewport::Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]);
|
|
||||||
|
|
||||||
recreate_swapchain = false;
|
recreate_swapchain = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if framebuffers.is_none() {
|
let (image_num, future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||||
framebuffers = Some(images.iter().map(|image| {
|
|
||||||
Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
|
|
||||||
.add(image.clone()).unwrap()
|
|
||||||
.build().unwrap())
|
|
||||||
}).collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_num, future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(),
|
|
||||||
None) {
|
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(vulkano::swapchain::AcquireError::OutOfDate) => {
|
Err(vulkano::swapchain::AcquireError::OutOfDate) => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
Err(err) => panic!("{:?}", err)
|
Err(err) => panic!("{:?}", err)
|
||||||
};
|
};
|
||||||
|
|
||||||
let cb = vulkano::command_buffer::AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
|
let cb = vulkano::command_buffer::AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.begin_render_pass(
|
.begin_render_pass(
|
||||||
framebuffers.as_ref().unwrap()[image_num].clone(), false,
|
framebuffers[image_num].clone(), false,
|
||||||
vec![[0.0, 0.0, 1.0, 1.0].into()]).unwrap()
|
vec![[0.0, 0.0, 1.0, 1.0].into()]).unwrap()
|
||||||
.draw(pipeline.clone(),
|
.draw(pipeline.clone(),
|
||||||
&dynamic_state,
|
&dynamic_state,
|
||||||
@ -235,6 +221,7 @@ fn main() {
|
|||||||
events_loop.poll_events(|ev| {
|
events_loop.poll_events(|ev| {
|
||||||
match ev {
|
match ev {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -242,6 +229,30 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method is called once during initialization then again whenever the window is resized
|
||||||
|
fn window_size_dependent_setup(
|
||||||
|
images: &[Arc<SwapchainImage<Window>>],
|
||||||
|
render_pass: Arc<RenderPassAbstract + Send + Sync>,
|
||||||
|
dynamic_state: &mut DynamicState
|
||||||
|
) -> Vec<Arc<FramebufferAbstract + Send + Sync>> {
|
||||||
|
let dimensions = images[0].dimensions();
|
||||||
|
|
||||||
|
let viewport = Viewport {
|
||||||
|
origin: [0.0, 0.0],
|
||||||
|
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||||
|
depth_range: 0.0 .. 1.0,
|
||||||
|
};
|
||||||
|
dynamic_state.viewports = Some(vec!(viewport));
|
||||||
|
|
||||||
|
images.iter().map(|image| {
|
||||||
|
Arc::new(
|
||||||
|
Framebuffer::start(render_pass.clone())
|
||||||
|
.add(image.clone()).unwrap()
|
||||||
|
.build().unwrap()
|
||||||
|
) as Arc<FramebufferAbstract + Send + Sync>
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
vulkano_shader!{
|
vulkano_shader!{
|
||||||
mod_name: vs,
|
mod_name: vs,
|
||||||
ty: "vertex",
|
ty: "vertex",
|
||||||
|
@ -35,20 +35,21 @@ use vulkano::descriptor::pipeline_layout::PipelineLayoutDescPcRange;
|
|||||||
use vulkano::device::Device;
|
use vulkano::device::Device;
|
||||||
use vulkano::device::DeviceExtensions;
|
use vulkano::device::DeviceExtensions;
|
||||||
use vulkano::format;
|
use vulkano::format;
|
||||||
use vulkano::framebuffer::Framebuffer;
|
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
||||||
use vulkano::framebuffer::Subpass;
|
use vulkano::image::SwapchainImage;
|
||||||
use vulkano::pipeline::GraphicsPipeline;
|
use vulkano::pipeline::GraphicsPipeline;
|
||||||
use vulkano::pipeline::shader::GraphicsShaderType;
|
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderInterfaceDef, ShaderInterfaceDefEntry, ShaderModule};
|
||||||
use vulkano::pipeline::shader::ShaderInterfaceDef;
|
|
||||||
use vulkano::pipeline::shader::ShaderInterfaceDefEntry;
|
|
||||||
use vulkano::pipeline::shader::ShaderModule;
|
|
||||||
use vulkano::pipeline::vertex::SingleBufferDefinition;
|
use vulkano::pipeline::vertex::SingleBufferDefinition;
|
||||||
use vulkano::pipeline::viewport::Viewport;
|
use vulkano::pipeline::viewport::Viewport;
|
||||||
use vulkano::swapchain::Swapchain;
|
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError};
|
||||||
|
use vulkano::swapchain;
|
||||||
use vulkano::sync::GpuFuture;
|
use vulkano::sync::GpuFuture;
|
||||||
|
use vulkano::sync;
|
||||||
|
|
||||||
use vulkano_win::VkSurfaceBuild;
|
use vulkano_win::VkSurfaceBuild;
|
||||||
|
|
||||||
|
use winit::Window;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -73,12 +74,9 @@ fn main() {
|
|||||||
.next()
|
.next()
|
||||||
.expect("no graphics device");
|
.expect("no graphics device");
|
||||||
let mut events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
let surface = winit::WindowBuilder::new()
|
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||||
.with_decorations(false)
|
let window = surface.window();
|
||||||
.with_title("particle storm")
|
let (device, mut queues) = {
|
||||||
.build_vk_surface(&events_loop, instance.clone())
|
|
||||||
.unwrap();
|
|
||||||
let (graphics_device, mut queues) = {
|
|
||||||
let graphical_queue_family = physical
|
let graphical_queue_family = physical
|
||||||
.queue_families()
|
.queue_families()
|
||||||
.find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false))
|
.find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false))
|
||||||
@ -96,17 +94,17 @@ fn main() {
|
|||||||
};
|
};
|
||||||
let graphics_queue = queues.next().unwrap();
|
let graphics_queue = queues.next().unwrap();
|
||||||
|
|
||||||
let (swapchain, images) = {
|
let (mut swapchain, images) = {
|
||||||
let caps = surface
|
let caps = surface
|
||||||
.capabilities(graphics_device.physical_device())
|
.capabilities(device.physical_device())
|
||||||
.expect("failure to get surface capabilities");
|
.expect("failure to get surface capabilities");
|
||||||
|
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||||
let format = caps.supported_formats[0].0;
|
let format = caps.supported_formats[0].0;
|
||||||
let dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
let dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
||||||
let usage = caps.supported_usage_flags;
|
let usage = caps.supported_usage_flags;
|
||||||
let present = caps.present_modes.iter().next().unwrap();
|
|
||||||
|
|
||||||
Swapchain::new(
|
Swapchain::new(
|
||||||
graphics_device.clone(),
|
device.clone(),
|
||||||
surface.clone(),
|
surface.clone(),
|
||||||
caps.min_image_count,
|
caps.min_image_count,
|
||||||
format,
|
format,
|
||||||
@ -114,17 +112,17 @@ fn main() {
|
|||||||
1,
|
1,
|
||||||
usage,
|
usage,
|
||||||
&graphics_queue,
|
&graphics_queue,
|
||||||
vk::swapchain::SurfaceTransform::Identity,
|
SurfaceTransform::Identity,
|
||||||
vk::swapchain::CompositeAlpha::Opaque,
|
alpha,
|
||||||
present,
|
PresentMode::Fifo,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
).expect("failed to create swapchain")
|
).expect("failed to create swapchain")
|
||||||
};
|
};
|
||||||
|
|
||||||
let renderpass = Arc::new(
|
let render_pass = Arc::new(
|
||||||
single_pass_renderpass!(
|
single_pass_renderpass!(
|
||||||
graphics_device.clone(), attachments: {
|
device.clone(), attachments: {
|
||||||
color: {
|
color: {
|
||||||
load: Clear,
|
load: Clear,
|
||||||
store: Store,
|
store: Store,
|
||||||
@ -146,7 +144,7 @@ fn main() {
|
|||||||
f.read_to_end(&mut v).unwrap();
|
f.read_to_end(&mut v).unwrap();
|
||||||
// Create a ShaderModule on a device the same Shader::load does it.
|
// Create a ShaderModule on a device the same Shader::load does it.
|
||||||
// NOTE: You will have to verify correctness of the data by yourself!
|
// NOTE: You will have to verify correctness of the data by yourself!
|
||||||
unsafe { ShaderModule::new(graphics_device.clone(), &v) }.unwrap()
|
unsafe { ShaderModule::new(device.clone(), &v) }.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let fs = {
|
let fs = {
|
||||||
@ -154,7 +152,7 @@ fn main() {
|
|||||||
.expect("Can't find file src/bin/runtime-shader/frag.spv");
|
.expect("Can't find file src/bin/runtime-shader/frag.spv");
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
f.read_to_end(&mut v).unwrap();
|
f.read_to_end(&mut v).unwrap();
|
||||||
unsafe { ShaderModule::new(graphics_device.clone(), &v) }.unwrap()
|
unsafe { ShaderModule::new(device.clone(), &v) }.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
// This structure will tell Vulkan how input entries of our vertex shader
|
// This structure will tell Vulkan how input entries of our vertex shader
|
||||||
@ -387,25 +385,20 @@ fn main() {
|
|||||||
.vertex_input(SingleBufferDefinition::<Vertex>::new())
|
.vertex_input(SingleBufferDefinition::<Vertex>::new())
|
||||||
.vertex_shader(vert_main, ())
|
.vertex_shader(vert_main, ())
|
||||||
.triangle_list()
|
.triangle_list()
|
||||||
.viewports([
|
.viewports_dynamic_scissors_irrelevant(1)
|
||||||
Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
depth_range: 0.0..1.0,
|
|
||||||
dimensions: [images[0].dimensions()[0] as f32,
|
|
||||||
images[0].dimensions()[1] as f32],
|
|
||||||
},
|
|
||||||
].iter().cloned())
|
|
||||||
.fragment_shader(frag_main, ())
|
.fragment_shader(frag_main, ())
|
||||||
.cull_mode_front()
|
.cull_mode_front()
|
||||||
.front_face_counter_clockwise()
|
.front_face_counter_clockwise()
|
||||||
.depth_stencil_disabled()
|
.depth_stencil_disabled()
|
||||||
.render_pass(Subpass::from(renderpass.clone(), 0).unwrap())
|
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||||
.build(graphics_device.clone())
|
.build(device.clone())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut recreate_swapchain = false;
|
||||||
|
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
graphics_device.clone(),
|
device.clone(),
|
||||||
BufferUsage::all(),
|
BufferUsage::all(),
|
||||||
[
|
[
|
||||||
Vertex { position: [-1.0, 1.0], color: [1.0, 0.0, 0.0] },
|
Vertex { position: [-1.0, 1.0], color: [1.0, 0.0, 0.0] },
|
||||||
@ -418,27 +411,45 @@ fn main() {
|
|||||||
// note that passing wrong types, providing sets at wrong indexes will cause
|
// note that passing wrong types, providing sets at wrong indexes will cause
|
||||||
// descriptor set builder to return Err!
|
// descriptor set builder to return Err!
|
||||||
|
|
||||||
let framebuffers: Vec<_> = images
|
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
|
||||||
.iter()
|
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||||
.map(|image| Arc::new(
|
let mut previous_frame_end = Box::new(sync::now(device.clone())) as Box<GpuFuture>;
|
||||||
Framebuffer::start(renderpass.clone())
|
|
||||||
.add(image.clone()).unwrap()
|
|
||||||
.build().unwrap(),
|
|
||||||
))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
events_loop.poll_events(|_| ());
|
previous_frame_end.cleanup_finished();
|
||||||
|
|
||||||
let (image_num, acquire_future) =
|
if recreate_swapchain {
|
||||||
vk::swapchain::acquire_next_image(
|
// Get the new dimensions for the viewport/framebuffers.
|
||||||
swapchain.clone(),
|
let dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
None,
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
).expect("failed to acquire swapchain in time");
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let command_buffer = AutoCommandBufferBuilder
|
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||||
::new(
|
Ok(r) => r,
|
||||||
graphics_device.clone(),
|
Err(SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||||
|
Err(err) => panic!("{:?}", err)
|
||||||
|
};
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||||
|
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(AcquireError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
Err(err) => panic!("{:?}", err)
|
||||||
|
};
|
||||||
|
|
||||||
|
let command_buffer = AutoCommandBufferBuilder::new(
|
||||||
|
device.clone(),
|
||||||
graphics_queue.family(),
|
graphics_queue.family(),
|
||||||
).unwrap()
|
).unwrap()
|
||||||
.begin_render_pass(
|
.begin_render_pass(
|
||||||
@ -448,7 +459,7 @@ fn main() {
|
|||||||
).unwrap()
|
).unwrap()
|
||||||
.draw(
|
.draw(
|
||||||
graphics_pipeline.clone(),
|
graphics_pipeline.clone(),
|
||||||
&DynamicState::none(),
|
&dynamic_state,
|
||||||
vertex_buffer.clone(),
|
vertex_buffer.clone(),
|
||||||
(),
|
(),
|
||||||
(),
|
(),
|
||||||
@ -456,10 +467,57 @@ fn main() {
|
|||||||
.end_render_pass().unwrap()
|
.end_render_pass().unwrap()
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
|
|
||||||
acquire_future
|
let future = previous_frame_end.join(acquire_future)
|
||||||
.then_execute(graphics_queue.clone(), command_buffer).unwrap()
|
.then_execute(graphics_queue.clone(), command_buffer).unwrap()
|
||||||
.then_swapchain_present(graphics_queue.clone(), swapchain.clone(), image_num)
|
.then_swapchain_present(graphics_queue.clone(), swapchain.clone(), image_num)
|
||||||
.then_signal_fence_and_flush().unwrap()
|
.then_signal_fence_and_flush();
|
||||||
.wait(None).unwrap();
|
|
||||||
|
match future {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Box::new(future) as Box<_>;
|
||||||
|
}
|
||||||
|
Err(vulkano::sync::FlushError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{:?}", e);
|
||||||
|
previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut done = false;
|
||||||
|
events_loop.poll_events(|ev| {
|
||||||
|
match ev {
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if done { return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method is called once during initialization then again whenever the window is resized
|
||||||
|
fn window_size_dependent_setup(
|
||||||
|
images: &[Arc<SwapchainImage<Window>>],
|
||||||
|
render_pass: Arc<RenderPassAbstract + Send + Sync>,
|
||||||
|
dynamic_state: &mut DynamicState
|
||||||
|
) -> Vec<Arc<FramebufferAbstract + Send + Sync>> {
|
||||||
|
let dimensions = images[0].dimensions();
|
||||||
|
|
||||||
|
let viewport = Viewport {
|
||||||
|
origin: [0.0, 0.0],
|
||||||
|
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||||
|
depth_range: 0.0 .. 1.0,
|
||||||
|
};
|
||||||
|
dynamic_state.viewports = Some(vec!(viewport));
|
||||||
|
|
||||||
|
images.iter().map(|image| {
|
||||||
|
Arc::new(
|
||||||
|
Framebuffer::start(render_pass.clone())
|
||||||
|
.add(image.clone()).unwrap()
|
||||||
|
.build().unwrap()
|
||||||
|
) as Arc<FramebufferAbstract + Send + Sync>
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
@ -18,84 +18,95 @@ extern crate vulkano_shaders;
|
|||||||
extern crate vulkano_win;
|
extern crate vulkano_win;
|
||||||
|
|
||||||
use vulkano_win::VkSurfaceBuild;
|
use vulkano_win::VkSurfaceBuild;
|
||||||
|
|
||||||
|
use vulkano::buffer::cpu_pool::CpuBufferPool;
|
||||||
|
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||||
|
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
|
||||||
|
use vulkano::device::{Device, DeviceExtensions};
|
||||||
|
use vulkano::format::Format;
|
||||||
|
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
||||||
|
use vulkano::image::SwapchainImage;
|
||||||
|
use vulkano::image::attachment::AttachmentImage;
|
||||||
|
use vulkano::instance::Instance;
|
||||||
|
use vulkano::instance::PhysicalDevice;
|
||||||
|
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
|
||||||
|
use vulkano::pipeline::vertex::TwoBuffersDefinition;
|
||||||
|
use vulkano::pipeline::viewport::Viewport;
|
||||||
|
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError};
|
||||||
|
use vulkano::swapchain;
|
||||||
use vulkano::sync::GpuFuture;
|
use vulkano::sync::GpuFuture;
|
||||||
|
|
||||||
use vulkano_shaders::vulkano_shader;
|
use vulkano_shaders::vulkano_shader;
|
||||||
|
|
||||||
|
use winit::Window;
|
||||||
|
|
||||||
|
use cgmath::{Matrix3, Matrix4, Point3, Vector3, Rad};
|
||||||
|
|
||||||
|
use examples::{Vertex, Normal, VERTICES, NORMALS, INDICES};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// The start of this example is exactly the same as `triangle`. You should read the
|
// The start of this example is exactly the same as `triangle`. You should read the
|
||||||
// `triangle` example if you haven't done so yet.
|
// `triangle` example if you haven't done so yet.
|
||||||
|
|
||||||
let extensions = vulkano_win::required_extensions();
|
let extensions = vulkano_win::required_extensions();
|
||||||
let instance = vulkano::instance::Instance::new(None, &extensions, None).expect("failed to create instance");
|
let instance = Instance::new(None, &extensions, None).expect("failed to create instance");
|
||||||
|
|
||||||
let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
|
let physical = PhysicalDevice::enumerate(&instance).next().expect("no device available");
|
||||||
.next().expect("no device available");
|
|
||||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||||
|
|
||||||
let mut events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||||
|
let window = surface.window();
|
||||||
|
|
||||||
let mut dimensions;
|
// unlike the triangle example we need to keep track of the width and height so we can calculate
|
||||||
|
// render the teapot with the correct aspect ratio.
|
||||||
let queue_family = physical.queue_families().find(|&q| q.supports_graphics() &&
|
let mut dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
surface.is_supported(q).unwrap_or(false))
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
.expect("couldn't find a graphical queue family");
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
let device_ext = vulkano::device::DeviceExtensions {
|
return;
|
||||||
khr_swapchain: true,
|
|
||||||
.. vulkano::device::DeviceExtensions::none()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (device, mut queues) = vulkano::device::Device::new(physical, physical.supported_features(),
|
let queue_family = physical.queue_families().find(|&q|
|
||||||
&device_ext, [(queue_family, 0.5)].iter().cloned())
|
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||||
.expect("failed to create device");
|
).expect("couldn't find a graphical queue family");
|
||||||
|
|
||||||
|
let device_ext = DeviceExtensions { khr_swapchain: true, .. DeviceExtensions::none() };
|
||||||
|
|
||||||
|
let (device, mut queues) = Device::new(
|
||||||
|
physical, physical.supported_features(), &device_ext, [(queue_family, 0.5)].iter().cloned()
|
||||||
|
).expect("failed to create device");
|
||||||
|
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
let (mut swapchain, mut images) = {
|
let (mut swapchain, images) = {
|
||||||
let caps = surface.capabilities(physical).expect("failed to get surface capabilities");
|
let caps = surface.capabilities(physical).expect("failed to get surface capabilities");
|
||||||
|
|
||||||
dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
|
||||||
|
|
||||||
let usage = caps.supported_usage_flags;
|
let usage = caps.supported_usage_flags;
|
||||||
let format = caps.supported_formats[0].0;
|
let format = caps.supported_formats[0].0;
|
||||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||||
|
|
||||||
vulkano::swapchain::Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1,
|
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1,
|
||||||
usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
|
usage, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, None).expect("failed to create swapchain")
|
||||||
alpha,
|
|
||||||
vulkano::swapchain::PresentMode::Fifo, true, None).expect("failed to create swapchain")
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let vertices = VERTICES.iter().cloned();
|
||||||
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), vertices).unwrap();
|
||||||
|
|
||||||
let mut depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), dimensions, vulkano::format::D16Unorm).unwrap();
|
let normals = NORMALS.iter().cloned();
|
||||||
|
let normals_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), normals).unwrap();
|
||||||
|
|
||||||
let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
|
let indices = INDICES.iter().cloned();
|
||||||
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::VERTICES.iter().cloned())
|
let index_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), indices).unwrap();
|
||||||
.expect("failed to create buffer");
|
|
||||||
|
|
||||||
let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
|
let uniform_buffer = CpuBufferPool::<vs::ty::Data>::new(device.clone(), BufferUsage::all());
|
||||||
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::NORMALS.iter().cloned())
|
|
||||||
.expect("failed to create buffer");
|
|
||||||
|
|
||||||
let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
|
|
||||||
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::INDICES.iter().cloned())
|
|
||||||
.expect("failed to create buffer");
|
|
||||||
|
|
||||||
// note: this teapot was meant for OpenGL where the origin is at the lower left
|
|
||||||
// instead the origin is at the upper left in Vulkan, so we reverse the Y axis
|
|
||||||
let mut proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { dimensions[0] as f32 / dimensions[1] as f32 }, 0.01, 100.0);
|
|
||||||
let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
|
|
||||||
let scale = cgmath::Matrix4::from_scale(0.01);
|
|
||||||
|
|
||||||
let uniform_buffer = vulkano::buffer::cpu_pool::CpuBufferPool::<vs::ty::Data>
|
|
||||||
::new(device.clone(), vulkano::buffer::BufferUsage::all());
|
|
||||||
|
|
||||||
let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
|
let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
|
||||||
let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");
|
let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");
|
||||||
|
|
||||||
let renderpass = Arc::new(
|
let render_pass = Arc::new(
|
||||||
single_pass_renderpass!(device.clone(),
|
single_pass_renderpass!(device.clone(),
|
||||||
attachments: {
|
attachments: {
|
||||||
color: {
|
color: {
|
||||||
@ -118,84 +129,51 @@ fn main() {
|
|||||||
).unwrap()
|
).unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::start()
|
let (mut pipeline, mut framebuffers) = window_size_dependent_setup(device.clone(), &vs, &fs, &images, render_pass.clone());
|
||||||
.vertex_input(vulkano::pipeline::vertex::TwoBuffersDefinition::new())
|
|
||||||
.vertex_shader(vs.main_entry_point(), ())
|
|
||||||
.triangle_list()
|
|
||||||
.viewports_dynamic_scissors_irrelevant(1)
|
|
||||||
.fragment_shader(fs.main_entry_point(), ())
|
|
||||||
.depth_stencil_simple_depth()
|
|
||||||
.render_pass(vulkano::framebuffer::Subpass::from(renderpass.clone(), 0).unwrap())
|
|
||||||
.build(device.clone())
|
|
||||||
.unwrap());
|
|
||||||
let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
|
|
||||||
|
|
||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
|
|
||||||
let mut previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
|
let mut previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
|
||||||
let rotation_start = std::time::Instant::now();
|
let rotation_start = std::time::Instant::now();
|
||||||
|
|
||||||
let mut dynamic_state = vulkano::command_buffer::DynamicState {
|
|
||||||
line_width: None,
|
|
||||||
viewports: Some(vec![vulkano::pipeline::viewport::Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]),
|
|
||||||
scissors: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
previous_frame.cleanup_finished();
|
previous_frame.cleanup_finished();
|
||||||
|
|
||||||
if recreate_swapchain {
|
if recreate_swapchain {
|
||||||
|
dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
dimensions = surface.capabilities(physical)
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
.expect("failed to get surface capabilities")
|
[dimensions.0, dimensions.1]
|
||||||
.current_extent.unwrap_or([1024, 768]);
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => {
|
Err(SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||||
continue;
|
|
||||||
},
|
|
||||||
Err(err) => panic!("{:?}", err)
|
Err(err) => panic!("{:?}", err)
|
||||||
};
|
};
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
swapchain = new_swapchain;
|
||||||
images = new_images;
|
|
||||||
|
|
||||||
depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), dimensions, vulkano::format::D16Unorm).unwrap();
|
let (new_pipeline, new_framebuffers) = window_size_dependent_setup(device.clone(), &vs, &fs, &new_images, render_pass.clone());
|
||||||
|
pipeline = new_pipeline;
|
||||||
framebuffers = None;
|
framebuffers = new_framebuffers;
|
||||||
|
|
||||||
proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { dimensions[0] as f32 / dimensions[1] as f32 }, 0.01, 100.0);
|
|
||||||
|
|
||||||
dynamic_state.viewports = Some(vec![vulkano::pipeline::viewport::Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]);
|
|
||||||
|
|
||||||
recreate_swapchain = false;
|
recreate_swapchain = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if framebuffers.is_none() {
|
|
||||||
framebuffers = Some(images.iter().map(|image| {
|
|
||||||
Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
|
|
||||||
.add(image.clone()).unwrap()
|
|
||||||
.add(depth_buffer.clone()).unwrap()
|
|
||||||
.build().unwrap())
|
|
||||||
}).collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
let uniform_buffer_subbuffer = {
|
let uniform_buffer_subbuffer = {
|
||||||
let elapsed = rotation_start.elapsed();
|
let elapsed = rotation_start.elapsed();
|
||||||
let rotation = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0;
|
let rotation = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0;
|
||||||
let rotation = cgmath::Matrix3::from_angle_y(cgmath::Rad(rotation as f32));
|
let rotation = Matrix3::from_angle_y(Rad(rotation as f32));
|
||||||
|
|
||||||
|
// note: this teapot was meant for OpenGL where the origin is at the lower left
|
||||||
|
// instead the origin is at the upper left in Vulkan, so we reverse the Y axis
|
||||||
|
let aspect_ratio = dimensions[0] as f32 / dimensions[1] as f32;
|
||||||
|
let proj = cgmath::perspective(Rad(std::f32::consts::FRAC_PI_2), aspect_ratio, 0.01, 100.0);
|
||||||
|
let view = Matrix4::look_at(Point3::new(0.3, 0.3, 1.0), Point3::new(0.0, 0.0, 0.0), Vector3::new(0.0, -1.0, 0.0));
|
||||||
|
let scale = Matrix4::from_scale(0.01);
|
||||||
|
|
||||||
let uniform_data = vs::ty::Data {
|
let uniform_data = vs::ty::Data {
|
||||||
world : cgmath::Matrix4::from(rotation).into(),
|
world: Matrix4::from(rotation).into(),
|
||||||
view: (view * scale).into(),
|
view: (view * scale).into(),
|
||||||
proj: proj.into(),
|
proj: proj.into(),
|
||||||
};
|
};
|
||||||
@ -208,27 +186,26 @@ fn main() {
|
|||||||
.build().unwrap()
|
.build().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(),
|
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||||
None) {
|
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(vulkano::swapchain::AcquireError::OutOfDate) => {
|
Err(AcquireError::OutOfDate) => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
Err(err) => panic!("{:?}", err)
|
Err(err) => panic!("{:?}", err)
|
||||||
};
|
};
|
||||||
|
|
||||||
let command_buffer = vulkano::command_buffer::AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||||
.begin_render_pass(
|
.begin_render_pass(
|
||||||
framebuffers.as_ref().unwrap()[image_num].clone(), false,
|
framebuffers[image_num].clone(), false,
|
||||||
vec![
|
vec![
|
||||||
[0.0, 0.0, 1.0, 1.0].into(),
|
[0.0, 0.0, 1.0, 1.0].into(),
|
||||||
1f32.into()
|
1f32.into()
|
||||||
]).unwrap()
|
]).unwrap()
|
||||||
.draw_indexed(
|
.draw_indexed(
|
||||||
pipeline.clone(),
|
pipeline.clone(),
|
||||||
&dynamic_state,
|
&DynamicState::none(),
|
||||||
(vertex_buffer.clone(), normals_buffer.clone()),
|
vec!(vertex_buffer.clone(), normals_buffer.clone()),
|
||||||
index_buffer.clone(), set.clone(), ()).unwrap()
|
index_buffer.clone(), set.clone(), ()).unwrap()
|
||||||
.end_render_pass().unwrap()
|
.end_render_pass().unwrap()
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
@ -256,6 +233,7 @@ fn main() {
|
|||||||
events_loop.poll_events(|ev| {
|
events_loop.poll_events(|ev| {
|
||||||
match ev {
|
match ev {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -263,6 +241,50 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method is called once during initialization then again whenever the window is resized
|
||||||
|
fn window_size_dependent_setup(
|
||||||
|
device: Arc<Device>,
|
||||||
|
vs: &vs::Shader,
|
||||||
|
fs: &fs::Shader,
|
||||||
|
images: &[Arc<SwapchainImage<Window>>],
|
||||||
|
render_pass: Arc<RenderPassAbstract + Send + Sync>,
|
||||||
|
) -> (Arc<GraphicsPipelineAbstract + Send + Sync>, Vec<Arc<FramebufferAbstract + Send + Sync>> ) {
|
||||||
|
let dimensions = images[0].dimensions();
|
||||||
|
|
||||||
|
let depth_buffer = AttachmentImage::transient(device.clone(), dimensions, Format::D16Unorm).unwrap();
|
||||||
|
|
||||||
|
let framebuffers = images.iter().map(|image| {
|
||||||
|
Arc::new(
|
||||||
|
Framebuffer::start(render_pass.clone())
|
||||||
|
.add(image.clone()).unwrap()
|
||||||
|
.add(depth_buffer.clone()).unwrap()
|
||||||
|
.build().unwrap()
|
||||||
|
) as Arc<FramebufferAbstract + Send + Sync>
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// In the triangle example we use a dynamic viewport, as its a simple example.
|
||||||
|
// However in the teapot example, we recreate the pipelines with a hardcoded viewport instead.
|
||||||
|
// This allows the driver to optimize things, at the cost of slower window resizes.
|
||||||
|
// https://computergraphics.stackexchange.com/questions/5742/vulkan-best-way-of-updating-pipeline-viewport
|
||||||
|
let pipeline = Arc::new(GraphicsPipeline::start()
|
||||||
|
.vertex_input(TwoBuffersDefinition::<Vertex, Normal>::new())
|
||||||
|
.vertex_shader(vs.main_entry_point(), ())
|
||||||
|
.triangle_list()
|
||||||
|
.viewports_dynamic_scissors_irrelevant(1)
|
||||||
|
.viewports(iter::once(Viewport {
|
||||||
|
origin: [0.0, 0.0],
|
||||||
|
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||||
|
depth_range: 0.0 .. 1.0,
|
||||||
|
}))
|
||||||
|
.fragment_shader(fs.main_entry_point(), ())
|
||||||
|
.depth_stencil_simple_depth()
|
||||||
|
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||||
|
.build(device.clone())
|
||||||
|
.unwrap());
|
||||||
|
|
||||||
|
(pipeline, framebuffers)
|
||||||
|
}
|
||||||
|
|
||||||
vulkano_shader!{
|
vulkano_shader!{
|
||||||
mod_name: vs,
|
mod_name: vs,
|
||||||
ty: "vertex",
|
ty: "vertex",
|
||||||
|
@ -26,26 +26,22 @@ extern crate vulkano_win;
|
|||||||
|
|
||||||
use vulkano_win::VkSurfaceBuild;
|
use vulkano_win::VkSurfaceBuild;
|
||||||
|
|
||||||
use vulkano::buffer::BufferUsage;
|
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||||
use vulkano::buffer::CpuAccessibleBuffer;
|
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
|
||||||
use vulkano::command_buffer::AutoCommandBufferBuilder;
|
|
||||||
use vulkano::command_buffer::DynamicState;
|
|
||||||
use vulkano::device::Device;
|
use vulkano::device::Device;
|
||||||
use vulkano::framebuffer::Framebuffer;
|
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
||||||
use vulkano::framebuffer::Subpass;
|
use vulkano::image::SwapchainImage;
|
||||||
use vulkano::instance::Instance;
|
use vulkano::instance::Instance;
|
||||||
use vulkano::pipeline::GraphicsPipeline;
|
use vulkano::pipeline::GraphicsPipeline;
|
||||||
use vulkano::pipeline::viewport::Viewport;
|
use vulkano::pipeline::viewport::Viewport;
|
||||||
use vulkano::swapchain;
|
use vulkano::swapchain;
|
||||||
use vulkano::swapchain::PresentMode;
|
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError};
|
||||||
use vulkano::swapchain::SurfaceTransform;
|
|
||||||
use vulkano::swapchain::Swapchain;
|
|
||||||
use vulkano::swapchain::AcquireError;
|
|
||||||
use vulkano::swapchain::SwapchainCreationError;
|
|
||||||
use vulkano::sync::now;
|
use vulkano::sync::now;
|
||||||
use vulkano::sync::GpuFuture;
|
use vulkano::sync::GpuFuture;
|
||||||
use vulkano_shaders::vulkano_shader;
|
use vulkano_shaders::vulkano_shader;
|
||||||
|
|
||||||
|
use winit::Window;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
vulkano_shader!{
|
vulkano_shader!{
|
||||||
@ -148,6 +144,7 @@ fn main() {
|
|||||||
|
|
||||||
let mut events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||||
|
let window = surface.window();
|
||||||
|
|
||||||
let queue = physical.queue_families().find(|&q| {
|
let queue = physical.queue_families().find(|&q| {
|
||||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||||
@ -163,13 +160,17 @@ fn main() {
|
|||||||
};
|
};
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
let mut dimensions;
|
let mut dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let (mut swapchain, mut images) = {
|
let (mut swapchain, images) = {
|
||||||
let caps = surface.capabilities(physical)
|
let caps = surface.capabilities(physical)
|
||||||
.expect("failed to get surface capabilities");
|
.expect("failed to get surface capabilities");
|
||||||
|
|
||||||
dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
|
||||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||||
let format = caps.supported_formats[0].0;
|
let format = caps.supported_formats[0].0;
|
||||||
|
|
||||||
@ -234,25 +235,20 @@ fn main() {
|
|||||||
.build(device.clone())
|
.build(device.clone())
|
||||||
.unwrap());
|
.unwrap());
|
||||||
|
|
||||||
let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
|
|
||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
|
let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
|
||||||
let mut dynamic_state = DynamicState {
|
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
|
||||||
line_width: None,
|
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||||
viewports: Some(vec![Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]),
|
|
||||||
scissors: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
previous_frame_end.cleanup_finished();
|
previous_frame_end.cleanup_finished();
|
||||||
if recreate_swapchain {
|
if recreate_swapchain {
|
||||||
dimensions = surface.capabilities(physical)
|
dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
.expect("failed to get surface capabilities")
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
.current_extent.unwrap();
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
@ -263,27 +259,12 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
swapchain = new_swapchain;
|
||||||
images = new_images;
|
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||||
framebuffers = None;
|
|
||||||
dynamic_state.viewports = Some(vec![Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]);
|
|
||||||
|
|
||||||
recreate_swapchain = false;
|
recreate_swapchain = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if framebuffers.is_none() {
|
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||||
framebuffers = Some(images.iter().map(|image| {
|
|
||||||
Arc::new(Framebuffer::start(render_pass.clone())
|
|
||||||
.add(image.clone()).unwrap()
|
|
||||||
.build().unwrap())
|
|
||||||
}).collect::<Vec<_>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
|
|
||||||
None) {
|
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(AcquireError::OutOfDate) => {
|
Err(AcquireError::OutOfDate) => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
@ -293,8 +274,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||||
.begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false,
|
.begin_render_pass(framebuffers[image_num].clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()])
|
||||||
vec![[0.0, 0.0, 0.0, 1.0].into()])
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.draw(pipeline.clone(),
|
.draw(pipeline.clone(),
|
||||||
&dynamic_state,
|
&dynamic_state,
|
||||||
@ -327,9 +307,33 @@ fn main() {
|
|||||||
events_loop.poll_events(|ev| {
|
events_loop.poll_events(|ev| {
|
||||||
match ev {
|
match ev {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if done { return }
|
if done { return }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn window_size_dependent_setup(
|
||||||
|
images: &[Arc<SwapchainImage<Window>>],
|
||||||
|
render_pass: Arc<RenderPassAbstract + Send + Sync>,
|
||||||
|
dynamic_state: &mut DynamicState
|
||||||
|
) -> Vec<Arc<FramebufferAbstract + Send + Sync>> {
|
||||||
|
let dimensions = images[0].dimensions();
|
||||||
|
|
||||||
|
let viewport = Viewport {
|
||||||
|
origin: [0.0, 0.0],
|
||||||
|
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||||
|
depth_range: 0.0 .. 1.0,
|
||||||
|
};
|
||||||
|
dynamic_state.viewports = Some(vec!(viewport));
|
||||||
|
|
||||||
|
images.iter().map(|image| {
|
||||||
|
Arc::new(
|
||||||
|
Framebuffer::start(render_pass.clone())
|
||||||
|
.add(image.clone()).unwrap()
|
||||||
|
.build().unwrap()
|
||||||
|
) as Arc<FramebufferAbstract + Send + Sync>
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
@ -32,27 +32,24 @@ extern crate vulkano_win;
|
|||||||
|
|
||||||
use vulkano_win::VkSurfaceBuild;
|
use vulkano_win::VkSurfaceBuild;
|
||||||
|
|
||||||
use vulkano::buffer::BufferUsage;
|
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||||
use vulkano::buffer::CpuAccessibleBuffer;
|
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
|
||||||
use vulkano::command_buffer::AutoCommandBufferBuilder;
|
|
||||||
use vulkano::command_buffer::DynamicState;
|
|
||||||
use vulkano::device::Device;
|
use vulkano::device::Device;
|
||||||
use vulkano::framebuffer::Framebuffer;
|
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
||||||
use vulkano::framebuffer::Subpass;
|
use vulkano::image::SwapchainImage;
|
||||||
use vulkano::instance::Instance;
|
use vulkano::instance::Instance;
|
||||||
|
use vulkano::instance::PhysicalDevice;
|
||||||
use vulkano::pipeline::GraphicsPipeline;
|
use vulkano::pipeline::GraphicsPipeline;
|
||||||
use vulkano::pipeline::viewport::Viewport;
|
use vulkano::pipeline::viewport::Viewport;
|
||||||
|
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError};
|
||||||
use vulkano::swapchain;
|
use vulkano::swapchain;
|
||||||
use vulkano::swapchain::PresentMode;
|
|
||||||
use vulkano::swapchain::SurfaceTransform;
|
|
||||||
use vulkano::swapchain::Swapchain;
|
|
||||||
use vulkano::swapchain::AcquireError;
|
|
||||||
use vulkano::swapchain::SwapchainCreationError;
|
|
||||||
use vulkano::sync::now;
|
|
||||||
use vulkano::sync::GpuFuture;
|
use vulkano::sync::GpuFuture;
|
||||||
|
use vulkano::sync::now;
|
||||||
|
|
||||||
use vulkano_shaders::vulkano_shader;
|
use vulkano_shaders::vulkano_shader;
|
||||||
|
|
||||||
|
use winit::Window;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// TODO: Move this back to the middle of the example, it makes for a more coherent sequential explanation (check git history)
|
// TODO: Move this back to the middle of the example, it makes for a more coherent sequential explanation (check git history)
|
||||||
@ -117,8 +114,7 @@ fn main() {
|
|||||||
//
|
//
|
||||||
// For the sake of the example we are just going to use the first device, which should work
|
// For the sake of the example we are just going to use the first device, which should work
|
||||||
// most of the time.
|
// most of the time.
|
||||||
let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
|
let physical = PhysicalDevice::enumerate(&instance).next().expect("no device available");
|
||||||
.next().expect("no device available");
|
|
||||||
// Some little debug infos.
|
// Some little debug infos.
|
||||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||||
|
|
||||||
@ -135,6 +131,7 @@ fn main() {
|
|||||||
// window and a cross-platform Vulkan surface that represents the surface of the window.
|
// window and a cross-platform Vulkan surface that represents the surface of the window.
|
||||||
let mut events_loop = winit::EventsLoop::new();
|
let mut events_loop = winit::EventsLoop::new();
|
||||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||||
|
let window = surface.window();
|
||||||
|
|
||||||
// The next step is to choose which GPU queue will execute our draw commands.
|
// The next step is to choose which GPU queue will execute our draw commands.
|
||||||
//
|
//
|
||||||
@ -185,21 +182,25 @@ fn main() {
|
|||||||
// iterator and throw it away.
|
// iterator and throw it away.
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
// The dimensions of the surface.
|
// The dimensions of the window, only used to initially setup the swapchain.
|
||||||
// This variable needs to be mutable since the viewport can change size.
|
let initial_dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
let mut dimensions;
|
// convert to physical pixels
|
||||||
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
// The window no longer exists so exit the application.
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// Before we can draw on the surface, we have to create what is called a swapchain. Creating
|
// Before we can draw on the surface, we have to create what is called a swapchain. Creating
|
||||||
// a swapchain allocates the color buffers that will contain the image that will ultimately
|
// a swapchain allocates the color buffers that will contain the image that will ultimately
|
||||||
// be visible on the screen. These images are returned alongside with the swapchain.
|
// be visible on the screen. These images are returned alongside with the swapchain.
|
||||||
let (mut swapchain, mut images) = {
|
let (mut swapchain, images) = {
|
||||||
// Querying the capabilities of the surface. When we create the swapchain we can only
|
// Querying the capabilities of the surface. When we create the swapchain we can only
|
||||||
// pass values that are allowed by the capabilities.
|
// pass values that are allowed by the capabilities.
|
||||||
let caps = surface.capabilities(physical)
|
let caps = surface.capabilities(physical)
|
||||||
.expect("failed to get surface capabilities");
|
.expect("failed to get surface capabilities");
|
||||||
|
|
||||||
dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
|
||||||
|
|
||||||
// We choose the dimensions of the swapchain to match the current extent of the surface.
|
// We choose the dimensions of the swapchain to match the current extent of the surface.
|
||||||
// If `caps.current_extent` is `None`, this means that the window size will be determined
|
// If `caps.current_extent` is `None`, this means that the window size will be determined
|
||||||
// by the dimensions of the swapchain, in which case we just use the width and height defined above.
|
// by the dimensions of the swapchain, in which case we just use the width and height defined above.
|
||||||
@ -213,7 +214,7 @@ fn main() {
|
|||||||
|
|
||||||
// Please take a look at the docs for the meaning of the parameters we didn't mention.
|
// Please take a look at the docs for the meaning of the parameters we didn't mention.
|
||||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||||
dimensions, 1, caps.supported_usage_flags, &queue,
|
initial_dimensions, 1, caps.supported_usage_flags, &queue,
|
||||||
SurfaceTransform::Identity, alpha, PresentMode::Fifo, true,
|
SurfaceTransform::Identity, alpha, PresentMode::Fifo, true,
|
||||||
None).expect("failed to create swapchain")
|
None).expect("failed to create swapchain")
|
||||||
};
|
};
|
||||||
@ -293,12 +294,16 @@ fn main() {
|
|||||||
.build(device.clone())
|
.build(device.clone())
|
||||||
.unwrap());
|
.unwrap());
|
||||||
|
|
||||||
|
// Dynamic viewports allow us to recreate just the viewport when the window is resized
|
||||||
|
// Otherwise we would have to recreate the whole pipeline.
|
||||||
|
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
|
||||||
|
|
||||||
// The render pass we created above only describes the layout of our framebuffers. Before we
|
// The render pass we created above only describes the layout of our framebuffers. Before we
|
||||||
// can draw we also need to create the actual framebuffers.
|
// can draw we also need to create the actual framebuffers.
|
||||||
//
|
//
|
||||||
// Since we need to draw to multiple images, we are going to create a different framebuffer for
|
// Since we need to draw to multiple images, we are going to create a different framebuffer for
|
||||||
// each image.
|
// each image.
|
||||||
let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
|
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||||
|
|
||||||
// Initialization is finally finished!
|
// Initialization is finally finished!
|
||||||
|
|
||||||
@ -321,16 +326,6 @@ fn main() {
|
|||||||
// that, we store the submission of the previous frame here.
|
// that, we store the submission of the previous frame here.
|
||||||
let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
|
let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
|
||||||
|
|
||||||
let mut dynamic_state = DynamicState {
|
|
||||||
line_width: None,
|
|
||||||
viewports: Some(vec![Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]),
|
|
||||||
scissors: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// It is important to call this function from time to time, otherwise resources will keep
|
// It is important to call this function from time to time, otherwise resources will keep
|
||||||
// accumulating and you will eventually reach an out of memory error.
|
// accumulating and you will eventually reach an out of memory error.
|
||||||
@ -338,45 +333,31 @@ fn main() {
|
|||||||
// already processed, and frees the resources that are no longer needed.
|
// already processed, and frees the resources that are no longer needed.
|
||||||
previous_frame_end.cleanup_finished();
|
previous_frame_end.cleanup_finished();
|
||||||
|
|
||||||
// If the swapchain needs to be recreated, recreate it
|
// Whenever the window resizes we need to recreate everything dependent on the window size.
|
||||||
|
// In this example that includes the swapchain, the framebuffers and the dynamic state viewport.
|
||||||
if recreate_swapchain {
|
if recreate_swapchain {
|
||||||
// Get the new dimensions for the viewport/framebuffers.
|
// Get the new dimensions for the viewport/framebuffers.
|
||||||
dimensions = surface.capabilities(physical)
|
let dimensions = if let Some(dimensions) = window.get_inner_size() {
|
||||||
.expect("failed to get surface capabilities")
|
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
||||||
.current_extent.unwrap();
|
[dimensions.0, dimensions.1]
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
// This error tends to happen when the user is manually resizing the window.
|
// This error tends to happen when the user is manually resizing the window.
|
||||||
// Simply restarting the loop is the easiest way to fix this issue.
|
// Simply restarting the loop is the easiest way to fix this issue.
|
||||||
Err(SwapchainCreationError::UnsupportedDimensions) => {
|
Err(SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||||
continue;
|
|
||||||
},
|
|
||||||
Err(err) => panic!("{:?}", err)
|
Err(err) => panic!("{:?}", err)
|
||||||
};
|
};
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
swapchain = new_swapchain;
|
||||||
images = new_images;
|
|
||||||
|
|
||||||
framebuffers = None;
|
|
||||||
|
|
||||||
dynamic_state.viewports = Some(vec![Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
|
||||||
depth_range: 0.0 .. 1.0,
|
|
||||||
}]);
|
|
||||||
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Because framebuffers contains an Arc on the old swapchain, we need to
|
// Because framebuffers contains an Arc on the old swapchain, we need to
|
||||||
// recreate framebuffers as well.
|
// recreate framebuffers as well.
|
||||||
if framebuffers.is_none() {
|
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||||
framebuffers = Some(images.iter().map(|image| {
|
|
||||||
Arc::new(Framebuffer::start(render_pass.clone())
|
recreate_swapchain = false;
|
||||||
.add(image.clone()).unwrap()
|
|
||||||
.build().unwrap())
|
|
||||||
}).collect::<Vec<_>>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before we can draw on the output, we have to *acquire* an image from the swapchain. If
|
// Before we can draw on the output, we have to *acquire* an image from the swapchain. If
|
||||||
@ -386,8 +367,7 @@ fn main() {
|
|||||||
//
|
//
|
||||||
// This function can block if no image is available. The parameter is an optional timeout
|
// This function can block if no image is available. The parameter is an optional timeout
|
||||||
// after which the function call will return an error.
|
// after which the function call will return an error.
|
||||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
|
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||||
None) {
|
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(AcquireError::OutOfDate) => {
|
Err(AcquireError::OutOfDate) => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
@ -413,7 +393,7 @@ fn main() {
|
|||||||
// The third parameter builds the list of values to clear the attachments with. The API
|
// The third parameter builds the list of values to clear the attachments with. The API
|
||||||
// is similar to the list of attachments when building the framebuffers, except that
|
// is similar to the list of attachments when building the framebuffers, except that
|
||||||
// only the attachments that use `load: Clear` appear in the list.
|
// only the attachments that use `load: Clear` appear in the list.
|
||||||
.begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false,
|
.begin_render_pass(framebuffers[image_num].clone(), false,
|
||||||
vec![[0.0, 0.0, 1.0, 1.0].into()])
|
vec![[0.0, 0.0, 1.0, 1.0].into()])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
||||||
@ -475,9 +455,34 @@ fn main() {
|
|||||||
events_loop.poll_events(|ev| {
|
events_loop.poll_events(|ev| {
|
||||||
match ev {
|
match ev {
|
||||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
|
||||||
|
winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if done { return; }
|
if done { return; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method is called once during initialization then again whenever the window is resized
|
||||||
|
fn window_size_dependent_setup(
|
||||||
|
images: &[Arc<SwapchainImage<Window>>],
|
||||||
|
render_pass: Arc<RenderPassAbstract + Send + Sync>,
|
||||||
|
dynamic_state: &mut DynamicState
|
||||||
|
) -> Vec<Arc<FramebufferAbstract + Send + Sync>> {
|
||||||
|
let dimensions = images[0].dimensions();
|
||||||
|
|
||||||
|
let viewport = Viewport {
|
||||||
|
origin: [0.0, 0.0],
|
||||||
|
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||||
|
depth_range: 0.0 .. 1.0,
|
||||||
|
};
|
||||||
|
dynamic_state.viewports = Some(vec!(viewport));
|
||||||
|
|
||||||
|
images.iter().map(|image| {
|
||||||
|
Arc::new(
|
||||||
|
Framebuffer::start(render_pass.clone())
|
||||||
|
.add(image.clone()).unwrap()
|
||||||
|
.build().unwrap()
|
||||||
|
) as Arc<FramebufferAbstract + Send + Sync>
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user