Skip to content

Commit

Permalink
extensions/nv/low_latency2: Use count parameter for p_timings "ar…
Browse files Browse the repository at this point in the history
…ray" member

As it turns out this extension has a rather suboptimal layout where
the `vk::GetLatencyMarkerInfoNV` struct is not aware that its own
`p_timings` field is an array, because it does not have a count field.
Instead the length of this array is passed around via the `pTimingCount`
pointer parameter of `get_latency_timings()`.

A couple things are needed to set this straight:
1. The struct builder must be adjusted to accept a slice (without
   storing the length anywhere...);
2. The `get_latency_timings()` wrapper function should no longer accept
   a mutable slice of `vk::GetLatencyMarkerInfoNV`, but instead accept a
   single object that contains a pointer to the array (and `p_next`...);
3. This function must have a separate parameter to pass the length of
   the `p_timings` slice mentioned at 1., as we cannot reconstruct it
   from `vk::GetLatencyMarkerInfoNV` nor via its `p_timings` pointer;
4. The mutable struct and initialized `p_timings` array must still be
   passed fully by the user because both `vk::GetLatencyMarkerInfoNV`
   and `vk::LatencyTimingsFrameReportNV` have a `p_next` field that the
   user could initialize to point to some extension structure that they
   desire to be filled in.  This info might also be relevant in the
   `_len()` query;
5. Asserts have been put in place to ensure correct use of this API
   with regards to `p_timings` being (not) NULL for querying the count
   or actual values, respectively.
  • Loading branch information
MarijnS95 committed Nov 9, 2023
1 parent d0c5e97 commit d1ae6aa
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 20 deletions.
38 changes: 24 additions & 14 deletions ash/src/extensions/nv/low_latency2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::RawPtr;
use crate::{Device, Instance};
use std::ffi::CStr;
use std::mem;
use std::ptr;

/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_NV_low_latency2.html>
#[derive(Clone)]
Expand Down Expand Up @@ -53,32 +52,43 @@ impl LowLatency2 {
(self.fp.set_latency_marker_nv)(self.handle, swapchain, latency_marker_info)
}

