mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 08:14:20 +00:00
Partial validation of queue commands (#2373)
* Move resource tracking/locking back from Queue to futures * Add partially validated `submit` command * Add partially validated `present` command * More safety docs * Small doc change * Add SemaphorePresentInfo * Put safety docs in the semaphore/fence modules instead * More fence and semaphore docs * Re-add missing imports * Remove state tracking from Fence * Remove state tracking from Semaphore
This commit is contained in:
parent
151e5c49cb
commit
def21843fc
@ -189,12 +189,16 @@ mod linux {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let acquire_fd = acquire_sem
|
let acquire_fd = unsafe {
|
||||||
.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
|
acquire_sem
|
||||||
.unwrap();
|
.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
|
||||||
let release_fd = release_sem
|
.unwrap()
|
||||||
.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
|
};
|
||||||
.unwrap();
|
let release_fd = unsafe {
|
||||||
|
release_sem
|
||||||
|
.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let barrier_clone = barrier.clone();
|
let barrier_clone = barrier.clone();
|
||||||
let barrier_2_clone = barrier_2.clone();
|
let barrier_2_clone = barrier_2.clone();
|
||||||
@ -300,9 +304,9 @@ mod linux {
|
|||||||
Event::RedrawEventsCleared => {
|
Event::RedrawEventsCleared => {
|
||||||
queue
|
queue
|
||||||
.with(|mut q| unsafe {
|
.with(|mut q| unsafe {
|
||||||
q.submit_unchecked(
|
q.submit(
|
||||||
[SubmitInfo {
|
&[SubmitInfo {
|
||||||
signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
|
signal_semaphores: vec![SemaphoreSubmitInfo::new(
|
||||||
acquire_sem.clone(),
|
acquire_sem.clone(),
|
||||||
)],
|
)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -317,9 +321,9 @@ mod linux {
|
|||||||
|
|
||||||
queue
|
queue
|
||||||
.with(|mut q| unsafe {
|
.with(|mut q| unsafe {
|
||||||
q.submit_unchecked(
|
q.submit(
|
||||||
[SubmitInfo {
|
&[SubmitInfo {
|
||||||
wait_semaphores: vec![SemaphoreSubmitInfo::semaphore(
|
wait_semaphores: vec![SemaphoreSubmitInfo::new(
|
||||||
release_sem.clone(),
|
release_sem.clone(),
|
||||||
)],
|
)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -131,6 +131,10 @@ unsafe impl<A> PrimaryCommandBufferAbstract for PrimaryAutoCommandBuffer<A>
|
|||||||
where
|
where
|
||||||
A: CommandBufferAllocator,
|
A: CommandBufferAllocator,
|
||||||
{
|
{
|
||||||
|
fn queue_family_index(&self) -> u32 {
|
||||||
|
self.inner.queue_family_index()
|
||||||
|
}
|
||||||
|
|
||||||
fn usage(&self) -> CommandBufferUsage {
|
fn usage(&self) -> CommandBufferUsage {
|
||||||
self.inner.usage()
|
self.inner.usage()
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@
|
|||||||
//! [`StandardCommandBufferAllocator`]: self::allocator::StandardCommandBufferAllocator
|
//! [`StandardCommandBufferAllocator`]: self::allocator::StandardCommandBufferAllocator
|
||||||
//! [`CommandBufferAllocator`]: self::allocator::CommandBufferAllocator
|
//! [`CommandBufferAllocator`]: self::allocator::CommandBufferAllocator
|
||||||
//! [inherit]: CommandBufferInheritanceInfo
|
//! [inherit]: CommandBufferInheritanceInfo
|
||||||
//! [`build`]: CommandBufferBuilder::build
|
//! [`build`]: AutoCommandBufferBuilder::build
|
||||||
//! [pipeline barriers]: CommandBufferBuilder::pipeline_barrier
|
//! [pipeline barriers]: CommandBufferBuilder::pipeline_barrier
|
||||||
//! [`GpuFuture`]: crate::sync::GpuFuture
|
//! [`GpuFuture`]: crate::sync::GpuFuture
|
||||||
|
|
||||||
@ -723,7 +723,7 @@ pub struct SubmitInfo {
|
|||||||
/// The command buffers to execute.
|
/// The command buffers to execute.
|
||||||
///
|
///
|
||||||
/// The default value is empty.
|
/// The default value is empty.
|
||||||
pub command_buffers: Vec<Arc<dyn PrimaryCommandBufferAbstract>>,
|
pub command_buffers: Vec<CommandBufferSubmitInfo>,
|
||||||
|
|
||||||
/// The semaphores to signal after the execution of this batch of command buffer operations
|
/// The semaphores to signal after the execution of this batch of command buffer operations
|
||||||
/// has completed.
|
/// has completed.
|
||||||
@ -746,10 +746,95 @@ impl Default for SubmitInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parameters for a semaphore signal or wait operation in a command buffer submission.
|
impl SubmitInfo {
|
||||||
|
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||||
|
let &Self {
|
||||||
|
ref wait_semaphores,
|
||||||
|
ref command_buffers,
|
||||||
|
ref signal_semaphores,
|
||||||
|
_ne: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
for (index, semaphore_submit_info) in wait_semaphores.iter().enumerate() {
|
||||||
|
semaphore_submit_info
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context(format!("wait_semaphores[{}]", index)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, command_buffer_submit_info) in command_buffers.iter().enumerate() {
|
||||||
|
command_buffer_submit_info
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context(format!("command_buffers[{}]", index)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, semaphore_submit_info) in signal_semaphores.iter().enumerate() {
|
||||||
|
semaphore_submit_info
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context(format!("signal_semaphores[{}]", index)))?;
|
||||||
|
|
||||||
|
let &SemaphoreSubmitInfo {
|
||||||
|
semaphore: _,
|
||||||
|
stages,
|
||||||
|
_ne: _,
|
||||||
|
} = semaphore_submit_info;
|
||||||
|
|
||||||
|
if stages != PipelineStages::ALL_COMMANDS && !device.enabled_features().synchronization2
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: format!("signal_semaphores[{}].stages", index).into(),
|
||||||
|
problem: "is not `PipelineStages::ALL_COMMANDS`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"synchronization2",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-vkQueueSubmit2-synchronization2-03866"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters for a command buffer in a queue submit operation.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct CommandBufferSubmitInfo {
|
||||||
|
/// The command buffer to execute.
|
||||||
|
///
|
||||||
|
/// There is no default value.
|
||||||
|
pub command_buffer: Arc<dyn PrimaryCommandBufferAbstract>,
|
||||||
|
|
||||||
|
pub _ne: crate::NonExhaustive,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandBufferSubmitInfo {
|
||||||
|
/// Returns a `CommandBufferSubmitInfo` with the specified `command_buffer`.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(command_buffer: Arc<dyn PrimaryCommandBufferAbstract>) -> Self {
|
||||||
|
Self {
|
||||||
|
command_buffer,
|
||||||
|
_ne: crate::NonExhaustive(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||||
|
let &Self {
|
||||||
|
ref command_buffer,
|
||||||
|
_ne: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
// VUID?
|
||||||
|
assert_eq!(device, command_buffer.device().as_ref());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters for a semaphore signal or wait operation in a queue submit operation.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SemaphoreSubmitInfo {
|
pub struct SemaphoreSubmitInfo {
|
||||||
/// The semaphore to signal or wait for.
|
/// The semaphore to signal or wait for.
|
||||||
|
///
|
||||||
|
/// There is no default value.
|
||||||
pub semaphore: Arc<Semaphore>,
|
pub semaphore: Arc<Semaphore>,
|
||||||
|
|
||||||
/// For a semaphore wait operation, specifies the pipeline stages in the second synchronization
|
/// For a semaphore wait operation, specifies the pipeline stages in the second synchronization
|
||||||
@ -774,13 +859,191 @@ pub struct SemaphoreSubmitInfo {
|
|||||||
impl SemaphoreSubmitInfo {
|
impl SemaphoreSubmitInfo {
|
||||||
/// Returns a `SemaphoreSubmitInfo` with the specified `semaphore`.
|
/// Returns a `SemaphoreSubmitInfo` with the specified `semaphore`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn semaphore(semaphore: Arc<Semaphore>) -> Self {
|
pub fn new(semaphore: Arc<Semaphore>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
semaphore,
|
semaphore,
|
||||||
stages: PipelineStages::ALL_COMMANDS,
|
stages: PipelineStages::ALL_COMMANDS,
|
||||||
_ne: crate::NonExhaustive(()),
|
_ne: crate::NonExhaustive(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||||
|
let &Self {
|
||||||
|
ref semaphore,
|
||||||
|
stages,
|
||||||
|
_ne: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
// VUID?
|
||||||
|
assert_eq!(device, semaphore.device().as_ref());
|
||||||
|
|
||||||
|
stages.validate_device(device).map_err(|err| {
|
||||||
|
err.add_context("stages")
|
||||||
|
.set_vuids(&["VUID-VkSemaphoreSubmitInfo-stageMask-parameter"])
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if !device.enabled_features().synchronization2 && stages.contains_flags2() {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains flags from `VkPipelineStageFlagBits2`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"synchronization2",
|
||||||
|
)])]),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().geometry_shader
|
||||||
|
&& stages.intersects(PipelineStages::GEOMETRY_SHADER)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::GEOMETRY_SHADER`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"geometry_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03929"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().tessellation_shader
|
||||||
|
&& stages.intersects(
|
||||||
|
PipelineStages::TESSELLATION_CONTROL_SHADER
|
||||||
|
| PipelineStages::TESSELLATION_EVALUATION_SHADER,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
|
||||||
|
`PipelineStages::TESSELLATION_EVALUATION_SHADER`"
|
||||||
|
.into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"tessellation_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03930"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().conditional_rendering
|
||||||
|
&& stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::CONDITIONAL_RENDERING`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"conditional_rendering",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03931"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().fragment_density_map
|
||||||
|
&& stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"fragment_density_map",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03932"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().transform_feedback
|
||||||
|
&& stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::TRANSFORM_FEEDBACK`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"transform_feedback",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03933"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().mesh_shader && stages.intersects(PipelineStages::MESH_SHADER)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::MESH_SHADER`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"mesh_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03934"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().task_shader && stages.intersects(PipelineStages::TASK_SHADER)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::TASK_SHADER`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"task_shader",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03935"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(device.enabled_features().attachment_fragment_shading_rate
|
||||||
|
|| device.enabled_features().shading_rate_image)
|
||||||
|
&& stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[
|
||||||
|
RequiresAllOf(&[Requires::Feature("attachment_fragment_shading_rate")]),
|
||||||
|
RequiresAllOf(&[Requires::Feature("shading_rate_image")]),
|
||||||
|
]),
|
||||||
|
vuids: &["VUID-VkMemoryBarrier2-shadingRateImage-07316"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().subpass_shading
|
||||||
|
&& stages.intersects(PipelineStages::SUBPASS_SHADING)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::SUBPASS_SHADING`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"subpass_shading",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-04957"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !device.enabled_features().invocation_mask
|
||||||
|
&& stages.intersects(PipelineStages::INVOCATION_MASK)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::INVOCATION_MASK`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"invocation_mask",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-04995"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(device.enabled_extensions().nv_ray_tracing
|
||||||
|
|| device.enabled_features().ray_tracing_pipeline)
|
||||||
|
&& stages.intersects(PipelineStages::RAY_TRACING_SHADER)
|
||||||
|
{
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "stages".into(),
|
||||||
|
problem: "contains `PipelineStages::RAY_TRACING_SHADER`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"ray_tracing_pipeline",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-07946"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
CommandBufferInheritanceInfo, CommandBufferResourcesUsage, CommandBufferState,
|
CommandBufferInheritanceInfo, CommandBufferResourcesUsage, CommandBufferState,
|
||||||
CommandBufferUsage, SecondaryCommandBufferResourcesUsage, SemaphoreSubmitInfo, SubmitInfo,
|
CommandBufferSubmitInfo, CommandBufferUsage, SecondaryCommandBufferResourcesUsage,
|
||||||
|
SemaphoreSubmitInfo, SubmitInfo,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
@ -17,7 +18,10 @@ use crate::{
|
|||||||
image::{Image, ImageLayout},
|
image::{Image, ImageLayout},
|
||||||
swapchain::Swapchain,
|
swapchain::Swapchain,
|
||||||
sync::{
|
sync::{
|
||||||
future::{now, AccessCheckError, AccessError, GpuFuture, NowFuture, SubmitAnyBuilder},
|
future::{
|
||||||
|
now, queue_submit, AccessCheckError, AccessError, GpuFuture, NowFuture,
|
||||||
|
SubmitAnyBuilder,
|
||||||
|
},
|
||||||
PipelineStages,
|
PipelineStages,
|
||||||
},
|
},
|
||||||
DeviceSize, SafeDeref, Validated, ValidationError, VulkanError, VulkanObject,
|
DeviceSize, SafeDeref, Validated, ValidationError, VulkanError, VulkanObject,
|
||||||
@ -38,6 +42,9 @@ use std::{
|
|||||||
pub unsafe trait PrimaryCommandBufferAbstract:
|
pub unsafe trait PrimaryCommandBufferAbstract:
|
||||||
VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
|
VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
|
||||||
{
|
{
|
||||||
|
/// Returns the queue family index of this command buffer.
|
||||||
|
fn queue_family_index(&self) -> u32;
|
||||||
|
|
||||||
/// Returns the usage of this command buffer.
|
/// Returns the usage of this command buffer.
|
||||||
fn usage(&self) -> CommandBufferUsage;
|
fn usage(&self) -> CommandBufferUsage;
|
||||||
|
|
||||||
@ -143,6 +150,10 @@ where
|
|||||||
T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
|
T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
|
||||||
T::Target: PrimaryCommandBufferAbstract,
|
T::Target: PrimaryCommandBufferAbstract,
|
||||||
{
|
{
|
||||||
|
fn queue_family_index(&self) -> u32 {
|
||||||
|
(**self).queue_family_index()
|
||||||
|
}
|
||||||
|
|
||||||
fn usage(&self) -> CommandBufferUsage {
|
fn usage(&self) -> CommandBufferUsage {
|
||||||
(**self).usage()
|
(**self).usage()
|
||||||
}
|
}
|
||||||
@ -237,7 +248,9 @@ where
|
|||||||
Ok(match self.previous.build_submission()? {
|
Ok(match self.previous.build_submission()? {
|
||||||
SubmitAnyBuilder::Empty => SubmitAnyBuilder::CommandBuffer(
|
SubmitAnyBuilder::Empty => SubmitAnyBuilder::CommandBuffer(
|
||||||
SubmitInfo {
|
SubmitInfo {
|
||||||
command_buffers: vec![self.command_buffer.clone()],
|
command_buffers: vec![CommandBufferSubmitInfo::new(
|
||||||
|
self.command_buffer.clone(),
|
||||||
|
)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
@ -251,11 +264,13 @@ where
|
|||||||
SemaphoreSubmitInfo {
|
SemaphoreSubmitInfo {
|
||||||
// TODO: correct stages ; hard
|
// TODO: correct stages ; hard
|
||||||
stages: PipelineStages::ALL_COMMANDS,
|
stages: PipelineStages::ALL_COMMANDS,
|
||||||
..SemaphoreSubmitInfo::semaphore(semaphore)
|
..SemaphoreSubmitInfo::new(semaphore)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
command_buffers: vec![self.command_buffer.clone()],
|
command_buffers: vec![CommandBufferSubmitInfo::new(
|
||||||
|
self.command_buffer.clone(),
|
||||||
|
)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
@ -265,7 +280,7 @@ where
|
|||||||
// FIXME: add pipeline barrier
|
// FIXME: add pipeline barrier
|
||||||
submit_info
|
submit_info
|
||||||
.command_buffers
|
.command_buffers
|
||||||
.push(self.command_buffer.clone());
|
.push(CommandBufferSubmitInfo::new(self.command_buffer.clone()));
|
||||||
SubmitAnyBuilder::CommandBuffer(submit_info, fence)
|
SubmitAnyBuilder::CommandBuffer(submit_info, fence)
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_, _) => {
|
SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_, _) => {
|
||||||
@ -305,9 +320,7 @@ where
|
|||||||
match self.build_submission_impl()? {
|
match self.build_submission_impl()? {
|
||||||
SubmitAnyBuilder::Empty => {}
|
SubmitAnyBuilder::Empty => {}
|
||||||
SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
|
SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
|
||||||
self.queue.with(|mut q| {
|
queue_submit(&self.queue, submit_info, fence, &self.previous).unwrap();
|
||||||
q.submit_with_future(submit_info, fence, &self.previous, &self.queue)
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
@ -319,7 +332,36 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn signal_finished(&self) {
|
unsafe fn signal_finished(&self) {
|
||||||
self.finished.store(true, Ordering::SeqCst);
|
if !self.finished.swap(true, Ordering::SeqCst) {
|
||||||
|
let resource_usage = self.command_buffer.resources_usage();
|
||||||
|
|
||||||
|
for usage in &resource_usage.buffers {
|
||||||
|
let mut state = usage.buffer.state();
|
||||||
|
|
||||||
|
for (range, range_usage) in usage.ranges.iter() {
|
||||||
|
if range_usage.mutable {
|
||||||
|
state.gpu_write_unlock(range.clone());
|
||||||
|
} else {
|
||||||
|
state.gpu_read_unlock(range.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for usage in &resource_usage.images {
|
||||||
|
let mut state = usage.image.state();
|
||||||
|
|
||||||
|
for (range, range_usage) in usage.ranges.iter() {
|
||||||
|
if range_usage.mutable {
|
||||||
|
state.gpu_write_unlock(range.clone());
|
||||||
|
} else {
|
||||||
|
state.gpu_read_unlock(range.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.command_buffer.state().set_submit_finished();
|
||||||
|
}
|
||||||
|
|
||||||
self.previous.signal_finished();
|
self.previous.signal_finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +487,10 @@ where
|
|||||||
self.flush().unwrap();
|
self.flush().unwrap();
|
||||||
// Block until the queue finished.
|
// Block until the queue finished.
|
||||||
self.queue.with(|mut q| q.wait_idle()).unwrap();
|
self.queue.with(|mut q| q.wait_idle()).unwrap();
|
||||||
unsafe { self.previous.signal_finished() };
|
|
||||||
|
unsafe {
|
||||||
|
self.signal_finished();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
//! [`DescriptorSet`]. It is what you pass to the draw functions.
|
//! [`DescriptorSet`]. It is what you pass to the draw functions.
|
||||||
//!
|
//!
|
||||||
//! [`DescriptorPool`]: pool::DescriptorPool
|
//! [`DescriptorPool`]: pool::DescriptorPool
|
||||||
|
//! [`UnsafeDescriptorSet`]: sys::UnsafeDescriptorSet
|
||||||
//! [`DescriptorSetAllocator`]: allocator::DescriptorSetAllocator
|
//! [`DescriptorSetAllocator`]: allocator::DescriptorSetAllocator
|
||||||
//! [`StandardDescriptorSetAllocator`]: allocator::StandardDescriptorSetAllocator
|
//! [`StandardDescriptorSetAllocator`]: allocator::StandardDescriptorSetAllocator
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,10 +14,11 @@ use crate::{
|
|||||||
image::{Image, ImageLayout},
|
image::{Image, ImageLayout},
|
||||||
sync::{
|
sync::{
|
||||||
fence::Fence,
|
fence::Fence,
|
||||||
future::{AccessCheckError, AccessError, GpuFuture, SubmitAnyBuilder},
|
future::{queue_present, AccessCheckError, AccessError, GpuFuture, SubmitAnyBuilder},
|
||||||
semaphore::Semaphore,
|
semaphore::Semaphore,
|
||||||
},
|
},
|
||||||
DeviceSize, Validated, ValidationError, VulkanError, VulkanObject,
|
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError,
|
||||||
|
VulkanObject,
|
||||||
};
|
};
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
use std::{
|
use std::{
|
||||||
@ -145,16 +146,6 @@ pub fn acquire_next_image(
|
|||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let mut state = semaphore.state();
|
|
||||||
state.swapchain_acquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let mut state = fence.state();
|
|
||||||
state.import_swapchain_acquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
image_index,
|
image_index,
|
||||||
is_suboptimal,
|
is_suboptimal,
|
||||||
@ -216,16 +207,6 @@ pub unsafe fn acquire_next_image_raw(
|
|||||||
err => return Err(VulkanError::from(err).into()),
|
err => return Err(VulkanError::from(err).into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(semaphore) = semaphore {
|
|
||||||
let mut state = semaphore.state();
|
|
||||||
state.swapchain_acquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(fence) = fence {
|
|
||||||
let mut state = fence.state();
|
|
||||||
state.import_swapchain_acquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AcquiredImage {
|
Ok(AcquiredImage {
|
||||||
image_index: out.assume_init(),
|
image_index: out.assume_init(),
|
||||||
is_suboptimal,
|
is_suboptimal,
|
||||||
@ -431,12 +412,12 @@ pub struct PresentInfo {
|
|||||||
/// The semaphores to wait for before beginning the execution of the present operations.
|
/// The semaphores to wait for before beginning the execution of the present operations.
|
||||||
///
|
///
|
||||||
/// The default value is empty.
|
/// The default value is empty.
|
||||||
pub wait_semaphores: Vec<Arc<Semaphore>>,
|
pub wait_semaphores: Vec<SemaphorePresentInfo>,
|
||||||
|
|
||||||
/// The present operations to perform.
|
/// The present operations to perform.
|
||||||
///
|
///
|
||||||
/// The default value is empty.
|
/// The default value is empty.
|
||||||
pub swapchain_infos: Vec<SwapchainPresentInfo>,
|
pub swapchains: Vec<SwapchainPresentInfo>,
|
||||||
|
|
||||||
pub _ne: crate::NonExhaustive,
|
pub _ne: crate::NonExhaustive,
|
||||||
}
|
}
|
||||||
@ -446,12 +427,79 @@ impl Default for PresentInfo {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
wait_semaphores: Vec::new(),
|
wait_semaphores: Vec::new(),
|
||||||
swapchain_infos: Vec::new(),
|
swapchains: Vec::new(),
|
||||||
_ne: crate::NonExhaustive(()),
|
_ne: crate::NonExhaustive(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PresentInfo {
|
||||||
|
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||||
|
let &Self {
|
||||||
|
ref wait_semaphores,
|
||||||
|
swapchains: ref swapchain_infos,
|
||||||
|
_ne: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
for (index, semaphore_present_info) in wait_semaphores.iter().enumerate() {
|
||||||
|
semaphore_present_info
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context(format!("wait_semaphores[{}]", index)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(!swapchain_infos.is_empty());
|
||||||
|
|
||||||
|
let has_present_mode = swapchain_infos
|
||||||
|
.first()
|
||||||
|
.map_or(false, |first| first.present_mode.is_some());
|
||||||
|
|
||||||
|
for (index, swapchain_info) in swapchain_infos.iter().enumerate() {
|
||||||
|
swapchain_info
|
||||||
|
.validate(device)
|
||||||
|
.map_err(|err| err.add_context(format!("swapchain_infos[{}]", index)))?;
|
||||||
|
|
||||||
|
let &SwapchainPresentInfo {
|
||||||
|
swapchain: _,
|
||||||
|
image_index: _,
|
||||||
|
present_id: _,
|
||||||
|
present_mode,
|
||||||
|
present_regions: _,
|
||||||
|
_ne: _,
|
||||||
|
} = swapchain_info;
|
||||||
|
|
||||||
|
if has_present_mode {
|
||||||
|
if present_mode.is_none() {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"`swapchain_infos[0].present_mode` is `Some`, but \
|
||||||
|
`swapchain_infos[{}].present_mode` is not also `Some`",
|
||||||
|
index
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkPresentInfoKHR-pSwapchains-09199"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if present_mode.is_some() {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"`swapchain_infos[0].present_mode` is `None`, but \
|
||||||
|
`swapchain_infos[{}].present_mode` is not also `None`",
|
||||||
|
index
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkPresentInfoKHR-pSwapchains-09199"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parameters for a single present operation on a swapchain.
|
/// Parameters for a single present operation on a swapchain.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SwapchainPresentInfo {
|
pub struct SwapchainPresentInfo {
|
||||||
@ -530,6 +578,113 @@ impl SwapchainPresentInfo {
|
|||||||
_ne: crate::NonExhaustive(()),
|
_ne: crate::NonExhaustive(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||||
|
let &Self {
|
||||||
|
ref swapchain,
|
||||||
|
image_index,
|
||||||
|
present_id,
|
||||||
|
present_mode,
|
||||||
|
ref present_regions,
|
||||||
|
_ne: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
// VUID-VkPresentInfoKHR-commonparent
|
||||||
|
assert_eq!(device, swapchain.device().as_ref());
|
||||||
|
|
||||||
|
if image_index >= swapchain.image_count() {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`image_index` is not less than `swapchain.image_count()`".into(),
|
||||||
|
vuids: &["VUID-VkPresentInfoKHR-pImageIndices-01430"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if present_id.is_some() && !device.enabled_features().present_id {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "present_id".into(),
|
||||||
|
problem: "is `Some`".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||||
|
"present_id",
|
||||||
|
)])]),
|
||||||
|
vuids: &["VUID-VkPresentInfoKHR-pNext-06235"],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(present_mode) = present_mode {
|
||||||
|
if !swapchain.present_modes().contains(&present_mode) {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "`swapchain.present_modes()` does not contain `present_mode`".into(),
|
||||||
|
vuids: &["VUID-VkSwapchainPresentModeInfoEXT-pPresentModes-07761"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !present_regions.is_empty() && !device.enabled_extensions().khr_incremental_present {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
context: "present_regions".into(),
|
||||||
|
problem: "is not empty".into(),
|
||||||
|
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
|
||||||
|
"khr_incremental_present",
|
||||||
|
)])]),
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, rectangle_layer) in present_regions.iter().enumerate() {
|
||||||
|
let &RectangleLayer {
|
||||||
|
offset,
|
||||||
|
extent,
|
||||||
|
layer,
|
||||||
|
} = rectangle_layer;
|
||||||
|
|
||||||
|
if offset[0] + extent[0] > swapchain.image_extent()[0] {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"`present_regions[{0}].offset[0]` + `present_regions[{0}].extent[0]` is \
|
||||||
|
greater than `swapchain.image_extent()[0]`",
|
||||||
|
index
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkRectLayerKHR-offset-04864"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset[1] + extent[1] > swapchain.image_extent()[1] {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"`present_regions[{0}].offset[1]` + `present_regions[{0}].extent[1]` is \
|
||||||
|
greater than `swapchain.image_extent()[1]`",
|
||||||
|
index
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkRectLayerKHR-offset-04864"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if layer >= swapchain.image_array_layers() {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"`present_regions[{0}].layer` is greater than \
|
||||||
|
`swapchain.image_array_layers()`",
|
||||||
|
index
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-VkRectLayerKHR-layer-01262"],
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafe
|
||||||
|
// VUID-VkPresentInfoKHR-pImageIndices-01430
|
||||||
|
// VUID-VkPresentIdKHR-presentIds-04999
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a rectangular region on an image layer.
|
/// Represents a rectangular region on an image layer.
|
||||||
@ -572,6 +727,40 @@ impl From<&RectangleLayer> for ash::vk::RectLayerKHR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parameters for a semaphore wait operation in a queue present operation.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SemaphorePresentInfo {
|
||||||
|
/// The semaphore to wait for.
|
||||||
|
///
|
||||||
|
/// There is no default value.
|
||||||
|
pub semaphore: Arc<Semaphore>,
|
||||||
|
|
||||||
|
pub _ne: crate::NonExhaustive,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SemaphorePresentInfo {
|
||||||
|
/// Returns a `SemaphorePresentInfo` with the specified `semaphore`.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(semaphore: Arc<Semaphore>) -> Self {
|
||||||
|
Self {
|
||||||
|
semaphore,
|
||||||
|
_ne: crate::NonExhaustive(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
|
||||||
|
let &Self {
|
||||||
|
ref semaphore,
|
||||||
|
_ne: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
// VUID-VkPresentInfoKHR-commonparent
|
||||||
|
assert_eq!(device, semaphore.device().as_ref());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a swapchain image being presented on the screen.
|
/// Represents a swapchain image being presented on the screen.
|
||||||
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
|
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
|
||||||
pub struct PresentFuture<P>
|
pub struct PresentFuture<P>
|
||||||
@ -640,13 +829,16 @@ where
|
|||||||
|
|
||||||
Ok(match self.previous.build_submission()? {
|
Ok(match self.previous.build_submission()? {
|
||||||
SubmitAnyBuilder::Empty => SubmitAnyBuilder::QueuePresent(PresentInfo {
|
SubmitAnyBuilder::Empty => SubmitAnyBuilder::QueuePresent(PresentInfo {
|
||||||
swapchain_infos: vec![self.swapchain_info.clone()],
|
swapchains: vec![self.swapchain_info.clone()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
|
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
|
||||||
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
||||||
wait_semaphores: semaphores.into_iter().collect(),
|
wait_semaphores: semaphores
|
||||||
swapchain_infos: vec![self.swapchain_info.clone()],
|
.into_iter()
|
||||||
|
.map(SemaphorePresentInfo::new)
|
||||||
|
.collect(),
|
||||||
|
swapchains: vec![self.swapchain_info.clone()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -654,7 +846,7 @@ where
|
|||||||
self.previous.flush()?;
|
self.previous.flush()?;
|
||||||
|
|
||||||
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
||||||
swapchain_infos: vec![self.swapchain_info.clone()],
|
swapchains: vec![self.swapchain_info.clone()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -662,26 +854,24 @@ where
|
|||||||
self.previous.flush()?;
|
self.previous.flush()?;
|
||||||
|
|
||||||
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
||||||
swapchain_infos: vec![self.swapchain_info.clone()],
|
swapchains: vec![self.swapchain_info.clone()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::QueuePresent(mut present_info) => {
|
SubmitAnyBuilder::QueuePresent(mut present_info) => {
|
||||||
if present_info.swapchain_infos.first().map_or(false, |prev| {
|
if present_info.swapchains.first().map_or(false, |prev| {
|
||||||
prev.present_mode.is_some() != self.swapchain_info.present_mode.is_some()
|
prev.present_mode.is_some() != self.swapchain_info.present_mode.is_some()
|
||||||
}) {
|
}) {
|
||||||
// If the present mode Option variants don't match, create a new command.
|
// If the present mode Option variants don't match, create a new command.
|
||||||
self.previous.flush()?;
|
self.previous.flush()?;
|
||||||
|
|
||||||
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
SubmitAnyBuilder::QueuePresent(PresentInfo {
|
||||||
swapchain_infos: vec![self.swapchain_info.clone()],
|
swapchains: vec![self.swapchain_info.clone()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, add our swapchain to the previous.
|
// Otherwise, add our swapchain to the previous.
|
||||||
present_info
|
present_info.swapchains.push(self.swapchain_info.clone());
|
||||||
.swapchain_infos
|
|
||||||
.push(self.swapchain_info.clone());
|
|
||||||
|
|
||||||
SubmitAnyBuilder::QueuePresent(present_info)
|
SubmitAnyBuilder::QueuePresent(present_info)
|
||||||
}
|
}
|
||||||
@ -701,21 +891,17 @@ where
|
|||||||
SubmitAnyBuilder::QueuePresent(present_info) => {
|
SubmitAnyBuilder::QueuePresent(present_info) => {
|
||||||
let PresentInfo {
|
let PresentInfo {
|
||||||
wait_semaphores: _,
|
wait_semaphores: _,
|
||||||
swapchain_infos,
|
swapchains,
|
||||||
_ne: _,
|
_ne: _,
|
||||||
} = &present_info;
|
} = &present_info;
|
||||||
|
|
||||||
let has_present_mode = swapchain_infos
|
for swapchain_info in swapchains {
|
||||||
.first()
|
|
||||||
.map_or(false, |first| first.present_mode.is_some());
|
|
||||||
|
|
||||||
for swapchain_info in swapchain_infos {
|
|
||||||
let &SwapchainPresentInfo {
|
let &SwapchainPresentInfo {
|
||||||
ref swapchain,
|
ref swapchain,
|
||||||
image_index: _,
|
image_index: _,
|
||||||
present_id,
|
present_id,
|
||||||
present_regions: _,
|
present_regions: _,
|
||||||
present_mode,
|
present_mode: _,
|
||||||
_ne: _,
|
_ne: _,
|
||||||
} = swapchain_info;
|
} = swapchain_info;
|
||||||
|
|
||||||
@ -731,25 +917,6 @@ where
|
|||||||
})
|
})
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(present_mode) = present_mode {
|
|
||||||
assert!(has_present_mode);
|
|
||||||
|
|
||||||
if !swapchain.present_modes().contains(&present_mode) {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the requested present mode is not one of the modes \
|
|
||||||
in `swapchain.present_modes()`"
|
|
||||||
.into(),
|
|
||||||
vuids: &[
|
|
||||||
"VUID-VkSwapchainPresentModeInfoEXT-pPresentModes-07761",
|
|
||||||
],
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert!(!has_present_mode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.previous.check_swapchain_image_acquired(
|
match self.previous.check_swapchain_image_acquired(
|
||||||
@ -769,9 +936,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self
|
Ok(queue_present(&self.queue, present_info)?
|
||||||
.queue
|
|
||||||
.with(|mut q| q.present_unchecked(present_info))?
|
|
||||||
.map(|r| r.map(|_| ()))
|
.map(|r| r.map(|_| ()))
|
||||||
.fold(Ok(()), Result::and)?)
|
.fold(Ok(()), Result::and)?)
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,38 @@
|
|||||||
|
|
||||||
//! A fence provides synchronization between the device and the host, or between an external source
|
//! A fence provides synchronization between the device and the host, or between an external source
|
||||||
//! and the host.
|
//! and the host.
|
||||||
|
//!
|
||||||
|
//! A fence has two states: **signaled** and **unsignaled**.
|
||||||
|
//!
|
||||||
|
//! The device can only perform one operation on a fence:
|
||||||
|
//! - A **fence signal operation** will put the fence into the signaled state.
|
||||||
|
//!
|
||||||
|
//! The host can poll a fence's status, wait for it to become signaled, or reset the fence back
|
||||||
|
//! to the unsignaled state.
|
||||||
|
//!
|
||||||
|
//! # Queue-to-host synchronization
|
||||||
|
//!
|
||||||
|
//! The primary use of a fence is to know when a queue operation has completed executing.
|
||||||
|
//! When adding a command to a queue, a fence can be provided with the command, to be signaled
|
||||||
|
//! when the operation finishes. You can check for a fence's current status by calling
|
||||||
|
//! `is_signaled`, `wait` or `await` on it. If the fence is found to be signaled, that means that
|
||||||
|
//! the queue has completed the operation that is associated with the fence, and all operations
|
||||||
|
//! that happened-before it have been completed as well.
|
||||||
|
//!
|
||||||
|
//! # Safety
|
||||||
|
//!
|
||||||
|
//! - There must never be more than one fence signal operation queued at any given time.
|
||||||
|
//! - The fence must be unsignaled at the time the function (for example [`submit`]) is called.
|
||||||
|
//!
|
||||||
|
//! [`submit`]: crate::device::QueueGuard::submit
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
device::{physical::PhysicalDevice, Device, DeviceOwned, Queue},
|
device::{physical::PhysicalDevice, Device, DeviceOwned},
|
||||||
instance::InstanceOwnedDebugWrapper,
|
instance::InstanceOwnedDebugWrapper,
|
||||||
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
|
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
|
||||||
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
|
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
|
||||||
VulkanObject,
|
VulkanObject,
|
||||||
};
|
};
|
||||||
use parking_lot::{Mutex, MutexGuard};
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::{
|
use std::{
|
||||||
@ -26,32 +49,12 @@ use std::{
|
|||||||
num::NonZeroU64,
|
num::NonZeroU64,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
ptr,
|
ptr,
|
||||||
sync::{Arc, Weak},
|
sync::Arc,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A two-state synchronization primitive that is signalled by the device and waited on by the host.
|
/// A two-state synchronization primitive that is signalled by the device and waited on by the host.
|
||||||
///
|
|
||||||
/// # Queue-to-host synchronization
|
|
||||||
///
|
|
||||||
/// The primary use of a fence is to know when a queue operation has completed executing.
|
|
||||||
/// When adding a command to a queue, a fence can be provided with the command, to be signaled
|
|
||||||
/// when the operation finishes. You can check for a fence's current status by calling
|
|
||||||
/// `is_signaled`, `wait` or `await` on it. If the fence is found to be signaled, that means that
|
|
||||||
/// the queue has completed the operation that is associated with the fence, and all operations that
|
|
||||||
/// were submitted before it have been completed as well.
|
|
||||||
///
|
|
||||||
/// When a queue command accesses a resource, it must be kept alive until the queue command has
|
|
||||||
/// finished executing, and you may not be allowed to perform certain other operations (or even any)
|
|
||||||
/// while the resource is in use. By calling `is_signaled`, `wait` or `await`, the queue will be
|
|
||||||
/// notified when the fence is signaled, so that all resources of the associated queue operation and
|
|
||||||
/// preceding operations can be released.
|
|
||||||
///
|
|
||||||
/// Because of this, it is highly recommended to call `is_signaled`, `wait` or `await` on your fences.
|
|
||||||
/// Otherwise, the queue will hold onto resources indefinitely (using up memory)
|
|
||||||
/// and resource locks will not be released, which may cause errors when submitting future
|
|
||||||
/// queue operations.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Fence {
|
pub struct Fence {
|
||||||
handle: ash::vk::Fence,
|
handle: ash::vk::Fence,
|
||||||
@ -62,7 +65,6 @@ pub struct Fence {
|
|||||||
export_handle_types: ExternalFenceHandleTypes,
|
export_handle_types: ExternalFenceHandleTypes,
|
||||||
|
|
||||||
must_put_in_pool: bool,
|
must_put_in_pool: bool,
|
||||||
state: Mutex<FenceState>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fence {
|
impl Fence {
|
||||||
@ -141,10 +143,6 @@ impl Fence {
|
|||||||
export_handle_types,
|
export_handle_types,
|
||||||
|
|
||||||
must_put_in_pool: false,
|
must_put_in_pool: false,
|
||||||
state: Mutex::new(FenceState {
|
|
||||||
is_signaled: flags.intersects(FenceCreateFlags::SIGNALED),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +174,6 @@ impl Fence {
|
|||||||
export_handle_types: ExternalFenceHandleTypes::empty(),
|
export_handle_types: ExternalFenceHandleTypes::empty(),
|
||||||
|
|
||||||
must_put_in_pool: true,
|
must_put_in_pool: true,
|
||||||
state: Mutex::new(Default::default()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -218,10 +215,6 @@ impl Fence {
|
|||||||
export_handle_types,
|
export_handle_types,
|
||||||
|
|
||||||
must_put_in_pool: false,
|
must_put_in_pool: false,
|
||||||
state: Mutex::new(FenceState {
|
|
||||||
is_signaled: flags.intersects(FenceCreateFlags::SIGNALED),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,84 +233,44 @@ impl Fence {
|
|||||||
/// Returns true if the fence is signaled.
|
/// Returns true if the fence is signaled.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_signaled(&self) -> Result<bool, VulkanError> {
|
pub fn is_signaled(&self) -> Result<bool, VulkanError> {
|
||||||
let queue_to_signal = {
|
let result = unsafe {
|
||||||
let mut state = self.state();
|
let fns = self.device.fns();
|
||||||
|
(fns.v1_0.get_fence_status)(self.device.handle(), self.handle)
|
||||||
// If the fence is already signaled, or it's unsignaled but there's no queue that
|
|
||||||
// could signal it, return the currently known value.
|
|
||||||
if let Some(is_signaled) = state.is_signaled() {
|
|
||||||
return Ok(is_signaled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We must ask Vulkan for the state.
|
|
||||||
let result = unsafe {
|
|
||||||
let fns = self.device.fns();
|
|
||||||
(fns.v1_0.get_fence_status)(self.device.handle(), self.handle)
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
|
||||||
ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
|
|
||||||
ash::vk::Result::NOT_READY => return Ok(false),
|
|
||||||
err => return Err(VulkanError::from(err)),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we have a queue that we need to signal our status to,
|
match result {
|
||||||
// do so now after the state lock is dropped, to avoid deadlocks.
|
ash::vk::Result::SUCCESS => Ok(true),
|
||||||
if let Some(queue) = queue_to_signal {
|
ash::vk::Result::NOT_READY => Ok(false),
|
||||||
unsafe {
|
err => Err(VulkanError::from(err)),
|
||||||
queue.with(|mut q| q.fence_signaled(self));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits until the fence is signaled, or at least until the timeout duration has elapsed.
|
/// Waits until the fence is signaled, or at least until the timeout duration has elapsed.
|
||||||
///
|
///
|
||||||
/// If you pass a duration of 0, then the function will return without blocking.
|
/// If you pass a duration of 0, then the function will return without blocking.
|
||||||
pub fn wait(&self, timeout: Option<Duration>) -> Result<(), VulkanError> {
|
pub fn wait(&self, timeout: Option<Duration>) -> Result<(), VulkanError> {
|
||||||
let queue_to_signal = {
|
let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
|
||||||
let mut state = self.state.lock();
|
timeout
|
||||||
|
.as_secs()
|
||||||
|
.saturating_mul(1_000_000_000)
|
||||||
|
.saturating_add(timeout.subsec_nanos() as u64)
|
||||||
|
});
|
||||||
|
|
||||||
// If the fence is already signaled, we don't need to wait.
|
let result = unsafe {
|
||||||
if state.is_signaled().unwrap_or(false) {
|
let fns = self.device.fns();
|
||||||
return Ok(());
|
(fns.v1_0.wait_for_fences)(
|
||||||
}
|
self.device.handle(),
|
||||||
|
1,
|
||||||
let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
|
&self.handle,
|
||||||
timeout
|
ash::vk::TRUE,
|
||||||
.as_secs()
|
timeout_ns,
|
||||||
.saturating_mul(1_000_000_000)
|
)
|
||||||
.saturating_add(timeout.subsec_nanos() as u64)
|
|
||||||
});
|
|
||||||
|
|
||||||
let result = unsafe {
|
|
||||||
let fns = self.device.fns();
|
|
||||||
(fns.v1_0.wait_for_fences)(
|
|
||||||
self.device.handle(),
|
|
||||||
1,
|
|
||||||
&self.handle,
|
|
||||||
ash::vk::TRUE,
|
|
||||||
timeout_ns,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
|
||||||
ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
|
|
||||||
err => return Err(VulkanError::from(err)),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we have a queue that we need to signal our status to,
|
match result {
|
||||||
// do so now after the state lock is dropped, to avoid deadlocks.
|
ash::vk::Result::SUCCESS => Ok(()),
|
||||||
if let Some(queue) = queue_to_signal {
|
err => Err(VulkanError::from(err)),
|
||||||
unsafe {
|
|
||||||
queue.with(|mut q| q.fence_signaled(self));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits for multiple fences at once.
|
/// Waits for multiple fences at once.
|
||||||
@ -358,153 +311,96 @@ impl Fence {
|
|||||||
fences: impl IntoIterator<Item = &'a Fence>,
|
fences: impl IntoIterator<Item = &'a Fence>,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let queues_to_signal: SmallVec<[_; 8]> = {
|
let iter = fences.into_iter();
|
||||||
let iter = fences.into_iter();
|
let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new();
|
||||||
let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new();
|
let mut fences: SmallVec<[_; 8]> = SmallVec::new();
|
||||||
let mut fences: SmallVec<[_; 8]> = SmallVec::new();
|
|
||||||
let mut states: SmallVec<[_; 8]> = SmallVec::new();
|
|
||||||
|
|
||||||
for fence in iter {
|
for fence in iter {
|
||||||
let state = fence.state.lock();
|
fences_vk.push(fence.handle);
|
||||||
|
fences.push(fence);
|
||||||
// Skip the fences that are already signaled.
|
|
||||||
if !state.is_signaled().unwrap_or(false) {
|
|
||||||
fences_vk.push(fence.handle);
|
|
||||||
fences.push(fence);
|
|
||||||
states.push(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VUID-vkWaitForFences-fenceCount-arraylength
|
|
||||||
// If there are no fences, or all the fences are signaled, we don't need to wait.
|
|
||||||
if fences_vk.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let device = &fences[0].device;
|
|
||||||
let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
|
|
||||||
timeout
|
|
||||||
.as_secs()
|
|
||||||
.saturating_mul(1_000_000_000)
|
|
||||||
.saturating_add(timeout.subsec_nanos() as u64)
|
|
||||||
});
|
|
||||||
|
|
||||||
let result = {
|
|
||||||
let fns = device.fns();
|
|
||||||
(fns.v1_0.wait_for_fences)(
|
|
||||||
device.handle(),
|
|
||||||
fences_vk.len() as u32,
|
|
||||||
fences_vk.as_ptr(),
|
|
||||||
ash::vk::TRUE, // TODO: let the user choose false here?
|
|
||||||
timeout_ns,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
|
||||||
ash::vk::Result::SUCCESS => fences
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut states)
|
|
||||||
.filter_map(|(fence, state)| state.set_signaled().map(|state| (state, fence)))
|
|
||||||
.collect(),
|
|
||||||
err => return Err(VulkanError::from(err)),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// If we have queues that we need to signal our status to,
|
|
||||||
// do so now after the state locks are dropped, to avoid deadlocks.
|
|
||||||
for (queue, fence) in queues_to_signal {
|
|
||||||
queue.with(|mut q| q.fence_signaled(fence));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
// VUID-vkWaitForFences-fenceCount-arraylength
|
||||||
|
// If there are no fences, we don't need to wait.
|
||||||
|
if fences_vk.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let device = &fences[0].device;
|
||||||
|
let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
|
||||||
|
timeout
|
||||||
|
.as_secs()
|
||||||
|
.saturating_mul(1_000_000_000)
|
||||||
|
.saturating_add(timeout.subsec_nanos() as u64)
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
let fns = device.fns();
|
||||||
|
(fns.v1_0.wait_for_fences)(
|
||||||
|
device.handle(),
|
||||||
|
fences_vk.len() as u32,
|
||||||
|
fences_vk.as_ptr(),
|
||||||
|
ash::vk::TRUE, // TODO: let the user choose false here?
|
||||||
|
timeout_ns,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
ash::vk::Result::SUCCESS => Ok(()),
|
||||||
|
err => Err(VulkanError::from(err)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the fence.
|
/// Resets the fence.
|
||||||
///
|
///
|
||||||
/// The fence must not be in use by a queue operation.
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - The fence must not be in use by the device.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset(&self) -> Result<(), Validated<VulkanError>> {
|
pub unsafe fn reset(&self) -> Result<(), Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_reset()?;
|
||||||
self.validate_reset(&state)?;
|
|
||||||
|
|
||||||
unsafe { Ok(self.reset_unchecked_locked(&mut state)?) }
|
unsafe { Ok(self.reset_unchecked()?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_reset(&self, state: &FenceState) -> Result<(), Box<ValidationError>> {
|
fn validate_reset(&self) -> Result<(), Box<ValidationError>> {
|
||||||
if state.is_in_queue() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the fence is in use".into(),
|
|
||||||
vuids: &["VUID-vkResetFences-pFences-01123"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn reset_unchecked(&self) -> Result<(), VulkanError> {
|
pub unsafe fn reset_unchecked(&self) -> Result<(), VulkanError> {
|
||||||
let mut state = self.state.lock();
|
|
||||||
|
|
||||||
self.reset_unchecked_locked(&mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn reset_unchecked_locked(&self, state: &mut FenceState) -> Result<(), VulkanError> {
|
|
||||||
let fns = self.device.fns();
|
let fns = self.device.fns();
|
||||||
(fns.v1_0.reset_fences)(self.device.handle(), 1, &self.handle)
|
(fns.v1_0.reset_fences)(self.device.handle(), 1, &self.handle)
|
||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.reset();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets multiple fences at once.
|
/// Resets multiple fences at once.
|
||||||
///
|
///
|
||||||
/// The fences must not be in use by a queue operation.
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// - The elements of `fences` must not be in use by the device.
|
||||||
///
|
pub unsafe fn multi_reset<'a>(
|
||||||
/// - Panics if not all fences belong to the same device.
|
|
||||||
pub fn multi_reset<'a>(
|
|
||||||
fences: impl IntoIterator<Item = &'a Fence>,
|
fences: impl IntoIterator<Item = &'a Fence>,
|
||||||
) -> Result<(), Validated<VulkanError>> {
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
|
let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
|
||||||
.into_iter()
|
Self::validate_multi_reset(&fences)?;
|
||||||
.map(|fence| {
|
|
||||||
let state = fence.state.lock();
|
|
||||||
(fence, state)
|
|
||||||
})
|
|
||||||
.unzip();
|
|
||||||
Self::validate_multi_reset(&fences, &states)?;
|
|
||||||
|
|
||||||
unsafe { Ok(Self::multi_reset_unchecked_locked(&fences, &mut states)?) }
|
unsafe { Ok(Self::multi_reset_unchecked(fences)?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_multi_reset(
|
fn validate_multi_reset(fences: &[&Fence]) -> Result<(), Box<ValidationError>> {
|
||||||
fences: &[&Fence],
|
|
||||||
states: &[MutexGuard<'_, FenceState>],
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
|
||||||
if fences.is_empty() {
|
if fences.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let device = &fences[0].device;
|
let device = &fences[0].device;
|
||||||
|
|
||||||
for (fence_index, (fence, state)) in fences.iter().zip(states).enumerate() {
|
for fence in fences {
|
||||||
// VUID-vkResetFences-pFences-parent
|
// VUID-vkResetFences-pFences-parent
|
||||||
assert_eq!(device, &fence.device);
|
assert_eq!(device, &fence.device);
|
||||||
|
|
||||||
if state.is_in_queue() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
context: format!("fences[{}]", fence_index).into(),
|
|
||||||
problem: "the fence is in use".into(),
|
|
||||||
vuids: &["VUID-vkResetFences-pFences-01123"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -514,21 +410,8 @@ impl Fence {
|
|||||||
pub unsafe fn multi_reset_unchecked<'a>(
|
pub unsafe fn multi_reset_unchecked<'a>(
|
||||||
fences: impl IntoIterator<Item = &'a Fence>,
|
fences: impl IntoIterator<Item = &'a Fence>,
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
|
let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
|
||||||
.into_iter()
|
|
||||||
.map(|fence| {
|
|
||||||
let state = fence.state.lock();
|
|
||||||
(fence, state)
|
|
||||||
})
|
|
||||||
.unzip();
|
|
||||||
|
|
||||||
Self::multi_reset_unchecked_locked(&fences, &mut states)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn multi_reset_unchecked_locked(
|
|
||||||
fences: &[&Fence],
|
|
||||||
states: &mut [MutexGuard<'_, FenceState>],
|
|
||||||
) -> Result<(), VulkanError> {
|
|
||||||
if fences.is_empty() {
|
if fences.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -541,10 +424,6 @@ impl Fence {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
for state in states {
|
|
||||||
state.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,21 +431,27 @@ impl Fence {
|
|||||||
///
|
///
|
||||||
/// The [`khr_external_fence_fd`](crate::device::DeviceExtensions::khr_external_fence_fd)
|
/// The [`khr_external_fence_fd`](crate::device::DeviceExtensions::khr_external_fence_fd)
|
||||||
/// extension must be enabled on the device.
|
/// extension must be enabled on the device.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - If `handle_type` has copy transference, then the fence must be signaled, or a signal
|
||||||
|
/// operation on the fence must be pending.
|
||||||
|
/// - The fence must not currently have an imported payload from a swapchain acquire operation.
|
||||||
|
/// - If the fence has an imported payload, its handle type must allow re-exporting as
|
||||||
|
/// `handle_type`, as returned by [`PhysicalDevice::external_fence_properties`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn export_fd(
|
pub unsafe fn export_fd(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalFenceHandleType,
|
handle_type: ExternalFenceHandleType,
|
||||||
) -> Result<File, Validated<VulkanError>> {
|
) -> Result<File, Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_export_fd(handle_type)?;
|
||||||
self.validate_export_fd(handle_type, &state)?;
|
|
||||||
|
|
||||||
unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
|
unsafe { Ok(self.export_fd_unchecked(handle_type)?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_export_fd(
|
fn validate_export_fd(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalFenceHandleType,
|
handle_type: ExternalFenceHandleType,
|
||||||
state: &FenceState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().khr_external_fence_fd {
|
if !self.device.enabled_extensions().khr_external_fence_fd {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -604,73 +489,13 @@ impl Fence {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle_type.has_copy_transference()
|
|
||||||
&& !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
the fence is not signaled, and \
|
|
||||||
a signal operation on the fence is not pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-01454"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(imported_handle_type) = state.current_import {
|
|
||||||
match imported_handle_type {
|
|
||||||
ImportType::SwapchainAcquire => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the fence currently has an imported payload from a \
|
|
||||||
swapchain acquire operation"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkFenceGetFdInfoKHR-fence-01455"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
ImportType::ExternalFence(imported_handle_type) => {
|
|
||||||
let external_fence_properties = unsafe {
|
|
||||||
self.device
|
|
||||||
.physical_device()
|
|
||||||
.external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
|
|
||||||
handle_type,
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
if !external_fence_properties
|
|
||||||
.export_from_imported_handle_types
|
|
||||||
.intersects(imported_handle_type.into())
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the fence currently has an imported payload, whose type \
|
|
||||||
does not allow re-exporting as `handle_type`, as \
|
|
||||||
returned by `PhysicalDevice::external_fence_properties`"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkFenceGetFdInfoKHR-fence-01455"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn export_fd_unchecked(
|
pub unsafe fn export_fd_unchecked(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalFenceHandleType,
|
handle_type: ExternalFenceHandleType,
|
||||||
) -> Result<File, VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.export_fd_unchecked_locked(handle_type, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn export_fd_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
handle_type: ExternalFenceHandleType,
|
|
||||||
state: &mut FenceState,
|
|
||||||
) -> Result<File, VulkanError> {
|
) -> Result<File, VulkanError> {
|
||||||
let info_vk = ash::vk::FenceGetFdInfoKHR {
|
let info_vk = ash::vk::FenceGetFdInfoKHR {
|
||||||
fence: self.handle,
|
fence: self.handle,
|
||||||
@ -688,8 +513,6 @@ impl Fence {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.export(handle_type);
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::os::unix::io::FromRawFd;
|
use std::os::unix::io::FromRawFd;
|
||||||
@ -707,21 +530,29 @@ impl Fence {
|
|||||||
///
|
///
|
||||||
/// The [`khr_external_fence_win32`](crate::device::DeviceExtensions::khr_external_fence_win32)
|
/// The [`khr_external_fence_win32`](crate::device::DeviceExtensions::khr_external_fence_win32)
|
||||||
/// extension must be enabled on the device.
|
/// extension must be enabled on the device.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - If `handle_type` has copy transference, then the fence must be signaled, or a signal
|
||||||
|
/// operation on the fence must be pending.
|
||||||
|
/// - The fence must not currently have an imported payload from a swapchain acquire operation.
|
||||||
|
/// - If the fence has an imported payload, its handle type must allow re-exporting as
|
||||||
|
/// `handle_type`, as returned by [`PhysicalDevice::external_fence_properties`].
|
||||||
|
/// - If `handle_type` is `ExternalFenceHandleType::OpaqueWin32`, then a handle of this type
|
||||||
|
/// must not have been already exported from this fence.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn export_win32_handle(
|
pub fn export_win32_handle(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalFenceHandleType,
|
handle_type: ExternalFenceHandleType,
|
||||||
) -> Result<*mut std::ffi::c_void, Validated<VulkanError>> {
|
) -> Result<*mut std::ffi::c_void, Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_export_win32_handle(handle_type)?;
|
||||||
self.validate_export_win32_handle(handle_type, &state)?;
|
|
||||||
|
|
||||||
unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
|
unsafe { Ok(self.export_win32_handle_unchecked(handle_type)?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_export_win32_handle(
|
fn validate_export_win32_handle(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalFenceHandleType,
|
handle_type: ExternalFenceHandleType,
|
||||||
state: &FenceState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().khr_external_fence_win32 {
|
if !self.device.enabled_extensions().khr_external_fence_win32 {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -759,85 +590,13 @@ impl Fence {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(handle_type, ExternalFenceHandleType::OpaqueWin32)
|
|
||||||
&& state.is_exported(handle_type)
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` is `ExternalFenceHandleType::OpaqueWin32`, but \
|
|
||||||
a handle of this type has already been exported from this fence"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01449"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if handle_type.has_copy_transference()
|
|
||||||
&& !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
the fence is not signaled, and \
|
|
||||||
a signal operation on the fence is not pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01451"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(imported_handle_type) = state.current_import {
|
|
||||||
match imported_handle_type {
|
|
||||||
ImportType::SwapchainAcquire => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the fence currently has an imported payload from a \
|
|
||||||
swapchain acquire operation"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-fence-01450"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
ImportType::ExternalFence(imported_handle_type) => {
|
|
||||||
let external_fence_properties = unsafe {
|
|
||||||
self.device
|
|
||||||
.physical_device()
|
|
||||||
.external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
|
|
||||||
handle_type,
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
if !external_fence_properties
|
|
||||||
.export_from_imported_handle_types
|
|
||||||
.intersects(imported_handle_type.into())
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the fence currently has an imported payload, whose type \
|
|
||||||
does not allow re-exporting as `handle_type`, as \
|
|
||||||
returned by `PhysicalDevice::external_fence_properties`"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-fence-01450"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn export_win32_handle_unchecked(
|
pub unsafe fn export_win32_handle_unchecked(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalFenceHandleType,
|
handle_type: ExternalFenceHandleType,
|
||||||
) -> Result<*mut std::ffi::c_void, VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.export_win32_handle_unchecked_locked(handle_type, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn export_win32_handle_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
handle_type: ExternalFenceHandleType,
|
|
||||||
state: &mut FenceState,
|
|
||||||
) -> Result<*mut std::ffi::c_void, VulkanError> {
|
) -> Result<*mut std::ffi::c_void, VulkanError> {
|
||||||
let info_vk = ash::vk::FenceGetWin32HandleInfoKHR {
|
let info_vk = ash::vk::FenceGetWin32HandleInfoKHR {
|
||||||
fence: self.handle,
|
fence: self.handle,
|
||||||
@ -855,8 +614,6 @@ impl Fence {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.export(handle_type);
|
|
||||||
|
|
||||||
Ok(output.assume_init())
|
Ok(output.assume_init())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -867,6 +624,7 @@ impl Fence {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
/// - The fence must not be in use by the device.
|
||||||
/// - If in `import_fence_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
|
/// - If in `import_fence_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
|
||||||
/// then `file` must represent a fence that was exported from Vulkan or a compatible API,
|
/// then `file` must represent a fence that was exported from Vulkan or a compatible API,
|
||||||
/// with a driver and device UUID equal to those of the device that owns `self`.
|
/// with a driver and device UUID equal to those of the device that owns `self`.
|
||||||
@ -875,16 +633,14 @@ impl Fence {
|
|||||||
&self,
|
&self,
|
||||||
import_fence_fd_info: ImportFenceFdInfo,
|
import_fence_fd_info: ImportFenceFdInfo,
|
||||||
) -> Result<(), Validated<VulkanError>> {
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_import_fd(&import_fence_fd_info)?;
|
||||||
self.validate_import_fd(&import_fence_fd_info, &state)?;
|
|
||||||
|
|
||||||
Ok(self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)?)
|
Ok(self.import_fd_unchecked(import_fence_fd_info)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_import_fd(
|
fn validate_import_fd(
|
||||||
&self,
|
&self,
|
||||||
import_fence_fd_info: &ImportFenceFdInfo,
|
import_fence_fd_info: &ImportFenceFdInfo,
|
||||||
state: &FenceState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().khr_external_fence_fd {
|
if !self.device.enabled_extensions().khr_external_fence_fd {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -895,14 +651,6 @@ impl Fence {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.is_in_queue() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the fence is in use".into(),
|
|
||||||
vuids: &["VUID-vkImportFenceFdKHR-fence-01463"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
import_fence_fd_info
|
import_fence_fd_info
|
||||||
.validate(&self.device)
|
.validate(&self.device)
|
||||||
.map_err(|err| err.add_context("import_fence_fd_info"))?;
|
.map_err(|err| err.add_context("import_fence_fd_info"))?;
|
||||||
@ -911,19 +659,9 @@ impl Fence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn import_fd_unchecked(
|
pub unsafe fn import_fd_unchecked(
|
||||||
&self,
|
&self,
|
||||||
import_fence_fd_info: ImportFenceFdInfo,
|
import_fence_fd_info: ImportFenceFdInfo,
|
||||||
) -> Result<(), VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn import_fd_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
import_fence_fd_info: ImportFenceFdInfo,
|
|
||||||
state: &mut FenceState,
|
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let ImportFenceFdInfo {
|
let ImportFenceFdInfo {
|
||||||
flags,
|
flags,
|
||||||
@ -957,8 +695,6 @@ impl Fence {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -969,6 +705,7 @@ impl Fence {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
/// - The fence must not be in use by the device.
|
||||||
/// - In `import_fence_win32_handle_info`, `handle` must represent a fence that was exported
|
/// - In `import_fence_win32_handle_info`, `handle` must represent a fence that was exported
|
||||||
/// from Vulkan or a compatible API, with a driver and device UUID equal to those of the
|
/// from Vulkan or a compatible API, with a driver and device UUID equal to those of the
|
||||||
/// device that owns `self`.
|
/// device that owns `self`.
|
||||||
@ -977,16 +714,14 @@ impl Fence {
|
|||||||
&self,
|
&self,
|
||||||
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
|
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
|
||||||
) -> Result<(), Validated<VulkanError>> {
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_import_win32_handle(&import_fence_win32_handle_info)?;
|
||||||
self.validate_import_win32_handle(&import_fence_win32_handle_info, &state)?;
|
|
||||||
|
|
||||||
Ok(self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)?)
|
Ok(self.import_win32_handle_unchecked(import_fence_win32_handle_info)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_import_win32_handle(
|
fn validate_import_win32_handle(
|
||||||
&self,
|
&self,
|
||||||
import_fence_win32_handle_info: &ImportFenceWin32HandleInfo,
|
import_fence_win32_handle_info: &ImportFenceWin32HandleInfo,
|
||||||
state: &FenceState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().khr_external_fence_win32 {
|
if !self.device.enabled_extensions().khr_external_fence_win32 {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -997,14 +732,6 @@ impl Fence {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.is_in_queue() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the fence is in use".into(),
|
|
||||||
vuids: &["VUID-vkImportFenceWin32HandleKHR-fence-04448"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
import_fence_win32_handle_info
|
import_fence_win32_handle_info
|
||||||
.validate(&self.device)
|
.validate(&self.device)
|
||||||
.map_err(|err| err.add_context("import_fence_win32_handle_info"))?;
|
.map_err(|err| err.add_context("import_fence_win32_handle_info"))?;
|
||||||
@ -1013,19 +740,9 @@ impl Fence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn import_win32_handle_unchecked(
|
pub unsafe fn import_win32_handle_unchecked(
|
||||||
&self,
|
&self,
|
||||||
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
|
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
|
||||||
) -> Result<(), VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn import_win32_handle_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
|
|
||||||
state: &mut FenceState,
|
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let ImportFenceWin32HandleInfo {
|
let ImportFenceWin32HandleInfo {
|
||||||
flags,
|
flags,
|
||||||
@ -1051,15 +768,9 @@ impl Fence {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn state(&self) -> MutexGuard<'_, FenceState> {
|
|
||||||
self.state.lock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shared by Fence and FenceSignalFuture
|
// Shared by Fence and FenceSignalFuture
|
||||||
pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll<Result<(), VulkanError>> {
|
pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll<Result<(), VulkanError>> {
|
||||||
// Vulkan only allows polling of the fence status, so we have to use a spin future.
|
// Vulkan only allows polling of the fence status, so we have to use a spin future.
|
||||||
@ -1527,124 +1238,6 @@ pub struct ExternalFenceProperties {
|
|||||||
pub compatible_handle_types: ExternalFenceHandleTypes,
|
pub compatible_handle_types: ExternalFenceHandleTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub(crate) struct FenceState {
|
|
||||||
is_signaled: bool,
|
|
||||||
pending_signal: Option<Weak<Queue>>,
|
|
||||||
|
|
||||||
reference_exported: bool,
|
|
||||||
exported_handle_types: ExternalFenceHandleTypes,
|
|
||||||
current_import: Option<ImportType>,
|
|
||||||
permanent_import: Option<ExternalFenceHandleType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FenceState {
|
|
||||||
/// If the fence is not in a queue and has no external references, returns the current status.
|
|
||||||
#[inline]
|
|
||||||
fn is_signaled(&self) -> Option<bool> {
|
|
||||||
// If either of these is true, we can't be certain of the status.
|
|
||||||
if self.is_in_queue() || self.has_external_reference() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(self.is_signaled)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_in_queue(&self) -> bool {
|
|
||||||
self.pending_signal.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether there are any potential external references to the fence payload.
|
|
||||||
/// That is, the fence has been exported by reference transference, or imported.
|
|
||||||
#[inline]
|
|
||||||
fn has_external_reference(&self) -> bool {
|
|
||||||
self.reference_exported || self.current_import.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
fn is_exported(&self, handle_type: ExternalFenceHandleType) -> bool {
|
|
||||||
self.exported_handle_types.intersects(handle_type.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc<Queue>) {
|
|
||||||
self.pending_signal = Some(Arc::downgrade(queue));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when a fence first discovers that it is signaled.
|
|
||||||
/// Returns the queue that should be informed about it.
|
|
||||||
#[inline]
|
|
||||||
unsafe fn set_signaled(&mut self) -> Option<Arc<Queue>> {
|
|
||||||
self.is_signaled = true;
|
|
||||||
|
|
||||||
// Fences with external references can't be used to determine queue completion.
|
|
||||||
if self.has_external_reference() {
|
|
||||||
self.pending_signal = None;
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.pending_signal.take().and_then(|queue| queue.upgrade())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when a queue is unlocking resources.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn set_signal_finished(&mut self) {
|
|
||||||
self.is_signaled = true;
|
|
||||||
self.pending_signal = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn reset(&mut self) {
|
|
||||||
debug_assert!(!self.is_in_queue());
|
|
||||||
self.current_import = self.permanent_import.map(Into::into);
|
|
||||||
self.is_signaled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
unsafe fn export(&mut self, handle_type: ExternalFenceHandleType) {
|
|
||||||
self.exported_handle_types |= handle_type.into();
|
|
||||||
|
|
||||||
if handle_type.has_copy_transference() {
|
|
||||||
self.reset();
|
|
||||||
} else {
|
|
||||||
self.reference_exported = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
unsafe fn import(&mut self, handle_type: ExternalFenceHandleType, temporary: bool) {
|
|
||||||
debug_assert!(!self.is_in_queue());
|
|
||||||
self.current_import = Some(handle_type.into());
|
|
||||||
|
|
||||||
if !temporary {
|
|
||||||
self.permanent_import = Some(handle_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn import_swapchain_acquire(&mut self) {
|
|
||||||
debug_assert!(!self.is_in_queue());
|
|
||||||
self.current_import = Some(ImportType::SwapchainAcquire);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
enum ImportType {
|
|
||||||
SwapchainAcquire,
|
|
||||||
ExternalFence(ExternalFenceHandleType),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ExternalFenceHandleType> for ImportType {
|
|
||||||
#[inline]
|
|
||||||
fn from(handle_type: ExternalFenceHandleType) -> Self {
|
|
||||||
Self::ExternalFence(handle_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -1703,7 +1296,11 @@ mod tests {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
fence.reset().unwrap();
|
|
||||||
|
unsafe {
|
||||||
|
fence.reset().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
assert!(!fence.is_signaled().unwrap());
|
assert!(!fence.is_signaled().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1760,7 +1357,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let _ = Fence::multi_reset([&fence1, &fence2]);
|
let _ = unsafe { Fence::multi_reset([&fence1, &fence2]) };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||||||
swapchain::Swapchain,
|
swapchain::Swapchain,
|
||||||
sync::{
|
sync::{
|
||||||
fence::Fence,
|
fence::Fence,
|
||||||
future::{AccessError, SubmitAnyBuilder},
|
future::{queue_bind_sparse, queue_present, queue_submit, AccessError, SubmitAnyBuilder},
|
||||||
PipelineStages,
|
PipelineStages,
|
||||||
},
|
},
|
||||||
DeviceSize, Validated, ValidationError, VulkanError,
|
DeviceSize, Validated, ValidationError, VulkanError,
|
||||||
@ -243,35 +243,36 @@ where
|
|||||||
SubmitAnyBuilder::Empty => {
|
SubmitAnyBuilder::Empty => {
|
||||||
debug_assert!(!partially_flushed);
|
debug_assert!(!partially_flushed);
|
||||||
|
|
||||||
queue
|
queue_submit(
|
||||||
.with(|mut q| {
|
&queue,
|
||||||
q.submit_unchecked([Default::default()], Some(new_fence.clone()))
|
Default::default(),
|
||||||
})
|
Some(new_fence.clone()),
|
||||||
.map_err(|err| OutcomeErr::Full(err.into()))
|
&previous,
|
||||||
|
)
|
||||||
|
.map_err(OutcomeErr::Full)
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
|
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
|
||||||
debug_assert!(!partially_flushed);
|
debug_assert!(!partially_flushed);
|
||||||
|
|
||||||
queue
|
queue_submit(
|
||||||
.with(|mut q| {
|
&queue,
|
||||||
q.submit_unchecked(
|
SubmitInfo {
|
||||||
[SubmitInfo {
|
wait_semaphores: semaphores
|
||||||
wait_semaphores: semaphores
|
.into_iter()
|
||||||
.into_iter()
|
.map(|semaphore| {
|
||||||
.map(|semaphore| {
|
SemaphoreSubmitInfo {
|
||||||
SemaphoreSubmitInfo {
|
// TODO: correct stages ; hard
|
||||||
// TODO: correct stages ; hard
|
stages: PipelineStages::ALL_COMMANDS,
|
||||||
stages: PipelineStages::ALL_COMMANDS,
|
..SemaphoreSubmitInfo::new(semaphore)
|
||||||
..SemaphoreSubmitInfo::semaphore(semaphore)
|
}
|
||||||
}
|
})
|
||||||
})
|
.collect(),
|
||||||
.collect(),
|
..Default::default()
|
||||||
..Default::default()
|
},
|
||||||
}],
|
None,
|
||||||
None,
|
&previous,
|
||||||
)
|
)
|
||||||
})
|
.map_err(OutcomeErr::Full)
|
||||||
.map_err(|err| OutcomeErr::Full(err.into()))
|
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
|
SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
|
||||||
debug_assert!(!partially_flushed);
|
debug_assert!(!partially_flushed);
|
||||||
@ -282,15 +283,7 @@ where
|
|||||||
// assertion.
|
// assertion.
|
||||||
assert!(fence.is_none());
|
assert!(fence.is_none());
|
||||||
|
|
||||||
queue
|
queue_submit(&queue, submit_info, Some(new_fence.clone()), &previous)
|
||||||
.with(|mut q| {
|
|
||||||
q.submit_with_future(
|
|
||||||
submit_info,
|
|
||||||
Some(new_fence.clone()),
|
|
||||||
&previous,
|
|
||||||
&queue,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(OutcomeErr::Full)
|
.map_err(OutcomeErr::Full)
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::BindSparse(bind_infos, fence) => {
|
SubmitAnyBuilder::BindSparse(bind_infos, fence) => {
|
||||||
@ -302,19 +295,20 @@ where
|
|||||||
.queue_flags
|
.queue_flags
|
||||||
.intersects(QueueFlags::SPARSE_BINDING));
|
.intersects(QueueFlags::SPARSE_BINDING));
|
||||||
|
|
||||||
queue
|
queue_bind_sparse(&queue, bind_infos, Some(new_fence.clone()))
|
||||||
.with(|mut q| q.bind_sparse_unchecked(bind_infos, Some(new_fence.clone())))
|
.map_err(OutcomeErr::Full)
|
||||||
.map_err(|err| OutcomeErr::Full(err.into()))
|
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::QueuePresent(present_info) => {
|
SubmitAnyBuilder::QueuePresent(present_info) => {
|
||||||
if partially_flushed {
|
if partially_flushed {
|
||||||
queue
|
queue_submit(
|
||||||
.with(|mut q| {
|
&queue,
|
||||||
q.submit_unchecked([Default::default()], Some(new_fence.clone()))
|
Default::default(),
|
||||||
})
|
Some(new_fence.clone()),
|
||||||
.map_err(|err| OutcomeErr::Partial(err.into()))
|
&previous,
|
||||||
|
)
|
||||||
|
.map_err(OutcomeErr::Partial)
|
||||||
} else {
|
} else {
|
||||||
for swapchain_info in &present_info.swapchain_infos {
|
for swapchain_info in &present_info.swapchains {
|
||||||
if swapchain_info.present_id.map_or(false, |present_id| {
|
if swapchain_info.present_id.map_or(false, |present_id| {
|
||||||
!swapchain_info.swapchain.try_claim_present_id(present_id)
|
!swapchain_info.swapchain.try_claim_present_id(present_id)
|
||||||
}) {
|
}) {
|
||||||
@ -346,20 +340,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let intermediary_result = queue
|
let intermediary_result = queue_present(&queue, present_info)?
|
||||||
.with(|mut q| q.present_unchecked(present_info))?
|
|
||||||
.map(|r| r.map(|_| ()))
|
.map(|r| r.map(|_| ()))
|
||||||
.fold(Ok(()), Result::and);
|
.fold(Ok(()), Result::and);
|
||||||
|
|
||||||
match intermediary_result {
|
match intermediary_result {
|
||||||
Ok(()) => queue
|
Ok(()) => queue_submit(
|
||||||
.with(|mut q| {
|
&queue,
|
||||||
q.submit_unchecked(
|
Default::default(),
|
||||||
[Default::default()],
|
Some(new_fence.clone()),
|
||||||
Some(new_fence.clone()),
|
&previous,
|
||||||
)
|
)
|
||||||
})
|
.map_err(OutcomeErr::Partial),
|
||||||
.map_err(|err| OutcomeErr::Partial(err.into())),
|
|
||||||
Err(err) => Err(OutcomeErr::Full(err.into())),
|
Err(err) => Err(OutcomeErr::Full(err.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,22 +98,26 @@ pub use self::{
|
|||||||
};
|
};
|
||||||
use super::{fence::Fence, semaphore::Semaphore};
|
use super::{fence::Fence, semaphore::Semaphore};
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::Buffer,
|
buffer::{Buffer, BufferState},
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract, SubmitInfo,
|
CommandBufferExecError, CommandBufferExecFuture, CommandBufferResourcesUsage,
|
||||||
|
CommandBufferState, CommandBufferSubmitInfo, CommandBufferUsage,
|
||||||
|
PrimaryCommandBufferAbstract, SubmitInfo,
|
||||||
},
|
},
|
||||||
device::{DeviceOwned, Queue},
|
device::{DeviceOwned, Queue},
|
||||||
image::{Image, ImageLayout},
|
image::{Image, ImageLayout, ImageState},
|
||||||
memory::BindSparseInfo,
|
memory::BindSparseInfo,
|
||||||
swapchain::{self, PresentFuture, PresentInfo, Swapchain, SwapchainPresentInfo},
|
swapchain::{self, PresentFuture, PresentInfo, Swapchain, SwapchainPresentInfo},
|
||||||
DeviceSize, Validated, VulkanError,
|
DeviceSize, Validated, ValidationError, VulkanError, VulkanObject,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use ahash::HashMap;
|
||||||
|
use parking_lot::MutexGuard;
|
||||||
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt::{Display, Error as FmtError, Formatter},
|
fmt::{Display, Error as FmtError, Formatter},
|
||||||
ops::Range,
|
ops::Range,
|
||||||
sync::Arc,
|
sync::{atomic::Ordering, Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod fence_signal;
|
mod fence_signal;
|
||||||
@ -554,3 +558,321 @@ impl From<AccessError> for AccessCheckError {
|
|||||||
AccessCheckError::Denied(err)
|
AccessCheckError::Denied(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn queue_bind_sparse(
|
||||||
|
queue: &Arc<Queue>,
|
||||||
|
bind_infos: impl IntoIterator<Item = BindSparseInfo>,
|
||||||
|
fence: Option<Arc<Fence>>,
|
||||||
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
|
let bind_infos: SmallVec<[_; 4]> = bind_infos.into_iter().collect();
|
||||||
|
queue.with(|mut queue_guard| queue_guard.bind_sparse_unchecked(&bind_infos, fence.as_ref()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn queue_present(
|
||||||
|
queue: &Arc<Queue>,
|
||||||
|
present_info: PresentInfo,
|
||||||
|
) -> Result<impl ExactSizeIterator<Item = Result<bool, VulkanError>>, Validated<VulkanError>> {
|
||||||
|
let results: SmallVec<[_; 1]> = queue
|
||||||
|
.with(|mut queue_guard| queue_guard.present(&present_info))?
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let PresentInfo {
|
||||||
|
wait_semaphores: _,
|
||||||
|
swapchains,
|
||||||
|
_ne: _,
|
||||||
|
} = &present_info;
|
||||||
|
|
||||||
|
// If a presentation results in a loss of full-screen exclusive mode,
|
||||||
|
// signal that to the relevant swapchain.
|
||||||
|
for (&result, swapchain_info) in results.iter().zip(swapchains) {
|
||||||
|
if result == Err(VulkanError::FullScreenExclusiveModeLost) {
|
||||||
|
swapchain_info
|
||||||
|
.swapchain
|
||||||
|
.full_screen_exclusive_held()
|
||||||
|
.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(results.into_iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn queue_submit(
|
||||||
|
queue: &Arc<Queue>,
|
||||||
|
submit_info: SubmitInfo,
|
||||||
|
fence: Option<Arc<Fence>>,
|
||||||
|
future: &dyn GpuFuture,
|
||||||
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
|
let submit_infos: SmallVec<[_; 4]> = smallvec![submit_info];
|
||||||
|
let mut states = States::from_submit_infos(&submit_infos);
|
||||||
|
|
||||||
|
for submit_info in &submit_infos {
|
||||||
|
for command_buffer_submit_info in &submit_info.command_buffers {
|
||||||
|
let &CommandBufferSubmitInfo {
|
||||||
|
ref command_buffer,
|
||||||
|
_ne: _,
|
||||||
|
} = command_buffer_submit_info;
|
||||||
|
|
||||||
|
let state = states
|
||||||
|
.command_buffers
|
||||||
|
.get(&command_buffer.handle())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match command_buffer.usage() {
|
||||||
|
CommandBufferUsage::OneTimeSubmit => {
|
||||||
|
if state.has_been_submitted() {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "a command buffer, or one of the secondary \
|
||||||
|
command buffers it executes, was created with the \
|
||||||
|
`CommandBufferUsage::OneTimeSubmit` usage, but \
|
||||||
|
it has already been submitted in the past"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-vkQueueSubmit2-commandBuffer-03874"],
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandBufferUsage::MultipleSubmit => {
|
||||||
|
if state.is_submit_pending() {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: "a command buffer, or one of the secondary \
|
||||||
|
command buffers it executes, was not created with the \
|
||||||
|
`CommandBufferUsage::SimultaneousUse` usage, but \
|
||||||
|
it is already in use by the device"
|
||||||
|
.into(),
|
||||||
|
vuids: &["VUID-vkQueueSubmit2-commandBuffer-03875"],
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandBufferUsage::SimultaneousUse => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let CommandBufferResourcesUsage {
|
||||||
|
buffers,
|
||||||
|
images,
|
||||||
|
buffer_indices: _,
|
||||||
|
image_indices: _,
|
||||||
|
} = command_buffer.resources_usage();
|
||||||
|
|
||||||
|
for usage in buffers {
|
||||||
|
let state = states.buffers.get_mut(&usage.buffer.handle()).unwrap();
|
||||||
|
|
||||||
|
for (range, range_usage) in usage.ranges.iter() {
|
||||||
|
match future.check_buffer_access(
|
||||||
|
&usage.buffer,
|
||||||
|
range.clone(),
|
||||||
|
range_usage.mutable,
|
||||||
|
queue,
|
||||||
|
) {
|
||||||
|
Err(AccessCheckError::Denied(error)) => {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"access to a resource has been denied \
|
||||||
|
(resource use: {:?}, error: {})",
|
||||||
|
range_usage.first_use, error
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
Err(AccessCheckError::Unknown) => {
|
||||||
|
let result = if range_usage.mutable {
|
||||||
|
state.check_gpu_write(range.clone())
|
||||||
|
} else {
|
||||||
|
state.check_gpu_read(range.clone())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(error) = result {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"access to a resource has been denied \
|
||||||
|
(resource use: {:?}, error: {})",
|
||||||
|
range_usage.first_use, error
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for usage in images {
|
||||||
|
let state = states.images.get_mut(&usage.image.handle()).unwrap();
|
||||||
|
|
||||||
|
for (range, range_usage) in usage.ranges.iter() {
|
||||||
|
match future.check_image_access(
|
||||||
|
&usage.image,
|
||||||
|
range.clone(),
|
||||||
|
range_usage.mutable,
|
||||||
|
range_usage.expected_layout,
|
||||||
|
queue,
|
||||||
|
) {
|
||||||
|
Err(AccessCheckError::Denied(error)) => {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"access to a resource has been denied \
|
||||||
|
(resource use: {:?}, error: {})",
|
||||||
|
range_usage.first_use, error
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
Err(AccessCheckError::Unknown) => {
|
||||||
|
let result = if range_usage.mutable {
|
||||||
|
state.check_gpu_write(range.clone(), range_usage.expected_layout)
|
||||||
|
} else {
|
||||||
|
state.check_gpu_read(range.clone(), range_usage.expected_layout)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(error) = result {
|
||||||
|
return Err(Box::new(ValidationError {
|
||||||
|
problem: format!(
|
||||||
|
"access to a resource has been denied \
|
||||||
|
(resource use: {:?}, error: {})",
|
||||||
|
range_usage.first_use, error
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.with(|mut queue_guard| queue_guard.submit(&submit_infos, fence.as_ref()))?;
|
||||||
|
|
||||||
|
for submit_info in &submit_infos {
|
||||||
|
let SubmitInfo {
|
||||||
|
wait_semaphores: _,
|
||||||
|
command_buffers,
|
||||||
|
signal_semaphores: _,
|
||||||
|
_ne: _,
|
||||||
|
} = submit_info;
|
||||||
|
|
||||||
|
for command_buffer_submit_info in command_buffers {
|
||||||
|
let CommandBufferSubmitInfo {
|
||||||
|
command_buffer,
|
||||||
|
_ne: _,
|
||||||
|
} = command_buffer_submit_info;
|
||||||
|
|
||||||
|
let state = states
|
||||||
|
.command_buffers
|
||||||
|
.get_mut(&command_buffer.handle())
|
||||||
|
.unwrap();
|
||||||
|
state.add_queue_submit();
|
||||||
|
|
||||||
|
let CommandBufferResourcesUsage {
|
||||||
|
buffers,
|
||||||
|
images,
|
||||||
|
buffer_indices: _,
|
||||||
|
image_indices: _,
|
||||||
|
} = command_buffer.resources_usage();
|
||||||
|
|
||||||
|
for usage in buffers {
|
||||||
|
let state = states.buffers.get_mut(&usage.buffer.handle()).unwrap();
|
||||||
|
|
||||||
|
for (range, range_usage) in usage.ranges.iter() {
|
||||||
|
if range_usage.mutable {
|
||||||
|
state.gpu_write_lock(range.clone());
|
||||||
|
} else {
|
||||||
|
state.gpu_read_lock(range.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for usage in images {
|
||||||
|
let state = states.images.get_mut(&usage.image.handle()).unwrap();
|
||||||
|
|
||||||
|
for (range, range_usage) in usage.ranges.iter() {
|
||||||
|
if range_usage.mutable {
|
||||||
|
state.gpu_write_lock(range.clone(), range_usage.final_layout);
|
||||||
|
} else {
|
||||||
|
state.gpu_read_lock(range.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// This struct exists to ensure that every object gets locked exactly once.
|
||||||
|
// Otherwise we get deadlocks.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct States<'a> {
|
||||||
|
buffers: HashMap<ash::vk::Buffer, MutexGuard<'a, BufferState>>,
|
||||||
|
command_buffers: HashMap<ash::vk::CommandBuffer, MutexGuard<'a, CommandBufferState>>,
|
||||||
|
images: HashMap<ash::vk::Image, MutexGuard<'a, ImageState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> States<'a> {
|
||||||
|
fn from_submit_infos(submit_infos: &'a [SubmitInfo]) -> Self {
|
||||||
|
let mut buffers = HashMap::default();
|
||||||
|
let mut command_buffers = HashMap::default();
|
||||||
|
let mut images = HashMap::default();
|
||||||
|
|
||||||
|
for submit_info in submit_infos {
|
||||||
|
let SubmitInfo {
|
||||||
|
wait_semaphores: _,
|
||||||
|
command_buffers: info_command_buffers,
|
||||||
|
signal_semaphores: _,
|
||||||
|
_ne: _,
|
||||||
|
} = submit_info;
|
||||||
|
|
||||||
|
for command_buffer_submit_info in info_command_buffers {
|
||||||
|
let &CommandBufferSubmitInfo {
|
||||||
|
ref command_buffer,
|
||||||
|
_ne: _,
|
||||||
|
} = command_buffer_submit_info;
|
||||||
|
|
||||||
|
command_buffers
|
||||||
|
.entry(command_buffer.handle())
|
||||||
|
.or_insert_with(|| command_buffer.state());
|
||||||
|
|
||||||
|
let CommandBufferResourcesUsage {
|
||||||
|
buffers: buffers_usage,
|
||||||
|
images: images_usage,
|
||||||
|
buffer_indices: _,
|
||||||
|
image_indices: _,
|
||||||
|
} = command_buffer.resources_usage();
|
||||||
|
|
||||||
|
for usage in buffers_usage {
|
||||||
|
let buffer = &usage.buffer;
|
||||||
|
buffers
|
||||||
|
.entry(buffer.handle())
|
||||||
|
.or_insert_with(|| buffer.state());
|
||||||
|
}
|
||||||
|
|
||||||
|
for usage in images_usage {
|
||||||
|
let image = &usage.image;
|
||||||
|
images
|
||||||
|
.entry(image.handle())
|
||||||
|
.or_insert_with(|| image.state());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
buffers,
|
||||||
|
command_buffers,
|
||||||
|
images,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,14 +7,18 @@
|
|||||||
// 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 super::{AccessCheckError, GpuFuture, SubmitAnyBuilder};
|
use super::{queue_present, AccessCheckError, GpuFuture, SubmitAnyBuilder};
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
command_buffer::{SemaphoreSubmitInfo, SubmitInfo},
|
command_buffer::{SemaphoreSubmitInfo, SubmitInfo},
|
||||||
device::{Device, DeviceOwned, Queue},
|
device::{Device, DeviceOwned, Queue},
|
||||||
image::{Image, ImageLayout},
|
image::{Image, ImageLayout},
|
||||||
swapchain::Swapchain,
|
swapchain::Swapchain,
|
||||||
sync::{future::AccessError, semaphore::Semaphore, PipelineStages},
|
sync::{
|
||||||
|
future::{queue_submit, AccessError},
|
||||||
|
semaphore::Semaphore,
|
||||||
|
PipelineStages,
|
||||||
|
},
|
||||||
DeviceSize, Validated, ValidationError, VulkanError,
|
DeviceSize, Validated, ValidationError, VulkanError,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@ -89,51 +93,49 @@ where
|
|||||||
|
|
||||||
match self.previous.build_submission()? {
|
match self.previous.build_submission()? {
|
||||||
SubmitAnyBuilder::Empty => {
|
SubmitAnyBuilder::Empty => {
|
||||||
queue.with(|mut q| {
|
queue_submit(
|
||||||
q.submit_unchecked(
|
&queue,
|
||||||
[SubmitInfo {
|
SubmitInfo {
|
||||||
signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
|
signal_semaphores: vec![SemaphoreSubmitInfo::new(
|
||||||
self.semaphore.clone(),
|
self.semaphore.clone(),
|
||||||
)],
|
)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
},
|
||||||
None,
|
None,
|
||||||
)
|
&self.previous,
|
||||||
})?;
|
)?;
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
|
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
|
||||||
queue.with(|mut q| {
|
queue_submit(
|
||||||
q.submit_unchecked(
|
&queue,
|
||||||
[SubmitInfo {
|
SubmitInfo {
|
||||||
wait_semaphores: semaphores
|
wait_semaphores: semaphores
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|semaphore| {
|
.map(|semaphore| {
|
||||||
SemaphoreSubmitInfo {
|
SemaphoreSubmitInfo {
|
||||||
// TODO: correct stages ; hard
|
// TODO: correct stages ; hard
|
||||||
stages: PipelineStages::ALL_COMMANDS,
|
stages: PipelineStages::ALL_COMMANDS,
|
||||||
..SemaphoreSubmitInfo::semaphore(semaphore)
|
..SemaphoreSubmitInfo::new(semaphore)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
|
signal_semaphores: vec![SemaphoreSubmitInfo::new(
|
||||||
self.semaphore.clone(),
|
self.semaphore.clone(),
|
||||||
)],
|
)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
},
|
||||||
None,
|
None,
|
||||||
)
|
&self.previous,
|
||||||
})?;
|
)?;
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
|
SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
|
||||||
debug_assert!(submit_info.signal_semaphores.is_empty());
|
debug_assert!(submit_info.signal_semaphores.is_empty());
|
||||||
|
|
||||||
submit_info
|
submit_info
|
||||||
.signal_semaphores
|
.signal_semaphores
|
||||||
.push(SemaphoreSubmitInfo::semaphore(self.semaphore.clone()));
|
.push(SemaphoreSubmitInfo::new(self.semaphore.clone()));
|
||||||
|
|
||||||
queue.with(|mut q| {
|
queue_submit(&queue, submit_info, fence, &self.previous)?;
|
||||||
q.submit_with_future(submit_info, fence, &self.previous, &queue)
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::BindSparse(_, _) => {
|
SubmitAnyBuilder::BindSparse(_, _) => {
|
||||||
unimplemented!() // TODO: how to do that?
|
unimplemented!() // TODO: how to do that?
|
||||||
@ -142,7 +144,7 @@ where
|
|||||||
builder.submit(&queue)?;*/
|
builder.submit(&queue)?;*/
|
||||||
}
|
}
|
||||||
SubmitAnyBuilder::QueuePresent(present_info) => {
|
SubmitAnyBuilder::QueuePresent(present_info) => {
|
||||||
for swapchain_info in &present_info.swapchain_infos {
|
for swapchain_info in &present_info.swapchains {
|
||||||
if swapchain_info.present_id.map_or(false, |present_id| {
|
if swapchain_info.present_id.map_or(false, |present_id| {
|
||||||
!swapchain_info.swapchain.try_claim_present_id(present_id)
|
!swapchain_info.swapchain.try_claim_present_id(present_id)
|
||||||
}) {
|
}) {
|
||||||
@ -174,22 +176,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.with(|mut q| {
|
queue_present(&queue, present_info)?
|
||||||
q.present_unchecked(present_info)?
|
.map(|r| r.map(|_| ()))
|
||||||
.map(|r| r.map(|_| ()))
|
.fold(Ok(()), Result::and)?;
|
||||||
.fold(Ok(()), Result::and)?;
|
|
||||||
// FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
|
// FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
|
||||||
q.submit_unchecked(
|
queue_submit(
|
||||||
[SubmitInfo {
|
&queue,
|
||||||
signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
|
SubmitInfo {
|
||||||
self.semaphore.clone(),
|
signal_semaphores: vec![SemaphoreSubmitInfo::new(
|
||||||
)],
|
self.semaphore.clone(),
|
||||||
..Default::default()
|
)],
|
||||||
}],
|
..Default::default()
|
||||||
None,
|
},
|
||||||
)?;
|
None,
|
||||||
Ok::<_, Validated<VulkanError>>(())
|
&self.previous,
|
||||||
})?;
|
)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -267,7 +269,10 @@ where
|
|||||||
self.flush().unwrap();
|
self.flush().unwrap();
|
||||||
// Block until the queue finished.
|
// Block until the queue finished.
|
||||||
self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
|
self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
|
||||||
unsafe { self.previous.signal_finished() };
|
|
||||||
|
unsafe {
|
||||||
|
self.signal_finished();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,42 @@
|
|||||||
|
|
||||||
//! A semaphore provides synchronization between multiple queues, with non-command buffer
|
//! A semaphore provides synchronization between multiple queues, with non-command buffer
|
||||||
//! commands on the same queue, or between the device and an external source.
|
//! 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,
|
||||||
|
//! the host cannot perform any operations on it.
|
||||||
|
//!
|
||||||
|
//! Two operations can be performed on a 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,
|
||||||
|
//! 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.
|
||||||
|
//!
|
||||||
|
//! # Safety
|
||||||
|
//!
|
||||||
|
//! - When a semaphore signal operation is executed on the device,
|
||||||
|
//! 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
|
||||||
|
//! at the same time.
|
||||||
|
//! - When a semaphore wait operation is queued as part of a command,
|
||||||
|
//! 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).
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
device::{physical::PhysicalDevice, Device, DeviceOwned, Queue},
|
device::{physical::PhysicalDevice, Device, DeviceOwned},
|
||||||
instance::InstanceOwnedDebugWrapper,
|
instance::InstanceOwnedDebugWrapper,
|
||||||
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
|
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
|
||||||
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
|
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
|
||||||
VulkanObject,
|
VulkanObject,
|
||||||
};
|
};
|
||||||
use parking_lot::{Mutex, MutexGuard};
|
use std::{fs::File, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
|
||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
mem::MaybeUninit,
|
|
||||||
num::NonZeroU64,
|
|
||||||
ptr,
|
|
||||||
sync::{Arc, Weak},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Used to provide synchronization between command buffers during their execution.
|
/// Used to provide synchronization between command buffers during their execution.
|
||||||
///
|
///
|
||||||
@ -39,7 +59,6 @@ pub struct Semaphore {
|
|||||||
export_handle_types: ExternalSemaphoreHandleTypes,
|
export_handle_types: ExternalSemaphoreHandleTypes,
|
||||||
|
|
||||||
must_put_in_pool: bool,
|
must_put_in_pool: bool,
|
||||||
state: Mutex<SemaphoreState>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Semaphore {
|
impl Semaphore {
|
||||||
@ -128,7 +147,6 @@ impl Semaphore {
|
|||||||
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
|
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
|
||||||
|
|
||||||
must_put_in_pool: true,
|
must_put_in_pool: true,
|
||||||
state: Mutex::new(Default::default()),
|
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// Pool is empty, alloc new semaphore
|
// Pool is empty, alloc new semaphore
|
||||||
@ -167,7 +185,6 @@ impl Semaphore {
|
|||||||
export_handle_types,
|
export_handle_types,
|
||||||
|
|
||||||
must_put_in_pool: false,
|
must_put_in_pool: false,
|
||||||
state: Mutex::new(Default::default()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,21 +195,28 @@ impl Semaphore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Exports the semaphore into a POSIX file descriptor. The caller owns the returned `File`.
|
/// Exports the semaphore into a POSIX file descriptor. The caller owns the returned `File`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - If `handle_type` has copy transference, then the semaphore must be signaled, or a signal
|
||||||
|
/// operation on the semaphore must be pending, and no wait operations must be pending.
|
||||||
|
/// - The semaphore must not currently have an imported payload from a swapchain acquire
|
||||||
|
/// operation.
|
||||||
|
/// - If the semaphore has an imported payload, its handle type must allow re-exporting as
|
||||||
|
/// `handle_type`, as returned by [`PhysicalDevice::external_semaphore_properties`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn export_fd(
|
pub unsafe fn export_fd(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
) -> Result<File, Validated<VulkanError>> {
|
) -> Result<File, Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_export_fd(handle_type)?;
|
||||||
self.validate_export_fd(handle_type, &state)?;
|
|
||||||
|
|
||||||
unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
|
unsafe { Ok(self.export_fd_unchecked(handle_type)?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_export_fd(
|
fn validate_export_fd(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
state: &SemaphoreState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().khr_external_semaphore_fd {
|
if !self.device.enabled_extensions().khr_external_semaphore_fd {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -230,86 +254,13 @@ impl Semaphore {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(imported_handle_type) = state.current_import {
|
|
||||||
match imported_handle_type {
|
|
||||||
ImportType::SwapchainAcquire => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore currently has an imported payload from a \
|
|
||||||
swapchain acquire operation"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
ImportType::ExternalSemaphore(imported_handle_type) => {
|
|
||||||
let external_semaphore_properties = unsafe {
|
|
||||||
self.device
|
|
||||||
.physical_device()
|
|
||||||
.external_semaphore_properties_unchecked(
|
|
||||||
ExternalSemaphoreInfo::handle_type(handle_type),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !external_semaphore_properties
|
|
||||||
.export_from_imported_handle_types
|
|
||||||
.intersects(imported_handle_type.into())
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore currently has an imported payload, whose type \
|
|
||||||
does not allow re-exporting as `handle_type`, as \
|
|
||||||
returned by `PhysicalDevice::external_semaphore_properties`"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if handle_type.has_copy_transference() {
|
|
||||||
if state.is_wait_pending() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
a wait operation on the semaphore is pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-01134"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
the semaphore is not signaled, and \
|
|
||||||
a signal operation on the semaphore is not pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &[
|
|
||||||
"VUID-VkSemaphoreGetFdInfoKHR-handleType-01135",
|
|
||||||
"VUID-VkSemaphoreGetFdInfoKHR-handleType-03254",
|
|
||||||
],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn export_fd_unchecked(
|
pub unsafe fn export_fd_unchecked(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
) -> Result<File, VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.export_fd_unchecked_locked(handle_type, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn export_fd_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
|
||||||
state: &mut SemaphoreState,
|
|
||||||
) -> Result<File, VulkanError> {
|
) -> Result<File, VulkanError> {
|
||||||
let info_vk = ash::vk::SemaphoreGetFdInfoKHR {
|
let info_vk = ash::vk::SemaphoreGetFdInfoKHR {
|
||||||
semaphore: self.handle,
|
semaphore: self.handle,
|
||||||
@ -327,8 +278,6 @@ impl Semaphore {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.export(handle_type);
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::os::unix::io::FromRawFd;
|
use std::os::unix::io::FromRawFd;
|
||||||
@ -346,21 +295,31 @@ impl Semaphore {
|
|||||||
///
|
///
|
||||||
/// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
|
/// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
|
||||||
/// extension must be enabled on the device.
|
/// extension must be enabled on the device.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - If `handle_type` has copy transference, then the semaphore must be signaled, or a signal
|
||||||
|
/// operation on the semaphore must be pending, and no wait operations must be pending.
|
||||||
|
/// - The semaphore must not currently have an imported payload from a swapchain acquire
|
||||||
|
/// operation.
|
||||||
|
/// - If the semaphore has an imported payload, its handle type must allow re-exporting as
|
||||||
|
/// `handle_type`, as returned by [`PhysicalDevice::external_semaphore_properties`].
|
||||||
|
/// - If `handle_type` is `ExternalSemaphoreHandleType::OpaqueWin32` or
|
||||||
|
/// `ExternalSemaphoreHandleType::D3D12Fence`, then a handle of this type must not have been
|
||||||
|
/// already exported from this semaphore.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn export_win32_handle(
|
pub fn export_win32_handle(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
) -> Result<*mut std::ffi::c_void, Validated<VulkanError>> {
|
) -> Result<*mut std::ffi::c_void, Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_export_win32_handle(handle_type)?;
|
||||||
self.validate_export_win32_handle(handle_type, &state)?;
|
|
||||||
|
|
||||||
unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
|
unsafe { Ok(self.export_win32_handle_unchecked(handle_type)?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_export_win32_handle(
|
fn validate_export_win32_handle(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
state: &SemaphoreState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self
|
if !self
|
||||||
.device
|
.device
|
||||||
@ -405,98 +364,13 @@ impl Semaphore {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(
|
|
||||||
handle_type,
|
|
||||||
ExternalSemaphoreHandleType::OpaqueWin32 | ExternalSemaphoreHandleType::D3D12Fence
|
|
||||||
) && state.is_exported(handle_type)
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` is `ExternalSemaphoreHandleType::OpaqueWin32` or \
|
|
||||||
`ExternalSemaphoreHandleType::D3D12Fence`, but \
|
|
||||||
a handle of this type has already been exported from this semaphore"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01127"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(imported_handle_type) = state.current_import {
|
|
||||||
match imported_handle_type {
|
|
||||||
ImportType::SwapchainAcquire => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore currently has an imported payload from a \
|
|
||||||
swapchain acquire operation"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
ImportType::ExternalSemaphore(imported_handle_type) => {
|
|
||||||
let external_semaphore_properties = unsafe {
|
|
||||||
self.device
|
|
||||||
.physical_device()
|
|
||||||
.external_semaphore_properties_unchecked(
|
|
||||||
ExternalSemaphoreInfo::handle_type(handle_type),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !external_semaphore_properties
|
|
||||||
.export_from_imported_handle_types
|
|
||||||
.intersects(imported_handle_type.into())
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore currently has an imported payload, whose type \
|
|
||||||
does not allow re-exporting as `handle_type`, as \
|
|
||||||
returned by `PhysicalDevice::external_semaphore_properties`"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if handle_type.has_copy_transference() {
|
|
||||||
if state.is_wait_pending() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
a wait operation on the semaphore is pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01129"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
the semaphore is not signaled, and \
|
|
||||||
a signal operation on the semaphore is not pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01130"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn export_win32_handle_unchecked(
|
pub unsafe fn export_win32_handle_unchecked(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
) -> Result<*mut std::ffi::c_void, VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.export_win32_handle_unchecked_locked(handle_type, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn export_win32_handle_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
|
||||||
state: &mut SemaphoreState,
|
|
||||||
) -> Result<*mut std::ffi::c_void, VulkanError> {
|
) -> Result<*mut std::ffi::c_void, VulkanError> {
|
||||||
let info_vk = ash::vk::SemaphoreGetWin32HandleInfoKHR {
|
let info_vk = ash::vk::SemaphoreGetWin32HandleInfoKHR {
|
||||||
semaphore: self.handle,
|
semaphore: self.handle,
|
||||||
@ -513,27 +387,32 @@ impl Semaphore {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.export(handle_type);
|
|
||||||
|
|
||||||
Ok(output.assume_init())
|
Ok(output.assume_init())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exports the semaphore into a Zircon event handle.
|
/// Exports the semaphore into a Zircon event handle.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - If `handle_type` has copy transference, then the semaphore must be signaled, or a signal
|
||||||
|
/// operation on the semaphore must be pending, and no wait operations must be pending.
|
||||||
|
/// - The semaphore must not currently have an imported payload from a swapchain acquire
|
||||||
|
/// operation.
|
||||||
|
/// - If the semaphore has an imported payload, its handle type must allow re-exporting as
|
||||||
|
/// `handle_type`, as returned by [`PhysicalDevice::external_semaphore_properties`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn export_zircon_handle(
|
pub unsafe fn export_zircon_handle(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
) -> Result<ash::vk::zx_handle_t, Validated<VulkanError>> {
|
) -> Result<ash::vk::zx_handle_t, Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_export_zircon_handle(handle_type)?;
|
||||||
self.validate_export_zircon_handle(handle_type, &state)?;
|
|
||||||
|
|
||||||
unsafe { Ok(self.export_zircon_handle_unchecked_locked(handle_type, &mut state)?) }
|
unsafe { Ok(self.export_zircon_handle_unchecked(handle_type)?) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_export_zircon_handle(
|
fn validate_export_zircon_handle(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
state: &SemaphoreState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().fuchsia_external_semaphore {
|
if !self.device.enabled_extensions().fuchsia_external_semaphore {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -566,83 +445,13 @@ impl Semaphore {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(imported_handle_type) = state.current_import {
|
|
||||||
match imported_handle_type {
|
|
||||||
ImportType::SwapchainAcquire => {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore currently has an imported payload from a \
|
|
||||||
swapchain acquire operation"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
ImportType::ExternalSemaphore(imported_handle_type) => {
|
|
||||||
let external_semaphore_properties = unsafe {
|
|
||||||
self.device
|
|
||||||
.physical_device()
|
|
||||||
.external_semaphore_properties_unchecked(
|
|
||||||
ExternalSemaphoreInfo::handle_type(handle_type),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !external_semaphore_properties
|
|
||||||
.export_from_imported_handle_types
|
|
||||||
.intersects(imported_handle_type.into())
|
|
||||||
{
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore currently has an imported payload, whose type \
|
|
||||||
does not allow re-exporting as `handle_type`, as \
|
|
||||||
returned by `PhysicalDevice::external_semaphore_properties`"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if handle_type.has_copy_transference() {
|
|
||||||
if state.is_wait_pending() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
a wait operation on the semaphore is pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04760"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "`handle_type` has copy transference, but \
|
|
||||||
the semaphore is not signaled, and \
|
|
||||||
a signal operation on the semaphore is not pending"
|
|
||||||
.into(),
|
|
||||||
vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04761"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn export_zircon_handle_unchecked(
|
pub unsafe fn export_zircon_handle_unchecked(
|
||||||
&self,
|
&self,
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
handle_type: ExternalSemaphoreHandleType,
|
||||||
) -> Result<ash::vk::zx_handle_t, VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.export_zircon_handle_unchecked_locked(handle_type, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn export_zircon_handle_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
handle_type: ExternalSemaphoreHandleType,
|
|
||||||
state: &mut SemaphoreState,
|
|
||||||
) -> Result<ash::vk::zx_handle_t, VulkanError> {
|
) -> Result<ash::vk::zx_handle_t, VulkanError> {
|
||||||
let info_vk = ash::vk::SemaphoreGetZirconHandleInfoFUCHSIA {
|
let info_vk = ash::vk::SemaphoreGetZirconHandleInfoFUCHSIA {
|
||||||
semaphore: self.handle,
|
semaphore: self.handle,
|
||||||
@ -661,8 +470,6 @@ impl Semaphore {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.export(handle_type);
|
|
||||||
|
|
||||||
Ok(output.assume_init())
|
Ok(output.assume_init())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,6 +480,7 @@ impl Semaphore {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
/// - The semaphore must not be in use by the device.
|
||||||
/// - If in `import_semaphore_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
|
/// - If in `import_semaphore_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
|
||||||
/// then `file` must represent a binary semaphore that was exported from Vulkan or a
|
/// then `file` must represent a binary semaphore that was exported from Vulkan or a
|
||||||
/// compatible API, with a driver and device UUID equal to those of the device that owns
|
/// compatible API, with a driver and device UUID equal to those of the device that owns
|
||||||
@ -682,16 +490,14 @@ impl Semaphore {
|
|||||||
&self,
|
&self,
|
||||||
import_semaphore_fd_info: ImportSemaphoreFdInfo,
|
import_semaphore_fd_info: ImportSemaphoreFdInfo,
|
||||||
) -> Result<(), Validated<VulkanError>> {
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_import_fd(&import_semaphore_fd_info)?;
|
||||||
self.validate_import_fd(&import_semaphore_fd_info, &state)?;
|
|
||||||
|
|
||||||
Ok(self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)?)
|
Ok(self.import_fd_unchecked(import_semaphore_fd_info)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_import_fd(
|
fn validate_import_fd(
|
||||||
&self,
|
&self,
|
||||||
import_semaphore_fd_info: &ImportSemaphoreFdInfo,
|
import_semaphore_fd_info: &ImportSemaphoreFdInfo,
|
||||||
state: &SemaphoreState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().khr_external_semaphore_fd {
|
if !self.device.enabled_extensions().khr_external_semaphore_fd {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -702,14 +508,6 @@ impl Semaphore {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.is_in_queue() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore is in use".into(),
|
|
||||||
vuids: &["VUID-vkImportSemaphoreFdKHR-semaphore-01142"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
import_semaphore_fd_info
|
import_semaphore_fd_info
|
||||||
.validate(&self.device)
|
.validate(&self.device)
|
||||||
.map_err(|err| err.add_context("import_semaphore_fd_info"))?;
|
.map_err(|err| err.add_context("import_semaphore_fd_info"))?;
|
||||||
@ -718,19 +516,9 @@ impl Semaphore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn import_fd_unchecked(
|
pub unsafe fn import_fd_unchecked(
|
||||||
&self,
|
&self,
|
||||||
import_semaphore_fd_info: ImportSemaphoreFdInfo,
|
import_semaphore_fd_info: ImportSemaphoreFdInfo,
|
||||||
) -> Result<(), VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn import_fd_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
import_semaphore_fd_info: ImportSemaphoreFdInfo,
|
|
||||||
state: &mut SemaphoreState,
|
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let ImportSemaphoreFdInfo {
|
let ImportSemaphoreFdInfo {
|
||||||
flags,
|
flags,
|
||||||
@ -764,11 +552,6 @@ impl Semaphore {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.import(
|
|
||||||
handle_type,
|
|
||||||
flags.intersects(SemaphoreImportFlags::TEMPORARY),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -779,6 +562,7 @@ impl Semaphore {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
/// - The semaphore must not be in use by the device.
|
||||||
/// - In `import_semaphore_win32_handle_info`, `handle` must represent a binary semaphore that
|
/// - In `import_semaphore_win32_handle_info`, `handle` must represent a binary semaphore that
|
||||||
/// was exported from Vulkan or a compatible API, with a driver and device UUID equal to
|
/// was exported from Vulkan or a compatible API, with a driver and device UUID equal to
|
||||||
/// those of the device that owns `self`.
|
/// those of the device that owns `self`.
|
||||||
@ -787,17 +571,14 @@ impl Semaphore {
|
|||||||
&self,
|
&self,
|
||||||
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
|
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
|
||||||
) -> Result<(), Validated<VulkanError>> {
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_import_win32_handle(&import_semaphore_win32_handle_info)?;
|
||||||
self.validate_import_win32_handle(&import_semaphore_win32_handle_info, &state)?;
|
|
||||||
|
|
||||||
Ok(self
|
Ok(self.import_win32_handle_unchecked(import_semaphore_win32_handle_info)?)
|
||||||
.import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_import_win32_handle(
|
fn validate_import_win32_handle(
|
||||||
&self,
|
&self,
|
||||||
import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo,
|
import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo,
|
||||||
state: &SemaphoreState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self
|
if !self
|
||||||
.device
|
.device
|
||||||
@ -812,14 +593,6 @@ impl Semaphore {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.is_in_queue() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore is in use".into(),
|
|
||||||
// vuids?
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
import_semaphore_win32_handle_info
|
import_semaphore_win32_handle_info
|
||||||
.validate(&self.device)
|
.validate(&self.device)
|
||||||
.map_err(|err| err.add_context("import_semaphore_win32_handle_info"))?;
|
.map_err(|err| err.add_context("import_semaphore_win32_handle_info"))?;
|
||||||
@ -828,19 +601,9 @@ impl Semaphore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn import_win32_handle_unchecked(
|
pub unsafe fn import_win32_handle_unchecked(
|
||||||
&self,
|
&self,
|
||||||
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
|
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
|
||||||
) -> Result<(), VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn import_win32_handle_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
|
|
||||||
state: &mut SemaphoreState,
|
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let ImportSemaphoreWin32HandleInfo {
|
let ImportSemaphoreWin32HandleInfo {
|
||||||
flags,
|
flags,
|
||||||
@ -864,11 +627,6 @@ impl Semaphore {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.import(
|
|
||||||
handle_type,
|
|
||||||
flags.intersects(SemaphoreImportFlags::TEMPORARY),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,6 +637,7 @@ impl Semaphore {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
/// - The semaphore must not be in use by the device.
|
||||||
/// - In `import_semaphore_zircon_handle_info`, `zircon_handle` must have `ZX_RIGHTS_BASIC` and
|
/// - In `import_semaphore_zircon_handle_info`, `zircon_handle` must have `ZX_RIGHTS_BASIC` and
|
||||||
/// `ZX_RIGHTS_SIGNAL`.
|
/// `ZX_RIGHTS_SIGNAL`.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -886,19 +645,14 @@ impl Semaphore {
|
|||||||
&self,
|
&self,
|
||||||
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
|
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
|
||||||
) -> Result<(), Validated<VulkanError>> {
|
) -> Result<(), Validated<VulkanError>> {
|
||||||
let mut state = self.state.lock();
|
self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info)?;
|
||||||
self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info, &state)?;
|
|
||||||
|
|
||||||
Ok(self.import_zircon_handle_unchecked_locked(
|
Ok(self.import_zircon_handle_unchecked(import_semaphore_zircon_handle_info)?)
|
||||||
import_semaphore_zircon_handle_info,
|
|
||||||
&mut state,
|
|
||||||
)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_import_zircon_handle(
|
fn validate_import_zircon_handle(
|
||||||
&self,
|
&self,
|
||||||
import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo,
|
import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo,
|
||||||
state: &SemaphoreState,
|
|
||||||
) -> Result<(), Box<ValidationError>> {
|
) -> Result<(), Box<ValidationError>> {
|
||||||
if !self.device.enabled_extensions().fuchsia_external_semaphore {
|
if !self.device.enabled_extensions().fuchsia_external_semaphore {
|
||||||
return Err(Box::new(ValidationError {
|
return Err(Box::new(ValidationError {
|
||||||
@ -909,14 +663,6 @@ impl Semaphore {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.is_in_queue() {
|
|
||||||
return Err(Box::new(ValidationError {
|
|
||||||
problem: "the semaphore is in use".into(),
|
|
||||||
vuids: &["VUID-vkImportSemaphoreZirconHandleFUCHSIA-semaphore-04764"],
|
|
||||||
..Default::default()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
import_semaphore_zircon_handle_info
|
import_semaphore_zircon_handle_info
|
||||||
.validate(&self.device)
|
.validate(&self.device)
|
||||||
.map_err(|err| err.add_context("import_semaphore_zircon_handle_info"))?;
|
.map_err(|err| err.add_context("import_semaphore_zircon_handle_info"))?;
|
||||||
@ -925,19 +671,9 @@ impl Semaphore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||||
#[inline]
|
|
||||||
pub unsafe fn import_zircon_handle_unchecked(
|
pub unsafe fn import_zircon_handle_unchecked(
|
||||||
&self,
|
&self,
|
||||||
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
|
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
|
||||||
) -> Result<(), VulkanError> {
|
|
||||||
let mut state = self.state.lock();
|
|
||||||
self.import_zircon_handle_unchecked_locked(import_semaphore_zircon_handle_info, &mut state)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn import_zircon_handle_unchecked_locked(
|
|
||||||
&self,
|
|
||||||
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
|
|
||||||
state: &mut SemaphoreState,
|
|
||||||
) -> Result<(), VulkanError> {
|
) -> Result<(), VulkanError> {
|
||||||
let ImportSemaphoreZirconHandleInfo {
|
let ImportSemaphoreZirconHandleInfo {
|
||||||
flags,
|
flags,
|
||||||
@ -960,17 +696,8 @@ impl Semaphore {
|
|||||||
.result()
|
.result()
|
||||||
.map_err(VulkanError::from)?;
|
.map_err(VulkanError::from)?;
|
||||||
|
|
||||||
state.import(
|
|
||||||
handle_type,
|
|
||||||
flags.intersects(SemaphoreImportFlags::TEMPORARY),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn state(&self) -> MutexGuard<'_, SemaphoreState> {
|
|
||||||
self.state.lock()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Semaphore {
|
impl Drop for Semaphore {
|
||||||
@ -1498,136 +1225,6 @@ pub struct ExternalSemaphoreProperties {
|
|||||||
pub compatible_handle_types: ExternalSemaphoreHandleTypes,
|
pub compatible_handle_types: ExternalSemaphoreHandleTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub(crate) struct SemaphoreState {
|
|
||||||
is_signaled: bool,
|
|
||||||
pending_signal: Option<SignalType>,
|
|
||||||
pending_wait: Option<Weak<Queue>>,
|
|
||||||
|
|
||||||
reference_exported: bool,
|
|
||||||
exported_handle_types: ExternalSemaphoreHandleTypes,
|
|
||||||
current_import: Option<ImportType>,
|
|
||||||
permanent_import: Option<ExternalSemaphoreHandleType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SemaphoreState {
|
|
||||||
/// If the semaphore does not have a pending operation and has no external references,
|
|
||||||
/// returns the current status.
|
|
||||||
#[inline]
|
|
||||||
fn is_signaled(&self) -> Option<bool> {
|
|
||||||
// If any of these is true, we can't be certain of the status.
|
|
||||||
if self.pending_signal.is_some()
|
|
||||||
|| self.pending_wait.is_some()
|
|
||||||
|| self.has_external_reference()
|
|
||||||
{
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(self.is_signaled)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_signal_pending(&self) -> bool {
|
|
||||||
self.pending_signal.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_wait_pending(&self) -> bool {
|
|
||||||
self.pending_wait.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_in_queue(&self) -> bool {
|
|
||||||
matches!(self.pending_signal, Some(SignalType::Queue(_))) || self.pending_wait.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether there are any potential external references to the semaphore payload.
|
|
||||||
/// That is, the semaphore has been exported by reference transference, or imported.
|
|
||||||
#[inline]
|
|
||||||
fn has_external_reference(&self) -> bool {
|
|
||||||
self.reference_exported || self.current_import.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
fn is_exported(&self, handle_type: ExternalSemaphoreHandleType) -> bool {
|
|
||||||
self.exported_handle_types.intersects(handle_type.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc<Queue>) {
|
|
||||||
self.pending_signal = Some(SignalType::Queue(Arc::downgrade(queue)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn add_queue_wait(&mut self, queue: &Arc<Queue>) {
|
|
||||||
self.pending_wait = Some(Arc::downgrade(queue));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when a queue is unlocking resources.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn set_signal_finished(&mut self) {
|
|
||||||
self.pending_signal = None;
|
|
||||||
self.is_signaled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when a queue is unlocking resources.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn set_wait_finished(&mut self) {
|
|
||||||
self.pending_wait = None;
|
|
||||||
self.current_import = self.permanent_import.map(Into::into);
|
|
||||||
self.is_signaled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
unsafe fn export(&mut self, handle_type: ExternalSemaphoreHandleType) {
|
|
||||||
self.exported_handle_types |= handle_type.into();
|
|
||||||
|
|
||||||
if handle_type.has_copy_transference() {
|
|
||||||
self.current_import = self.permanent_import.map(Into::into);
|
|
||||||
self.is_signaled = false;
|
|
||||||
} else {
|
|
||||||
self.reference_exported = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
unsafe fn import(&mut self, handle_type: ExternalSemaphoreHandleType, temporary: bool) {
|
|
||||||
self.current_import = Some(handle_type.into());
|
|
||||||
|
|
||||||
if !temporary {
|
|
||||||
self.permanent_import = Some(handle_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) unsafe fn swapchain_acquire(&mut self) {
|
|
||||||
self.pending_signal = Some(SignalType::SwapchainAcquire);
|
|
||||||
self.current_import = Some(ImportType::SwapchainAcquire);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum SignalType {
|
|
||||||
Queue(Weak<Queue>),
|
|
||||||
SwapchainAcquire,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
enum ImportType {
|
|
||||||
SwapchainAcquire,
|
|
||||||
ExternalSemaphore(ExternalSemaphoreHandleType),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ExternalSemaphoreHandleType> for ImportType {
|
|
||||||
#[inline]
|
|
||||||
fn from(handle_type: ExternalSemaphoreHandleType) -> Self {
|
|
||||||
Self::ExternalSemaphore(handle_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -1717,8 +1314,9 @@ mod tests {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let _fd = sem
|
let _fd = unsafe {
|
||||||
.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
|
sem.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user