Skip to content

Commit

Permalink
relax alignment requirements for scalars, vectors and matrices when i…
Browse files Browse the repository at this point in the history
…n uniform address space
  • Loading branch information
teoxoy committed Mar 15, 2022
1 parent 151df26 commit 89f3a1c
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 25 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "encase"
version = "0.1.1"
version = "0.1.2"
edition = "2021"
rust-version = "1.57"

Expand Down Expand Up @@ -32,7 +32,7 @@ members = ["derive"]
criterion = { git = "https://github.com/bheisler/criterion.rs", rev = "6929f48e4828360de038f4e9732066d85b9a57c6" }

[dependencies]
encase_derive = { version = "=0.1.1", path = "derive" }
encase_derive = { version = "=0.1.2", path = "derive" }

thiserror = { version = "1", default-features = false }
const_panic = { version = "0.2", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "encase_derive"
version = "0.1.1"
version = "0.1.2"
edition = "2021"

license = "MIT-0"
Expand Down
50 changes: 41 additions & 9 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,17 +337,48 @@ fn emit(input: DeriveInput) -> TokenStream {
};
let ident = data.ident();
let name = ident.to_string();
let field_check = quote_spanned! {ident.span()=> {
let offset = <Self as #root::WgslType>::METADATA.offset(#i);
#root::concat_assert!(
#root::MIN_UNIFORM_ALIGNMENT.is_aligned(offset),
"offset of field '", #name, "' must be a multiple of ", #root::MIN_UNIFORM_ALIGNMENT.get(),
" (current offset: ", offset, ")"
)
}};
let field_offset_check = quote_spanned! {ident.span()=>
if let ::core::option::Option::Some(min_alignment) =
<#ty as #root::WgslType>::METADATA.uniform_min_alignment()
{
let offset = <Self as #root::WgslType>::METADATA.offset(#i);

#root::concat_assert!(
min_alignment.is_aligned(offset),
"offset of field '", #name, "' must be a multiple of ", min_alignment.get(),
" (current offset: ", offset, ")"
)
}
};
let field_offset_diff = if i != 0 {
let prev_field = &field_data[i - 1];
let prev_field_ty = &prev_field.field.ty;
let prev_ident_name = prev_field.ident().to_string();
quote_spanned! {ident.span()=>
if let ::core::option::Option::Some(min_alignment) =
<#prev_field_ty as #root::WgslType>::METADATA.uniform_min_alignment()
{
let prev_offset = <Self as #root::WgslType>::METADATA.offset(#i - 1);
let offset = <Self as #root::WgslType>::METADATA.offset(#i);
let diff = offset - prev_offset;

let prev_size = <#prev_field_ty as #root::Size>::SIZE.get();
let prev_size = min_alignment.round_up(prev_size);

#root::concat_assert!(
diff >= prev_size,
"offset between fields '", #prev_ident_name, "' and '", #name, "' must be at least ",
min_alignment.get(), " (currently: ", diff, ")"
)
}
}
} else {
quote! {()}
};
quote! {
#ty_check,
#field_check
#field_offset_check,
#field_offset_diff
}
});

Expand Down Expand Up @@ -579,6 +610,7 @@ fn emit(input: DeriveInput) -> TokenStream {

#root::Metadata {
alignment: struct_alignment,
has_uniform_min_alignment: true,
min_size,
extra,
}
Expand Down
13 changes: 12 additions & 1 deletion src/core/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use std::num::NonZeroU64;

use super::{AlignmentValue, BufferMut, BufferRef, Reader, SizeValue, Writer};

pub const MIN_UNIFORM_ALIGNMENT: AlignmentValue = AlignmentValue::new(16);
const UNIFORM_MIN_ALIGNMENT: AlignmentValue = AlignmentValue::new(16);

