Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `VK_EXT_display_control` display extension (#934)
- Added `VK_EXT_metal_objects` device extension (#942)
- Added `VK_AMD_anti_lag` device extension (#943)
- Added `VK_KHR_pipeline_binary` device extension (#944)
- Added `VK_KHR_video_queue`, `VK_KHR_video_encode_queue`, and `VK_KHR_video_decode_queue` device extensions (#965)
- Added (typically vendor-suffixed) aliases for global constants (#1018)

Expand Down
1 change: 1 addition & 0 deletions ash/src/extensions/khr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub mod maintenance4;
pub mod maintenance5;
pub mod maintenance6;
pub mod performance_query;
pub mod pipeline_binary;
pub mod pipeline_executable_properties;
pub mod present_wait;
pub mod push_descriptor;
Expand Down
89 changes: 89 additions & 0 deletions ash/src/extensions/khr/pipeline_binary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//! <https://docs.vulkan.org/refpages/latest/refpages/source/VK_KHR_pipeline_binary.html>

use crate::read_into_uninitialized_binary_vector;
use crate::vk;
use crate::RawPtr as _;
use crate::VkResult;
use alloc::vec::Vec;

impl crate::khr::pipeline_binary::Device {
/// <https://docs.vulkan.org/refpages/latest/refpages/source/vkCreatePipelineBinariesKHR.html>
#[inline]
#[doc(alias = "vkCreatePipelineBinariesKHR")]
pub unsafe fn create_pipeline_binaries(
&self,
create_info: &vk::PipelineBinaryCreateInfoKHR<'_>,
allocation_callbacks: Option<&vk::AllocationCallbacks>,
binaries: &mut vk::PipelineBinaryHandlesInfoKHR<'_>,
) -> VkResult<()> {
(self.fp.create_pipeline_binaries_khr)(
self.handle,
create_info,
allocation_callbacks.to_raw_ptr(),
binaries,
)
.result()
}

/// <https://docs.vulkan.org/refpages/latest/refpages/source/vkDestroyPipelineBinaryKHR.html>
#[inline]
#[doc(alias = "vkDestroyPipelineBinaryKHR")]
pub unsafe fn destroy_pipeline_binary(
&self,
pipeline_binary: vk::PipelineBinaryKHR,
allocation_callbacks: Option<&vk::AllocationCallbacks>,
) {
(self.fp.destroy_pipeline_binary_khr)(
self.handle,
pipeline_binary,
allocation_callbacks.to_raw_ptr(),
)
}

/// <https://docs.vulkan.org/refpages/latest/refpages/source/vkGetPipelineKeyKHR.html>
#[inline]
#[doc(alias = "vkGetPipelineKeyKHR")]
pub unsafe fn get_pipeline_key(
&self,
pipeline_create_info: Option<&vk::PipelineCreateInfoKHR<'_>>,
pipeline_key: &mut vk::PipelineBinaryKeyKHR<'_>,
) -> VkResult<()> {
(self.fp.get_pipeline_key_khr)(self.handle, pipeline_create_info.to_raw_ptr(), pipeline_key)
.result()
}

/// <https://docs.vulkan.org/refpages/latest/refpages/source/vkGetPipelineBinaryDataKHR.html>
#[inline]
#[doc(alias = "vkGetPipelineBinaryDataKHR")]
pub unsafe fn get_pipeline_binary_data(
&self,
info: &vk::PipelineBinaryDataInfoKHR<'_>,
pipeline_binary_key: &mut vk::PipelineBinaryKeyKHR<'_>,
) -> VkResult<Vec<u8>> {
read_into_uninitialized_binary_vector(|count, data| {
(self.fp.get_pipeline_binary_data_khr)(
self.handle,
info,
pipeline_binary_key,
count,
data,
)
})
}

/// <https://docs.vulkan.org/refpages/latest/refpages/source/vkReleaseCapturedPipelineDataKHR.html>
#[inline]
#[doc(alias = "vkReleaseCapturedPipelineDataKHR")]
pub unsafe fn release_captured_pipeline_data(
&self,
info: &vk::ReleaseCapturedPipelineDataInfoKHR<'_>,
allocation_callbacks: Option<&vk::AllocationCallbacks>,
) -> VkResult<()> {
(self.fp.release_captured_pipeline_data_khr)(
self.handle,
info,
allocation_callbacks.to_raw_ptr(),
)
.result()
}
}
42 changes: 39 additions & 3 deletions ash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ extern crate alloc;

use alloc::vec::Vec;
use core::convert::TryInto;
use core::ffi;
use core::mem;
use core::ptr;

Expand Down Expand Up @@ -242,13 +243,13 @@ impl vk::Result {
/// Repeatedly calls `f` until it does not return [`vk::Result::INCOMPLETE`] anymore, ensuring all
/// available data has been read into the vector.
///
/// See for example [`vkEnumerateInstanceExtensionProperties`]: the number of available items may
/// See for example [`vkEnumerateInstanceExtensionProperties()`]: the number of available items may
/// change between calls; [`vk::Result::INCOMPLETE`] is returned when the count increased (and the
/// vector is not large enough after querying the initial size), requiring Ash to try again.
///
/// [`vkEnumerateInstanceExtensionProperties`]: https://docs.vulkan.org/refpages/latest/refpages/source/vkEnumerateInstanceExtensionProperties.html
/// [`vkEnumerateInstanceExtensionProperties()`]: https://docs.vulkan.org/refpages/latest/refpages/source/vkEnumerateInstanceExtensionProperties.html
pub(crate) unsafe fn read_into_uninitialized_vector<N: Copy + Default + TryInto<usize>, T>(
f: impl Fn(&mut N, *mut T) -> vk::Result,
mut f: impl FnMut(&mut N, *mut T) -> vk::Result,
) -> VkResult<Vec<T>>
where
<N as TryInto<usize>>::Error: core::fmt::Debug,
Expand All @@ -269,6 +270,41 @@ where
}
}

/// Calls `f` at most twice until it does not return [`vk::Result::ERROR_NOT_ENOUGH_SPACE_KHR`],
/// ensuring all available binary data has been read into the vector.
///
/// The first call happens with a [`Vec`] of capacity `4096`. If this is not adequate, `f` is

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a blocker, but I'd like to see some sort of reference for why we think 4KiB in particular makes sense here rather than, say, 128B, or 1MiB.

/// supposed to return [`vk::Result::ERROR_NOT_ENOUGH_SPACE_KHR`] while also updating `count` to the
/// desired number of elements, allowing us to try again.
///
/// This function is _not_ designed to be used with [`vk::Result::INCOMPLETE`], see
/// [`read_into_uninitialized_vector()`] instead.
///
/// See for example [`vkGetPipelineBinaryDataKHR()`], where the new return code was first introduced.
///
/// [`vkGetPipelineBinaryDataKHR()`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetPipelineBinaryDataKHR.html
pub(crate) unsafe fn read_into_uninitialized_binary_vector(
mut f: impl FnMut(&mut usize, *mut ffi::c_void) -> vk::Result,
) -> VkResult<Vec<u8>> {
let mut data = Vec::<u8>::with_capacity(4096);
let mut count = data.capacity();
let mut err_code = f(&mut count, data.as_mut_ptr().cast());
if err_code == vk::Result::ERROR_NOT_ENOUGH_SPACE_KHR {
debug_assert!(
count > data.capacity(),
"Implementation should have updated the value to be higher than the initial request"
);
data.reserve(count);

@Ralith Ralith May 4, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec::reserve takes the number of additional bytes, so this will over-allocate. We should pass count - data.capacity() (probably via a temporary to keep borrowck happy).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We don't expect to reallocate this any further, so Vec::reserve_exact would be a little better.

err_code = f(&mut count, data.as_mut_ptr().cast());
debug_assert_ne!(
err_code,
vk::Result::ERROR_NOT_ENOUGH_SPACE_KHR,
"Updated count was still not adequate"
);
}
err_code.set_vec_len_on_success(data, count)
}

#[test]
fn trybuild() {
let t = trybuild::TestCases::new();
Expand Down