From 5c10df0ef913fe43c1f767c292d7345178e8a2d4 Mon Sep 17 00:00:00 2001 From: Alex S Date: Thu, 27 May 2021 06:59:16 +0300 Subject: [PATCH 01/11] Working arrays in crevice, can you believe it?! Quite a bit of black magic with newtypes and additional traits, but overall I quite like the final design. --- crevice-derive/src/layout.rs | 7 +++ crevice-tests/src/lib.rs | 32 ++++++++++ src/std140/dynamic_uniform.rs | 10 +++- src/std140/primitives.rs | 11 +++- src/std140/traits.rs | 109 +++++++++++++++++++++++++++++++++- src/std430/primitives.rs | 11 +++- src/std430/traits.rs | 107 ++++++++++++++++++++++++++++++++- 7 files changed, 281 insertions(+), 6 deletions(-) diff --git a/crevice-derive/src/layout.rs b/crevice-derive/src/layout.rs index a0d26fd..0819a01 100644 --- a/crevice-derive/src/layout.rs +++ b/crevice-derive/src/layout.rs @@ -19,6 +19,9 @@ pub fn emit( let as_trait_method = format_ident!("as_{}", mod_name); let from_trait_method = format_ident!("from_{}", mod_name); + let padded_name = format_ident!("{}Padded", trait_name); + let padded_path: Path = parse_quote!(#mod_path::#padded_name); + let visibility = input.vis; let input_name = input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); @@ -256,6 +259,10 @@ pub fn emit( unsafe impl #impl_generics #mod_path::#trait_name for #generated_name #ty_generics #where_clause { const ALIGNMENT: usize = #struct_alignment; const PAD_AT_END: bool = true; + type Padded = #padded_path(), + #struct_alignment + )}>; } impl #impl_generics #as_trait_path for #input_name #ty_generics #where_clause { diff --git a/crevice-tests/src/lib.rs b/crevice-tests/src/lib.rs index 340b162..d503545 100644 --- a/crevice-tests/src/lib.rs +++ b/crevice-tests/src/lib.rs @@ -323,3 +323,35 @@ fn proper_offset_calculations_for_differing_member_sizes() { trailing: 32, }); } + +#[test] +fn array_strides_small_value() { + #[derive(Debug, PartialEq, AsStd140, AsStd430)] + struct ArrayOfSmallValues { + inner: [f32; 4] + } + + assert_std140!((size = 64, align = 16) ArrayOfSmallValues { + inner: 0, + }); + + assert_std430!((size = 16, align = 4) ArrayOfSmallValues { + inner: 0, + }); +} + +#[test] +fn array_strides_vec3() { + #[derive(Debug, PartialEq, AsStd140, AsStd430)] + struct ArrayOfSmallValues { + inner: [Vector3; 4] + } + + assert_std140!((size = 64, align = 16) ArrayOfSmallValues { + inner: 0, + }); + + assert_std430!((size = 64, align = 16) ArrayOfSmallValues { + inner: 0, + }); +} diff --git a/src/std140/dynamic_uniform.rs b/src/std140/dynamic_uniform.rs index 8c071c2..262f8ea 100644 --- a/src/std140/dynamic_uniform.rs +++ b/src/std140/dynamic_uniform.rs @@ -1,6 +1,7 @@ use bytemuck::{Pod, Zeroable}; -use crate::internal::max; +#[allow(unused_imports)] +use crate::internal::{align_offset, max}; use crate::std140::{AsStd140, Std140}; /// Wrapper type that aligns the inner type to at least 256 bytes. @@ -28,6 +29,13 @@ pub struct DynamicUniformStd140(T); unsafe impl Std140 for DynamicUniformStd140 { const ALIGNMENT: usize = max(256, T::ALIGNMENT); + #[cfg(const_evaluatable_checked)] + type Padded = crate::std140::Std140Padded< + Self, + { align_offset(core::mem::size_of::(), max(256, T::ALIGNMENT)) }, + >; + #[cfg(not(const_evaluatable_checked))] + type Padded = crate::std140::InvalidPadded; } unsafe impl Zeroable for DynamicUniformStd140 {} diff --git a/src/std140/primitives.rs b/src/std140/primitives.rs index c60496c..34e161e 100644 --- a/src/std140/primitives.rs +++ b/src/std140/primitives.rs @@ -1,22 +1,29 @@ use bytemuck::{Pod, Zeroable}; use crate::glsl::Glsl; -use crate::std140::Std140; +use crate::std140::{Std140, Std140Padded}; + +use crate::internal::{align_offset, max}; +use core::mem::size_of; unsafe impl Std140 for f32 { const ALIGNMENT: usize = 4; + type Padded = Std140Padded; } unsafe impl Std140 for f64 { const ALIGNMENT: usize = 8; + type Padded = Std140Padded; } unsafe impl Std140 for i32 { const ALIGNMENT: usize = 4; + type Padded = Std140Padded; } unsafe impl Std140 for u32 { const ALIGNMENT: usize = 4; + type Padded = Std140Padded; } macro_rules! vectors { @@ -39,6 +46,7 @@ macro_rules! vectors { unsafe impl Std140 for $name { const ALIGNMENT: usize = $align; + type Padded = Std140Padded(), max(16, $align))}>; } unsafe impl Glsl for $name { @@ -98,6 +106,7 @@ macro_rules! matrices { const ALIGNMENT: usize = $align; /// Matrices are technically arrays of primitives, and as such require pad at end. const PAD_AT_END: bool = true; + type Padded = Std140Padded(), max(16, $align))}>; } unsafe impl Glsl for $name { diff --git a/src/std140/traits.rs b/src/std140/traits.rs index 1f92955..cb02ace 100644 --- a/src/std140/traits.rs +++ b/src/std140/traits.rs @@ -1,4 +1,4 @@ -use core::mem::size_of; +use core::mem::{size_of, MaybeUninit}; #[cfg(feature = "std")] use std::io::{self, Write}; @@ -23,6 +23,10 @@ pub unsafe trait Std140: Copy + Zeroable + Pod { /// See /// (rule 4 and 9) const PAD_AT_END: bool = false; + /// Padded type (Std140Padded specialization) + /// The usual implementation is + /// type Padded = Std140Padded(), max(16, ALIGNMENT))}>; + type Padded: Std140Convertible; /// Casts the type to a byte array. Implementors should not override this /// method. @@ -35,9 +39,38 @@ pub unsafe trait Std140: Copy + Zeroable + Pod { } } +/// Trait specifically for Std140::Padded, implements conversions between padded type and base type. +pub trait Std140Convertible: Copy { + /// Convert from self to Std140 + fn into_std140(self) -> T; + /// Convert from Std140 to self + fn from_std140(_: T) -> Self; +} + +impl Std140Convertible for T { + fn into_std140(self) -> T { + self + } + fn from_std140(also_self: T) -> Self { + also_self + } +} + +/// Unfortunately, we cannot easily derive padded representation for generic Std140 types. +/// For now, we'll just use this empty enum with no values. +#[derive(Copy, Clone)] +pub enum InvalidPadded {} +impl Std140Convertible for InvalidPadded { + fn into_std140(self) -> T { + unimplemented!() + } + fn from_std140(_: T) -> Self { + unimplemented!() + } +} /** Trait implemented for all types that can be turned into `std140` values. - +* This trait can often be `#[derive]`'d instead of manually implementing it. Any struct which contains only fields that also implement `AsStd140` can derive `AsStd140`. @@ -109,6 +142,78 @@ where } } +#[doc(hidden)] +#[derive(Copy, Clone, Debug)] +pub struct Std140Padded { + inner: T, + _padding: [u8; PAD], +} + +unsafe impl Zeroable for Std140Padded {} +unsafe impl Pod for Std140Padded {} + +impl Std140Convertible for Std140Padded { + fn into_std140(self) -> T { + self.inner + } + + fn from_std140(inner: T) -> Self { + Self { + inner, + _padding: [0u8; PAD], + } + } +} + +#[doc(hidden)] +#[derive(Copy, Clone, Debug)] +#[repr(transparent)] +pub struct Std140Array([T::Padded; N]); + +unsafe impl Zeroable for Std140Array where T::Padded: Zeroable {} +unsafe impl Pod for Std140Array where T::Padded: Pod {} +unsafe impl Std140 for Std140Array +where + T::Padded: Pod, +{ + const ALIGNMENT: usize = crate::internal::max(T::ALIGNMENT, 16); + type Padded = Self; +} + +impl Std140Array { + fn uninit_array() -> [MaybeUninit; N] { + unsafe { MaybeUninit::uninit().assume_init() } + } + + fn from_uninit_array(a: [MaybeUninit; N]) -> Self { + unsafe { core::mem::transmute_copy(&a) } + } +} + +impl AsStd140 for [T; N] +where + ::Padded: Pod, +{ + type Output = Std140Array; + fn as_std140(&self) -> Self::Output { + let mut res = Self::Output::uninit_array(); + + for i in 0..N { + res[i] = MaybeUninit::new(Std140Convertible::from_std140(self[i].as_std140())); + } + + return Self::Output::from_uninit_array(res); + } + + fn from_std140(val: Self::Output) -> Self { + let mut res: [MaybeUninit; N] = unsafe{ MaybeUninit::uninit().assume_init() }; + for i in 0..N { + res[i] = MaybeUninit::new(T::from_std140(Std140Convertible::into_std140(val.0[i]))); + } + unsafe {core::mem::transmute_copy(&res) } + } +} + /// Trait implemented for all types that can be written into a buffer as /// `std140` bytes. This type is more general than [`AsStd140`]: all `AsStd140` /// types implement `WriteStd140`, but not the other way around. diff --git a/src/std430/primitives.rs b/src/std430/primitives.rs index 8b0281a..3348e82 100644 --- a/src/std430/primitives.rs +++ b/src/std430/primitives.rs @@ -1,22 +1,29 @@ use bytemuck::{Pod, Zeroable}; use crate::glsl::Glsl; -use crate::std430::Std430; +use crate::std430::{Std430, Std430Padded}; + +use crate::internal::align_offset; +use core::mem::size_of; unsafe impl Std430 for f32 { const ALIGNMENT: usize = 4; + type Padded = Self; } unsafe impl Std430 for f64 { const ALIGNMENT: usize = 8; + type Padded = Self; } unsafe impl Std430 for i32 { const ALIGNMENT: usize = 4; + type Padded = Self; } unsafe impl Std430 for u32 { const ALIGNMENT: usize = 4; + type Padded = Self; } macro_rules! vectors { @@ -39,6 +46,7 @@ macro_rules! vectors { unsafe impl Std430 for $name { const ALIGNMENT: usize = $align; + type Padded = Std430Padded(), $align)}>; } unsafe impl Glsl for $name { @@ -98,6 +106,7 @@ macro_rules! matrices { const ALIGNMENT: usize = $align; /// Matrices are technically arrays of primitives, and as such require pad at end. const PAD_AT_END: bool = true; + type Padded = Std430Padded(), $align)}>; } unsafe impl Glsl for $name { diff --git a/src/std430/traits.rs b/src/std430/traits.rs index 96523ba..3813339 100644 --- a/src/std430/traits.rs +++ b/src/std430/traits.rs @@ -1,4 +1,4 @@ -use core::mem::size_of; +use core::mem::{size_of, MaybeUninit}; #[cfg(feature = "std")] use std::io::{self, Write}; @@ -23,6 +23,10 @@ pub unsafe trait Std430: Copy + Zeroable + Pod { /// See /// (rule 4 and 9) const PAD_AT_END: bool = false; + /// Padded type (Std430Padded specialization) + /// The usual implementation is + /// type Padded = Std430Padded(), ALIGNMENT)}>; + type Padded: Std430Convertible; /// Casts the type to a byte array. Implementors should not override this /// method. @@ -35,6 +39,35 @@ pub unsafe trait Std430: Copy + Zeroable + Pod { } } +/// Trait specifically for Std430::Padded, implements conversions between padded type and base type. +pub trait Std430Convertible: Copy { + /// Convert from self to Std430 + fn into_std430(self) -> T; + /// Convert from Std430 to self + fn from_std430(_: T) -> Self; +} + +impl Std430Convertible for T { + fn into_std430(self) -> T { + self + } + fn from_std430(also_self: T) -> Self { + also_self + } +} + +/// Unfortunately, we cannot easily derive padded representation for generic Std140 types. +/// For now, we'll just use this empty enum with no values. +#[derive(Copy, Clone)] +pub enum InvalidPadded {} +impl Std430Convertible for InvalidPadded { + fn into_std430(self) -> T { + unimplemented!() + } + fn from_std430(_: T) -> Self { + unimplemented!() + } +} /** Trait implemented for all types that can be turned into `std430` values. @@ -109,6 +142,78 @@ where } } +#[doc(hidden)] +#[derive(Copy, Clone, Debug)] +pub struct Std430Padded { + inner: T, + _padding: [u8; PAD], +} + +unsafe impl Zeroable for Std430Padded {} +unsafe impl Pod for Std430Padded {} + +impl Std430Convertible for Std430Padded { + fn into_std430(self) -> T { + self.inner + } + + fn from_std430(inner: T) -> Self { + Self { + inner, + _padding: [0u8; PAD], + } + } +} + +#[doc(hidden)] +#[derive(Copy, Clone, Debug)] +#[repr(transparent)] +pub struct Std430Array([T::Padded; N]); + +unsafe impl Zeroable for Std430Array where T::Padded: Zeroable {} +unsafe impl Pod for Std430Array where T::Padded: Pod {} +unsafe impl Std430 for Std430Array +where + T::Padded: Pod, +{ + const ALIGNMENT: usize = T::ALIGNMENT; + type Padded = Self; +} + +impl Std430Array { + fn uninit_array() -> [MaybeUninit; N] { + unsafe { MaybeUninit::uninit().assume_init() } + } + + fn from_uninit_array(a: [MaybeUninit; N]) -> Self { + unsafe { core::mem::transmute_copy(&a) } + } +} + +impl AsStd430 for [T; N] +where + ::Padded: Pod, +{ + type Output = Std430Array; + fn as_std430(&self) -> Self::Output { + let mut res = Self::Output::uninit_array(); + + for i in 0..N { + res[i] = MaybeUninit::new(Std430Convertible::from_std430(self[i].as_std430())); + } + + return Self::Output::from_uninit_array(res); + } + + fn from_std430(val: Self::Output) -> Self { + let mut res: [MaybeUninit; N] = unsafe{ MaybeUninit::uninit().assume_init() }; + for i in 0..N { + res[i] = MaybeUninit::new(T::from_std430(val.0[i].into_std430())); + } + unsafe {core::mem::transmute_copy(&res) } + } +} + /// Trait implemented for all types that can be written into a buffer as /// `std430` bytes. This type is more general than [`AsStd430`]: all `AsStd430` /// types implement `WriteStd430`, but not the other way around. From 4e79e3a74f79f59022b1d1aef92cc3a8ca5f0523 Mon Sep 17 00:00:00 2001 From: Alex S Date: Thu, 27 May 2021 07:27:03 +0300 Subject: [PATCH 02/11] Rustfmt. --- crevice-tests/src/lib.rs | 4 ++-- src/std140/traits.rs | 4 ++-- src/std430/traits.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crevice-tests/src/lib.rs b/crevice-tests/src/lib.rs index d503545..a38a48d 100644 --- a/crevice-tests/src/lib.rs +++ b/crevice-tests/src/lib.rs @@ -328,7 +328,7 @@ fn proper_offset_calculations_for_differing_member_sizes() { fn array_strides_small_value() { #[derive(Debug, PartialEq, AsStd140, AsStd430)] struct ArrayOfSmallValues { - inner: [f32; 4] + inner: [f32; 4], } assert_std140!((size = 64, align = 16) ArrayOfSmallValues { @@ -344,7 +344,7 @@ fn array_strides_small_value() { fn array_strides_vec3() { #[derive(Debug, PartialEq, AsStd140, AsStd430)] struct ArrayOfSmallValues { - inner: [Vector3; 4] + inner: [Vector3; 4], } assert_std140!((size = 64, align = 16) ArrayOfSmallValues { diff --git a/src/std140/traits.rs b/src/std140/traits.rs index cb02ace..6165437 100644 --- a/src/std140/traits.rs +++ b/src/std140/traits.rs @@ -206,11 +206,11 @@ where } fn from_std140(val: Self::Output) -> Self { - let mut res: [MaybeUninit; N] = unsafe{ MaybeUninit::uninit().assume_init() }; + let mut res: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; for i in 0..N { res[i] = MaybeUninit::new(T::from_std140(Std140Convertible::into_std140(val.0[i]))); } - unsafe {core::mem::transmute_copy(&res) } + unsafe { core::mem::transmute_copy(&res) } } } diff --git a/src/std430/traits.rs b/src/std430/traits.rs index 3813339..8be54f7 100644 --- a/src/std430/traits.rs +++ b/src/std430/traits.rs @@ -206,11 +206,11 @@ where } fn from_std430(val: Self::Output) -> Self { - let mut res: [MaybeUninit; N] = unsafe{ MaybeUninit::uninit().assume_init() }; + let mut res: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; for i in 0..N { res[i] = MaybeUninit::new(T::from_std430(val.0[i].into_std430())); } - unsafe {core::mem::transmute_copy(&res) } + unsafe { core::mem::transmute_copy(&res) } } } From cdef9f8d3fdd377206aed2bde14f20e5472ef81c Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Nov 2021 10:17:22 +0300 Subject: [PATCH 03/11] Added GLSL generation support for arrays. --- crevice-derive/src/glsl.rs | 17 +++-- crevice-tests/src/lib.rs | 29 +++++++-- src/glsl.rs | 65 ++++++++++++++----- src/std140/traits.rs | 2 +- src/std430/traits.rs | 2 +- .../test__generate_struct_array_glsl.snap | 8 +++ tests/test.rs | 11 ++++ 7 files changed, 104 insertions(+), 30 deletions(-) create mode 100644 tests/snapshots/test__generate_struct_array_glsl.snap diff --git a/crevice-derive/src/glsl.rs b/crevice-derive/src/glsl.rs index e6b7a3c..fd74f0c 100644 --- a/crevice-derive/src/glsl.rs +++ b/crevice-derive/src/glsl.rs @@ -23,12 +23,15 @@ pub fn emit(input: DeriveInput) -> TokenStream { let glsl_fields = fields.named.iter().map(|field| { let field_ty = &field.ty; let field_name_str = Literal::string(&field.ident.as_ref().unwrap().to_string()); + let field_as = quote! {<#field_ty as ::crevice::glsl::GlslArray>}; quote! { - ::crevice::glsl::GlslField { - ty: <#field_ty as ::crevice::glsl::Glsl>::NAME, - name: #field_name_str, - } + s.push_str("\t"); + s.push_str(#field_as::NAME); + s.push_str(" "); + s.push_str(#field_name_str); + <#field_as::ArraySize as ::crevice::glsl::DimensionList>::push_to_string(s); + s.push_str(";\n"); } }); @@ -38,9 +41,9 @@ pub fn emit(input: DeriveInput) -> TokenStream { } unsafe impl #impl_generics #struct_trait_path for #name #ty_generics #where_clause { - const FIELDS: &'static [::crevice::glsl::GlslField] = &[ - #( #glsl_fields, )* - ]; + fn enumerate_fields(s: &mut String) { + #( #glsl_fields )* + } } } } diff --git a/crevice-tests/src/lib.rs b/crevice-tests/src/lib.rs index a38a48d..7c4b793 100644 --- a/crevice-tests/src/lib.rs +++ b/crevice-tests/src/lib.rs @@ -342,16 +342,37 @@ fn array_strides_small_value() { #[test] fn array_strides_vec3() { - #[derive(Debug, PartialEq, AsStd140, AsStd430)] - struct ArrayOfSmallValues { + #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] + struct ArrayOfVector3 { inner: [Vector3; 4], } - assert_std140!((size = 64, align = 16) ArrayOfSmallValues { + assert_std140!((size = 64, align = 16) ArrayOfVector3 { inner: 0, }); - assert_std430!((size = 64, align = 16) ArrayOfSmallValues { + assert_std430!((size = 64, align = 16) ArrayOfVector3 { inner: 0, }); + + test_round_trip_struct(ArrayOfVector3 { + inner: [[0.0, 1.0, 2.0].into(); 4], + }) +} + +#[test] +fn complex_array_glsl() { + #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] + struct Wrap { + inner: [[f32; 4]; 4], + } + + test_round_trip_struct(Wrap { + inner: [ + [0.0, 1.0, 2.0, 3.0], + [1.0, 2.0, 3.0, 0.0], + [2.0, 3.0, 0.0, 1.0], + [3.0, 0.0, 1.0, 2.0], + ], + }) } diff --git a/src/glsl.rs b/src/glsl.rs index 9305a77..3f879b6 100644 --- a/src/glsl.rs +++ b/src/glsl.rs @@ -1,6 +1,33 @@ //! Defines traits and types for generating GLSL code from Rust definitions. pub use crevice_derive::GlslStruct; +use std::marker::PhantomData; + +/// Type-level linked list of array dimensions +pub struct Dimension { + _marker: PhantomData, +} + +/// Type-level linked list terminator for array dimensions. +pub struct DimensionNil; + +/// Trait for type-level array dimensions. Probably shouldn't be implemented outside this crate. +pub unsafe trait DimensionList { + /// Write dimensions in square brackets to a string, list tail to list head. + fn push_to_string(s: &mut String); +} + +unsafe impl DimensionList for DimensionNil { + fn push_to_string(_: &mut String) {} +} + +unsafe impl DimensionList for Dimension { + fn push_to_string(s: &mut String) { + use std::fmt::Write; + A::push_to_string(s); + write!(s, "[{}]", N).unwrap(); + } +} /// Trait for types that have a GLSL equivalent. Useful for generating GLSL code /// from Rust structs. @@ -9,21 +36,12 @@ pub unsafe trait Glsl { const NAME: &'static str; } -/// A field contained within a GLSL struct definition. -pub struct GlslField { - /// The type of the field, like `vec2` or `mat3`. - pub ty: &'static str, - - /// The field's name. This must be a valid GLSL identifier. - pub name: &'static str, -} - /// Trait for types that can be represented as a struct in GLSL. /// /// This trait should not generally be implemented by hand, but can be derived. pub unsafe trait GlslStruct: Glsl { /// The fields contained in this struct. - const FIELDS: &'static [GlslField]; + fn enumerate_fields(s: &mut String); /// Generates GLSL code that represents this struct and its fields. fn glsl_definition() -> String { @@ -32,19 +50,26 @@ pub unsafe trait GlslStruct: Glsl { output.push_str(Self::NAME); output.push_str(" {\n"); - for field in Self::FIELDS { - output.push('\t'); - output.push_str(field.ty); - output.push(' '); - output.push_str(field.name); - output.push_str(";\n"); - } + Self::enumerate_fields(&mut output); output.push_str("};"); output } } +/// Trait for types that are expressible as a GLSL type with (possibly zero) array dimensions. +pub unsafe trait GlslArray { + /// Base type name. + const NAME: &'static str; + /// Type-level linked list of array dimensions, ordered outer to inner. + type ArraySize: DimensionList; +} + +unsafe impl GlslArray for T { + const NAME: &'static str = ::NAME; + type ArraySize = DimensionNil; +} + unsafe impl Glsl for f32 { const NAME: &'static str = "float"; } @@ -60,3 +85,9 @@ unsafe impl Glsl for i32 { unsafe impl Glsl for u32 { const NAME: &'static str = "uint"; } + +unsafe impl GlslArray for [T; N] { + const NAME: &'static str = T::NAME; + + type ArraySize = Dimension; +} diff --git a/src/std140/traits.rs b/src/std140/traits.rs index 6165437..caa8fce 100644 --- a/src/std140/traits.rs +++ b/src/std140/traits.rs @@ -202,7 +202,7 @@ where res[i] = MaybeUninit::new(Std140Convertible::from_std140(self[i].as_std140())); } - return Self::Output::from_uninit_array(res); + Self::Output::from_uninit_array(res) } fn from_std140(val: Self::Output) -> Self { diff --git a/src/std430/traits.rs b/src/std430/traits.rs index 8be54f7..6206ec7 100644 --- a/src/std430/traits.rs +++ b/src/std430/traits.rs @@ -202,7 +202,7 @@ where res[i] = MaybeUninit::new(Std430Convertible::from_std430(self[i].as_std430())); } - return Self::Output::from_uninit_array(res); + Self::Output::from_uninit_array(res) } fn from_std430(val: Self::Output) -> Self { diff --git a/tests/snapshots/test__generate_struct_array_glsl.snap b/tests/snapshots/test__generate_struct_array_glsl.snap new file mode 100644 index 0000000..7829bd6 --- /dev/null +++ b/tests/snapshots/test__generate_struct_array_glsl.snap @@ -0,0 +1,8 @@ +--- +source: tests/test.rs +expression: "TestGlsl::glsl_definition()" + +--- +struct TestGlsl { + vec3 foo[8][4]; +}; diff --git a/tests/test.rs b/tests/test.rs index 669557d..f07786c 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -48,3 +48,14 @@ fn generate_struct_glsl() { insta::assert_display_snapshot!(TestGlsl::glsl_definition()); } + +#[test] +fn generate_struct_array_glsl() { + #[allow(dead_code)] + #[derive(GlslStruct)] + struct TestGlsl { + foo: [[mint::Vector3; 8]; 4], + } + + insta::assert_display_snapshot!(TestGlsl::glsl_definition()); +} From 9b1807b1b462e9f26d7fae9f75df9662822ddc09 Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Nov 2021 10:43:20 +0300 Subject: [PATCH 04/11] Adjust tests. Complex arrays are not supported by standard GLSL, and vec3 strides test is failing. --- crevice-tests/src/lib.rs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/crevice-tests/src/lib.rs b/crevice-tests/src/lib.rs index 7c4b793..a5646bd 100644 --- a/crevice-tests/src/lib.rs +++ b/crevice-tests/src/lib.rs @@ -356,23 +356,12 @@ fn array_strides_vec3() { }); test_round_trip_struct(ArrayOfVector3 { - inner: [[0.0, 1.0, 2.0].into(); 4], - }) -} - -#[test] -fn complex_array_glsl() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct Wrap { - inner: [[f32; 4]; 4], - } - - test_round_trip_struct(Wrap { inner: [ - [0.0, 1.0, 2.0, 3.0], - [1.0, 2.0, 3.0, 0.0], - [2.0, 3.0, 0.0, 1.0], - [3.0, 0.0, 1.0, 2.0], + [0.0, 1.0, 2.0].into(), + [3.0, 4.0, 5.0].into(), + [6.0, 7.0, 8.0].into(), + [9.0, 10.0, 11.0].into(), ], }) } + From 15c8c558bb8f03d031c5e010ae6acfe40a03f64b Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 1 Nov 2021 11:04:55 +0300 Subject: [PATCH 05/11] Rustfmt --- crevice-tests/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crevice-tests/src/lib.rs b/crevice-tests/src/lib.rs index a5646bd..da61b47 100644 --- a/crevice-tests/src/lib.rs +++ b/crevice-tests/src/lib.rs @@ -364,4 +364,3 @@ fn array_strides_vec3() { ], }) } - From 4f5942ab0c89f29576577cb4094679de810d5056 Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 2 Nov 2021 15:18:42 +0300 Subject: [PATCH 06/11] remote debugging, oh joy --- crevice-tests/src/gpu.rs | 4 +++- crevice-tests/src/lib.rs | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/crevice-tests/src/gpu.rs b/crevice-tests/src/gpu.rs index 517e8d7..cf5f4a1 100644 --- a/crevice-tests/src/gpu.rs +++ b/crevice-tests/src/gpu.rs @@ -100,9 +100,11 @@ where "std140 value did not round-trip through wgpu successfully.\n\ Input: {:?}\n\ Output: {:?}\n\n\ + Data: {:?}\n\ + Bytes: {:?}\n\n\ GLSL shader:\n{}\n\n\ WGSL shader:\n{}", - value, output, glsl_shader, wgsl_shader, + value, output, data, bytes, glsl_shader, wgsl_shader, ); panic!("wgpu round-trip failure for {}", T::NAME); diff --git a/crevice-tests/src/lib.rs b/crevice-tests/src/lib.rs index da61b47..706122f 100644 --- a/crevice-tests/src/lib.rs +++ b/crevice-tests/src/lib.rs @@ -344,23 +344,25 @@ fn array_strides_small_value() { fn array_strides_vec3() { #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] struct ArrayOfVector3 { - inner: [Vector3; 4], + inner: [Vector3; 6], } - assert_std140!((size = 64, align = 16) ArrayOfVector3 { + assert_std140!((size = 96, align = 16) ArrayOfVector3 { inner: 0, }); - assert_std430!((size = 64, align = 16) ArrayOfVector3 { + assert_std430!((size = 96, align = 16) ArrayOfVector3 { inner: 0, }); test_round_trip_struct(ArrayOfVector3 { inner: [ - [0.0, 1.0, 2.0].into(), - [3.0, 4.0, 5.0].into(), - [6.0, 7.0, 8.0].into(), - [9.0, 10.0, 11.0].into(), + [0x00010203, 0x04050607, 0x08091011].into(), + [0x12131415, 0x16171819, 0x20212223].into(), + [0x24252627, 0x28293031, 0x32333435].into(), + [0x36373839, 0x40414243, 0x44454647].into(), + [0x48495051, 0x52535455, 0x56575859].into(), + [0x60616263, 0x64656667, 0x68697071].into(), ], }) } From 7c1508d720eb6f3f2fde79840f176aa78db16785 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 10 Nov 2021 14:27:24 +0300 Subject: [PATCH 07/11] Code review. --- src/std140/primitives.rs | 4 ++-- src/std140/traits.rs | 34 +++++++++++----------------------- src/std430/primitives.rs | 6 +++--- src/std430/traits.rs | 34 +++++++++++----------------------- 4 files changed, 27 insertions(+), 51 deletions(-) diff --git a/src/std140/primitives.rs b/src/std140/primitives.rs index 34e161e..92ce4cf 100644 --- a/src/std140/primitives.rs +++ b/src/std140/primitives.rs @@ -1,10 +1,10 @@ +use core::mem::size_of; + use bytemuck::{Pod, Zeroable}; use crate::glsl::Glsl; use crate::std140::{Std140, Std140Padded}; - use crate::internal::{align_offset, max}; -use core::mem::size_of; unsafe impl Std140 for f32 { const ALIGNMENT: usize = 4; diff --git a/src/std140/traits.rs b/src/std140/traits.rs index caa8fce..e50984e 100644 --- a/src/std140/traits.rs +++ b/src/std140/traits.rs @@ -40,7 +40,7 @@ pub unsafe trait Std140: Copy + Zeroable + Pod { } /// Trait specifically for Std140::Padded, implements conversions between padded type and base type. -pub trait Std140Convertible: Copy { +pub trait Std140Convertible: Copy + Pod { /// Convert from self to Std140 fn into_std140(self) -> T; /// Convert from Std140 to self @@ -60,6 +60,8 @@ impl Std140Convertible for T { /// For now, we'll just use this empty enum with no values. #[derive(Copy, Clone)] pub enum InvalidPadded {} +unsafe impl Zeroable for InvalidPadded {} +unsafe impl Pod for InvalidPadded {} impl Std140Convertible for InvalidPadded { fn into_std140(self) -> T { unimplemented!() @@ -180,37 +182,23 @@ where type Padded = Self; } -impl Std140Array { - fn uninit_array() -> [MaybeUninit; N] { - unsafe { MaybeUninit::uninit().assume_init() } - } - - fn from_uninit_array(a: [MaybeUninit; N]) -> Self { - unsafe { core::mem::transmute_copy(&a) } - } -} - -impl AsStd140 for [T; N] -where - ::Padded: Pod, -{ +impl AsStd140 for [T; N] { type Output = Std140Array; fn as_std140(&self) -> Self::Output { - let mut res = Self::Output::uninit_array(); + let mut res: [MaybeUninit<_>; N] = unsafe { MaybeUninit::uninit().assume_init() }; for i in 0..N { - res[i] = MaybeUninit::new(Std140Convertible::from_std140(self[i].as_std140())); + res[i] = MaybeUninit::new(::Padded::from_std140( + self[i].as_std140(), + )); } - Self::Output::from_uninit_array(res) + unsafe { core::mem::transmute_copy(&res) } } fn from_std140(val: Self::Output) -> Self { - let mut res: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; - for i in 0..N { - res[i] = MaybeUninit::new(T::from_std140(Std140Convertible::into_std140(val.0[i]))); - } - unsafe { core::mem::transmute_copy(&res) } + val.0 + .map(|x| T::from_std140(Std140Convertible::into_std140(x))) } } diff --git a/src/std430/primitives.rs b/src/std430/primitives.rs index 3348e82..cff4cdd 100644 --- a/src/std430/primitives.rs +++ b/src/std430/primitives.rs @@ -1,11 +1,11 @@ +use crate::internal::align_offset; +use core::mem::size_of; + use bytemuck::{Pod, Zeroable}; use crate::glsl::Glsl; use crate::std430::{Std430, Std430Padded}; -use crate::internal::align_offset; -use core::mem::size_of; - unsafe impl Std430 for f32 { const ALIGNMENT: usize = 4; type Padded = Self; diff --git a/src/std430/traits.rs b/src/std430/traits.rs index 6206ec7..ec95f70 100644 --- a/src/std430/traits.rs +++ b/src/std430/traits.rs @@ -40,7 +40,7 @@ pub unsafe trait Std430: Copy + Zeroable + Pod { } /// Trait specifically for Std430::Padded, implements conversions between padded type and base type. -pub trait Std430Convertible: Copy { +pub trait Std430Convertible: Copy + Pod { /// Convert from self to Std430 fn into_std430(self) -> T; /// Convert from Std430 to self @@ -60,6 +60,8 @@ impl Std430Convertible for T { /// For now, we'll just use this empty enum with no values. #[derive(Copy, Clone)] pub enum InvalidPadded {} +unsafe impl Zeroable for InvalidPadded {} +unsafe impl Pod for InvalidPadded {} impl Std430Convertible for InvalidPadded { fn into_std430(self) -> T { unimplemented!() @@ -180,37 +182,23 @@ where type Padded = Self; } -impl Std430Array { - fn uninit_array() -> [MaybeUninit; N] { - unsafe { MaybeUninit::uninit().assume_init() } - } - - fn from_uninit_array(a: [MaybeUninit; N]) -> Self { - unsafe { core::mem::transmute_copy(&a) } - } -} - -impl AsStd430 for [T; N] -where - ::Padded: Pod, -{ +impl AsStd430 for [T; N] { type Output = Std430Array; fn as_std430(&self) -> Self::Output { - let mut res = Self::Output::uninit_array(); + let mut res: [MaybeUninit<_>; N] = unsafe { MaybeUninit::uninit().assume_init() }; for i in 0..N { - res[i] = MaybeUninit::new(Std430Convertible::from_std430(self[i].as_std430())); + res[i] = MaybeUninit::new(::Padded::from_std430( + self[i].as_std430(), + )); } - Self::Output::from_uninit_array(res) + unsafe { core::mem::transmute_copy(&res) } } fn from_std430(val: Self::Output) -> Self { - let mut res: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; - for i in 0..N { - res[i] = MaybeUninit::new(T::from_std430(val.0[i].into_std430())); - } - unsafe { core::mem::transmute_copy(&res) } + val.0 + .map(|x| T::from_std430(Std430Convertible::into_std430(x))) } } From ca582a9ffe1e73eea16c6dd1a153857e610b96bd Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 26 Nov 2021 12:48:53 +0300 Subject: [PATCH 08/11] Remove PAD_AT_END because we always pad structures at the end now. --- crevice-derive/src/layout.rs | 32 +++----------------------------- src/std140/primitives.rs | 2 -- src/std140/traits.rs | 6 ------ src/std430/primitives.rs | 2 -- src/std430/traits.rs | 6 ------ 5 files changed, 3 insertions(+), 45 deletions(-) diff --git a/crevice-derive/src/layout.rs b/crevice-derive/src/layout.rs index a0d26fd..ef13915 100644 --- a/crevice-derive/src/layout.rs +++ b/crevice-derive/src/layout.rs @@ -50,14 +50,6 @@ pub fn emit( } }; - // Gives an expression telling whether the type should have trailing padding - // at least equal to its alignment. - let layout_pad_at_end_of_ty = |ty: &Type| { - quote! { - <<#ty as #as_trait_path>::Output as #trait_path>::PAD_AT_END - } - }; - let field_alignments = fields.iter().map(|field| layout_alignment_of_ty(&field.ty)); let struct_alignment = quote! { ::crevice::internal::max_arr([ @@ -100,15 +92,9 @@ pub fn emit( output.into_iter().collect::() }; - let pad_fn_impls: TokenStream = fields - .iter() - .enumerate() - .map(|(index, prev_field)| { - let pad_fn = &pad_fns[index]; - + let pad_fn_impls: TokenStream = pad_fns.iter().enumerate().map( + |(index, pad_fn)| { let starting_offset = offset_after_field(index); - let prev_field_has_end_padding = layout_pad_at_end_of_ty(&prev_field.ty); - let prev_field_alignment = layout_alignment_of_ty(&prev_field.ty); let next_field_or_self_alignment = fields .get(index + 1) @@ -125,21 +111,10 @@ pub fn emit( // alignment we are. let starting_offset = #starting_offset; - // If the previous field is a struct or array, we must align - // the next field to at least THAT field's alignment. - let min_alignment = if #prev_field_has_end_padding { - #prev_field_alignment - } else { - 0 - }; - // We set our target alignment to the larger of the // alignment due to the previous field and the alignment // requirement of the next field. - let alignment = ::crevice::internal::max( - #next_field_or_self_alignment, - min_alignment, - ); + let alignment = #next_field_or_self_alignment; // Using everything we've got, compute our padding amount. ::crevice::internal::align_offset(starting_offset, alignment) @@ -255,7 +230,6 @@ pub fn emit( unsafe impl #impl_generics #mod_path::#trait_name for #generated_name #ty_generics #where_clause { const ALIGNMENT: usize = #struct_alignment; - const PAD_AT_END: bool = true; } impl #impl_generics #as_trait_path for #input_name #ty_generics #where_clause { diff --git a/src/std140/primitives.rs b/src/std140/primitives.rs index c823389..8003e64 100644 --- a/src/std140/primitives.rs +++ b/src/std140/primitives.rs @@ -111,8 +111,6 @@ macro_rules! matrices { unsafe impl Std140 for $name { const ALIGNMENT: usize = $align; - /// Matrices are technically arrays of primitives, and as such require pad at end. - const PAD_AT_END: bool = true; } unsafe impl Glsl for $name { diff --git a/src/std140/traits.rs b/src/std140/traits.rs index 1f92955..17bb74a 100644 --- a/src/std140/traits.rs +++ b/src/std140/traits.rs @@ -18,12 +18,6 @@ pub unsafe trait Std140: Copy + Zeroable + Pod { /// slices safe. const ALIGNMENT: usize; - /// Whether this type requires a padding at the end (ie, is a struct or an array - /// of primitives). - /// See - /// (rule 4 and 9) - const PAD_AT_END: bool = false; - /// Casts the type to a byte array. Implementors should not override this /// method. /// diff --git a/src/std430/primitives.rs b/src/std430/primitives.rs index 1f5ea97..d1533ea 100644 --- a/src/std430/primitives.rs +++ b/src/std430/primitives.rs @@ -111,8 +111,6 @@ macro_rules! matrices { unsafe impl Std430 for $name { const ALIGNMENT: usize = $align; - /// Matrices are technically arrays of primitives, and as such require pad at end. - const PAD_AT_END: bool = true; } unsafe impl Glsl for $name { diff --git a/src/std430/traits.rs b/src/std430/traits.rs index 96523ba..fee8c07 100644 --- a/src/std430/traits.rs +++ b/src/std430/traits.rs @@ -18,12 +18,6 @@ pub unsafe trait Std430: Copy + Zeroable + Pod { /// slices safe. const ALIGNMENT: usize; - /// Whether this type requires a padding at the end (ie, is a struct or an array - /// of primitives). - /// See - /// (rule 4 and 9) - const PAD_AT_END: bool = false; - /// Casts the type to a byte array. Implementors should not override this /// method. /// From a18942606ef724c534acb632c36c4d5fdd2f3243 Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 26 Nov 2021 14:50:18 +0300 Subject: [PATCH 09/11] Separated arrays into a distinct feature. --- Cargo.toml | 1 + crevice-derive/Cargo.toml | 3 ++ crevice-derive/src/layout.rs | 22 +++++--- crevice-tests/Cargo.toml | 1 + crevice-tests/src/lib.rs | 24 +++++++++ src/lib.rs | 4 +- src/std140.rs | 4 ++ src/std140/arrays.rs | 78 ++++++++++++++++++++++++++++ src/std140/dynamic_uniform.rs | 7 --- src/std140/primitives.rs | 19 ++++--- src/std140/traits.rs | 96 +---------------------------------- src/std430.rs | 4 ++ src/std430/arrays.rs | 78 ++++++++++++++++++++++++++++ src/std430/primitives.rs | 19 ++++--- src/std430/traits.rs | 96 +---------------------------------- 15 files changed, 235 insertions(+), 221 deletions(-) create mode 100644 src/std140/arrays.rs create mode 100644 src/std430/arrays.rs diff --git a/Cargo.toml b/Cargo.toml index ffc580f..a9181df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ resolver = "2" [features] default = ["std"] std = [] +arrays = ["crevice-derive/arrays"] [workspace] members = ["crevice-derive", "crevice-tests"] diff --git a/crevice-derive/Cargo.toml b/crevice-derive/Cargo.toml index 1d64fbb..e78bef9 100644 --- a/crevice-derive/Cargo.toml +++ b/crevice-derive/Cargo.toml @@ -15,6 +15,9 @@ default = [] # Enable methods that let you introspect into the generated structs. debug-methods = [] +# Enable arrays support +arrays = [] + [lib] proc-macro = true diff --git a/crevice-derive/src/layout.rs b/crevice-derive/src/layout.rs index a1104ec..00d717e 100644 --- a/crevice-derive/src/layout.rs +++ b/crevice-derive/src/layout.rs @@ -19,8 +19,8 @@ pub fn emit( let as_trait_method = format_ident!("as_{}", mod_name); let from_trait_method = format_ident!("from_{}", mod_name); - let padded_name = format_ident!("{}Padded", trait_name); - let padded_path: Path = parse_quote!(#mod_path::#padded_name); + let array_name = format_ident!("{}ArrayItem", trait_name); + let array_path: Path = parse_quote!(#mod_path::#array_name); let visibility = input.vis; let input_name = input.ident; @@ -224,6 +224,16 @@ pub fn emit( quote!() }; + let array_item_impl = if cfg!(feature = "arrays") { + quote! { + unsafe impl #impl_generics #array_path for #generated_name #ty_generics #where_clause { + type Padding = [u8; 0]; + } + } + } else { + quote!() + }; + quote! { #pad_fn_impls #struct_definition @@ -231,14 +241,12 @@ pub fn emit( unsafe impl #impl_generics ::crevice::internal::bytemuck::Zeroable for #generated_name #ty_generics #where_clause {} unsafe impl #impl_generics ::crevice::internal::bytemuck::Pod for #generated_name #ty_generics #where_clause {} - unsafe impl #impl_generics #mod_path::#trait_name for #generated_name #ty_generics #where_clause { + unsafe impl #impl_generics #trait_path for #generated_name #ty_generics #where_clause { const ALIGNMENT: usize = #struct_alignment; - type Padded = #padded_path(), - #struct_alignment - )}>; } + #array_item_impl + impl #impl_generics #as_trait_path for #input_name #ty_generics #where_clause { type Output = #generated_name; diff --git a/crevice-tests/Cargo.toml b/crevice-tests/Cargo.toml index a6f8605..000ed61 100644 --- a/crevice-tests/Cargo.toml +++ b/crevice-tests/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" [features] wgpu-validation = ["wgpu", "naga", "futures"] +arrays = ["crevice/arrays"] [dependencies] crevice = { path = ".." } diff --git a/crevice-tests/src/lib.rs b/crevice-tests/src/lib.rs index a83c25a..00e80df 100644 --- a/crevice-tests/src/lib.rs +++ b/crevice-tests/src/lib.rs @@ -344,6 +344,7 @@ fn bools_and_bool_vectors() { } #[test] +#[cfg(feature = "arrays")] fn array_strides_small_value() { #[derive(Debug, PartialEq, AsStd140, AsStd430)] struct ArrayOfSmallValues { @@ -360,6 +361,7 @@ fn array_strides_small_value() { } #[test] +#[cfg(feature = "arrays")] fn array_strides_vec3() { #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] struct ArrayOfVector3 { @@ -385,3 +387,25 @@ fn array_strides_vec3() { ], }) } + +#[test] +#[cfg(feature = "arrays")] +fn array_of_custom_struct_works() { + #[derive(Debug, PartialEq, AsStd140, AsStd430)] + struct SomeStruct { + x: f32, + } + + #[derive(Debug, PartialEq, AsStd140, AsStd430)] + struct ArrayOfStructs { + inner: [SomeStruct; 4], + } + + assert_std140!((size = 64, align = 16) ArrayOfStructs { + inner: 0, + }); + + assert_std430!((size = 16, align = 4) ArrayOfStructs { + inner: 0, + }); +} diff --git a/src/lib.rs b/src/lib.rs index d873117..c0dc23b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -150,7 +150,9 @@ Crevice supports Rust 1.52.1 and newer due to use of new `const fn` features. [glsl-layout]: https://github.com/rustgd/glsl-layout */ -#![deny(missing_docs)] +#![cfg_attr(feature = "arrays", feature(generic_const_exprs))] + +//#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] #[macro_use] diff --git a/src/std140.rs b/src/std140.rs index a48d2d4..2eb2963 100644 --- a/src/std140.rs +++ b/src/std140.rs @@ -7,6 +7,8 @@ mod sizer; mod traits; #[cfg(feature = "std")] mod writer; +#[cfg(feature = "arrays")] +mod arrays; pub use crate::bool::Bool; @@ -16,5 +18,7 @@ pub use self::sizer::*; pub use self::traits::*; #[cfg(feature = "std")] pub use self::writer::*; +#[cfg(feature = "arrays")] +pub use self::arrays::Std140ArrayItem; pub use crevice_derive::AsStd140; diff --git a/src/std140/arrays.rs b/src/std140/arrays.rs new file mode 100644 index 0000000..fe85524 --- /dev/null +++ b/src/std140/arrays.rs @@ -0,0 +1,78 @@ +use core::mem::{transmute_copy, MaybeUninit}; +use core::fmt::Debug; + +use bytemuck::{Zeroable, Pod}; + +use super::{Std140, AsStd140}; + +pub unsafe trait Std140ArrayItem: Std140 { + type Padding: Zeroable + Copy + Debug; +} + +type Padded = (T, ::Padding); + +fn wrap(x: &T) -> Padded +where T::Output: Std140ArrayItem +{ + (x.as_std140(), Zeroable::zeroed()) +} + +fn unwrap(x: Padded) -> T + where T::Output: Std140ArrayItem +{ + T::from_std140(x.0) +} + +#[doc(hidden)] +#[derive(Copy, Clone, Debug)] +#[repr(transparent)] +pub struct Std140Array([Padded; N]); + +unsafe impl Zeroable for Std140Array +{} +unsafe impl Pod for Std140Array +{} +unsafe impl Std140 for Std140Array +{ + const ALIGNMENT: usize = crate::internal::max(16, T::ALIGNMENT); +} + +impl AsStd140 for [T; N] + where T::Output: Std140ArrayItem +{ + type Output = Std140Array; + fn as_std140(&self) -> Self::Output { + let mut res: [MaybeUninit<_>; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + for i in 0..N { + res[i] = MaybeUninit::new(wrap(&self[i])); + } + + unsafe { transmute_copy(&res) } + } + + fn from_std140(val: Self::Output) -> Self { + val.0 + .map(|x| unwrap(x)) + } +} + +unsafe impl Std140ArrayItem for f32 { + type Padding = [u8; 12]; +} + +unsafe impl Std140ArrayItem for f64 { + type Padding = [u8; 8]; +} + +unsafe impl Std140ArrayItem for i32 { + type Padding = [u8; 12]; +} + +unsafe impl Std140ArrayItem for u32 { + type Padding = [u8; 12]; +} + +unsafe impl Std140ArrayItem for crate::bool::Bool { + type Padding = [u8; 12]; +} diff --git a/src/std140/dynamic_uniform.rs b/src/std140/dynamic_uniform.rs index 262f8ea..9eaa4fa 100644 --- a/src/std140/dynamic_uniform.rs +++ b/src/std140/dynamic_uniform.rs @@ -29,13 +29,6 @@ pub struct DynamicUniformStd140(T); unsafe impl Std140 for DynamicUniformStd140 { const ALIGNMENT: usize = max(256, T::ALIGNMENT); - #[cfg(const_evaluatable_checked)] - type Padded = crate::std140::Std140Padded< - Self, - { align_offset(core::mem::size_of::(), max(256, T::ALIGNMENT)) }, - >; - #[cfg(not(const_evaluatable_checked))] - type Padded = crate::std140::InvalidPadded; } unsafe impl Zeroable for DynamicUniformStd140 {} diff --git a/src/std140/primitives.rs b/src/std140/primitives.rs index 7a8e6ce..78f091b 100644 --- a/src/std140/primitives.rs +++ b/src/std140/primitives.rs @@ -4,32 +4,27 @@ use bytemuck::{Pod, Zeroable}; use crate::bool::Bool; use crate::glsl::Glsl; -use crate::std140::{AsStd140, Std140, Std140Padded}; +use crate::std140::{AsStd140, Std140}; use crate::internal::{align_offset, max}; unsafe impl Std140 for f32 { const ALIGNMENT: usize = 4; - type Padded = Std140Padded; } unsafe impl Std140 for f64 { const ALIGNMENT: usize = 8; - type Padded = Std140Padded; } unsafe impl Std140 for i32 { const ALIGNMENT: usize = 4; - type Padded = Std140Padded; } unsafe impl Std140 for u32 { const ALIGNMENT: usize = 4; - type Padded = Std140Padded; } unsafe impl Std140 for Bool { const ALIGNMENT: usize = 4; - type Padded = Std140Padded; } impl AsStd140 for bool { @@ -64,7 +59,11 @@ macro_rules! vectors { unsafe impl Std140 for $name { const ALIGNMENT: usize = $align; - type Padded = Std140Padded(), max(16, $align))}>; + } + + #[cfg(feature = "arrays")] + unsafe impl super::Std140ArrayItem for $name { + type Padding = [u8; align_offset(size_of::<$name>(), max(16, $align))]; } unsafe impl Glsl for $name { @@ -120,7 +119,11 @@ macro_rules! matrices { unsafe impl Std140 for $name { const ALIGNMENT: usize = $align; - type Padded = Std140Padded(), max(16, $align))}>; + } + + #[cfg(feature = "arrays")] + unsafe impl super::Std140ArrayItem for $name { + type Padding = [u8; 0]; } unsafe impl Glsl for $name { diff --git a/src/std140/traits.rs b/src/std140/traits.rs index 3d0a240..17bb74a 100644 --- a/src/std140/traits.rs +++ b/src/std140/traits.rs @@ -1,4 +1,4 @@ -use core::mem::{size_of, MaybeUninit}; +use core::mem::size_of; #[cfg(feature = "std")] use std::io::{self, Write}; @@ -18,11 +18,6 @@ pub unsafe trait Std140: Copy + Zeroable + Pod { /// slices safe. const ALIGNMENT: usize; - /// Padded type (Std140Padded specialization) - /// The usual implementation is - /// type Padded = Std140Padded(), max(16, ALIGNMENT))}>; - type Padded: Std140Convertible; - /// Casts the type to a byte array. Implementors should not override this /// method. /// @@ -34,37 +29,6 @@ pub unsafe trait Std140: Copy + Zeroable + Pod { } } -/// Trait specifically for Std140::Padded, implements conversions between padded type and base type. -pub trait Std140Convertible: Copy + Pod { - /// Convert from self to Std140 - fn into_std140(self) -> T; - /// Convert from Std140 to self - fn from_std140(_: T) -> Self; -} - -impl Std140Convertible for T { - fn into_std140(self) -> T { - self - } - fn from_std140(also_self: T) -> Self { - also_self - } -} - -/// Unfortunately, we cannot easily derive padded representation for generic Std140 types. -/// For now, we'll just use this empty enum with no values. -#[derive(Copy, Clone)] -pub enum InvalidPadded {} -unsafe impl Zeroable for InvalidPadded {} -unsafe impl Pod for InvalidPadded {} -impl Std140Convertible for InvalidPadded { - fn into_std140(self) -> T { - unimplemented!() - } - fn from_std140(_: T) -> Self { - unimplemented!() - } -} /** Trait implemented for all types that can be turned into `std140` values. @@ -139,64 +103,6 @@ where } } -#[doc(hidden)] -#[derive(Copy, Clone, Debug)] -pub struct Std140Padded { - inner: T, - _padding: [u8; PAD], -} - -unsafe impl Zeroable for Std140Padded {} -unsafe impl Pod for Std140Padded {} - -impl Std140Convertible for Std140Padded { - fn into_std140(self) -> T { - self.inner - } - - fn from_std140(inner: T) -> Self { - Self { - inner, - _padding: [0u8; PAD], - } - } -} - -#[doc(hidden)] -#[derive(Copy, Clone, Debug)] -#[repr(transparent)] -pub struct Std140Array([T::Padded; N]); - -unsafe impl Zeroable for Std140Array where T::Padded: Zeroable {} -unsafe impl Pod for Std140Array where T::Padded: Pod {} -unsafe impl Std140 for Std140Array -where - T::Padded: Pod, -{ - const ALIGNMENT: usize = crate::internal::max(T::ALIGNMENT, 16); - type Padded = Self; -} - -impl AsStd140 for [T; N] { - type Output = Std140Array; - fn as_std140(&self) -> Self::Output { - let mut res: [MaybeUninit<_>; N] = unsafe { MaybeUninit::uninit().assume_init() }; - - for i in 0..N { - res[i] = MaybeUninit::new(::Padded::from_std140( - self[i].as_std140(), - )); - } - - unsafe { core::mem::transmute_copy(&res) } - } - - fn from_std140(val: Self::Output) -> Self { - val.0 - .map(|x| T::from_std140(Std140Convertible::into_std140(x))) - } -} - /// Trait implemented for all types that can be written into a buffer as /// `std140` bytes. This type is more general than [`AsStd140`]: all `AsStd140` /// types implement `WriteStd140`, but not the other way around. diff --git a/src/std430.rs b/src/std430.rs index 74500cf..cab447c 100644 --- a/src/std430.rs +++ b/src/std430.rs @@ -6,6 +6,8 @@ mod sizer; mod traits; #[cfg(feature = "std")] mod writer; +#[cfg(feature = "arrays")] +mod arrays; pub use crate::bool::Bool; @@ -14,5 +16,7 @@ pub use self::sizer::*; pub use self::traits::*; #[cfg(feature = "std")] pub use self::writer::*; +#[cfg(feature = "arrays")] +pub use self::arrays::Std430ArrayItem; pub use crevice_derive::AsStd430; diff --git a/src/std430/arrays.rs b/src/std430/arrays.rs new file mode 100644 index 0000000..c279b6d --- /dev/null +++ b/src/std430/arrays.rs @@ -0,0 +1,78 @@ +use core::mem::{transmute_copy, MaybeUninit}; +use core::fmt::Debug; + +use bytemuck::{Zeroable, Pod}; + +use super::{Std430, AsStd430}; + +pub unsafe trait Std430ArrayItem: Std430 { + type Padding: Zeroable + Copy + Debug; +} + +type Padded = (T, ::Padding); + +fn wrap(x: &T) -> Padded +where T::Output: Std430ArrayItem +{ + (x.as_std430(), Zeroable::zeroed()) +} + +fn unwrap(x: Padded) -> T + where T::Output: Std430ArrayItem +{ + T::from_std430(x.0) +} + +#[doc(hidden)] +#[derive(Copy, Clone, Debug)] +#[repr(transparent)] +pub struct Std430Array([Padded; N]); + +unsafe impl Zeroable for Std430Array +{} +unsafe impl Pod for Std430Array +{} +unsafe impl Std430 for Std430Array +{ + const ALIGNMENT: usize = T::ALIGNMENT; +} + +impl AsStd430 for [T; N] + where T::Output: Std430ArrayItem +{ + type Output = Std430Array; + fn as_std430(&self) -> Self::Output { + let mut res: [MaybeUninit<_>; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + for i in 0..N { + res[i] = MaybeUninit::new(wrap(&self[i])); + } + + unsafe { transmute_copy(&res) } + } + + fn from_std430(val: Self::Output) -> Self { + val.0 + .map(|x| unwrap(x)) + } +} + +unsafe impl Std430ArrayItem for f32 { + type Padding = [u8; 0]; +} + +unsafe impl Std430ArrayItem for f64 { + type Padding = [u8; 0]; +} + +unsafe impl Std430ArrayItem for i32 { + type Padding = [u8; 0]; +} + +unsafe impl Std430ArrayItem for u32 { + type Padding = [u8; 0]; +} + +unsafe impl Std430ArrayItem for crate::bool::Bool { + type Padding = [u8; 0]; +} diff --git a/src/std430/primitives.rs b/src/std430/primitives.rs index 4408df2..d397e0d 100644 --- a/src/std430/primitives.rs +++ b/src/std430/primitives.rs @@ -5,31 +5,26 @@ use bytemuck::{Pod, Zeroable}; use crate::bool::Bool; use crate::glsl::Glsl; -use crate::std430::{AsStd430, Std430, Std430Padded}; +use crate::std430::{AsStd430, Std430}; unsafe impl Std430 for f32 { const ALIGNMENT: usize = 4; - type Padded = Self; } unsafe impl Std430 for f64 { const ALIGNMENT: usize = 8; - type Padded = Self; } unsafe impl Std430 for i32 { const ALIGNMENT: usize = 4; - type Padded = Self; } unsafe impl Std430 for u32 { const ALIGNMENT: usize = 4; - type Padded = Self; } unsafe impl Std430 for Bool { const ALIGNMENT: usize = 4; - type Padded = Self; } impl AsStd430 for bool { @@ -64,7 +59,11 @@ macro_rules! vectors { unsafe impl Std430 for $name { const ALIGNMENT: usize = $align; - type Padded = Std430Padded(), $align)}>; + } + + #[cfg(feature = "arrays")] + unsafe impl super::Std430ArrayItem for $name { + type Padding = [u8; align_offset(size_of::<$name>(), $align)]; } unsafe impl Glsl for $name { @@ -120,7 +119,11 @@ macro_rules! matrices { unsafe impl Std430 for $name { const ALIGNMENT: usize = $align; - type Padded = Std430Padded(), $align)}>; + } + + #[cfg(feature = "arrays")] + unsafe impl super::Std430ArrayItem for $name { + type Padding = [u8; 0]; } unsafe impl Glsl for $name { diff --git a/src/std430/traits.rs b/src/std430/traits.rs index a0a1f93..fee8c07 100644 --- a/src/std430/traits.rs +++ b/src/std430/traits.rs @@ -1,4 +1,4 @@ -use core::mem::{size_of, MaybeUninit}; +use core::mem::size_of; #[cfg(feature = "std")] use std::io::{self, Write}; @@ -18,11 +18,6 @@ pub unsafe trait Std430: Copy + Zeroable + Pod { /// slices safe. const ALIGNMENT: usize; - /// Padded type (Std430Padded specialization) - /// The usual implementation is - /// type Padded = Std430Padded(), ALIGNMENT)}>; - type Padded: Std430Convertible; - /// Casts the type to a byte array. Implementors should not override this /// method. /// @@ -34,37 +29,6 @@ pub unsafe trait Std430: Copy + Zeroable + Pod { } } -/// Trait specifically for Std430::Padded, implements conversions between padded type and base type. -pub trait Std430Convertible: Copy + Pod { - /// Convert from self to Std430 - fn into_std430(self) -> T; - /// Convert from Std430 to self - fn from_std430(_: T) -> Self; -} - -impl Std430Convertible for T { - fn into_std430(self) -> T { - self - } - fn from_std430(also_self: T) -> Self { - also_self - } -} - -/// Unfortunately, we cannot easily derive padded representation for generic Std140 types. -/// For now, we'll just use this empty enum with no values. -#[derive(Copy, Clone)] -pub enum InvalidPadded {} -unsafe impl Zeroable for InvalidPadded {} -unsafe impl Pod for InvalidPadded {} -impl Std430Convertible for InvalidPadded { - fn into_std430(self) -> T { - unimplemented!() - } - fn from_std430(_: T) -> Self { - unimplemented!() - } -} /** Trait implemented for all types that can be turned into `std430` values. @@ -139,64 +103,6 @@ where } } -#[doc(hidden)] -#[derive(Copy, Clone, Debug)] -pub struct Std430Padded { - inner: T, - _padding: [u8; PAD], -} - -unsafe impl Zeroable for Std430Padded {} -unsafe impl Pod for Std430Padded {} - -impl Std430Convertible for Std430Padded { - fn into_std430(self) -> T { - self.inner - } - - fn from_std430(inner: T) -> Self { - Self { - inner, - _padding: [0u8; PAD], - } - } -} - -#[doc(hidden)] -#[derive(Copy, Clone, Debug)] -#[repr(transparent)] -pub struct Std430Array([T::Padded; N]); - -unsafe impl Zeroable for Std430Array where T::Padded: Zeroable {} -unsafe impl Pod for Std430Array where T::Padded: Pod {} -unsafe impl Std430 for Std430Array -where - T::Padded: Pod, -{ - const ALIGNMENT: usize = T::ALIGNMENT; - type Padded = Self; -} - -impl AsStd430 for [T; N] { - type Output = Std430Array; - fn as_std430(&self) -> Self::Output { - let mut res: [MaybeUninit<_>; N] = unsafe { MaybeUninit::uninit().assume_init() }; - - for i in 0..N { - res[i] = MaybeUninit::new(::Padded::from_std430( - self[i].as_std430(), - )); - } - - unsafe { core::mem::transmute_copy(&res) } - } - - fn from_std430(val: Self::Output) -> Self { - val.0 - .map(|x| T::from_std430(Std430Convertible::into_std430(x))) - } -} - /// Trait implemented for all types that can be written into a buffer as /// `std430` bytes. This type is more general than [`AsStd430`]: all `AsStd430` /// types implement `WriteStd430`, but not the other way around. From cbf4f31ae8f715b0da3335eb97a9756476f3d007 Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 26 Nov 2021 15:27:58 +0300 Subject: [PATCH 10/11] Add a slightly less yucky GLSL support. --- Cargo.toml | 3 +- crevice-derive/src/glsl.rs | 41 ++++++++++++++++------ src/glsl.rs | 69 ++++++++++++-------------------------- src/internal.rs | 3 ++ src/std140/primitives.rs | 2 ++ src/std430/primitives.rs | 4 ++- tests/test.rs | 1 + 7 files changed, 63 insertions(+), 60 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a9181df..f71a093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ resolver = "2" [features] default = ["std"] std = [] -arrays = ["crevice-derive/arrays"] +arrays = ["crevice-derive/arrays", "const_format"] [workspace] members = ["crevice-derive", "crevice-tests"] @@ -25,6 +25,7 @@ default-members = ["crevice-derive", "crevice-tests"] [dependencies] crevice-derive = { version = "0.8.0", path = "crevice-derive" } +const_format = {version = "0.2.22", optional = true} bytemuck = "1.4.1" mint = "0.5.8" diff --git a/crevice-derive/src/glsl.rs b/crevice-derive/src/glsl.rs index fd74f0c..c76c639 100644 --- a/crevice-derive/src/glsl.rs +++ b/crevice-derive/src/glsl.rs @@ -1,6 +1,8 @@ use proc_macro2::{Literal, TokenStream}; use quote::quote; -use syn::{parse_quote, Data, DeriveInput, Fields, Path}; +use syn::{parse_quote, Data, DeriveInput, Fields, Path, Type, Expr}; +#[cfg(feature = "arrays")] +use syn::TypeArray; pub fn emit(input: DeriveInput) -> TokenStream { let fields = match &input.data { @@ -22,16 +24,15 @@ pub fn emit(input: DeriveInput) -> TokenStream { let glsl_fields = fields.named.iter().map(|field| { let field_ty = &field.ty; + let (base_ty, array_suffix) = remove_array_layers(field_ty); let field_name_str = Literal::string(&field.ident.as_ref().unwrap().to_string()); - let field_as = quote! {<#field_ty as ::crevice::glsl::GlslArray>}; quote! { - s.push_str("\t"); - s.push_str(#field_as::NAME); - s.push_str(" "); - s.push_str(#field_name_str); - <#field_as::ArraySize as ::crevice::glsl::DimensionList>::push_to_string(s); - s.push_str(";\n"); + ::crevice::glsl::GlslField { + ty: <#base_ty as ::crevice::glsl::Glsl>::NAME, + name: #field_name_str, + dim: #array_suffix, + } } }); @@ -41,9 +42,29 @@ pub fn emit(input: DeriveInput) -> TokenStream { } unsafe impl #impl_generics #struct_trait_path for #name #ty_generics #where_clause { - fn enumerate_fields(s: &mut String) { - #( #glsl_fields )* + const FIELDS: &'static [::crevice::glsl::GlslField] = &[ + #( #glsl_fields, )* + ]; + } + } +} + +#[cfg(feature = "arrays")] +fn remove_array_layers(mut ty: &Type) -> (&Type, Expr) { + let mut suffix = quote!(""); + + loop { + match ty { + &Type::Array(TypeArray { ref elem, ref len, .. }) => { + ty = elem.as_ref(); + suffix = quote!(::crevice::internal::const_format::concatcp!("[", (#len as usize), "]", #suffix)); } + _ => break, } } + (ty, Expr::Verbatim(suffix)) } +#[cfg(not(feature = "arrays"))] +fn remove_array_layers(ty: &Type) -> (&Type, Expr) { + (ty, Expr::Verbatim(quote!(""))) +} \ No newline at end of file diff --git a/src/glsl.rs b/src/glsl.rs index 3f879b6..5196bd8 100644 --- a/src/glsl.rs +++ b/src/glsl.rs @@ -1,33 +1,6 @@ //! Defines traits and types for generating GLSL code from Rust definitions. pub use crevice_derive::GlslStruct; -use std::marker::PhantomData; - -/// Type-level linked list of array dimensions -pub struct Dimension { - _marker: PhantomData, -} - -/// Type-level linked list terminator for array dimensions. -pub struct DimensionNil; - -/// Trait for type-level array dimensions. Probably shouldn't be implemented outside this crate. -pub unsafe trait DimensionList { - /// Write dimensions in square brackets to a string, list tail to list head. - fn push_to_string(s: &mut String); -} - -unsafe impl DimensionList for DimensionNil { - fn push_to_string(_: &mut String) {} -} - -unsafe impl DimensionList for Dimension { - fn push_to_string(s: &mut String) { - use std::fmt::Write; - A::push_to_string(s); - write!(s, "[{}]", N).unwrap(); - } -} /// Trait for types that have a GLSL equivalent. Useful for generating GLSL code /// from Rust structs. @@ -36,12 +9,24 @@ pub unsafe trait Glsl { const NAME: &'static str; } +/// A field contained within a GLSL struct definition. +pub struct GlslField { + /// The type of the field, like `vec2` or `mat3`. + pub ty: &'static str, + + /// The field's name. This must be a valid GLSL identifier. + pub name: &'static str, + + /// The field's array dimensions. This is a string of the form "[1][2]..." + pub dim: &'static str, +} + /// Trait for types that can be represented as a struct in GLSL. /// /// This trait should not generally be implemented by hand, but can be derived. pub unsafe trait GlslStruct: Glsl { /// The fields contained in this struct. - fn enumerate_fields(s: &mut String); + const FIELDS: &'static [GlslField]; /// Generates GLSL code that represents this struct and its fields. fn glsl_definition() -> String { @@ -50,26 +35,20 @@ pub unsafe trait GlslStruct: Glsl { output.push_str(Self::NAME); output.push_str(" {\n"); - Self::enumerate_fields(&mut output); + for field in Self::FIELDS { + output.push('\t'); + output.push_str(field.ty); + output.push(' '); + output.push_str(field.name); + output.push_str(field.dim); + output.push_str(";\n"); + } output.push_str("};"); output } } -/// Trait for types that are expressible as a GLSL type with (possibly zero) array dimensions. -pub unsafe trait GlslArray { - /// Base type name. - const NAME: &'static str; - /// Type-level linked list of array dimensions, ordered outer to inner. - type ArraySize: DimensionList; -} - -unsafe impl GlslArray for T { - const NAME: &'static str = ::NAME; - type ArraySize = DimensionNil; -} - unsafe impl Glsl for f32 { const NAME: &'static str = "float"; } @@ -85,9 +64,3 @@ unsafe impl Glsl for i32 { unsafe impl Glsl for u32 { const NAME: &'static str = "uint"; } - -unsafe impl GlslArray for [T; N] { - const NAME: &'static str = T::NAME; - - type ArraySize = Dimension; -} diff --git a/src/internal.rs b/src/internal.rs index cd22972..0a444d4 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -38,3 +38,6 @@ pub const fn max_arr(input: [usize; N]) -> usize { max } + +#[cfg(feature = "arrays")] +pub use const_format; \ No newline at end of file diff --git a/src/std140/primitives.rs b/src/std140/primitives.rs index 78f091b..8062f15 100644 --- a/src/std140/primitives.rs +++ b/src/std140/primitives.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "arrays")] use core::mem::size_of; use bytemuck::{Pod, Zeroable}; @@ -5,6 +6,7 @@ use bytemuck::{Pod, Zeroable}; use crate::bool::Bool; use crate::glsl::Glsl; use crate::std140::{AsStd140, Std140}; +#[cfg(feature = "arrays")] use crate::internal::{align_offset, max}; unsafe impl Std140 for f32 { diff --git a/src/std430/primitives.rs b/src/std430/primitives.rs index d397e0d..43b3f0e 100644 --- a/src/std430/primitives.rs +++ b/src/std430/primitives.rs @@ -1,4 +1,4 @@ -use crate::internal::align_offset; +#[cfg(feature = "arrays")] use core::mem::size_of; use bytemuck::{Pod, Zeroable}; @@ -6,6 +6,8 @@ use bytemuck::{Pod, Zeroable}; use crate::bool::Bool; use crate::glsl::Glsl; use crate::std430::{AsStd430, Std430}; +#[cfg(feature = "arrays")] +use crate::internal::align_offset; unsafe impl Std430 for f32 { const ALIGNMENT: usize = 4; diff --git a/tests/test.rs b/tests/test.rs index f07786c..c349348 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -50,6 +50,7 @@ fn generate_struct_glsl() { } #[test] +#[cfg(feature = "arrays")] fn generate_struct_array_glsl() { #[allow(dead_code)] #[derive(GlslStruct)] From 112273ea71bd9a0dd0d49ccec4db91919313f29e Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 26 Nov 2021 15:29:28 +0300 Subject: [PATCH 11/11] Rustfmt. --- crevice-derive/src/glsl.rs | 12 ++++++++---- crevice-derive/src/layout.rs | 6 ++++-- src/internal.rs | 2 +- src/lib.rs | 1 - src/std140.rs | 8 ++++---- src/std140/arrays.rs | 27 +++++++++++++-------------- src/std140/primitives.rs | 2 +- src/std430.rs | 8 ++++---- src/std430/arrays.rs | 27 +++++++++++++-------------- src/std430/primitives.rs | 2 +- 10 files changed, 49 insertions(+), 46 deletions(-) diff --git a/crevice-derive/src/glsl.rs b/crevice-derive/src/glsl.rs index c76c639..c5b89e6 100644 --- a/crevice-derive/src/glsl.rs +++ b/crevice-derive/src/glsl.rs @@ -1,8 +1,8 @@ use proc_macro2::{Literal, TokenStream}; use quote::quote; -use syn::{parse_quote, Data, DeriveInput, Fields, Path, Type, Expr}; #[cfg(feature = "arrays")] use syn::TypeArray; +use syn::{parse_quote, Data, DeriveInput, Expr, Fields, Path, Type}; pub fn emit(input: DeriveInput) -> TokenStream { let fields = match &input.data { @@ -55,9 +55,13 @@ fn remove_array_layers(mut ty: &Type) -> (&Type, Expr) { loop { match ty { - &Type::Array(TypeArray { ref elem, ref len, .. }) => { + &Type::Array(TypeArray { + ref elem, ref len, .. + }) => { ty = elem.as_ref(); - suffix = quote!(::crevice::internal::const_format::concatcp!("[", (#len as usize), "]", #suffix)); + suffix = quote!( + ::crevice::internal::const_format::concatcp!("[", (#len as usize), "]", #suffix) + ); } _ => break, } @@ -67,4 +71,4 @@ fn remove_array_layers(mut ty: &Type) -> (&Type, Expr) { #[cfg(not(feature = "arrays"))] fn remove_array_layers(ty: &Type) -> (&Type, Expr) { (ty, Expr::Verbatim(quote!(""))) -} \ No newline at end of file +} diff --git a/crevice-derive/src/layout.rs b/crevice-derive/src/layout.rs index 00d717e..ab2f7c7 100644 --- a/crevice-derive/src/layout.rs +++ b/crevice-derive/src/layout.rs @@ -95,8 +95,10 @@ pub fn emit( output.into_iter().collect::() }; - let pad_fn_impls: TokenStream = pad_fns.iter().enumerate().map( - |(index, pad_fn)| { + let pad_fn_impls: TokenStream = pad_fns + .iter() + .enumerate() + .map(|(index, pad_fn)| { let starting_offset = offset_after_field(index); let next_field_or_self_alignment = fields diff --git a/src/internal.rs b/src/internal.rs index 0a444d4..d83c8b2 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -40,4 +40,4 @@ pub const fn max_arr(input: [usize; N]) -> usize { } #[cfg(feature = "arrays")] -pub use const_format; \ No newline at end of file +pub use const_format; diff --git a/src/lib.rs b/src/lib.rs index c0dc23b..abc3d90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,7 +151,6 @@ Crevice supports Rust 1.52.1 and newer due to use of new `const fn` features. */ #![cfg_attr(feature = "arrays", feature(generic_const_exprs))] - //#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/src/std140.rs b/src/std140.rs index 2eb2963..9849ac9 100644 --- a/src/std140.rs +++ b/src/std140.rs @@ -1,24 +1,24 @@ //! Defines traits and types for working with data adhering to GLSL's `std140` //! layout specification. +#[cfg(feature = "arrays")] +mod arrays; mod dynamic_uniform; mod primitives; mod sizer; mod traits; #[cfg(feature = "std")] mod writer; -#[cfg(feature = "arrays")] -mod arrays; pub use crate::bool::Bool; +#[cfg(feature = "arrays")] +pub use self::arrays::Std140ArrayItem; pub use self::dynamic_uniform::*; pub use self::primitives::*; pub use self::sizer::*; pub use self::traits::*; #[cfg(feature = "std")] pub use self::writer::*; -#[cfg(feature = "arrays")] -pub use self::arrays::Std140ArrayItem; pub use crevice_derive::AsStd140; diff --git a/src/std140/arrays.rs b/src/std140/arrays.rs index fe85524..e98105f 100644 --- a/src/std140/arrays.rs +++ b/src/std140/arrays.rs @@ -1,9 +1,9 @@ -use core::mem::{transmute_copy, MaybeUninit}; use core::fmt::Debug; +use core::mem::{transmute_copy, MaybeUninit}; -use bytemuck::{Zeroable, Pod}; +use bytemuck::{Pod, Zeroable}; -use super::{Std140, AsStd140}; +use super::{AsStd140, Std140}; pub unsafe trait Std140ArrayItem: Std140 { type Padding: Zeroable + Copy + Debug; @@ -12,13 +12,15 @@ pub unsafe trait Std140ArrayItem: Std140 { type Padded = (T, ::Padding); fn wrap(x: &T) -> Padded -where T::Output: Std140ArrayItem +where + T::Output: Std140ArrayItem, { (x.as_std140(), Zeroable::zeroed()) } fn unwrap(x: Padded) -> T - where T::Output: Std140ArrayItem +where + T::Output: Std140ArrayItem, { T::from_std140(x.0) } @@ -28,17 +30,15 @@ fn unwrap(x: Padded) -> T #[repr(transparent)] pub struct Std140Array([Padded; N]); -unsafe impl Zeroable for Std140Array -{} -unsafe impl Pod for Std140Array -{} -unsafe impl Std140 for Std140Array -{ +unsafe impl Zeroable for Std140Array {} +unsafe impl Pod for Std140Array {} +unsafe impl Std140 for Std140Array { const ALIGNMENT: usize = crate::internal::max(16, T::ALIGNMENT); } impl AsStd140 for [T; N] - where T::Output: Std140ArrayItem +where + T::Output: Std140ArrayItem, { type Output = Std140Array; fn as_std140(&self) -> Self::Output { @@ -52,8 +52,7 @@ impl AsStd140 for [T; N] } fn from_std140(val: Self::Output) -> Self { - val.0 - .map(|x| unwrap(x)) + val.0.map(|x| unwrap(x)) } } diff --git a/src/std140/primitives.rs b/src/std140/primitives.rs index 8062f15..1ec87d9 100644 --- a/src/std140/primitives.rs +++ b/src/std140/primitives.rs @@ -5,9 +5,9 @@ use bytemuck::{Pod, Zeroable}; use crate::bool::Bool; use crate::glsl::Glsl; -use crate::std140::{AsStd140, Std140}; #[cfg(feature = "arrays")] use crate::internal::{align_offset, max}; +use crate::std140::{AsStd140, Std140}; unsafe impl Std140 for f32 { const ALIGNMENT: usize = 4; diff --git a/src/std430.rs b/src/std430.rs index cab447c..421053e 100644 --- a/src/std430.rs +++ b/src/std430.rs @@ -1,22 +1,22 @@ //! Defines traits and types for working with data adhering to GLSL's `std140` //! layout specification. +#[cfg(feature = "arrays")] +mod arrays; mod primitives; mod sizer; mod traits; #[cfg(feature = "std")] mod writer; -#[cfg(feature = "arrays")] -mod arrays; pub use crate::bool::Bool; +#[cfg(feature = "arrays")] +pub use self::arrays::Std430ArrayItem; pub use self::primitives::*; pub use self::sizer::*; pub use self::traits::*; #[cfg(feature = "std")] pub use self::writer::*; -#[cfg(feature = "arrays")] -pub use self::arrays::Std430ArrayItem; pub use crevice_derive::AsStd430; diff --git a/src/std430/arrays.rs b/src/std430/arrays.rs index c279b6d..a3e4338 100644 --- a/src/std430/arrays.rs +++ b/src/std430/arrays.rs @@ -1,9 +1,9 @@ -use core::mem::{transmute_copy, MaybeUninit}; use core::fmt::Debug; +use core::mem::{transmute_copy, MaybeUninit}; -use bytemuck::{Zeroable, Pod}; +use bytemuck::{Pod, Zeroable}; -use super::{Std430, AsStd430}; +use super::{AsStd430, Std430}; pub unsafe trait Std430ArrayItem: Std430 { type Padding: Zeroable + Copy + Debug; @@ -12,13 +12,15 @@ pub unsafe trait Std430ArrayItem: Std430 { type Padded = (T, ::Padding); fn wrap(x: &T) -> Padded -where T::Output: Std430ArrayItem +where + T::Output: Std430ArrayItem, { (x.as_std430(), Zeroable::zeroed()) } fn unwrap(x: Padded) -> T - where T::Output: Std430ArrayItem +where + T::Output: Std430ArrayItem, { T::from_std430(x.0) } @@ -28,17 +30,15 @@ fn unwrap(x: Padded) -> T #[repr(transparent)] pub struct Std430Array([Padded; N]); -unsafe impl Zeroable for Std430Array -{} -unsafe impl Pod for Std430Array -{} -unsafe impl Std430 for Std430Array -{ +unsafe impl Zeroable for Std430Array {} +unsafe impl Pod for Std430Array {} +unsafe impl Std430 for Std430Array { const ALIGNMENT: usize = T::ALIGNMENT; } impl AsStd430 for [T; N] - where T::Output: Std430ArrayItem +where + T::Output: Std430ArrayItem, { type Output = Std430Array; fn as_std430(&self) -> Self::Output { @@ -52,8 +52,7 @@ impl AsStd430 for [T; N] } fn from_std430(val: Self::Output) -> Self { - val.0 - .map(|x| unwrap(x)) + val.0.map(|x| unwrap(x)) } } diff --git a/src/std430/primitives.rs b/src/std430/primitives.rs index 43b3f0e..d16e6ea 100644 --- a/src/std430/primitives.rs +++ b/src/std430/primitives.rs @@ -5,9 +5,9 @@ use bytemuck::{Pod, Zeroable}; use crate::bool::Bool; use crate::glsl::Glsl; -use crate::std430::{AsStd430, Std430}; #[cfg(feature = "arrays")] use crate::internal::align_offset; +use crate::std430::{AsStd430, Std430}; unsafe impl Std430 for f32 { const ALIGNMENT: usize = 4;