diff --git a/Cargo.toml b/Cargo.toml index 1e3040f0bda6da..18d6c8a002a65b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,6 +118,7 @@ rand = "0.8.0" ron = "0.7.0" serde = { version = "1", features = ["derive"] } bytemuck = "1.7" +encase = { git = "https://github.com/teoxoy/encase", features = ["glam"] } # Needed to poll Task examples futures-lite = "1.11.3" crossbeam-channel = "0.5.0" diff --git a/crates/bevy_crevice/Cargo.toml b/crates/bevy_crevice/Cargo.toml deleted file mode 100644 index 6ab98134a8440d..00000000000000 --- 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 d42ecff58bc87f..00000000000000 --- 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 32c2307fc6753d..00000000000000 --- 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 a5c16f69c75a0e..00000000000000 --- 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 42ca95cfb80dc5..00000000000000 --- 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 cc0042ae38244f..00000000000000 --- 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 dee33477c23507..00000000000000 --- 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 899343632bb030..00000000000000 --- 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 183bf209f4f599..00000000000000 --- 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 7d7a6bbec14a5a..00000000000000 --- 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 a91703e4ffef51..00000000000000 --- 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 2f0516e4abd532..00000000000000 --- 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 203afced8e2e6b..00000000000000 --- 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 d6b1c48b636071..00000000000000 --- 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 af49bd8915bbfe..00000000000000 --- 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 79ee7e071cec2c..00000000000000 --- 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 58ef711c278556..00000000000000 --- 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 056a181c2ca700..00000000000000 --- 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 3d1b89c0d315b4..00000000000000 --- 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 cd22972fb30aaa..00000000000000 --- 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 48451966be4a54..00000000000000 --- 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 dd7cde1cabf40f..00000000000000 --- 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 262f8ea449842b..00000000000000 --- 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 34e161e3b78184..00000000000000 --- 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 87c27cb63b3d91..00000000000000 --- 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 392251c3f80ece..00000000000000 --- 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 aeed06ff78e9b5..00000000000000 --- 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 676c999556c11d..00000000000000 --- 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 3348e82c7b2c65..00000000000000 --- 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 05203d5577d9c1..00000000000000 --- 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 04f9f526d7f3a8..00000000000000 --- 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 199ab3ab50abcc..00000000000000 --- 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 9c6c2a396450de..00000000000000 --- 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 7829bd64ca1410..00000000000000 --- 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 42fc1f4cd770ee..00000000000000 --- 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 693ce080c7f127..00000000000000 --- 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_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 37107c44d433a4..5ffb8b03ab9c02 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -28,3 +28,4 @@ bevy_window = { path = "../bevy_window", version = "0.8.0-dev" } bitflags = "1.2" # direct dependency required for derive macro bytemuck = { version = "1", features = ["derive"] } +encase = { git = "https://github.com/teoxoy/encase", features = ["glam"] } \ No newline at end of file diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 65362c5b14d132..3f498f15ce5548 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -8,13 +8,11 @@ use bevy_render::{ mesh::MeshVertexBufferLayout, prelude::Shader, render_asset::{PrepareAssetError, RenderAsset, RenderAssets}, - render_resource::{ - std140::{AsStd140, Std140}, - *, - }, + render_resource::*, renderer::RenderDevice, texture::Image, }; +use encase::ShaderType; /// A material with "standard" properties used in PBR lighting /// Standard property values with pictures here @@ -135,7 +133,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. @@ -291,12 +289,15 @@ impl RenderAsset for StandardMaterial { flags: flags.bits(), alpha_cutoff, }; - let value_std140 = value.as_std140(); + + let byte_buffer = [0; ::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: &[ @@ -418,9 +419,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 d3fafd0e018d17..441068c71f9b5f 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,6 +34,7 @@ use bevy_utils::{ tracing::{error, warn}, HashMap, }; +use encase::ShaderType; use std::num::NonZeroU32; #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] @@ -80,8 +81,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, @@ -92,13 +92,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 { @@ -110,66 +125,41 @@ 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(), - } - } - - pub fn len(&self) -> usize { - match self { - GpuPointLights::Uniform { buffer } => buffer.len(), - GpuPointLights::Storage { buffer } => buffer.values().len(), + GpuPointLights::Uniform(buffer) => buffer.binding(), + GpuPointLights::Storage(buffer) => buffer.binding(), } } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } } // NOTE: These must match the bit flags in bevy_pbr2/src/render/pbr.frag! @@ -182,8 +172,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, @@ -203,10 +192,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 @@ -247,7 +234,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, }, @@ -633,7 +620,7 @@ impl GlobalLightMeta { #[derive(Default)] pub struct LightMeta { - pub view_gpu_lights: DynamicUniformVec, + pub view_gpu_lights: DynamicUniformBuffer, pub shadow_view_bind_group: Option, } @@ -692,7 +679,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::>(); @@ -748,7 +734,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); @@ -1035,16 +1022,56 @@ fn pack_offset_and_count(offset: usize, count: usize) -> u32 { | (count as u32 & CLUSTER_COUNT_MASK) } +#[derive(ShaderType)] +pub struct GpuClusterLightIndexListsUniform { + data: Box<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>, +} + +const _: () = assert!(::SIZE.get() <= 16384); + +impl Default for GpuClusterLightIndexListsUniform { + fn default() -> Self { + Self { + data: Box::new([UVec4::ZERO; ViewClusterBindings::MAX_UNIFORM_ITEMS]), + } + } +} + +#[derive(ShaderType)] +pub 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)] +pub struct GpuClusterLightIndexListsStorage { + #[size(runtime)] + data: Vec, +} + +#[derive(ShaderType, Default)] +pub 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, }, } @@ -1058,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(), } } @@ -1091,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(); } } } @@ -1127,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)); } } @@ -1155,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); } } @@ -1238,7 +1266,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 2ccc6fde6c37dd..1a7785ce5699dd 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -19,21 +19,19 @@ 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}, RenderApp, RenderStage, }; use bevy_transform::components::GlobalTransform; -use std::num::NonZeroU64; +use encase::ShaderType; #[derive(Default)] pub struct MeshRenderPlugin; const MAX_JOINTS: usize = 256; -const JOINT_SIZE: usize = std::mem::size_of::(); -pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE; pub const MESH_VIEW_BIND_GROUP_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 9076678235888822571); @@ -62,21 +60,20 @@ impl Plugin for MeshRenderPlugin { load_internal_asset!(app, SKINNING_HANDLE, "skinning.wgsl", Shader::from_wgsl); app.add_plugin(UniformComponentPlugin::::default()); + app.add_plugin(UniformComponentPlugin::::default()); if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .init_resource::() - .init_resource::() .add_system_to_stage(RenderStage::Extract, extract_meshes) .add_system_to_stage(RenderStage::Extract, extract_skinned_meshes) - .add_system_to_stage(RenderStage::Prepare, prepare_skinned_meshes) .add_system_to_stage(RenderStage::Queue, queue_mesh_bind_group) .add_system_to_stage(RenderStage::Queue, queue_mesh_view_bind_groups); } } } -#[derive(Component, AsStd140, Clone)] +#[derive(Component, ShaderType, Clone)] pub struct MeshUniform { pub transform: Mat4, pub inverse_transpose_model: Mat4, @@ -170,85 +167,47 @@ pub fn extract_meshes( commands.insert_or_spawn_batch(not_caster_values); } -#[derive(Debug, Default)] -pub struct ExtractedJoints { - pub buffer: Vec, -} - -#[derive(Component)] -pub struct SkinnedMeshJoints { - pub index: u32, -} - -impl SkinnedMeshJoints { - #[inline] - pub fn build( - skin: &SkinnedMesh, - inverse_bindposes: &Assets, - joints: &Query<&GlobalTransform>, - buffer: &mut Vec, - ) -> Option { - let inverse_bindposes = inverse_bindposes.get(&skin.inverse_bindposes)?; - let bindposes = inverse_bindposes.iter(); - let skin_joints = skin.joints.iter(); - let start = buffer.len(); - for (inverse_bindpose, joint) in bindposes.zip(skin_joints).take(MAX_JOINTS) { - if let Ok(joint) = joints.get(*joint) { - buffer.push(joint.compute_affine() * *inverse_bindpose); - } else { - buffer.truncate(start); - return None; - } - } - - // Pad to 256 byte alignment - while buffer.len() % 4 != 0 { - buffer.push(Mat4::ZERO); - } - Some(Self { - index: start as u32, - }) - } - - pub fn to_buffer_index(mut self) -> Self { - self.index *= std::mem::size_of::() as u32; - self - } -} - pub fn extract_skinned_meshes( query: Query<(Entity, &ComputedVisibility, &SkinnedMesh)>, inverse_bindposes: Res>, joint_query: Query<&GlobalTransform>, mut commands: Commands, mut previous_len: Local, - mut previous_joint_len: Local, ) { let mut values = Vec::with_capacity(*previous_len); - let mut joints = Vec::with_capacity(*previous_joint_len); - let mut last_start = 0; for (entity, computed_visibility, skin) in query.iter() { if !computed_visibility.is_visible { continue; } // PERF: This can be expensive, can we move this to prepare? - if let Some(skinned_joints) = - SkinnedMeshJoints::build(skin, &inverse_bindposes, &joint_query, &mut joints) - { - last_start = last_start.max(skinned_joints.index as usize); - values.push((entity, (skinned_joints.to_buffer_index(),))); + if let Some(inverse_bindposes) = inverse_bindposes.get(&skin.inverse_bindposes) { + let bindposes = inverse_bindposes.iter(); + let skin_joints = skin.joints.iter(); + let entity_joints = bindposes + .zip(skin_joints) + .map(|(inverse_bindpose, joint)| { + joint_query + .get(*joint) + .ok() + .map(|joint| joint.compute_affine() * *inverse_bindpose) + }) + .chain(std::iter::from_fn(|| Some(Some(Mat4::default())))) + .take(MAX_JOINTS) + .collect::>>(); + + if let Some(entity_joints) = entity_joints { + values.push(( + entity, + (SkinnedMeshUniform { + joints: Box::new(entity_joints.try_into().unwrap()), + },), + )); + } } } - // Pad out the buffer to ensure that there's enough space for bindings - while joints.len() - last_start < MAX_JOINTS { - joints.push(Mat4::ZERO); - } - *previous_len = values.len(); - *previous_joint_len = joints.len(); - commands.insert_resource(ExtractedJoints { buffer: joints }); commands.insert_or_spawn_batch(values); } @@ -267,10 +226,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 +236,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 +247,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 +300,12 @@ 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(match clustered_forward_buffer_binding_type { + BufferBindingType::Storage { .. } => { + crate::GpuPointLightsStorage::min_size() + } + BufferBindingType::Uniform => crate::GpuPointLightsUniform::min_size(), + }), }, count: None, }, @@ -358,9 +316,14 @@ 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(match clustered_forward_buffer_binding_type { + BufferBindingType::Storage { .. } => { + crate::GpuClusterLightIndexListsStorage::min_size() + } + BufferBindingType::Uniform => { + crate::GpuClusterLightIndexListsUniform::min_size() + } + }), }, count: None, }, @@ -371,12 +334,14 @@ 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(match clustered_forward_buffer_binding_type { + BufferBindingType::Storage { .. } => { + crate::GpuClusterOffsetsAndCountsStorage::min_size() + } + BufferBindingType::Uniform => { + crate::GpuClusterOffsetsAndCountsUniform::min_size() + } + }), }, count: None, }, @@ -390,7 +355,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(crate::MeshUniform::min_size()), }, count: None, }; @@ -410,7 +375,7 @@ impl FromWorld for MeshPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(JOINT_BUFFER_SIZE as u64), + min_binding_size: Some(crate::SkinnedMeshUniform::min_size()), }, count: None, }, @@ -668,7 +633,7 @@ pub fn queue_mesh_bind_group( mesh_pipeline: Res, render_device: Res, mesh_uniforms: Res>, - skinned_mesh_uniform: Res, + skinned_mesh_uniform: Res>, ) { if let Some(mesh_binding) = mesh_uniforms.uniforms().binding() { let mut mesh_bind_group = MeshBindGroup { @@ -683,7 +648,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_mesh_binding) = skinned_mesh_uniform.uniforms().binding() { mesh_bind_group.skinned = Some(render_device.create_bind_group(&BindGroupDescriptor { entries: &[ BindGroupEntry { @@ -692,11 +657,7 @@ pub fn queue_mesh_bind_group( }, BindGroupEntry { binding: 1, - resource: BindingResource::Buffer(BufferBinding { - buffer: skinned_joints_buffer, - offset: 0, - size: Some(NonZeroU64::new(JOINT_BUFFER_SIZE as u64).unwrap()), - }), + resource: skinned_mesh_binding, }, ], label: Some("skinned_mesh_bind_group"), @@ -707,31 +668,19 @@ pub fn queue_mesh_bind_group( } } -#[derive(Default)] +#[derive(Component, ShaderType, Clone)] pub struct SkinnedMeshUniform { - pub buffer: UniformVec, + joints: Box<[Mat4; MAX_JOINTS]>, } -pub fn prepare_skinned_meshes( - render_device: Res, - render_queue: Res, - extracted_joints: Res, - mut skinned_mesh_uniform: ResMut, -) { - if extracted_joints.buffer.is_empty() { - return; - } +const _: () = assert!(::SIZE.get() <= 16384); - skinned_mesh_uniform.buffer.clear(); - skinned_mesh_uniform - .buffer - .reserve(extracted_joints.buffer.len(), &render_device); - for joint in extracted_joints.buffer.iter() { - skinned_mesh_uniform.buffer.push(*joint); +impl Default for SkinnedMeshUniform { + fn default() -> Self { + Self { + joints: Box::new([Mat4::default(); MAX_JOINTS]), + } } - skinned_mesh_uniform - .buffer - .write_buffer(&render_device, &render_queue); } #[derive(Component)] @@ -843,7 +792,7 @@ impl EntityRenderCommand for SetMeshBindGroup { SRes, SQuery<( Read>, - Option>, + Option>>, )>, ); #[inline] @@ -858,7 +807,7 @@ impl EntityRenderCommand for SetMeshBindGroup { pass.set_bind_group( I, mesh_bind_group.into_inner().skinned.as_ref().unwrap(), - &[mesh_index.index(), joints.index], + &[mesh_index.index(), joints.index()], ); } else { pass.set_bind_group( diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index df6230dca6d074..6ce977f3f8b36d 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -31,7 +31,6 @@ 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_math = { path = "../bevy_math", version = "0.8.0-dev" } @@ -67,3 +66,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 = { git = "https://github.com/teoxoy/encase", features = ["glam"] } diff --git a/crates/bevy_render/src/render_component.rs b/crates/bevy_render/src/render_component.rs index 8d15f2476d6ae8..17f6072a03b5f0 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::DynamicUniformBuffer, renderer::{RenderDevice, RenderQueue}, RenderApp, RenderStage, }; @@ -11,6 +11,7 @@ use bevy_ecs::{ query::{QueryItem, WorldQuery}, system::{lifetimeless::Read, StaticSystemParam}, }; +use encase::{internal::WriteInto, ShaderType}; use std::{marker::PhantomData, ops::Deref}; /// Stores the index of a uniform inside of [`ComponentUniforms`]. @@ -57,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 @@ -68,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 { @@ -81,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(), @@ -105,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 81fa1618dfc8e9..00b4cb270fc7aa 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,4 @@ pub use wgpu::{ VertexStepMode, }; -pub use bevy_crevice::*; - 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 b0015f1c3d9413..96c24a2c090eb3 100644 --- a/crates/bevy_render/src/render_resource/storage_buffer.rs +++ b/crates/bevy_render/src/render_resource/storage_buffer.rs @@ -1,141 +1,153 @@ 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}; - -/// 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, +use encase::{ + internal::WriteInto, DynamicStorageBuffer as DynamicStorageBufferWrapper, ShaderType, + StorageBuffer as StorageBufferWrapper, +}; +use wgpu::{util::BufferInitDescriptor, BindingResource, BufferBinding, BufferUsages}; + +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(BufferBinding { - buffer: self.buffer()?, - offset: 0, - size: Some(NonZeroU64::new((self.size()) as u64).unwrap()), - })) + Some(BindingResource::Buffer( + self.buffer()?.as_entire_buffer_binding(), + )) } - #[inline] - pub fn set_body(&mut self, body: U) { - self.body = body; + pub fn set(&mut self, value: T) { + self.value = value; } - 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 { + 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, - size: size as wgpu::BufferAddress, usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, - mapped_at_creation: false, + contents: self.scratch.as_ref(), })); - true - } else { - false + 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, +} - 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); +impl Default for DynamicStorageBuffer { + fn default() -> Self { + Self { + values: Vec::new(), + scratch: DynamicStorageBufferWrapper::new(Vec::new()), + buffer: None, + capacity: 0, } - size } +} - 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]); - } +impl DynamicStorageBuffer { + #[inline] + pub fn buffer(&self) -> Option<&Buffer> { + self.buffer.as_ref() } - pub fn values(&self) -> &[T] { - &self.values + #[inline] + pub fn binding(&self) -> Option { + Some(BindingResource::Buffer(BufferBinding { + buffer: self.buffer()?, + offset: 0, + size: Some(T::min_size()), + })) } - pub fn values_mut(&mut self) -> &mut [T] { - &mut self.values + #[inline] + pub fn len(&self) -> usize { + self.values.len() } #[inline] - pub fn clear(&mut self) { - self.values.clear(); + pub fn is_empty(&self) -> bool { + self.values.is_empty() } #[inline] - pub fn push(&mut self, value: T) { + 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 append(&mut self, values: &mut Vec) { - self.values.append(values); + 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::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()); + } + } + + #[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_buffer.rs b/crates/bevy_render/src/render_resource/uniform_buffer.rs new file mode 100644 index 00000000000000..6f9ad642dcc489 --- /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 f31e7e258d6a26..00000000000000 --- 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 e6760974b78cf8..f8ae5676f842fd 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -1,6 +1,7 @@ pub mod visibility; pub mod window; +use encase::ShaderType; pub use visibility::*; use wgpu::{ Color, Extent3d, Operations, RenderPassColorAttachment, TextureDescriptor, TextureDimension, @@ -12,7 +13,7 @@ use crate::{ camera::ExtractedCamera, prelude::Image, render_asset::RenderAssets, - render_resource::{std140::AsStd140, DynamicUniformVec, Texture, TextureView}, + render_resource::{DynamicUniformBuffer, Texture, TextureView}, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, TextureCache}, RenderApp, RenderStage, @@ -85,7 +86,7 @@ pub struct ExtractedView { pub far: f32, } -#[derive(Clone, AsStd140)] +#[derive(Clone, ShaderType)] pub struct ViewUniform { view_proj: Mat4, view: Mat4, @@ -100,7 +101,7 @@ pub struct ViewUniform { #[derive(Default)] pub struct ViewUniforms { - pub uniforms: DynamicUniformVec, + pub uniforms: DynamicUniformBuffer, } #[derive(Component)] diff --git a/crates/bevy_sprite/Cargo.toml b/crates/bevy_sprite/Cargo.toml index 238fe048b2f371..db2e539980997c 100644 --- a/crates/bevy_sprite/Cargo.toml +++ b/crates/bevy_sprite/Cargo.toml @@ -31,3 +31,4 @@ rectangle-pack = "0.4" serde = { version = "1", features = ["derive"] } bitflags = "1.2" copyless = "0.1.5" +encase = { git = "https://github.com/teoxoy/encase", features = ["glam"] } \ No newline at end of file diff --git a/crates/bevy_sprite/src/mesh2d/color_material.rs b/crates/bevy_sprite/src/mesh2d/color_material.rs index 5ea84c802c8e9c..d1ed5c6441440d 100644 --- a/crates/bevy_sprite/src/mesh2d/color_material.rs +++ b/crates/bevy_sprite/src/mesh2d/color_material.rs @@ -7,13 +7,11 @@ use bevy_render::{ color::Color, prelude::Shader, render_asset::{PrepareAssetError, RenderAsset, RenderAssets}, - render_resource::{ - std140::{AsStd140, Std140}, - *, - }, + render_resource::*, renderer::RenderDevice, texture::Image, }; +use encase::ShaderType; use crate::{Material2d, Material2dPipeline, Material2dPlugin, MaterialMesh2dBundle}; @@ -92,7 +90,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 +143,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 = [0; ::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 +202,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 47c4efbbb2c1c3..86667978e3729f 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -11,13 +11,14 @@ 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}, RenderApp, RenderStage, }; use bevy_transform::components::GlobalTransform; +use encase::ShaderType; /// Component for rendering with meshes in the 2d pipeline, usually with a [2d material](crate::Material2d) such as [`ColorMaterial`](crate::ColorMaterial). /// @@ -71,7 +72,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 +135,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 +150,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 25b155fd6531fe..5d99c1208667c3 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}, @@ -30,6 +30,7 @@ use bevy_utils::FloatOrd; use bevy_utils::HashMap; use bytemuck::{Pod, Zeroable}; use copyless::VecHelper; +use encase::ShaderType; pub struct SpritePipeline { view_layout: BindGroupLayout, @@ -48,7 +49,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/Cargo.toml b/crates/bevy_ui/Cargo.toml index 2997283d94d7ae..fe07f1b1354c21 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -31,3 +31,4 @@ stretch = "0.3.2" serde = { version = "1", features = ["derive"] } smallvec = { version = "1.6", features = ["union", "const_generics"] } bytemuck = { version = "1.5", features = ["derive"] } +encase = { git = "https://github.com/teoxoy/encase", features = ["glam"] } diff --git a/crates/bevy_ui/src/render/pipeline.rs b/crates/bevy_ui/src/render/pipeline.rs index d8034632c701b8..0e04088d601419 100644 --- a/crates/bevy_ui/src/render/pipeline.rs +++ b/crates/bevy_ui/src/render/pipeline.rs @@ -1,10 +1,8 @@ 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, }; +use encase::ShaderType; pub struct UiPipeline { pub view_layout: BindGroupLayout, @@ -23,7 +21,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 d004aae6b4076c..496a48825a3db2 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 44ef9d0a185534..77287d15db294d 100644 --- a/examples/shader/custom_vertex_attribute.rs +++ b/examples/shader/custom_vertex_attribute.rs @@ -7,11 +7,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, + ShaderStages, SpecializedMeshPipelineError, VertexFormat, }, renderer::RenderDevice, }, @@ -87,8 +86,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 = [0; ::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, }); @@ -128,7 +132,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 97db298ddaf9a3..58c158e36da6da 100644 --- a/examples/shader/shader_material.rs +++ b/examples/shader/shader_material.rs @@ -6,10 +6,9 @@ use bevy::{ render::{ render_asset::{PrepareAssetError, RenderAsset}, render_resource::{ - std140::{AsStd140, Std140}, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, Buffer, - BufferBindingType, BufferInitDescriptor, BufferSize, BufferUsages, ShaderStages, + BufferBindingType, BufferInitDescriptor, BufferUsages, ShaderStages, }, renderer::RenderDevice, }, @@ -73,8 +72,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 = [0; ::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, }); @@ -121,7 +125,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 7e405157ce99f2..c7c83f74315c2e 100644 --- a/examples/shader/shader_material_glsl.rs +++ b/examples/shader/shader_material_glsl.rs @@ -6,10 +6,7 @@ use bevy::{ render::{ mesh::MeshVertexBufferLayout, render_asset::{PrepareAssetError, RenderAsset}, - render_resource::{ - std140::{AsStd140, Std140}, - *, - }, + render_resource::*, renderer::RenderDevice, }, }; @@ -70,8 +67,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 = [0; ::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, }); @@ -127,7 +129,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 67b17c3ab0492d..85a71ee75813f4 100644 --- a/tools/publish.sh +++ b/tools/publish.sh @@ -19,8 +19,6 @@ crates=( bevy_hierarchy bevy_transform bevy_window - bevy_crevice/bevy-crevice-derive - bevy_crevice bevy_render bevy_core_pipeline bevy_input