diff --git a/crates/bevy_crevice/Cargo.toml b/crates/bevy_crevice/Cargo.toml deleted file mode 100644 index 6ab98134a8..0000000000 --- a/crates/bevy_crevice/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "bevy_crevice" -description = "Create GLSL-compatible versions of structs with explicitly-initialized padding (Bevy version)" -version = "0.8.0-dev" -edition = "2021" -authors = ["Lucien Greathouse "] -documentation = "https://docs.rs/crevice" -homepage = "https://github.com/LPGhatguy/crevice" -repository = "https://github.com/bevyengine/bevy" -readme = "README.md" -keywords = ["glsl", "std140", "std430"] -license = "MIT OR Apache-2.0" -# resolver = "2" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -default = ["std"] -std = [] - -# [workspace] -# members = ["crevice-derive", "crevice-tests"] -# default-members = ["crevice-derive", "crevice-tests"] - -[dependencies] -bevy-crevice-derive = { version = "0.8.0-dev", path = "bevy-crevice-derive" } - -bytemuck = "1.4.1" -mint = "0.5.8" - -cgmath = { version = "0.18.0", optional = true } -glam = { version = "0.20.0", features = ["mint"], optional = true } -nalgebra = { version = "0.30.0", features = ["mint"], optional = true } - -[dev-dependencies] -insta = "0.16.1" diff --git a/crates/bevy_crevice/LICENSE-APACHE b/crates/bevy_crevice/LICENSE-APACHE deleted file mode 100644 index d42ecff58b..0000000000 --- a/crates/bevy_crevice/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ -i Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/crates/bevy_crevice/LICENSE-MIT b/crates/bevy_crevice/LICENSE-MIT deleted file mode 100644 index 32c2307fc6..0000000000 --- a/crates/bevy_crevice/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2020 Lucien Greathouse - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/crates/bevy_crevice/README.md b/crates/bevy_crevice/README.md deleted file mode 100644 index a5c16f69c7..0000000000 --- a/crates/bevy_crevice/README.md +++ /dev/null @@ -1,181 +0,0 @@ -# Bevy Crevice - -This is a fork of [Crevice](https://crates.io/crates/crevice) for -[Bevy](https://bevyengine.org). - -For use outside of Bevy, you should consider -using [Crevice](https://crates.io/crates/crevice) directly. - -It was forked to allow better integration in Bevy: - -* Easier derive macro usage, without needing to depend on `Crevice` directly. -* Use of unmerged features (as of the fork), like -[Array Support](https://github.com/LPGhatguy/crevice/pull/27/). -* Renaming of traits and macros to better match Bevy API. - -## Crevice - -Crevice creates GLSL-compatible versions of types through the power of derive -macros. Generated structures provide an [`as_bytes`][std140::Std140::as_bytes] -method to allow safely packing data into buffers for uploading. - -Generated structs also implement [`bytemuck::Zeroable`] and -[`bytemuck::Pod`] for use with other libraries. - -Crevice is similar to [`glsl-layout`][glsl-layout], but supports types from many -math crates, can generate GLSL source from structs, and explicitly initializes -padding to remove one source of undefined behavior. - -Crevice has support for many Rust math libraries via feature flags, and most -other math libraries by use of the mint crate. Crevice currently supports: - -* mint 0.5, enabled by default -* cgmath 0.18, using the `cgmath` feature -* nalgebra 0.29, using the `nalgebra` feature -* glam 0.20, using the `glam` feature - -PRs are welcome to add or update math libraries to Crevice. - -If your math library is not supported, it's possible to define structs using the -types from mint and convert your math library's types into mint types. This is -supported by most Rust math libraries. - -Your math library may require you to turn on a feature flag to get mint support. -For example, cgmath requires the "mint" feature to be enabled to allow -conversions to and from mint types. - -## Examples - -### Single Value - -Uploading many types can be done by deriving [`AsStd140`][std140::AsStd140] and -using [`as_std140`][std140::AsStd140::as_std140] and -[`as_bytes`][std140::Std140::as_bytes] to turn the result into bytes. - -```glsl -uniform MAIN { - mat3 orientation; - vec3 position; - float scale; -} main; -``` - -```rust -use bevy_crevice::std140::{AsStd140, Std140}; - -#[derive(AsStd140)] -struct MainUniform { - orientation: mint::ColumnMatrix3, - position: mint::Vector3, - scale: f32, -} - -let value = MainUniform { - orientation: [ - [1.0, 0.0, 0.0], - [0.0, 1.0, 0.0], - [0.0, 0.0, 1.0], - ].into(), - position: [1.0, 2.0, 3.0].into(), - scale: 4.0, -}; - -let value_std140 = value.as_std140(); - -upload_data_to_gpu(value_std140.as_bytes()); -``` - -### Sequential Types - -More complicated data can be uploaded using the std140 -[`Writer`][std140::Writer] type. - -```glsl -struct PointLight { - vec3 position; - vec3 color; - float brightness; -}; - -buffer POINT_LIGHTS { - uint len; - PointLight[] lights; -} point_lights; -``` - -```rust -use bevy_crevice::std140::{self, AsStd140}; - -#[derive(AsStd140)] -struct PointLight { - position: mint::Vector3, - color: mint::Vector3, - brightness: f32, -} - -let lights = vec![ - PointLight { - position: [0.0, 1.0, 0.0].into(), - color: [1.0, 0.0, 0.0].into(), - brightness: 0.6, - }, - PointLight { - position: [0.0, 4.0, 3.0].into(), - color: [1.0, 1.0, 1.0].into(), - brightness: 1.0, - }, -]; - -let target_buffer = map_gpu_buffer_for_write(); -let mut writer = std140::Writer::new(target_buffer); - -let light_count = lights.len() as u32; -writer.write(&light_count)?; - -// Crevice will automatically insert the required padding to align the -// PointLight structure correctly. In this case, there will be 12 bytes of -// padding between the length field and the light list. - -writer.write(lights.as_slice())?; - -unmap_gpu_buffer(); - -``` - -## Features - -* `std` (default): Enables [`std::io::Write`]-based structs. -* `cgmath`: Enables support for types from cgmath. -* `nalgebra`: Enables support for types from nalgebra. -* `glam`: Enables support for types from glam. - -## Minimum Supported Rust Version (MSRV) - -Crevice supports Rust 1.52.1 and newer due to use of new `const fn` features. - -[glsl-layout]: https://github.com/rustgd/glsl-layout - -[std140::AsStd140]: https://docs.rs/crevice/latest/crevice/std140/trait.AsStd140.html -[std140::AsStd140::as_std140]: https://docs.rs/crevice/latest/crevice/std140/trait.AsStd140.html#method.as_std140 -[std140::Std140::as_bytes]: https://docs.rs/crevice/latest/crevice/std140/trait.Std140.html#method.as_bytes -[std140::Writer]: https://docs.rs/crevice/latest/crevice/std140/struct.Writer.html - -[`std::io::Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html - -[`bytemuck::Pod`]: https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html -[`bytemuck::Zeroable`]: https://docs.rs/bytemuck/latest/bytemuck/trait.Zeroable.html - -## License - -Licensed under either of - -* Apache License, Version 2.0, ([LICENSE-APACHE](http://www.apache.org/licenses/LICENSE-2.0)) -* MIT license ([LICENSE-MIT](http://opensource.org/licenses/MIT)) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/crates/bevy_crevice/README.tpl b/crates/bevy_crevice/README.tpl deleted file mode 100644 index 42ca95cfb8..0000000000 --- a/crates/bevy_crevice/README.tpl +++ /dev/null @@ -1,25 +0,0 @@ -# Crevice - -{{readme}} - -[std140::AsStd140]: https://docs.rs/crevice/latest/crevice/std140/trait.AsStd140.html -[std140::AsStd140::as_std140]: https://docs.rs/crevice/latest/crevice/std140/trait.AsStd140.html#method.as_std140 -[std140::Std140::as_bytes]: https://docs.rs/crevice/latest/crevice/std140/trait.Std140.html#method.as_bytes -[std140::Writer]: https://docs.rs/crevice/latest/crevice/std140/struct.Writer.html - -[`std::io::Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html - -[`bytemuck::Pod`]: https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html -[`bytemuck::Zeroable`]: https://docs.rs/bytemuck/latest/bytemuck/trait.Zeroable.html - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. \ No newline at end of file diff --git a/crates/bevy_crevice/bevy-crevice-derive/Cargo.toml b/crates/bevy_crevice/bevy-crevice-derive/Cargo.toml deleted file mode 100644 index cc0042ae38..0000000000 --- a/crates/bevy_crevice/bevy-crevice-derive/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "bevy-crevice-derive" -description = "Derive crate for the 'crevice' crate (Bevy version)" -version = "0.8.0-dev" -edition = "2018" -authors = ["Lucien Greathouse "] -documentation = "https://docs.rs/crevice-derive" -homepage = "https://github.com/LPGhatguy/crevice" -repository = "https://github.com/bevyengine/bevy" -license = "MIT OR Apache-2.0" - -[features] -default = [] - -# Enable methods that let you introspect into the generated structs. -debug-methods = [] - -[lib] -proc-macro = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -syn = "1.0.40" -quote = "1.0.7" -proc-macro2 = "1.0.21" -bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.8.0-dev" } diff --git a/crates/bevy_crevice/bevy-crevice-derive/src/glsl.rs b/crates/bevy_crevice/bevy-crevice-derive/src/glsl.rs deleted file mode 100644 index dee33477c2..0000000000 --- a/crates/bevy_crevice/bevy-crevice-derive/src/glsl.rs +++ /dev/null @@ -1,48 +0,0 @@ -use bevy_macro_utils::get_named_struct_fields; -use proc_macro2::{Literal, TokenStream}; -use quote::quote; -use syn::{parse_quote, DeriveInput, Path}; - -pub fn emit(input: DeriveInput) -> TokenStream { - let bevy_crevice_path = crate::bevy_crevice_path(); - - let fields = match get_named_struct_fields(&input.data) { - Ok(fields) => fields, - Err(e) => return e.into_compile_error(), - }; - - let base_trait_path: Path = parse_quote!(#bevy_crevice_path::glsl::Glsl); - let struct_trait_path: Path = parse_quote!(#bevy_crevice_path::glsl::GlslStruct); - - let name = input.ident; - let name_str = Literal::string(&name.to_string()); - - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - - 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 #bevy_crevice_path::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 #bevy_crevice_path::glsl::DimensionList>::push_to_string(s); - s.push_str(";\n"); - } - }); - - quote! { - unsafe impl #impl_generics #base_trait_path for #name #ty_generics #where_clause { - const NAME: &'static str = #name_str; - } - - unsafe impl #impl_generics #struct_trait_path for #name #ty_generics #where_clause { - fn enumerate_fields(s: &mut String) { - #( #glsl_fields )* - } - } - } -} diff --git a/crates/bevy_crevice/bevy-crevice-derive/src/layout.rs b/crates/bevy_crevice/bevy-crevice-derive/src/layout.rs deleted file mode 100644 index 899343632b..0000000000 --- a/crates/bevy_crevice/bevy-crevice-derive/src/layout.rs +++ /dev/null @@ -1,287 +0,0 @@ -use bevy_macro_utils::get_named_struct_fields; -use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote}; -use syn::{parse_quote, DeriveInput, Ident, Path, Type}; - -pub fn emit( - input: DeriveInput, - trait_name: &'static str, - mod_name: &'static str, - min_struct_alignment: usize, -) -> TokenStream { - let bevy_crevice_path = crate::bevy_crevice_path(); - - let mod_name = Ident::new(mod_name, Span::call_site()); - let trait_name = Ident::new(trait_name, Span::call_site()); - - let mod_path: Path = parse_quote!(#bevy_crevice_path::#mod_name); - let trait_path: Path = parse_quote!(#mod_path::#trait_name); - - let as_trait_name = format_ident!("As{}", trait_name); - let as_trait_path: Path = parse_quote!(#mod_path::#as_trait_name); - 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(); - - let generated_name = format_ident!("{}{}", trait_name, input_name); - - // Crevice's derive only works on regular structs. We could potentially - // support transparent tuple structs in the future. - let fields: Vec<_> = match get_named_struct_fields(&input.data) { - Ok(fields) => fields.named.iter().collect(), - Err(e) => return e.into_compile_error(), - }; - - // Gives the layout-specific version of the given type. - let layout_version_of_ty = |ty: &Type| { - quote! { - <#ty as #as_trait_path>::Output - } - }; - - // Gives an expression returning the layout-specific alignment for the type. - let layout_alignment_of_ty = |ty: &Type| { - quote! { - <<#ty as #as_trait_path>::Output as #trait_path>::ALIGNMENT - } - }; - - // 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! { - #bevy_crevice_path::internal::max_arr([ - #min_struct_alignment, - #(#field_alignments,)* - ]) - }; - - // Generate names for each padding calculation function. - let pad_fns: Vec<_> = (0..fields.len()) - .map(|index| format_ident!("_{}__{}Pad{}", input_name, trait_name, index)) - .collect(); - - // Computes the offset immediately AFTER the field with the given index. - // - // This function depends on the generated padding calculation functions to - // do correct alignment. Be careful not to cause recursion! - let offset_after_field = |target: usize| { - let mut output = vec![quote!(0usize)]; - - for index in 0..=target { - let field_ty = &fields[index].ty; - let layout_ty = layout_version_of_ty(field_ty); - - output.push(quote! { - + ::core::mem::size_of::<#layout_ty>() - }); - - // For every field except our target field, also add the generated - // padding. Padding occurs after each field, so it isn't included in - // this value. - if index < target { - let pad_fn = &pad_fns[index]; - output.push(quote! { - + #pad_fn() - }); - } - } - - output.into_iter().collect::() - }; - - let pad_fn_impls: TokenStream = fields - .iter() - .enumerate() - .map(|(index, prev_field)| { - let pad_fn = &pad_fns[index]; - - 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) - .map(|next_field| layout_alignment_of_ty(&next_field.ty)) - .unwrap_or(quote!(#struct_alignment)); - - quote! { - /// Tells how many bytes of padding have to be inserted after - /// the field with index #index. - #[allow(non_snake_case)] - const fn #pad_fn() -> usize { - // First up, calculate our offset into the struct so far. - // We'll use this value to figure out how far out of - // 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 = #bevy_crevice_path::internal::max( - #next_field_or_self_alignment, - min_alignment, - ); - - // Using everything we've got, compute our padding amount. - #bevy_crevice_path::internal::align_offset(starting_offset, alignment) - } - } - }) - .collect(); - - let generated_struct_fields: TokenStream = fields - .iter() - .enumerate() - .map(|(index, field)| { - let field_name = field.ident.as_ref().unwrap(); - let field_ty = layout_version_of_ty(&field.ty); - let pad_field_name = format_ident!("_pad{}", index); - let pad_fn = &pad_fns[index]; - - quote! { - #field_name: #field_ty, - #pad_field_name: [u8; #pad_fn()], - } - }) - .collect(); - - let generated_struct_field_init: TokenStream = fields - .iter() - .map(|field| { - let field_name = field.ident.as_ref().unwrap(); - - quote! { - #field_name: self.#field_name.#as_trait_method(), - } - }) - .collect(); - - let input_struct_field_init: TokenStream = fields - .iter() - .map(|field| { - let field_name = field.ident.as_ref().unwrap(); - - quote! { - #field_name: #as_trait_path::#from_trait_method(input.#field_name), - } - }) - .collect(); - - let struct_definition = quote! { - #[derive(Debug, Clone, Copy)] - #[repr(C)] - #[allow(non_snake_case)] - #visibility struct #generated_name #ty_generics #where_clause { - #generated_struct_fields - } - }; - - let debug_methods = if cfg!(feature = "debug-methods") { - let debug_fields: TokenStream = fields - .iter() - .map(|field| { - let field_name = field.ident.as_ref().unwrap(); - let field_ty = &field.ty; - - quote! { - fields.push(Field { - name: stringify!(#field_name), - size: ::core::mem::size_of::<#field_ty>(), - offset: (&zeroed.#field_name as *const _ as usize) - - (&zeroed as *const _ as usize), - }); - } - }) - .collect(); - - quote! { - impl #impl_generics #generated_name #ty_generics #where_clause { - fn debug_metrics() -> String { - let size = ::core::mem::size_of::(); - let align = ::ALIGNMENT; - - let zeroed: Self = #bevy_crevice_path::internal::bytemuck::Zeroable::zeroed(); - - #[derive(Debug)] - struct Field { - name: &'static str, - offset: usize, - size: usize, - } - let mut fields = Vec::new(); - - #debug_fields - - format!("Size {}, Align {}, fields: {:#?}", size, align, fields) - } - - fn debug_definitions() -> &'static str { - stringify!( - #struct_definition - #pad_fn_impls - ) - } - } - } - } else { - quote!() - }; - - quote! { - #pad_fn_impls - #struct_definition - - unsafe impl #impl_generics #bevy_crevice_path::internal::bytemuck::Zeroable for #generated_name #ty_generics #where_clause {} - unsafe impl #impl_generics #bevy_crevice_path::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 { - 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 { - type Output = #generated_name; - - fn #as_trait_method(&self) -> Self::Output { - Self::Output { - #generated_struct_field_init - - ..#bevy_crevice_path::internal::bytemuck::Zeroable::zeroed() - } - } - - fn #from_trait_method(input: Self::Output) -> Self { - Self { - #input_struct_field_init - } - } - } - - #debug_methods - } -} diff --git a/crates/bevy_crevice/bevy-crevice-derive/src/lib.rs b/crates/bevy_crevice/bevy-crevice-derive/src/lib.rs deleted file mode 100644 index 183bf209f4..0000000000 --- a/crates/bevy_crevice/bevy-crevice-derive/src/lib.rs +++ /dev/null @@ -1,59 +0,0 @@ -mod glsl; -mod layout; - -use bevy_macro_utils::BevyManifest; -use proc_macro::TokenStream as CompilerTokenStream; - -use syn::{parse_macro_input, DeriveInput, Path}; - -#[proc_macro_derive(AsStd140)] -pub fn derive_as_std140(input: CompilerTokenStream) -> CompilerTokenStream { - let input = parse_macro_input!(input as DeriveInput); - let expanded = layout::emit(input, "Std140", "std140", 16); - - CompilerTokenStream::from(expanded) -} - -#[proc_macro_derive(AsStd430)] -pub fn derive_as_std430(input: CompilerTokenStream) -> CompilerTokenStream { - let input = parse_macro_input!(input as DeriveInput); - let expanded = layout::emit(input, "Std430", "std430", 0); - - CompilerTokenStream::from(expanded) -} - -#[proc_macro_derive(GlslStruct)] -pub fn derive_glsl_struct(input: CompilerTokenStream) -> CompilerTokenStream { - let input = parse_macro_input!(input as DeriveInput); - let expanded = glsl::emit(input); - - CompilerTokenStream::from(expanded) -} - -const BEVY: &str = "bevy"; -const BEVY_CREVICE: &str = "bevy_crevice"; -const BEVY_RENDER: &str = "bevy_render"; - -fn bevy_crevice_path() -> Path { - let bevy_manifest = BevyManifest::default(); - bevy_manifest - .maybe_get_path(crate::BEVY) - .map(|bevy_path| { - let mut segments = bevy_path.segments; - segments.push(BevyManifest::parse_str("render")); - Path { - leading_colon: None, - segments, - } - }) - .or_else(|| bevy_manifest.maybe_get_path(crate::BEVY_RENDER)) - .map(|bevy_render_path| { - let mut segments = bevy_render_path.segments; - segments.push(BevyManifest::parse_str("render_resource")); - Path { - leading_colon: None, - segments, - } - }) - .unwrap_or_else(|| bevy_manifest.get_path(crate::BEVY_CREVICE)) -} diff --git a/crates/bevy_crevice/crevice-tests/Cargo.toml b/crates/bevy_crevice/crevice-tests/Cargo.toml deleted file mode 100644 index 7d7a6bbec1..0000000000 --- a/crates/bevy_crevice/crevice-tests/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "crevice-tests" -version = "0.1.0" -edition = "2018" - -[features] -wgpu-validation = ["wgpu", "naga", "futures"] - -[dependencies] -bevy_crevice = { path = ".." } -bevy-crevice-derive = { path = "../bevy-crevice-derive", features = ["debug-methods"] } - -anyhow = "1.0.44" -bytemuck = "1.7.2" -memoffset = "0.6.4" -mint = "0.5.5" - -futures = { version = "0.3.17", features = ["executor"], optional = true } -naga = { version = "0.8.0", features = ["glsl-in", "wgsl-out"], optional = true } -wgpu = { version = "0.12.0", optional = true } diff --git a/crates/bevy_crevice/crevice-tests/src/gpu.rs b/crates/bevy_crevice/crevice-tests/src/gpu.rs deleted file mode 100644 index a91703e4ff..0000000000 --- a/crates/bevy_crevice/crevice-tests/src/gpu.rs +++ /dev/null @@ -1,268 +0,0 @@ -use std::borrow::Cow; -use std::fmt::Debug; -use std::marker::PhantomData; - -use bevy_crevice::glsl::{Glsl, GlslStruct}; -use bevy_crevice::std140::{AsStd140, Std140}; -use bevy_crevice::std430::{AsStd430, Std430}; -use futures::executor::block_on; -use wgpu::util::DeviceExt; - -const BASE_SHADER: &str = "#version 450 - -{struct_definition} - -layout({layout}, set = 0, binding = 0) readonly buffer INPUT { - {struct_name} in_data; -}; - -layout({layout}, set = 0, binding = 1) buffer OUTPUT { - {struct_name} out_data; -}; - -void main() { - out_data = in_data; -}"; - -pub fn test_round_trip_struct(value: T) { - let shader_std140 = glsl_shader_for_struct::("std140"); - let shader_std430 = glsl_shader_for_struct::("std430"); - - let context = Context::new(); - context.test_round_trip_std140(&shader_std140, &value); - context.test_round_trip_std430(&shader_std430, &value); -} - -pub fn test_round_trip_primitive(value: T) { - let shader_std140 = glsl_shader_for_primitive::("std140"); - let shader_std430 = glsl_shader_for_primitive::("std430"); - - let context = Context::new(); - context.test_round_trip_std140(&shader_std140, &value); - context.test_round_trip_std430(&shader_std430, &value); -} - -fn glsl_shader_for_struct(layout: &str) -> String { - BASE_SHADER - .replace("{struct_name}", T::NAME) - .replace("{struct_definition}", &T::glsl_definition()) - .replace("{layout}", layout) -} - -fn glsl_shader_for_primitive(layout: &str) -> String { - BASE_SHADER - .replace("{struct_name}", T::NAME) - .replace("{struct_definition}", "") - .replace("{layout}", layout) -} - -fn compile_glsl(glsl: &str) -> String { - match compile(glsl) { - Ok(shader) => shader, - Err(err) => { - eprintln!("Bad shader: {}", glsl); - panic!("{}", err); - } - } -} - -struct Context { - device: wgpu::Device, - queue: wgpu::Queue, - _phantom: PhantomData<*const T>, -} - -impl Context -where - T: Debug + PartialEq + AsStd140 + AsStd430 + Glsl, -{ - fn new() -> Self { - let (device, queue) = setup(); - Self { - device, - queue, - _phantom: PhantomData, - } - } - - fn test_round_trip_std140(&self, glsl_shader: &str, value: &T) { - let mut data = Vec::new(); - data.extend_from_slice(value.as_std140().as_bytes()); - - let wgsl_shader = compile_glsl(glsl_shader); - let bytes = self.round_trip(&wgsl_shader, &data); - - let std140 = bytemuck::from_bytes::<::Output>(&bytes); - let output = T::from_std140(*std140); - - if value != &output { - println!( - "std140 value did not round-trip through wgpu successfully.\n\ - Input: {:?}\n\ - Output: {:?}\n\n\ - GLSL shader:\n{}\n\n\ - WGSL shader:\n{}", - value, output, glsl_shader, wgsl_shader, - ); - - panic!("wgpu round-trip failure for {}", T::NAME); - } - } - - fn test_round_trip_std430(&self, glsl_shader: &str, value: &T) { - let mut data = Vec::new(); - data.extend_from_slice(value.as_std430().as_bytes()); - - let wgsl_shader = compile_glsl(glsl_shader); - let bytes = self.round_trip(&wgsl_shader, &data); - - let std430 = bytemuck::from_bytes::<::Output>(&bytes); - let output = T::from_std430(*std430); - - if value != &output { - println!( - "std430 value did not round-trip through wgpu successfully.\n\ - Input: {:?}\n\ - Output: {:?}\n\n\ - GLSL shader:\n{}\n\n\ - WGSL shader:\n{}", - value, output, glsl_shader, wgsl_shader, - ); - - panic!("wgpu round-trip failure for {}", T::NAME); - } - } - - fn round_trip(&self, shader: &str, data: &[u8]) -> Vec { - let input_buffer = self - .device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Input Buffer"), - contents: &data, - usage: wgpu::BufferUsages::STORAGE - | wgpu::BufferUsages::COPY_DST - | wgpu::BufferUsages::COPY_SRC, - }); - - let output_gpu_buffer = self.device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Output Buffer"), - size: data.len() as wgpu::BufferAddress, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC, - mapped_at_creation: false, - }); - - let output_cpu_buffer = self.device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Output Buffer"), - size: data.len() as wgpu::BufferAddress, - usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - let cs_module = self - .device - .create_shader_module(&wgpu::ShaderModuleDescriptor { - label: None, - source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(shader)), - }); - - let compute_pipeline = - self.device - .create_compute_pipeline(&wgpu::ComputePipelineDescriptor { - label: None, - layout: None, - module: &cs_module, - entry_point: "main", - }); - - let bind_group_layout = compute_pipeline.get_bind_group_layout(0); - let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: input_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: output_gpu_buffer.as_entire_binding(), - }, - ], - }); - - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - - { - let mut cpass = - encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None }); - cpass.set_pipeline(&compute_pipeline); - cpass.set_bind_group(0, &bind_group, &[]); - cpass.dispatch(1, 1, 1); - } - - encoder.copy_buffer_to_buffer( - &output_gpu_buffer, - 0, - &output_cpu_buffer, - 0, - data.len() as wgpu::BufferAddress, - ); - - self.queue.submit(std::iter::once(encoder.finish())); - - let output_slice = output_cpu_buffer.slice(..); - let output_future = output_slice.map_async(wgpu::MapMode::Read); - - self.device.poll(wgpu::Maintain::Wait); - block_on(output_future).unwrap(); - - let output = output_slice.get_mapped_range().to_vec(); - output_cpu_buffer.unmap(); - - output - } -} - -fn setup() -> (wgpu::Device, wgpu::Queue) { - let instance = wgpu::Instance::new(wgpu::Backends::all()); - let adapter = - block_on(instance.request_adapter(&wgpu::RequestAdapterOptions::default())).unwrap(); - - println!("Adapter info: {:#?}", adapter.get_info()); - - block_on(adapter.request_device( - &wgpu::DeviceDescriptor { - label: None, - features: wgpu::Features::empty(), - limits: wgpu::Limits::downlevel_defaults(), - }, - None, - )) - .unwrap() -} - -fn compile(glsl_source: &str) -> anyhow::Result { - let mut parser = naga::front::glsl::Parser::default(); - - let module = parser - .parse( - &naga::front::glsl::Options { - stage: naga::ShaderStage::Compute, - defines: Default::default(), - }, - glsl_source, - ) - .map_err(|err| anyhow::format_err!("{:?}", err))?; - - let info = naga::valid::Validator::new( - naga::valid::ValidationFlags::default(), - naga::valid::Capabilities::all(), - ) - .validate(&module)?; - - let wgsl = naga::back::wgsl::write_string(&module, &info)?; - - Ok(wgsl) -} diff --git a/crates/bevy_crevice/crevice-tests/src/lib.rs b/crates/bevy_crevice/crevice-tests/src/lib.rs deleted file mode 100644 index 2f0516e4ab..0000000000 --- a/crates/bevy_crevice/crevice-tests/src/lib.rs +++ /dev/null @@ -1,366 +0,0 @@ -#![cfg(test)] - -#[cfg(feature = "wgpu-validation")] -mod gpu; - -#[cfg(feature = "wgpu-validation")] -use gpu::{test_round_trip_primitive, test_round_trip_struct}; - -#[cfg(not(feature = "wgpu-validation"))] -fn test_round_trip_struct(_value: T) {} - -#[cfg(not(feature = "wgpu-validation"))] -fn test_round_trip_primitive(_value: T) {} - -#[macro_use] -mod util; - -use bevy_crevice::glsl::GlslStruct; -use bevy_crevice::std140::AsStd140; -use bevy_crevice::std430::AsStd430; -use mint::{ColumnMatrix2, ColumnMatrix3, ColumnMatrix4, Vector2, Vector3, Vector4}; - -#[test] -fn two_f32() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct TwoF32 { - x: f32, - y: f32, - } - - assert_std140!((size = 16, align = 16) TwoF32 { - x: 0, - y: 4, - }); - - assert_std430!((size = 8, align = 4) TwoF32 { - x: 0, - y: 4, - }); - - test_round_trip_struct(TwoF32 { x: 5.0, y: 7.0 }); -} - -#[test] -fn vec2() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct UseVec2 { - one: Vector2, - } - - assert_std140!((size = 16, align = 16) UseVec2 { - one: 0, - }); - - test_round_trip_struct(UseVec2 { - one: [1.0, 2.0].into(), - }); -} - -#[test] -fn mat2_bare() { - type Mat2 = ColumnMatrix2; - - assert_std140!((size = 32, align = 16) Mat2 { - x: 0, - y: 16, - }); - - assert_std430!((size = 16, align = 8) Mat2 { - x: 0, - y: 8, - }); - - // Naga doesn't work with std140 mat2 values. - // https://github.com/gfx-rs/naga/issues/1400 - - // test_round_trip_primitive(Mat2 { - // x: [1.0, 2.0].into(), - // y: [3.0, 4.0].into(), - // }); -} - -#[test] -fn mat3_bare() { - type Mat3 = ColumnMatrix3; - - assert_std140!((size = 48, align = 16) Mat3 { - x: 0, - y: 16, - z: 32, - }); - - // Naga produces invalid HLSL for mat3 value. - // https://github.com/gfx-rs/naga/issues/1466 - - // test_round_trip_primitive(Mat3 { - // x: [1.0, 2.0, 3.0].into(), - // y: [4.0, 5.0, 6.0].into(), - // z: [7.0, 8.0, 9.0].into(), - // }); -} - -#[test] -fn mat4_bare() { - type Mat4 = ColumnMatrix4; - - assert_std140!((size = 64, align = 16) Mat4 { - x: 0, - y: 16, - z: 32, - w: 48, - }); - - test_round_trip_primitive(Mat4 { - x: [1.0, 2.0, 3.0, 4.0].into(), - y: [5.0, 6.0, 7.0, 8.0].into(), - z: [9.0, 10.0, 11.0, 12.0].into(), - w: [13.0, 14.0, 15.0, 16.0].into(), - }); -} - -#[test] -fn mat3() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct TestData { - one: ColumnMatrix3, - } - - // Naga produces invalid HLSL for mat3 value. - // https://github.com/gfx-rs/naga/issues/1466 - - // test_round_trip_struct(TestData { - // one: [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]].into(), - // }); -} - -#[test] -fn dvec4() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct UsingDVec4 { - doubles: Vector4, - } - - assert_std140!((size = 32, align = 32) UsingDVec4 { - doubles: 0, - }); - - // Naga does not appear to support doubles. - // https://github.com/gfx-rs/naga/issues/1272 - - // test_round_trip_struct(UsingDVec4 { - // doubles: [1.0, 2.0, 3.0, 4.0].into(), - // }); -} - -#[test] -fn four_f64() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct FourF64 { - x: f64, - y: f64, - z: f64, - w: f64, - } - - assert_std140!((size = 32, align = 16) FourF64 { - x: 0, - y: 8, - z: 16, - w: 24, - }); - - // Naga does not appear to support doubles. - // https://github.com/gfx-rs/naga/issues/1272 - - // test_round_trip_struct(FourF64 { - // x: 5.0, - // y: 7.0, - // z: 9.0, - // w: 11.0, - // }); -} - -#[test] -fn two_vec3() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct TwoVec3 { - one: Vector3, - two: Vector3, - } - - print_std140!(TwoVec3); - print_std430!(TwoVec3); - - assert_std140!((size = 32, align = 16) TwoVec3 { - one: 0, - two: 16, - }); - - assert_std430!((size = 32, align = 16) TwoVec3 { - one: 0, - two: 16, - }); - - test_round_trip_struct(TwoVec3 { - one: [1.0, 2.0, 3.0].into(), - two: [4.0, 5.0, 6.0].into(), - }); -} - -#[test] -fn two_vec4() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct TwoVec4 { - one: Vector4, - two: Vector4, - } - - assert_std140!((size = 32, align = 16) TwoVec4 { - one: 0, - two: 16, - }); - - test_round_trip_struct(TwoVec4 { - one: [1.0, 2.0, 3.0, 4.0].into(), - two: [5.0, 6.0, 7.0, 8.0].into(), - }); -} - -#[test] -fn vec3_then_f32() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct Vec3ThenF32 { - one: Vector3, - two: f32, - } - - assert_std140!((size = 16, align = 16) Vec3ThenF32 { - one: 0, - two: 12, - }); - - test_round_trip_struct(Vec3ThenF32 { - one: [1.0, 2.0, 3.0].into(), - two: 4.0, - }); -} - -#[test] -fn mat3_padding() { - #[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)] - struct Mat3Padding { - // Three rows of 16 bytes (3x f32 + 4 bytes padding) - one: mint::ColumnMatrix3, - two: f32, - } - - assert_std140!((size = 64, align = 16) Mat3Padding { - one: 0, - two: 48, - }); - - // Naga produces invalid HLSL for mat3 value. - // https://github.com/gfx-rs/naga/issues/1466 - - // test_round_trip_struct(Mat3Padding { - // one: [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]].into(), - // two: 10.0, - // }); -} - -#[test] -fn padding_after_struct() { - #[derive(AsStd140)] - struct TwoF32 { - x: f32, - } - - #[derive(AsStd140)] - struct PaddingAfterStruct { - base_value: TwoF32, - // There should be 8 bytes of padding inserted here. - small_field: f32, - } - - assert_std140!((size = 32, align = 16) PaddingAfterStruct { - base_value: 0, - small_field: 16, - }); -} - -#[test] -fn proper_offset_calculations_for_differing_member_sizes() { - #[derive(AsStd140)] - struct Foo { - x: f32, - } - - #[derive(AsStd140)] - struct Bar { - first: Foo, - second: Foo, - } - - #[derive(AsStd140)] - struct Outer { - leading: Bar, - trailing: Foo, - } - - // Offset Size Contents - // 0 4 Bar.leading.first.x - // 4 12 [padding] - // 16 4 Bar.leading.second.x - // 20 12 [padding] - // 32 4 Bar.trailing.x - // 36 12 [padding] - // - // Total size is 48. - - assert_std140!((size = 48, align = 16) Outer { - leading: 0, - 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, GlslStruct)] - struct ArrayOfVector3 { - inner: [Vector3; 4], - } - - assert_std140!((size = 64, align = 16) ArrayOfVector3 { - inner: 0, - }); - - assert_std430!((size = 64, 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(), - ], - }) -} diff --git a/crates/bevy_crevice/crevice-tests/src/util.rs b/crates/bevy_crevice/crevice-tests/src/util.rs deleted file mode 100644 index 203afced8e..0000000000 --- a/crates/bevy_crevice/crevice-tests/src/util.rs +++ /dev/null @@ -1,143 +0,0 @@ -#[macro_export] -macro_rules! print_std140 { - ($type:ty) => { - println!( - "{}", - <$type as crevice::std140::AsStd140>::Output::debug_metrics() - ); - println!(); - println!(); - println!( - "{}", - <$type as crevice::std140::AsStd140>::Output::debug_definitions() - ); - }; -} - -#[macro_export] -macro_rules! print_std430 { - ($type:ty) => { - println!( - "{}", - <$type as crevice::std430::AsStd430>::Output::debug_metrics() - ); - println!(); - println!(); - println!( - "{}", - <$type as crevice::std430::AsStd430>::Output::debug_definitions() - ); - }; -} - -#[macro_export] -macro_rules! assert_std140 { - ((size = $size:literal, align = $align:literal) $struct:ident { - $( $field:ident: $offset:literal, )* - }) => {{ - type Target = <$struct as crevice::std140::AsStd140>::Output; - - let mut fail = false; - - let actual_size = std::mem::size_of::(); - if actual_size != $size { - fail = true; - println!( - "Invalid size for std140 struct {}\n\ - Expected: {}\n\ - Actual: {}\n", - stringify!($struct), - $size, - actual_size, - ); - } - - let actual_alignment = ::ALIGNMENT; - if actual_alignment != $align { - fail = true; - println!( - "Invalid alignment for std140 struct {}\n\ - Expected: {}\n\ - Actual: {}\n", - stringify!($struct), - $align, - actual_alignment, - ); - } - - $({ - let actual_offset = memoffset::offset_of!(Target, $field); - if actual_offset != $offset { - fail = true; - println!( - "Invalid offset for field {}\n\ - Expected: {}\n\ - Actual: {}\n", - stringify!($field), - $offset, - actual_offset, - ); - } - })* - - if fail { - panic!("Invalid std140 result for {}", stringify!($struct)); - } - }}; -} - -#[macro_export] -macro_rules! assert_std430 { - ((size = $size:literal, align = $align:literal) $struct:ident { - $( $field:ident: $offset:literal, )* - }) => {{ - type Target = <$struct as crevice::std430::AsStd430>::Output; - - let mut fail = false; - - let actual_size = std::mem::size_of::(); - if actual_size != $size { - fail = true; - println!( - "Invalid size for std430 struct {}\n\ - Expected: {}\n\ - Actual: {}\n", - stringify!($struct), - $size, - actual_size, - ); - } - - let actual_alignment = ::ALIGNMENT; - if actual_alignment != $align { - fail = true; - println!( - "Invalid alignment for std430 struct {}\n\ - Expected: {}\n\ - Actual: {}\n", - stringify!($struct), - $align, - actual_alignment, - ); - } - - $({ - let actual_offset = memoffset::offset_of!(Target, $field); - if actual_offset != $offset { - fail = true; - println!( - "Invalid offset for std430 field {}\n\ - Expected: {}\n\ - Actual: {}\n", - stringify!($field), - $offset, - actual_offset, - ); - } - })* - - if fail { - panic!("Invalid std430 result for {}", stringify!($struct)); - } - }}; -} diff --git a/crates/bevy_crevice/src/glsl.rs b/crates/bevy_crevice/src/glsl.rs deleted file mode 100644 index d6b1c48b63..0000000000 --- a/crates/bevy_crevice/src/glsl.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! Defines traits and types for generating GLSL code from Rust definitions. - -pub use bevy_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. -pub unsafe trait Glsl { - /// The name of this type in GLSL, like `vec2` or `mat4`. - const 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. - fn enumerate_fields(s: &mut String); - - /// Generates GLSL code that represents this struct and its fields. - fn glsl_definition() -> String { - let mut output = String::new(); - output.push_str("struct "); - output.push_str(Self::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"; -} - -unsafe impl Glsl for f64 { - const NAME: &'static str = "double"; -} - -unsafe impl Glsl for i32 { - const NAME: &'static str = "int"; -} - -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/crates/bevy_crevice/src/imp.rs b/crates/bevy_crevice/src/imp.rs deleted file mode 100644 index af49bd8915..0000000000 --- a/crates/bevy_crevice/src/imp.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod imp_mint; - -#[cfg(feature = "cgmath")] -mod imp_cgmath; - -#[cfg(feature = "glam")] -mod imp_glam; - -#[cfg(feature = "nalgebra")] -mod imp_nalgebra; diff --git a/crates/bevy_crevice/src/imp/imp_cgmath.rs b/crates/bevy_crevice/src/imp/imp_cgmath.rs deleted file mode 100644 index 79ee7e071c..0000000000 --- a/crates/bevy_crevice/src/imp/imp_cgmath.rs +++ /dev/null @@ -1,30 +0,0 @@ -easy_impl! { - Vec2 cgmath::Vector2 { x, y }, - Vec3 cgmath::Vector3 { x, y, z }, - Vec4 cgmath::Vector4 { x, y, z, w }, - - IVec2 cgmath::Vector2 { x, y }, - IVec3 cgmath::Vector3 { x, y, z }, - IVec4 cgmath::Vector4 { x, y, z, w }, - - UVec2 cgmath::Vector2 { x, y }, - UVec3 cgmath::Vector3 { x, y, z }, - UVec4 cgmath::Vector4 { x, y, z, w }, - - // bool vectors are disabled due to https://github.com/LPGhatguy/crevice/issues/36 - // BVec2 cgmath::Vector2 { x, y }, - // BVec3 cgmath::Vector3 { x, y, z }, - // BVec4 cgmath::Vector4 { x, y, z, w }, - - DVec2 cgmath::Vector2 { x, y }, - DVec3 cgmath::Vector3 { x, y, z }, - DVec4 cgmath::Vector4 { x, y, z, w }, - - Mat2 cgmath::Matrix2 { x, y }, - Mat3 cgmath::Matrix3 { x, y, z }, - Mat4 cgmath::Matrix4 { x, y, z, w }, - - DMat2 cgmath::Matrix2 { x, y }, - DMat3 cgmath::Matrix3 { x, y, z }, - DMat4 cgmath::Matrix4 { x, y, z, w }, -} diff --git a/crates/bevy_crevice/src/imp/imp_glam.rs b/crates/bevy_crevice/src/imp/imp_glam.rs deleted file mode 100644 index 58ef711c27..0000000000 --- a/crates/bevy_crevice/src/imp/imp_glam.rs +++ /dev/null @@ -1,24 +0,0 @@ -minty_impl! { - mint::Vector2 => glam::Vec2, - mint::Vector3 => glam::Vec3, - mint::Vector4 => glam::Vec4, - mint::Vector2 => glam::IVec2, - mint::Vector3 => glam::IVec3, - mint::Vector4 => glam::IVec4, - mint::Vector2 => glam::UVec2, - mint::Vector3 => glam::UVec3, - mint::Vector4 => glam::UVec4, - // bool vectors are disabled due to https://github.com/LPGhatguy/crevice/issues/36 - // mint::Vector2 => glam::BVec2, - // mint::Vector3 => glam::BVec3, - // mint::Vector4 => glam::BVec4, - mint::Vector2 => glam::DVec2, - mint::Vector3 => glam::DVec3, - mint::Vector4 => glam::DVec4, - mint::ColumnMatrix2 => glam::Mat2, - mint::ColumnMatrix3 => glam::Mat3, - mint::ColumnMatrix4 => glam::Mat4, - mint::ColumnMatrix2 => glam::DMat2, - mint::ColumnMatrix3 => glam::DMat3, - mint::ColumnMatrix4 => glam::DMat4, -} diff --git a/crates/bevy_crevice/src/imp/imp_mint.rs b/crates/bevy_crevice/src/imp/imp_mint.rs deleted file mode 100644 index 056a181c2c..0000000000 --- a/crates/bevy_crevice/src/imp/imp_mint.rs +++ /dev/null @@ -1,30 +0,0 @@ -easy_impl! { - Vec2 mint::Vector2 { x, y }, - Vec3 mint::Vector3 { x, y, z }, - Vec4 mint::Vector4 { x, y, z, w }, - - IVec2 mint::Vector2 { x, y }, - IVec3 mint::Vector3 { x, y, z }, - IVec4 mint::Vector4 { x, y, z, w }, - - UVec2 mint::Vector2 { x, y }, - UVec3 mint::Vector3 { x, y, z }, - UVec4 mint::Vector4 { x, y, z, w }, - - // bool vectors are disabled due to https://github.com/LPGhatguy/crevice/issues/36 - // BVec2 mint::Vector2 { x, y }, - // BVec3 mint::Vector3 { x, y, z }, - // BVec4 mint::Vector4 { x, y, z, w }, - - DVec2 mint::Vector2 { x, y }, - DVec3 mint::Vector3 { x, y, z }, - DVec4 mint::Vector4 { x, y, z, w }, - - Mat2 mint::ColumnMatrix2 { x, y }, - Mat3 mint::ColumnMatrix3 { x, y, z }, - Mat4 mint::ColumnMatrix4 { x, y, z, w }, - - DMat2 mint::ColumnMatrix2 { x, y }, - DMat3 mint::ColumnMatrix3 { x, y, z }, - DMat4 mint::ColumnMatrix4 { x, y, z, w }, -} diff --git a/crates/bevy_crevice/src/imp/imp_nalgebra.rs b/crates/bevy_crevice/src/imp/imp_nalgebra.rs deleted file mode 100644 index 3d1b89c0d3..0000000000 --- a/crates/bevy_crevice/src/imp/imp_nalgebra.rs +++ /dev/null @@ -1,24 +0,0 @@ -minty_impl! { - mint::Vector2 => nalgebra::Vector2, - mint::Vector3 => nalgebra::Vector3, - mint::Vector4 => nalgebra::Vector4, - mint::Vector2 => nalgebra::Vector2, - mint::Vector3 => nalgebra::Vector3, - mint::Vector4 => nalgebra::Vector4, - mint::Vector2 => nalgebra::Vector2, - mint::Vector3 => nalgebra::Vector3, - mint::Vector4 => nalgebra::Vector4, - // bool vectors are disabled due to https://github.com/LPGhatguy/crevice/issues/36 - // mint::Vector2 => nalgebra::Vector2, - // mint::Vector3 => nalgebra::Vector3, - // mint::Vector4 => nalgebra::Vector4, - mint::Vector2 => nalgebra::Vector2, - mint::Vector3 => nalgebra::Vector3, - mint::Vector4 => nalgebra::Vector4, - mint::ColumnMatrix2 => nalgebra::Matrix2, - mint::ColumnMatrix3 => nalgebra::Matrix3, - mint::ColumnMatrix4 => nalgebra::Matrix4, - mint::ColumnMatrix2 => nalgebra::Matrix2, - mint::ColumnMatrix3 => nalgebra::Matrix3, - mint::ColumnMatrix4 => nalgebra::Matrix4, -} diff --git a/crates/bevy_crevice/src/internal.rs b/crates/bevy_crevice/src/internal.rs deleted file mode 100644 index cd22972fb3..0000000000 --- a/crates/bevy_crevice/src/internal.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! This module is internal to crevice but used by its derive macro. No -//! guarantees are made about its contents. - -pub use bytemuck; - -/// Gives the number of bytes needed to make `offset` be aligned to `alignment`. -pub const fn align_offset(offset: usize, alignment: usize) -> usize { - if alignment == 0 || offset % alignment == 0 { - 0 - } else { - alignment - offset % alignment - } -} - -/// Max of two `usize`. Implemented because the `max` method from `Ord` cannot -/// be used in const fns. -pub const fn max(a: usize, b: usize) -> usize { - if a > b { - a - } else { - b - } -} - -/// Max of an array of `usize`. This function's implementation is funky because -/// we have no for loops! -pub const fn max_arr(input: [usize; N]) -> usize { - let mut max = 0; - let mut i = 0; - - while i < N { - if input[i] > max { - max = input[i]; - } - - i += 1; - } - - max -} diff --git a/crates/bevy_crevice/src/lib.rs b/crates/bevy_crevice/src/lib.rs deleted file mode 100644 index 48451966be..0000000000 --- a/crates/bevy_crevice/src/lib.rs +++ /dev/null @@ -1,174 +0,0 @@ -#![allow( - clippy::new_without_default, - clippy::needless_update, - clippy::len_without_is_empty, - clippy::needless_range_loop, - clippy::all, - clippy::doc_markdown -)] -/*! -[![GitHub CI Status](https://github.com/LPGhatguy/crevice/workflows/CI/badge.svg)](https://github.com/LPGhatguy/crevice/actions) -[![crevice on crates.io](https://img.shields.io/crates/v/crevice.svg)](https://crates.io/crates/crevice) -[![crevice docs](https://img.shields.io/badge/docs-docs.rs-orange.svg)](https://docs.rs/crevice) - -Crevice creates GLSL-compatible versions of types through the power of derive -macros. Generated structures provide an [`as_bytes`][std140::Std140::as_bytes] -method to allow safely packing data into buffers for uploading. - -Generated structs also implement [`bytemuck::Zeroable`] and -[`bytemuck::Pod`] for use with other libraries. - -Crevice is similar to [`glsl-layout`][glsl-layout], but supports types from many -math crates, can generate GLSL source from structs, and explicitly initializes -padding to remove one source of undefined behavior. - -Crevice has support for many Rust math libraries via feature flags, and most -other math libraries by use of the mint crate. Crevice currently supports: - -* mint 0.5, enabled by default -* cgmath 0.18, using the `cgmath` feature -* nalgebra 0.29, using the `nalgebra` feature -* glam 0.19, using the `glam` feature - -PRs are welcome to add or update math libraries to Crevice. - -If your math library is not supported, it's possible to define structs using the -types from mint and convert your math library's types into mint types. This is -supported by most Rust math libraries. - -Your math library may require you to turn on a feature flag to get mint support. -For example, cgmath requires the "mint" feature to be enabled to allow -conversions to and from mint types. - -## Examples - -### Single Value - -Uploading many types can be done by deriving [`AsStd140`][std140::AsStd140] and -using [`as_std140`][std140::AsStd140::as_std140] and -[`as_bytes`][std140::Std140::as_bytes] to turn the result into bytes. - -```glsl -uniform MAIN { - mat3 orientation; - vec3 position; - float scale; -} main; -``` - -```rust -use bevy_crevice::std140::{AsStd140, Std140}; - -#[derive(AsStd140)] -struct MainUniform { - orientation: mint::ColumnMatrix3, - position: mint::Vector3, - scale: f32, -} - -let value = MainUniform { - orientation: [ - [1.0, 0.0, 0.0], - [0.0, 1.0, 0.0], - [0.0, 0.0, 1.0], - ].into(), - position: [1.0, 2.0, 3.0].into(), - scale: 4.0, -}; - -let value_std140 = value.as_std140(); - -# fn upload_data_to_gpu(_value: &[u8]) {} -upload_data_to_gpu(value_std140.as_bytes()); -``` - -### Sequential Types - -More complicated data can be uploaded using the std140 -[`Writer`][std140::Writer] type. - -```glsl -struct PointLight { - vec3 position; - vec3 color; - float brightness; -}; - -buffer POINT_LIGHTS { - uint len; - PointLight[] lights; -} point_lights; -``` - -```rust -use bevy_crevice::std140::{self, AsStd140}; - -#[derive(AsStd140)] -struct PointLight { - position: mint::Vector3, - color: mint::Vector3, - brightness: f32, -} - -let lights = vec![ - PointLight { - position: [0.0, 1.0, 0.0].into(), - color: [1.0, 0.0, 0.0].into(), - brightness: 0.6, - }, - PointLight { - position: [0.0, 4.0, 3.0].into(), - color: [1.0, 1.0, 1.0].into(), - brightness: 1.0, - }, -]; - -# fn map_gpu_buffer_for_write() -> &'static mut [u8] { -# Box::leak(vec![0; 1024].into_boxed_slice()) -# } -let target_buffer = map_gpu_buffer_for_write(); -let mut writer = std140::Writer::new(target_buffer); - -let light_count = lights.len() as u32; -writer.write(&light_count)?; - -// Crevice will automatically insert the required padding to align the -// PointLight structure correctly. In this case, there will be 12 bytes of -// padding between the length field and the light list. - -writer.write(lights.as_slice())?; - -# fn unmap_gpu_buffer() {} -unmap_gpu_buffer(); - -# Ok::<(), std::io::Error>(()) -``` - -## Features - -* `std` (default): Enables [`std::io::Write`]-based structs. -* `cgmath`: Enables support for types from cgmath. -* `nalgebra`: Enables support for types from nalgebra. -* `glam`: Enables support for types from glam. - -## Minimum Supported Rust Version (MSRV) - -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(not(feature = "std"), no_std)] - -#[macro_use] -mod util; - -pub mod glsl; -pub mod std140; -pub mod std430; - -#[doc(hidden)] -pub mod internal; - -mod imp; diff --git a/crates/bevy_crevice/src/std140.rs b/crates/bevy_crevice/src/std140.rs deleted file mode 100644 index dd7cde1cab..0000000000 --- a/crates/bevy_crevice/src/std140.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Defines traits and types for working with data adhering to GLSL's `std140` -//! layout specification. - -mod dynamic_uniform; -mod primitives; -mod sizer; -mod traits; -#[cfg(feature = "std")] -mod writer; - -pub use self::dynamic_uniform::*; -pub use self::primitives::*; -pub use self::sizer::*; -pub use self::traits::*; -#[cfg(feature = "std")] -pub use self::writer::*; - -pub use bevy_crevice_derive::AsStd140; diff --git a/crates/bevy_crevice/src/std140/dynamic_uniform.rs b/crates/bevy_crevice/src/std140/dynamic_uniform.rs deleted file mode 100644 index 262f8ea449..0000000000 --- a/crates/bevy_crevice/src/std140/dynamic_uniform.rs +++ /dev/null @@ -1,68 +0,0 @@ -use bytemuck::{Pod, Zeroable}; - -#[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. -/// -/// This type is useful for ensuring correct alignment when creating dynamic -/// uniform buffers in APIs like WebGPU. -pub struct DynamicUniform(pub T); - -impl AsStd140 for DynamicUniform { - type Output = DynamicUniformStd140<::Output>; - - fn as_std140(&self) -> Self::Output { - DynamicUniformStd140(self.0.as_std140()) - } - - fn from_std140(value: Self::Output) -> Self { - DynamicUniform(::from_std140(value.0)) - } -} - -/// std140 variant of [`DynamicUniform`]. -#[derive(Clone, Copy)] -#[repr(transparent)] -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 {} -unsafe impl Pod for DynamicUniformStd140 {} - -#[cfg(test)] -mod test { - use super::*; - - use crate::std140::{self, WriteStd140}; - - #[test] - fn size_is_unchanged() { - let dynamic_f32 = DynamicUniform(0.0f32); - - assert_eq!(dynamic_f32.std140_size(), 0.0f32.std140_size()); - } - - #[test] - fn alignment_applies() { - let mut output = Vec::new(); - let mut writer = std140::Writer::new(&mut output); - - writer.write(&DynamicUniform(0.0f32)).unwrap(); - assert_eq!(writer.len(), 4); - - writer.write(&DynamicUniform(1.0f32)).unwrap(); - assert_eq!(writer.len(), 260); - } -} diff --git a/crates/bevy_crevice/src/std140/primitives.rs b/crates/bevy_crevice/src/std140/primitives.rs deleted file mode 100644 index 34e161e3b7..0000000000 --- a/crates/bevy_crevice/src/std140/primitives.rs +++ /dev/null @@ -1,175 +0,0 @@ -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; - 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 { - ( - $( - #[$doc:meta] align($align:literal) $glsl_name:ident $name:ident <$prim:ident> ($($field:ident),+) - )+ - ) => { - $( - #[$doc] - #[allow(missing_docs)] - #[derive(Debug, Clone, Copy, PartialEq)] - #[repr(C)] - pub struct $name { - $(pub $field: $prim,)+ - } - - unsafe impl Zeroable for $name {} - unsafe impl Pod for $name {} - - unsafe impl Std140 for $name { - const ALIGNMENT: usize = $align; - type Padded = Std140Padded(), max(16, $align))}>; - } - - unsafe impl Glsl for $name { - const NAME: &'static str = stringify!($glsl_name); - } - )+ - }; -} - -vectors! { - #[doc = "Corresponds to a GLSL `vec2` in std140 layout."] align(8) vec2 Vec2(x, y) - #[doc = "Corresponds to a GLSL `vec3` in std140 layout."] align(16) vec3 Vec3(x, y, z) - #[doc = "Corresponds to a GLSL `vec4` in std140 layout."] align(16) vec4 Vec4(x, y, z, w) - - #[doc = "Corresponds to a GLSL `ivec2` in std140 layout."] align(8) ivec2 IVec2(x, y) - #[doc = "Corresponds to a GLSL `ivec3` in std140 layout."] align(16) ivec3 IVec3(x, y, z) - #[doc = "Corresponds to a GLSL `ivec4` in std140 layout."] align(16) ivec4 IVec4(x, y, z, w) - - #[doc = "Corresponds to a GLSL `uvec2` in std140 layout."] align(8) uvec2 UVec2(x, y) - #[doc = "Corresponds to a GLSL `uvec3` in std140 layout."] align(16) uvec3 UVec3(x, y, z) - #[doc = "Corresponds to a GLSL `uvec4` in std140 layout."] align(16) uvec4 UVec4(x, y, z, w) - - // bool vectors are disabled due to https://github.com/LPGhatguy/crevice/issues/36 - - // #[doc = "Corresponds to a GLSL `bvec2` in std140 layout."] align(8) bvec2 BVec2(x, y) - // #[doc = "Corresponds to a GLSL `bvec3` in std140 layout."] align(16) bvec3 BVec3(x, y, z) - // #[doc = "Corresponds to a GLSL `bvec4` in std140 layout."] align(16) bvec4 BVec4(x, y, z, w) - - #[doc = "Corresponds to a GLSL `dvec2` in std140 layout."] align(16) dvec2 DVec2(x, y) - #[doc = "Corresponds to a GLSL `dvec3` in std140 layout."] align(32) dvec3 DVec3(x, y, z) - #[doc = "Corresponds to a GLSL `dvec4` in std140 layout."] align(32) dvec4 DVec4(x, y, z, w) -} - -macro_rules! matrices { - ( - $( - #[$doc:meta] - align($align:literal) - $glsl_name:ident $name:ident { - $($field:ident: $field_ty:ty,)+ - } - )+ - ) => { - $( - #[$doc] - #[allow(missing_docs)] - #[derive(Debug, Clone, Copy)] - #[repr(C)] - pub struct $name { - $(pub $field: $field_ty,)+ - } - - unsafe impl Zeroable for $name {} - unsafe impl Pod for $name {} - - 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; - type Padded = Std140Padded(), max(16, $align))}>; - } - - unsafe impl Glsl for $name { - const NAME: &'static str = stringify!($glsl_name); - } - )+ - }; -} - -matrices! { - #[doc = "Corresponds to a GLSL `mat2` in std140 layout."] - align(16) - mat2 Mat2 { - x: Vec2, - _pad_x: [f32; 2], - y: Vec2, - _pad_y: [f32; 2], - } - - #[doc = "Corresponds to a GLSL `mat3` in std140 layout."] - align(16) - mat3 Mat3 { - x: Vec3, - _pad_x: f32, - y: Vec3, - _pad_y: f32, - z: Vec3, - _pad_z: f32, - } - - #[doc = "Corresponds to a GLSL `mat4` in std140 layout."] - align(16) - mat4 Mat4 { - x: Vec4, - y: Vec4, - z: Vec4, - w: Vec4, - } - - #[doc = "Corresponds to a GLSL `dmat2` in std140 layout."] - align(16) - dmat2 DMat2 { - x: DVec2, - y: DVec2, - } - - #[doc = "Corresponds to a GLSL `dmat3` in std140 layout."] - align(32) - dmat3 DMat3 { - x: DVec3, - _pad_x: f64, - y: DVec3, - _pad_y: f64, - z: DVec3, - _pad_z: f64, - } - - #[doc = "Corresponds to a GLSL `dmat3` in std140 layout."] - align(32) - dmat4 DMat4 { - x: DVec4, - y: DVec4, - z: DVec4, - w: DVec4, - } -} diff --git a/crates/bevy_crevice/src/std140/sizer.rs b/crates/bevy_crevice/src/std140/sizer.rs deleted file mode 100644 index 87c27cb63b..0000000000 --- a/crates/bevy_crevice/src/std140/sizer.rs +++ /dev/null @@ -1,81 +0,0 @@ -use core::mem::size_of; - -use crate::internal::align_offset; -use crate::std140::{AsStd140, Std140}; - -/** -Type that computes the buffer size needed by a series of `std140` types laid -out. - -This type works well well when paired with `Writer`, precomputing a buffer's -size to alleviate the need to dynamically re-allocate buffers. - -## Example - -```glsl -struct Frob { - vec3 size; - float frobiness; -} - -buffer FROBS { - uint len; - Frob[] frobs; -} frobs; -``` - -``` -use bevy_crevice::std140::{self, AsStd140}; - -#[derive(AsStd140)] -struct Frob { - size: mint::Vector3, - frobiness: f32, -} - -// Many APIs require that buffers contain at least enough space for all -// fixed-size bindiongs to a buffer as well as one element of any arrays, if -// there are any. -let mut sizer = std140::Sizer::new(); -sizer.add::(); -sizer.add::(); - -# fn create_buffer_with_size(size: usize) {} -let buffer = create_buffer_with_size(sizer.len()); -# assert_eq!(sizer.len(), 32); -``` -*/ -pub struct Sizer { - offset: usize, -} - -impl Sizer { - /// Create a new `Sizer`. - pub fn new() -> Self { - Self { offset: 0 } - } - - /// Add a type's necessary padding and size to the `Sizer`. Returns the - /// offset into the buffer where that type would be written. - pub fn add(&mut self) -> usize - where - T: AsStd140, - { - let size = size_of::<::Output>(); - let alignment = ::Output::ALIGNMENT; - let padding = align_offset(self.offset, alignment); - - self.offset += padding; - let write_here = self.offset; - - self.offset += size; - - write_here - } - - /// Returns the number of bytes required to contain all the types added to - /// the `Sizer`. - pub fn len(&self) -> usize { - self.offset - } -} diff --git a/crates/bevy_crevice/src/std140/traits.rs b/crates/bevy_crevice/src/std140/traits.rs deleted file mode 100644 index 392251c3f8..0000000000 --- a/crates/bevy_crevice/src/std140/traits.rs +++ /dev/null @@ -1,284 +0,0 @@ -use core::mem::{size_of, MaybeUninit}; -#[cfg(feature = "std")] -use std::io::{self, Write}; - -use bytemuck::{bytes_of, Pod, Zeroable}; - -#[cfg(feature = "std")] -use crate::std140::Writer; - -/// Trait implemented for all `std140` primitives. Generally should not be -/// implemented outside this crate. -pub unsafe trait Std140: Copy + Zeroable + Pod { - /// The required alignment of the type. Must be a power of two. - /// - /// This is distinct from the value returned by `std::mem::align_of` because - /// `AsStd140` structs do not use Rust's alignment. This enables them to - /// control and zero their padding bytes, making converting them to and from - /// 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; - /// 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. - /// - /// # Safety - /// This is always safe due to the requirements of [`bytemuck::Pod`] being a - /// prerequisite for this trait. - fn as_bytes(&self) -> &[u8] { - bytes_of(self) - } -} - -/// 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`. - -Types from the mint crate implement `AsStd140`, making them convenient for use -in uniform types. Most Rust math crates, like cgmath, nalgebra, and -ultraviolet support mint. - -## Example - -```glsl -uniform CAMERA { - mat4 view; - mat4 projection; -} camera; -``` - -```no_run -use bevy_crevice::std140::{AsStd140, Std140}; - -#[derive(AsStd140)] -struct CameraUniform { - view: mint::ColumnMatrix4, - projection: mint::ColumnMatrix4, -} - -let view: mint::ColumnMatrix4 = todo!("your math code here"); -let projection: mint::ColumnMatrix4 = todo!("your math code here"); - -let camera = CameraUniform { - view, - projection, -}; - -# fn write_to_gpu_buffer(bytes: &[u8]) {} -let camera_std140 = camera.as_std140(); -write_to_gpu_buffer(camera_std140.as_bytes()); -``` -*/ -pub trait AsStd140 { - /// The `std140` version of this value. - type Output: Std140; - - /// Convert this value into the `std140` version of itself. - fn as_std140(&self) -> Self::Output; - - /// Returns the size of the `std140` version of this type. Useful for - /// pre-sizing buffers. - fn std140_size_static() -> usize { - size_of::() - } - - /// Converts from `std140` version of self to self. - fn from_std140(val: Self::Output) -> Self; -} - -impl AsStd140 for T -where - T: Std140, -{ - type Output = Self; - - fn as_std140(&self) -> Self { - *self - } - - fn from_std140(x: Self) -> Self { - x - } -} - -#[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())); - } - - 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. -/// -/// While `AsStd140` requires implementers to return a type that implements the -/// `Std140` trait, `WriteStd140` directly writes bytes using a [`Writer`]. This -/// makes `WriteStd140` usable for writing slices or other DSTs that could not -/// implement `AsStd140` without allocating new memory on the heap. -#[cfg(feature = "std")] -pub trait WriteStd140 { - /// Writes this value into the given [`Writer`] using `std140` layout rules. - /// - /// Should return the offset of the first byte of this type, as returned by - /// the first call to [`Writer::write`]. - fn write_std140(&self, writer: &mut Writer) -> io::Result; - - /// The space required to write this value using `std140` layout rules. This - /// does not include alignment padding that may be needed before or after - /// this type when written as part of a larger buffer. - fn std140_size(&self) -> usize { - let mut writer = Writer::new(io::sink()); - self.write_std140(&mut writer).unwrap(); - writer.len() - } -} - -#[cfg(feature = "std")] -impl WriteStd140 for T -where - T: AsStd140, -{ - fn write_std140(&self, writer: &mut Writer) -> io::Result { - writer.write_std140(&self.as_std140()) - } - - fn std140_size(&self) -> usize { - size_of::<::Output>() - } -} - -#[cfg(feature = "std")] -impl WriteStd140 for [T] -where - T: WriteStd140, -{ - fn write_std140(&self, writer: &mut Writer) -> io::Result { - // if no items are written, offset is current position of the writer - let mut offset = writer.len(); - - let mut iter = self.iter(); - - if let Some(item) = iter.next() { - offset = item.write_std140(writer)?; - } - - for item in iter { - item.write_std140(writer)?; - } - - Ok(offset) - } - - fn std140_size(&self) -> usize { - let mut writer = Writer::new(io::sink()); - self.write_std140(&mut writer).unwrap(); - writer.len() - } -} diff --git a/crates/bevy_crevice/src/std140/writer.rs b/crates/bevy_crevice/src/std140/writer.rs deleted file mode 100644 index aeed06ff78..0000000000 --- a/crates/bevy_crevice/src/std140/writer.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::io::{self, Write}; -use std::mem::size_of; - -use bytemuck::bytes_of; - -use crate::internal::align_offset; -use crate::std140::{AsStd140, Std140, WriteStd140}; - -/** -Type that enables writing correctly aligned `std140` values to a buffer. - -`Writer` is useful when many values need to be laid out in a row that cannot be -represented by a struct alone, like dynamically sized arrays or dynamically -laid-out values. - -## Example -In this example, we'll write a length-prefixed list of lights to a buffer. -`std140::Writer` helps align correctly, even across multiple structs, which can -be tricky and error-prone otherwise. - -```glsl -struct PointLight { - vec3 position; - vec3 color; - float brightness; -}; - -buffer POINT_LIGHTS { - uint len; - PointLight[] lights; -} point_lights; -``` - -``` -use bevy_crevice::std140::{self, AsStd140}; - -#[derive(AsStd140)] -struct PointLight { - position: mint::Vector3, - color: mint::Vector3, - brightness: f32, -} - -let lights = vec![ - PointLight { - position: [0.0, 1.0, 0.0].into(), - color: [1.0, 0.0, 0.0].into(), - brightness: 0.6, - }, - PointLight { - position: [0.0, 4.0, 3.0].into(), - color: [1.0, 1.0, 1.0].into(), - brightness: 1.0, - }, -]; - -# fn map_gpu_buffer_for_write() -> &'static mut [u8] { -# Box::leak(vec![0; 1024].into_boxed_slice()) -# } -let target_buffer = map_gpu_buffer_for_write(); -let mut writer = std140::Writer::new(target_buffer); - -let light_count = lights.len() as u32; -writer.write(&light_count)?; - -// Crevice will automatically insert the required padding to align the -// PointLight structure correctly. In this case, there will be 12 bytes of -// padding between the length field and the light list. - -writer.write(lights.as_slice())?; - -# fn unmap_gpu_buffer() {} -unmap_gpu_buffer(); - -# Ok::<(), std::io::Error>(()) -``` -*/ -pub struct Writer { - writer: W, - offset: usize, -} - -impl Writer { - /// Create a new `Writer`, wrapping a buffer, file, or other type that - /// implements [`std::io::Write`]. - pub fn new(writer: W) -> Self { - Self { writer, offset: 0 } - } - - /// Write a new value to the underlying buffer, writing zeroed padding where - /// necessary. - /// - /// Returns the offset into the buffer that the value was written to. - pub fn write(&mut self, value: &T) -> io::Result - where - T: WriteStd140 + ?Sized, - { - value.write_std140(self) - } - - /// Write an iterator of values to the underlying buffer. - /// - /// Returns the offset into the buffer that the first value was written to. - /// If no values were written, returns the `len()`. - pub fn write_iter(&mut self, iter: I) -> io::Result - where - I: IntoIterator, - T: WriteStd140, - { - let mut offset = self.offset; - - let mut iter = iter.into_iter(); - - if let Some(item) = iter.next() { - offset = item.write_std140(self)?; - } - - for item in iter { - item.write_std140(self)?; - } - - Ok(offset) - } - - /// Write an `Std140` type to the underlying buffer. - pub fn write_std140(&mut self, value: &T) -> io::Result - where - T: Std140, - { - let padding = align_offset(self.offset, T::ALIGNMENT); - - for _ in 0..padding { - self.writer.write_all(&[0])?; - } - self.offset += padding; - - let value = value.as_std140(); - self.writer.write_all(bytes_of(&value))?; - - let write_here = self.offset; - self.offset += size_of::(); - - Ok(write_here) - } - - /// Write a slice of values to the underlying buffer. - #[deprecated( - since = "0.6.0", - note = "Use `write` instead -- it now works on slices." - )] - pub fn write_slice(&mut self, slice: &[T]) -> io::Result - where - T: AsStd140, - { - self.write(slice) - } - - /// Returns the amount of data written by this `Writer`. - pub fn len(&self) -> usize { - self.offset - } -} diff --git a/crates/bevy_crevice/src/std430.rs b/crates/bevy_crevice/src/std430.rs deleted file mode 100644 index 676c999556..0000000000 --- a/crates/bevy_crevice/src/std430.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Defines traits and types for working with data adhering to GLSL's `std140` -//! layout specification. - -mod primitives; -mod sizer; -mod traits; -#[cfg(feature = "std")] -mod writer; - -pub use self::primitives::*; -pub use self::sizer::*; -pub use self::traits::*; -#[cfg(feature = "std")] -pub use self::writer::*; - -pub use bevy_crevice_derive::AsStd430; diff --git a/crates/bevy_crevice/src/std430/primitives.rs b/crates/bevy_crevice/src/std430/primitives.rs deleted file mode 100644 index 3348e82c7b..0000000000 --- a/crates/bevy_crevice/src/std430/primitives.rs +++ /dev/null @@ -1,173 +0,0 @@ -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; -} - -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 { - ( - $( - #[$doc:meta] align($align:literal) $glsl_name:ident $name:ident <$prim:ident> ($($field:ident),+) - )+ - ) => { - $( - #[$doc] - #[allow(missing_docs)] - #[derive(Debug, Clone, Copy)] - #[repr(C)] - pub struct $name { - $(pub $field: $prim,)+ - } - - unsafe impl Zeroable for $name {} - unsafe impl Pod for $name {} - - unsafe impl Std430 for $name { - const ALIGNMENT: usize = $align; - type Padded = Std430Padded(), $align)}>; - } - - unsafe impl Glsl for $name { - const NAME: &'static str = stringify!($glsl_name); - } - )+ - }; -} - -vectors! { - #[doc = "Corresponds to a GLSL `vec2` in std430 layout."] align(8) vec2 Vec2(x, y) - #[doc = "Corresponds to a GLSL `vec3` in std430 layout."] align(16) vec3 Vec3(x, y, z) - #[doc = "Corresponds to a GLSL `vec4` in std430 layout."] align(16) vec4 Vec4(x, y, z, w) - - #[doc = "Corresponds to a GLSL `ivec2` in std430 layout."] align(8) ivec2 IVec2(x, y) - #[doc = "Corresponds to a GLSL `ivec3` in std430 layout."] align(16) ivec3 IVec3(x, y, z) - #[doc = "Corresponds to a GLSL `ivec4` in std430 layout."] align(16) ivec4 IVec4(x, y, z, w) - - #[doc = "Corresponds to a GLSL `uvec2` in std430 layout."] align(8) uvec2 UVec2(x, y) - #[doc = "Corresponds to a GLSL `uvec3` in std430 layout."] align(16) uvec3 UVec3(x, y, z) - #[doc = "Corresponds to a GLSL `uvec4` in std430 layout."] align(16) uvec4 UVec4(x, y, z, w) - - // bool vectors are disabled due to https://github.com/LPGhatguy/crevice/issues/36 - - // #[doc = "Corresponds to a GLSL `bvec2` in std430 layout."] align(8) bvec2 BVec2(x, y) - // #[doc = "Corresponds to a GLSL `bvec3` in std430 layout."] align(16) bvec3 BVec3(x, y, z) - // #[doc = "Corresponds to a GLSL `bvec4` in std430 layout."] align(16) bvec4 BVec4(x, y, z, w) - - #[doc = "Corresponds to a GLSL `dvec2` in std430 layout."] align(16) dvec2 DVec2(x, y) - #[doc = "Corresponds to a GLSL `dvec3` in std430 layout."] align(32) dvec3 DVec3(x, y, z) - #[doc = "Corresponds to a GLSL `dvec4` in std430 layout."] align(32) dvec4 DVec4(x, y, z, w) -} - -macro_rules! matrices { - ( - $( - #[$doc:meta] - align($align:literal) - $glsl_name:ident $name:ident { - $($field:ident: $field_ty:ty,)+ - } - )+ - ) => { - $( - #[$doc] - #[allow(missing_docs)] - #[derive(Debug, Clone, Copy)] - #[repr(C)] - pub struct $name { - $(pub $field: $field_ty,)+ - } - - unsafe impl Zeroable for $name {} - unsafe impl Pod for $name {} - - 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; - type Padded = Std430Padded(), $align)}>; - } - - unsafe impl Glsl for $name { - const NAME: &'static str = stringify!($glsl_name); - } - )+ - }; -} - -matrices! { - #[doc = "Corresponds to a GLSL `mat2` in std430 layout."] - align(8) - mat2 Mat2 { - x: Vec2, - y: Vec2, - } - - #[doc = "Corresponds to a GLSL `mat3` in std430 layout."] - align(16) - mat3 Mat3 { - x: Vec3, - _pad_x: f32, - y: Vec3, - _pad_y: f32, - z: Vec3, - _pad_z: f32, - } - - #[doc = "Corresponds to a GLSL `mat4` in std430 layout."] - align(16) - mat4 Mat4 { - x: Vec4, - y: Vec4, - z: Vec4, - w: Vec4, - } - - #[doc = "Corresponds to a GLSL `dmat2` in std430 layout."] - align(16) - dmat2 DMat2 { - x: DVec2, - y: DVec2, - } - - #[doc = "Corresponds to a GLSL `dmat3` in std430 layout."] - align(32) - dmat3 DMat3 { - x: DVec3, - _pad_x: f64, - y: DVec3, - _pad_y: f64, - z: DVec3, - _pad_z: f64, - } - - #[doc = "Corresponds to a GLSL `dmat3` in std430 layout."] - align(32) - dmat4 DMat4 { - x: DVec4, - y: DVec4, - z: DVec4, - w: DVec4, - } -} diff --git a/crates/bevy_crevice/src/std430/sizer.rs b/crates/bevy_crevice/src/std430/sizer.rs deleted file mode 100644 index 05203d5577..0000000000 --- a/crates/bevy_crevice/src/std430/sizer.rs +++ /dev/null @@ -1,81 +0,0 @@ -use core::mem::size_of; - -use crate::internal::align_offset; -use crate::std430::{AsStd430, Std430}; - -/** -Type that computes the buffer size needed by a series of `std430` types laid -out. - -This type works well well when paired with `Writer`, precomputing a buffer's -size to alleviate the need to dynamically re-allocate buffers. - -## Example - -```glsl -struct Frob { - vec3 size; - float frobiness; -} - -buffer FROBS { - uint len; - Frob[] frobs; -} frobs; -``` - -``` -use bevy_crevice::std430::{self, AsStd430}; - -#[derive(AsStd430)] -struct Frob { - size: mint::Vector3, - frobiness: f32, -} - -// Many APIs require that buffers contain at least enough space for all -// fixed-size bindiongs to a buffer as well as one element of any arrays, if -// there are any. -let mut sizer = std430::Sizer::new(); -sizer.add::(); -sizer.add::(); - -# fn create_buffer_with_size(size: usize) {} -let buffer = create_buffer_with_size(sizer.len()); -# assert_eq!(sizer.len(), 32); -``` -*/ -pub struct Sizer { - offset: usize, -} - -impl Sizer { - /// Create a new `Sizer`. - pub fn new() -> Self { - Self { offset: 0 } - } - - /// Add a type's necessary padding and size to the `Sizer`. Returns the - /// offset into the buffer where that type would be written. - pub fn add(&mut self) -> usize - where - T: AsStd430, - { - let size = size_of::<::Output>(); - let alignment = ::Output::ALIGNMENT; - let padding = align_offset(self.offset, alignment); - - self.offset += padding; - let write_here = self.offset; - - self.offset += size; - - write_here - } - - /// Returns the number of bytes required to contain all the types added to - /// the `Sizer`. - pub fn len(&self) -> usize { - self.offset - } -} diff --git a/crates/bevy_crevice/src/std430/traits.rs b/crates/bevy_crevice/src/std430/traits.rs deleted file mode 100644 index 04f9f526d7..0000000000 --- a/crates/bevy_crevice/src/std430/traits.rs +++ /dev/null @@ -1,291 +0,0 @@ -use core::mem::{size_of, MaybeUninit}; -#[cfg(feature = "std")] -use std::io::{self, Write}; - -use bytemuck::{bytes_of, Pod, Zeroable}; - -#[cfg(feature = "std")] -use crate::std430::Writer; - -/// Trait implemented for all `std430` primitives. Generally should not be -/// implemented outside this crate. -pub unsafe trait Std430: Copy + Zeroable + Pod { - /// The required alignment of the type. Must be a power of two. - /// - /// This is distinct from the value returned by `std::mem::align_of` because - /// `AsStd430` structs do not use Rust's alignment. This enables them to - /// control and zero their padding bytes, making converting them to and from - /// 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; - /// 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. - /// - /// # Safety - /// This is always safe due to the requirements of [`bytemuck::Pod`] being a - /// prerequisite for this trait. - fn as_bytes(&self) -> &[u8] { - bytes_of(self) - } -} - -unsafe impl Std430 for () { - const ALIGNMENT: usize = 0; - - const PAD_AT_END: bool = false; - - type Padded = (); -} - -/// 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. - -This trait can often be `#[derive]`'d instead of manually implementing it. Any -struct which contains only fields that also implement `AsStd430` can derive -`AsStd430`. - -Types from the mint crate implement `AsStd430`, making them convenient for use -in uniform types. Most Rust geometry crates, like cgmath, nalgebra, and -ultraviolet support mint. - -## Example - -```glsl -uniform CAMERA { - mat4 view; - mat4 projection; -} camera; -``` - -```no_run -use bevy_crevice::std430::{AsStd430, Std430}; - -#[derive(AsStd430)] -struct CameraUniform { - view: mint::ColumnMatrix4, - projection: mint::ColumnMatrix4, -} - -let view: mint::ColumnMatrix4 = todo!("your math code here"); -let projection: mint::ColumnMatrix4 = todo!("your math code here"); - -let camera = CameraUniform { - view, - projection, -}; - -# fn write_to_gpu_buffer(bytes: &[u8]) {} -let camera_std430 = camera.as_std430(); -write_to_gpu_buffer(camera_std430.as_bytes()); -``` -*/ -pub trait AsStd430 { - /// The `std430` version of this value. - type Output: Std430; - - /// Convert this value into the `std430` version of itself. - fn as_std430(&self) -> Self::Output; - - /// Returns the size of the `std430` version of this type. Useful for - /// pre-sizing buffers. - fn std430_size_static() -> usize { - size_of::() - } - - /// Converts from `std430` version of self to self. - fn from_std430(value: Self::Output) -> Self; -} - -impl AsStd430 for T -where - T: Std430, -{ - type Output = Self; - - fn as_std430(&self) -> Self { - *self - } - - fn from_std430(value: Self) -> Self { - value - } -} - -#[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())); - } - - 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. -/// -/// While `AsStd430` requires implementers to return a type that implements the -/// `Std430` trait, `WriteStd430` directly writes bytes using a [`Writer`]. This -/// makes `WriteStd430` usable for writing slices or other DSTs that could not -/// implement `AsStd430` without allocating new memory on the heap. -#[cfg(feature = "std")] -pub trait WriteStd430 { - /// Writes this value into the given [`Writer`] using `std430` layout rules. - /// - /// Should return the offset of the first byte of this type, as returned by - /// the first call to [`Writer::write`]. - fn write_std430(&self, writer: &mut Writer) -> io::Result; - - /// The space required to write this value using `std430` layout rules. This - /// does not include alignment padding that may be needed before or after - /// this type when written as part of a larger buffer. - fn std430_size(&self) -> usize { - let mut writer = Writer::new(io::sink()); - self.write_std430(&mut writer).unwrap(); - writer.len() - } -} - -#[cfg(feature = "std")] -impl WriteStd430 for T -where - T: AsStd430, -{ - fn write_std430(&self, writer: &mut Writer) -> io::Result { - writer.write_std430(&self.as_std430()) - } - - fn std430_size(&self) -> usize { - size_of::<::Output>() - } -} - -#[cfg(feature = "std")] -impl WriteStd430 for [T] -where - T: WriteStd430, -{ - fn write_std430(&self, writer: &mut Writer) -> io::Result { - let mut offset = writer.len(); - - let mut iter = self.iter(); - - if let Some(item) = iter.next() { - offset = item.write_std430(writer)?; - } - - for item in iter { - item.write_std430(writer)?; - } - - Ok(offset) - } - - fn std430_size(&self) -> usize { - let mut writer = Writer::new(io::sink()); - self.write_std430(&mut writer).unwrap(); - writer.len() - } -} diff --git a/crates/bevy_crevice/src/std430/writer.rs b/crates/bevy_crevice/src/std430/writer.rs deleted file mode 100644 index 199ab3ab50..0000000000 --- a/crates/bevy_crevice/src/std430/writer.rs +++ /dev/null @@ -1,150 +0,0 @@ -use std::io::{self, Write}; -use std::mem::size_of; - -use bytemuck::bytes_of; - -use crate::internal::align_offset; -use crate::std430::{AsStd430, Std430, WriteStd430}; - -/** -Type that enables writing correctly aligned `std430` values to a buffer. - -`Writer` is useful when many values need to be laid out in a row that cannot be -represented by a struct alone, like dynamically sized arrays or dynamically -laid-out values. - -## Example -In this example, we'll write a length-prefixed list of lights to a buffer. -`std430::Writer` helps align correctly, even across multiple structs, which can -be tricky and error-prone otherwise. - -```glsl -struct PointLight { - vec3 position; - vec3 color; - float brightness; -}; - -buffer POINT_LIGHTS { - uint len; - PointLight[] lights; -} point_lights; -``` - -``` -use bevy_crevice::std430::{self, AsStd430}; - -#[derive(AsStd430)] -struct PointLight { - position: mint::Vector3, - color: mint::Vector3, - brightness: f32, -} - -let lights = vec![ - PointLight { - position: [0.0, 1.0, 0.0].into(), - color: [1.0, 0.0, 0.0].into(), - brightness: 0.6, - }, - PointLight { - position: [0.0, 4.0, 3.0].into(), - color: [1.0, 1.0, 1.0].into(), - brightness: 1.0, - }, -]; - -# fn map_gpu_buffer_for_write() -> &'static mut [u8] { -# Box::leak(vec![0; 1024].into_boxed_slice()) -# } -let target_buffer = map_gpu_buffer_for_write(); -let mut writer = std430::Writer::new(target_buffer); - -let light_count = lights.len() as u32; -writer.write(&light_count)?; - -// Crevice will automatically insert the required padding to align the -// PointLight structure correctly. In this case, there will be 12 bytes of -// padding between the length field and the light list. - -writer.write(lights.as_slice())?; - -# fn unmap_gpu_buffer() {} -unmap_gpu_buffer(); - -# Ok::<(), std::io::Error>(()) -``` -*/ -pub struct Writer { - writer: W, - offset: usize, -} - -impl Writer { - /// Create a new `Writer`, wrapping a buffer, file, or other type that - /// implements [`std::io::Write`]. - pub fn new(writer: W) -> Self { - Self { writer, offset: 0 } - } - - /// Write a new value to the underlying buffer, writing zeroed padding where - /// necessary. - /// - /// Returns the offset into the buffer that the value was written to. - pub fn write(&mut self, value: &T) -> io::Result - where - T: WriteStd430 + ?Sized, - { - value.write_std430(self) - } - - /// Write an iterator of values to the underlying buffer. - /// - /// Returns the offset into the buffer that the first value was written to. - /// If no values were written, returns the `len()`. - pub fn write_iter(&mut self, iter: I) -> io::Result - where - I: IntoIterator, - T: WriteStd430, - { - let mut offset = self.offset; - - let mut iter = iter.into_iter(); - - if let Some(item) = iter.next() { - offset = item.write_std430(self)?; - } - - for item in iter { - item.write_std430(self)?; - } - - Ok(offset) - } - - /// Write an `Std430` type to the underlying buffer. - pub fn write_std430(&mut self, value: &T) -> io::Result - where - T: Std430, - { - let padding = align_offset(self.offset, T::ALIGNMENT); - - for _ in 0..padding { - self.writer.write_all(&[0])?; - } - self.offset += padding; - - let value = value.as_std430(); - self.writer.write_all(bytes_of(&value))?; - - let write_here = self.offset; - self.offset += size_of::(); - - Ok(write_here) - } - - /// Returns the amount of data written by this `Writer`. - pub fn len(&self) -> usize { - self.offset - } -} diff --git a/crates/bevy_crevice/src/util.rs b/crates/bevy_crevice/src/util.rs deleted file mode 100644 index 9c6c2a3964..0000000000 --- a/crates/bevy_crevice/src/util.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![allow(unused_macros)] - -macro_rules! easy_impl { - ( $( $std_name:ident $imp_ty:ty { $($field:ident),* }, )* ) => { - $( - impl crate::std140::AsStd140 for $imp_ty { - type Output = crate::std140::$std_name; - - #[inline] - fn as_std140(&self) -> Self::Output { - crate::std140::$std_name { - $( - $field: self.$field.as_std140(), - )* - ..bytemuck::Zeroable::zeroed() - } - } - - #[inline] - fn from_std140(value: Self::Output) -> Self { - Self { - $( - $field: <_ as crate::std140::AsStd140>::from_std140(value.$field), - )* - } - } - } - - impl crate::std430::AsStd430 for $imp_ty { - type Output = crate::std430::$std_name; - - #[inline] - fn as_std430(&self) -> Self::Output { - crate::std430::$std_name { - $( - $field: self.$field.as_std430(), - )* - ..bytemuck::Zeroable::zeroed() - } - } - - #[inline] - fn from_std430(value: Self::Output) -> Self { - Self { - $( - $field: <_ as crate::std430::AsStd430>::from_std430(value.$field), - )* - } - } - } - - unsafe impl crate::glsl::Glsl for $imp_ty { - const NAME: &'static str = crate::std140::$std_name::NAME; - } - )* - }; -} - -macro_rules! minty_impl { - ( $( $mint_ty:ty => $imp_ty:ty, )* ) => { - $( - impl crate::std140::AsStd140 for $imp_ty { - type Output = <$mint_ty as crate::std140::AsStd140>::Output; - - #[inline] - fn as_std140(&self) -> Self::Output { - let mint: $mint_ty = (*self).into(); - mint.as_std140() - } - - #[inline] - fn from_std140(value: Self::Output) -> Self { - <$mint_ty>::from_std140(value).into() - } - } - - impl crate::std430::AsStd430 for $imp_ty { - type Output = <$mint_ty as crate::std430::AsStd430>::Output; - - #[inline] - fn as_std430(&self) -> Self::Output { - let mint: $mint_ty = (*self).into(); - mint.as_std430() - } - - #[inline] - fn from_std430(value: Self::Output) -> Self { - <$mint_ty>::from_std430(value).into() - } - } - - unsafe impl crate::glsl::Glsl for $imp_ty { - const NAME: &'static str = <$mint_ty>::NAME; - } - )* - }; -} diff --git a/crates/bevy_crevice/tests/snapshots/test__generate_struct_array_glsl.snap b/crates/bevy_crevice/tests/snapshots/test__generate_struct_array_glsl.snap deleted file mode 100644 index 7829bd64ca..0000000000 --- a/crates/bevy_crevice/tests/snapshots/test__generate_struct_array_glsl.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/test.rs -expression: "TestGlsl::glsl_definition()" - ---- -struct TestGlsl { - vec3 foo[8][4]; -}; diff --git a/crates/bevy_crevice/tests/snapshots/test__generate_struct_glsl.snap b/crates/bevy_crevice/tests/snapshots/test__generate_struct_glsl.snap deleted file mode 100644 index 42fc1f4cd7..0000000000 --- a/crates/bevy_crevice/tests/snapshots/test__generate_struct_glsl.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: tests/test.rs -expression: "TestGlsl::glsl_definition()" - ---- -struct TestGlsl { - vec3 foo; - mat2 bar; -}; diff --git a/crates/bevy_crevice/tests/test.rs b/crates/bevy_crevice/tests/test.rs deleted file mode 100644 index 693ce080c7..0000000000 --- a/crates/bevy_crevice/tests/test.rs +++ /dev/null @@ -1,61 +0,0 @@ -use bevy_crevice::glsl::GlslStruct; -use bevy_crevice::std140::AsStd140; - -#[test] -fn there_and_back_again() { - #[derive(AsStd140, Debug, PartialEq)] - struct ThereAndBackAgain { - view: mint::ColumnMatrix3, - origin: mint::Vector3, - } - - let x = ThereAndBackAgain { - view: mint::ColumnMatrix3 { - x: mint::Vector3 { - x: 1.0, - y: 0.0, - z: 0.0, - }, - y: mint::Vector3 { - x: 0.0, - y: 1.0, - z: 0.0, - }, - z: mint::Vector3 { - x: 0.0, - y: 0.0, - z: 1.0, - }, - }, - origin: mint::Vector3 { - x: 0.0, - y: 1.0, - z: 2.0, - }, - }; - let x_as = x.as_std140(); - assert_eq!(::from_std140(x_as), x); -} - -#[test] -fn generate_struct_glsl() { - #[allow(dead_code)] - #[derive(GlslStruct)] - struct TestGlsl { - foo: mint::Vector3, - bar: mint::ColumnMatrix2, - } - - 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()); -} diff --git a/crates/bevy_encase_derive/Cargo.toml b/crates/bevy_encase_derive/Cargo.toml new file mode 100644 index 0000000000..16e518a573 --- /dev/null +++ b/crates/bevy_encase_derive/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bevy_encase_derive" +version = "0.8.0-dev" +edition = "2021" +description = "Bevy derive macro for encase" +homepage = "https://bevyengine.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[lib] +proc-macro = true + +[dependencies] +bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.8.0-dev" } +encase_derive_impl = "0.2" diff --git a/crates/bevy_encase_derive/src/lib.rs b/crates/bevy_encase_derive/src/lib.rs new file mode 100644 index 0000000000..0ef5c43817 --- /dev/null +++ b/crates/bevy_encase_derive/src/lib.rs @@ -0,0 +1,40 @@ +use bevy_macro_utils::BevyManifest; +use encase_derive_impl::{implement, syn}; + +const BEVY: &str = "bevy"; +const BEVY_RENDER: &str = "bevy_render"; +const ENCASE: &str = "encase"; + +fn bevy_encase_path() -> syn::Path { + let bevy_manifest = BevyManifest::default(); + bevy_manifest + .maybe_get_path(BEVY) + .map(|bevy_path| { + let mut segments = bevy_path.segments; + segments.push(BevyManifest::parse_str("render")); + syn::Path { + leading_colon: None, + segments, + } + }) + .or_else(|| bevy_manifest.maybe_get_path(BEVY_RENDER)) + .map(|bevy_render_path| { + let mut segments = bevy_render_path.segments; + segments.push(BevyManifest::parse_str("render_resource")); + syn::Path { + leading_colon: None, + segments, + } + }) + .map(|path| { + let mut segments = path.segments; + segments.push(BevyManifest::parse_str(ENCASE)); + syn::Path { + leading_colon: None, + segments, + } + }) + .unwrap_or_else(|| bevy_manifest.get_path(ENCASE)) +} + +implement!(bevy_encase_path()); diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 54a74a517d..14e02c8b6c 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -8,10 +8,7 @@ use bevy_render::{ mesh::MeshVertexBufferLayout, prelude::Shader, render_asset::{PrepareAssetError, RenderAsset, RenderAssets}, - render_resource::{ - std140::{AsStd140, Std140}, - *, - }, + render_resource::*, renderer::RenderDevice, texture::Image, }; @@ -140,7 +137,7 @@ bitflags::bitflags! { } /// The GPU representation of the uniform data of a [`StandardMaterial`]. -#[derive(Clone, Default, AsStd140)] +#[derive(Clone, Default, ShaderType)] pub struct StandardMaterialUniformData { /// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything /// in between. @@ -296,12 +293,15 @@ impl RenderAsset for StandardMaterial { flags: flags.bits(), alpha_cutoff, }; - let value_std140 = value.as_std140(); + + let byte_buffer = [0u8; StandardMaterialUniformData::SIZE.get() as usize]; + let mut buffer = encase::UniformBuffer::new(byte_buffer); + buffer.write(&value).unwrap(); let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { label: Some("pbr_standard_material_uniform_buffer"), usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, - contents: value_std140.as_bytes(), + contents: buffer.as_ref(), }); let bind_group = render_device.create_bind_group(&BindGroupDescriptor { entries: &[ @@ -423,9 +423,7 @@ impl SpecializedMaterial for StandardMaterial { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: BufferSize::new( - StandardMaterialUniformData::std140_size_static() as u64, - ), + min_binding_size: Some(StandardMaterialUniformData::min_size()), }, count: None, }, diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index f4b7c5aedd..82c3855e76 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -21,7 +21,7 @@ use bevy_render::{ EntityRenderCommand, PhaseItem, RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass, }, - render_resource::{std140::AsStd140, std430::AsStd430, *}, + render_resource::*, renderer::{RenderContext, RenderDevice, RenderQueue}, texture::*, view::{ @@ -34,7 +34,7 @@ use bevy_utils::{ tracing::{error, warn}, HashMap, }; -use std::num::NonZeroU32; +use std::num::{NonZeroU32, NonZeroU64}; #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] pub enum RenderLightSystems { @@ -78,8 +78,7 @@ pub struct ExtractedDirectionalLight { pub type ExtractedDirectionalLightShadowMap = DirectionalLightShadowMap; -#[repr(C)] -#[derive(Copy, Clone, AsStd140, AsStd430, Default, Debug)] +#[derive(Copy, Clone, ShaderType, Default, Debug)] pub struct GpuPointLight { // The lower-right 2x2 values of the projection matrix 22 23 32 33 projection_lr: Vec4, @@ -90,13 +89,28 @@ pub struct GpuPointLight { shadow_normal_bias: f32, } +#[derive(ShaderType)] +pub struct GpuPointLightsUniform { + data: Box<[GpuPointLight; MAX_UNIFORM_BUFFER_POINT_LIGHTS]>, +} + +impl Default for GpuPointLightsUniform { + fn default() -> Self { + Self { + data: Box::new([GpuPointLight::default(); MAX_UNIFORM_BUFFER_POINT_LIGHTS]), + } + } +} + +#[derive(ShaderType, Default)] +pub struct GpuPointLightsStorage { + #[size(runtime)] + data: Vec, +} + pub enum GpuPointLights { - Uniform { - buffer: UniformVec<[GpuPointLight; MAX_UNIFORM_BUFFER_POINT_LIGHTS]>, - }, - Storage { - buffer: StorageBuffer, - }, + Uniform(UniformBuffer), + Storage(StorageBuffer), } impl GpuPointLights { @@ -108,66 +122,48 @@ impl GpuPointLights { } fn uniform() -> Self { - Self::Uniform { - buffer: UniformVec::default(), - } + Self::Uniform(UniformBuffer::default()) } fn storage() -> Self { - Self::Storage { - buffer: StorageBuffer::default(), - } + Self::Storage(StorageBuffer::default()) } - fn clear(&mut self) { + fn set(&mut self, mut lights: Vec) { match self { - GpuPointLights::Uniform { buffer } => buffer.clear(), - GpuPointLights::Storage { buffer } => buffer.clear(), - } - } - - fn push(&mut self, mut lights: Vec) { - match self { - GpuPointLights::Uniform { buffer } => { - // NOTE: This iterator construction allows moving and padding with default - // values and is like this to avoid unnecessary cloning. - let gpu_point_lights = lights - .drain(..) - .chain(std::iter::repeat_with(GpuPointLight::default)) - .take(MAX_UNIFORM_BUFFER_POINT_LIGHTS) - .collect::>(); - buffer.push(gpu_point_lights.try_into().unwrap()); + GpuPointLights::Uniform(buffer) => { + let len = lights.len().min(MAX_UNIFORM_BUFFER_POINT_LIGHTS); + let src = &lights[..len]; + let dst = &mut buffer.get_mut().data[..len]; + dst.copy_from_slice(src); } - GpuPointLights::Storage { buffer } => { - buffer.append(&mut lights); + GpuPointLights::Storage(buffer) => { + buffer.get_mut().data.clear(); + buffer.get_mut().data.append(&mut lights); } } } fn write_buffer(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) { match self { - GpuPointLights::Uniform { buffer } => buffer.write_buffer(render_device, render_queue), - GpuPointLights::Storage { buffer } => buffer.write_buffer(render_device, render_queue), + GpuPointLights::Uniform(buffer) => buffer.write_buffer(render_device, render_queue), + GpuPointLights::Storage(buffer) => buffer.write_buffer(render_device, render_queue), } } pub fn binding(&self) -> Option { match self { - GpuPointLights::Uniform { buffer } => buffer.binding(), - GpuPointLights::Storage { buffer } => buffer.binding(), + GpuPointLights::Uniform(buffer) => buffer.binding(), + GpuPointLights::Storage(buffer) => buffer.binding(), } } - pub fn len(&self) -> usize { - match self { - GpuPointLights::Uniform { buffer } => buffer.len(), - GpuPointLights::Storage { buffer } => buffer.values().len(), + pub fn min_size(buffer_binding_type: BufferBindingType) -> NonZeroU64 { + match buffer_binding_type { + BufferBindingType::Storage { .. } => GpuPointLightsStorage::min_size(), + BufferBindingType::Uniform => GpuPointLightsUniform::min_size(), } } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } } // NOTE: These must match the bit flags in bevy_pbr2/src/render/pbr.frag! @@ -180,8 +176,7 @@ bitflags::bitflags! { } } -#[repr(C)] -#[derive(Copy, Clone, AsStd140, Default, Debug)] +#[derive(Copy, Clone, ShaderType, Default, Debug)] pub struct GpuDirectionalLight { view_projection: Mat4, color: Vec4, @@ -201,10 +196,8 @@ bitflags::bitflags! { } } -#[repr(C)] -#[derive(Copy, Clone, Debug, AsStd140)] +#[derive(Copy, Clone, Debug, ShaderType)] pub struct GpuLights { - // TODO: this comes first to work around a WGSL alignment issue. We need to solve this issue before releasing the renderer rework directional_lights: [GpuDirectionalLight; MAX_DIRECTIONAL_LIGHTS], ambient_color: Vec4, // xyz are x/y/z cluster dimensions and w is the number of clusters @@ -245,7 +238,7 @@ impl FromWorld for ShadowPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(ViewUniform::std140_size_static() as u64), + min_binding_size: Some(ViewUniform::min_size()), }, count: None, }, @@ -629,7 +622,7 @@ impl GlobalLightMeta { #[derive(Default)] pub struct LightMeta { - pub view_gpu_lights: DynamicUniformVec, + pub view_gpu_lights: DynamicUniformBuffer, pub shadow_view_bind_group: Option, } @@ -688,7 +681,6 @@ pub fn prepare_lights( .map(|CubeMapFace { target, up }| GlobalTransform::identity().looking_at(*target, *up)) .collect::>(); - global_light_meta.gpu_point_lights.clear(); global_light_meta.entity_to_index.clear(); let mut point_lights: Vec<_> = point_lights.iter().collect::>(); @@ -744,7 +736,8 @@ pub fn prepare_lights( }); global_light_meta.entity_to_index.insert(entity, index); } - global_light_meta.gpu_point_lights.push(gpu_point_lights); + + global_light_meta.gpu_point_lights.set(gpu_point_lights); global_light_meta .gpu_point_lights .write_buffer(&render_device, &render_queue); @@ -1027,16 +1020,58 @@ fn pack_offset_and_count(offset: usize, count: usize) -> u32 { | (count as u32 & CLUSTER_COUNT_MASK) } +#[derive(ShaderType)] +struct GpuClusterLightIndexListsUniform { + data: Box<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>, +} + +// NOTE: Assert at compile time that GpuClusterLightIndexListsUniform +// fits within the maximum uniform buffer binding size +const _: () = assert!(GpuClusterLightIndexListsUniform::SIZE.get() <= 16384); + +impl Default for GpuClusterLightIndexListsUniform { + fn default() -> Self { + Self { + data: Box::new([UVec4::ZERO; ViewClusterBindings::MAX_UNIFORM_ITEMS]), + } + } +} + +#[derive(ShaderType)] +struct GpuClusterOffsetsAndCountsUniform { + data: Box<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>, +} + +impl Default for GpuClusterOffsetsAndCountsUniform { + fn default() -> Self { + Self { + data: Box::new([UVec4::ZERO; ViewClusterBindings::MAX_UNIFORM_ITEMS]), + } + } +} + +#[derive(ShaderType, Default)] +struct GpuClusterLightIndexListsStorage { + #[size(runtime)] + data: Vec, +} + +#[derive(ShaderType, Default)] +struct GpuClusterOffsetsAndCountsStorage { + #[size(runtime)] + data: Vec, +} + enum ViewClusterBuffers { Uniform { // NOTE: UVec4 is because all arrays in Std140 layout have 16-byte alignment - cluster_light_index_lists: UniformVec<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>, + cluster_light_index_lists: UniformBuffer, // NOTE: UVec4 is because all arrays in Std140 layout have 16-byte alignment - cluster_offsets_and_counts: UniformVec<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>, + cluster_offsets_and_counts: UniformBuffer, }, Storage { - cluster_light_index_lists: StorageBuffer, - cluster_offsets_and_counts: StorageBuffer, + cluster_light_index_lists: StorageBuffer, + cluster_offsets_and_counts: StorageBuffer, }, } @@ -1050,8 +1085,8 @@ impl ViewClusterBuffers { fn uniform() -> Self { ViewClusterBuffers::Uniform { - cluster_light_index_lists: UniformVec::default(), - cluster_offsets_and_counts: UniformVec::default(), + cluster_light_index_lists: UniformBuffer::default(), + cluster_offsets_and_counts: UniformBuffer::default(), } } @@ -1083,24 +1118,22 @@ impl ViewClusterBindings { } } - pub fn reserve_and_clear(&mut self) { + pub fn clear(&mut self) { match &mut self.buffers { ViewClusterBuffers::Uniform { cluster_light_index_lists, cluster_offsets_and_counts, } => { - cluster_light_index_lists.clear(); - cluster_light_index_lists.push([UVec4::ZERO; Self::MAX_UNIFORM_ITEMS]); - cluster_offsets_and_counts.clear(); - cluster_offsets_and_counts.push([UVec4::ZERO; Self::MAX_UNIFORM_ITEMS]); + *cluster_light_index_lists.get_mut().data = [UVec4::ZERO; Self::MAX_UNIFORM_ITEMS]; + *cluster_offsets_and_counts.get_mut().data = [UVec4::ZERO; Self::MAX_UNIFORM_ITEMS]; } ViewClusterBuffers::Storage { cluster_light_index_lists, cluster_offsets_and_counts, .. } => { - cluster_light_index_lists.clear(); - cluster_offsets_and_counts.clear(); + cluster_light_index_lists.get_mut().data.clear(); + cluster_offsets_and_counts.get_mut().data.clear(); } } } @@ -1119,13 +1152,16 @@ impl ViewClusterBindings { let component = self.n_offsets & ((1 << 2) - 1); let packed = pack_offset_and_count(offset, count); - cluster_offsets_and_counts.get_mut(0)[array_index][component] = packed; + cluster_offsets_and_counts.get_mut().data[array_index][component] = packed; } ViewClusterBuffers::Storage { cluster_offsets_and_counts, .. } => { - cluster_offsets_and_counts.push(UVec2::new(offset as u32, count as u32)); + cluster_offsets_and_counts + .get_mut() + .data + .push(UVec2::new(offset as u32, count as u32)); } } @@ -1147,14 +1183,14 @@ impl ViewClusterBindings { let sub_index = self.n_indices & ((1 << 2) - 1); let index = index as u32 & POINT_LIGHT_INDEX_MASK; - cluster_light_index_lists.get_mut(0)[array_index][component] |= + cluster_light_index_lists.get_mut().data[array_index][component] |= index << (8 * sub_index); } ViewClusterBuffers::Storage { cluster_light_index_lists, .. } => { - cluster_light_index_lists.push(index as u32); + cluster_light_index_lists.get_mut().data.push(index as u32); } } @@ -1205,6 +1241,24 @@ impl ViewClusterBindings { } => cluster_offsets_and_counts.binding(), } } + + pub fn min_size_cluster_light_index_lists( + buffer_binding_type: BufferBindingType, + ) -> NonZeroU64 { + match buffer_binding_type { + BufferBindingType::Storage { .. } => GpuClusterLightIndexListsStorage::min_size(), + BufferBindingType::Uniform => GpuClusterLightIndexListsUniform::min_size(), + } + } + + pub fn min_size_cluster_offsets_and_counts( + buffer_binding_type: BufferBindingType, + ) -> NonZeroU64 { + match buffer_binding_type { + BufferBindingType::Storage { .. } => GpuClusterOffsetsAndCountsStorage::min_size(), + BufferBindingType::Uniform => GpuClusterOffsetsAndCountsUniform::min_size(), + } + } } pub fn prepare_clusters( @@ -1230,7 +1284,7 @@ pub fn prepare_clusters( for (entity, cluster_config, extracted_clusters) in views.iter() { let mut view_clusters_bindings = ViewClusterBindings::new(mesh_pipeline.clustered_forward_buffer_binding_type); - view_clusters_bindings.reserve_and_clear(); + view_clusters_bindings.clear(); let mut indices_full = false; diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index f90d3894bb..1329d16ced 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1,6 +1,6 @@ use crate::{ - GlobalLightMeta, GpuLights, LightMeta, NotShadowCaster, NotShadowReceiver, ShadowPipeline, - ViewClusterBindings, ViewLightsUniformOffset, ViewShadowBindings, + GlobalLightMeta, GpuLights, GpuPointLights, LightMeta, NotShadowCaster, NotShadowReceiver, + ShadowPipeline, ViewClusterBindings, ViewLightsUniformOffset, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, }; use bevy_app::Plugin; @@ -19,7 +19,7 @@ use bevy_render::{ render_asset::RenderAssets, render_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin}, render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, - render_resource::{std140::AsStd140, *}, + render_resource::*, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo}, view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms}, @@ -76,7 +76,7 @@ impl Plugin for MeshRenderPlugin { } } -#[derive(Component, AsStd140, Clone)] +#[derive(Component, ShaderType, Clone)] pub struct MeshUniform { pub transform: Mat4, pub inverse_transpose_model: Mat4, @@ -267,10 +267,7 @@ impl FromWorld for MeshPipeline { let render_device = world.resource::(); let clustered_forward_buffer_binding_type = render_device .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT); - let cluster_min_binding_size = match clustered_forward_buffer_binding_type { - BufferBindingType::Storage { .. } => None, - BufferBindingType::Uniform => BufferSize::new(16384), - }; + let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { entries: &[ // View @@ -280,7 +277,7 @@ impl FromWorld for MeshPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(ViewUniform::std140_size_static() as u64), + min_binding_size: Some(ViewUniform::min_size()), }, count: None, }, @@ -291,7 +288,7 @@ impl FromWorld for MeshPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(GpuLights::std140_size_static() as u64), + min_binding_size: Some(GpuLights::min_size()), }, count: None, }, @@ -344,10 +341,9 @@ impl FromWorld for MeshPipeline { ty: BindingType::Buffer { ty: clustered_forward_buffer_binding_type, has_dynamic_offset: false, - // NOTE (when no storage buffers): Static size for uniform buffers. - // GpuPointLight has a padded size of 64 bytes, so 16384 / 64 = 256 - // point lights max - min_binding_size: cluster_min_binding_size, + min_binding_size: Some(GpuPointLights::min_size( + clustered_forward_buffer_binding_type, + )), }, count: None, }, @@ -358,9 +354,11 @@ impl FromWorld for MeshPipeline { ty: BindingType::Buffer { ty: clustered_forward_buffer_binding_type, has_dynamic_offset: false, - // NOTE (when no storage buffers): With 256 point lights max, indices - // need 8 bits so use u8 - min_binding_size: cluster_min_binding_size, + min_binding_size: Some( + ViewClusterBindings::min_size_cluster_light_index_lists( + clustered_forward_buffer_binding_type, + ), + ), }, count: None, }, @@ -371,12 +369,11 @@ impl FromWorld for MeshPipeline { ty: BindingType::Buffer { ty: clustered_forward_buffer_binding_type, has_dynamic_offset: false, - // NOTE (when no storage buffers): The offset needs to address 16384 - // indices, which needs 14 bits. The count can be at most all 256 lights - // so 8 bits. - // NOTE: Pack the offset into the upper 19 bits and the count into the - // lower 13 bits. - min_binding_size: cluster_min_binding_size, + min_binding_size: Some( + ViewClusterBindings::min_size_cluster_offsets_and_counts( + clustered_forward_buffer_binding_type, + ), + ), }, count: None, }, @@ -390,7 +387,7 @@ impl FromWorld for MeshPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(MeshUniform::std140_size_static() as u64), + min_binding_size: Some(MeshUniform::min_size()), }, count: None, }; @@ -688,7 +685,7 @@ pub fn queue_mesh_bind_group( skinned: None, }; - if let Some(skinned_joints_buffer) = skinned_mesh_uniform.buffer.uniform_buffer() { + if let Some(skinned_joints_buffer) = skinned_mesh_uniform.buffer.buffer() { mesh_bind_group.skinned = Some(render_device.create_bind_group(&BindGroupDescriptor { entries: &[ BindGroupEntry { @@ -712,9 +709,15 @@ pub fn queue_mesh_bind_group( } } +// NOTE: This is using BufferVec because it is using a trick to allow a fixed-size array +// in a uniform buffer to be used like a variable-sized array by only writing the valid data +// into the buffer, knowing the number of valid items starting from the dynamic offset, and +// ignoring the rest, whether they're valid for other dynamic offsets or not. This trick may +// be supported later in encase, and then we should make use of it. + #[derive(Default)] pub struct SkinnedMeshUniform { - pub buffer: UniformVec, + pub buffer: BufferVec, } pub fn prepare_skinned_meshes( diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index df6230dca6..f81e2918b1 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -31,9 +31,9 @@ webgl = ["wgpu/webgl"] bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } -bevy_crevice = { path = "../bevy_crevice", version = "0.8.0-dev", features = ["glam"] } bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_encase_derive = { path = "../bevy_encase_derive", version = "0.8.0-dev" } bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } @@ -67,3 +67,4 @@ flate2 = { version = "1.0.22", optional = true } ruzstd = { version = "0.2.4", optional = true } # For transcoding of UASTC/ETC1S universal formats, and for .basis file support basis-universal = { version = "0.2.0", optional = true } +encase = { version = "0.2", features = ["glam"] } diff --git a/crates/bevy_render/src/render_component.rs b/crates/bevy_render/src/render_component.rs index 7cd3158cb9..673b23c307 100644 --- a/crates/bevy_render/src/render_component.rs +++ b/crates/bevy_render/src/render_component.rs @@ -1,5 +1,5 @@ use crate::{ - render_resource::{std140::AsStd140, DynamicUniformVec}, + render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ComputedVisibility, RenderApp, RenderStage, @@ -58,7 +58,7 @@ impl Default for UniformComponentPlugin { } } -impl Plugin for UniformComponentPlugin { +impl Plugin for UniformComponentPlugin { fn build(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app @@ -69,12 +69,12 @@ impl Plugin for UniformComponentPlugin { } /// Stores all uniforms of the component type. -pub struct ComponentUniforms { - uniforms: DynamicUniformVec, +pub struct ComponentUniforms { + uniforms: DynamicUniformBuffer, } -impl Deref for ComponentUniforms { - type Target = DynamicUniformVec; +impl Deref for ComponentUniforms { + type Target = DynamicUniformBuffer; #[inline] fn deref(&self) -> &Self::Target { @@ -82,14 +82,14 @@ impl Deref for ComponentUniforms { } } -impl ComponentUniforms { +impl ComponentUniforms { #[inline] - pub fn uniforms(&self) -> &DynamicUniformVec { + pub fn uniforms(&self) -> &DynamicUniformBuffer { &self.uniforms } } -impl Default for ComponentUniforms { +impl Default for ComponentUniforms { fn default() -> Self { Self { uniforms: Default::default(), @@ -106,7 +106,7 @@ fn prepare_uniform_components( mut component_uniforms: ResMut>, components: Query<(Entity, &C)>, ) where - C: AsStd140 + Clone, + C: ShaderType + WriteInto + Clone, { component_uniforms.uniforms.clear(); let entities = components diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index 81fa1618df..c09566f716 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -8,7 +8,7 @@ mod pipeline_specializer; mod shader; mod storage_buffer; mod texture; -mod uniform_vec; +mod uniform_buffer; pub use bind_group::*; pub use bind_group_layout::*; @@ -20,7 +20,7 @@ pub use pipeline_specializer::*; pub use shader::*; pub use storage_buffer::*; pub use texture::*; -pub use uniform_vec::*; +pub use uniform_buffer::*; // TODO: decide where re-exports should go pub use wgpu::{ @@ -44,6 +44,11 @@ pub use wgpu::{ VertexStepMode, }; -pub use bevy_crevice::*; +pub mod encase { + pub use bevy_encase_derive::ShaderType; + pub use encase::*; +} + +pub use self::encase::{ShaderType, Size as ShaderSize}; pub use naga::ShaderStage; diff --git a/crates/bevy_render/src/render_resource/storage_buffer.rs b/crates/bevy_render/src/render_resource/storage_buffer.rs index 620676ad81..96c24a2c09 100644 --- a/crates/bevy_render/src/render_resource/storage_buffer.rs +++ b/crates/bevy_render/src/render_resource/storage_buffer.rs @@ -1,42 +1,105 @@ use super::Buffer; use crate::renderer::{RenderDevice, RenderQueue}; -use bevy_crevice::std430::{self, AsStd430, Std430}; -use bevy_utils::tracing::warn; -use std::num::NonZeroU64; -use wgpu::{BindingResource, BufferBinding, BufferDescriptor, BufferUsages}; +use encase::{ + internal::WriteInto, DynamicStorageBuffer as DynamicStorageBufferWrapper, ShaderType, + StorageBuffer as StorageBufferWrapper, +}; +use wgpu::{util::BufferInitDescriptor, BindingResource, BufferBinding, BufferUsages}; -/// A helper for a storage buffer binding with a body, or a variable-sized array, or both. -pub struct StorageBuffer { - body: U, - values: Vec, - scratch: Vec, - storage_buffer: Option, +pub struct StorageBuffer { + value: T, + scratch: StorageBufferWrapper>, + buffer: Option, + capacity: usize, } -impl Default for StorageBuffer { - /// Creates a new [`StorageBuffer`] - /// - /// This does not immediately allocate system/video RAM buffers. - fn default() -> Self { +impl From for StorageBuffer { + fn from(value: T) -> Self { Self { - body: U::default(), - values: Vec::new(), - scratch: Vec::new(), - storage_buffer: None, + value, + scratch: StorageBufferWrapper::new(Vec::new()), + buffer: None, + capacity: 0, } } } -impl StorageBuffer { - // NOTE: AsStd430::std430_size_static() uses size_of internally but trait functions cannot be - // marked as const functions - const BODY_SIZE: usize = std::mem::size_of::(); - const ITEM_SIZE: usize = std::mem::size_of::(); +impl Default for StorageBuffer { + fn default() -> Self { + Self { + value: T::default(), + scratch: StorageBufferWrapper::new(Vec::new()), + buffer: None, + capacity: 0, + } + } +} - /// Gets the reference to the underlying buffer, if one has been allocated. +impl StorageBuffer { #[inline] pub fn buffer(&self) -> Option<&Buffer> { - self.storage_buffer.as_ref() + self.buffer.as_ref() + } + + #[inline] + pub fn binding(&self) -> Option { + Some(BindingResource::Buffer( + self.buffer()?.as_entire_buffer_binding(), + )) + } + + pub fn set(&mut self, value: T) { + self.value = value; + } + + pub fn get(&self) -> &T { + &self.value + } + + pub fn get_mut(&mut self) -> &mut T { + &mut self.value + } + + pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { + self.scratch.write(&self.value).unwrap(); + + let size = self.scratch.as_ref().len(); + + if self.capacity < size { + self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { + label: None, + usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, + contents: self.scratch.as_ref(), + })); + self.capacity = size; + } else if let Some(buffer) = &self.buffer { + queue.write_buffer(buffer, 0, self.scratch.as_ref()); + } + } +} + +pub struct DynamicStorageBuffer { + values: Vec, + scratch: DynamicStorageBufferWrapper>, + buffer: Option, + capacity: usize, +} + +impl Default for DynamicStorageBuffer { + fn default() -> Self { + Self { + values: Vec::new(), + scratch: DynamicStorageBufferWrapper::new(Vec::new()), + buffer: None, + capacity: 0, + } + } +} + +impl DynamicStorageBuffer { + #[inline] + pub fn buffer(&self) -> Option<&Buffer> { + self.buffer.as_ref() } #[inline] @@ -44,171 +107,47 @@ impl StorageBuffer { Some(BindingResource::Buffer(BufferBinding { buffer: self.buffer()?, offset: 0, - size: Some(NonZeroU64::new((self.size()) as u64).unwrap()), + size: Some(T::min_size()), })) } #[inline] - pub fn set_body(&mut self, body: U) { - self.body = body; + pub fn len(&self) -> usize { + self.values.len() } - fn reserve_buffer(&mut self, device: &RenderDevice) -> bool { - let size = self.size(); - if self.storage_buffer.is_none() || size > self.scratch.len() { - self.scratch.resize(size, 0); - self.storage_buffer = Some(device.create_buffer(&BufferDescriptor { - label: None, - size: size as wgpu::BufferAddress, - usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, - mapped_at_creation: false, - })); - true - } else { - false - } + #[inline] + pub fn is_empty(&self) -> bool { + self.values.is_empty() } - fn size(&self) -> usize { - let mut size = 0; - size += Self::BODY_SIZE; - if Self::ITEM_SIZE > 0 { - if size > 0 { - // Pad according to the array item type's alignment - size = (size + ::Output::ALIGNMENT - 1) - & !(::Output::ALIGNMENT - 1); - } - // Variable size arrays must have at least 1 element - size += Self::ITEM_SIZE * self.values.len().max(1); - } - size + #[inline] + pub fn push(&mut self, value: T) -> u32 { + let offset = self.scratch.write(&value).unwrap() as u32; + self.values.push(value); + offset } + #[inline] pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { - self.reserve_buffer(device); - if let Some(storage_buffer) = &self.storage_buffer { - let range = 0..self.size(); - let mut writer = std430::Writer::new(&mut self.scratch[range.clone()]); - let mut offset = 0; - // First write the struct body if there is one - if Self::BODY_SIZE > 0 { - if let Ok(new_offset) = writer.write(&self.body).map_err(|e| warn!("{:?}", e)) { - offset = new_offset; - } - } - if Self::ITEM_SIZE > 0 { - if self.values.is_empty() { - // Zero-out the padding and dummy array item in the case of the array being empty - for i in offset..self.size() { - self.scratch[i] = 0; - } - } else { - // Then write the array. Note that padding bytes may be added between the body - // and the array in order to align the array to the alignment requirements of its - // items - writer - .write(self.values.as_slice()) - .map_err(|e| warn!("{:?}", e)) - .ok(); - } - } - queue.write_buffer(storage_buffer, 0, &self.scratch[range]); + let size = self.scratch.as_ref().len(); + + if self.capacity < size { + self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { + label: None, + usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, + contents: self.scratch.as_ref(), + })); + self.capacity = size; + } else if let Some(buffer) = &self.buffer { + queue.write_buffer(buffer, 0, self.scratch.as_ref()); } } - pub fn values(&self) -> &[T] { - &self.values - } - - pub fn values_mut(&mut self) -> &mut [T] { - &mut self.values - } - #[inline] pub fn clear(&mut self) { self.values.clear(); - } - - #[inline] - pub fn push(&mut self, value: T) { - self.values.push(value); - } - - #[inline] - pub fn append(&mut self, values: &mut Vec) { - self.values.append(values); - } -} - -#[cfg(test)] -mod tests { - use super::StorageBuffer; - use bevy_crevice::std430; - use bevy_crevice::std430::AsStd430; - use bevy_crevice::std430::Std430; - use bevy_math::Vec3; - use bevy_math::Vec4; - - //Note: - //A Vec3 has 12 bytes and needs to be padded to 16 bytes, when converted to std430 - //https://www.w3.org/TR/WGSL/#alignment-and-size - #[derive(AsStd430, Default)] - struct NotInherentlyAligned { - data: Vec3, - } - - //Note: - //A Vec4 has 16 bytes and does not need to be padded to fit in std430 - //https://www.w3.org/TR/WGSL/#alignment-and-size - #[derive(AsStd430)] - struct InherentlyAligned { - data: Vec4, - } - - #[test] - fn storage_buffer_correctly_sized_nonaligned() { - let mut buffer: StorageBuffer = StorageBuffer::default(); - buffer.push(NotInherentlyAligned { data: Vec3::ONE }); - - let actual_size = buffer.size(); - - let data = [NotInherentlyAligned { data: Vec3::ONE }].as_std430(); - let data_as_bytes = data.as_bytes(); - - assert_eq!(actual_size, data_as_bytes.len()); - } - - #[test] - fn storage_buffer_correctly_sized_aligned() { - let mut buffer: StorageBuffer = StorageBuffer::default(); - buffer.push(InherentlyAligned { data: Vec4::ONE }); - - let actual_size = buffer.size(); - - let data = [InherentlyAligned { data: Vec4::ONE }].as_std430(); - let data_as_bytes = data.as_bytes(); - - assert_eq!(actual_size, data_as_bytes.len()); - } - - #[test] - fn storage_buffer_correctly_sized_item_and_body() { - let mut buffer: StorageBuffer = - StorageBuffer::default(); - buffer.push(NotInherentlyAligned { data: Vec3::ONE }); - buffer.set_body(NotInherentlyAligned { data: Vec3::ONE }); - - let calculated_size = buffer.size(); - - //Emulate Write - let mut scratch = Vec::::new(); - scratch.resize(calculated_size, 0); - let mut writer = std430::Writer::new(&mut scratch[0..calculated_size]); - writer - .write(&buffer.body) - .expect("Buffer has enough space to write the body."); - writer - .write(buffer.values.as_slice()) - .expect("Buffer has enough space to write the values."); + self.scratch.as_mut().clear(); + self.scratch.set_offset(0); } } diff --git a/crates/bevy_render/src/render_resource/uniform_buffer.rs b/crates/bevy_render/src/render_resource/uniform_buffer.rs new file mode 100644 index 0000000000..6f9ad642dc --- /dev/null +++ b/crates/bevy_render/src/render_resource/uniform_buffer.rs @@ -0,0 +1,150 @@ +use crate::{ + render_resource::Buffer, + renderer::{RenderDevice, RenderQueue}, +}; +use encase::{ + internal::WriteInto, DynamicUniformBuffer as DynamicUniformBufferWrapper, ShaderType, + UniformBuffer as UniformBufferWrapper, +}; +use wgpu::{util::BufferInitDescriptor, BindingResource, BufferBinding, BufferUsages}; + +pub struct UniformBuffer { + value: T, + scratch: UniformBufferWrapper>, + buffer: Option, +} + +impl From for UniformBuffer { + fn from(value: T) -> Self { + Self { + value, + scratch: UniformBufferWrapper::new(Vec::new()), + buffer: None, + } + } +} + +impl Default for UniformBuffer { + fn default() -> Self { + Self { + value: T::default(), + scratch: UniformBufferWrapper::new(Vec::new()), + buffer: None, + } + } +} + +impl UniformBuffer { + #[inline] + pub fn buffer(&self) -> Option<&Buffer> { + self.buffer.as_ref() + } + + #[inline] + pub fn binding(&self) -> Option { + Some(BindingResource::Buffer( + self.buffer()?.as_entire_buffer_binding(), + )) + } + + pub fn set(&mut self, value: T) { + self.value = value; + } + + pub fn get(&self) -> &T { + &self.value + } + + pub fn get_mut(&mut self) -> &mut T { + &mut self.value + } + + pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { + self.scratch.write(&self.value).unwrap(); + + match &self.buffer { + Some(buffer) => queue.write_buffer(buffer, 0, self.scratch.as_ref()), + None => { + self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { + label: None, + usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM, + contents: self.scratch.as_ref(), + })); + } + } + } +} + +pub struct DynamicUniformBuffer { + values: Vec, + scratch: DynamicUniformBufferWrapper>, + buffer: Option, + capacity: usize, +} + +impl Default for DynamicUniformBuffer { + fn default() -> Self { + Self { + values: Vec::new(), + scratch: DynamicUniformBufferWrapper::new(Vec::new()), + buffer: None, + capacity: 0, + } + } +} + +impl DynamicUniformBuffer { + #[inline] + pub fn buffer(&self) -> Option<&Buffer> { + self.buffer.as_ref() + } + + #[inline] + pub fn binding(&self) -> Option { + Some(BindingResource::Buffer(BufferBinding { + buffer: self.buffer()?, + offset: 0, + size: Some(T::min_size()), + })) + } + + #[inline] + pub fn len(&self) -> usize { + self.values.len() + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.values.is_empty() + } + + #[inline] + pub fn push(&mut self, value: T) -> u32 { + let offset = self.scratch.write(&value).unwrap() as u32; + self.values.push(value); + offset + } + + #[inline] + pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { + let size = self.scratch.as_ref().len(); + + if self.capacity < size { + self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { + label: None, + usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM, + contents: self.scratch.as_ref(), + })); + self.capacity = size; + } else if let Some(buffer) = &self.buffer { + queue.write_buffer(buffer, 0, self.scratch.as_ref()); + } + } + + #[inline] + pub fn clear(&mut self) { + self.values.clear(); + self.scratch.as_mut().clear(); + self.scratch.set_offset(0); + } +} diff --git a/crates/bevy_render/src/render_resource/uniform_vec.rs b/crates/bevy_render/src/render_resource/uniform_vec.rs deleted file mode 100644 index f31e7e258d..0000000000 --- a/crates/bevy_render/src/render_resource/uniform_vec.rs +++ /dev/null @@ -1,166 +0,0 @@ -use crate::{ - render_resource::std140::{self, AsStd140, DynamicUniform, Std140}, - render_resource::Buffer, - renderer::{RenderDevice, RenderQueue}, -}; -use std::num::NonZeroU64; -use wgpu::{BindingResource, BufferBinding, BufferDescriptor, BufferUsages}; - -pub struct UniformVec { - values: Vec, - scratch: Vec, - uniform_buffer: Option, - capacity: usize, - item_size: usize, -} - -impl Default for UniformVec { - fn default() -> Self { - Self { - values: Vec::new(), - scratch: Vec::new(), - uniform_buffer: None, - capacity: 0, - item_size: (T::std140_size_static() + ::Output::ALIGNMENT - 1) - & !(::Output::ALIGNMENT - 1), - } - } -} - -impl UniformVec { - #[inline] - pub fn uniform_buffer(&self) -> Option<&Buffer> { - self.uniform_buffer.as_ref() - } - - #[inline] - pub fn binding(&self) -> Option { - Some(BindingResource::Buffer(BufferBinding { - buffer: self.uniform_buffer()?, - offset: 0, - size: Some(NonZeroU64::new(self.item_size as u64).unwrap()), - })) - } - - #[inline] - pub fn len(&self) -> usize { - self.values.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.values.is_empty() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.capacity - } - - pub fn push(&mut self, value: T) -> usize { - let index = self.values.len(); - self.values.push(value); - index - } - - pub fn get_mut(&mut self, index: usize) -> &mut T { - &mut self.values[index] - } - - pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) -> bool { - if capacity > self.capacity { - self.capacity = capacity; - let size = self.item_size * capacity; - self.scratch.resize(size, 0); - self.uniform_buffer = Some(device.create_buffer(&BufferDescriptor { - label: None, - size: size as wgpu::BufferAddress, - usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM, - mapped_at_creation: false, - })); - true - } else { - false - } - } - - pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { - if self.values.is_empty() { - return; - } - self.reserve(self.values.len(), device); - if let Some(uniform_buffer) = &self.uniform_buffer { - let range = 0..self.item_size * self.values.len(); - let mut writer = std140::Writer::new(&mut self.scratch[range.clone()]); - writer.write(self.values.as_slice()).unwrap(); - queue.write_buffer(uniform_buffer, 0, &self.scratch[range]); - } - } - - pub fn clear(&mut self) { - self.values.clear(); - } - - pub fn values(&self) -> &[T] { - &self.values - } -} - -pub struct DynamicUniformVec { - uniform_vec: UniformVec>, -} - -impl Default for DynamicUniformVec { - fn default() -> Self { - Self { - uniform_vec: Default::default(), - } - } -} - -impl DynamicUniformVec { - #[inline] - pub fn uniform_buffer(&self) -> Option<&Buffer> { - self.uniform_vec.uniform_buffer() - } - - #[inline] - pub fn binding(&self) -> Option { - self.uniform_vec.binding() - } - - #[inline] - pub fn len(&self) -> usize { - self.uniform_vec.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.uniform_vec.is_empty() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.uniform_vec.capacity() - } - - #[inline] - pub fn push(&mut self, value: T) -> u32 { - (self.uniform_vec.push(DynamicUniform(value)) * self.uniform_vec.item_size) as u32 - } - - #[inline] - pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) { - self.uniform_vec.reserve(capacity, device); - } - - #[inline] - pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { - self.uniform_vec.write_buffer(device, queue); - } - - #[inline] - pub fn clear(&mut self) { - self.uniform_vec.clear(); - } -} diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index f5e547b0f8..0403abb461 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -12,7 +12,7 @@ use crate::{ camera::ExtractedCamera, prelude::Image, render_asset::RenderAssets, - render_resource::{std140::AsStd140, DynamicUniformVec, Texture, TextureView}, + render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView}, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, TextureCache}, RenderApp, RenderStage, @@ -83,7 +83,7 @@ pub struct ExtractedView { pub height: u32, } -#[derive(Clone, AsStd140)] +#[derive(Clone, ShaderType)] pub struct ViewUniform { view_proj: Mat4, view: Mat4, @@ -96,7 +96,7 @@ pub struct ViewUniform { #[derive(Default)] pub struct ViewUniforms { - pub uniforms: DynamicUniformVec, + pub uniforms: DynamicUniformBuffer, } #[derive(Component)] diff --git a/crates/bevy_sprite/src/mesh2d/color_material.rs b/crates/bevy_sprite/src/mesh2d/color_material.rs index 5ea84c802c..0721b1a0a6 100644 --- a/crates/bevy_sprite/src/mesh2d/color_material.rs +++ b/crates/bevy_sprite/src/mesh2d/color_material.rs @@ -7,10 +7,7 @@ use bevy_render::{ color::Color, prelude::Shader, render_asset::{PrepareAssetError, RenderAsset, RenderAssets}, - render_resource::{ - std140::{AsStd140, Std140}, - *, - }, + render_resource::*, renderer::RenderDevice, texture::Image, }; @@ -92,7 +89,7 @@ bitflags::bitflags! { } /// The GPU representation of the uniform data of a [`ColorMaterial`]. -#[derive(Clone, Default, AsStd140)] +#[derive(Clone, Default, ShaderType)] pub struct ColorMaterialUniformData { pub color: Vec4, pub flags: u32, @@ -145,12 +142,15 @@ impl RenderAsset for ColorMaterial { color: material.color.as_linear_rgba_f32().into(), flags: flags.bits(), }; - let value_std140 = value.as_std140(); + + let byte_buffer = [0u8; ColorMaterialUniformData::SIZE.get() as usize]; + let mut buffer = encase::UniformBuffer::new(byte_buffer); + buffer.write(&value).unwrap(); let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { label: Some("color_material_uniform_buffer"), usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, - contents: value_std140.as_bytes(), + contents: buffer.as_ref(), }); let bind_group = render_device.create_bind_group(&BindGroupDescriptor { entries: &[ @@ -201,9 +201,7 @@ impl Material2d for ColorMaterial { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: BufferSize::new( - ColorMaterialUniformData::std140_size_static() as u64, - ), + min_binding_size: Some(ColorMaterialUniformData::min_size()), }, count: None, }, diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index eb7f40b751..dee3d52134 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -11,7 +11,7 @@ use bevy_render::{ render_asset::RenderAssets, render_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin}, render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, - render_resource::{std140::AsStd140, *}, + render_resource::*, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo}, view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms}, @@ -71,7 +71,7 @@ impl Plugin for Mesh2dRenderPlugin { } } -#[derive(Component, AsStd140, Clone)] +#[derive(Component, ShaderType, Clone)] pub struct Mesh2dUniform { pub transform: Mat4, pub inverse_transpose_model: Mat4, @@ -134,7 +134,7 @@ impl FromWorld for Mesh2dPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(ViewUniform::std140_size_static() as u64), + min_binding_size: Some(ViewUniform::min_size()), }, count: None, }, @@ -149,7 +149,7 @@ impl FromWorld for Mesh2dPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(Mesh2dUniform::std140_size_static() as u64), + min_binding_size: Some(Mesh2dUniform::min_size()), }, count: None, }], diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 25b155fd65..d41c502475 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -19,7 +19,7 @@ use bevy_render::{ BatchedPhaseItem, DrawFunctions, EntityRenderCommand, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass, }, - render_resource::{std140::AsStd140, *}, + render_resource::*, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, Image}, view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility}, @@ -48,7 +48,7 @@ impl FromWorld for SpritePipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(ViewUniform::std140_size_static() as u64), + min_binding_size: Some(ViewUniform::min_size()), }, count: None, }], diff --git a/crates/bevy_ui/src/render/pipeline.rs b/crates/bevy_ui/src/render/pipeline.rs index d8034632c7..34fce8e548 100644 --- a/crates/bevy_ui/src/render/pipeline.rs +++ b/crates/bevy_ui/src/render/pipeline.rs @@ -1,9 +1,6 @@ use bevy_ecs::prelude::*; use bevy_render::{ - render_resource::{std140::AsStd140, *}, - renderer::RenderDevice, - texture::BevyDefault, - view::ViewUniform, + render_resource::*, renderer::RenderDevice, texture::BevyDefault, view::ViewUniform, }; pub struct UiPipeline { @@ -23,7 +20,7 @@ impl FromWorld for UiPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(ViewUniform::std140_size_static() as u64), + min_binding_size: Some(ViewUniform::min_size()), }, count: None, }], diff --git a/deny.toml b/deny.toml index d004aae6b4..496a48825a 100644 --- a/deny.toml +++ b/deny.toml @@ -7,7 +7,6 @@ yanked = "deny" notice = "deny" ignore = [ "RUSTSEC-2020-0056", # from gilrs v0.8.1 - unmaintained - https://github.com/koute/stdweb/issues/403 - "RUSTSEC-2020-0095", # from crevice dev dependency - unmaintained - https://github.com/johannhof/difference.rs/issues/45 ] [licenses] @@ -15,6 +14,7 @@ unlicensed = "deny" copyleft = "deny" allow = [ "MIT", + "MIT-0", "Apache-2.0", "BSD-3-Clause", "ISC", diff --git a/examples/shader/custom_vertex_attribute.rs b/examples/shader/custom_vertex_attribute.rs index 9453245f8e..989ab6c7df 100644 --- a/examples/shader/custom_vertex_attribute.rs +++ b/examples/shader/custom_vertex_attribute.rs @@ -9,11 +9,10 @@ use bevy::{ mesh::{MeshVertexAttribute, MeshVertexBufferLayout}, render_asset::{PrepareAssetError, RenderAsset}, render_resource::{ - std140::{AsStd140, Std140}, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, Buffer, - BufferBindingType, BufferInitDescriptor, BufferSize, BufferUsages, - RenderPipelineDescriptor, ShaderStages, SpecializedMeshPipelineError, VertexFormat, + BufferBindingType, BufferInitDescriptor, BufferUsages, RenderPipelineDescriptor, + ShaderSize, ShaderStages, ShaderType, SpecializedMeshPipelineError, VertexFormat, }, renderer::RenderDevice, }, @@ -89,8 +88,13 @@ impl RenderAsset for CustomMaterial { (render_device, material_pipeline): &mut SystemParamItem, ) -> Result> { let color = Vec4::from_slice(&extracted_asset.color.as_linear_rgba_f32()); + + let byte_buffer = [0u8; Vec4::SIZE.get() as usize]; + let mut buffer = bevy::render::render_resource::encase::UniformBuffer::new(byte_buffer); + buffer.write(&color).unwrap(); + let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { - contents: color.as_std140().as_bytes(), + contents: buffer.as_ref(), label: None, usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, }); @@ -130,7 +134,7 @@ impl Material for CustomMaterial { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: BufferSize::new(Vec4::std140_size_static() as u64), + min_binding_size: Some(Vec4::min_size()), }, count: None, }], diff --git a/examples/shader/shader_material.rs b/examples/shader/shader_material.rs index d0eae8481f..5ef4c0ed3f 100644 --- a/examples/shader/shader_material.rs +++ b/examples/shader/shader_material.rs @@ -8,10 +8,10 @@ use bevy::{ render::{ render_asset::{PrepareAssetError, RenderAsset}, render_resource::{ - std140::{AsStd140, Std140}, - BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, + encase, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, Buffer, - BufferBindingType, BufferInitDescriptor, BufferSize, BufferUsages, ShaderStages, + BufferBindingType, BufferInitDescriptor, BufferUsages, ShaderSize, ShaderStages, + ShaderType, }, renderer::RenderDevice, }, @@ -75,8 +75,13 @@ impl RenderAsset for CustomMaterial { (render_device, material_pipeline): &mut SystemParamItem, ) -> Result> { let color = Vec4::from_slice(&extracted_asset.color.as_linear_rgba_f32()); + + let byte_buffer = [0u8; Vec4::SIZE.get() as usize]; + let mut buffer = encase::UniformBuffer::new(byte_buffer); + buffer.write(&color).unwrap(); + let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { - contents: color.as_std140().as_bytes(), + contents: buffer.as_ref(), label: None, usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, }); @@ -123,7 +128,7 @@ impl Material for CustomMaterial { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: BufferSize::new(Vec4::std140_size_static() as u64), + min_binding_size: Some(Vec4::min_size()), }, count: None, }], diff --git a/examples/shader/shader_material_glsl.rs b/examples/shader/shader_material_glsl.rs index c09ea8b2ba..df74841af3 100644 --- a/examples/shader/shader_material_glsl.rs +++ b/examples/shader/shader_material_glsl.rs @@ -8,10 +8,7 @@ use bevy::{ render::{ mesh::MeshVertexBufferLayout, render_asset::{PrepareAssetError, RenderAsset}, - render_resource::{ - std140::{AsStd140, Std140}, - *, - }, + render_resource::*, renderer::RenderDevice, }, }; @@ -72,8 +69,13 @@ impl RenderAsset for CustomMaterial { (render_device, material_pipeline): &mut SystemParamItem, ) -> Result> { let color = Vec4::from_slice(&extracted_asset.color.as_linear_rgba_f32()); + + let byte_buffer = [0u8; Vec4::SIZE.get() as usize]; + let mut buffer = encase::UniformBuffer::new(byte_buffer); + buffer.write(&color).unwrap(); + let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { - contents: color.as_std140().as_bytes(), + contents: buffer.as_ref(), label: None, usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, }); @@ -129,7 +131,7 @@ impl SpecializedMaterial for CustomMaterial { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: BufferSize::new(Vec4::std140_size_static() as u64), + min_binding_size: Some(Vec4::min_size()), }, count: None, }], diff --git a/tools/publish.sh b/tools/publish.sh index 124e63d0dc..06737f1fb3 100644 --- a/tools/publish.sh +++ b/tools/publish.sh @@ -20,8 +20,7 @@ crates=( bevy_hierarchy bevy_transform bevy_window - bevy_crevice/bevy-crevice-derive - bevy_crevice + bevy_encase_derive bevy_render bevy_core_pipeline bevy_input