Skip to content

Commit

Permalink
generator: Replace Extends{Root} with StructExtends<Root> generic
Browse files Browse the repository at this point in the history
Instead of emitting a new `trait` for every `Root` struct that is being
implemented by one or more "child" structs (those that have `Root` in
their `structextends`), create one trait that takes the root struct as a
generic parameter, and implement that directly instead.

This not only saves on having to define the `trait` for every
`Root` struct but also paves the way towards providing default trait
implementations for any pair of root and child struct, such as the
`p_next` builder methods.
  • Loading branch information
MarijnS95 committed Dec 8, 2024
1 parent 8b0d4c5 commit b2b971f
Show file tree
Hide file tree
Showing 9 changed files with 3,563 additions and 2,119 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `get_pipeline_executable_statistics()`.
The expected length of this array can be queried with the respective `*_len()` variant of these functions.
- `push_next()` has been renamed to `extend()` and marked as `unsafe`. Users are encouraged to call `push()` for singular structs instead. (#909)
- All `Extends{Root}` traits have been replaced with a single `Extends<Root>` trait using generics. (#971)

### Removed

Expand Down
3 changes: 3 additions & 0 deletions ash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ rust-version = "1.69.0"
[dependencies]
libloading = { version = "0.8", optional = true }

[dev-dependencies]
trybuild = "1.0"

[features]
default = ["loaded", "debug", "std"]
# Link the Vulkan loader at compile time.
Expand Down
5 changes: 4 additions & 1 deletion ash/src/extensions/khr/acceleration_structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,10 @@ impl crate::khr::acceleration_structure::Device {
max_primitive_counts: &[u32],
size_info: &mut vk::AccelerationStructureBuildSizesInfoKHR<'_>,
) {
assert_eq!(max_primitive_counts.len(), build_info.geometry_count as _);
assert_eq!(
max_primitive_counts.len(),
build_info.geometry_count as usize
);

(self.fp.get_acceleration_structure_build_sizes_khr)(
self.handle,
Expand Down
6 changes: 6 additions & 0 deletions ash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,9 @@ where
}
}
}

#[test]
fn trybuild() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/fail/long_lived_root_struct_borrow.rs");
}
65 changes: 65 additions & 0 deletions ash/src/vk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ pub unsafe trait TaggedStructure {
const STRUCTURE_TYPE: StructureType;
}

/// Implemented for every structure that extends base structure `B`. Concretely that means struct
/// `B` is listed in its array of [`structextends` in the Vulkan registry][1].
///
/// Similar to [`TaggedStructure`] , all `unsafe` implementers of this trait must guarantee that
/// their structure is layout-compatible [`vk::BaseInStructure`] and [`vk::BaseOutStructure`].
///
/// [1]: https://registry.khronos.org/vulkan/specs/latest/styleguide.html#extensions-interactions
pub unsafe trait Extends<B> {}

/// Iterates through the pointer chain. Includes the item that is passed into the function.
/// Stops at the last [`BaseOutStructure`] that has a null [`BaseOutStructure::p_next`] field.
pub(crate) unsafe fn ptr_chain_iter<T: ?Sized>(
Expand Down Expand Up @@ -222,6 +231,62 @@ mod tests {
assert_eq!(chain, chain2);
}

#[test]
#[should_panic]
fn disallow_nested_ptr_chains() {
let mut generated_commands =
vk::PhysicalDeviceDeviceGeneratedCommandsFeaturesEXT::default();
let mut private_data = vk::PhysicalDevicePrivateDataFeatures {
p_next: <*mut _>::cast(&mut generated_commands),
..Default::default()
};
let _device_create_info = vk::DeviceCreateInfo::default().push(&mut private_data);
}

#[test]
fn test_nested_ptr_chains() {
let mut generated_commands =
vk::PhysicalDeviceDeviceGeneratedCommandsFeaturesEXT::default();
let mut private_data = vk::PhysicalDevicePrivateDataFeatures {
p_next: <*mut _>::cast(&mut generated_commands),
..Default::default()
};
let mut variable_pointers = vk::PhysicalDeviceVariablePointerFeatures::default();
let mut corner = vk::PhysicalDeviceCornerSampledImageFeaturesNV::default();
let chain = alloc::vec![
<*mut _>::cast(&mut private_data),
<*mut _>::cast(&mut generated_commands),
<*mut _>::cast(&mut variable_pointers),
<*mut _>::cast(&mut corner),
];
let mut device_create_info = vk::DeviceCreateInfo::default()
.push(&mut corner)
.push(&mut variable_pointers);
// Insert private_data->generated_commands into the chain, such that generate_commands->variable_pointers->corner:
device_create_info = unsafe { device_create_info.extend(&mut private_data) };
let chain2: Vec<*mut vk::BaseOutStructure<'_>> = unsafe {
vk::ptr_chain_iter(&mut device_create_info)
.skip(1)
.collect()
};
assert_eq!(chain, chain2);
}

#[test]
fn test_dynamic_add_to_ptr_chain() {
let mut variable_pointers = vk::PhysicalDeviceVariablePointerFeatures::default();
let variable_pointers: &mut dyn vk::Extends<vk::DeviceCreateInfo<'_>> =
&mut variable_pointers;
let chain = alloc::vec![<*mut _>::cast(variable_pointers)];
let mut device_create_info = vk::DeviceCreateInfo::default().push(variable_pointers);
let chain2: Vec<*mut vk::BaseOutStructure<'_>> = unsafe {
vk::ptr_chain_iter(&mut device_create_info)
.skip(1)
.collect()
};
assert_eq!(chain, chain2);
}

#[test]
fn test_debug_flags() {
assert_eq!(
Expand Down
Loading

0 comments on commit b2b971f

Please sign in to comment.