vulkayes_core/queue/
macros.rs

1/// This macro is intended to substitute for const generics when transforming input arguments to the [Queue::submit](queue/struct.Queue.html#method.submit) function.
2///
3/// Usage:
4/// ```
5/// # #[macro_use] extern crate vulkayes_core;
6/// const_queue_submit!(
7/// 	pub fn submit_one(
8/// 		&queue,
9/// 		waits: [&Semaphore; 1],
10/// 		stages: [vk::PipelineStageFlags; _],
11/// 		buffers: [&CommandBuffer; 1],
12/// 		signals: [&Semaphore; 1],
13/// 		fence: Option<&Fence>
14/// 	) -> Result<(), QueueSubmitError>;
15/// );
16/// ```
17///
18/// this expands to something like the [Queue::submit_one](queue/struct.Queue.html#method.submit_one)
19#[macro_export]
20macro_rules! const_queue_submit {
21	(
22		$(#[$attribute: meta])*
23		pub fn $name: ident (
24			&queue,
25			$waits: ident: [&Semaphore; $count_waits: literal],
26			stages: [vk::PipelineStageFlags; _],
27			$buffers: ident: [&CommandBuffer; $count_buffers: literal],
28			$signals: ident: [&Semaphore; $count_signals: literal],
29			fence: Option<&Fence>
30		) -> Result<(), QueueSubmitError>;
31	) => {
32		$(#[$attribute])*
33		#[allow(unused_variables)]
34		#[allow(unused_imports)]
35		pub fn $name(
36			queue: &$crate::queue::Queue,
37			$waits: [&$crate::sync::semaphore::Semaphore; $count_waits],
38			stages: [$crate::ash::vk::PipelineStageFlags; $count_waits],
39			$buffers: [&$crate::command::buffer::CommandBuffer; $count_buffers],
40			$signals: [&$crate::sync::semaphore::Semaphore; $count_signals],
41			fence: Option<&$crate::sync::fence::Fence>
42		) -> Result<(), $crate::queue::error::QueueSubmitError> {
43			use $crate::queue::error::QueueSubmitError;
44			use $crate::util::sync::VutexGuard;
45			use $crate::ash::vk;
46
47			#[cfg(feature = "runtime_implicit_validations")]
48			{
49				for stage in stages.iter() {
50					if stage.is_empty() {
51						return Err(QueueSubmitError::WaitStagesEmpty)
52					}
53				}
54				{ // check that all waits, buffers and signals come from the same device
55					if !$crate::util::validations::validate_all_match(
56						$waits.iter().map(|w| w.device()).chain(
57							$buffers.iter().map(|b| b.pool().device())
58						).chain(
59							$signals.iter().map(|s| s.device())
60						)
61					) {
62						return Err(QueueSubmitError::WaitBufferSignalDeviceMismatch)
63					}
64				}
65				for cb in $buffers.iter() {
66					if cb.pool().queue_family_index() != queue.queue_family_index() {
67						return Err(QueueSubmitError::QueueFamilyMismatch)
68					}
69				}
70				if let Some(ref fence) = fence {
71					if queue.device() != fence.device() {
72						return Err(QueueSubmitError::QueueFenceDeviceMismatch)
73					}
74				}
75			}
76
77			$crate::lock_and_deref_closure!(
78				let [$waits; $count_waits]{.lock().expect("vutex poisoned")} => |$waits: [VutexGuard<vk::Semaphore>; $count_waits], w|
79				let [$buffers; $count_buffers]{.lock().expect("vutex poisoned")} => |$buffers: [VutexGuard<vk::CommandBuffer>; $count_buffers], b|
80				let [$signals; $count_signals]{.lock().expect("vutex poisoned")} => |$signals: [VutexGuard<vk::Semaphore>; $count_signals], s|
81				{
82					let submit_info = vk::SubmitInfo::builder()
83						.wait_semaphores(&w)
84						.wait_dst_stage_mask(&stages)
85						.command_buffers(&b)
86						.signal_semaphores(&s)
87						.build()
88					;
89
90					unsafe {
91						queue.submit(
92							[submit_info],
93							fence
94						)
95					}
96				}
97			)
98		}
99	}
100}
101
102/// This macro is intended to substitute for const generics when transforming input arguments to the [Swapchain::present](swapchain/struct.Swapchain.html#method.present) function.
103///
104/// Usage:
105/// ```
106/// # #[macro_use] extern crate vulkayes_core;
107/// const_queue_present!(
108/// 	pub fn present_one(
109/// 		&queue,
110/// 		waits: [&Semaphore; 1],
111/// 		images: [&SwapchainImage; 1],
112/// 		result_for_all: bool
113/// 	) -> QueuePresentMultipleResult<[QueuePresentResult; _]>;
114/// );
115/// ```
116///
117/// this expands to something like the [Queue::present_one](queue/struct.Queue.html#method.present_one)
118#[macro_export]
119macro_rules! const_queue_present {
120	(
121		$(#[$attribute: meta])*
122		pub fn $name: ident (
123			&queue,
124			$waits: ident: [&Semaphore; $count_waits: literal],
125			$images: ident: [&SwapchainImage; $count_images: literal],
126			result_for_all: bool
127		) -> QueuePresentMultipleResult<[QueuePresentResult; _]>;
128	) => {
129		$(#[$attribute])*
130		#[allow(unused_variables)]
131		#[allow(unused_imports)]
132		pub fn $name(
133			queue: &$crate::queue::Queue,
134			$waits: [&$crate::sync::semaphore::Semaphore; $count_waits],
135			$images: [&$crate::swapchain::image::SwapchainImage; $count_images],
136			result_for_all: bool
137		) -> $crate::queue::error::QueuePresentMultipleResult<[$crate::queue::error::QueuePresentResult; $count_images]> {
138			use $crate::queue::error::{QueuePresentMultipleResult, QueuePresentResult, QueuePresentResultValue, QueuePresentError};
139			use $crate::util::sync::VutexGuard;
140			use $crate::ash::vk;
141
142			#[cfg(feature = "runtime_implicit_validations")]
143			{
144				if $count_images == 0 {
145					return QueuePresentMultipleResult::Single(
146						Err(QueuePresentError::SwapchainsEmpty)
147					)
148				}
149				if !$crate::util::validations::validate_all_match(
150					$images.iter().map(|&i| i.device().instance()).chain(
151						$waits.iter().map(|&w| w.device().instance())
152					)
153				) {
154					return QueuePresentMultipleResult::Single(
155						Err(QueuePresentError::SwapchainsSempahoredInstanceMismatch)
156					)
157				}
158			}
159
160			// Choose any swapchain, we only need it for the `present` function which uses the loader
161			let any_swapchain = $images[0].swapchain();
162
163			let indices = $crate::seq_macro::seq!(
164				N in 0 .. $count_images {
165					[ #( $images[N].index(), )* ]
166				}
167			);
168
169			$crate::lock_and_deref_closure!(
170				let [$waits; $count_waits]{.lock().expect("vutex poisoned")} => |$waits: [VutexGuard<vk::Semaphore>; $count_waits], w|
171				let [$images; $count_images]{.swapchain().lock().expect("vutex poisoned")} => |$images: [VutexGuard<vk::SwapchainKHR>; $count_images], s|
172				{
173					let present_info = vk::PresentInfoKHR::builder()
174						.wait_semaphores(&w)
175						.swapchains(&s)
176						.image_indices(&indices)
177					;
178
179					if result_for_all {
180						// This variable should be named `results` but it breaks with `seq` because of macro hygiene.
181						let mut $name = [vk::Result::SUCCESS; $count_images];
182						let present_info = present_info.results(&mut $name);
183						let _ = unsafe {
184							any_swapchain.present(
185								queue,
186								present_info
187							)
188						};
189
190						let result_values: [QueuePresentResult; $count_images] = $crate::seq_macro::seq!(
191							N in 0 .. $count_images {
192								[
193									#(
194										match $name[N] {
195											vk::Result::SUCCESS => Ok(QueuePresentResultValue::SUCCESS),
196											vk::Result::SUBOPTIMAL_KHR => Ok(QueuePresentResultValue::SUBOPTIMAL_KHR),
197											err => Err(err.into())
198										},
199									)*
200								]
201							}
202						);
203						QueuePresentMultipleResult::Multiple(
204							result_values
205						)
206					} else {
207						unsafe {
208							any_swapchain.present(
209								queue,
210								present_info
211							).into()
212						}
213					}
214				}
215			)
216		}
217	}
218}