mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2025-02-16 17:12:29 +00:00
upgrade winit to 0.20 and cocoa to 0.20
This commit is contained in:
parent
6ca6d84a87
commit
b95c058f9a
@ -8,6 +8,8 @@
|
||||
- Allow `DebugCallback` to be sent between threads
|
||||
- Decouple descriptor sets from pipeline
|
||||
- Pipeline barriers are now correctly inserted when a resource is used more than two times.
|
||||
- Update Winit to 0.20.0
|
||||
- Update MacOS dependency cocoa to 0.20
|
||||
|
||||
# Version 0.16.0 (2019-11-01)
|
||||
|
||||
@ -19,7 +21,6 @@
|
||||
- Shader includes now work on Windows.
|
||||
- **Breaking Change** Shader include directories passed to the `shader!` macro are now relative to the crates `Cargo.toml`
|
||||
- Add support for `VK_KHR_16bit_storage` and `VK_KHR_storage_buffer_storage_class` device extensions.
|
||||
- Update Winit to 0.20.0
|
||||
- Update dependencies: lazy_static, half, syn, quote & proc-macro2
|
||||
- Swapchain can now be recreated with dimensions of corresponding surface using `recreate()`.
|
||||
- Added `raw_loaded_extensions()` to `Instance` to allow querying of all extensions, not just known ones.
|
||||
|
@ -12,7 +12,7 @@ vulkano = { path = "../vulkano" }
|
||||
vulkano-shaders = { path = "../vulkano-shaders" }
|
||||
# The Vulkan library doesn't provide any functionality to create and handle windows, as
|
||||
# this would be out of scope. In order to open a window, we are going to use the `winit` crate.
|
||||
winit = "0.19"
|
||||
winit = "0.20"
|
||||
# The `vulkano_win` crate is the link between `vulkano` and `winit`. Vulkano doesn't know about winit,
|
||||
# and winit doesn't know about vulkano, so import a crate that will provide a link between the two.
|
||||
vulkano-win = { path = "../vulkano-win" }
|
||||
|
@ -73,18 +73,19 @@ fn main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "compute",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
data.data[idx] *= 12;
|
||||
}"
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
data.data[idx] *= 12;
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
let shader = cs::Shader::load(device.clone()).unwrap();
|
||||
|
@ -34,8 +34,9 @@ use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::{EventsLoop, WindowBuilder, Event, WindowEvent};
|
||||
use winit::window::WindowBuilder;
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use cgmath::Matrix4;
|
||||
use cgmath::SquareMatrix;
|
||||
@ -49,14 +50,13 @@ use crate::triangle_draw_system::*;
|
||||
|
||||
fn main() {
|
||||
// Basic initialization. See the triangle example if you want more details about this.
|
||||
let extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &extensions, None).unwrap();
|
||||
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
|
||||
let mut events_loop = EventsLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q| {
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -73,16 +73,10 @@ fn main() {
|
||||
let usage = caps.supported_usage_flags;
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
|
||||
let initial_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 dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||
initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
PresentMode::Fifo, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||
};
|
||||
|
||||
@ -92,91 +86,82 @@ fn main() {
|
||||
let triangle_draw_system = TriangleDrawSystem::new(queue.clone(), frame_system.deferred_subpass());
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
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(SwapchainCreationError::UnsupportedDimensions) => {
|
||||
continue;
|
||||
}
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
images = new_images;
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
recreate_swapchain = true;
|
||||
continue;
|
||||
}
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
let future = previous_frame_end.join(acquire_future);
|
||||
let mut frame = frame_system.frame(future, images[image_num].clone(), Matrix4::identity());
|
||||
let mut after_future = None;
|
||||
while let Some(pass) = frame.next_pass() {
|
||||
match pass {
|
||||
Pass::Deferred(mut draw_pass) => {
|
||||
let cb = triangle_draw_system.draw(draw_pass.viewport_dimensions());
|
||||
draw_pass.execute(cb);
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
images = new_images;
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
Pass::Lighting(mut lighting) => {
|
||||
lighting.ambient_light([0.1, 0.1, 0.1]);
|
||||
lighting.directional_light(Vector3::new(0.2, -0.1, -0.7), [0.6, 0.6, 0.6]);
|
||||
lighting.point_light(Vector3::new(0.5, -0.5, -0.1), [1.0, 0.0, 0.0]);
|
||||
lighting.point_light(Vector3::new(-0.9, 0.2, -0.15), [0.0, 1.0, 0.0]);
|
||||
lighting.point_light(Vector3::new(0.0, 0.5, -0.05), [0.0, 0.0, 1.0]);
|
||||
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
let future = previous_frame_end.take().unwrap().join(acquire_future);
|
||||
let mut frame = frame_system.frame(future, images[image_num].clone(), Matrix4::identity());
|
||||
let mut after_future = None;
|
||||
while let Some(pass) = frame.next_pass() {
|
||||
match pass {
|
||||
Pass::Deferred(mut draw_pass) => {
|
||||
let cb = triangle_draw_system.draw(draw_pass.viewport_dimensions());
|
||||
draw_pass.execute(cb);
|
||||
}
|
||||
Pass::Lighting(mut lighting) => {
|
||||
lighting.ambient_light([0.1, 0.1, 0.1]);
|
||||
lighting.directional_light(Vector3::new(0.2, -0.1, -0.7), [0.6, 0.6, 0.6]);
|
||||
lighting.point_light(Vector3::new(0.5, -0.5, -0.1), [1.0, 0.0, 0.0]);
|
||||
lighting.point_light(Vector3::new(-0.9, 0.2, -0.15), [0.0, 1.0, 0.0]);
|
||||
lighting.point_light(Vector3::new(0.0, 0.5, -0.05), [0.0, 0.0, 1.0]);
|
||||
}
|
||||
Pass::Finished(af) => {
|
||||
after_future = Some(af);
|
||||
}
|
||||
}
|
||||
}
|
||||
Pass::Finished(af) => {
|
||||
after_future = Some(af);
|
||||
|
||||
let future = after_future.unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
},
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
let future = after_future.unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame_end = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
}
|
||||
|
||||
let mut done = false;
|
||||
events_loop.poll_events(|ev| {
|
||||
match ev {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
if done { return; }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -24,8 +24,9 @@ use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent};
|
||||
use winit::window::{WindowBuilder, Window};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use png;
|
||||
use std::io::Cursor;
|
||||
@ -36,15 +37,13 @@ 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 = Instance::new(None, &extensions, None).unwrap();
|
||||
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||
|
||||
let mut events_loop = EventsLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q|
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -61,18 +60,10 @@ fn main() {
|
||||
let usage = caps.supported_usage_flags;
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
|
||||
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;
|
||||
};
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||
initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
PresentMode::Fifo, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||
};
|
||||
|
||||
@ -155,78 +146,72 @@ fn main() {
|
||||
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<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(tex_future) as Box<dyn GpuFuture>);
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
if recreate_swapchain {
|
||||
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(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, future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
recreate_swapchain = true;
|
||||
continue;
|
||||
}
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
let cb = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
|
||||
.unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap()
|
||||
.draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), set.clone(), ()).unwrap()
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
let future = previous_frame_end.join(future)
|
||||
.then_execute(queue.clone(), cb).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
swapchain = new_swapchain;
|
||||
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame_end = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
let cb = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
|
||||
.unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap()
|
||||
.draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), set.clone(), ()).unwrap()
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.take().unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), cb).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
},
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
let mut done = false;
|
||||
events_loop.poll_events(|ev| {
|
||||
match ev {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
if done { return; }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This method is called once during initialization, then again whenever the window is resized
|
||||
|
@ -46,8 +46,9 @@ use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent};
|
||||
use winit::window::{WindowBuilder, Window};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::iter;
|
||||
@ -61,18 +62,13 @@ struct Vertex {
|
||||
impl_vertex!(Vertex, position);
|
||||
|
||||
fn main() {
|
||||
let instance = {
|
||||
let extensions = vulkano_win::required_extensions();
|
||||
Instance::new(None, &extensions, None).unwrap()
|
||||
};
|
||||
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||
|
||||
|
||||
let mut events_loop = EventsLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q| {
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -89,15 +85,10 @@ fn main() {
|
||||
let usage = caps.supported_usage_flags;
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
let initial_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 dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||
initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
PresentMode::Fifo, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||
};
|
||||
|
||||
@ -105,14 +96,15 @@ fn main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "vertex",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
// The triangle vertex positions.
|
||||
layout(location = 0) in vec2 position;
|
||||
// The triangle vertex positions.
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}"
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,14 +112,14 @@ void main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,38 +129,38 @@ void main() {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "compute",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(local_size_x = 16, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(local_size_x = 16, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) buffer Output {
|
||||
vec2 pos[];
|
||||
} triangles;
|
||||
layout(set = 0, binding = 0) buffer Output {
|
||||
vec2 pos[];
|
||||
} triangles;
|
||||
|
||||
layout(set = 0, binding = 1) buffer IndirectDrawArgs {
|
||||
uint vertices;
|
||||
uint unused0;
|
||||
uint unused1;
|
||||
uint unused2;
|
||||
};
|
||||
layout(set = 0, binding = 1) buffer IndirectDrawArgs {
|
||||
uint vertices;
|
||||
uint unused0;
|
||||
uint unused1;
|
||||
uint unused2;
|
||||
};
|
||||
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
|
||||
// each thread of compute shader is going to increment the counter, so we need to use atomic
|
||||
// operations for safety. The previous value of the counter is returned so that gives us
|
||||
// the offset into the vertex buffer this thread can write it's vertices into.
|
||||
uint offset = atomicAdd(vertices, 6);
|
||||
// each thread of compute shader is going to increment the counter, so we need to use atomic
|
||||
// operations for safety. The previous value of the counter is returned so that gives us
|
||||
// the offset into the vertex buffer this thread can write it's vertices into.
|
||||
uint offset = atomicAdd(vertices, 6);
|
||||
|
||||
vec2 center = vec2(-0.8, -0.8) + idx * vec2(0.1, 0.1);
|
||||
triangles.pos[offset + 0] = center + vec2(0.0, 0.0375);
|
||||
triangles.pos[offset + 1] = center + vec2(0.025, -0.01725);
|
||||
triangles.pos[offset + 2] = center + vec2(-0.025, -0.01725);
|
||||
triangles.pos[offset + 3] = center + vec2(0.0, -0.0375);
|
||||
triangles.pos[offset + 4] = center + vec2(0.025, 0.01725);
|
||||
triangles.pos[offset + 5] = center + vec2(-0.025, 0.01725);
|
||||
}
|
||||
"
|
||||
vec2 center = vec2(-0.8, -0.8) + idx * vec2(0.1, 0.1);
|
||||
triangles.pos[offset + 0] = center + vec2(0.0, 0.0375);
|
||||
triangles.pos[offset + 1] = center + vec2(0.025, -0.01725);
|
||||
triangles.pos[offset + 2] = center + vec2(-0.025, -0.01725);
|
||||
triangles.pos[offset + 3] = center + vec2(0.0, -0.0375);
|
||||
triangles.pos[offset + 4] = center + vec2(0.025, 0.01725);
|
||||
triangles.pos[offset + 5] = center + vec2(-0.025, 0.01725);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,114 +204,110 @@ void main() {
|
||||
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: 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(sync::now(device.clone())) as Box<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
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(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;
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
|
||||
// Allocate a GPU buffer to hold the arguments for this frames draw call. The compute
|
||||
// shader will only update vertex_count, so set the other parameters correctly here.
|
||||
let indirect_args = indirect_args_pool.chunk(iter::once(
|
||||
DrawIndirectCommand{
|
||||
vertex_count: 0,
|
||||
instance_count: 1,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
})).unwrap();
|
||||
|
||||
// Allocate a GPU buffer to hold this frames vertices. This needs to be large enough to hold
|
||||
// the worst case number of vertices generated by the compute shader
|
||||
let vertices = vertex_pool.chunk((0..(6 * 16)).map(|_| Vertex{ position: [0.0;2] })).unwrap();
|
||||
|
||||
// Pass the two buffers to the compute shader
|
||||
let layout = compute_pipeline.layout().descriptor_set_layout(0).unwrap();
|
||||
let cs_desciptor_set = Arc::new(PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(vertices.clone()).unwrap()
|
||||
.add_buffer(indirect_args.clone()).unwrap()
|
||||
.build().unwrap()
|
||||
);
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
// First in the command buffer we dispatch the compute shader to generate the vertices and fill out the draw
|
||||
// call arguments
|
||||
.dispatch([1,1,1], compute_pipeline.clone(), cs_desciptor_set.clone(), ())
|
||||
.unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values)
|
||||
.unwrap()
|
||||
// The indirect draw call is placed in the command buffer with a reference to the GPU buffer that will
|
||||
// contain the arguments when the draw is executed on the GPU
|
||||
.draw_indirect(
|
||||
render_pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertices.clone(),
|
||||
indirect_args.clone(),
|
||||
(),
|
||||
()
|
||||
)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame_end = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
let mut done = false;
|
||||
events_loop.poll_events(|ev| {
|
||||
match ev {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
if done { return; }
|
||||
}
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
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;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
|
||||
// Allocate a GPU buffer to hold the arguments for this frames draw call. The compute
|
||||
// shader will only update vertex_count, so set the other parameters correctly here.
|
||||
let indirect_args = indirect_args_pool.chunk(iter::once(
|
||||
DrawIndirectCommand{
|
||||
vertex_count: 0,
|
||||
instance_count: 1,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
})).unwrap();
|
||||
|
||||
// Allocate a GPU buffer to hold this frames vertices. This needs to be large enough to hold
|
||||
// the worst case number of vertices generated by the compute shader
|
||||
let vertices = vertex_pool.chunk((0..(6 * 16)).map(|_| Vertex{ position: [0.0;2] })).unwrap();
|
||||
|
||||
// Pass the two buffers to the compute shader
|
||||
let layout = compute_pipeline.layout().descriptor_set_layout(0).unwrap();
|
||||
let cs_desciptor_set = Arc::new(PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(vertices.clone()).unwrap()
|
||||
.add_buffer(indirect_args.clone()).unwrap()
|
||||
.build().unwrap()
|
||||
);
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
// First in the command buffer we dispatch the compute shader to generate the vertices and fill out the draw
|
||||
// call arguments
|
||||
.dispatch([1,1,1], compute_pipeline.clone(), cs_desciptor_set.clone(), ())
|
||||
.unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values)
|
||||
.unwrap()
|
||||
// The indirect draw call is placed in the command buffer with a reference to the GPU buffer that will
|
||||
// contain the arguments when the draw is executed on the GPU
|
||||
.draw_indirect(
|
||||
render_pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertices.clone(),
|
||||
indirect_args.clone(),
|
||||
(),
|
||||
()
|
||||
)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.take().unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
},
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This method is called once during initialization, then again whenever the window is resized
|
||||
|
@ -33,8 +33,9 @@ use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent};
|
||||
use winit::window::{WindowBuilder, Window};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -59,18 +60,14 @@ struct InstanceData {
|
||||
impl_vertex!(InstanceData, position_offset, scale);
|
||||
|
||||
fn main() {
|
||||
let instance = {
|
||||
let extensions = vulkano_win::required_extensions();
|
||||
Instance::new(None, &extensions, None).unwrap()
|
||||
};
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||
|
||||
|
||||
let mut events_loop = EventsLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q| {
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -87,15 +84,10 @@ fn main() {
|
||||
let usage = caps.supported_usage_flags;
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
let initial_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 dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||
initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
PresentMode::Fifo, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||
};
|
||||
|
||||
@ -135,19 +127,20 @@ fn main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "vertex",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
// The triangle vertex positions.
|
||||
layout(location = 0) in vec2 position;
|
||||
// The triangle vertex positions.
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
// The per-instance data.
|
||||
layout(location = 1) in vec2 position_offset;
|
||||
layout(location = 2) in float scale;
|
||||
// The per-instance data.
|
||||
layout(location = 1) in vec2 position_offset;
|
||||
layout(location = 2) in float scale;
|
||||
|
||||
void main() {
|
||||
// Apply the scale and offset for the instance.
|
||||
gl_Position = vec4(position * scale + position_offset, 0.0, 1.0);
|
||||
}"
|
||||
void main() {
|
||||
// Apply the scale and offset for the instance.
|
||||
gl_Position = vec4(position * scale + position_offset, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,14 +148,14 @@ void main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,86 +193,82 @@ void main() {
|
||||
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: 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(sync::now(device.clone())) as Box<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
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(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;
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values)
|
||||
.unwrap()
|
||||
.draw(
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
// We pass both our lists of vertices here.
|
||||
(triangle_vertex_buffer.clone(), instance_data_buffer.clone()),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame_end = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
let mut done = false;
|
||||
events_loop.poll_events(|ev| {
|
||||
match ev {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
if done { return; }
|
||||
}
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
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;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values)
|
||||
.unwrap()
|
||||
.draw(
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
// We pass both our lists of vertices here.
|
||||
(triangle_vertex_buffer.clone(), instance_data_buffer.clone()),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.take().unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
},
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This method is called once during initialization, then again whenever the window is resized
|
||||
|
@ -72,7 +72,7 @@ use vulkano::device::{Device, DeviceExtensions};
|
||||
use vulkano::format::Format;
|
||||
use vulkano::framebuffer::{Framebuffer, Subpass};
|
||||
use vulkano::image::{AttachmentImage, Dimensions, StorageImage};
|
||||
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||
use vulkano::instance::{Instance, PhysicalDevice};
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::sync::GpuFuture;
|
||||
@ -83,7 +83,8 @@ use std::io::BufWriter;
|
||||
|
||||
fn main() {
|
||||
// The usual Vulkan initialization.
|
||||
let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
let queue_family = physical.queue_families().find(|&q| q.supports_graphics()).unwrap();
|
||||
let (device, mut queues) = Device::new(physical, physical.supported_features(),
|
||||
@ -153,27 +154,28 @@ fn main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "vertex",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}"
|
||||
}
|
||||
}
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}"
|
||||
}
|
||||
}
|
||||
|
||||
mod fs {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
mod fs {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}"
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,11 +236,11 @@ void main() {
|
||||
|
||||
let buffer_content = buf.read().unwrap();
|
||||
let path = Path::new("triangle.png");
|
||||
let file = File::create(path).unwrap();
|
||||
let ref mut w = BufWriter::new(file);
|
||||
let mut encoder = png::Encoder::new(w, 1024, 1024); // Width is 2 pixels and height is 1.
|
||||
encoder.set_color(png::ColorType::RGBA);
|
||||
encoder.set_depth(png::BitDepth::Eight);
|
||||
let mut writer = encoder.write_header().unwrap();
|
||||
writer.write_image_data(&buffer_content).unwrap();
|
||||
let file = File::create(path).unwrap();
|
||||
let ref mut w = BufWriter::new(file);
|
||||
let mut encoder = png::Encoder::new(w, 1024, 1024); // Width is 2 pixels and height is 1.
|
||||
encoder.set_color(png::ColorType::RGBA);
|
||||
encoder.set_depth(png::BitDepth::Eight);
|
||||
let mut writer = encoder.write_header().unwrap();
|
||||
writer.write_image_data(&buffer_content).unwrap();
|
||||
}
|
||||
|
@ -34,32 +34,32 @@ fn main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "compute",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(push_constant) uniform PushConstantData {
|
||||
int multiple;
|
||||
float addend;
|
||||
bool enable;
|
||||
} pc;
|
||||
layout(push_constant) uniform PushConstantData {
|
||||
int multiple;
|
||||
float addend;
|
||||
bool enable;
|
||||
} pc;
|
||||
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
if (pc.enable) {
|
||||
data.data[idx] *= pc.multiple;
|
||||
data.data[idx] += uint(pc.addend);
|
||||
}
|
||||
}"
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
if (pc.enable) {
|
||||
data.data[idx] *= pc.multiple;
|
||||
data.data[idx] += uint(pc.addend);
|
||||
}
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
let shader = cs::Shader::load(device.clone()).unwrap();
|
||||
|
||||
let pipeline = Arc::new(ComputePipeline::new(device.clone(), &shader.main_entry_point(), &()).unwrap());
|
||||
|
||||
let data_buffer = {
|
||||
|
@ -39,12 +39,14 @@ use vulkano::pipeline::vertex::SingleBufferDefinition;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError, ColorSpace};
|
||||
use vulkano::swapchain;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
use vulkano::instance::Instance;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::Window;
|
||||
use winit::window::{WindowBuilder, Window};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CStr;
|
||||
@ -61,12 +63,12 @@ pub struct Vertex {
|
||||
vulkano::impl_vertex!(Vertex, position, color);
|
||||
|
||||
fn main() {
|
||||
let instance = vk::instance::Instance::new(None, &vulkano_win::required_extensions(), None).unwrap();
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
let physical = vk::instance::PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
|
||||
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 event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q| {
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -78,20 +80,14 @@ fn main() {
|
||||
};
|
||||
let queue = queues.next().unwrap();
|
||||
|
||||
let initial_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, images) = {
|
||||
let caps = surface.capabilities(physical).unwrap();
|
||||
let usage = caps.supported_usage_flags;
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, initial_dimensions,
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions,
|
||||
1, usage, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||
};
|
||||
|
||||
@ -384,80 +380,71 @@ fn main() {
|
||||
|
||||
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: 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<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
|
||||
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 (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;
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 0.0, 1.0].into());
|
||||
let command_buffer = AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap()
|
||||
.draw(graphics_pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ()).unwrap()
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame_end = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(vulkano::sync::FlushError::OutOfDate) => {
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
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<_>;
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
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; }
|
||||
}
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
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;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
let clear_values = vec!([0.0, 0.0, 0.0, 1.0].into());
|
||||
let command_buffer = AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap()
|
||||
.draw(graphics_pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ()).unwrap()
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.take().unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
},
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This method is called once during initialization, then again whenever the window is resized
|
||||
|
@ -24,41 +24,46 @@ use vulkano::sync;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() {
|
||||
let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
let queue_family = physical.queue_families().find(|&q| q.supports_compute()).unwrap();
|
||||
let (device, mut queues) = Device::new(physical, physical.supported_features(),
|
||||
&DeviceExtensions::none(), [(queue_family, 0.5)].iter().cloned()).unwrap();
|
||||
let queue = queues.next().unwrap();
|
||||
let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
let queue_family = physical.queue_families().find(|&q| q.supports_compute()).unwrap();
|
||||
let device_extensions = DeviceExtensions{
|
||||
khr_storage_buffer_storage_class:true,
|
||||
.. DeviceExtensions::none()
|
||||
};
|
||||
let (device, mut queues) = Device::new(physical, physical.supported_features(),
|
||||
&device_extensions, [(queue_family, 0.5)].iter().cloned()).unwrap();
|
||||
let queue = queues.next().unwrap();
|
||||
|
||||
println!("Device initialized");
|
||||
println!("Device initialized");
|
||||
|
||||
let pipeline = Arc::new({
|
||||
mod cs {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "compute",
|
||||
// We declare what directories to search for when using the `#include <...>`
|
||||
// syntax. Specified directories have descending priorities based on their order.
|
||||
include: [ "src/bin/shader-include/standard-shaders" ],
|
||||
src: "
|
||||
#version 450
|
||||
// Substitutes this line with the contents of the file `common.glsl` found in one of the standard
|
||||
// `include` directories specified above.
|
||||
// Note, that relative inclusion (`#include \"...\"`), although it falls back to standard
|
||||
// inclusion, should not be used for **embedded** shader source, as it may be misleading and/or
|
||||
// confusing.
|
||||
#include <common.glsl>
|
||||
let pipeline = Arc::new({
|
||||
mod cs {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "compute",
|
||||
// We declare what directories to search for when using the `#include <...>`
|
||||
// syntax. Specified directories have descending priorities based on their order.
|
||||
include: [ "src/bin/shader-include/standard-shaders" ],
|
||||
src: "
|
||||
#version 450
|
||||
// Substitutes this line with the contents of the file `common.glsl` found in one of the standard
|
||||
// `include` directories specified above.
|
||||
// Note, that relative inclusion (`#include \"...\"`), although it falls back to standard
|
||||
// inclusion, should not be used for **embedded** shader source, as it may be misleading and/or
|
||||
// confusing.
|
||||
#include <common.glsl>
|
||||
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
data.data[idx] = multiply_by_12(data.data[idx]);
|
||||
}"
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
data.data[idx] = multiply_by_12(data.data[idx]);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
let shader = cs::Shader::load(device.clone()).unwrap();
|
||||
|
@ -34,25 +34,26 @@ fn main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "compute",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(constant_id = 0) const int multiple = 64;
|
||||
layout(constant_id = 1) const float addend = 64;
|
||||
layout(constant_id = 2) const bool enable = true;
|
||||
const vec2 foo = vec2(0, 0); // TODO: How do I hit Instruction::SpecConstantComposite
|
||||
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(constant_id = 0) const int multiple = 64;
|
||||
layout(constant_id = 1) const float addend = 64;
|
||||
layout(constant_id = 2) const bool enable = true;
|
||||
const vec2 foo = vec2(0, 0); // TODO: How do I hit Instruction::SpecConstantComposite
|
||||
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
layout(set = 0, binding = 0) buffer Data {
|
||||
uint data[];
|
||||
} data;
|
||||
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
if (enable) {
|
||||
data.data[idx] *= multiple;
|
||||
data.data[idx] += uint(addend);
|
||||
}
|
||||
}"
|
||||
void main() {
|
||||
uint idx = gl_GlobalInvocationID.x;
|
||||
if (enable) {
|
||||
data.data[idx] *= multiple;
|
||||
data.data[idx] += uint(addend);
|
||||
}
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,13 @@ use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
|
||||
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError, ColorSpace};
|
||||
use vulkano::swapchain;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::Window;
|
||||
use winit::window::{WindowBuilder, Window};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use cgmath::{Matrix3, Matrix4, Point3, Vector3, Rad};
|
||||
|
||||
@ -42,24 +43,14 @@ 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 = Instance::new(None, &extensions, None).unwrap();
|
||||
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
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();
|
||||
|
||||
// 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 event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q|
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -123,117 +114,110 @@ fn main() {
|
||||
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(sync::now(device.clone())) as Box<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||
let rotation_start = Instant::now();
|
||||
|
||||
loop {
|
||||
previous_frame.cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
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(SwapchainCreationError::UnsupportedDimensions) => continue,
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
swapchain = new_swapchain;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = 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: Matrix4::from(rotation).into(),
|
||||
view: (view * scale).into(),
|
||||
proj: proj.into(),
|
||||
};
|
||||
|
||||
uniform_buffer.next(uniform_data).unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.descriptor_set_layout(0).unwrap();
|
||||
let set = Arc::new(PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(uniform_buffer_subbuffer).unwrap()
|
||||
.build().unwrap()
|
||||
);
|
||||
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
recreate_swapchain = true;
|
||||
continue;
|
||||
}
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(
|
||||
framebuffers[image_num].clone(), false,
|
||||
vec![
|
||||
[0.0, 0.0, 1.0, 1.0].into(),
|
||||
1f32.into()
|
||||
]
|
||||
).unwrap()
|
||||
.draw_indexed(
|
||||
pipeline.clone(),
|
||||
&DynamicState::none(),
|
||||
vec!(vertex_buffer.clone(), normals_buffer.clone()),
|
||||
index_buffer.clone(), set.clone(), ()).unwrap()
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
let future = previous_frame.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
swapchain = new_swapchain;
|
||||
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;
|
||||
}
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(sync::FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
previous_frame = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
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 = 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: Matrix4::from(rotation).into(),
|
||||
view: (view * scale).into(),
|
||||
proj: proj.into(),
|
||||
};
|
||||
|
||||
uniform_buffer.next(uniform_data).unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.descriptor_set_layout(0).unwrap();
|
||||
let set = Arc::new(PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(uniform_buffer_subbuffer).unwrap()
|
||||
.build().unwrap()
|
||||
);
|
||||
|
||||
let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(
|
||||
framebuffers[image_num].clone(), false,
|
||||
vec![
|
||||
[0.0, 0.0, 1.0, 1.0].into(),
|
||||
1f32.into()
|
||||
]
|
||||
).unwrap()
|
||||
.draw_indexed(
|
||||
pipeline.clone(),
|
||||
&DynamicState::none(),
|
||||
vec!(vertex_buffer.clone(), normals_buffer.clone()),
|
||||
index_buffer.clone(), set.clone(), ()).unwrap()
|
||||
.end_render_pass().unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.take().unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
},
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(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
|
||||
|
@ -32,8 +32,9 @@ use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent};
|
||||
use winit::window::{WindowBuilder, Window};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -41,13 +42,14 @@ mod vs {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "vertex",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}"
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,24 +57,25 @@ mod tcs {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "tess_ctrl",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout (vertices = 3) out; // a value of 3 means a patch consists of a single triangle
|
||||
layout (vertices = 3) out; // a value of 3 means a patch consists of a single triangle
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// save the position of the patch, so the tes can access it
|
||||
// We could define our own output variables for this,
|
||||
// but gl_out is handily provided.
|
||||
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
|
||||
void main(void)
|
||||
{
|
||||
// save the position of the patch, so the tes can access it
|
||||
// We could define our own output variables for this,
|
||||
// but gl_out is handily provided.
|
||||
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
|
||||
|
||||
gl_TessLevelInner[0] = 10; // many triangles are generated in the center
|
||||
gl_TessLevelOuter[0] = 1; // no triangles are generated for this edge
|
||||
gl_TessLevelOuter[1] = 10; // many triangles are generated for this edge
|
||||
gl_TessLevelOuter[2] = 10; // many triangles are generated for this edge
|
||||
// gl_TessLevelInner[1] = only used when tes uses layout(quads)
|
||||
// gl_TessLevelOuter[3] = only used when tes uses layout(quads)
|
||||
}"
|
||||
gl_TessLevelInner[0] = 10; // many triangles are generated in the center
|
||||
gl_TessLevelOuter[0] = 1; // no triangles are generated for this edge
|
||||
gl_TessLevelOuter[1] = 10; // many triangles are generated for this edge
|
||||
gl_TessLevelOuter[2] = 10; // many triangles are generated for this edge
|
||||
// gl_TessLevelInner[1] = only used when tes uses layout(quads)
|
||||
// gl_TessLevelOuter[3] = only used when tes uses layout(quads)
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,25 +95,26 @@ mod tes {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "tess_eval",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(triangles, equal_spacing, cw) in;
|
||||
layout(triangles, equal_spacing, cw) in;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// retrieve the vertex positions set by the tcs
|
||||
vec4 vert_x = gl_in[0].gl_Position;
|
||||
vec4 vert_y = gl_in[1].gl_Position;
|
||||
vec4 vert_z = gl_in[2].gl_Position;
|
||||
void main(void)
|
||||
{
|
||||
// retrieve the vertex positions set by the tcs
|
||||
vec4 vert_x = gl_in[0].gl_Position;
|
||||
vec4 vert_y = gl_in[1].gl_Position;
|
||||
vec4 vert_z = gl_in[2].gl_Position;
|
||||
|
||||
// convert gl_TessCoord from barycentric coordinates to cartesian coordinates
|
||||
gl_Position = vec4(
|
||||
gl_TessCoord.x * vert_x.x + gl_TessCoord.y * vert_y.x + gl_TessCoord.z * vert_z.x,
|
||||
gl_TessCoord.x * vert_x.y + gl_TessCoord.y * vert_y.y + gl_TessCoord.z * vert_z.y,
|
||||
gl_TessCoord.x * vert_x.z + gl_TessCoord.y * vert_y.z + gl_TessCoord.z * vert_z.z,
|
||||
1.0
|
||||
);
|
||||
}"
|
||||
// convert gl_TessCoord from barycentric coordinates to cartesian coordinates
|
||||
gl_Position = vec4(
|
||||
gl_TessCoord.x * vert_x.x + gl_TessCoord.y * vert_y.x + gl_TessCoord.z * vert_z.x,
|
||||
gl_TessCoord.x * vert_x.y + gl_TessCoord.y * vert_y.y + gl_TessCoord.z * vert_z.y,
|
||||
gl_TessCoord.x * vert_x.z + gl_TessCoord.y * vert_y.z + gl_TessCoord.z * vert_z.z,
|
||||
1.0
|
||||
);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,27 +122,27 @@ mod fs {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}"
|
||||
void main() {
|
||||
f_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &extensions, None).unwrap();
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||
|
||||
let mut events_loop = EventsLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
|
||||
let queue_family = physical.queue_families().find(|&q| {
|
||||
q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
|
||||
@ -149,20 +153,14 @@ fn main() {
|
||||
[(queue_family, 0.5)].iter().cloned()).unwrap();
|
||||
let queue = queues.next().unwrap();
|
||||
|
||||
let initial_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, images) = {
|
||||
let caps = surface.capabilities(physical).unwrap();
|
||||
let usage = caps.supported_usage_flags;
|
||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, initial_dimensions,
|
||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions,
|
||||
1, usage, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||
};
|
||||
|
||||
@ -223,83 +221,75 @@ fn main() {
|
||||
.unwrap());
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: None };
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
if recreate_swapchain {
|
||||
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(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;
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()])
|
||||
.unwrap()
|
||||
.draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ())
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame_end = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
let mut done = false;
|
||||
events_loop.poll_events(|ev| {
|
||||
match ev {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
if done { return }
|
||||
}
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
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;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
.begin_render_pass(framebuffers[image_num].clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()])
|
||||
.unwrap()
|
||||
.draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ())
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.take().unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This method is called once during initialization, then again whenever the window is resized
|
||||
|
@ -30,24 +30,24 @@ use vulkano::sync::{GpuFuture, FlushError};
|
||||
use vulkano::sync;
|
||||
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
|
||||
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent};
|
||||
use winit::window::{WindowBuilder, Window};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use winit::event::{Event, WindowEvent};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() {
|
||||
// The first step of any Vulkan program is to create an instance.
|
||||
let instance = {
|
||||
// When we create an instance, we have to pass a list of extensions that we want to enable.
|
||||
//
|
||||
// All the window-drawing functionalities are part of non-core extensions that we need
|
||||
// to enable manually. To do so, we ask the `vulkano_win` crate for the list of extensions
|
||||
// required to draw to a window.
|
||||
let extensions = vulkano_win::required_extensions();
|
||||
//
|
||||
// When we create an instance, we have to pass a list of extensions that we want to enable.
|
||||
//
|
||||
// All the window-drawing functionalities are part of non-core extensions that we need
|
||||
// to enable manually. To do so, we ask the `vulkano_win` crate for the list of extensions
|
||||
// required to draw to a window.
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
|
||||
// Now creating the instance.
|
||||
Instance::new(None, &extensions, None).unwrap()
|
||||
};
|
||||
// Now creating the instance.
|
||||
let instance = Instance::new(None, &required_extensions, None).unwrap();
|
||||
|
||||
// We then choose which physical device to use.
|
||||
//
|
||||
@ -64,10 +64,10 @@ 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 = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
|
||||
// Some little debug infos.
|
||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||
|
||||
|
||||
// The objective of this example is to draw a triangle on a window. To do so, we first need to
|
||||
// create the window.
|
||||
//
|
||||
@ -78,9 +78,8 @@ fn main() {
|
||||
//
|
||||
// This returns a `vulkano::swapchain::Surface` object that contains both a cross-platform winit
|
||||
// window and a cross-platform Vulkan surface that represents the surface of the window.
|
||||
let mut events_loop = EventsLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||
let window = surface.window();
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap();
|
||||
|
||||
// The next step is to choose which GPU queue will execute our draw commands.
|
||||
//
|
||||
@ -132,7 +131,6 @@ fn main() {
|
||||
// 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).unwrap();
|
||||
|
||||
let usage = caps.supported_usage_flags;
|
||||
|
||||
// The alpha mode indicates how the alpha value of the final image will behave. For example
|
||||
@ -152,18 +150,11 @@ fn main() {
|
||||
// These drivers will allow anything but the only sensible value is the window dimensions.
|
||||
//
|
||||
// Because for both of these cases, the swapchain needs to be the window dimensions, we just use that.
|
||||
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;
|
||||
};
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
// 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,
|
||||
initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||
PresentMode::Fifo, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||
|
||||
};
|
||||
@ -193,13 +184,14 @@ fn main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "vertex",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}"
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,14 +199,14 @@ void main() {
|
||||
vulkano_shaders::shader!{
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
void main() {
|
||||
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,145 +302,125 @@ void main() {
|
||||
//
|
||||
// Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to avoid
|
||||
// that, we store the submission of the previous frame here.
|
||||
let mut previous_frame_end = Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>;
|
||||
let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||
|
||||
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.
|
||||
// Calling this function polls various fences in order to determine what the GPU has
|
||||
// already processed, and frees the resources that are no longer needed.
|
||||
previous_frame_end.cleanup_finished();
|
||||
|
||||
// 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 of the window.
|
||||
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(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// This operation returns the index of the image that we are allowed to draw upon.
|
||||
//
|
||||
// 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) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
continue;
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
Err(err) => panic!("{:?}", err)
|
||||
};
|
||||
|
||||
// Specify the color to clear the framebuffer with i.e. blue
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
|
||||
// In order to draw, we have to build a *command buffer*. The command buffer object holds
|
||||
// the list of commands that are going to be executed.
|
||||
//
|
||||
// Building a command buffer is an expensive operation (usually a few hundred
|
||||
// microseconds), but it is known to be a hot path in the driver and is expected to be
|
||||
// optimized.
|
||||
//
|
||||
// Note that we have to pass a queue family when we create the command buffer. The command
|
||||
// buffer will only be executable on that given queue family.
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
// Before we can draw, we have to *enter a render pass*. There are two methods to do
|
||||
// this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is
|
||||
// not covered here.
|
||||
//
|
||||
// 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[image_num].clone(), false, clear_values)
|
||||
.unwrap()
|
||||
|
||||
// We are now inside the first subpass of the render pass. We add a draw command.
|
||||
//
|
||||
// The last two parameters contain the list of resources to pass to the shaders.
|
||||
// Since we used an `EmptyPipeline` object, the objects have to be `()`.
|
||||
.draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ())
|
||||
.unwrap()
|
||||
|
||||
// We leave the render pass by calling `draw_end`. Note that if we had multiple
|
||||
// subpasses we could have called `next_inline` (or `next_secondary`) to jump to the
|
||||
// next subpass.
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
|
||||
// Finish building the command buffer by calling `build`.
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
|
||||
// The color output is now expected to contain our triangle. But in order to show it on
|
||||
// the screen, we have to *present* the image by calling `present`.
|
||||
//
|
||||
// This function does not actually present the image immediately. Instead it submits a
|
||||
// present command at the end of the queue. This means that it will only be presented once
|
||||
// the GPU has finished executing the command buffer that draws the triangle.
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
// This wait is required when using NVIDIA or running on macOS. See https://github.com/vulkano-rs/vulkano/issues/1247
|
||||
future.wait(None).unwrap();
|
||||
previous_frame_end = Box::new(future) as Box<_>;
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;
|
||||
}
|
||||
},
|
||||
Event::RedrawEventsCleared => {
|
||||
// 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.
|
||||
// Calling this function polls various fences in order to determine what the GPU has
|
||||
// already processed, and frees the resources that are no longer needed.
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
// 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 of the window.
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
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) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e)
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// This operation returns the index of the image that we are allowed to draw upon.
|
||||
//
|
||||
// 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) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
return;
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e)
|
||||
};
|
||||
|
||||
// Specify the color to clear the framebuffer with i.e. blue
|
||||
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
||||
|
||||
// In order to draw, we have to build a *command buffer*. The command buffer object holds
|
||||
// the list of commands that are going to be executed.
|
||||
//
|
||||
// Building a command buffer is an expensive operation (usually a few hundred
|
||||
// microseconds), but it is known to be a hot path in the driver and is expected to be
|
||||
// optimized.
|
||||
//
|
||||
// Note that we have to pass a queue family when we create the command buffer. The command
|
||||
// buffer will only be executable on that given queue family.
|
||||
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
|
||||
// Before we can draw, we have to *enter a render pass*. There are two methods to do
|
||||
// this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is
|
||||
// not covered here.
|
||||
//
|
||||
// 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[image_num].clone(), false, clear_values).unwrap()
|
||||
|
||||
// We are now inside the first subpass of the render pass. We add a draw command.
|
||||
//
|
||||
// The last two parameters contain the list of resources to pass to the shaders.
|
||||
// Since we used an `EmptyPipeline` object, the objects have to be `()`.
|
||||
.draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ()).unwrap()
|
||||
|
||||
// We leave the render pass by calling `draw_end`. Note that if we had multiple
|
||||
// subpasses we could have called `next_inline` (or `next_secondary`) to jump to the
|
||||
// next subpass.
|
||||
.end_render_pass().unwrap()
|
||||
|
||||
// Finish building the command buffer by calling `build`.
|
||||
.build().unwrap();
|
||||
|
||||
let future = previous_frame_end.take().unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer).unwrap()
|
||||
|
||||
// The color output is now expected to contain our triangle. But in order to show it on
|
||||
// the screen, we have to *present* the image by calling `present`.
|
||||
//
|
||||
// This function does not actually present the image immediately. Instead it submits a
|
||||
// present command at the end of the queue. This means that it will only be presented once
|
||||
// the GPU has finished executing the command buffer that draws the triangle.
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||
},
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
// Note that in more complex programs it is likely that one of `acquire_next_image`,
|
||||
// `command_buffer::submit`, or `present` will block for some time. This happens when the
|
||||
// GPU's queue is full and the driver has to wait until the GPU finished some work.
|
||||
//
|
||||
// Unfortunately the Vulkan API doesn't provide any way to not wait or to detect when a
|
||||
// wait would happen. Blocking may be the desired behavior, but if you don't want to
|
||||
// block you should spawn a separate thread dedicated to submissions.
|
||||
|
||||
// Handling the window events in order to close the program when the user wants to close
|
||||
// it.
|
||||
let mut done = false;
|
||||
events_loop.poll_events(|ev| {
|
||||
match ev {
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
|
||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
||||
_ => ()
|
||||
}
|
||||
});
|
||||
if done { return; }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This method is called once during initialization, then again whenever the window is resized
|
||||
|
@ -12,10 +12,10 @@ keywords = ["vulkan", "bindings", "graphics", "gpu", "rendering"]
|
||||
categories = ["rendering::graphics-api"]
|
||||
|
||||
[dependencies]
|
||||
winit = "0.19"
|
||||
winit = "0.20"
|
||||
vulkano = { version = "0.16.0", path = "../vulkano" }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
metal = "0.17.0"
|
||||
cocoa = "0.19.1"
|
||||
cocoa = "0.20.0"
|
||||
objc = "0.2.7"
|
||||
|
@ -12,8 +12,10 @@ use vulkano::instance::Instance;
|
||||
use vulkano::instance::InstanceExtensions;
|
||||
use vulkano::swapchain::Surface;
|
||||
use vulkano::swapchain::SurfaceCreationError;
|
||||
use winit::{EventsLoop, WindowBuilder};
|
||||
use winit::CreationError as WindowCreationError;
|
||||
use winit::window::Window;
|
||||
use winit::window::WindowBuilder;
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::error::OsError as WindowCreationError;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use cocoa::appkit::{NSView, NSWindow};
|
||||
@ -52,22 +54,22 @@ pub fn create_vk_surface<W>(
|
||||
window: W, instance: Arc<Instance>
|
||||
) -> Result<Arc<Surface<W>>, SurfaceCreationError>
|
||||
where
|
||||
W: SafeBorrow<winit::Window>,
|
||||
W: SafeBorrow<Window>,
|
||||
{
|
||||
unsafe { winit_to_surface(instance, window) }
|
||||
}
|
||||
|
||||
pub trait VkSurfaceBuild {
|
||||
pub trait VkSurfaceBuild<E> {
|
||||
fn build_vk_surface(
|
||||
self, events_loop: &EventsLoop, instance: Arc<Instance>,
|
||||
) -> Result<Arc<Surface<winit::Window>>, CreationError>;
|
||||
self, event_loop: &EventLoop<E>, instance: Arc<Instance>,
|
||||
) -> Result<Arc<Surface<Window>>, CreationError>;
|
||||
}
|
||||
|
||||
impl VkSurfaceBuild for WindowBuilder {
|
||||
impl<E> VkSurfaceBuild<E> for WindowBuilder {
|
||||
fn build_vk_surface(
|
||||
self, events_loop: &EventsLoop, instance: Arc<Instance>,
|
||||
) -> Result<Arc<Surface<winit::Window>>, CreationError> {
|
||||
let window = self.build(events_loop)?;
|
||||
self, event_loop: &EventLoop<E>, instance: Arc<Instance>,
|
||||
) -> Result<Arc<Surface<Window>>, CreationError> {
|
||||
let window = self.build(event_loop)?;
|
||||
Ok(create_vk_surface(window, instance)?)
|
||||
}
|
||||
}
|
||||
@ -121,21 +123,23 @@ impl From<WindowCreationError> for CreationError {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<winit::Window>>(
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<Window>>(
|
||||
instance: Arc<Instance>, win: W,
|
||||
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
|
||||
use winit::os::android::WindowExt;
|
||||
Surface::from_anativewindow(instance, win.borrow().get_native_window(), win)
|
||||
use winit::platform::android::WindowExtAndroid;
|
||||
|
||||
Surface::from_anativewindow(instance, win.borrow().native_window(), win)
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<winit::Window>>(
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<Window>>(
|
||||
instance: Arc<Instance>, win: W,
|
||||
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
|
||||
use winit::os::unix::WindowExt;
|
||||
use winit::platform::unix::WindowExtUnix;
|
||||
|
||||
match (
|
||||
win.borrow().get_wayland_display(),
|
||||
win.borrow().get_wayland_surface(),
|
||||
win.borrow().wayland_display(),
|
||||
win.borrow().wayland_surface(),
|
||||
) {
|
||||
(Some(display), Some(surface)) => Surface::from_wayland(instance, display, surface, win),
|
||||
_ => {
|
||||
@ -144,15 +148,15 @@ unsafe fn winit_to_surface<W: SafeBorrow<winit::Window>>(
|
||||
if instance.loaded_extensions().khr_xlib_surface {
|
||||
Surface::from_xlib(
|
||||
instance,
|
||||
win.borrow().get_xlib_display().unwrap(),
|
||||
win.borrow().get_xlib_window().unwrap() as _,
|
||||
win.borrow().xlib_display().unwrap(),
|
||||
win.borrow().xlib_window().unwrap() as _,
|
||||
win,
|
||||
)
|
||||
} else {
|
||||
Surface::from_xcb(
|
||||
instance,
|
||||
win.borrow().get_xcb_connection().unwrap(),
|
||||
win.borrow().get_xlib_window().unwrap() as _,
|
||||
win.borrow().xcb_connection().unwrap(),
|
||||
win.borrow().xlib_window().unwrap() as _,
|
||||
win,
|
||||
)
|
||||
}
|
||||
@ -161,26 +165,26 @@ unsafe fn winit_to_surface<W: SafeBorrow<winit::Window>>(
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<winit::Window>>(
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<Window>>(
|
||||
instance: Arc<Instance>, win: W,
|
||||
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
|
||||
use winit::os::windows::WindowExt;
|
||||
use winit::platform::windows::WindowExtWindows;
|
||||
|
||||
Surface::from_hwnd(
|
||||
instance,
|
||||
ptr::null() as *const (), // FIXME
|
||||
win.borrow().get_hwnd(),
|
||||
win.borrow().hwnd(),
|
||||
win,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<winit::Window>>(
|
||||
unsafe fn winit_to_surface<W: SafeBorrow<Window>>(
|
||||
instance: Arc<Instance>, win: W,
|
||||
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
|
||||
use winit::os::macos::WindowExt;
|
||||
|
||||
let wnd: cocoa_id = mem::transmute(win.borrow().get_nswindow());
|
||||
use winit::platform::macos::WindowExtMacOS ;
|
||||
|
||||
let wnd: cocoa_id = mem::transmute(win.borrow().ns_window());
|
||||
let layer = CoreAnimationLayer::new();
|
||||
|
||||
layer.set_edge_antialiasing_mask(0);
|
||||
@ -193,7 +197,7 @@ unsafe fn winit_to_surface<W: SafeBorrow<winit::Window>>(
|
||||
view.setLayer(mem::transmute(layer.as_ref())); // Bombs here with out of memory
|
||||
view.setWantsLayer(YES);
|
||||
|
||||
Surface::from_macos_moltenvk(instance, win.borrow().get_nsview() as *const (), win)
|
||||
Surface::from_macos_moltenvk(instance, win.borrow().ns_view() as *const (), win)
|
||||
}
|
||||
|
||||
/// An alternative to `Borrow<T>` with the requirement that all calls to
|
||||
|
Loading…
Reference in New Issue
Block a user