mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-24 15:55:07 +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 surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q| {
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -86,7 +87,12 @@ fn main() {
|
||||
let (mut swapchain, mut images) = {
|
||||
let caps = surface.capabilities(physical)
|
||||
.expect("failed to get surface capabilities");
|
||||
dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
||||
let 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 format = caps.supported_formats[0].0;
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||
@ -108,9 +114,12 @@ fn main() {
|
||||
previous_frame_end.cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
dimensions = surface.capabilities(physical)
|
||||
.expect("failed to get surface capabilities")
|
||||
.current_extent.unwrap();
|
||||
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 (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
@ -125,8 +134,7 @@ fn main() {
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
|
||||
None) {
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
@ -179,6 +187,7 @@ fn main() {
|
||||
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,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
|
@ -19,6 +19,12 @@ extern crate vulkano_win;
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
use vulkano::sync::GpuFuture;
|
||||
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;
|
||||
|
||||
@ -35,8 +41,7 @@ fn main() {
|
||||
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
|
||||
let mut dimensions;
|
||||
let window = surface.window();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q| q.supports_graphics() &&
|
||||
surface.is_supported(q).unwrap_or(false))
|
||||
@ -51,10 +56,17 @@ fn main() {
|
||||
.expect("failed to create device");
|
||||
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");
|
||||
|
||||
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 alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
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 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(),
|
||||
attachments: {
|
||||
color: {
|
||||
@ -127,7 +139,7 @@ fn main() {
|
||||
.viewports_dynamic_scissors_irrelevant(1)
|
||||
.fragment_shader(fs.main_entry_point(), ())
|
||||
.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())
|
||||
.unwrap());
|
||||
|
||||
@ -136,74 +148,48 @@ fn main() {
|
||||
.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 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 {
|
||||
previous_frame_end.cleanup_finished();
|
||||
if recreate_swapchain {
|
||||
|
||||
dimensions = surface.capabilities(physical)
|
||||
.expect("failed to get surface capabilities")
|
||||
.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 (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => {
|
||||
continue;
|
||||
},
|
||||
Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
images = new_images;
|
||||
|
||||
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,
|
||||
}]);
|
||||
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||
|
||||
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()
|
||||
.build().unwrap())
|
||||
}).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
let (image_num, future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(),
|
||||
None) {
|
||||
let (image_num, future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(vulkano::swapchain::AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
continue;
|
||||
},
|
||||
}
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
let cb = vulkano::command_buffer::AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
|
||||
.unwrap()
|
||||
.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()
|
||||
.draw(pipeline.clone(),
|
||||
&dynamic_state,
|
||||
@ -235,6 +221,7 @@ fn main() {
|
||||
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,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
@ -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!{
|
||||
mod_name: vs,
|
||||
ty: "vertex",
|
||||
|
@ -35,20 +35,21 @@ use vulkano::descriptor::pipeline_layout::PipelineLayoutDescPcRange;
|
||||
use vulkano::device::Device;
|
||||
use vulkano::device::DeviceExtensions;
|
||||
use vulkano::format;
|
||||
use vulkano::framebuffer::Framebuffer;
|
||||
use vulkano::framebuffer::Subpass;
|
||||
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
||||
use vulkano::image::SwapchainImage;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::shader::GraphicsShaderType;
|
||||
use vulkano::pipeline::shader::ShaderInterfaceDef;
|
||||
use vulkano::pipeline::shader::ShaderInterfaceDefEntry;
|
||||
use vulkano::pipeline::shader::ShaderModule;
|
||||
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderInterfaceDef, ShaderInterfaceDefEntry, ShaderModule};
|
||||
use vulkano::pipeline::vertex::SingleBufferDefinition;
|
||||
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;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::Window;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
@ -73,12 +74,9 @@ fn main() {
|
||||
.next()
|
||||
.expect("no graphics device");
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
let surface = winit::WindowBuilder::new()
|
||||
.with_decorations(false)
|
||||
.with_title("particle storm")
|
||||
.build_vk_surface(&events_loop, instance.clone())
|
||||
.unwrap();
|
||||
let (graphics_device, mut queues) = {
|
||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
let (device, mut queues) = {
|
||||
let graphical_queue_family = physical
|
||||
.queue_families()
|
||||
.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 (swapchain, images) = {
|
||||
let (mut swapchain, images) = {
|
||||
let caps = surface
|
||||
.capabilities(graphics_device.physical_device())
|
||||
.capabilities(device.physical_device())
|
||||
.expect("failure to get surface capabilities");
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
let dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
||||
let usage = caps.supported_usage_flags;
|
||||
let present = caps.present_modes.iter().next().unwrap();
|
||||
|
||||
Swapchain::new(
|
||||
graphics_device.clone(),
|
||||
device.clone(),
|
||||
surface.clone(),
|
||||
caps.min_image_count,
|
||||
format,
|
||||
@ -114,17 +112,17 @@ fn main() {
|
||||
1,
|
||||
usage,
|
||||
&graphics_queue,
|
||||
vk::swapchain::SurfaceTransform::Identity,
|
||||
vk::swapchain::CompositeAlpha::Opaque,
|
||||
present,
|
||||
SurfaceTransform::Identity,
|
||||
alpha,
|
||||
PresentMode::Fifo,
|
||||
true,
|
||||
None,
|
||||
).expect("failed to create swapchain")
|
||||
};
|
||||
|
||||
let renderpass = Arc::new(
|
||||
let render_pass = Arc::new(
|
||||
single_pass_renderpass!(
|
||||
graphics_device.clone(), attachments: {
|
||||
device.clone(), attachments: {
|
||||
color: {
|
||||
load: Clear,
|
||||
store: Store,
|
||||
@ -146,7 +144,7 @@ fn main() {
|
||||
f.read_to_end(&mut v).unwrap();
|
||||
// Create a ShaderModule on a device the same Shader::load does it.
|
||||
// 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 = {
|
||||
@ -154,7 +152,7 @@ fn main() {
|
||||
.expect("Can't find file src/bin/runtime-shader/frag.spv");
|
||||
let mut v = vec![];
|
||||
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
|
||||
@ -387,25 +385,20 @@ fn main() {
|
||||
.vertex_input(SingleBufferDefinition::<Vertex>::new())
|
||||
.vertex_shader(vert_main, ())
|
||||
.triangle_list()
|
||||
.viewports([
|
||||
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())
|
||||
.viewports_dynamic_scissors_irrelevant(1)
|
||||
.fragment_shader(frag_main, ())
|
||||
.cull_mode_front()
|
||||
.front_face_counter_clockwise()
|
||||
.depth_stencil_disabled()
|
||||
.render_pass(Subpass::from(renderpass.clone(), 0).unwrap())
|
||||
.build(graphics_device.clone())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.build(device.clone())
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
graphics_device.clone(),
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
[
|
||||
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
|
||||
// descriptor set builder to return Err!
|
||||
|
||||
let framebuffers: Vec<_> = images
|
||||
.iter()
|
||||
.map(|image| Arc::new(
|
||||
Framebuffer::start(renderpass.clone())
|
||||
.add(image.clone()).unwrap()
|
||||
.build().unwrap(),
|
||||
))
|
||||
.collect();
|
||||
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 previous_frame_end = Box::new(sync::now(device.clone())) as Box<GpuFuture>;
|
||||
|
||||
loop {
|
||||
events_loop.poll_events(|_| ());
|
||||
previous_frame_end.cleanup_finished();
|
||||
|
||||
let (image_num, acquire_future) =
|
||||
vk::swapchain::acquire_next_image(
|
||||
swapchain.clone(),
|
||||
None,
|
||||
).expect("failed to acquire swapchain in time");
|
||||
if recreate_swapchain {
|
||||
// Get the new dimensions for the viewport/framebuffers.
|
||||
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 command_buffer = AutoCommandBufferBuilder
|
||||
::new(
|
||||
graphics_device.clone(),
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
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(),
|
||||
).unwrap()
|
||||
.begin_render_pass(
|
||||
@ -448,7 +459,7 @@ fn main() {
|
||||
).unwrap()
|
||||
.draw(
|
||||
graphics_pipeline.clone(),
|
||||
&DynamicState::none(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
@ -456,10 +467,57 @@ fn main() {
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
acquire_future
|
||||
let future = previous_frame_end.join(acquire_future)
|
||||
.then_execute(graphics_queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(graphics_queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush().unwrap()
|
||||
.wait(None).unwrap();
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
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;
|
||||
|
||||
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_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::iter;
|
||||
|
||||
fn main() {
|
||||
// The start of this example is exactly the same as `triangle`. You should read the
|
||||
// `triangle` example if you haven't done so yet.
|
||||
|
||||
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)
|
||||
.next().expect("no device available");
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().expect("no device available");
|
||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
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() &&
|
||||
surface.is_supported(q).unwrap_or(false))
|
||||
.expect("couldn't find a graphical queue family");
|
||||
|
||||
let device_ext = vulkano::device::DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
.. vulkano::device::DeviceExtensions::none()
|
||||
// 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 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 (device, mut queues) = vulkano::device::Device::new(physical, physical.supported_features(),
|
||||
&device_ext, [(queue_family, 0.5)].iter().cloned())
|
||||
.expect("failed to create device");
|
||||
let queue_family = physical.queue_families().find(|&q|
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
).expect("couldn't find a graphical queue family");
|
||||
|
||||
let device_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 (mut swapchain, mut images) = {
|
||||
let (mut swapchain, images) = {
|
||||
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 format = caps.supported_formats[0].0;
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
|
||||
vulkano::swapchain::Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1,
|
||||
usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
|
||||
alpha,
|
||||
vulkano::swapchain::PresentMode::Fifo, true, None).expect("failed to create swapchain")
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1,
|
||||
usage, &queue, SurfaceTransform::Identity, alpha, 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
|
||||
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::VERTICES.iter().cloned())
|
||||
.expect("failed to create buffer");
|
||||
let indices = INDICES.iter().cloned();
|
||||
let index_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), indices).unwrap();
|
||||
|
||||
let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
|
||||
::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 uniform_buffer = CpuBufferPool::<vs::ty::Data>::new(device.clone(), BufferUsage::all());
|
||||
|
||||
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 renderpass = Arc::new(
|
||||
let render_pass = Arc::new(
|
||||
single_pass_renderpass!(device.clone(),
|
||||
attachments: {
|
||||
color: {
|
||||
@ -118,86 +129,53 @@ fn main() {
|
||||
).unwrap()
|
||||
);
|
||||
|
||||
let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::start()
|
||||
.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 pipeline, mut framebuffers) = window_size_dependent_setup(device.clone(), &vs, &fs, &images, render_pass.clone());
|
||||
let mut recreate_swapchain = false;
|
||||
|
||||
let mut previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
|
||||
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 {
|
||||
previous_frame.cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
|
||||
dimensions = surface.capabilities(physical)
|
||||
.expect("failed to get surface capabilities")
|
||||
.current_extent.unwrap_or([1024, 768]);
|
||||
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 (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => {
|
||||
continue;
|
||||
},
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
images = new_images;
|
||||
|
||||
depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), dimensions, vulkano::format::D16Unorm).unwrap();
|
||||
|
||||
framebuffers = None;
|
||||
|
||||
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,
|
||||
}]);
|
||||
let (new_pipeline, new_framebuffers) = window_size_dependent_setup(device.clone(), &vs, &fs, &new_images, render_pass.clone());
|
||||
pipeline = new_pipeline;
|
||||
framebuffers = new_framebuffers;
|
||||
|
||||
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 elapsed = rotation_start.elapsed();
|
||||
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 {
|
||||
world : cgmath::Matrix4::from(rotation).into(),
|
||||
view : (view * scale).into(),
|
||||
proj : proj.into(),
|
||||
world: Matrix4::from(rotation).into(),
|
||||
view: (view * scale).into(),
|
||||
proj: proj.into(),
|
||||
};
|
||||
|
||||
uniform_buffer.next(uniform_data).unwrap()
|
||||
@ -208,27 +186,26 @@ fn main() {
|
||||
.build().unwrap()
|
||||
);
|
||||
|
||||
let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(),
|
||||
None) {
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(vulkano::swapchain::AcquireError::OutOfDate) => {
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
continue;
|
||||
},
|
||||
}
|
||||
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(
|
||||
framebuffers.as_ref().unwrap()[image_num].clone(), false,
|
||||
framebuffers[image_num].clone(), false,
|
||||
vec![
|
||||
[0.0, 0.0, 1.0, 1.0].into(),
|
||||
1f32.into()
|
||||
]).unwrap()
|
||||
.draw_indexed(
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
(vertex_buffer.clone(), normals_buffer.clone()),
|
||||
&DynamicState::none(),
|
||||
vec!(vertex_buffer.clone(), normals_buffer.clone()),
|
||||
index_buffer.clone(), set.clone(), ()).unwrap()
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
@ -256,6 +233,7 @@ fn main() {
|
||||
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,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
@ -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!{
|
||||
mod_name: vs,
|
||||
ty: "vertex",
|
||||
|
@ -26,26 +26,22 @@ extern crate vulkano_win;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use vulkano::buffer::BufferUsage;
|
||||
use vulkano::buffer::CpuAccessibleBuffer;
|
||||
use vulkano::command_buffer::AutoCommandBufferBuilder;
|
||||
use vulkano::command_buffer::DynamicState;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
|
||||
use vulkano::device::Device;
|
||||
use vulkano::framebuffer::Framebuffer;
|
||||
use vulkano::framebuffer::Subpass;
|
||||
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
||||
use vulkano::image::SwapchainImage;
|
||||
use vulkano::instance::Instance;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
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::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError};
|
||||
use vulkano::sync::now;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano_shaders::vulkano_shader;
|
||||
|
||||
use winit::Window;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
vulkano_shader!{
|
||||
@ -148,6 +144,7 @@ fn main() {
|
||||
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
|
||||
let queue = physical.queue_families().find(|&q| {
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -163,13 +160,17 @@ fn main() {
|
||||
};
|
||||
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)
|
||||
.expect("failed to get surface capabilities");
|
||||
|
||||
dimensions = caps.current_extent.unwrap_or([1024, 768]);
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
|
||||
@ -234,25 +235,20 @@ fn main() {
|
||||
.build(device.clone())
|
||||
.unwrap());
|
||||
|
||||
let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
|
||||
let mut recreate_swapchain = false;
|
||||
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,
|
||||
};
|
||||
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);
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
if recreate_swapchain {
|
||||
dimensions = surface.capabilities(physical)
|
||||
.expect("failed to get surface capabilities")
|
||||
.current_extent.unwrap();
|
||||
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 (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
@ -263,27 +259,12 @@ fn main() {
|
||||
};
|
||||
|
||||
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,
|
||||
}]);
|
||||
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
if framebuffers.is_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) {
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
@ -293,8 +274,7 @@ fn main() {
|
||||
};
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false,
|
||||
vec![[0.0, 0.0, 0.0, 1.0].into()])
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()])
|
||||
.unwrap()
|
||||
.draw(pipeline.clone(),
|
||||
&dynamic_state,
|
||||
@ -327,9 +307,33 @@ fn main() {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
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::buffer::BufferUsage;
|
||||
use vulkano::buffer::CpuAccessibleBuffer;
|
||||
use vulkano::command_buffer::AutoCommandBufferBuilder;
|
||||
use vulkano::command_buffer::DynamicState;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
|
||||
use vulkano::device::Device;
|
||||
use vulkano::framebuffer::Framebuffer;
|
||||
use vulkano::framebuffer::Subpass;
|
||||
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
||||
use vulkano::image::SwapchainImage;
|
||||
use vulkano::instance::Instance;
|
||||
use vulkano::instance::PhysicalDevice;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError};
|
||||
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::now;
|
||||
|
||||
use vulkano_shaders::vulkano_shader;
|
||||
|
||||
use winit::Window;
|
||||
|
||||
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)
|
||||
@ -117,8 +114,7 @@ fn main() {
|
||||
//
|
||||
// For the sake of the example we are just going to use the first device, which should work
|
||||
// most of the time.
|
||||
let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
|
||||
.next().expect("no device available");
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().expect("no device available");
|
||||
// Some little debug infos.
|
||||
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.
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
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.
|
||||
//
|
||||
@ -185,21 +182,25 @@ fn main() {
|
||||
// iterator and throw it away.
|
||||
let queue = queues.next().unwrap();
|
||||
|
||||
// The dimensions of the surface.
|
||||
// This variable needs to be mutable since the viewport can change size.
|
||||
let mut dimensions;
|
||||
// The dimensions of the window, only used to initially setup the swapchain.
|
||||
let initial_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;
|
||||
};
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// pass values that are allowed by the capabilities.
|
||||
let caps = surface.capabilities(physical)
|
||||
.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.
|
||||
// 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.
|
||||
@ -213,7 +214,7 @@ fn main() {
|
||||
|
||||
// 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,
|
||||
dimensions, 1, caps.supported_usage_flags, &queue,
|
||||
initial_dimensions, 1, caps.supported_usage_flags, &queue,
|
||||
SurfaceTransform::Identity, alpha, PresentMode::Fifo, true,
|
||||
None).expect("failed to create swapchain")
|
||||
};
|
||||
@ -293,12 +294,16 @@ fn main() {
|
||||
.build(device.clone())
|
||||
.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
|
||||
// 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
|
||||
// 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!
|
||||
|
||||
@ -321,16 +326,6 @@ fn main() {
|
||||
// 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 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 {
|
||||
// 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.
|
||||
@ -338,47 +333,33 @@ fn main() {
|
||||
// already processed, and frees the resources that are no longer needed.
|
||||
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 {
|
||||
// Get the new dimensions for the viewport/framebuffers.
|
||||
dimensions = surface.capabilities(physical)
|
||||
.expect("failed to get surface capabilities")
|
||||
.current_extent.unwrap();
|
||||
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 (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
// 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.
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => {
|
||||
continue;
|
||||
},
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
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,
|
||||
}]);
|
||||
// Because framebuffers contains an Arc on the old swapchain, we need to
|
||||
// recreate framebuffers as well.
|
||||
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
// Because framebuffers contains an Arc on the old swapchain, we need to
|
||||
// recreate framebuffers as well.
|
||||
if framebuffers.is_none() {
|
||||
framebuffers = Some(images.iter().map(|image| {
|
||||
Arc::new(Framebuffer::start(render_pass.clone())
|
||||
.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
|
||||
// no image is available (which happens if you submit draw commands too quickly), then the
|
||||
// function will block.
|
||||
@ -386,8 +367,7 @@ fn main() {
|
||||
//
|
||||
// This function can block if no image is available. The parameter is an optional timeout
|
||||
// after which the function call will return an error.
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
|
||||
None) {
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
@ -413,7 +393,7 @@ fn main() {
|
||||
// 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
|
||||
// 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()])
|
||||
.unwrap()
|
||||
|
||||
@ -475,9 +455,34 @@ fn main() {
|
||||
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<_>>()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user