pub struct Metadata<E> {
pub alignment: AlignmentValue,
pub has_uniform_min_alignment: bool,
pub min_size: SizeValue,
pub extra: E,
}
Expand All @@ -14,6 +15,7 @@ impl Metadata<()> {
pub const fn from_alignment_and_size(alignment: u64, size: u64) -> Self {
Self {
alignment: AlignmentValue::new(alignment),
has_uniform_min_alignment: false,
min_size: SizeValue::new(size),
extra: (),
}
Expand All @@ -30,6 +32,15 @@ impl<E> Metadata<E> {
value
}

pub const fn uniform_min_alignment(self) -> Option<AlignmentValue> {
let value = self.has_uniform_min_alignment;
core::mem::forget(self);
match value {
true => Some(UNIFORM_MIN_ALIGNMENT),
false => None,
}
}

pub const fn min_size(self) -> SizeValue {
let value = self.min_size;
core::mem::forget(self);
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ pub mod private {
pub use super::core::SizeValue;
pub use super::core::WriteInto;
pub use super::core::Writer;
pub use super::core::MIN_UNIFORM_ALIGNMENT;
pub use super::types::array::ArrayMetadata;
pub use super::types::matrix::*;
pub use super::types::r#struct::StructMetadata;
Expand Down
21 changes: 12 additions & 9 deletions src/types/array.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::core::{
BufferMut, BufferRef, CreateFrom, Metadata, ReadFrom, Reader, Size, SizeValue, WgslType,
WriteInto, Writer, MIN_UNIFORM_ALIGNMENT,
WriteInto, Writer,
};

pub struct ArrayMetadata {
Expand Down Expand Up @@ -34,21 +34,24 @@ impl<T: WgslType + Size, const N: usize> WgslType for [T; N] {

Metadata {
alignment,
has_uniform_min_alignment: true,
min_size: size,
extra: ArrayMetadata { stride, el_padding },
}
};

const UNIFORM_COMPAT_ASSERT: () = crate::utils::consume_zsts([
<T as WgslType>::UNIFORM_COMPAT_ASSERT,
const_panic::concat_assert!(
MIN_UNIFORM_ALIGNMENT.is_aligned(Self::METADATA.stride().get()),
"array stride must be a multiple of ",
MIN_UNIFORM_ALIGNMENT.get(),
" (current stride: ",
Self::METADATA.stride().get(),
")"
),
if let Some(min_alignment) = Self::METADATA.uniform_min_alignment() {
const_panic::concat_assert!(
min_alignment.is_aligned(Self::METADATA.stride().get()),
"array stride must be a multiple of ",
min_alignment.get(),
" (current stride: ",
Self::METADATA.stride().get(),
")"
)
},
]);
}

Expand Down
1 change: 1 addition & 0 deletions src/types/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ macro_rules! impl_matrix_inner {

$crate::private::Metadata {
alignment,
has_uniform_min_alignment: false,
min_size: size,
extra: $crate::private::MatrixMetadata {
row_padding,
Expand Down
1 change: 1 addition & 0 deletions src/types/runtime_sized_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ macro_rules! impl_rts_array_inner {

$crate::private::Metadata {
alignment,
has_uniform_min_alignment: true,
min_size: el_size,
extra: $crate::private::ArrayMetadata { stride, el_padding },
}
Expand Down
1 change: 1 addition & 0 deletions src/types/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ macro_rules! impl_vector_inner {

$crate::private::Metadata {
alignment,
has_uniform_min_alignment: false,
min_size: size,
extra: ()
}
Expand Down
48 changes: 48 additions & 0 deletions tests/compile_fail/assert_uniform_compat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use encase::WgslType;

fn main() {}

#[derive(WgslType)]
struct S {
x: f32,
}

#[derive(WgslType)]
struct WrappedF32 {
#[size(16)]
elem: f32,
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestStruct {
a: u32,
b: S,
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestArray {
a: u32,
b: [WrappedF32; 1],
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestStructFirst {
a: S,
b: f32,
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestArrayStride {
a: [u32; 8],
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestRTSArray {
#[size(runtime)]
a: Vec<f32>,
}
57 changes: 57 additions & 0 deletions tests/compile_fail/assert_uniform_compat.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
error[E0080]: evaluation of constant value failed
--> tests/compile_fail/assert_uniform_compat.rs:16:10
|
16 | #[derive(WgslType)]
| ^^^^^^^^ the evaluated program panicked at 'offset of field 'b' must be a multiple of 16 (current offset: 4)', $DIR/tests/compile_fail/assert_uniform_compat.rs:16:10
|
= note: this error originates in the macro `$crate::concat_panic` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: evaluation of constant value failed
--> tests/compile_fail/assert_uniform_compat.rs:23:10
|
23 | #[derive(WgslType)]
| ^^^^^^^^ the evaluated program panicked at 'offset of field 'b' must be a multiple of 16 (current offset: 4)', $DIR/tests/compile_fail/assert_uniform_compat.rs:23:10
|
= note: this error originates in the macro `$crate::concat_panic` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: evaluation of constant value failed
--> tests/compile_fail/assert_uniform_compat.rs:30:10
|
30 | #[derive(WgslType)]
| ^^^^^^^^ the evaluated program panicked at 'offset between fields 'a' and 'b' must be at least 16 (currently: 4)', $DIR/tests/compile_fail/assert_uniform_compat.rs:30:10
|
= note: this error originates in the macro `$crate::concat_panic` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: evaluation of `encase::types::array::<impl encase::WgslType for [u32; 8]>::UNIFORM_COMPAT_ASSERT` failed
--> src/types/array.rs
|
| / const_panic::concat_assert!(
| | min_alignment.is_aligned(Self::METADATA.stride().get()),
| | "array stride must be a multiple of ",
| | min_alignment.get(),
... |
| | ")"
| | )
| |_____________^ the evaluated program panicked at 'array stride must be a multiple of 16 (current stride: 4)', $DIR/src/types/array.rs:46:13
|
= note: this error originates in the macro `$crate::concat_panic` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: erroneous constant used
--> tests/compile_fail/assert_uniform_compat.rs:40:8
|
40 | a: [u32; 8],
| ^^^^^^^^ referenced constant has errors

error[E0080]: evaluation of `encase::types::runtime_sized_array::<impl encase::WgslType for std::vec::Vec<f32>>::UNIFORM_COMPAT_ASSERT` failed
--> src/types/runtime_sized_array.rs
|
| impl_rts_array!(Vec<T>; using len truncate);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'runtime-sized array can't be used in uniform buffers', $DIR/src/types/runtime_sized_array.rs:249:1
|
= note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0080]: erroneous constant used
--> tests/compile_fail/assert_uniform_compat.rs:47:8
|
47 | a: Vec<f32>,
| ^^^^^^^^ referenced constant has errors
38 changes: 38 additions & 0 deletions tests/pass/assert_uniform_compat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use encase::WgslType;

fn main() {}

#[derive(WgslType)]
struct S {
x: f32,
}

#[derive(WgslType)]
struct WrappedF32 {
#[size(16)]
elem: f32,
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestStruct {
a: u32,
#[align(16)]
b: S,
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestArray {
a: u32,
#[align(16)]
b: [WrappedF32; 1],
}

#[derive(WgslType)]
#[assert_uniform_compat]
struct TestStructFirst {
a: S,
#[align(16)]
b: f32,
}
2 changes: 1 addition & 1 deletion tests/pass/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ fn main() {}
#[derive(WgslType)]
#[assert_uniform_compat]
struct TestAttributes {
a: u32,
#[align(16)]
a: u32,
#[size(8)]
b: u32,
}
Expand Down
1 change: 0 additions & 1 deletion tests/uniform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use encase::{UniformBuffer, WgslType};
#[assert_uniform_compat]
struct TestUniform {
a: u32,
#[align(16)]
b: u32,
}

Expand Down

0 comments on commit 89f3a1c

Please sign in to comment.