upgrade winit to 0.20 and cocoa to 0.20

This commit is contained in:
Austin Johnson 2020-01-23 01:37:12 -06:00 committed by GitHub
parent 6ca6d84a87
commit b95c058f9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 979 additions and 1085 deletions

View File

@ -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.

View File

@ -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" }

View File

@ -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();

View File

@ -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; }
}
});
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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 = {

View File

@ -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

View File

@ -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();

View File

@ -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);
}
}
"
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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