mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-24 07:45:13 +00:00
Add timeline semaphores (#2380)
* Add timeline semaphores * Remove leftover comment * Doc typo
This commit is contained in:
parent
1964ae7922
commit
f6cb0bb184
@ -128,7 +128,10 @@ use crate::{
|
||||
query::{QueryControlFlags, QueryPipelineStatisticFlags},
|
||||
range_map::RangeMap,
|
||||
render_pass::{Framebuffer, Subpass},
|
||||
sync::{semaphore::Semaphore, PipelineStageAccessFlags, PipelineStages},
|
||||
sync::{
|
||||
semaphore::{Semaphore, SemaphoreType},
|
||||
PipelineStageAccessFlags, PipelineStages,
|
||||
},
|
||||
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError,
|
||||
};
|
||||
use ahash::HashMap;
|
||||
@ -774,6 +777,7 @@ impl SubmitInfo {
|
||||
|
||||
let &SemaphoreSubmitInfo {
|
||||
semaphore: _,
|
||||
value: _,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
@ -791,6 +795,11 @@ impl SubmitInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// unsafe
|
||||
// VUID-VkSubmitInfo2-semaphore-03882
|
||||
// VUID-VkSubmitInfo2-semaphore-03883
|
||||
// VUID-VkSubmitInfo2-semaphore-03884
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -837,6 +846,18 @@ pub struct SemaphoreSubmitInfo {
|
||||
/// There is no default value.
|
||||
pub semaphore: Arc<Semaphore>,
|
||||
|
||||
/// If `semaphore.semaphore_type()` is [`SemaphoreType::Timeline`], specifies the value that
|
||||
/// will be used for the semaphore operation:
|
||||
/// - If it's a signal operation, then the semaphore's value will be set to this value
|
||||
/// when it is signaled.
|
||||
/// - If it's a wait operation, then the semaphore will wait until its value is greater than
|
||||
/// or equal to this value.
|
||||
///
|
||||
/// If `semaphore.semaphore_type()` is [`SemaphoreType::Binary`], then this must be `0`.
|
||||
///
|
||||
/// The default value is `0`.
|
||||
pub value: u64,
|
||||
|
||||
/// For a semaphore wait operation, specifies the pipeline stages in the second synchronization
|
||||
/// scope: stages of queue operations following the wait operation that can start executing
|
||||
/// after the semaphore is signalled.
|
||||
@ -862,6 +883,7 @@ impl SemaphoreSubmitInfo {
|
||||
pub fn new(semaphore: Arc<Semaphore>) -> Self {
|
||||
Self {
|
||||
semaphore,
|
||||
value: 0,
|
||||
stages: PipelineStages::ALL_COMMANDS,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
@ -870,6 +892,7 @@ impl SemaphoreSubmitInfo {
|
||||
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||
let &Self {
|
||||
ref semaphore,
|
||||
value,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = self;
|
||||
@ -877,6 +900,20 @@ impl SemaphoreSubmitInfo {
|
||||
// VUID?
|
||||
assert_eq!(device, semaphore.device().as_ref());
|
||||
|
||||
match semaphore.semaphore_type() {
|
||||
SemaphoreType::Binary => {
|
||||
if value != 0 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`semaphore.semaphore_type()` is `SemaphoreType::Binary`, but \
|
||||
`value` is not `0`"
|
||||
.into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
SemaphoreType::Timeline => {}
|
||||
}
|
||||
|
||||
stages.validate_device(device).map_err(|err| {
|
||||
err.add_context("stages")
|
||||
.set_vuids(&["VUID-VkSemaphoreSubmitInfo-stageMask-parameter"])
|
||||
|
@ -27,7 +27,7 @@ use crate::{
|
||||
},
|
||||
sync::{
|
||||
fence::{ExternalFenceInfo, ExternalFenceProperties},
|
||||
semaphore::{ExternalSemaphoreInfo, ExternalSemaphoreProperties},
|
||||
semaphore::{ExternalSemaphoreInfo, ExternalSemaphoreProperties, SemaphoreType},
|
||||
Sharing,
|
||||
},
|
||||
DebugWrapper, ExtensionProperties, Requires, RequiresAllOf, RequiresOneOf, Validated,
|
||||
@ -1191,13 +1191,28 @@ impl PhysicalDevice {
|
||||
|
||||
let &ExternalSemaphoreInfo {
|
||||
handle_type,
|
||||
semaphore_type,
|
||||
initial_value,
|
||||
_ne: _,
|
||||
} = info;
|
||||
|
||||
let external_semaphore_info = ash::vk::PhysicalDeviceExternalSemaphoreInfo {
|
||||
let mut external_semaphore_info_vk = ash::vk::PhysicalDeviceExternalSemaphoreInfo {
|
||||
handle_type: handle_type.into(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut semaphore_type_create_info_vk = None;
|
||||
|
||||
if semaphore_type != SemaphoreType::Binary {
|
||||
let next =
|
||||
semaphore_type_create_info_vk.insert(ash::vk::SemaphoreTypeCreateInfo {
|
||||
semaphore_type: semaphore_type.into(),
|
||||
initial_value,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = external_semaphore_info_vk.p_next;
|
||||
external_semaphore_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
/* Output */
|
||||
|
||||
@ -1211,14 +1226,14 @@ impl PhysicalDevice {
|
||||
if self.instance.api_version() >= Version::V1_1 {
|
||||
(fns.v1_1.get_physical_device_external_semaphore_properties)(
|
||||
self.handle,
|
||||
&external_semaphore_info,
|
||||
&external_semaphore_info_vk,
|
||||
&mut external_semaphore_properties,
|
||||
)
|
||||
} else {
|
||||
(fns.khr_external_semaphore_capabilities
|
||||
.get_physical_device_external_semaphore_properties_khr)(
|
||||
self.handle,
|
||||
&external_semaphore_info,
|
||||
&external_semaphore_info_vk,
|
||||
&mut external_semaphore_properties,
|
||||
);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use crate::{
|
||||
BindSparseInfo, SparseBufferMemoryBind, SparseImageMemoryBind, SparseImageOpaqueMemoryBind,
|
||||
},
|
||||
swapchain::{PresentInfo, SemaphorePresentInfo, SwapchainPresentInfo},
|
||||
sync::{fence::Fence, PipelineStages},
|
||||
sync::{fence::Fence, semaphore::SemaphoreType, PipelineStages},
|
||||
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
|
||||
VulkanObject,
|
||||
};
|
||||
@ -778,6 +778,7 @@ impl<'a> QueueGuard<'a> {
|
||||
for (semaphore_index, semaphore_submit_info) in wait_semaphores.iter().enumerate() {
|
||||
let &SemaphoreSubmitInfo {
|
||||
semaphore: _,
|
||||
value: _,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
@ -824,6 +825,7 @@ impl<'a> QueueGuard<'a> {
|
||||
for (semaphore_index, semaphore_submit_info) in signal_semaphores.iter().enumerate() {
|
||||
let &SemaphoreSubmitInfo {
|
||||
semaphore: _,
|
||||
value: _,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
@ -846,12 +848,14 @@ impl<'a> QueueGuard<'a> {
|
||||
}
|
||||
|
||||
// unsafe
|
||||
// VUID-VkSubmitInfo2-semaphore-03882
|
||||
// VUID-VkSubmitInfo2-semaphore-03883
|
||||
// VUID-VkSubmitInfo2-semaphore-03884
|
||||
// VUID-vkQueueSubmit2-fence-04894
|
||||
// VUID-vkQueueSubmit2-fence-04895
|
||||
// VUID-vkQueueSubmit2-commandBuffer-03867
|
||||
// VUID-vkQueueSubmit2-semaphore-03868
|
||||
// VUID-vkQueueSubmit2-semaphore-03871
|
||||
// VUID-vkQueueSubmit2-semaphore-03872
|
||||
// VUID-vkQueueSubmit2-semaphore-03873
|
||||
// VUID-vkQueueSubmit2-commandBuffer-03874
|
||||
// VUID-vkQueueSubmit2-commandBuffer-03875
|
||||
@ -875,7 +879,7 @@ impl<'a> QueueGuard<'a> {
|
||||
signal_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo; 4]>,
|
||||
}
|
||||
|
||||
let (mut submit_info_vk, per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
|
||||
let (mut submit_info_vk, mut per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
|
||||
submit_infos
|
||||
.iter()
|
||||
.map(|submit_info| {
|
||||
@ -886,59 +890,65 @@ impl<'a> QueueGuard<'a> {
|
||||
_ne: _,
|
||||
} = submit_info;
|
||||
|
||||
let wait_semaphore_infos_vk = wait_semaphores
|
||||
.iter()
|
||||
.map(|semaphore_submit_info| {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
let mut per_submit_vk = PerSubmitInfo {
|
||||
wait_semaphore_infos_vk: SmallVec::with_capacity(wait_semaphores.len()),
|
||||
command_buffer_infos_vk: SmallVec::with_capacity(command_buffers.len()),
|
||||
signal_semaphore_infos_vk: SmallVec::with_capacity(
|
||||
signal_semaphores.len(),
|
||||
),
|
||||
};
|
||||
let PerSubmitInfo {
|
||||
wait_semaphore_infos_vk,
|
||||
command_buffer_infos_vk,
|
||||
signal_semaphore_infos_vk,
|
||||
} = &mut per_submit_vk;
|
||||
|
||||
ash::vk::SemaphoreSubmitInfo {
|
||||
semaphore: semaphore.handle(),
|
||||
value: 0, // TODO:
|
||||
stage_mask: stages.into(),
|
||||
device_index: 0, // TODO:
|
||||
..Default::default()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
for semaphore_submit_info in wait_semaphores {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
value,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
|
||||
let command_buffer_infos_vk = command_buffers
|
||||
.iter()
|
||||
.map(|command_buffer_submit_info| {
|
||||
let &CommandBufferSubmitInfo {
|
||||
ref command_buffer,
|
||||
_ne: _,
|
||||
} = command_buffer_submit_info;
|
||||
wait_semaphore_infos_vk.push(ash::vk::SemaphoreSubmitInfo {
|
||||
semaphore: semaphore.handle(),
|
||||
value,
|
||||
stage_mask: stages.into(),
|
||||
device_index: 0, // TODO:
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
ash::vk::CommandBufferSubmitInfo {
|
||||
command_buffer: command_buffer.handle(),
|
||||
device_mask: 0, // TODO:
|
||||
..Default::default()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
for command_buffer_submit_info in command_buffers {
|
||||
let &CommandBufferSubmitInfo {
|
||||
ref command_buffer,
|
||||
_ne: _,
|
||||
} = command_buffer_submit_info;
|
||||
|
||||
let signal_semaphore_infos_vk = signal_semaphores
|
||||
.iter()
|
||||
.map(|semaphore_submit_info| {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
command_buffer_infos_vk.push(ash::vk::CommandBufferSubmitInfo {
|
||||
command_buffer: command_buffer.handle(),
|
||||
device_mask: 0, // TODO:
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
ash::vk::SemaphoreSubmitInfo {
|
||||
semaphore: semaphore.handle(),
|
||||
value: 0, // TODO:
|
||||
stage_mask: stages.into(),
|
||||
device_index: 0, // TODO:
|
||||
..Default::default()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
for semaphore_submit_info in signal_semaphores {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
value,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
|
||||
signal_semaphore_infos_vk.push(ash::vk::SemaphoreSubmitInfo {
|
||||
semaphore: semaphore.handle(),
|
||||
value,
|
||||
stage_mask: stages.into(),
|
||||
device_index: 0, // TODO:
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
(
|
||||
ash::vk::SubmitInfo2 {
|
||||
@ -951,11 +961,7 @@ impl<'a> QueueGuard<'a> {
|
||||
p_signal_semaphore_infos: ptr::null(),
|
||||
..Default::default()
|
||||
},
|
||||
PerSubmitInfo {
|
||||
wait_semaphore_infos_vk,
|
||||
command_buffer_infos_vk,
|
||||
signal_semaphore_infos_vk,
|
||||
},
|
||||
per_submit_vk,
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
@ -967,7 +973,7 @@ impl<'a> QueueGuard<'a> {
|
||||
command_buffer_infos_vk,
|
||||
signal_semaphore_infos_vk,
|
||||
},
|
||||
) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter())
|
||||
) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter_mut())
|
||||
{
|
||||
*submit_info_vk = ash::vk::SubmitInfo2 {
|
||||
wait_semaphore_info_count: wait_semaphore_infos_vk.len() as u32,
|
||||
@ -1006,13 +1012,16 @@ impl<'a> QueueGuard<'a> {
|
||||
.map_err(VulkanError::from)
|
||||
} else {
|
||||
struct PerSubmitInfo {
|
||||
timeline_semaphore_submit_info_vk: Option<ash::vk::TimelineSemaphoreSubmitInfo>,
|
||||
wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
|
||||
wait_semaphore_values_vk: SmallVec<[u64; 4]>,
|
||||
wait_dst_stage_mask_vk: SmallVec<[ash::vk::PipelineStageFlags; 4]>,
|
||||
command_buffers_vk: SmallVec<[ash::vk::CommandBuffer; 4]>,
|
||||
signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
|
||||
signal_semaphore_values_vk: SmallVec<[u64; 4]>,
|
||||
}
|
||||
|
||||
let (mut submit_info_vk, per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
|
||||
let (mut submit_info_vk, mut per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
|
||||
submit_infos
|
||||
.iter()
|
||||
.map(|submit_info| {
|
||||
@ -1023,43 +1032,77 @@ impl<'a> QueueGuard<'a> {
|
||||
_ne: _,
|
||||
} = submit_info;
|
||||
|
||||
let (wait_semaphores_vk, wait_dst_stage_mask_vk) = wait_semaphores
|
||||
.iter()
|
||||
.map(|semaphore_submit_info| {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
let mut per_submit_vk = PerSubmitInfo {
|
||||
timeline_semaphore_submit_info_vk: None,
|
||||
wait_semaphores_vk: SmallVec::with_capacity(wait_semaphores.len()),
|
||||
wait_semaphore_values_vk: SmallVec::with_capacity(
|
||||
wait_semaphores.len(),
|
||||
),
|
||||
wait_dst_stage_mask_vk: SmallVec::with_capacity(wait_semaphores.len()),
|
||||
command_buffers_vk: SmallVec::with_capacity(command_buffers.len()),
|
||||
signal_semaphores_vk: SmallVec::with_capacity(signal_semaphores.len()),
|
||||
signal_semaphore_values_vk: SmallVec::with_capacity(
|
||||
signal_semaphores.len(),
|
||||
),
|
||||
};
|
||||
let PerSubmitInfo {
|
||||
timeline_semaphore_submit_info_vk,
|
||||
wait_semaphores_vk,
|
||||
wait_semaphore_values_vk,
|
||||
wait_dst_stage_mask_vk,
|
||||
command_buffers_vk,
|
||||
signal_semaphores_vk,
|
||||
signal_semaphore_values_vk,
|
||||
} = &mut per_submit_vk;
|
||||
|
||||
(semaphore.handle(), stages.into())
|
||||
})
|
||||
.unzip();
|
||||
let mut has_timeline_semaphores = false;
|
||||
|
||||
let command_buffers_vk = command_buffers
|
||||
.iter()
|
||||
.map(|command_buffer_submit_info| {
|
||||
let &CommandBufferSubmitInfo {
|
||||
ref command_buffer,
|
||||
_ne: _,
|
||||
} = command_buffer_submit_info;
|
||||
for semaphore_submit_info in wait_semaphores {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
value,
|
||||
stages,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
|
||||
command_buffer.handle()
|
||||
})
|
||||
.collect();
|
||||
if semaphore.semaphore_type() == SemaphoreType::Timeline {
|
||||
has_timeline_semaphores = true;
|
||||
}
|
||||
|
||||
let signal_semaphores_vk = signal_semaphores
|
||||
.iter()
|
||||
.map(|semaphore_submit_info| {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
stages: _,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
wait_semaphores_vk.push(semaphore.handle());
|
||||
wait_semaphore_values_vk.push(value);
|
||||
wait_dst_stage_mask_vk.push(stages.into());
|
||||
}
|
||||
|
||||
semaphore.handle()
|
||||
})
|
||||
.collect();
|
||||
for command_buffer_submit_info in command_buffers {
|
||||
let &CommandBufferSubmitInfo {
|
||||
ref command_buffer,
|
||||
_ne: _,
|
||||
} = command_buffer_submit_info;
|
||||
|
||||
command_buffers_vk.push(command_buffer.handle());
|
||||
}
|
||||
|
||||
for semaphore_submit_info in signal_semaphores {
|
||||
let &SemaphoreSubmitInfo {
|
||||
ref semaphore,
|
||||
value,
|
||||
stages: _,
|
||||
_ne: _,
|
||||
} = semaphore_submit_info;
|
||||
|
||||
if semaphore.semaphore_type() == SemaphoreType::Timeline {
|
||||
has_timeline_semaphores = true;
|
||||
}
|
||||
|
||||
signal_semaphores_vk.push(semaphore.handle());
|
||||
signal_semaphore_values_vk.push(value);
|
||||
}
|
||||
|
||||
if has_timeline_semaphores {
|
||||
*timeline_semaphore_submit_info_vk =
|
||||
Some(ash::vk::TimelineSemaphoreSubmitInfo::default());
|
||||
}
|
||||
|
||||
(
|
||||
ash::vk::SubmitInfo {
|
||||
@ -1072,12 +1115,7 @@ impl<'a> QueueGuard<'a> {
|
||||
p_signal_semaphores: ptr::null(),
|
||||
..Default::default()
|
||||
},
|
||||
PerSubmitInfo {
|
||||
wait_semaphores_vk,
|
||||
wait_dst_stage_mask_vk,
|
||||
command_buffers_vk,
|
||||
signal_semaphores_vk,
|
||||
},
|
||||
per_submit_vk,
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
@ -1085,12 +1123,15 @@ impl<'a> QueueGuard<'a> {
|
||||
for (
|
||||
submit_info_vk,
|
||||
PerSubmitInfo {
|
||||
timeline_semaphore_submit_info_vk,
|
||||
wait_semaphores_vk,
|
||||
wait_semaphore_values_vk,
|
||||
wait_dst_stage_mask_vk,
|
||||
command_buffers_vk,
|
||||
signal_semaphores_vk,
|
||||
signal_semaphore_values_vk,
|
||||
},
|
||||
) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter())
|
||||
) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter_mut())
|
||||
{
|
||||
*submit_info_vk = ash::vk::SubmitInfo {
|
||||
wait_semaphore_count: wait_semaphores_vk.len() as u32,
|
||||
@ -1102,6 +1143,19 @@ impl<'a> QueueGuard<'a> {
|
||||
p_signal_semaphores: signal_semaphores_vk.as_ptr(),
|
||||
..*submit_info_vk
|
||||
};
|
||||
|
||||
if let Some(timeline_semaphore_submit_info_vk) = timeline_semaphore_submit_info_vk {
|
||||
*timeline_semaphore_submit_info_vk = ash::vk::TimelineSemaphoreSubmitInfo {
|
||||
wait_semaphore_value_count: wait_semaphore_values_vk.len() as u32,
|
||||
p_wait_semaphore_values: wait_semaphore_values_vk.as_ptr(),
|
||||
signal_semaphore_value_count: signal_semaphore_values_vk.len() as u32,
|
||||
p_signal_semaphore_values: signal_semaphore_values_vk.as_ptr(),
|
||||
..*timeline_semaphore_submit_info_vk
|
||||
};
|
||||
|
||||
timeline_semaphore_submit_info_vk.p_next = submit_info_vk.p_next;
|
||||
submit_info_vk.p_next = timeline_semaphore_submit_info_vk as *mut _ as *mut _;
|
||||
}
|
||||
}
|
||||
|
||||
let fns = self.queue.device.fns();
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
sync::{
|
||||
fence::Fence,
|
||||
future::{queue_present, AccessCheckError, AccessError, GpuFuture, SubmitAnyBuilder},
|
||||
semaphore::Semaphore,
|
||||
semaphore::{Semaphore, SemaphoreType},
|
||||
},
|
||||
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError,
|
||||
VulkanObject,
|
||||
@ -104,6 +104,15 @@ impl AcquireNextImageInfo {
|
||||
if let Some(semaphore) = semaphore {
|
||||
// VUID-VkAcquireNextImageInfoKHR-commonparent
|
||||
assert_eq!(device, semaphore.device().as_ref());
|
||||
|
||||
if semaphore.semaphore_type() != SemaphoreType::Binary {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "semaphore.semaphore_type()".into(),
|
||||
problem: "is not `SemaphoreType::Binary`".into(),
|
||||
vuids: &["VUID-VkAcquireNextImageInfoKHR-semaphore-03266"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fence) = fence {
|
||||
@ -757,6 +766,15 @@ impl SemaphorePresentInfo {
|
||||
// VUID-VkPresentInfoKHR-commonparent
|
||||
assert_eq!(device, semaphore.device().as_ref());
|
||||
|
||||
if semaphore.semaphore_type() != SemaphoreType::Binary {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "semaphore.semaphore_type()".into(),
|
||||
problem: "is not `SemaphoreType::Binary`".into(),
|
||||
vuids: &["VUID-vkQueuePresentKHR-pWaitSemaphores-03267"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,9 @@
|
||||
//! An event can also be signaled from the host, by calling the [`set`] method directly on the
|
||||
//! [`Event`].
|
||||
//!
|
||||
//! [`set_event`]: crate::command_buffer::CommandBufferBuilder::set_event
|
||||
//! [pipeline barrier]: crate::command_buffer::CommandBufferBuilder::pipeline_barrier
|
||||
//! [`wait_events`]: crate::command_buffer::CommandBufferBuilder::wait_events
|
||||
//! [`set_event`]: crate::command_buffer::sys::UnsafeCommandBufferBuilder::set_event
|
||||
//! [pipeline barrier]: crate::command_buffer::sys::UnsafeCommandBufferBuilder::pipeline_barrier
|
||||
//! [`wait_events`]: crate::command_buffer::sys::UnsafeCommandBufferBuilder::wait_events
|
||||
//! [`set`]: Event::set
|
||||
|
||||
use crate::{
|
||||
|
@ -10,24 +10,48 @@
|
||||
//! A semaphore provides synchronization between multiple queues, with non-command buffer
|
||||
//! commands on the same queue, or between the device and an external source.
|
||||
//!
|
||||
//! A semaphore has two states: **signaled** and **unsignaled**.
|
||||
//! Only the device can perform operations on a semaphore,
|
||||
//! Semaphores come in two types: **binary** and **timeline** semaphores.
|
||||
//!
|
||||
//! # Binary semaphores
|
||||
//!
|
||||
//! A binary semaphore has two states: **signaled** and **unsignaled**.
|
||||
//! Only the device can perform operations on a binary semaphore,
|
||||
//! the host cannot perform any operations on it.
|
||||
//!
|
||||
//! Two operations can be performed on a semaphore:
|
||||
//! Two operations can be performed on a binary semaphore:
|
||||
//! - A **semaphore signal operation** will put the semaphore into the signaled state.
|
||||
//! - A **semaphore wait operation** will block execution of the operation is associated with,
|
||||
//! - A **semaphore wait operation** will block execution of the operation it is associated with,
|
||||
//! as long as the semaphore is in the unsignaled state. Once the semaphore is in the signaled
|
||||
//! state, the semaphore is put back in the unsignaled state and execution continues.
|
||||
//!
|
||||
//! Semaphore signals and waits must always occur in pairs: one signal operation is paired with one
|
||||
//! wait operation. If a semaphore is signaled without waiting for it, it stays in the signaled
|
||||
//! state until it is waited for, or destroyed.
|
||||
//! Binary semaphore signals and waits must always occur in pairs: one signal operation is paired
|
||||
//! with one wait operation. If a binary semaphore is signaled without waiting for it, it stays in
|
||||
//! the signaled state until it is waited for, or destroyed.
|
||||
//!
|
||||
//! # Timeline semaphores
|
||||
//!
|
||||
//! Also called *counting semaphore* in literature, its state is an integer counter value.
|
||||
//! Timeline semaphores cannot be used in swapchain-related commands,
|
||||
//! binary semaphores and fences must be used.
|
||||
//!
|
||||
//! Both the device and the host can perform the same two operations on a timeline semaphore:
|
||||
//! - A **semaphore signal operation** will set the semaphore counter value to a specified value.
|
||||
//! - A **semaphore wait operation** will block execution of the operation it is associated with,
|
||||
//! as long as the semaphore's counter value is less than a specified threshold value.
|
||||
//! Once the semaphore's counter value is equal to or greater than the threshold, execution
|
||||
//! continues. Unlike with binary semaphores, waiting does not alter the state of a timeline
|
||||
//! semaphore, so multiple operations can wait for the same semaphore value.
|
||||
//!
|
||||
//! Additionally, the host can query the current counter value of a timeline semaphore.
|
||||
//!
|
||||
//! If the device signals a timeline semaphore, and the host waits for it, then it can be used
|
||||
//! in ways similar to a [fence], to signal to the host that the device has completed an
|
||||
//! operation.
|
||||
//!
|
||||
//! # Safety
|
||||
//!
|
||||
//! - When a semaphore signal operation is executed on the device,
|
||||
//! the semaphore must be in the unsignaled state.
|
||||
//! For binary semaphores:
|
||||
//! - When a semaphore signal operation is executed, the semaphore must be in the unsignaled state.
|
||||
//! In other words, the same semaphore cannot be signalled by multiple commands;
|
||||
//! there must always be a wait operation in between them.
|
||||
//! - There must never be more than one semaphore wait operation executing on the same semaphore
|
||||
@ -36,15 +60,29 @@
|
||||
//! the semaphore must already be in the signaled state, or
|
||||
//! the signal operation that it waits for must have been queued previously
|
||||
//! (as part of a previous command, or an earlier batch within the same command).
|
||||
//!
|
||||
//! For timeline semaphores:
|
||||
//! - When a semaphore signal operation is executed, the new counter value of the semaphore must be
|
||||
//! greater than its current value, and less than the value of any pending signal operations on
|
||||
//! that semaphore.
|
||||
//! - If an operation both waits on and signals the same semaphore, the signaled value must be
|
||||
//! greater than the waited value.
|
||||
//! - At any given time, the difference between the current semaphore counter value, and the value
|
||||
//! of any outstanding signal or wait operations on that semaphore, must not be greater than the
|
||||
//! [`max_timeline_semaphore_value_difference`] device limit.
|
||||
//!
|
||||
//! [fence]: crate::sync::fence
|
||||
//! [`max_timeline_semaphore_value_difference`]: crate::device::Properties::max_timeline_semaphore_value_difference
|
||||
|
||||
use crate::{
|
||||
device::{physical::PhysicalDevice, Device, DeviceOwned},
|
||||
instance::InstanceOwnedDebugWrapper,
|
||||
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
|
||||
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum},
|
||||
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
|
||||
VulkanObject,
|
||||
};
|
||||
use std::{fs::File, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
|
||||
use smallvec::SmallVec;
|
||||
use std::{fs::File, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc, time::Duration};
|
||||
|
||||
/// Used to provide synchronization between command buffers during their execution.
|
||||
///
|
||||
@ -56,6 +94,7 @@ pub struct Semaphore {
|
||||
device: InstanceOwnedDebugWrapper<Arc<Device>>,
|
||||
id: NonZeroU64,
|
||||
|
||||
semaphore_type: SemaphoreType,
|
||||
export_handle_types: ExternalSemaphoreHandleTypes,
|
||||
|
||||
must_put_in_pool: bool,
|
||||
@ -89,27 +128,39 @@ impl Semaphore {
|
||||
device: Arc<Device>,
|
||||
create_info: SemaphoreCreateInfo,
|
||||
) -> Result<Semaphore, VulkanError> {
|
||||
let SemaphoreCreateInfo {
|
||||
let &SemaphoreCreateInfo {
|
||||
semaphore_type,
|
||||
initial_value,
|
||||
export_handle_types,
|
||||
_ne: _,
|
||||
} = create_info;
|
||||
} = &create_info;
|
||||
|
||||
let mut create_info_vk = ash::vk::SemaphoreCreateInfo {
|
||||
flags: ash::vk::SemaphoreCreateFlags::empty(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut semaphore_type_create_info_vk = None;
|
||||
let mut export_semaphore_create_info_vk = None;
|
||||
|
||||
if semaphore_type != SemaphoreType::Binary {
|
||||
let next = semaphore_type_create_info_vk.insert(ash::vk::SemaphoreTypeCreateInfo {
|
||||
semaphore_type: semaphore_type.into(),
|
||||
initial_value,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if !export_handle_types.is_empty() {
|
||||
let _ = export_semaphore_create_info_vk.insert(ash::vk::ExportSemaphoreCreateInfo {
|
||||
let next = export_semaphore_create_info_vk.insert(ash::vk::ExportSemaphoreCreateInfo {
|
||||
handle_types: export_handle_types.into(),
|
||||
..Default::default()
|
||||
});
|
||||
};
|
||||
|
||||
if let Some(info) = export_semaphore_create_info_vk.as_mut() {
|
||||
info.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = info as *const _ as *const _;
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
let handle = {
|
||||
@ -144,6 +195,7 @@ impl Semaphore {
|
||||
device: InstanceOwnedDebugWrapper(device),
|
||||
id: Self::next_id(),
|
||||
|
||||
semaphore_type: SemaphoreType::Binary,
|
||||
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
|
||||
|
||||
must_put_in_pool: true,
|
||||
@ -173,6 +225,8 @@ impl Semaphore {
|
||||
create_info: SemaphoreCreateInfo,
|
||||
) -> Semaphore {
|
||||
let SemaphoreCreateInfo {
|
||||
semaphore_type,
|
||||
initial_value: _,
|
||||
export_handle_types,
|
||||
_ne: _,
|
||||
} = create_info;
|
||||
@ -182,18 +236,329 @@ impl Semaphore {
|
||||
device: InstanceOwnedDebugWrapper(device),
|
||||
id: Self::next_id(),
|
||||
|
||||
semaphore_type,
|
||||
export_handle_types,
|
||||
|
||||
must_put_in_pool: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the type of the semaphore.
|
||||
#[inline]
|
||||
pub fn semaphore_type(&self) -> SemaphoreType {
|
||||
self.semaphore_type
|
||||
}
|
||||
|
||||
/// Returns the handle types that can be exported from the semaphore.
|
||||
#[inline]
|
||||
pub fn export_handle_types(&self) -> ExternalSemaphoreHandleTypes {
|
||||
self.export_handle_types
|
||||
}
|
||||
|
||||
/// If `self` is a timeline semaphore, returns the current counter value of the semaphore.
|
||||
///
|
||||
/// The returned value may be immediately out of date, if a signal operation on the semaphore
|
||||
/// is pending on the device.
|
||||
#[inline]
|
||||
pub fn counter_value(&self) -> Result<u64, Validated<VulkanError>> {
|
||||
self.validate_counter_value()?;
|
||||
|
||||
unsafe { Ok(self.counter_value_unchecked()?) }
|
||||
}
|
||||
|
||||
fn validate_counter_value(&self) -> Result<(), Box<ValidationError>> {
|
||||
if self.semaphore_type != SemaphoreType::Timeline {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "self.semaphore_type()".into(),
|
||||
problem: "is not `SemaphoreType::Timeline`".into(),
|
||||
vuids: &["VUID-vkGetSemaphoreCounterValue-semaphore-03255"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||
pub unsafe fn counter_value_unchecked(&self) -> Result<u64, VulkanError> {
|
||||
let mut output = MaybeUninit::uninit();
|
||||
let fns = self.device.fns();
|
||||
|
||||
if self.device.api_version() >= Version::V1_2 {
|
||||
(fns.v1_2.get_semaphore_counter_value)(
|
||||
self.device.handle(),
|
||||
self.handle,
|
||||
output.as_mut_ptr(),
|
||||
)
|
||||
} else {
|
||||
(fns.khr_timeline_semaphore.get_semaphore_counter_value_khr)(
|
||||
self.device.handle(),
|
||||
self.handle,
|
||||
output.as_mut_ptr(),
|
||||
)
|
||||
}
|
||||
.result()
|
||||
.map_err(VulkanError::from)?;
|
||||
|
||||
Ok(output.assume_init())
|
||||
}
|
||||
|
||||
/// If `self` is a timeline semaphore, performs a signal operation on the semaphore, setting
|
||||
/// the new counter value to `value`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - The safety requirements for semaphores, as detailed in the module documentation,
|
||||
/// must be followed.
|
||||
#[inline]
|
||||
pub unsafe fn signal(
|
||||
&self,
|
||||
signal_info: SemaphoreSignalInfo,
|
||||
) -> Result<(), Validated<VulkanError>> {
|
||||
self.validate_signal(&signal_info)?;
|
||||
|
||||
Ok(self.signal_unchecked(signal_info)?)
|
||||
}
|
||||
|
||||
fn validate_signal(
|
||||
&self,
|
||||
signal_info: &SemaphoreSignalInfo,
|
||||
) -> Result<(), Box<ValidationError>> {
|
||||
if self.semaphore_type != SemaphoreType::Timeline {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "self.semaphore_type()".into(),
|
||||
problem: "is not `SemaphoreType::Timeline`".into(),
|
||||
vuids: &["VUID-VkSemaphoreSignalInfo-semaphore-03257"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
signal_info.validate(&self.device)?;
|
||||
|
||||
// unsafe
|
||||
// VUID-VkSemaphoreSignalInfo-value-03258
|
||||
// VUID-VkSemaphoreSignalInfo-value-03259
|
||||
// VUID-VkSemaphoreSignalInfo-value-03260
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||
pub unsafe fn signal_unchecked(
|
||||
&self,
|
||||
signal_info: SemaphoreSignalInfo,
|
||||
) -> Result<(), VulkanError> {
|
||||
let &SemaphoreSignalInfo { value, _ne: _ } = &signal_info;
|
||||
|
||||
let signal_info_vk = ash::vk::SemaphoreSignalInfo {
|
||||
semaphore: self.handle,
|
||||
value,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let fns = self.device.fns();
|
||||
|
||||
if self.device.api_version() >= Version::V1_2 {
|
||||
(fns.v1_2.signal_semaphore)(self.device.handle(), &signal_info_vk)
|
||||
} else {
|
||||
(fns.khr_timeline_semaphore.signal_semaphore_khr)(self.device.handle(), &signal_info_vk)
|
||||
}
|
||||
.result()
|
||||
.map_err(VulkanError::from)
|
||||
}
|
||||
|
||||
/// If `self` is a timeline semaphore, performs a wait operation on the semaphore, blocking
|
||||
/// until the counter value is equal to or greater than `wait_info.value`.
|
||||
#[inline]
|
||||
pub fn wait(
|
||||
&self,
|
||||
wait_info: SemaphoreWaitInfo,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<(), Validated<VulkanError>> {
|
||||
self.validate_wait(&wait_info, timeout)?;
|
||||
|
||||
unsafe { Ok(self.wait_unchecked(wait_info, timeout)?) }
|
||||
}
|
||||
|
||||
fn validate_wait(
|
||||
&self,
|
||||
wait_info: &SemaphoreWaitInfo,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<(), Box<ValidationError>> {
|
||||
if self.semaphore_type != SemaphoreType::Timeline {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "self.semaphore_type()".into(),
|
||||
problem: "is not `SemaphoreType::Timeline`".into(),
|
||||
vuids: &["VUID-VkSemaphoreWaitInfo-pSemaphores-03256"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
wait_info
|
||||
.validate(&self.device)
|
||||
.map_err(|err| err.add_context("wait_info"))?;
|
||||
|
||||
if let Some(timeout) = timeout {
|
||||
if timeout.as_nanos() >= u64::MAX as u128 {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "timeout".into(),
|
||||
problem: "is not less than `u64::MAX` nanoseconds".into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||
pub unsafe fn wait_unchecked(
|
||||
&self,
|
||||
wait_info: SemaphoreWaitInfo,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<(), VulkanError> {
|
||||
let &SemaphoreWaitInfo {
|
||||
flags,
|
||||
value,
|
||||
_ne: _,
|
||||
} = &wait_info;
|
||||
|
||||
let semaphores_vk = [self.handle];
|
||||
let values_vk = [value];
|
||||
|
||||
let wait_info_vk = ash::vk::SemaphoreWaitInfo {
|
||||
flags: flags.into(),
|
||||
semaphore_count: 1,
|
||||
p_semaphores: semaphores_vk.as_ptr(),
|
||||
p_values: values_vk.as_ptr(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let fns = self.device.fns();
|
||||
|
||||
if self.device.api_version() >= Version::V1_2 {
|
||||
(fns.v1_2.wait_semaphores)(
|
||||
self.device.handle(),
|
||||
&wait_info_vk,
|
||||
timeout.map_or(u64::MAX, |duration| {
|
||||
u64::try_from(duration.as_nanos()).unwrap()
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(fns.khr_timeline_semaphore.wait_semaphores_khr)(
|
||||
self.device.handle(),
|
||||
&wait_info_vk,
|
||||
timeout.map_or(u64::MAX, |duration| {
|
||||
u64::try_from(duration.as_nanos()).unwrap()
|
||||
}),
|
||||
)
|
||||
}
|
||||
.result()
|
||||
.map_err(VulkanError::from)
|
||||
}
|
||||
|
||||
/// Waits for multiple timeline semaphores at once.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - Panics if not all semaphores belong to the same device.
|
||||
#[inline]
|
||||
pub fn wait_multiple(
|
||||
wait_info: SemaphoreWaitMultipleInfo,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<(), Validated<VulkanError>> {
|
||||
Self::validate_wait_multiple(&wait_info, timeout)?;
|
||||
|
||||
unsafe { Ok(Self::wait_multiple_unchecked(wait_info, timeout)?) }
|
||||
}
|
||||
|
||||
fn validate_wait_multiple(
|
||||
wait_info: &SemaphoreWaitMultipleInfo,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<(), Box<ValidationError>> {
|
||||
if let Some(timeout) = timeout {
|
||||
if timeout.as_nanos() >= u64::MAX as u128 {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "timeout".into(),
|
||||
problem: "is not less than `u64::MAX` nanoseconds".into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if wait_info.semaphores.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let device = &wait_info.semaphores[0].semaphore.device;
|
||||
wait_info
|
||||
.validate(device)
|
||||
.map_err(|err| err.add_context("wait_info"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||
pub unsafe fn wait_multiple_unchecked(
|
||||
wait_info: SemaphoreWaitMultipleInfo,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<(), VulkanError> {
|
||||
let &SemaphoreWaitMultipleInfo {
|
||||
flags,
|
||||
ref semaphores,
|
||||
_ne: _,
|
||||
} = &wait_info;
|
||||
|
||||
if semaphores.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut semaphores_vk: SmallVec<[_; 8]> = SmallVec::with_capacity(semaphores.len());
|
||||
let mut values_vk: SmallVec<[_; 8]> = SmallVec::with_capacity(semaphores.len());
|
||||
|
||||
for value_info in semaphores {
|
||||
let &SemaphoreWaitValueInfo {
|
||||
ref semaphore,
|
||||
value,
|
||||
_ne: _,
|
||||
} = value_info;
|
||||
|
||||
semaphores_vk.push(semaphore.handle);
|
||||
values_vk.push(value);
|
||||
}
|
||||
|
||||
let wait_info_vk = ash::vk::SemaphoreWaitInfo {
|
||||
flags: flags.into(),
|
||||
semaphore_count: semaphores_vk.len() as u32,
|
||||
p_semaphores: semaphores_vk.as_ptr(),
|
||||
p_values: values_vk.as_ptr(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let device = &semaphores[0].semaphore.device;
|
||||
let fns = device.fns();
|
||||
|
||||
if device.api_version() >= Version::V1_2 {
|
||||
(fns.v1_2.wait_semaphores)(
|
||||
device.handle(),
|
||||
&wait_info_vk,
|
||||
timeout.map_or(u64::MAX, |duration| {
|
||||
u64::try_from(duration.as_nanos()).unwrap()
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(fns.khr_timeline_semaphore.wait_semaphores_khr)(
|
||||
device.handle(),
|
||||
&wait_info_vk,
|
||||
timeout.map_or(u64::MAX, |duration| {
|
||||
u64::try_from(duration.as_nanos()).unwrap()
|
||||
}),
|
||||
)
|
||||
}
|
||||
.result()
|
||||
.map_err(VulkanError::from)
|
||||
}
|
||||
|
||||
/// Exports the semaphore into a POSIX file descriptor. The caller owns the returned `File`.
|
||||
///
|
||||
/// # Safety
|
||||
@ -254,6 +619,16 @@ impl Semaphore {
|
||||
}));
|
||||
}
|
||||
|
||||
if handle_type.has_copy_transference() && self.semaphore_type != SemaphoreType::Binary {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`handle_type` has copy transference, but \
|
||||
`self.semaphore_type()` is not `SemaphoreType::Binary`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-03253"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -428,6 +803,15 @@ impl Semaphore {
|
||||
.set_vuids(&["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-parameter"])
|
||||
})?;
|
||||
|
||||
if self.semaphore_type != SemaphoreType::Binary {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "self.semaphore_type()".into(),
|
||||
problem: "is not `SemaphoreType::Binary`".into(),
|
||||
vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04763"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "handle_type".into(),
|
||||
@ -512,6 +896,26 @@ impl Semaphore {
|
||||
.validate(&self.device)
|
||||
.map_err(|err| err.add_context("import_semaphore_fd_info"))?;
|
||||
|
||||
let &ImportSemaphoreFdInfo {
|
||||
flags,
|
||||
handle_type: _,
|
||||
file: _,
|
||||
_ne: _,
|
||||
} = import_semaphore_fd_info;
|
||||
|
||||
if self.semaphore_type == SemaphoreType::Timeline
|
||||
&& flags.intersects(SemaphoreImportFlags::TEMPORARY)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`self.semaphore_type()` is `SemaphoreType::Timeline`, but \
|
||||
`import_semaphore_fd_info.flags` contains \
|
||||
`SemaphoreImportFlags::TEMPORARY`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImportSemaphoreFdInfoKHR-flags-03323"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -597,6 +1001,26 @@ impl Semaphore {
|
||||
.validate(&self.device)
|
||||
.map_err(|err| err.add_context("import_semaphore_win32_handle_info"))?;
|
||||
|
||||
let &ImportSemaphoreWin32HandleInfo {
|
||||
flags,
|
||||
handle_type: _,
|
||||
handle: _,
|
||||
_ne: _,
|
||||
} = import_semaphore_win32_handle_info;
|
||||
|
||||
if self.semaphore_type == SemaphoreType::Timeline
|
||||
&& flags.intersects(SemaphoreImportFlags::TEMPORARY)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`self.semaphore_type()` is `SemaphoreType::Timeline`, but \
|
||||
`import_semaphore_win32_handle_info.flags` contains \
|
||||
`SemaphoreImportFlags::TEMPORARY`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-03322"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -667,6 +1091,14 @@ impl Semaphore {
|
||||
.validate(&self.device)
|
||||
.map_err(|err| err.add_context("import_semaphore_zircon_handle_info"))?;
|
||||
|
||||
if self.semaphore_type == SemaphoreType::Timeline {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`self.semaphore_type()` is `SemaphoreType::Timeline`".into(),
|
||||
vuids: &["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-semaphoreType-04768"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -736,6 +1168,19 @@ impl_id_counter!(Semaphore);
|
||||
/// Parameters to create a new `Semaphore`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SemaphoreCreateInfo {
|
||||
/// The type of semaphore to create.
|
||||
///
|
||||
/// The default value is [`SemaphoreType::Binary`].
|
||||
pub semaphore_type: SemaphoreType,
|
||||
|
||||
/// If `semaphore_type` is [`SemaphoreType::Timeline`],
|
||||
/// specifies the counter value that the semaphore has when it is created.
|
||||
///
|
||||
/// If `semaphore_type` is [`SemaphoreType::Binary`], then this must be `0`.
|
||||
///
|
||||
/// The default value is `0`.
|
||||
pub initial_value: u64,
|
||||
|
||||
/// The handle types that can be exported from the semaphore.
|
||||
///
|
||||
/// The default value is [`ExternalSemaphoreHandleTypes::empty()`].
|
||||
@ -748,6 +1193,8 @@ impl Default for SemaphoreCreateInfo {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
semaphore_type: SemaphoreType::Binary,
|
||||
initial_value: 0,
|
||||
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
@ -757,10 +1204,43 @@ impl Default for SemaphoreCreateInfo {
|
||||
impl SemaphoreCreateInfo {
|
||||
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||
let &Self {
|
||||
semaphore_type,
|
||||
initial_value,
|
||||
export_handle_types,
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
semaphore_type.validate_device(device).map_err(|err| {
|
||||
err.add_context("semaphore_type")
|
||||
.set_vuids(&["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-parameter"])
|
||||
})?;
|
||||
|
||||
match semaphore_type {
|
||||
SemaphoreType::Binary => {
|
||||
if initial_value != 0 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`semaphore_type` is `SemaphoreType::Binary`, but \
|
||||
`initial_value` is not `0`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-03279"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
SemaphoreType::Timeline => {
|
||||
if !device.enabled_features().timeline_semaphore {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "semaphore_type".into(),
|
||||
problem: "is `SemaphoreType::Timeline`".into(),
|
||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||
"timeline_semaphore",
|
||||
)])]),
|
||||
vuids: &["VUID-VkSemaphoreTypeCreateInfo-timelineSemaphore-03252"],
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !export_handle_types.is_empty() {
|
||||
if !(device.api_version() >= Version::V1_1
|
||||
|| device.enabled_extensions().khr_external_semaphore)
|
||||
@ -785,9 +1265,11 @@ impl SemaphoreCreateInfo {
|
||||
let external_semaphore_properties = unsafe {
|
||||
device
|
||||
.physical_device()
|
||||
.external_semaphore_properties_unchecked(
|
||||
ExternalSemaphoreInfo::handle_type(handle_type),
|
||||
)
|
||||
.external_semaphore_properties_unchecked(ExternalSemaphoreInfo {
|
||||
semaphore_type,
|
||||
initial_value,
|
||||
..ExternalSemaphoreInfo::handle_type(handle_type)
|
||||
})
|
||||
};
|
||||
|
||||
if !external_semaphore_properties.exportable {
|
||||
@ -829,6 +1311,24 @@ impl SemaphoreCreateInfo {
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_enum! {
|
||||
#[non_exhaustive]
|
||||
|
||||
/// The type that a semaphore can have.
|
||||
SemaphoreType = SemaphoreType(i32);
|
||||
|
||||
/// A semaphore that can only have two states: unsignaled and signaled.
|
||||
/// At any given time, only one pending operation may signal a binary semaphore, and only
|
||||
/// one pending operation may wait on it.
|
||||
Binary = BINARY,
|
||||
|
||||
/// A semaphore whose state is a monotonically increasing integer. Signaling and waiting
|
||||
/// operations have an associated semaphore value: signaling a timeline semaphore sets it to
|
||||
/// the associated value, while waiting for a timeline semaphore will wait
|
||||
/// until the current semaphore state is greater than or equal to the associated value.
|
||||
Timeline = TIMELINE,
|
||||
}
|
||||
|
||||
vulkan_bitflags_enum! {
|
||||
#[non_exhaustive]
|
||||
|
||||
@ -893,6 +1393,198 @@ vulkan_bitflags_enum! {
|
||||
]),
|
||||
}
|
||||
|
||||
/// Parameters to signal a timeline semaphore.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SemaphoreSignalInfo {
|
||||
/// The new value to set the semaphore's counter to.
|
||||
///
|
||||
/// The default value is `0`.
|
||||
pub value: u64,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for SemaphoreSignalInfo {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
value: 0,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SemaphoreSignalInfo {
|
||||
pub(crate) fn validate(&self, _device: &Device) -> Result<(), Box<ValidationError>> {
|
||||
let &Self { value: _, _ne: _ } = self;
|
||||
|
||||
// unsafe
|
||||
// VUID-VkSemaphoreSignalInfo-value-03258
|
||||
// VUID-VkSemaphoreSignalInfo-value-03259
|
||||
// VUID-VkSemaphoreSignalInfo-value-03260
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters to wait for a single timeline semaphore.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SemaphoreWaitInfo {
|
||||
/// Additional properties of the wait operation.
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub flags: SemaphoreWaitFlags,
|
||||
|
||||
/// The value to wait for.
|
||||
///
|
||||
/// The default value is `0`.
|
||||
pub value: u64,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for SemaphoreWaitInfo {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
flags: SemaphoreWaitFlags::empty(),
|
||||
value: 0,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SemaphoreWaitInfo {
|
||||
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||
let &Self {
|
||||
flags,
|
||||
value: _,
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
flags.validate_device(device).map_err(|err| {
|
||||
err.add_context("flags")
|
||||
.set_vuids(&["VUID-VkSemaphoreWaitInfo-flags-parameter"])
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters to wait for multiple timeline semaphores.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SemaphoreWaitMultipleInfo {
|
||||
/// Additional properties of the wait operation.
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub flags: SemaphoreWaitFlags,
|
||||
|
||||
/// The semaphores to wait for, and the values to wait for.
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub semaphores: Vec<SemaphoreWaitValueInfo>,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for SemaphoreWaitMultipleInfo {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
flags: SemaphoreWaitFlags::empty(),
|
||||
semaphores: Vec::new(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SemaphoreWaitMultipleInfo {
|
||||
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||
let &Self {
|
||||
flags,
|
||||
ref semaphores,
|
||||
_ne,
|
||||
} = self;
|
||||
|
||||
flags.validate_device(device).map_err(|err| {
|
||||
err.add_context("flags")
|
||||
.set_vuids(&["VUID-VkSemaphoreWaitInfo-flags-parameter"])
|
||||
})?;
|
||||
|
||||
if semaphores.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for (index, value_info) in semaphores.iter().enumerate() {
|
||||
value_info
|
||||
.validate(device)
|
||||
.map_err(|err| err.add_context(format!("semaphores[{}]", index)))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_bitflags! {
|
||||
#[non_exhaustive]
|
||||
|
||||
/// Flags specifying additional properties of a semaphore wait operation.
|
||||
SemaphoreWaitFlags = SemaphoreWaitFlags(u32);
|
||||
|
||||
/// Wait for at least one of the semaphores to signal the required value,
|
||||
/// rather than all of them.
|
||||
ANY = ANY,
|
||||
}
|
||||
|
||||
/// A semaphore to wait for, along with the value to wait for.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SemaphoreWaitValueInfo {
|
||||
/// The semaphore to wait for.
|
||||
///
|
||||
/// There is no default value.
|
||||
pub semaphore: Arc<Semaphore>,
|
||||
|
||||
/// The value to wait for.
|
||||
///
|
||||
/// There is no default value.
|
||||
pub value: u64,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl SemaphoreWaitValueInfo {
|
||||
/// Returns a `SemaphoreWaitValueInfo` with the specified `semaphore` and `value`.
|
||||
#[inline]
|
||||
pub fn new(semaphore: Arc<Semaphore>, value: u64) -> Self {
|
||||
Self {
|
||||
semaphore,
|
||||
value,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||
let &Self {
|
||||
ref semaphore,
|
||||
value: _,
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
assert_eq!(device, semaphore.device.as_ref());
|
||||
|
||||
if semaphore.semaphore_type != SemaphoreType::Timeline {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "semaphore.semaphore_type()".into(),
|
||||
problem: "is not `SemaphoreType::Timeline`".into(),
|
||||
vuids: &["VUID-VkSemaphoreWaitInfo-pSemaphores-03256"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_bitflags! {
|
||||
#[non_exhaustive]
|
||||
|
||||
@ -1170,6 +1862,16 @@ pub struct ExternalSemaphoreInfo {
|
||||
/// There is no default value.
|
||||
pub handle_type: ExternalSemaphoreHandleType,
|
||||
|
||||
/// The type that the semaphore will have.
|
||||
///
|
||||
/// The default value is [`SemaphoreType::Binary`].
|
||||
pub semaphore_type: SemaphoreType,
|
||||
|
||||
/// The initial value that the semaphore will have.
|
||||
///
|
||||
/// The default value is `0`.
|
||||
pub initial_value: u64,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
@ -1179,6 +1881,8 @@ impl ExternalSemaphoreInfo {
|
||||
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
|
||||
Self {
|
||||
handle_type,
|
||||
semaphore_type: SemaphoreType::Binary,
|
||||
initial_value: 0,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
@ -1189,6 +1893,8 @@ impl ExternalSemaphoreInfo {
|
||||
) -> Result<(), Box<ValidationError>> {
|
||||
let &Self {
|
||||
handle_type,
|
||||
semaphore_type,
|
||||
initial_value,
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
@ -1199,6 +1905,39 @@ impl ExternalSemaphoreInfo {
|
||||
.set_vuids(&["VUID-VkPhysicalDeviceExternalSemaphoreInfo-handleType-parameter"])
|
||||
})?;
|
||||
|
||||
semaphore_type
|
||||
.validate_physical_device(physical_device)
|
||||
.map_err(|err| {
|
||||
err.add_context("semaphore_type")
|
||||
.set_vuids(&["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-parameter"])
|
||||
})?;
|
||||
|
||||
match semaphore_type {
|
||||
SemaphoreType::Binary => {
|
||||
if initial_value != 0 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`semaphore_type` is `SemaphoreType::Binary`, but \
|
||||
`initial_value` is not `0`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-03279"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
SemaphoreType::Timeline => {
|
||||
if !physical_device.supported_features().timeline_semaphore {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "semaphore_type".into(),
|
||||
problem: "is `SemaphoreType::Timeline`".into(),
|
||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||
"timeline_semaphore",
|
||||
)])]),
|
||||
vuids: &["VUID-VkSemaphoreTypeCreateInfo-timelineSemaphore-03252"],
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user