mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
Update dependencies (#2385)
* Update winit * Update raw-window-handle * Update syn * Remove vulkano-win from the workspace
This commit is contained in:
parent
3664c079f7
commit
4a77d39b85
@ -4,7 +4,7 @@ members = [
|
|||||||
"vulkano-macros",
|
"vulkano-macros",
|
||||||
"vulkano-shaders",
|
"vulkano-shaders",
|
||||||
"vulkano-util",
|
"vulkano-util",
|
||||||
"vulkano-win",
|
# "vulkano-win",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
@ -44,13 +44,13 @@ parking_lot = "0.12"
|
|||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
proc-macro-crate = "1.2"
|
proc-macro-crate = "1.2"
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
raw-window-handle = "0.5"
|
raw-window-handle = "0.6"
|
||||||
regex = "1.8"
|
regex = "1.8"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
shaderc = "0.8"
|
shaderc = "0.8"
|
||||||
smallvec = "1.8"
|
smallvec = "1.8"
|
||||||
syn = "1.0"
|
syn = "2.0"
|
||||||
thread_local = "1.1"
|
thread_local = "1.1"
|
||||||
vk-parse = "0.12"
|
vk-parse = "0.12"
|
||||||
winit = "0.28"
|
winit = "0.29"
|
||||||
|
@ -12,4 +12,4 @@ vulkano = { path = "../vulkano" }
|
|||||||
vulkano-macros = { path = "../vulkano-macros" }
|
vulkano-macros = { path = "../vulkano-macros" }
|
||||||
vulkano-shaders = { path = "../vulkano-shaders" }
|
vulkano-shaders = { path = "../vulkano-shaders" }
|
||||||
vulkano-util = { path = "../vulkano-util" }
|
vulkano-util = { path = "../vulkano-util" }
|
||||||
winit = "0.28"
|
winit = "0.29"
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
use cgmath::{Matrix4, Rad};
|
use cgmath::{Matrix4, Rad};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::{
|
use std::{
|
||||||
|
error::Error,
|
||||||
hint,
|
hint,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||||
@ -91,18 +92,19 @@ use vulkano::{
|
|||||||
Validated, VulkanError, VulkanLibrary,
|
Validated, VulkanError, VulkanLibrary,
|
||||||
};
|
};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
event::{ElementState, Event, KeyEvent, WindowEvent},
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
keyboard::{Key, NamedKey},
|
||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TRANSFER_GRANULARITY: u32 = 4096;
|
const TRANSFER_GRANULARITY: u32 = 4096;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -521,13 +523,15 @@ fn main() {
|
|||||||
|
|
||||||
println!("\nPress space to update part of the texture");
|
println!("\nPress space to update part of the texture");
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -538,10 +542,10 @@ fn main() {
|
|||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event:
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
input:
|
event:
|
||||||
KeyboardInput {
|
KeyEvent {
|
||||||
|
logical_key: Key::Named(NamedKey::Space),
|
||||||
state: ElementState::Released,
|
state: ElementState::Released,
|
||||||
virtual_keycode: Some(VirtualKeyCode::Space),
|
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
..
|
..
|
||||||
@ -550,7 +554,10 @@ fn main() {
|
|||||||
} => {
|
} => {
|
||||||
channel.send(()).unwrap();
|
channel.send(()).unwrap();
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
if image_extent.contains(&0) {
|
||||||
@ -685,9 +692,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
// Modified triangle example to show `SubbufferAllocator`.
|
// Modified triangle example to show `SubbufferAllocator`.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
error::Error,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
@ -55,11 +56,11 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -280,13 +281,15 @@ fn main() {
|
|||||||
let command_buffer_allocator =
|
let command_buffer_allocator =
|
||||||
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -294,7 +297,10 @@ fn main() {
|
|||||||
} => {
|
} => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
if image_extent.contains(&0) {
|
||||||
@ -426,9 +432,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// notice may not be copied, modified, or distributed except
|
// notice may not be copied, modified, or distributed except
|
||||||
// according to those terms.
|
// according to those terms.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, ClearAttachment,
|
allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, ClearAttachment,
|
||||||
@ -32,14 +32,14 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
||||||
// example if you haven't done so yet.
|
// example if you haven't done so yet.
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -157,140 +157,149 @@ fn main() {
|
|||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
width = swapchain.image_extent()[0];
|
|
||||||
height = swapchain.image_extent()[1];
|
|
||||||
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone());
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
// Clear attachments with clear values and rects information. All the rects will be
|
|
||||||
// cleared by the same value. Note that the ClearRect offsets and extents are not
|
|
||||||
// affected by the viewport, they are directly applied to the rendering image.
|
|
||||||
.clear_attachments(
|
|
||||||
[ClearAttachment::Color {
|
|
||||||
color_attachment: 0,
|
|
||||||
clear_value: [1.0, 0.0, 0.0, 1.0].into(),
|
|
||||||
}]
|
|
||||||
.into_iter()
|
|
||||||
.collect(),
|
|
||||||
[
|
|
||||||
// Fixed offset and extent.
|
|
||||||
ClearRect {
|
|
||||||
offset: [0, 0],
|
|
||||||
extent: [100, 100],
|
|
||||||
array_layers: 0..1,
|
|
||||||
},
|
|
||||||
// Fixed offset, relative extent.
|
|
||||||
ClearRect {
|
|
||||||
offset: [100, 150],
|
|
||||||
extent: [width / 4, height / 4],
|
|
||||||
array_layers: 0..1,
|
|
||||||
},
|
|
||||||
// Relative offset and extent.
|
|
||||||
ClearRect {
|
|
||||||
offset: [width / 2, height / 2],
|
|
||||||
extent: [width / 3, height / 5],
|
|
||||||
array_layers: 0..1,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
width = swapchain.image_extent()[0];
|
||||||
|
height = swapchain.image_extent()[1];
|
||||||
|
framebuffers = window_size_dependent_setup(&new_images, render_pass.clone());
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
// Clear attachments with clear values and rects information. All the rects
|
||||||
|
// will be cleared by the same value. Note that the ClearRect offsets and
|
||||||
|
// extents are not affected by the viewport, they are directly applied to the
|
||||||
|
// rendering image.
|
||||||
|
.clear_attachments(
|
||||||
|
[ClearAttachment::Color {
|
||||||
|
color_attachment: 0,
|
||||||
|
clear_value: [1.0, 0.0, 0.0, 1.0].into(),
|
||||||
|
}]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
[
|
||||||
|
// Fixed offset and extent.
|
||||||
|
ClearRect {
|
||||||
|
offset: [0, 0],
|
||||||
|
extent: [100, 100],
|
||||||
|
array_layers: 0..1,
|
||||||
|
},
|
||||||
|
// Fixed offset, relative extent.
|
||||||
|
ClearRect {
|
||||||
|
offset: [100, 150],
|
||||||
|
extent: [width / 4, height / 4],
|
||||||
|
array_layers: 0..1,
|
||||||
|
},
|
||||||
|
// Relative offset and extent.
|
||||||
|
ClearRect {
|
||||||
|
offset: [width / 2, height / 2],
|
||||||
|
extent: [width / 3, height / 5],
|
||||||
|
array_layers: 0..1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -30,7 +30,7 @@ use crate::{
|
|||||||
triangle_draw_system::TriangleDrawSystem,
|
triangle_draw_system::TriangleDrawSystem,
|
||||||
};
|
};
|
||||||
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::allocator::{
|
command_buffer::allocator::{
|
||||||
StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo,
|
StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo,
|
||||||
@ -57,13 +57,13 @@ use winit::{
|
|||||||
mod frame;
|
mod frame;
|
||||||
mod triangle_draw_system;
|
mod triangle_draw_system;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// Basic initialization. See the triangle example if you want more details about this.
|
// Basic initialization. See the triangle example if you want more details about this.
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -186,107 +186,116 @@ fn main() {
|
|||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
let new_images = new_images
|
|
||||||
.into_iter()
|
|
||||||
.map(|image| ImageView::new_default(image).unwrap())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
images = new_images;
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let future = previous_frame_end.take().unwrap().join(acquire_future);
|
if image_extent.contains(&0) {
|
||||||
let mut frame = frame_system.frame(
|
return;
|
||||||
future,
|
|
||||||
images[image_index as usize].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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let future = after_future
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
if recreate_swapchain {
|
||||||
Ok(future) => {
|
let (new_swapchain, new_images) = swapchain
|
||||||
previous_frame_end = Some(future.boxed());
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
let new_images = new_images
|
||||||
|
.into_iter()
|
||||||
|
.map(|image| ImageView::new_default(image).unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
images = new_images;
|
||||||
|
recreate_swapchain = false;
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let future = previous_frame_end.take().unwrap().join(acquire_future);
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut frame = frame_system.frame(
|
||||||
|
future,
|
||||||
|
images[image_index as usize].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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let future = after_future
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
fn main() {
|
fn main() -> Result<(), winit::error::EventLoopError> {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
linux::main();
|
{
|
||||||
|
linux::main()
|
||||||
|
}
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
println!("Not Implemented");
|
{
|
||||||
|
Ok(println!("Not Implemented"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Can this be demonstrated for other platforms as well?
|
// TODO: Can this be demonstrated for other platforms as well?
|
||||||
@ -80,7 +84,7 @@ mod linux {
|
|||||||
window::{Window, WindowBuilder},
|
window::{Window, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() -> Result<(), winit::error::EventLoopError> {
|
||||||
let event_loop_gl = winit_glium::event_loop::EventLoop::new();
|
let event_loop_gl = winit_glium::event_loop::EventLoop::new();
|
||||||
// For some reason, this must be created before the vulkan window
|
// For some reason, this must be created before the vulkan window
|
||||||
let hrb = glutin::ContextBuilder::new()
|
let hrb = glutin::ContextBuilder::new()
|
||||||
@ -102,7 +106,7 @@ mod linux {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
let (
|
let (
|
||||||
device,
|
device,
|
||||||
_instance,
|
_instance,
|
||||||
@ -287,13 +291,15 @@ mod linux {
|
|||||||
let mut previous_frame_end: Option<Box<dyn GpuFuture>> =
|
let mut previous_frame_end: Option<Box<dyn GpuFuture>> =
|
||||||
Some(Box::new(now(device.clone())));
|
Some(Box::new(now(device.clone())));
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -301,7 +307,10 @@ mod linux {
|
|||||||
} => {
|
} => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
queue
|
queue
|
||||||
.with(|mut q| unsafe {
|
.with(|mut q| unsafe {
|
||||||
q.submit(
|
q.submit(
|
||||||
@ -441,10 +450,10 @@ mod linux {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BufferContents, Vertex)]
|
#[derive(BufferContents, Vertex)]
|
||||||
@ -473,7 +482,7 @@ mod linux {
|
|||||||
Subbuffer<[MyVertex]>,
|
Subbuffer<[MyVertex]>,
|
||||||
) {
|
) {
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// notice may not be copied, modified, or distributed except
|
// notice may not be copied, modified, or distributed except
|
||||||
// according to those terms.
|
// according to those terms.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -57,14 +57,14 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
||||||
// example if you haven't done so yet.
|
// example if you haven't done so yet.
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -415,120 +415,131 @@ fn main() {
|
|||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.bind_descriptor_sets(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
set.clone(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_descriptor_sets(
|
||||||
|
PipelineBindPoint::Graphics,
|
||||||
|
pipeline.layout().clone(),
|
||||||
|
0,
|
||||||
|
set.clone(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// notice may not be copied, modified, or distributed except
|
// notice may not be copied, modified, or distributed except
|
||||||
// according to those terms.
|
// according to those terms.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -56,14 +56,14 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
||||||
// example if you haven't done so yet.
|
// example if you haven't done so yet.
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -363,120 +363,131 @@ fn main() {
|
|||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.bind_descriptor_sets(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
set.clone(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_descriptor_sets(
|
||||||
|
PipelineBindPoint::Graphics,
|
||||||
|
pipeline.layout().clone(),
|
||||||
|
0,
|
||||||
|
set.clone(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
// - The sampler is added to the descriptor set layout at pipeline creation.
|
// - The sampler is added to the descriptor set layout at pipeline creation.
|
||||||
// - No sampler is included when building a descriptor set.
|
// - No sampler is included when building a descriptor set.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -65,11 +65,11 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -381,120 +381,131 @@ fn main() {
|
|||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.bind_descriptor_sets(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
set.clone(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_descriptor_sets(
|
||||||
|
PipelineBindPoint::Graphics,
|
||||||
|
pipeline.layout().clone(),
|
||||||
|
0,
|
||||||
|
set.clone(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
// For an explanation of how the rendering of the triangles takes place see the `triangle.rs`
|
// For an explanation of how the rendering of the triangles takes place see the `triangle.rs`
|
||||||
// example.
|
// example.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{
|
buffer::{
|
||||||
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
||||||
@ -72,11 +72,11 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -226,9 +226,9 @@ fn main() {
|
|||||||
void main() {
|
void main() {
|
||||||
uint idx = gl_GlobalInvocationID.x;
|
uint idx = gl_GlobalInvocationID.x;
|
||||||
|
|
||||||
// Each invocation of the compute shader is going to increment the counter, so
|
// Each invocation of the compute shader is going to increment the counter, so
|
||||||
// we need to use atomic operations for safety. The previous value of the
|
// 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
|
// counter is returned so that gives us the offset into the vertex buffer this
|
||||||
// thread can write it's vertices into.
|
// thread can write it's vertices into.
|
||||||
uint offset = atomicAdd(vertices, 6);
|
uint offset = atomicAdd(vertices, 6);
|
||||||
|
|
||||||
@ -375,13 +375,15 @@ fn main() {
|
|||||||
let command_buffer_allocator =
|
let command_buffer_allocator =
|
||||||
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -389,7 +391,10 @@ fn main() {
|
|||||||
} => {
|
} => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
if image_extent.contains(&0) {
|
||||||
@ -538,9 +543,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// This is a simple, modified version of the `triangle.rs` example that demonstrates how we can use
|
// This is a simple, modified version of the `triangle.rs` example that demonstrates how we can use
|
||||||
// the "instancing" technique with vulkano to draw many instances of the triangle.
|
// the "instancing" technique with vulkano to draw many instances of the triangle.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -71,11 +71,11 @@ struct InstanceData {
|
|||||||
scale: f32,
|
scale: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -319,8 +319,8 @@ fn main() {
|
|||||||
None,
|
None,
|
||||||
GraphicsPipelineCreateInfo {
|
GraphicsPipelineCreateInfo {
|
||||||
stages: stages.into_iter().collect(),
|
stages: stages.into_iter().collect(),
|
||||||
// Use the implementations of the `Vertex` trait to describe to vulkano how the two vertex
|
// Use the implementations of the `Vertex` trait to describe to vulkano how the two
|
||||||
// types are expected to be used.
|
// vertex types are expected to be used.
|
||||||
vertex_input_state: Some(vertex_input_state),
|
vertex_input_state: Some(vertex_input_state),
|
||||||
input_assembly_state: Some(InputAssemblyState::default()),
|
input_assembly_state: Some(InputAssemblyState::default()),
|
||||||
viewport_state: Some(ViewportState::default()),
|
viewport_state: Some(ViewportState::default()),
|
||||||
@ -350,13 +350,15 @@ fn main() {
|
|||||||
let command_buffer_allocator =
|
let command_buffer_allocator =
|
||||||
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -364,7 +366,10 @@ fn main() {
|
|||||||
} => {
|
} => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
if image_extent.contains(&0) {
|
||||||
@ -465,9 +470,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -25,10 +25,8 @@ use vulkano::{
|
|||||||
use vulkano_util::{renderer::VulkanoWindowRenderer, window::WindowDescriptor};
|
use vulkano_util::{renderer::VulkanoWindowRenderer, window::WindowDescriptor};
|
||||||
use winit::{
|
use winit::{
|
||||||
dpi::PhysicalPosition,
|
dpi::PhysicalPosition,
|
||||||
event::{
|
event::{ElementState, Event, KeyEvent, MouseButton, MouseScrollDelta, WindowEvent},
|
||||||
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, VirtualKeyCode,
|
keyboard::{Key, NamedKey},
|
||||||
WindowEvent,
|
|
||||||
},
|
|
||||||
window::Fullscreen,
|
window::Fullscreen,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -324,9 +322,9 @@ impl InputState {
|
|||||||
|
|
||||||
fn handle_input(&mut self, window_size: [f32; 2], event: &Event<()>) {
|
fn handle_input(&mut self, window_size: [f32; 2], event: &Event<()>) {
|
||||||
self.window_size = window_size;
|
self.window_size = window_size;
|
||||||
if let winit::event::Event::WindowEvent { event, .. } = event {
|
if let Event::WindowEvent { event, .. } = event {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::KeyboardInput { input, .. } => self.on_keyboard_event(input),
|
WindowEvent::KeyboardInput { event, .. } => self.on_keyboard_event(event),
|
||||||
WindowEvent::MouseInput { state, button, .. } => {
|
WindowEvent::MouseInput { state, button, .. } => {
|
||||||
self.on_mouse_click_event(*state, *button)
|
self.on_mouse_click_event(*state, *button)
|
||||||
}
|
}
|
||||||
@ -338,21 +336,19 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Matches keyboard events to our defined inputs.
|
/// Matches keyboard events to our defined inputs.
|
||||||
fn on_keyboard_event(&mut self, input: &KeyboardInput) {
|
fn on_keyboard_event(&mut self, event: &KeyEvent) {
|
||||||
if let Some(key_code) = input.virtual_keycode {
|
match event.logical_key.as_ref() {
|
||||||
match key_code {
|
Key::Named(NamedKey::Escape) => self.should_quit = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::Escape => self.should_quit = state_is_pressed(input.state),
|
Key::Character("w") => self.pan_up = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::W => self.pan_up = state_is_pressed(input.state),
|
Key::Character("a") => self.pan_left = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::A => self.pan_left = state_is_pressed(input.state),
|
Key::Character("s") => self.pan_down = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::S => self.pan_down = state_is_pressed(input.state),
|
Key::Character("d") => self.pan_right = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::D => self.pan_right = state_is_pressed(input.state),
|
Key::Character("f") => self.toggle_full_screen = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::F => self.toggle_full_screen = state_is_pressed(input.state),
|
Key::Named(NamedKey::Enter) => self.randomize_palette = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::Return => self.randomize_palette = state_is_pressed(input.state),
|
Key::Character("=") => self.increase_iterations = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::Equals => self.increase_iterations = state_is_pressed(input.state),
|
Key::Character("-") => self.decrease_iterations = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::Minus => self.decrease_iterations = state_is_pressed(input.state),
|
Key::Named(NamedKey::Space) => self.toggle_julia = state_is_pressed(event.state),
|
||||||
VirtualKeyCode::Space => self.toggle_julia = state_is_pressed(input.state),
|
_ => (),
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
// - A simple `InputState` to interact with the application.
|
// - A simple `InputState` to interact with the application.
|
||||||
|
|
||||||
use crate::app::FractalApp;
|
use crate::app::FractalApp;
|
||||||
|
use std::error::Error;
|
||||||
use vulkano::{image::ImageUsage, swapchain::PresentMode, sync::GpuFuture};
|
use vulkano::{image::ImageUsage, swapchain::PresentMode, sync::GpuFuture};
|
||||||
use vulkano_util::{
|
use vulkano_util::{
|
||||||
context::{VulkanoConfig, VulkanoContext},
|
context::{VulkanoConfig, VulkanoContext},
|
||||||
@ -36,9 +37,9 @@ mod fractal_compute_pipeline;
|
|||||||
mod pixels_draw_pipeline;
|
mod pixels_draw_pipeline;
|
||||||
mod place_over_frame;
|
mod place_over_frame;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// Create the event loop.
|
// Create the event loop.
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
let context = VulkanoContext::new(VulkanoConfig::default());
|
let context = VulkanoContext::new(VulkanoConfig::default());
|
||||||
let mut windows = VulkanoWindows::default();
|
let mut windows = VulkanoWindows::default();
|
||||||
let _id = windows.create_window(
|
let _id = windows.create_window(
|
||||||
@ -74,11 +75,13 @@ fn main() {
|
|||||||
);
|
);
|
||||||
app.print_guide();
|
app.print_guide();
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
let renderer = windows.get_primary_renderer_mut().unwrap();
|
let renderer = windows.get_primary_renderer_mut().unwrap();
|
||||||
|
|
||||||
if process_event(renderer, &event, &mut app, render_target_id) {
|
if process_event(renderer, &event, &mut app, render_target_id) {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,15 +99,20 @@ pub fn process_event(
|
|||||||
render_target_id: usize,
|
render_target_id: usize,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match &event {
|
match &event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent {
|
||||||
WindowEvent::CloseRequested => {
|
event: WindowEvent::CloseRequested,
|
||||||
return true;
|
..
|
||||||
}
|
} => {
|
||||||
WindowEvent::Resized(..) | WindowEvent::ScaleFactorChanged { .. } => renderer.resize(),
|
return true;
|
||||||
_ => (),
|
}
|
||||||
},
|
Event::WindowEvent {
|
||||||
Event::MainEventsCleared => renderer.window().request_redraw(),
|
event: WindowEvent::Resized(..) | WindowEvent::ScaleFactorChanged { .. },
|
||||||
Event::RedrawRequested(_) => 'redraw: {
|
..
|
||||||
|
} => renderer.resize(),
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => 'redraw: {
|
||||||
// Tasks for redrawing:
|
// Tasks for redrawing:
|
||||||
// 1. Update state based on events
|
// 1. Update state based on events
|
||||||
// 2. Compute & Render
|
// 2. Compute & Render
|
||||||
@ -132,6 +140,7 @@ pub fn process_event(
|
|||||||
app.max_iters
|
app.max_iters
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => renderer.window().request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
!app.is_running()
|
!app.is_running()
|
||||||
|
@ -23,7 +23,7 @@ mod render_pass;
|
|||||||
|
|
||||||
use crate::app::{App, RenderPipeline};
|
use crate::app::{App, RenderPipeline};
|
||||||
use cgmath::Vector2;
|
use cgmath::Vector2;
|
||||||
use std::time::Instant;
|
use std::{error::Error, time::Instant};
|
||||||
use vulkano_util::renderer::VulkanoWindowRenderer;
|
use vulkano_util::renderer::VulkanoWindowRenderer;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{ElementState, Event, MouseButton, WindowEvent},
|
event::{ElementState, Event, MouseButton, WindowEvent},
|
||||||
@ -36,11 +36,11 @@ pub const WINDOW2_WIDTH: f32 = 512.0;
|
|||||||
pub const WINDOW2_HEIGHT: f32 = 512.0;
|
pub const WINDOW2_HEIGHT: f32 = 512.0;
|
||||||
pub const SCALING: f32 = 2.0;
|
pub const SCALING: f32 = 2.0;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
println!("Welcome to Vulkano Game of Life\nUse the mouse to draw life on the grid(s)\n");
|
println!("Welcome to Vulkano Game of Life\nUse the mouse to draw life on the grid(s)\n");
|
||||||
|
|
||||||
// Create event loop.
|
// Create event loop.
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
// Create app with vulkano context.
|
// Create app with vulkano context.
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
@ -54,7 +54,9 @@ fn main() {
|
|||||||
let mut mouse_is_pressed_w1 = false;
|
let mut mouse_is_pressed_w1 = false;
|
||||||
let mut mouse_is_pressed_w2 = false;
|
let mut mouse_is_pressed_w2 = false;
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
if process_event(
|
if process_event(
|
||||||
&event,
|
&event,
|
||||||
&mut app,
|
&mut app,
|
||||||
@ -62,8 +64,12 @@ fn main() {
|
|||||||
&mut mouse_is_pressed_w1,
|
&mut mouse_is_pressed_w1,
|
||||||
&mut mouse_is_pressed_w2,
|
&mut mouse_is_pressed_w2,
|
||||||
) {
|
) {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
return;
|
return;
|
||||||
|
} else if event == Event::AboutToWait {
|
||||||
|
for (_, renderer) in app.windows.iter() {
|
||||||
|
renderer.window().request_redraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw life on windows if mouse is down.
|
// Draw life on windows if mouse is down.
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
// that you want to learn Vulkan. This means that for example it won't go into details about what a
|
// that you want to learn Vulkan. This means that for example it won't go into details about what a
|
||||||
// vertex or a shader is.
|
// vertex or a shader is.
|
||||||
|
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -51,7 +51,7 @@ use vulkano::{
|
|||||||
Validated, VulkanError, VulkanLibrary,
|
Validated, VulkanError, VulkanLibrary,
|
||||||
};
|
};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{ElementState, Event, KeyboardInput, WindowEvent},
|
event::{ElementState, Event, KeyEvent, WindowEvent},
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
window::{Window, WindowBuilder},
|
window::{Window, WindowBuilder},
|
||||||
};
|
};
|
||||||
@ -65,11 +65,11 @@ struct WindowSurface {
|
|||||||
previous_frame_end: Option<Box<dyn GpuFuture>>,
|
previous_frame_end: Option<Box<dyn GpuFuture>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -326,188 +326,198 @@ fn main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, event_loop, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
window_id,
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
window_surfaces
|
|
||||||
.get_mut(&window_id)
|
|
||||||
.unwrap()
|
|
||||||
.recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event:
|
|
||||||
WindowEvent::KeyboardInput {
|
|
||||||
input:
|
|
||||||
KeyboardInput {
|
|
||||||
state: ElementState::Pressed,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let window = Arc::new(WindowBuilder::new().build(event_loop).unwrap());
|
|
||||||
let surface = Surface::from_window(instance.clone(), window.clone()).unwrap();
|
|
||||||
let window_id = window.id();
|
|
||||||
let (swapchain, images) = {
|
|
||||||
let composite_alpha = surface_caps
|
|
||||||
.supported_composite_alpha
|
|
||||||
.into_iter()
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
let image_format = device
|
|
||||||
.physical_device()
|
|
||||||
.surface_formats(&surface, Default::default())
|
|
||||||
.unwrap()[0]
|
|
||||||
.0;
|
|
||||||
|
|
||||||
Swapchain::new(
|
match event {
|
||||||
device.clone(),
|
Event::WindowEvent {
|
||||||
surface,
|
event: WindowEvent::CloseRequested,
|
||||||
SwapchainCreateInfo {
|
..
|
||||||
min_image_count: surface_caps.min_image_count.max(2),
|
} => {
|
||||||
image_format,
|
elwt.exit();
|
||||||
image_extent: window.inner_size().into(),
|
}
|
||||||
image_usage: ImageUsage::COLOR_ATTACHMENT,
|
Event::WindowEvent {
|
||||||
composite_alpha,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
window_surfaces.insert(
|
|
||||||
window_id,
|
window_id,
|
||||||
WindowSurface {
|
event: WindowEvent::Resized(_),
|
||||||
window,
|
..
|
||||||
swapchain,
|
} => {
|
||||||
recreate_swapchain: false,
|
window_surfaces
|
||||||
framebuffers: window_size_dependent_setup(
|
.get_mut(&window_id)
|
||||||
&images,
|
.unwrap()
|
||||||
render_pass.clone(),
|
.recreate_swapchain = true;
|
||||||
&mut viewport,
|
|
||||||
),
|
|
||||||
previous_frame_end: Some(sync::now(device.clone()).boxed()),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
window_surfaces
|
|
||||||
.values()
|
|
||||||
.for_each(|s| s.window.request_redraw());
|
|
||||||
}
|
|
||||||
Event::RedrawRequested(window_id) => {
|
|
||||||
let WindowSurface {
|
|
||||||
window,
|
|
||||||
swapchain,
|
|
||||||
recreate_swapchain,
|
|
||||||
framebuffers,
|
|
||||||
previous_frame_end,
|
|
||||||
} = window_surfaces.get_mut(&window_id).unwrap();
|
|
||||||
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event:
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
event:
|
||||||
|
KeyEvent {
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let window = Arc::new(WindowBuilder::new().build(elwt).unwrap());
|
||||||
|
let surface = Surface::from_window(instance.clone(), window.clone()).unwrap();
|
||||||
|
let window_id = window.id();
|
||||||
|
let (swapchain, images) = {
|
||||||
|
let composite_alpha = surface_caps
|
||||||
|
.supported_composite_alpha
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
let image_format = device
|
||||||
|
.physical_device()
|
||||||
|
.surface_formats(&surface, Default::default())
|
||||||
|
.unwrap()[0]
|
||||||
|
.0;
|
||||||
|
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
Swapchain::new(
|
||||||
|
device.clone(),
|
||||||
if *recreate_swapchain {
|
surface,
|
||||||
let (new_swapchain, new_images) = swapchain
|
SwapchainCreateInfo {
|
||||||
.recreate(SwapchainCreateInfo {
|
min_image_count: surface_caps.min_image_count.max(2),
|
||||||
image_extent,
|
image_format,
|
||||||
..swapchain.create_info()
|
image_extent: window.inner_size().into(),
|
||||||
})
|
image_usage: ImageUsage::COLOR_ATTACHMENT,
|
||||||
.expect("failed to recreate swapchain");
|
composite_alpha,
|
||||||
|
..Default::default()
|
||||||
*swapchain = new_swapchain;
|
},
|
||||||
*framebuffers =
|
)
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
.unwrap()
|
||||||
*recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
*recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if suboptimal {
|
window_surfaces.insert(
|
||||||
*recreate_swapchain = true;
|
window_id,
|
||||||
}
|
WindowSurface {
|
||||||
|
window,
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
swapchain,
|
||||||
&command_buffer_allocator,
|
recreate_swapchain: false,
|
||||||
queue.queue_family_index(),
|
framebuffers: window_size_dependent_setup(
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
&images,
|
||||||
)
|
render_pass.clone(),
|
||||||
.unwrap();
|
&mut viewport,
|
||||||
|
),
|
||||||
builder
|
previous_frame_end: Some(sync::now(device.clone()).boxed()),
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
Default::default(),
|
);
|
||||||
)
|
}
|
||||||
.unwrap()
|
Event::WindowEvent {
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
event: WindowEvent::RedrawRequested,
|
||||||
.unwrap()
|
window_id,
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
} => {
|
||||||
.unwrap()
|
let WindowSurface {
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
window,
|
||||||
.unwrap()
|
swapchain,
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
recreate_swapchain,
|
||||||
.unwrap()
|
framebuffers,
|
||||||
.end_render_pass(Default::default())
|
previous_frame_end,
|
||||||
.unwrap();
|
} = window_surfaces.get_mut(&window_id).unwrap();
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
if image_extent.contains(&0) {
|
||||||
Ok(future) => {
|
return;
|
||||||
*previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if *recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
*swapchain = new_swapchain;
|
||||||
|
*framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
*recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
*recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
*recreate_swapchain = true;
|
*recreate_swapchain = true;
|
||||||
*previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
*previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
*previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
*recreate_swapchain = true;
|
||||||
|
*previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
*previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => {
|
||||||
|
window_surfaces
|
||||||
|
.values()
|
||||||
|
.for_each(|s| s.window.request_redraw());
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_size_dependent_setup(
|
fn window_size_dependent_setup(
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
// queries. Occlusion queries allow you to query whether, and sometimes how many, pixels pass the
|
// queries. Occlusion queries allow you to query whether, and sometimes how many, pixels pass the
|
||||||
// depth test in a range of draw calls.
|
// depth test in a range of draw calls.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -54,11 +54,11 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -335,9 +335,9 @@ fn main() {
|
|||||||
viewport_state: Some(ViewportState::default()),
|
viewport_state: Some(ViewportState::default()),
|
||||||
rasterization_state: Some(RasterizationState::default()),
|
rasterization_state: Some(RasterizationState::default()),
|
||||||
multisample_state: Some(MultisampleState::default()),
|
multisample_state: Some(MultisampleState::default()),
|
||||||
// Enable depth testing, which is needed for occlusion queries to make sense at all. If you
|
// Enable depth testing, which is needed for occlusion queries to make sense at
|
||||||
// disable depth testing, every pixel is considered to pass the depth test, so every query
|
// all. If you disable depth testing, every pixel is considered to pass the depth
|
||||||
// will return a nonzero result.
|
// test, so every query will return a nonzero result.
|
||||||
depth_stencil_state: Some(DepthStencilState {
|
depth_stencil_state: Some(DepthStencilState {
|
||||||
depth: Some(DepthState::simple()),
|
depth: Some(DepthState::simple()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -373,199 +373,211 @@ fn main() {
|
|||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers = window_size_dependent_setup(
|
|
||||||
&new_images,
|
|
||||||
render_pass.clone(),
|
|
||||||
&mut viewport,
|
|
||||||
memory_allocator.clone(),
|
|
||||||
);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Beginning or resetting a query is unsafe for now.
|
|
||||||
unsafe {
|
|
||||||
builder
|
|
||||||
// A query must be reset before each use, including the first use. This must be
|
|
||||||
// done outside a render pass.
|
|
||||||
.reset_query_pool(query_pool.clone(), 0..3)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into()), Some(1.0.into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
// Begin query 0, then draw the red triangle. Enabling the
|
|
||||||
// `QueryControlFlags::PRECISE` flag would give exact numeric results. This
|
|
||||||
// needs the `occlusion_query_precise` feature to be enabled on the device.
|
|
||||||
.begin_query(
|
|
||||||
query_pool.clone(),
|
|
||||||
0,
|
|
||||||
QueryControlFlags::empty(),
|
|
||||||
// QueryControlFlags::PRECISE,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, triangle1.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(triangle1.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
// End query 0.
|
|
||||||
.end_query(query_pool.clone(), 0)
|
|
||||||
.unwrap()
|
|
||||||
// Begin query 1 for the cyan triangle.
|
|
||||||
.begin_query(query_pool.clone(), 1, QueryControlFlags::empty())
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, triangle2.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(triangle2.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_query(query_pool.clone(), 1)
|
|
||||||
.unwrap()
|
|
||||||
// Finally, query 2 for the green triangle.
|
|
||||||
.begin_query(query_pool.clone(), 2, QueryControlFlags::empty())
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, triangle3.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(triangle3.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_query(query_pool.clone(), 2)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
memory_allocator.clone(),
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Beginning or resetting a query is unsafe for now.
|
||||||
|
unsafe {
|
||||||
|
builder
|
||||||
|
// A query must be reset before each use, including the first use. This
|
||||||
|
// must be done outside a render pass.
|
||||||
|
.reset_query_pool(query_pool.clone(), 0..3)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![
|
||||||
|
Some([0.0, 0.0, 1.0, 1.0].into()),
|
||||||
|
Some(1.0.into()),
|
||||||
|
],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
// Begin query 0, then draw the red triangle. Enabling the
|
||||||
|
// `QueryControlFlags::PRECISE` flag would give exact numeric results. This
|
||||||
|
// needs the `occlusion_query_precise` feature to be enabled on the device.
|
||||||
|
.begin_query(
|
||||||
|
query_pool.clone(),
|
||||||
|
0,
|
||||||
|
QueryControlFlags::empty(),
|
||||||
|
// QueryControlFlags::PRECISE,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, triangle1.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(triangle1.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
// End query 0.
|
||||||
|
.end_query(query_pool.clone(), 0)
|
||||||
|
.unwrap()
|
||||||
|
// Begin query 1 for the cyan triangle.
|
||||||
|
.begin_query(query_pool.clone(), 1, QueryControlFlags::empty())
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, triangle2.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(triangle2.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_query(query_pool.clone(), 1)
|
||||||
|
.unwrap()
|
||||||
|
// Finally, query 2 for the green triangle.
|
||||||
|
.begin_query(query_pool.clone(), 2, QueryControlFlags::empty())
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, triangle3.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(triangle3.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_query(query_pool.clone(), 2)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the query results. This copies the results to a variable on the CPU.
|
||||||
|
// You can also use the `copy_query_pool_results` function on a command buffer to
|
||||||
|
// write results to a Vulkano buffer. This could then be used to influence draw
|
||||||
|
// operations further down the line, either in the same frame or a future frame.
|
||||||
|
#[rustfmt::skip]
|
||||||
|
query_pool.get_results(
|
||||||
|
0..3,
|
||||||
|
&mut query_results,
|
||||||
|
// Block the function call until the results are available.
|
||||||
|
// NOTE: If not all the queries have actually been executed, then this will
|
||||||
|
// wait forever for something that never happens!
|
||||||
|
QueryResultFlags::WAIT
|
||||||
|
|
||||||
|
// Enable this flag to give partial results if available, instead of waiting
|
||||||
|
// for the full results.
|
||||||
|
// | QueryResultFlags::PARTIAL
|
||||||
|
|
||||||
|
// Blocking and waiting will ensure the results are always available after the
|
||||||
|
// function returns.
|
||||||
|
//
|
||||||
|
// If you disable waiting, then this flag can be enabled to include the
|
||||||
|
// availability of each query's results. You need one extra element per query
|
||||||
|
// in your `query_results` buffer for this. This element will be filled with a
|
||||||
|
// zero/nonzero value indicating availability.
|
||||||
|
// | QueryResultFlags::WITH_AVAILABILITY
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// If the `precise` bit was not enabled, then you're only guaranteed to get a
|
||||||
|
// boolean result here: zero if all pixels were occluded, nonzero if only some were
|
||||||
|
// occluded. Enabling `precise` will give the exact number of pixels.
|
||||||
|
|
||||||
|
// Query 0 (red triangle) will always succeed, because the depth buffer starts
|
||||||
|
// empty and will never occlude anything.
|
||||||
|
assert_ne!(query_results[0], 0);
|
||||||
|
|
||||||
|
// Query 1 (cyan triangle) will fail, because it's drawn completely behind the
|
||||||
|
// first.
|
||||||
|
assert_eq!(query_results[1], 0);
|
||||||
|
|
||||||
|
// Query 2 (green triangle) will succeed, because it's only partially occluded.
|
||||||
|
assert_ne!(query_results[2], 0);
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
// Retrieve the query results. This copies the results to a variable on the CPU. You
|
_ => (),
|
||||||
// can also use the `copy_query_pool_results` function on a command buffer to write
|
|
||||||
// results to a Vulkano buffer. This could then be used to influence draw operations
|
|
||||||
// further down the line, either in the same frame or a future frame.
|
|
||||||
#[rustfmt::skip]
|
|
||||||
query_pool.get_results(
|
|
||||||
0..3,
|
|
||||||
&mut query_results,
|
|
||||||
// Block the function call until the results are available.
|
|
||||||
// NOTE: If not all the queries have actually been executed, then this will
|
|
||||||
// wait forever for something that never happens!
|
|
||||||
QueryResultFlags::WAIT
|
|
||||||
|
|
||||||
// Enable this flag to give partial results if available, instead of waiting
|
|
||||||
// for the full results.
|
|
||||||
// | QueryResultFlags::PARTIAL
|
|
||||||
|
|
||||||
// Blocking and waiting will ensure the results are always available after the
|
|
||||||
// function returns.
|
|
||||||
//
|
|
||||||
// If you disable waiting, then this flag can be enabled to include the
|
|
||||||
// availability of each query's results. You need one extra element per query
|
|
||||||
// in your `query_results` buffer for this. This element will be filled with a
|
|
||||||
// zero/nonzero value indicating availability.
|
|
||||||
// | QueryResultFlags::WITH_AVAILABILITY
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// If the `precise` bit was not enabled, then you're only guaranteed to get a boolean
|
|
||||||
// result here: zero if all pixels were occluded, nonzero if only some were occluded.
|
|
||||||
// Enabling `precise` will give the exact number of pixels.
|
|
||||||
|
|
||||||
// Query 0 (red triangle) will always succeed, because the depth buffer starts empty
|
|
||||||
// and will never occlude anything.
|
|
||||||
assert_ne!(query_results[0], 0);
|
|
||||||
|
|
||||||
// Query 1 (cyan triangle) will fail, because it's drawn completely behind the first.
|
|
||||||
assert_eq!(query_results[1], 0);
|
|
||||||
|
|
||||||
// Query 2 (green triangle) will succeed, because it's only partially occluded.
|
|
||||||
assert_ne!(query_results[2], 0);
|
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_size_dependent_setup(
|
fn window_size_dependent_setup(
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// notice may not be copied, modified, or distributed except
|
// notice may not be copied, modified, or distributed except
|
||||||
// according to those terms.
|
// according to those terms.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -54,11 +54,11 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -353,127 +353,138 @@ fn main() {
|
|||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.push_descriptor_set(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
// If the binding is an immutable sampler, using push descriptors
|
|
||||||
// you must write a dummy value to the binding.
|
|
||||||
WriteDescriptorSet::none(0),
|
|
||||||
WriteDescriptorSet::image_view(1, texture.clone()),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.push_descriptor_set(
|
||||||
|
PipelineBindPoint::Graphics,
|
||||||
|
pipeline.layout().clone(),
|
||||||
|
0,
|
||||||
|
[
|
||||||
|
// If the binding is an immutable sampler, using push descriptors
|
||||||
|
// you must write a dummy value to the binding.
|
||||||
|
WriteDescriptorSet::none(0),
|
||||||
|
WriteDescriptorSet::image_view(1, texture.clone()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// notice may not be copied, modified, or distributed except
|
// notice may not be copied, modified, or distributed except
|
||||||
// according to those terms.
|
// according to those terms.
|
||||||
|
|
||||||
use std::{io::Cursor, sync::Arc};
|
use std::{error::Error, io::Cursor, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -57,14 +57,14 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
||||||
// example if you haven't done so yet.
|
// example if you haven't done so yet.
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -484,120 +484,131 @@ fn main() {
|
|||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.bind_descriptor_sets(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
set.clone(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_descriptor_sets(
|
||||||
|
PipelineBindPoint::Graphics,
|
||||||
|
pipeline.layout().clone(),
|
||||||
|
0,
|
||||||
|
set.clone(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
//
|
//
|
||||||
// Vulkano uses shaderc to build your shaders internally.
|
// Vulkano uses shaderc to build your shaders internally.
|
||||||
|
|
||||||
use std::{fs::File, io::Read, path::Path, sync::Arc};
|
use std::{error::Error, fs::File, io::Read, path::Path, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -62,11 +62,11 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -296,113 +296,124 @@ fn main() {
|
|||||||
let command_buffer_allocator =
|
let command_buffer_allocator =
|
||||||
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::MultipleSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(graphics_pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::MultipleSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(graphics_pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// staging buffer and then copying the data to a device-local buffer to be accessed solely by the
|
// staging buffer and then copying the data to a device-local buffer to be accessed solely by the
|
||||||
// GPU through the compute shader and as a vertex array.
|
// GPU through the compute shader and as a vertex array.
|
||||||
|
|
||||||
use std::{sync::Arc, time::SystemTime};
|
use std::{error::Error, sync::Arc, time::SystemTime};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -63,13 +63,13 @@ const WINDOW_HEIGHT: u32 = 600;
|
|||||||
|
|
||||||
const PARTICLE_COUNT: usize = 100_000;
|
const PARTICLE_COUNT: usize = 100_000;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// The usual Vulkan initialization. Largely the same as example `triangle.rs` until further
|
// The usual Vulkan initialization. Largely the same as example `triangle.rs` until further
|
||||||
// commentation is provided.
|
// commentation is provided.
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -521,15 +521,20 @@ fn main() {
|
|||||||
|
|
||||||
let start_time = SystemTime::now();
|
let start_time = SystemTime::now();
|
||||||
let mut last_frame_time = start_time;
|
let mut last_frame_time = start_time;
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
if image_extent.contains(&0) {
|
||||||
@ -644,7 +649,8 @@ fn main() {
|
|||||||
};
|
};
|
||||||
previous_fence_index = image_index;
|
previous_fence_index = image_index;
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
use self::model::{Normal, Position, INDICES, NORMALS, POSITIONS};
|
use self::model::{Normal, Position, INDICES, NORMALS, POSITIONS};
|
||||||
use cgmath::{Matrix3, Matrix4, Point3, Rad, Vector3};
|
use cgmath::{Matrix3, Matrix4, Point3, Rad, Vector3};
|
||||||
use std::{sync::Arc, time::Instant};
|
use std::{error::Error, sync::Arc, time::Instant};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{
|
buffer::{
|
||||||
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
||||||
@ -55,20 +55,20 @@ use vulkano::{
|
|||||||
};
|
};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, WindowEvent},
|
event::{Event, WindowEvent},
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::EventLoop,
|
||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
// The start of this example is exactly the same as `triangle`. You should read the `triangle`
|
||||||
// example if you haven't done so yet.
|
// example if you haven't done so yet.
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -265,13 +265,13 @@ fn main() {
|
|||||||
let command_buffer_allocator =
|
let command_buffer_allocator =
|
||||||
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -279,7 +279,10 @@ fn main() {
|
|||||||
} => {
|
} => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
if image_extent.contains(&0) {
|
||||||
@ -432,9 +435,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
// - `tessellation_shaders` and `tessellation_state` are called on the pipeline builder.
|
// - `tessellation_shaders` and `tessellation_state` are called on the pipeline builder.
|
||||||
// - The use of `PrimitiveTopology::PatchList`.
|
// - The use of `PrimitiveTopology::PatchList`.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -159,11 +159,11 @@ mod fs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -414,113 +414,124 @@ fn main() {
|
|||||||
let command_buffer_allocator =
|
let command_buffer_allocator =
|
||||||
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
StandardCommandBufferAllocator::new(device.clone(), Default::default());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// notice may not be copied, modified, or distributed except
|
// notice may not be copied, modified, or distributed except
|
||||||
// according to those terms.
|
// according to those terms.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -56,16 +56,16 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
// This example is about this:
|
// This example is about this:
|
||||||
// uniform sampler2DArray texture_array;
|
// uniform sampler2DArray texture_array;
|
||||||
// And not this:
|
// And not this:
|
||||||
// uniform sampler2D array_of_textures[42];
|
// uniform sampler2D array_of_textures[42];
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
InstanceCreateInfo {
|
InstanceCreateInfo {
|
||||||
@ -374,120 +374,131 @@ fn main() {
|
|||||||
.boxed(),
|
.boxed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, elwt| {
|
||||||
Event::WindowEvent {
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
|
||||||
|
|
||||||
if image_extent.contains(&0) {
|
match event {
|
||||||
return;
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
elwt.exit();
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
if recreate_swapchain {
|
} => {
|
||||||
let (new_swapchain, new_images) = swapchain
|
|
||||||
.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent,
|
|
||||||
..swapchain.create_info()
|
|
||||||
})
|
|
||||||
.expect("failed to recreate swapchain");
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
framebuffers =
|
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
if image_extent.contains(&0) {
|
||||||
&command_buffer_allocator,
|
return;
|
||||||
queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.begin_render_pass(
|
|
||||||
RenderPassBeginInfo {
|
|
||||||
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
|
||||||
..RenderPassBeginInfo::framebuffer(
|
|
||||||
framebuffers[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap()
|
|
||||||
.bind_pipeline_graphics(pipeline.clone())
|
|
||||||
.unwrap()
|
|
||||||
.bind_descriptor_sets(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
set.clone(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
|
||||||
.unwrap()
|
|
||||||
.draw(vertex_buffer.len() as u32, 3, 0, 0)
|
|
||||||
.unwrap()
|
|
||||||
.end_render_pass(Default::default())
|
|
||||||
.unwrap();
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
}
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
|
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let (new_swapchain, new_images) = swapchain
|
||||||
|
.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent,
|
||||||
|
..swapchain.create_info()
|
||||||
|
})
|
||||||
|
.expect("failed to recreate swapchain");
|
||||||
|
|
||||||
|
swapchain = new_swapchain;
|
||||||
|
framebuffers = window_size_dependent_setup(
|
||||||
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_index, suboptimal, acquire_future) =
|
||||||
|
match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed to acquire next image: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
&command_buffer_allocator,
|
||||||
|
queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
builder
|
||||||
|
.begin_render_pass(
|
||||||
|
RenderPassBeginInfo {
|
||||||
|
clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())],
|
||||||
|
..RenderPassBeginInfo::framebuffer(
|
||||||
|
framebuffers[image_index as usize].clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.set_viewport(0, [viewport.clone()].into_iter().collect())
|
||||||
|
.unwrap()
|
||||||
|
.bind_pipeline_graphics(pipeline.clone())
|
||||||
|
.unwrap()
|
||||||
|
.bind_descriptor_sets(
|
||||||
|
PipelineBindPoint::Graphics,
|
||||||
|
pipeline.layout().clone(),
|
||||||
|
0,
|
||||||
|
set.clone(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||||
|
.unwrap()
|
||||||
|
.draw(vertex_buffer.len() as u32, 3, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.end_render_pass(Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
|
let future = previous_frame_end
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.join(acquire_future)
|
||||||
|
.then_execute(queue.clone(), command_buffer)
|
||||||
|
.unwrap()
|
||||||
|
.then_swapchain_present(
|
||||||
|
queue.clone(),
|
||||||
|
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
||||||
|
)
|
||||||
|
.then_signal_fence_and_flush();
|
||||||
|
|
||||||
|
match future.map_err(Validated::unwrap) {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(future.boxed());
|
||||||
|
}
|
||||||
|
Err(VulkanError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("failed to flush future: {e}");
|
||||||
|
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
// `khr_dynamic_rendering` extension, or if you want to see how to support older versions, see the
|
// `khr_dynamic_rendering` extension, or if you want to see how to support older versions, see the
|
||||||
// original triangle example.
|
// original triangle example.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -62,8 +62,8 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ fn main() {
|
|||||||
// All the window-drawing functionalities are part of non-core extensions that we need to
|
// All the window-drawing functionalities are part of non-core extensions that we need to
|
||||||
// enable manually. To do so, we ask `Surface` for the list of extensions required to draw to
|
// enable manually. To do so, we ask `Surface` for the list of extensions required to draw to
|
||||||
// a window.
|
// a window.
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
|
|
||||||
// Now creating the instance.
|
// Now creating the instance.
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
@ -515,13 +515,15 @@ fn main() {
|
|||||||
// that, we store the submission of the previous frame here.
|
// that, we store the submission of the previous frame here.
|
||||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -529,7 +531,10 @@ fn main() {
|
|||||||
} => {
|
} => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
// Do not draw the frame when the screen size is zero. On Windows, this can
|
// Do not draw the frame when the screen size is zero. On Windows, this can
|
||||||
// occur when minimizing the application.
|
// occur when minimizing the application.
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
@ -688,9 +693,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
// that you want to learn Vulkan. This means that for example it won't go into details about what a
|
// that you want to learn Vulkan. This means that for example it won't go into details about what a
|
||||||
// vertex or a shader is.
|
// vertex or a shader is.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{error::Error, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
@ -56,8 +56,8 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
window::WindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), impl Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ fn main() {
|
|||||||
// All the window-drawing functionalities are part of non-core extensions that we need to
|
// All the window-drawing functionalities are part of non-core extensions that we need to
|
||||||
// enable manually. To do so, we ask `Surface` for the list of extensions required to draw to
|
// enable manually. To do so, we ask `Surface` for the list of extensions required to draw to
|
||||||
// a window.
|
// a window.
|
||||||
let required_extensions = Surface::required_extensions(&event_loop);
|
let required_extensions = Surface::required_extensions(&event_loop).unwrap();
|
||||||
|
|
||||||
// Now creating the instance.
|
// Now creating the instance.
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
@ -512,13 +512,15 @@ fn main() {
|
|||||||
// that, we store the submission of the previous frame here.
|
// that, we store the submission of the previous frame here.
|
||||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, elwt| {
|
||||||
|
elwt.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*control_flow = ControlFlow::Exit;
|
elwt.exit();
|
||||||
}
|
}
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(_),
|
event: WindowEvent::Resized(_),
|
||||||
@ -526,7 +528,10 @@ fn main() {
|
|||||||
} => {
|
} => {
|
||||||
recreate_swapchain = true;
|
recreate_swapchain = true;
|
||||||
}
|
}
|
||||||
Event::RedrawEventsCleared => {
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
// Do not draw the frame when the screen size is zero. On Windows, this can
|
// Do not draw the frame when the screen size is zero. On Windows, this can
|
||||||
// occur when minimizing the application.
|
// occur when minimizing the application.
|
||||||
let image_extent: [u32; 2] = window.inner_size().into();
|
let image_extent: [u32; 2] = window.inner_size().into();
|
||||||
@ -687,9 +692,10 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::AboutToWait => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
/// This function is called once during initialization, then again whenever the window is resized.
|
||||||
|
@ -12,7 +12,7 @@ use proc_macro2::TokenStream;
|
|||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse_quote, spanned::Spanned, Data, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Ident,
|
parse_quote, spanned::Spanned, Data, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Ident,
|
||||||
Meta, MetaList, NestedMeta, Result, Type, TypeArray, TypeSlice, WherePredicate,
|
Result, Type, TypeArray, TypeSlice, WherePredicate,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn derive_buffer_contents(mut ast: DeriveInput) -> Result<TokenStream> {
|
pub fn derive_buffer_contents(mut ast: DeriveInput) -> Result<TokenStream> {
|
||||||
@ -20,23 +20,26 @@ pub fn derive_buffer_contents(mut ast: DeriveInput) -> Result<TokenStream> {
|
|||||||
|
|
||||||
let struct_ident = &ast.ident;
|
let struct_ident = &ast.ident;
|
||||||
|
|
||||||
if !ast
|
let is_repr_rust = ast
|
||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&attr| attr.path.is_ident("repr"))
|
.filter(|&attr| attr.path().is_ident("repr"))
|
||||||
.map(|attr| attr.parse_meta().unwrap())
|
.map(|attr| {
|
||||||
.any(|meta| match meta {
|
let mut is_repr_rust = true;
|
||||||
Meta::List(MetaList { nested, .. }) => {
|
|
||||||
nested.iter().any(|nested_meta| match nested_meta {
|
let _ = attr.parse_nested_meta(|meta| {
|
||||||
NestedMeta::Meta(Meta::Path(path)) => {
|
if meta.path.is_ident("C") || meta.path.is_ident("transparent") {
|
||||||
path.is_ident("C") || path.is_ident("transparent")
|
is_repr_rust = false;
|
||||||
}
|
}
|
||||||
_ => false,
|
|
||||||
})
|
Ok(())
|
||||||
}
|
});
|
||||||
_ => false,
|
|
||||||
|
is_repr_rust
|
||||||
})
|
})
|
||||||
{
|
.all(|b| b);
|
||||||
|
|
||||||
|
if is_repr_rust {
|
||||||
bail!(
|
bail!(
|
||||||
"deriving `BufferContents` is only supported for types that are marked `#[repr(C)]` \
|
"deriving `BufferContents` is only supported for types that are marked `#[repr(C)]` \
|
||||||
or `#[repr(transparent)]`",
|
or `#[repr(transparent)]`",
|
||||||
|
@ -41,7 +41,7 @@ pub fn derive_vertex(ast: syn::DeriveInput) -> Result<TokenStream> {
|
|||||||
let mut names = vec![field_name_lit.clone()];
|
let mut names = vec![field_name_lit.clone()];
|
||||||
let mut format = quote! {};
|
let mut format = quote! {};
|
||||||
for attr in &field.attrs {
|
for attr in &field.attrs {
|
||||||
let attr_ident = if let Some(ident) = attr.path.get_ident() {
|
let attr_ident = if let Some(ident) = attr.path().get_ident() {
|
||||||
ident
|
ident
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
@ -134,7 +134,7 @@ struct NameMeta {
|
|||||||
impl Parse for NameMeta {
|
impl Parse for NameMeta {
|
||||||
fn parse(input: ParseStream) -> Result<Self> {
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
lit_str_list: input.parse_terminated(<LitStr as Parse>::parse)?,
|
lit_str_list: input.parse_terminated(<LitStr as Parse>::parse, Token![,])?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ half = { workspace = true, features = ["bytemuck"] }
|
|||||||
libloading = { workspace = true }
|
libloading = { workspace = true }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
parking_lot = { workspace = true, features = ["send_guard"] }
|
parking_lot = { workspace = true, features = ["send_guard"] }
|
||||||
raw-window-handle = { workspace = true }
|
raw-window-handle = { workspace = true, features = ["std"] }
|
||||||
serde = { workspace = true, optional = true }
|
serde = { workspace = true, optional = true }
|
||||||
smallvec = { workspace = true }
|
smallvec = { workspace = true }
|
||||||
thread_local = { workspace = true }
|
thread_local = { workspace = true }
|
||||||
|
@ -22,12 +22,13 @@ use crate::{
|
|||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
use objc::{class, msg_send, runtime::Object, sel, sel_impl};
|
use objc::{class, msg_send, runtime::Object, sel, sel_impl};
|
||||||
use raw_window_handle::{
|
use raw_window_handle::{
|
||||||
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
|
HandleError, HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
fmt::{Debug, Error as FmtError, Formatter},
|
error::Error,
|
||||||
|
fmt::{Debug, Display, Error as FmtError, Formatter},
|
||||||
mem::MaybeUninit,
|
mem::MaybeUninit,
|
||||||
num::NonZeroU64,
|
num::NonZeroU64,
|
||||||
ptr,
|
ptr,
|
||||||
@ -60,12 +61,14 @@ pub struct Surface {
|
|||||||
impl Surface {
|
impl Surface {
|
||||||
/// Returns the instance extensions required to create a surface from a window of the given
|
/// Returns the instance extensions required to create a surface from a window of the given
|
||||||
/// event loop.
|
/// event loop.
|
||||||
pub fn required_extensions(event_loop: &impl HasRawDisplayHandle) -> InstanceExtensions {
|
pub fn required_extensions(
|
||||||
|
event_loop: &impl HasDisplayHandle,
|
||||||
|
) -> Result<InstanceExtensions, HandleError> {
|
||||||
let mut extensions = InstanceExtensions {
|
let mut extensions = InstanceExtensions {
|
||||||
khr_surface: true,
|
khr_surface: true,
|
||||||
..InstanceExtensions::empty()
|
..InstanceExtensions::empty()
|
||||||
};
|
};
|
||||||
match event_loop.raw_display_handle() {
|
match event_loop.display_handle()?.as_raw() {
|
||||||
RawDisplayHandle::Android(_) => extensions.khr_android_surface = true,
|
RawDisplayHandle::Android(_) => extensions.khr_android_surface = true,
|
||||||
// FIXME: `mvk_macos_surface` and `mvk_ios_surface` are deprecated.
|
// FIXME: `mvk_macos_surface` and `mvk_ios_surface` are deprecated.
|
||||||
RawDisplayHandle::AppKit(_) => extensions.mvk_macos_surface = true,
|
RawDisplayHandle::AppKit(_) => extensions.mvk_macos_surface = true,
|
||||||
@ -77,14 +80,14 @@ impl Surface {
|
|||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
extensions
|
Ok(extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `Surface` from the given `window`.
|
/// Creates a new `Surface` from the given `window`.
|
||||||
pub fn from_window(
|
pub fn from_window(
|
||||||
instance: Arc<Instance>,
|
instance: Arc<Instance>,
|
||||||
window: Arc<impl HasRawWindowHandle + HasRawDisplayHandle + Any + Send + Sync>,
|
window: Arc<impl HasWindowHandle + HasDisplayHandle + Any + Send + Sync>,
|
||||||
) -> Result<Arc<Self>, Validated<VulkanError>> {
|
) -> Result<Arc<Self>, FromWindowError> {
|
||||||
let mut surface = unsafe { Self::from_window_ref(instance, &*window) }?;
|
let mut surface = unsafe { Self::from_window_ref(instance, &*window) }?;
|
||||||
Arc::get_mut(&mut surface).unwrap().object = Some(window);
|
Arc::get_mut(&mut surface).unwrap().object = Some(window);
|
||||||
|
|
||||||
@ -99,43 +102,67 @@ impl Surface {
|
|||||||
/// - The given `window` must outlive the created surface.
|
/// - The given `window` must outlive the created surface.
|
||||||
pub unsafe fn from_window_ref(
|
pub unsafe fn from_window_ref(
|
||||||
instance: Arc<Instance>,
|
instance: Arc<Instance>,
|
||||||
window: &(impl HasRawWindowHandle + HasRawDisplayHandle),
|
window: &(impl HasWindowHandle + HasDisplayHandle),
|
||||||
) -> Result<Arc<Self>, Validated<VulkanError>> {
|
) -> Result<Arc<Self>, FromWindowError> {
|
||||||
match (window.raw_window_handle(), window.raw_display_handle()) {
|
let window_handle = window
|
||||||
|
.window_handle()
|
||||||
|
.map_err(FromWindowError::RetrieveHandle)?;
|
||||||
|
let display_handle = window
|
||||||
|
.display_handle()
|
||||||
|
.map_err(FromWindowError::RetrieveHandle)?;
|
||||||
|
|
||||||
|
match (window_handle.as_raw(), display_handle.as_raw()) {
|
||||||
(RawWindowHandle::AndroidNdk(window), RawDisplayHandle::Android(_display)) => {
|
(RawWindowHandle::AndroidNdk(window), RawDisplayHandle::Android(_display)) => {
|
||||||
Self::from_android(instance, window.a_native_window, None)
|
Self::from_android(instance, window.a_native_window.as_ptr(), None)
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
(RawWindowHandle::AppKit(window), RawDisplayHandle::AppKit(_display)) => {
|
(RawWindowHandle::AppKit(window), RawDisplayHandle::AppKit(_display)) => {
|
||||||
// Ensure the layer is `CAMetalLayer`.
|
// Ensure the layer is `CAMetalLayer`.
|
||||||
let layer = get_metal_layer_macos(window.ns_view);
|
let layer = get_metal_layer_macos(window.ns_view.as_ptr());
|
||||||
|
|
||||||
Self::from_mac_os(instance, layer as *const (), None)
|
Self::from_mac_os(instance, layer as *const (), None)
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
(RawWindowHandle::UiKit(window), RawDisplayHandle::UiKit(_display)) => {
|
(RawWindowHandle::UiKit(window), RawDisplayHandle::UiKit(_display)) => {
|
||||||
// Ensure the layer is `CAMetalLayer`.
|
// Ensure the layer is `CAMetalLayer`.
|
||||||
let layer = get_metal_layer_ios(window.ui_view);
|
let layer = get_metal_layer_ios(window.ui_view.as_ptr());
|
||||||
|
|
||||||
Self::from_ios(instance, layer, None)
|
Self::from_ios(instance, layer, None)
|
||||||
}
|
}
|
||||||
(RawWindowHandle::Wayland(window), RawDisplayHandle::Wayland(display)) => {
|
(RawWindowHandle::Wayland(window), RawDisplayHandle::Wayland(display)) => {
|
||||||
Self::from_wayland(instance, display.display, window.surface, None)
|
Self::from_wayland(
|
||||||
|
instance,
|
||||||
|
display.display.as_ptr(),
|
||||||
|
window.surface.as_ptr(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(RawWindowHandle::Win32(window), RawDisplayHandle::Windows(_display)) => {
|
(RawWindowHandle::Win32(window), RawDisplayHandle::Windows(_display)) => {
|
||||||
Self::from_win32(instance, window.hinstance, window.hwnd, None)
|
Self::from_win32(
|
||||||
}
|
instance,
|
||||||
(RawWindowHandle::Xcb(window), RawDisplayHandle::Xcb(display)) => {
|
window.hinstance.unwrap().get() as *const (),
|
||||||
Self::from_xcb(instance, display.connection, window.window, None)
|
window.hwnd.get() as *const (),
|
||||||
}
|
None,
|
||||||
(RawWindowHandle::Xlib(window), RawDisplayHandle::Xlib(display)) => {
|
)
|
||||||
Self::from_xlib(instance, display.display, window.window, None)
|
|
||||||
}
|
}
|
||||||
|
(RawWindowHandle::Xcb(window), RawDisplayHandle::Xcb(display)) => Self::from_xcb(
|
||||||
|
instance,
|
||||||
|
display.connection.unwrap().as_ptr(),
|
||||||
|
window.window.get(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
(RawWindowHandle::Xlib(window), RawDisplayHandle::Xlib(display)) => Self::from_xlib(
|
||||||
|
instance,
|
||||||
|
display.display.unwrap().as_ptr(),
|
||||||
|
window.window,
|
||||||
|
None,
|
||||||
|
),
|
||||||
_ => unimplemented!(
|
_ => unimplemented!(
|
||||||
"the window was created with a windowing API that is not supported \
|
"the window was created with a windowing API that is not supported \
|
||||||
by Vulkan/Vulkano"
|
by Vulkan/Vulkano"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
.map_err(FromWindowError::CreateSurface)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Surface` from a raw handle.
|
/// Creates a `Surface` from a raw handle.
|
||||||
@ -2335,6 +2362,35 @@ pub struct SurfaceCapabilities {
|
|||||||
pub full_screen_exclusive_supported: bool,
|
pub full_screen_exclusive_supported: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error that can happen when creating a [`Surface`] from a window.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum FromWindowError {
|
||||||
|
/// Retrieving the window or display handle failed.
|
||||||
|
RetrieveHandle(HandleError),
|
||||||
|
/// Creating the surface failed.
|
||||||
|
CreateSurface(Validated<VulkanError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for FromWindowError {
|
||||||
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
|
match self {
|
||||||
|
Self::RetrieveHandle(err) => Some(err),
|
||||||
|
Self::CreateSurface(err) => Some(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for FromWindowError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||||
|
match self {
|
||||||
|
Self::RetrieveHandle(_) => {
|
||||||
|
write!(f, "retrieving the window or display handle has failed")
|
||||||
|
}
|
||||||
|
Self::CreateSurface(_) => write!(f, "creating the surface has failed"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Loading…
Reference in New Issue
Block a user