use crate::ShaderLayout;
pub trait ShaderLayoutCompat: ShaderLayout {
const ALIGN_CONSTRAINT: core::num::NonZero<u64> = Self::ALIGN;
const SIZE_CONSTRAINT: core::num::NonZero<u64> =
core::num::NonZero::new(size_of::<Self>() as u64).unwrap();
}
pub trait ShaderLayoutCompatArrayElement: crate::ShaderLayoutArrayElement {}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_shader_layout_compat {
($($ty:ty),+$(,)?) => {
$(
$crate::impl_shader_layout!($ty);
impl $crate::ShaderLayoutCompat for $ty {}
)+
};
($align:expr $(, $ty:ty)+$(,)?) => {
$(
$crate::impl_shader_layout!($align, $ty);
impl $crate::ShaderLayoutCompat for $ty {}
)+
};
($align:expr, $align_constraint:expr $(, $ty:ty)+$(,)?) => {
$(
$crate::impl_shader_layout!($align, $ty);
impl $crate::ShaderLayoutCompat for $ty {
const ALIGN_CONSTRAINT: ::core::num::NonZero<u64> = ::core::num::NonZero::new($align_constraint).unwrap();
}
)+
};
($align:expr, $align_constraint:expr, $size_constraint:expr $(, $ty:ty)+$(,)?) => {
const _: () ={
assert!((($size_constraint) as u64).is_multiple_of(16u64));
};
$(
$crate::impl_shader_layout!($align, $ty);
impl $crate::ShaderLayoutCompat for $ty {
const ALIGN_CONSTRAINT: ::core::num::NonZero<u64> = ::core::num::NonZero::new($align_constraint).unwrap();
const SIZE_CONSTRAINT: ::core::num::NonZero<u64> = ::core::num::NonZero::new($size_constraint).unwrap();
}
)+
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_shader_layout_compat_array_element {
($($ty:ty),+$(,)?) => {
$(
$crate::impl_shader_layout_array_element!($ty);
impl $crate::ShaderLayoutCompatArrayElement for $ty {}
const _: () = {
const ELEMENT_ALIGN: u64 = <$ty as $crate::ShaderLayout>::ALIGN.get().next_multiple_of(16);
const N: usize = 1;
const ACTUAL_SIZE: u64 = size_of::<[$ty; N]>() as u64;
const SIZE: u64 = (size_of::<$ty>() as u64).next_multiple_of(ELEMENT_ALIGN) * N as u64;
if SIZE != ACTUAL_SIZE {
let mut msg = $crate::internal::MsgBuf::<256>::new();
msg.write_str("Failed to implement `ShaderLayoutCompatArrayElement`: `[")
.write_str(stringify!($ty))
.write_str("; N]` size (")
.write_usize(size_of::<[$ty; N]>())
.write_str(" * N) must be equal to its shader size (")
.write_u64(SIZE)
.write_str(" * N), i.e. the stride must be rounded up to `ALIGN` (")
.write_u64(ELEMENT_ALIGN)
.write_str(") and 16");
panic!("{}", msg.as_str());
}
};
)+
};
}
#[macro_export]
macro_rules! impl_shader_layout_compat_struct {
(
$(#[$attr:meta])*
$vis:vis struct $struct_name:ident {
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident : $field_ty:ty
),* $(,)?
}
) => {
$crate::impl_shader_layout_struct!(
$(#[$attr])*
$vis struct $struct_name {
$(
$(#[$field_attr])*
$field_vis $field_name: $field_ty
),*
}
);
$(
const _: () = {
const MEMBER_ALIGN_CONSTRAINT: u64 = <$field_ty as $crate::ShaderLayoutCompat>::ALIGN_CONSTRAINT.get();
const MEMBER_SIZE_CONSTRAINT: u64 = <$field_ty as $crate::ShaderLayoutCompat>::SIZE_CONSTRAINT.get();
const MEMBER_SIZE: u64 = size_of::<$field_ty>() as u64;
const MEMBER_OFFSET: u64 = core::mem::offset_of!($struct_name, $field_name) as u64;
if MEMBER_SIZE != MEMBER_SIZE_CONSTRAINT {
let mut msg = $crate::internal::MsgBuf::<256>::new();
msg.write_str("Failed to impl `ShaderLayoutCompat`: field `")
.write_str(stringify!($struct_name))
.write_str("::")
.write_str(stringify!($field_name))
.write_str("` (`")
.write_str(stringify!($field_ty))
.write_str("`) size (")
.write_u64(MEMBER_SIZE)
.write_str(") must be `SIZE_CONSTRAINT` (")
.write_u64(MEMBER_SIZE_CONSTRAINT)
.write_str(") due to uniform layout constraints");
panic!("{}", msg.as_str());
}
if !MEMBER_OFFSET.is_multiple_of(MEMBER_ALIGN_CONSTRAINT) {
let mut msg = $crate::internal::MsgBuf::<256>::new();
msg.write_str("Failed to impl `ShaderLayoutCompat`: field `")
.write_str(stringify!($struct_name))
.write_str("::")
.write_str(stringify!($field_name))
.write_str("` (`")
.write_str(stringify!($field_ty))
.write_str("`) is not properly aligned. The offset is ")
.write_u64(MEMBER_OFFSET)
.write_str(" but required align is `ALIGN_CONSTRAINT` (")
.write_u64(MEMBER_ALIGN_CONSTRAINT)
.write_str(")");
panic!("{}", msg.as_str());
}
};
)*
impl $crate::ShaderLayoutCompat for $struct_name {
const ALIGN_CONSTRAINT: ::core::num::NonZero<u64> = {
const MEMBER_ALIGNS: &[u64] = &[$(
(<$field_ty as $crate::ShaderLayoutCompat>::ALIGN_CONSTRAINT.get())
),*];
let mut max = MEMBER_ALIGNS[0];
let mut i = 1;
while i < MEMBER_ALIGNS.len() {
if MEMBER_ALIGNS[i] > max {
max = MEMBER_ALIGNS[i];
}
i += 1;
}
::core::num::NonZero::new(max.next_multiple_of(16)).unwrap()
};
const SIZE_CONSTRAINT: ::core::num::NonZero<u64> = {
const MEMBER_SIZES: &[u64] = &[$(
(<$field_ty as $crate::ShaderLayoutCompat>::SIZE_CONSTRAINT.get())
),*];
let mut sum = MEMBER_SIZES[0];
let mut i = 1;
while i < MEMBER_SIZES.len() {
sum += MEMBER_SIZES[i];
i += 1;
}
::core::num::NonZero::new(sum.next_multiple_of(16)).unwrap()
};
}
};
}
#[macro_export]
macro_rules! shader_layout_compat {
(
$(#[$attr:meta])*
$vis:vis struct $struct_name:ident {
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident : $field_ty:ty
),* $(,)?
}
) => {
#[derive(Copy, Clone)]
#[repr(C)]
$(#[$attr])*
$vis struct $struct_name {
$(
$(#[$field_attr])*
$field_vis $field_name: $field_ty
),*
}
$crate::impl_shader_layout_compat_struct!{
$(#[$attr])*
$vis struct $struct_name {
$(
$(#[$field_attr])*
$field_vis $field_name: $field_ty
),*
}
}
};
}