/// Retrieve the number of elements to pass to [`get_latency_timings()`][Self::get_latency_timings()]
/// Retrieve the number of elements to pass to [`vk::GetLatencyMarkerInfoNV::timings()`] in
/// [`get_latency_timings()`][Self::get_latency_timings()]
#[inline]
pub unsafe fn get_latency_timings_len(&self, swapchain: vk::SwapchainKHR) -> usize {
pub unsafe fn get_latency_timings_len(
&self,
swapchain: vk::SwapchainKHR,
latency_marker_info: &mut vk::GetLatencyMarkerInfoNV<'_>,
) -> usize {
assert!(
latency_marker_info.p_timings.is_null(),
"latency_marker_info.p_timings must be NULL in order to query its length"
);
let mut count = 0;
(self.fp.get_latency_timings_nv)(self.handle, swapchain, &mut count, ptr::null_mut());
(self.fp.get_latency_timings_nv)(self.handle, swapchain, &mut count, latency_marker_info);
count as usize
}

/// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetLatencyTimingsNV.html>
///
/// Call [`get_latency_timings_len()`][Self::get_latency_timings_len()] to query the number of elements to pass to `latency_marker_info`.
/// Be sure to [`Default::default()`]-initialize these elements and optionally set their `p_next` pointer.
/// Call [`get_latency_timings_len()`][Self::get_latency_timings_len()] to query the number of
/// elements to pass to [`vk::GetLatencyMarkerInfoNV::timings()`].
/// Be sure to [`Default::default()`]-initialize `timing_count` elements and optionally set their `p_next` pointer.
#[inline]
pub unsafe fn get_latency_timings(
&self,
swapchain: vk::SwapchainKHR,
latency_marker_info: &mut [vk::GetLatencyMarkerInfoNV<'_>],
timing_count: usize,
latency_marker_info: &mut vk::GetLatencyMarkerInfoNV<'_>,
) {
let mut count = latency_marker_info.len() as u32;
(self.fp.get_latency_timings_nv)(
self.handle,
swapchain,
&mut count,
latency_marker_info.as_mut_ptr(),
let mut count = timing_count as u32;
assert!(
!latency_marker_info.p_timings.is_null(),
"latency_marker_info.p_timings must be a valid pointer to an array of {} elements",
count
);
assert_eq!(count as usize, latency_marker_info.len());
(self.fp.get_latency_timings_nv)(self.handle, swapchain, &mut count, latency_marker_info);
assert_eq!(timing_count, count as usize);
}

/// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkQueueNotifyOutOfBandNV.html>
Expand Down
21 changes: 17 additions & 4 deletions ash/src/vk/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4319,8 +4319,8 @@ impl<'a> PipelineMultisampleStateCreateInfo<'a> {
self.min_sample_shading = min_sample_shading;
self
}
#[doc = r" Sets `p_sample_mask` to `null` if the slice is empty. The mask will"]
#[doc = r" be treated as if it has all bits set to `1`."]
#[doc = r" Sets [`Self::p_sample_mask`] to [`std::ptr::null()`] if the slice is empty. The"]
#[doc = r" mask will be treated as if it has all bits set to `1`."]
#[doc = r""]
#[doc = r" See <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineMultisampleStateCreateInfo.html#_description>"]
#[doc = r" for more details."]
Expand Down Expand Up @@ -51890,9 +51890,22 @@ unsafe impl<'a> TaggedStructure for GetLatencyMarkerInfoNV<'a> {
const STRUCTURE_TYPE: StructureType = StructureType::GET_LATENCY_MARKER_INFO_NV;
}
impl<'a> GetLatencyMarkerInfoNV<'a> {
#[doc = r" This only sets the slice pointer. Users must manually pass the length of"]
#[doc = r" `timings` to [`crate::extensions::nv::LowLatency2::get_latency_timings()`]."]
#[doc = r""]
#[doc = r" [`Self::p_timings`] will be set to to [`std::ptr::null_mut()`] if the"]
#[doc = r" slice is empty, which is necessary to query the length of the array via"]
#[doc = r" [`crate::extensions::nv::LowLatency2::get_latency_timings_len()`]."]
#[doc = r""]
#[doc = r" See <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetLatencyTimingsNV.html#_description>"]
#[doc = r" for more details."]
#[inline]
pub fn timings(mut self, timings: &'a mut LatencyTimingsFrameReportNV<'a>) -> Self {
self.p_timings = timings;
pub fn timings(mut self, timings: &'a mut [LatencyTimingsFrameReportNV<'a>]) -> Self {
self.p_timings = if timings.is_empty() {
std::ptr::null_mut()
} else {
timings.as_mut_ptr()
};
self
}
}
Expand Down
30 changes: 28 additions & 2 deletions generator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1972,8 +1972,8 @@ fn derive_setters(

if name == "pSampleMask" {
return Some(quote! {
/// Sets `p_sample_mask` to `null` if the slice is empty. The mask will
/// be treated as if it has all bits set to `1`.
/// Sets [`Self::p_sample_mask`] to [`std::ptr::null()`] if the slice is empty. The
/// mask will be treated as if it has all bits set to `1`.
///
/// See <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPipelineMultisampleStateCreateInfo.html#_description>
/// for more details.
Expand Down Expand Up @@ -2004,6 +2004,32 @@ fn derive_setters(
});
}

// pTimings is a dynamic array, but its length is only available as a mutable-pointer parameter in a calling function:
// https://github.com/KhronosGroup/Vulkan-Docs/issues/2269
if struct_.name == "VkGetLatencyMarkerInfoNV" && field.name.as_deref() == Some("pTimings") {
return Some(quote! {
/// This only sets the slice pointer. Users must manually pass the length of
/// `timings` to [`crate::extensions::nv::LowLatency2::get_latency_timings()`].
///
/// [`Self::p_timings`] will be set to to [`std::ptr::null_mut()`] if the
/// slice is empty, which is necessary to query the length of the array via
/// [`crate::extensions::nv::LowLatency2::get_latency_timings_len()`].
///
/// See <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetLatencyTimingsNV.html#_description>
/// for more details.
#[inline]
#deprecated
pub fn timings(mut self, timings: &'a mut [LatencyTimingsFrameReportNV<'a>]) -> Self {
self.p_timings = if timings.is_empty() {
std::ptr::null_mut()
} else {
timings.as_mut_ptr()
};
self
}
});
}

if matches!(field.array, Some(vkxml::ArrayType::Dynamic)) {
if let Some(ref array_size) = field.size {
let mut slice_param_ty_tokens = field.safe_type_tokens(quote!('a), type_lifetime.clone(), None);
Expand Down

0 comments on commit d1ae6aa

Please sign in to comment.