use crate::ShaderLayout;
pub trait ShaderLayoutCompat: ShaderLayout {
const ALIGN_COMPAT: core::num::NonZero<u64> = Self::ALIGN;
const SIZE_COMPAT: core::num::NonZero<u64> =
core::num::NonZero::new(size_of::<Self>() as u64).unwrap();
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_shader_layout_compat_primitive {
($($ty:ty),+$(,)?) => {
$(
$crate::impl_shader_layout_primitive!($ty);
impl $crate::ShaderLayoutCompat for $ty {}
)+
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_shader_layout_compat {
($align:expr $(, $ty:ty)+$(,)?) => {
$(
$crate::impl_shader_layout!($align, $ty);
impl $crate::ShaderLayoutCompat for $ty {}
)+
};
($align:expr, $align_compat:expr $(, $ty:ty)+$(,)?) => {
$(
$crate::impl_shader_layout!($align, $ty);
impl $crate::ShaderLayoutCompat for $ty {
const ALIGN_COMPAT: ::core::num::NonZero<u64> = ::core::num::NonZero::new($align_compat).unwrap();
}
)+
};
($align:expr, $align_compat:expr, $size_compat:expr $(, $ty:ty)+$(,)?) => {
const _: () ={
assert!((($size_compat) as u64).is_multiple_of(16u64));
};
$(
$crate::impl_shader_layout!($align, $ty);
impl $crate::ShaderLayoutCompat for $ty {
const ALIGN_COMPAT: ::core::num::NonZero<u64> = ::core::num::NonZero::new($align_compat).unwrap();
const SIZE_COMPAT: ::core::num::NonZero<u64> = ::core::num::NonZero::new($size_compat).unwrap();
}
)+
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_shader_layout_custom_array_compat {
($elem_ty:ty, $array_ty:ty, $n:expr) => {
$crate::impl_shader_layout_custom_array!($elem_ty, $array_ty, $n);
impl $crate::ShaderLayoutCompat for $array_ty {
const ALIGN_COMPAT: ::core::num::NonZero<u64> = ::core::num::NonZero::new(
<$elem_ty as $crate::ShaderLayout>::ALIGN
.get()
.next_multiple_of(16),
)
.unwrap();
const SIZE_COMPAT: ::core::num::NonZero<u64> = ::core::num::NonZero::new(
(size_of::<$elem_ty>() as u64)
.next_multiple_of(<$elem_ty as $crate::ShaderLayout>::ALIGN.get())
.next_multiple_of(16)
* $n as u64,
)
.unwrap();
}
const _: () = {
const N: usize = $n;
const SIZE: u64 = <$array_ty as $crate::ShaderLayoutCompat>::SIZE_COMPAT.get();
if SIZE != size_of::<$array_ty>() as u64 {
let mut msg = $crate::internal::MsgBuf::<256>::new();
msg.write_str("Failed to implement `ShaderLayoutCompat`: array `")
.write_str(stringify!($array_ty))
.write_str("` size (")
.write_usize(size_of::<$array_ty>())
.write_str(") must be equal to its shader size (")
.write_u64(SIZE)
.write_str("), i.e. the stride must be rounded up to `ALIGN` (")
.write_u64(<$elem_ty as $crate::ShaderLayout>::ALIGN.get())
.write_str(") and 16");
panic!("{}", msg.as_str());
}
};
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_shader_layout_array_compat {
($($ty:ty),+$(,)?) => {
$(
$crate::impl_shader_layout_array!($ty);
impl<const N: usize> $crate::ShaderLayoutCompat for [$ty; N]
{
const ALIGN_COMPAT: ::core::num::NonZero<u64> = ::core::num::NonZero::new(
<$ty as $crate::ShaderLayout>::ALIGN.get().next_multiple_of(16)
).unwrap();
const SIZE_COMPAT: ::core::num::NonZero<u64> = ::core::num::NonZero::new(
(size_of::<$ty>() as u64).next_multiple_of(<$ty as $crate::ShaderLayout>::ALIGN.get()).next_multiple_of(16) * N as u64
).unwrap();
}
const _: () = {
const ELEMENT_ALIGN: u64 = <$ty as $crate::ShaderLayout>::ALIGN.get();
const N: usize = 1;
const SIZE: u64 = <[$ty; N] as $crate::ShaderLayoutCompat>::SIZE_COMPAT.get();
if SIZE != size_of::<[$ty; N]>() as u64 {
let mut msg = $crate::internal::MsgBuf::<256>::new();
msg.write_str("`[")
.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! shader_layout_compat {
(
$(#[$attr:meta])*
$vis:vis struct $struct_name:ident {
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident : $field_ty:ty
),* $(,)?
}
) => {
$crate::shader_layout!(
$(#[$attr])*
$vis struct $struct_name {
$(
$(#[$field_attr])*
$field_vis $field_name: $field_ty
),*
}
);
$(
const _: () = {
const MEMBER_ALIGN_COMPAT: u64 = <$field_ty as $crate::ShaderLayoutCompat>::ALIGN_COMPAT.get();
const MEMBER_SIZE_COMPAT: u64 = <$field_ty as $crate::ShaderLayoutCompat>::SIZE_COMPAT.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_COMPAT {
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_COMPAT` (")
.write_u64(MEMBER_SIZE_COMPAT)
.write_str(") due to uniform layout constraints");
panic!("{}", msg.as_str());
}
if !MEMBER_OFFSET.is_multiple_of(MEMBER_ALIGN_COMPAT) {
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_COMPAT` (")
.write_u64(MEMBER_ALIGN_COMPAT)
.write_str(")");
panic!("{}", msg.as_str());
}
};
)*
impl $crate::ShaderLayoutCompat for $struct_name {
const ALIGN_COMPAT: ::core::num::NonZero<u64> = {
const MEMBER_ALIGNS: &[u64] = &[$(
(<$field_ty as $crate::ShaderLayoutCompat>::ALIGN_COMPAT.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_COMPAT: ::core::num::NonZero<u64> = {
const MEMBER_SIZES: &[u64] = &[$(
(<$field_ty as $crate::ShaderLayoutCompat>::SIZE_COMPAT.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()
};
}
};
}