diff --git a/Cargo.toml b/Cargo.toml index dd904e1217590..1b20db33cd6cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -217,6 +217,7 @@ common_api = [ "bevy_image", "bevy_mesh", "bevy_shader", + "bevy_material", "bevy_text", "hdr", "png", @@ -374,6 +375,9 @@ bevy_light = ["bevy_internal/bevy_light"] # Provides shaders usable through asset handles. bevy_shader = ["bevy_internal/bevy_shader"] +# Provides materials. +bevy_material = ["bevy_internal/bevy_material"] + # Adds support for gizmos bevy_gizmos = ["bevy_internal/bevy_gizmos"] diff --git a/crates/bevy_core_pipeline/Cargo.toml b/crates/bevy_core_pipeline/Cargo.toml index 33ab74f745780..13860bf03aee7 100644 --- a/crates/bevy_core_pipeline/Cargo.toml +++ b/crates/bevy_core_pipeline/Cargo.toml @@ -40,9 +40,6 @@ bevy_platform = { path = "../bevy_platform", version = "0.18.0-dev", default-fea bitflags = "2.3" radsort = "0.1" nonmax = "0.5" -serde = { version = "1", default-features = false, features = ["derive"] } -smallvec = { version = "1", default-features = false } -thiserror = { version = "2", default-features = false } tracing = { version = "0.1", default-features = false, features = ["std"] } [lints] diff --git a/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs b/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs index 2d76071cbdba5..b15d109c0bd36 100644 --- a/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs +++ b/crates/bevy_core_pipeline/src/mip_generation/experimental/depth.rs @@ -22,21 +22,19 @@ use bevy_ecs::{ use bevy_math::{uvec2, UVec2, Vec4Swizzles as _}; use bevy_render::{ batching::gpu_preprocessing::GpuPreprocessingSupport, - render_resource::BindGroupLayoutDescriptor, -}; -use bevy_render::{ experimental::occlusion_culling::{ OcclusionCulling, OcclusionCullingSubview, OcclusionCullingSubviewEntities, }, render_graph::{Node, NodeRunError, RenderGraphContext}, render_resource::{ binding_types::{sampler, texture_2d, texture_2d_multisampled, texture_storage_2d}, - BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, - CachedComputePipelineId, ComputePassDescriptor, ComputePipeline, ComputePipelineDescriptor, - Extent3d, IntoBinding, PipelineCache, PushConstantRange, Sampler, SamplerBindingType, - SamplerDescriptor, ShaderStages, SpecializedComputePipeline, SpecializedComputePipelines, - StorageTextureAccess, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, - TextureSampleType, TextureUsages, TextureView, TextureViewDescriptor, TextureViewDimension, + BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, + BindGroupLayoutEntries, CachedComputePipelineId, ComputePassDescriptor, ComputePipeline, + ComputePipelineDescriptor, Extent3d, IntoBinding, PipelineCache, PushConstantRange, + Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, SpecializedComputePipeline, + SpecializedComputePipelines, StorageTextureAccess, TextureAspect, TextureDescriptor, + TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureView, + TextureViewDescriptor, TextureViewDimension, }, renderer::{RenderContext, RenderDevice}, texture::TextureCache, diff --git a/crates/bevy_core_pipeline/src/mip_generation/mod.rs b/crates/bevy_core_pipeline/src/mip_generation/mod.rs index aa19f8994a750..7a286380dc33a 100644 --- a/crates/bevy_core_pipeline/src/mip_generation/mod.rs +++ b/crates/bevy_core_pipeline/src/mip_generation/mod.rs @@ -36,25 +36,21 @@ use bevy_render::{ diagnostic::RecordDiagnostics as _, render_asset::RenderAssets, render_resource::{ - binding_types::uniform_buffer, BindGroupLayoutDescriptor, FilterMode, ShaderType, - TextureFormatFeatureFlags, UniformBuffer, + binding_types::{sampler, texture_2d, texture_storage_2d, uniform_buffer}, + BindGroup, BindGroupEntries, BindGroupLayoutDescriptor, BindGroupLayoutEntries, + CachedComputePipelineId, ComputePassDescriptor, ComputePipelineDescriptor, Extent3d, + FilterMode, PipelineCache, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, + ShaderType, SpecializedComputePipelines, StorageTextureAccess, TextureAspect, + TextureDescriptor, TextureDimension, TextureFormat, TextureFormatFeatureFlags, + TextureUsages, TextureView, TextureViewDescriptor, TextureViewDimension, UniformBuffer, }, - renderer::{RenderAdapter, RenderQueue}, + renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue}, settings::WgpuFeatures, texture::GpuImage, RenderStartup, }; use bevy_render::{ render_graph::{Node, NodeRunError, RenderGraphContext, RenderGraphExt}, - render_resource::{ - binding_types::{sampler, texture_2d, texture_storage_2d}, - BindGroup, BindGroupEntries, BindGroupLayoutEntries, CachedComputePipelineId, - ComputePassDescriptor, ComputePipelineDescriptor, Extent3d, PipelineCache, Sampler, - SamplerBindingType, SamplerDescriptor, ShaderStages, SpecializedComputePipelines, - StorageTextureAccess, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, - TextureUsages, TextureView, TextureViewDescriptor, TextureViewDimension, - }, - renderer::{RenderContext, RenderDevice}, Render, RenderApp, RenderSystems, }; use bevy_shader::{Shader, ShaderDefVal}; diff --git a/crates/bevy_gltf/Cargo.toml b/crates/bevy_gltf/Cargo.toml index 34e1c56b73d98..ac3887634ce25 100644 --- a/crates/bevy_gltf/Cargo.toml +++ b/crates/bevy_gltf/Cargo.toml @@ -33,6 +33,7 @@ bevy_mesh = { path = "../bevy_mesh", version = "0.18.0-dev" } bevy_pbr = { path = "../bevy_pbr", version = "0.18.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.18.0-dev" } bevy_render = { path = "../bevy_render", version = "0.18.0-dev" } +bevy_material = { path = "../bevy_material", version = "0.18.0-dev" } bevy_scene = { path = "../bevy_scene", version = "0.18.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.18.0-dev" } bevy_tasks = { path = "../bevy_tasks", version = "0.18.0-dev" } diff --git a/crates/bevy_gltf/src/loader/gltf_ext/material.rs b/crates/bevy_gltf/src/loader/gltf_ext/material.rs index 5fadcae2b76ed..2dcc710acdf93 100644 --- a/crates/bevy_gltf/src/loader/gltf_ext/material.rs +++ b/crates/bevy_gltf/src/loader/gltf_ext/material.rs @@ -1,6 +1,6 @@ +use bevy_material::AlphaMode; use bevy_math::Affine2; use bevy_pbr::UvChannel; -use bevy_render::alpha::AlphaMode; use gltf::{json::texture::Info, Material}; diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 1b16fd9de4e85..bf3d5b898771a 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -229,6 +229,7 @@ bevy_window = ["dep:bevy_window", "dep:bevy_a11y", "bevy_image"] bevy_winit = ["dep:bevy_winit", "bevy_window"] bevy_camera = ["dep:bevy_camera", "bevy_mesh", "bevy_window"] bevy_scene = ["dep:bevy_scene", "bevy_asset"] +bevy_material = ["dep:bevy_material", "bevy_image", "bevy_shader"] bevy_light = ["dep:bevy_light", "bevy_camera", "bevy_gizmos?/bevy_light"] bevy_render = [ "dep:bevy_render", @@ -243,12 +244,14 @@ bevy_post_process = ["dep:bevy_post_process", "bevy_core_pipeline"] bevy_pbr = [ "dep:bevy_pbr", "bevy_light", + "bevy_material", "bevy_core_pipeline", "bevy_gizmos_render?/bevy_pbr", ] bevy_sprite_render = [ "dep:bevy_sprite_render", "bevy_sprite", + "bevy_material", "bevy_core_pipeline", "bevy_gizmos_render?/bevy_sprite_render", ] @@ -500,6 +503,7 @@ bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.18.0-dev" } bevy_feathers = { path = "../bevy_feathers", optional = true, version = "0.18.0-dev" } bevy_image = { path = "../bevy_image", optional = true, version = "0.18.0-dev" } bevy_shader = { path = "../bevy_shader", optional = true, version = "0.18.0-dev" } +bevy_material = { path = "../bevy_material", optional = true, version = "0.18.0-dev" } bevy_mesh = { path = "../bevy_mesh", optional = true, version = "0.18.0-dev" } bevy_camera = { path = "../bevy_camera", optional = true, version = "0.18.0-dev" } bevy_light = { path = "../bevy_light", optional = true, version = "0.18.0-dev" } diff --git a/crates/bevy_internal/src/lib.rs b/crates/bevy_internal/src/lib.rs index d1dab307fa7b6..794cf3afd95a1 100644 --- a/crates/bevy_internal/src/lib.rs +++ b/crates/bevy_internal/src/lib.rs @@ -58,6 +58,8 @@ pub use bevy_input_focus as input_focus; pub use bevy_light as light; #[cfg(feature = "bevy_log")] pub use bevy_log as log; +#[cfg(feature = "bevy_material")] +pub use bevy_material as material; pub use bevy_math as math; #[cfg(feature = "bevy_mesh")] pub use bevy_mesh as mesh; diff --git a/crates/bevy_internal/src/prelude.rs b/crates/bevy_internal/src/prelude.rs index ea4a306d0a6d6..193245b7afcf3 100644 --- a/crates/bevy_internal/src/prelude.rs +++ b/crates/bevy_internal/src/prelude.rs @@ -33,6 +33,10 @@ pub use crate::camera::prelude::*; #[cfg(feature = "bevy_shader")] pub use crate::shader::prelude::*; +#[doc(hidden)] +#[cfg(feature = "bevy_material")] +pub use crate::material::prelude::*; + pub use bevy_derive::{bevy_main, Deref, DerefMut}; #[doc(hidden)] diff --git a/crates/bevy_material/Cargo.toml b/crates/bevy_material/Cargo.toml new file mode 100644 index 0000000000000..ee0d881334610 --- /dev/null +++ b/crates/bevy_material/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "bevy_material" +version = "0.18.0-dev" +edition = "2024" +description = "Provides a material abstraction for Bevy Engine" +homepage = "https://bevy.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[dependencies] +# bevy +bevy_asset = { path = "../bevy_asset", version = "0.18.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.18.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.18.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.18.0-dev" } +bevy_material_macros = { path = "macros", version = "0.18.0-dev" } +bevy_mesh = { path = "../bevy_mesh", version = "0.18.0-dev" } +bevy_shader = { path = "../bevy_shader", version = "0.18.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.18.0-dev" } +bevy_platform = { path = "../bevy_platform", version = "0.18.0-dev" } + +encase = "0.12" +tracing = { version = "0.1", default-features = false, features = ["std"] } +thiserror = { version = "2", default-features = false } +wgpu-types = { version = "27", default-features = false } +variadics_please = "1.1" +smallvec = { version = "1", default-features = false } + +[lints] +workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"] +all-features = true diff --git a/crates/bevy_material/LICENSE-APACHE b/crates/bevy_material/LICENSE-APACHE new file mode 100644 index 0000000000000..d9a10c0d8e868 --- /dev/null +++ b/crates/bevy_material/LICENSE-APACHE @@ -0,0 +1,176 @@ + 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 diff --git a/crates/bevy_material/LICENSE-MIT b/crates/bevy_material/LICENSE-MIT new file mode 100644 index 0000000000000..9cf106272ac3b --- /dev/null +++ b/crates/bevy_material/LICENSE-MIT @@ -0,0 +1,19 @@ +MIT License + +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. diff --git a/crates/bevy_material/README.md b/crates/bevy_material/README.md new file mode 100644 index 0000000000000..d6c1939c62806 --- /dev/null +++ b/crates/bevy_material/README.md @@ -0,0 +1,7 @@ +# Bevy Material + +[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/bevyengine/bevy#license) +[![Crates.io](https://img.shields.io/crates/v/bevy_material.svg)](https://crates.io/crates/bevy_material) +[![Downloads](https://img.shields.io/crates/d/bevy_material.svg)](https://crates.io/crates/bevy_material) +[![Docs](https://docs.rs/bevy_material/badge.svg)](https://docs.rs/bevy_material/latest/bevy_material/) +[![Discord](https://img.shields.io/discord/691052431525675048.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/bevy) diff --git a/crates/bevy_material/macros/Cargo.toml b/crates/bevy_material/macros/Cargo.toml new file mode 100644 index 0000000000000..104d21f8ab517 --- /dev/null +++ b/crates/bevy_material/macros/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "bevy_material_macros" +version = "0.18.0-dev" +edition = "2024" +description = "Derive implementations for bevy_material" +homepage = "https://bevy.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[lib] +proc-macro = true + +[dependencies] +bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.18.0-dev" } + +syn = { version = "2.0", features = ["full"] } +quote = "1.0" + +[lints] +workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"] +all-features = true diff --git a/crates/bevy_material/macros/LICENSE-APACHE b/crates/bevy_material/macros/LICENSE-APACHE new file mode 100644 index 0000000000000..d9a10c0d8e868 --- /dev/null +++ b/crates/bevy_material/macros/LICENSE-APACHE @@ -0,0 +1,176 @@ + 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 diff --git a/crates/bevy_material/macros/LICENSE-MIT b/crates/bevy_material/macros/LICENSE-MIT new file mode 100644 index 0000000000000..9cf106272ac3b --- /dev/null +++ b/crates/bevy_material/macros/LICENSE-MIT @@ -0,0 +1,19 @@ +MIT License + +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. diff --git a/crates/bevy_material/macros/src/lib.rs b/crates/bevy_material/macros/src/lib.rs new file mode 100644 index 0000000000000..f8727aac2c695 --- /dev/null +++ b/crates/bevy_material/macros/src/lib.rs @@ -0,0 +1,33 @@ +#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +use bevy_macro_utils::{derive_label, BevyManifest}; +use proc_macro::TokenStream; +use quote::format_ident; +use syn::{parse_macro_input, DeriveInput}; + +pub(crate) fn bevy_material_path() -> syn::Path { + BevyManifest::shared(|manifest| manifest.get_path("bevy_material")) +} + +#[proc_macro_derive(ShaderLabel)] +pub fn derive_shader_label(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let mut trait_path = bevy_material_path(); + trait_path.segments.push(format_ident!("labels").into()); + trait_path + .segments + .push(format_ident!("ShaderLabel").into()); + derive_label(input, "ShaderLabel", &trait_path) +} + +#[proc_macro_derive(DrawFunctionLabel)] +pub fn derive_draw_function_label(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let mut trait_path = bevy_material_path(); + trait_path.segments.push(format_ident!("labels").into()); + trait_path + .segments + .push(format_ident!("DrawFunctionLabel").into()); + derive_label(input, "DrawFunctionLabel", &trait_path) +} diff --git a/crates/bevy_render/src/alpha.rs b/crates/bevy_material/src/alpha.rs similarity index 97% rename from crates/bevy_render/src/alpha.rs rename to crates/bevy_material/src/alpha.rs index dd748811193d4..1fe587ac7f506 100644 --- a/crates/bevy_render/src/alpha.rs +++ b/crates/bevy_material/src/alpha.rs @@ -1,3 +1,5 @@ +//! Allows configuring a material's transparency behavior. + use bevy_reflect::{std_traits::ReflectDefault, Reflect}; // TODO: add discussion about performance. diff --git a/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs b/crates/bevy_material/src/bind_group_layout_entries.rs similarity index 99% rename from crates/bevy_render/src/render_resource/bind_group_layout_entries.rs rename to crates/bevy_material/src/bind_group_layout_entries.rs index 17630b7dae2d7..ca6cd9392ad6a 100644 --- a/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs +++ b/crates/bevy_material/src/bind_group_layout_entries.rs @@ -1,6 +1,6 @@ use core::num::NonZero; use variadics_please::all_tuples_with_size; -use wgpu::{BindGroupLayoutEntry, BindingType, ShaderStages}; +use wgpu_types::{BindGroupLayoutEntry, BindingType, ShaderStages}; /// Helper for constructing bind group layouts. /// @@ -364,12 +364,12 @@ impl core::ops::Deref for DynamicBindGroupLayoutEntries { } pub mod binding_types { - use crate::render_resource::{ - BufferBindingType, SamplerBindingType, TextureSampleType, TextureViewDimension, - }; use core::num::NonZero; use encase::ShaderType; - use wgpu::{StorageTextureAccess, TextureFormat}; + use wgpu_types::{ + BufferBindingType, SamplerBindingType, TextureSampleType, TextureViewDimension, + }; + use wgpu_types::{StorageTextureAccess, TextureFormat}; use super::*; diff --git a/crates/bevy_material/src/descriptor.rs b/crates/bevy_material/src/descriptor.rs new file mode 100644 index 0000000000000..3f9a043c65ba7 --- /dev/null +++ b/crates/bevy_material/src/descriptor.rs @@ -0,0 +1,169 @@ +use alloc::borrow::Cow; +use bevy_asset::Handle; +use bevy_derive::Deref; +use bevy_mesh::VertexBufferLayout; +use bevy_shader::{CachedPipelineId, Shader, ShaderDefVal}; +use core::iter; +use thiserror::Error; +use wgpu_types::{ + BindGroupLayoutEntry, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState, + PushConstantRange, +}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +pub struct BindGroupLayoutDescriptor { + /// Debug label of the bind group layout descriptor. This will show up in graphics debuggers for easy identification. + pub label: Cow<'static, str>, + pub entries: Vec, +} + +impl BindGroupLayoutDescriptor { + pub fn new(label: impl Into>, entries: &[BindGroupLayoutEntry]) -> Self { + Self { + label: label.into(), + entries: entries.into(), + } + } +} + +/// Describes a render (graphics) pipeline. +#[derive(Clone, Debug, PartialEq, Default)] +pub struct RenderPipelineDescriptor { + /// Debug label of the pipeline. This will show up in graphics debuggers for easy identification. + pub label: Option>, + /// The layout of bind groups for this pipeline. + pub layout: Vec, + /// The push constant ranges for this pipeline. + /// Supply an empty vector if the pipeline doesn't use push constants. + pub push_constant_ranges: Vec, + /// The compiled vertex stage, its entry point, and the input buffers layout. + pub vertex: VertexState, + /// The properties of the pipeline at the primitive assembly and rasterization level. + pub primitive: PrimitiveState, + /// The effect of draw calls on the depth and stencil aspects of the output target, if any. + pub depth_stencil: Option, + /// The multi-sampling properties of the pipeline. + pub multisample: MultisampleState, + /// The compiled fragment stage, its entry point, and the color targets. + pub fragment: Option, + /// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true. + /// If this is false, reading from workgroup variables before writing to them will result in garbage values. + pub zero_initialize_workgroup_memory: bool, +} + +#[derive(Copy, Clone, Debug, Error)] +#[error("RenderPipelineDescriptor has no FragmentState configured")] +pub struct NoFragmentStateError; + +impl RenderPipelineDescriptor { + pub fn fragment_mut(&mut self) -> Result<&mut FragmentState, NoFragmentStateError> { + self.fragment.as_mut().ok_or(NoFragmentStateError) + } + + pub fn set_layout(&mut self, index: usize, layout: BindGroupLayoutDescriptor) { + filling_set_at(&mut self.layout, index, bevy_utils::default(), layout); + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Default)] +pub struct VertexState { + /// The compiled shader module for this stage. + pub shader: Handle, + pub shader_defs: Vec, + /// The name of the entry point in the compiled shader, or `None` if the default entry point + /// is used. + pub entry_point: Option>, + /// The format of any vertex buffers used with this pipeline. + pub buffers: Vec, +} + +/// Describes the fragment process in a render pipeline. +#[derive(Clone, Debug, PartialEq, Eq, Default)] +pub struct FragmentState { + /// The compiled shader module for this stage. + pub shader: Handle, + pub shader_defs: Vec, + /// The name of the entry point in the compiled shader, or `None` if the default entry point + /// is used. + pub entry_point: Option>, + /// The color state of the render targets. + pub targets: Vec>, +} + +impl FragmentState { + pub fn set_target(&mut self, index: usize, target: ColorTargetState) { + filling_set_at(&mut self.targets, index, None, Some(target)); + } +} + +/// Describes a compute pipeline. +#[derive(Clone, Debug, PartialEq, Eq, Default)] +pub struct ComputePipelineDescriptor { + pub label: Option>, + pub layout: Vec, + pub push_constant_ranges: Vec, + /// The compiled shader module for this stage. + pub shader: Handle, + pub shader_defs: Vec, + /// The name of the entry point in the compiled shader, or `None` if the default entry point + /// is used. + pub entry_point: Option>, + /// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true. + /// If this is false, reading from workgroup variables before writing to them will result in garbage values. + pub zero_initialize_workgroup_memory: bool, +} + +// utility function to set a value at the specified index, extending with +// a filler value if the index is out of bounds. +fn filling_set_at(vec: &mut Vec, index: usize, filler: T, value: T) { + let num_to_fill = (index + 1).saturating_sub(vec.len()); + vec.extend(iter::repeat_n(filler, num_to_fill)); + vec[index] = value; +} + +/// A descriptor for a [`Pipeline`](https://docs.rs/bevy/latest/bevy/render/render_resource/enum.Pipeline.html). +/// +/// Used to store a heterogenous collection of render and compute pipeline descriptors together. +#[derive(Debug)] +pub enum PipelineDescriptor { + RenderPipelineDescriptor(Box), + ComputePipelineDescriptor(Box), +} + +/// Index of a cached render pipeline in a `PipelineCache`. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Deref)] +pub struct CachedRenderPipelineId(CachedPipelineId); + +impl CachedRenderPipelineId { + /// An invalid cached render pipeline index, often used to initialize a variable. + pub const INVALID: Self = CachedRenderPipelineId(usize::MAX); + + #[inline] + pub fn new(id: usize) -> Self { + Self(id) + } + + #[inline] + pub fn id(&self) -> usize { + self.0 + } +} + +/// Index of a cached compute pipeline in a `PipelineCache`. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub struct CachedComputePipelineId(CachedPipelineId); + +impl CachedComputePipelineId { + /// An invalid cached compute pipeline index, often used to initialize a variable. + pub const INVALID: Self = CachedComputePipelineId(usize::MAX); + + #[inline] + pub fn new(id: usize) -> Self { + Self(id) + } + + #[inline] + pub fn id(&self) -> usize { + self.0 + } +} diff --git a/crates/bevy_material/src/key.rs b/crates/bevy_material/src/key.rs new file mode 100644 index 0000000000000..37854627d8502 --- /dev/null +++ b/crates/bevy_material/src/key.rs @@ -0,0 +1,156 @@ +use bevy_platform::{hash::FixedHasher, sync::Arc}; +use core::{ + any::{Any, TypeId}, + hash::{BuildHasher, Hash, Hasher}, +}; + +/// A type-erased mesh pipeline key, which stores the bits of the key as a `u64`. +#[derive(Clone, Copy)] +pub struct ErasedMeshPipelineKey { + bits: u64, + type_id: TypeId, +} + +impl ErasedMeshPipelineKey { + #[inline] + pub fn new(key: T) -> Self + where + u64: From, + { + Self { + bits: key.into(), + type_id: TypeId::of::(), + } + } + + #[inline] + pub fn downcast>(&self) -> T { + assert_eq!( + self.type_id, + TypeId::of::(), + "ErasedMeshPipelineKey::downcast called with wrong type" + ); + self.bits.into() + } +} + +impl PartialEq for ErasedMeshPipelineKey { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.type_id == other.type_id && self.bits == other.bits + } +} + +impl Eq for ErasedMeshPipelineKey {} + +impl Hash for ErasedMeshPipelineKey { + #[inline] + fn hash(&self, state: &mut H) { + self.type_id.hash(state); + self.bits.hash(state); + } +} + +impl Default for ErasedMeshPipelineKey { + fn default() -> Self { + Self { + bits: 0, + type_id: TypeId::of::<()>(), + } + } +} + +impl core::fmt::Debug for ErasedMeshPipelineKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ErasedMeshPipelineKey") + .field("type_id", &self.type_id) + .field("bits", &format_args!("{:#018x}", self.bits)) + .finish() + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ErasedMaterialPipelineKey { + pub mesh_key: ErasedMeshPipelineKey, + pub material_key: ErasedMaterialKey, + pub type_id: TypeId, +} + +#[derive(Debug)] +pub struct ErasedMaterialKey { + type_id: TypeId, + hash: u64, + value: Box, + vtable: Arc, +} + +#[derive(Debug)] +pub struct ErasedMaterialKeyVTable { + clone_fn: fn(&dyn Any) -> Box, + partial_eq_fn: fn(&dyn Any, &dyn Any) -> bool, +} + +impl ErasedMaterialKey { + pub fn new(material_key: T) -> Self + where + T: Clone + Hash + PartialEq + Send + Sync + 'static, + { + let type_id = TypeId::of::(); + let hash = FixedHasher::hash_one(&FixedHasher, &material_key); + + fn clone(any: &dyn Any) -> Box { + Box::new(any.downcast_ref::().unwrap().clone()) + } + fn partial_eq(a: &dyn Any, b: &dyn Any) -> bool { + a.downcast_ref::().unwrap() == b.downcast_ref::().unwrap() + } + + Self { + type_id, + hash, + value: Box::new(material_key), + vtable: Arc::new(ErasedMaterialKeyVTable { + clone_fn: clone::, + partial_eq_fn: partial_eq::, + }), + } + } + + pub fn to_key(&self) -> T { + debug_assert_eq!(self.type_id, TypeId::of::()); + self.value.downcast_ref::().unwrap().clone() + } +} + +impl PartialEq for ErasedMaterialKey { + fn eq(&self, other: &Self) -> bool { + self.type_id == other.type_id + && (self.vtable.partial_eq_fn)(self.value.as_ref(), other.value.as_ref()) + } +} + +impl Eq for ErasedMaterialKey {} + +impl Clone for ErasedMaterialKey { + fn clone(&self) -> Self { + Self { + type_id: self.type_id, + hash: self.hash, + value: (self.vtable.clone_fn)(self.value.as_ref()), + vtable: self.vtable.clone(), + } + } +} + +impl Hash for ErasedMaterialKey { + fn hash(&self, state: &mut H) { + self.type_id.hash(state); + self.hash.hash(state); + } +} + +impl Default for ErasedMaterialKey { + fn default() -> Self { + Self::new(()) + } +} diff --git a/crates/bevy_material/src/labels.rs b/crates/bevy_material/src/labels.rs new file mode 100644 index 0000000000000..6c821731501c9 --- /dev/null +++ b/crates/bevy_material/src/labels.rs @@ -0,0 +1,34 @@ +use bevy_ecs::define_label; +use bevy_ecs::intern::Interned; +pub use bevy_material_macros::ShaderLabel; + +define_label!( + #[diagnostic::on_unimplemented( + note = "consider annotating `{Self}` with `#[derive(ShaderLabel)]`" + )] + /// Labels used to uniquely identify types of material shaders + ShaderLabel, + SHADER_LABEL_INTERNER +); + +/// A shorthand for `Interned`. +pub type InternedShaderLabel = Interned; + +pub use bevy_material_macros::DrawFunctionLabel; + +define_label!( + #[diagnostic::on_unimplemented( + note = "consider annotating `{Self}` with `#[derive(DrawFunctionLabel)]`" + )] + /// Labels used to uniquely identify types of material shaders + DrawFunctionLabel, + DRAW_FUNCTION_LABEL_INTERNER +); + +pub type InternedDrawFunctionLabel = Interned; + +// TODO: make this generic? +/// An identifier for a [`Draw`](https://docs.rs/bevy/latest/bevy/render/render_phase/trait.Draw.html) +/// function stored in [`DrawFunctions`](https://docs.rs/bevy/latest/bevy/render/render_phase/struct.DrawFunctions.html). +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +pub struct DrawFunctionId(pub u32); diff --git a/crates/bevy_material/src/lib.rs b/crates/bevy_material/src/lib.rs new file mode 100644 index 0000000000000..27c7669610ca8 --- /dev/null +++ b/crates/bevy_material/src/lib.rs @@ -0,0 +1,114 @@ +//! Provides a material abstraction for bevy +#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")] + +use bevy_asset::Handle; +use bevy_shader::Shader; +use smallvec::SmallVec; + +extern crate alloc; + +use crate::{ + descriptor::BindGroupLayoutDescriptor, + key::{ErasedMaterialKey, ErasedMeshPipelineKey}, + labels::{ + DrawFunctionId, DrawFunctionLabel, InternedDrawFunctionLabel, InternedShaderLabel, + ShaderLabel, + }, + specialize::{BaseSpecializeFn, PrepassSpecializeFn, UserSpecializeFn}, +}; + +pub use crate::{alpha::AlphaMode, opaque::OpaqueRendererMethod, phase::RenderPhaseType}; + +mod alpha; +pub mod bind_group_layout_entries; +pub mod descriptor; +pub mod key; +pub mod labels; +mod opaque; +mod phase; +pub mod specialize; + +/// The material prelude. +/// +/// This includes the most common types in this crate, re-exported for your convenience. +pub mod prelude { + pub use crate::alpha::AlphaMode; +} + +/// Common material properties, calculated for a specific material instance. +#[derive(Default)] +pub struct MaterialProperties { + /// Is this material should be rendered by the deferred renderer when. + /// [`AlphaMode::Opaque`] or [`AlphaMode::Mask`] + pub render_method: OpaqueRendererMethod, + /// The [`AlphaMode`] of this material. + pub alpha_mode: AlphaMode, + /// The bits in the [`ErasedMeshPipelineKey`] for this material. + /// + /// These are precalculated so that we can just "or" them together in + /// [`queue_material_meshes`](https://docs.rs/bevy/latest/bevy/pbr/fn.queue_material_meshes.html). + pub mesh_pipeline_key_bits: ErasedMeshPipelineKey, + /// Add a bias to the view depth of the mesh which can be used to force a specific render order + /// for meshes with equal depth, to avoid z-fighting. + /// The bias is in depth-texture units so large values may be needed to overcome small depth differences. + pub depth_bias: f32, + /// Whether the material would like to read from + /// [`ViewTransmissionTexture`](https://docs.rs/bevy/latest/bevy/core_pipeline/core_3d/struct.ViewTransmissionTexture.html). + /// + /// This allows taking color output from the [`Opaque3d`](https://docs.rs/bevy/latest/bevy/core_pipeline/core_3d/struct.Opaque3d.html) + /// pass as an input, (for screen-space transmission) but requires rendering to take place in a separate + /// [`Transmissive3d`](https://docs.rs/bevy/latest/bevy/core_pipeline/core_3d/struct.Transmissive3d.html) pass. + pub reads_view_transmission_texture: bool, + pub render_phase_type: RenderPhaseType, + pub material_layout: Option, + /// Backing array is a size of 4 because the [`StandardMaterial`](https://docs.rs/bevy/latest/bevy/pbr/struct.StandardMaterial.html) + /// needs 4 draw functions by default + pub draw_functions: SmallVec<[(InternedDrawFunctionLabel, DrawFunctionId); 4]>, + /// Backing array is a size of 3 because the [`StandardMaterial`](https://docs.rs/bevy/latest/bevy/pbr/struct.StandardMaterial.html) + /// has 3 custom shaders (`frag`, `prepass_frag`, `deferred_frag`) which is the + /// most common use case + pub shaders: SmallVec<[(InternedShaderLabel, Handle); 3]>, + /// Whether this material *actually* uses bindless resources, taking the + /// platform support (or lack thereof) of bindless resources into account. + pub bindless: bool, + pub base_specialize: Option, + pub prepass_specialize: Option, + pub user_specialize: Option, + /// The key for this material, typically a bitfield of flags that are used to modify + /// the pipeline descriptor used for this material. + pub material_key: ErasedMaterialKey, + /// Whether shadows are enabled for this material + pub shadows_enabled: bool, + /// Whether prepass is enabled for this material + pub prepass_enabled: bool, +} + +impl MaterialProperties { + pub fn get_shader(&self, label: impl ShaderLabel) -> Option> { + self.shaders + .iter() + .find(|(inner_label, _)| inner_label == &label.intern()) + .map(|(_, shader)| shader) + .cloned() + } + + pub fn add_shader(&mut self, label: impl ShaderLabel, shader: Handle) { + self.shaders.push((label.intern(), shader)); + } + + pub fn get_draw_function(&self, label: impl DrawFunctionLabel) -> Option { + self.draw_functions + .iter() + .find(|(inner_label, _)| inner_label == &label.intern()) + .map(|(_, shader)| shader) + .cloned() + } + + pub fn add_draw_function( + &mut self, + label: impl DrawFunctionLabel, + draw_function: DrawFunctionId, + ) { + self.draw_functions.push((label.intern(), draw_function)); + } +} diff --git a/crates/bevy_material/src/opaque.rs b/crates/bevy_material/src/opaque.rs new file mode 100644 index 0000000000000..406ececcdef6d --- /dev/null +++ b/crates/bevy_material/src/opaque.rs @@ -0,0 +1,28 @@ +use bevy_reflect::{prelude::ReflectDefault, Reflect}; + +/// Render method used for opaque materials. +/// +/// The forward rendering main pass draws each mesh entity and shades it according to its +/// corresponding material and the lights that affect it. Some render features like Screen Space +/// Ambient Occlusion require running depth and normal prepasses, that are 'deferred'-like +/// prepasses over all mesh entities to populate depth and normal textures. This means that when +/// using render features that require running prepasses, multiple passes over all visible geometry +/// are required. This can be slow if there is a lot of geometry that cannot be batched into few +/// draws. +/// +/// Deferred rendering runs a prepass to gather not only geometric information like depth and +/// normals, but also all the material properties like base color, emissive color, reflectance, +/// metalness, etc, and writes them into a deferred 'g-buffer' texture. The deferred main pass is +/// then a fullscreen pass that reads data from these textures and executes shading. This allows +/// for one pass over geometry, but is at the cost of not being able to use MSAA, and has heavier +/// bandwidth usage which can be unsuitable for low end mobile or other bandwidth-constrained devices. +/// +/// If a material indicates `OpaqueRendererMethod::Auto`, `DefaultOpaqueRendererMethod` will be used. +#[derive(Default, Clone, Copy, Debug, PartialEq, Reflect)] +#[reflect(Default, Clone, PartialEq)] +pub enum OpaqueRendererMethod { + #[default] + Forward, + Deferred, + Auto, +} diff --git a/crates/bevy_material/src/phase.rs b/crates/bevy_material/src/phase.rs new file mode 100644 index 0000000000000..487d003f3e0a0 --- /dev/null +++ b/crates/bevy_material/src/phase.rs @@ -0,0 +1,9 @@ +/// Which phase a material renders in. +#[derive(Clone, Copy, Default)] +pub enum RenderPhaseType { + #[default] + Opaque, + AlphaMask, + Transmissive, + Transparent, +} diff --git a/crates/bevy_material/src/specialize.rs b/crates/bevy_material/src/specialize.rs new file mode 100644 index 0000000000000..a865eb3906b7e --- /dev/null +++ b/crates/bevy_material/src/specialize.rs @@ -0,0 +1,53 @@ +use bevy_ecs::world::World; +use bevy_mesh::{MeshVertexBufferLayoutRef, MissingVertexAttributeError}; +use bevy_platform::sync::Arc; +use core::any::Any; +use thiserror::Error; + +use crate::{ + descriptor::{CachedRenderPipelineId, RenderPipelineDescriptor}, + key::ErasedMaterialPipelineKey, + MaterialProperties, +}; + +/// A type erased function pointer for specializing a material pipeline. The implementation is +/// expected to: +/// - Look up the appropriate specializer from the world +/// - Downcast the erased key to the concrete key type +/// - Call `SpecializedMeshPipelines::specialize` with the specializer and return the resulting pipeline id +pub type BaseSpecializeFn = fn( + &mut World, + ErasedMaterialPipelineKey, + &MeshVertexBufferLayoutRef, + &Arc, +) -> Result; + +/// A type erased function pointer for specializing a material prepass pipeline. The implementation is +/// expected to: +/// - Look up the appropriate specializer from the world +/// - Downcast the erased key to the concrete key type +/// - Call `SpecializedMeshPipelines::specialize` with the specializer and return the resulting pipeline id +pub type PrepassSpecializeFn = fn( + &mut World, + ErasedMaterialPipelineKey, + &MeshVertexBufferLayoutRef, + &Arc, +) -> Result; + +/// A type erased function pointer for specializing a material prepass pipeline. The implementation is +/// expected to: +/// - Look up the appropriate specializer from the world +/// - Downcast the erased key to the concrete key type +/// - Call `SpecializedMeshPipelines::specialize` with the specializer and return the resulting pipeline id +pub type UserSpecializeFn = fn( + &dyn Any, + &mut RenderPipelineDescriptor, + &MeshVertexBufferLayoutRef, + ErasedMaterialPipelineKey, +) -> Result<(), SpecializedMeshPipelineError>; + +#[derive(Error, Debug)] +pub enum SpecializedMeshPipelineError { + #[error(transparent)] + MissingVertexAttribute(#[from] MissingVertexAttributeError), +} diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 22aa4b724723a..534993d2a39e5 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -49,6 +49,7 @@ bevy_mesh = { path = "../bevy_mesh", version = "0.18.0-dev", features = [ "bevy_mikktspace", ] } bevy_shader = { path = "../bevy_shader", version = "0.18.0-dev" } +bevy_material = { path = "../bevy_material", version = "0.18.0-dev" } bevy_math = { path = "../bevy_math", version = "0.18.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.18.0-dev" } bevy_render = { path = "../bevy_render", version = "0.18.0-dev", features = [ diff --git a/crates/bevy_pbr/src/decal/forward.rs b/crates/bevy_pbr/src/decal/forward.rs index c90c1f00f049c..71a3e4f38a074 100644 --- a/crates/bevy_pbr/src/decal/forward.rs +++ b/crates/bevy_pbr/src/decal/forward.rs @@ -7,11 +7,11 @@ use bevy_asset::{Asset, Assets, Handle}; use bevy_ecs::{ component::Component, lifecycle::HookContext, resource::Resource, world::DeferredWorld, }; +use bevy_material::AlphaMode; use bevy_math::{prelude::Rectangle, Quat, Vec2, Vec3}; use bevy_mesh::{Mesh, Mesh3d, MeshBuilder, MeshVertexBufferLayoutRef, Meshable}; use bevy_reflect::{Reflect, TypePath}; use bevy_render::{ - alpha::AlphaMode, render_asset::RenderAssets, render_resource::{ AsBindGroup, AsBindGroupShaderType, CompareFunction, RenderPipelineDescriptor, ShaderType, diff --git a/crates/bevy_pbr/src/extended_material.rs b/crates/bevy_pbr/src/extended_material.rs index 732648bf9d017..088a81f65cb2f 100644 --- a/crates/bevy_pbr/src/extended_material.rs +++ b/crates/bevy_pbr/src/extended_material.rs @@ -2,11 +2,11 @@ use alloc::borrow::Cow; use bevy_asset::Asset; use bevy_ecs::system::SystemParamItem; +use bevy_material::{AlphaMode, OpaqueRendererMethod}; use bevy_mesh::MeshVertexBufferLayoutRef; use bevy_platform::{collections::HashSet, hash::FixedHasher}; use bevy_reflect::{impl_type_path, Reflect}; use bevy_render::{ - alpha::AlphaMode, render_resource::{ AsBindGroup, AsBindGroupError, BindGroupLayout, BindGroupLayoutEntry, BindlessDescriptor, BindlessResourceType, BindlessSlabResourceLimit, RenderPipelineDescriptor, @@ -335,7 +335,7 @@ impl Material for ExtendedMaterial { } } - fn opaque_render_method(&self) -> crate::OpaqueRendererMethod { + fn opaque_render_method(&self) -> OpaqueRendererMethod { B::opaque_render_method(&self.base) } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 79163cb648134..97bc4a1b7848c 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -134,8 +134,8 @@ use bevy_ecs::prelude::*; #[cfg(feature = "bluenoise_texture")] use bevy_image::{CompressedImageFormats, ImageType}; use bevy_image::{Image, ImageSampler}; +use bevy_material::AlphaMode; use bevy_render::{ - alpha::AlphaMode, camera::sort_cameras, extract_resource::ExtractResourcePlugin, render_graph::RenderGraph, diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 4f82c075d8a76..e4b055df8b431 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -26,6 +26,11 @@ use bevy_ecs::{ SystemParamItem, SystemState, }, }; +use bevy_material::{ + key::{ErasedMaterialKey, ErasedMaterialPipelineKey, ErasedMeshPipelineKey}, + labels::{DrawFunctionLabel, InternedShaderLabel, ShaderLabel}, + MaterialProperties, OpaqueRendererMethod, RenderPhaseType, +}; use bevy_mesh::{ mark_3d_meshes_as_changed_if_their_assets_changed, Mesh3d, MeshVertexBufferLayoutRef, }; @@ -55,11 +60,11 @@ use bevy_render::{ }; use bevy_render::{mesh::allocator::MeshAllocator, sync_world::MainEntityHashMap}; use bevy_render::{texture::FallbackImage, view::RenderVisibleEntities}; -use bevy_shader::{Shader, ShaderDefVal}; +use bevy_shader::ShaderDefVal; use bevy_utils::Parallel; use core::{ any::{Any, TypeId}, - hash::{BuildHasher, Hash, Hasher}, + hash::Hash, marker::PhantomData, }; use smallvec::SmallVec; @@ -437,114 +442,6 @@ pub struct MaterialPipelineKey { pub bind_group_data: M::Data, } -/// A type-erased mesh pipeline key, which stores the bits of the key as a `u64`. -#[derive(Clone, Copy)] -pub struct ErasedMeshPipelineKey { - bits: u64, - type_id: TypeId, -} - -impl ErasedMeshPipelineKey { - #[inline] - pub fn new(key: T) -> Self - where - u64: From, - { - Self { - bits: key.into(), - type_id: TypeId::of::(), - } - } - - #[inline] - pub fn downcast>(&self) -> T { - assert_eq!( - self.type_id, - TypeId::of::(), - "ErasedMeshPipelineKey::downcast called with wrong type" - ); - self.bits.into() - } -} - -impl PartialEq for ErasedMeshPipelineKey { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.type_id == other.type_id && self.bits == other.bits - } -} - -impl Eq for ErasedMeshPipelineKey {} - -impl Hash for ErasedMeshPipelineKey { - #[inline] - fn hash(&self, state: &mut H) { - self.type_id.hash(state); - self.bits.hash(state); - } -} - -impl Default for ErasedMeshPipelineKey { - fn default() -> Self { - Self { - bits: 0, - type_id: TypeId::of::<()>(), - } - } -} - -impl core::fmt::Debug for ErasedMeshPipelineKey { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ErasedMeshPipelineKey") - .field("type_id", &self.type_id) - .field("bits", &format_args!("{:#018x}", self.bits)) - .finish() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct ErasedMaterialPipelineKey { - pub mesh_key: ErasedMeshPipelineKey, - pub material_key: ErasedMaterialKey, - pub type_id: TypeId, -} - -/// A type erased function pointer for specializing a material pipeline. The implementation is -/// expected to: -/// - Look up the appropriate specializer from the world -/// - Downcast the erased key to the concrete key type -/// - Call [`SpecializedMeshPipelines::specialize`] with the specializer and return the resulting pipeline id -pub type BaseSpecializeFn = fn( - &mut World, - ErasedMaterialPipelineKey, - &MeshVertexBufferLayoutRef, - &Arc, -) -> Result; - -/// A type erased function pointer for specializing a material prepass pipeline. The implementation is -/// expected to: -/// - Look up the appropriate specializer from the world -/// - Downcast the erased key to the concrete key type -/// - Call [`SpecializedMeshPipelines::specialize`] with the specializer and return the resulting pipeline id -pub type PrepassSpecializeFn = fn( - &mut World, - ErasedMaterialPipelineKey, - &MeshVertexBufferLayoutRef, - &Arc, -) -> Result; - -/// A type erased function pointer for specializing a material prepass pipeline. The implementation is -/// expected to: -/// - Look up the appropriate specializer from the world -/// - Downcast the erased key to the concrete key type -/// - Call [`SpecializedMeshPipelines::specialize`] with the specializer and return the resulting pipeline id -pub type UserSpecializeFn = fn( - &dyn Any, - &mut RenderPipelineDescriptor, - &MeshVertexBufferLayoutRef, - ErasedMaterialPipelineKey, -) -> Result<(), SpecializedMeshPipelineError>; - /// Render pipeline data for a given [`Material`]. #[derive(Resource, Clone)] pub struct MaterialPipeline { @@ -1494,33 +1391,6 @@ impl DefaultOpaqueRendererMethod { } } -/// Render method used for opaque materials. -/// -/// The forward rendering main pass draws each mesh entity and shades it according to its -/// corresponding material and the lights that affect it. Some render features like Screen Space -/// Ambient Occlusion require running depth and normal prepasses, that are 'deferred'-like -/// prepasses over all mesh entities to populate depth and normal textures. This means that when -/// using render features that require running prepasses, multiple passes over all visible geometry -/// are required. This can be slow if there is a lot of geometry that cannot be batched into few -/// draws. -/// -/// Deferred rendering runs a prepass to gather not only geometric information like depth and -/// normals, but also all the material properties like base color, emissive color, reflectance, -/// metalness, etc, and writes them into a deferred 'g-buffer' texture. The deferred main pass is -/// then a fullscreen pass that reads data from these textures and executes shading. This allows -/// for one pass over geometry, but is at the cost of not being able to use MSAA, and has heavier -/// bandwidth usage which can be unsuitable for low end mobile or other bandwidth-constrained devices. -/// -/// If a material indicates `OpaqueRendererMethod::Auto`, `DefaultOpaqueRendererMethod` will be used. -#[derive(Default, Clone, Copy, Debug, PartialEq, Reflect)] -#[reflect(Default, Clone, PartialEq)] -pub enum OpaqueRendererMethod { - #[default] - Forward, - Deferred, - Auto, -} - #[derive(ShaderLabel, Debug, Hash, PartialEq, Eq, Clone, Default)] pub struct MaterialVertexShader; @@ -1570,168 +1440,6 @@ pub struct DeferredAlphaMaskDrawFunction; #[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)] pub struct ShadowsDrawFunction; -#[derive(Debug)] -pub struct ErasedMaterialKey { - type_id: TypeId, - hash: u64, - value: Box, - vtable: Arc, -} - -#[derive(Debug)] -pub struct ErasedMaterialKeyVTable { - clone_fn: fn(&dyn Any) -> Box, - partial_eq_fn: fn(&dyn Any, &dyn Any) -> bool, -} - -impl ErasedMaterialKey { - pub fn new(material_key: T) -> Self - where - T: Clone + Hash + PartialEq + Send + Sync + 'static, - { - let type_id = TypeId::of::(); - let hash = FixedHasher::hash_one(&FixedHasher, &material_key); - - fn clone(any: &dyn Any) -> Box { - Box::new(any.downcast_ref::().unwrap().clone()) - } - fn partial_eq(a: &dyn Any, b: &dyn Any) -> bool { - a.downcast_ref::().unwrap() == b.downcast_ref::().unwrap() - } - - Self { - type_id, - hash, - value: Box::new(material_key), - vtable: Arc::new(ErasedMaterialKeyVTable { - clone_fn: clone::, - partial_eq_fn: partial_eq::, - }), - } - } - - pub fn to_key(&self) -> T { - debug_assert_eq!(self.type_id, TypeId::of::()); - self.value.downcast_ref::().unwrap().clone() - } -} - -impl PartialEq for ErasedMaterialKey { - fn eq(&self, other: &Self) -> bool { - self.type_id == other.type_id - && (self.vtable.partial_eq_fn)(self.value.as_ref(), other.value.as_ref()) - } -} - -impl Eq for ErasedMaterialKey {} - -impl Clone for ErasedMaterialKey { - fn clone(&self) -> Self { - Self { - type_id: self.type_id, - hash: self.hash, - value: (self.vtable.clone_fn)(self.value.as_ref()), - vtable: self.vtable.clone(), - } - } -} - -impl Hash for ErasedMaterialKey { - fn hash(&self, state: &mut H) { - self.type_id.hash(state); - self.hash.hash(state); - } -} - -impl Default for ErasedMaterialKey { - fn default() -> Self { - Self::new(()) - } -} - -/// Common [`Material`] properties, calculated for a specific material instance. -#[derive(Default)] -pub struct MaterialProperties { - /// Is this material should be rendered by the deferred renderer when. - /// [`AlphaMode::Opaque`] or [`AlphaMode::Mask`] - pub render_method: OpaqueRendererMethod, - /// The [`AlphaMode`] of this material. - pub alpha_mode: AlphaMode, - /// The bits in the [`MeshPipelineKey`] for this material. - /// - /// These are precalculated so that we can just "or" them together in - /// [`queue_material_meshes`]. - pub mesh_pipeline_key_bits: ErasedMeshPipelineKey, - /// Add a bias to the view depth of the mesh which can be used to force a specific render order - /// for meshes with equal depth, to avoid z-fighting. - /// The bias is in depth-texture units so large values may be needed to overcome small depth differences. - pub depth_bias: f32, - /// Whether the material would like to read from [`ViewTransmissionTexture`](bevy_core_pipeline::core_3d::ViewTransmissionTexture). - /// - /// This allows taking color output from the [`Opaque3d`] pass as an input, (for screen-space transmission) but requires - /// rendering to take place in a separate [`Transmissive3d`] pass. - pub reads_view_transmission_texture: bool, - pub render_phase_type: RenderPhaseType, - pub material_layout: Option, - /// Backing array is a size of 4 because the `StandardMaterial` needs 4 draw functions by default - pub draw_functions: SmallVec<[(InternedDrawFunctionLabel, DrawFunctionId); 4]>, - /// Backing array is a size of 3 because the `StandardMaterial` has 3 custom shaders (`frag`, `prepass_frag`, `deferred_frag`) which is the - /// most common use case - pub shaders: SmallVec<[(InternedShaderLabel, Handle); 3]>, - /// Whether this material *actually* uses bindless resources, taking the - /// platform support (or lack thereof) of bindless resources into account. - pub bindless: bool, - pub base_specialize: Option, - pub prepass_specialize: Option, - pub user_specialize: Option, - /// The key for this material, typically a bitfield of flags that are used to modify - /// the pipeline descriptor used for this material. - pub material_key: ErasedMaterialKey, - /// Whether shadows are enabled for this material - pub shadows_enabled: bool, - /// Whether prepass is enabled for this material - pub prepass_enabled: bool, -} - -impl MaterialProperties { - pub fn get_shader(&self, label: impl ShaderLabel) -> Option> { - self.shaders - .iter() - .find(|(inner_label, _)| inner_label == &label.intern()) - .map(|(_, shader)| shader) - .cloned() - } - - pub fn add_shader(&mut self, label: impl ShaderLabel, shader: Handle) { - self.shaders.push((label.intern(), shader)); - } - - pub fn get_draw_function(&self, label: impl DrawFunctionLabel) -> Option { - self.draw_functions - .iter() - .find(|(inner_label, _)| inner_label == &label.intern()) - .map(|(_, shader)| shader) - .cloned() - } - - pub fn add_draw_function( - &mut self, - label: impl DrawFunctionLabel, - draw_function: DrawFunctionId, - ) { - self.draw_functions.push((label.intern(), draw_function)); - } -} - -#[derive(Clone, Copy, Default)] -pub enum RenderPhaseType { - #[default] - Opaque, - AlphaMask, - Transmissive, - Transparent, -} - /// A resource that maps each untyped material ID to its binding. /// /// This duplicates information in `RenderAssets`, but it doesn't have the diff --git a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs index 0d776c4a792f4..6d4d4770457da 100644 --- a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs +++ b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs @@ -10,6 +10,10 @@ use bevy_core_pipeline::{ }; use bevy_derive::{Deref, DerefMut}; use bevy_light::{EnvironmentMapLight, IrradianceVolume, ShadowFilteringMethod}; +use bevy_material::{ + key::{ErasedMaterialPipelineKey, ErasedMeshPipelineKey}, + OpaqueRendererMethod, +}; use bevy_mesh::VertexBufferLayout; use bevy_mesh::{Mesh, MeshVertexBufferLayout, MeshVertexBufferLayoutRef, MeshVertexBufferLayouts}; use bevy_platform::collections::{HashMap, HashSet}; diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index c1d08acc282e2..21242ac552e69 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -1,5 +1,6 @@ use bevy_asset::Asset; use bevy_color::{Alpha, ColorToComponents}; +use bevy_material::OpaqueRendererMethod; use bevy_math::{Affine2, Affine3, Mat2, Mat3, Vec2, Vec3, Vec4}; use bevy_mesh::MeshVertexBufferLayoutRef; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 2b834e1ecb8ac..eb7634626d5fa 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -5,11 +5,10 @@ use crate::{ collect_meshes_for_gpu_building, init_material_pipeline, set_mesh_motion_vector_flags, setup_morph_and_skinning_defs, skin, DeferredAlphaMaskDrawFunction, DeferredFragmentShader, DeferredOpaqueDrawFunction, DeferredVertexShader, DrawMesh, EntitySpecializationTicks, - ErasedMaterialPipelineKey, ErasedMeshPipelineKey, MaterialPipeline, MaterialProperties, - MeshLayouts, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial, + MaterialPipeline, MeshLayouts, MeshPipeline, MeshPipelineKey, PreparedMaterial, PrepassAlphaMaskDrawFunction, PrepassFragmentShader, PrepassOpaqueDrawFunction, PrepassVertexShader, RenderLightmaps, RenderMaterialInstances, RenderMeshInstanceFlags, - RenderMeshInstances, RenderPhaseType, SetMaterialBindGroup, SetMeshBindGroup, ShadowView, + RenderMeshInstances, SetMaterialBindGroup, SetMeshBindGroup, ShadowView, }; use bevy_app::{App, Plugin, PreUpdate}; use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle}; @@ -22,10 +21,13 @@ use bevy_ecs::{ SystemParam, SystemParamItem, SystemState, }, }; +use bevy_material::{ + key::{ErasedMaterialPipelineKey, ErasedMeshPipelineKey}, + AlphaMode, MaterialProperties, OpaqueRendererMethod, RenderPhaseType, +}; use bevy_math::{Affine3A, Mat4, Vec4}; use bevy_mesh::{Mesh, Mesh3d, MeshVertexBufferLayoutRef}; use bevy_render::{ - alpha::AlphaMode, batching::gpu_preprocessing::GpuPreprocessingSupport, globals::{GlobalsBuffer, GlobalsUniform}, mesh::{allocator::MeshAllocator, RenderMesh}, diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index e24f1643114fa..bcaefc8765039 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -29,6 +29,10 @@ use bevy_light::{ Cascades, DirectionalLight, DirectionalLightShadowMap, GlobalAmbientLight, NotShadowCaster, PointLight, PointLightShadowMap, ShadowFilteringMethod, SpotLight, VolumetricLight, }; +use bevy_material::{ + key::{ErasedMaterialPipelineKey, ErasedMeshPipelineKey}, + MaterialProperties, +}; use bevy_math::{ops, Mat4, UVec4, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_mesh::MeshVertexBufferLayoutRef; use bevy_platform::collections::{HashMap, HashSet}; diff --git a/crates/bevy_post_process/Cargo.toml b/crates/bevy_post_process/Cargo.toml index df0d8c848d62c..f23eca4d8b5fb 100644 --- a/crates/bevy_post_process/Cargo.toml +++ b/crates/bevy_post_process/Cargo.toml @@ -26,18 +26,13 @@ bevy_camera = { path = "../bevy_camera", version = "0.18.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.18.0-dev" } bevy_shader = { path = "../bevy_shader", version = "0.18.0-dev" } bevy_render = { path = "../bevy_render", version = "0.18.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.18.0-dev" } bevy_math = { path = "../bevy_math", version = "0.18.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.18.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.18.0-dev" } bevy_platform = { path = "../bevy_platform", version = "0.18.0-dev", default-features = false, features = [ "std", "serialize", ] } -bitflags = "2.3" -radsort = "0.1" -nonmax = "0.5" smallvec = { version = "1", default-features = false } thiserror = { version = "2", default-features = false } tracing = { version = "0.1", default-features = false, features = ["std"] } diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 278ae95b8fef7..cb4565c9a2d7a 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -61,8 +61,10 @@ bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.18.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.18.0-dev" } bevy_encase_derive = { path = "../bevy_encase_derive", version = "0.18.0-dev" } bevy_math = { path = "../bevy_math", version = "0.18.0-dev" } +bevy_material = { path = "../bevy_material", version = "0.18.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.18.0-dev" } -bevy_render_macros = { path = "macros", version = "0.18.0-dev" } +bevy_material_macros = { path = "../bevy_material/macros", version = "0.18.0-dev" } +bevy_render_macros = { path = "../bevy_render/macros", version = "0.18.0-dev" } bevy_time = { path = "../bevy_time", version = "0.18.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.18.0-dev" } bevy_window = { path = "../bevy_window", version = "0.18.0-dev" } diff --git a/crates/bevy_render/macros/src/lib.rs b/crates/bevy_render/macros/src/lib.rs index a30cce08f59d1..78b255e2a6eee 100644 --- a/crates/bevy_render/macros/src/lib.rs +++ b/crates/bevy_render/macros/src/lib.rs @@ -120,29 +120,3 @@ pub fn derive_specialize(input: TokenStream) -> TokenStream { pub fn derive_specializer_key(input: TokenStream) -> TokenStream { specializer::impl_specializer_key(input) } - -#[proc_macro_derive(ShaderLabel)] -pub fn derive_shader_label(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let mut trait_path = bevy_render_path(); - trait_path - .segments - .push(format_ident!("render_phase").into()); - trait_path - .segments - .push(format_ident!("ShaderLabel").into()); - derive_label(input, "ShaderLabel", &trait_path) -} - -#[proc_macro_derive(DrawFunctionLabel)] -pub fn derive_draw_function_label(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - let mut trait_path = bevy_render_path(); - trait_path - .segments - .push(format_ident!("render_phase").into()); - trait_path - .segments - .push(format_ident!("DrawFunctionLabel").into()); - derive_label(input, "DrawFunctionLabel", &trait_path) -} diff --git a/crates/bevy_render/src/batching/mod.rs b/crates/bevy_render/src/batching/mod.rs index bceca626417cd..1d585864c6024 100644 --- a/crates/bevy_render/src/batching/mod.rs +++ b/crates/bevy_render/src/batching/mod.rs @@ -7,12 +7,14 @@ use bytemuck::Pod; use gpu_preprocessing::UntypedPhaseIndirectParametersBuffers; use nonmax::NonMaxU32; +use bevy_material::{descriptor::CachedRenderPipelineId, labels::DrawFunctionId}; + use crate::{ render_phase::{ - BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItemExtraIndex, - SortedPhaseItem, SortedRenderPhase, ViewBinnedRenderPhases, + BinnedPhaseItem, CachedRenderPipelinePhaseItem, PhaseItemExtraIndex, SortedPhaseItem, + SortedRenderPhase, ViewBinnedRenderPhases, }, - render_resource::{CachedRenderPipelineId, GpuArrayBufferable}, + render_resource::GpuArrayBufferable, sync_world::MainEntity, }; diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 2325139a0af98..9b8725cd439eb 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -35,7 +35,6 @@ extern crate core; // Required to make proc macros work in bevy itself. extern crate self as bevy_render; -pub mod alpha; pub mod batching; pub mod camera; pub mod diagnostic; @@ -69,8 +68,8 @@ pub mod view; pub mod prelude { #[doc(hidden)] pub use crate::{ - alpha::AlphaMode, camera::NormalizedRenderTargetExt as _, texture::ManualTextureViews, - view::Msaa, ExtractSchedule, + camera::NormalizedRenderTargetExt as _, texture::ManualTextureViews, view::Msaa, + ExtractSchedule, }; } diff --git a/crates/bevy_render/src/render_phase/draw.rs b/crates/bevy_render/src/render_phase/draw.rs index 494074df4e43b..319c907843f68 100644 --- a/crates/bevy_render/src/render_phase/draw.rs +++ b/crates/bevy_render/src/render_phase/draw.rs @@ -1,3 +1,5 @@ +use bevy_material::labels::DrawFunctionId; + use crate::render_phase::{PhaseItem, TrackedRenderPass}; use bevy_app::{App, SubApp}; use bevy_ecs::{ @@ -8,7 +10,7 @@ use bevy_ecs::{ world::World, }; use bevy_utils::TypeIdMap; -use core::{any::TypeId, fmt::Debug, hash::Hash}; +use core::{any::TypeId, fmt::Debug}; use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; use variadics_please::all_tuples; @@ -49,11 +51,6 @@ pub enum DrawError { ViewEntityNotFound, } -// TODO: make this generic? -/// An identifier for a [`Draw`] function stored in [`DrawFunctions`]. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub struct DrawFunctionId(u32); - /// Stores all [`Draw`] functions for the [`PhaseItem`] type. /// /// For retrieval, the [`Draw`] functions are mapped to their respective [`TypeId`]s. diff --git a/crates/bevy_render/src/render_phase/mod.rs b/crates/bevy_render/src/render_phase/mod.rs index ea9deb540284a..fcd8547ec6f83 100644 --- a/crates/bevy_render/src/render_phase/mod.rs +++ b/crates/bevy_render/src/render_phase/mod.rs @@ -51,6 +51,8 @@ use crate::renderer::RenderDevice; use crate::sync_world::{MainEntity, MainEntityHashMap}; use crate::view::RetainedViewEntity; use crate::RenderDebugFlags; +use bevy_material::descriptor::CachedRenderPipelineId; + use crate::{ batching::{ self, @@ -58,46 +60,21 @@ use crate::{ no_gpu_preprocessing::{self, BatchedInstanceBuffer}, GetFullBatchData, }, - render_resource::{CachedRenderPipelineId, GpuArrayBufferIndex, PipelineCache}, + render_resource::{GpuArrayBufferIndex, PipelineCache}, Render, RenderApp, RenderSystems, }; -use bevy_ecs::intern::Interned; use bevy_ecs::{ - define_label, prelude::*, system::{lifetimeless::SRes, SystemParamItem}, }; +pub use bevy_material::labels::DrawFunctionId; +pub use bevy_material_macros::DrawFunctionLabel; +pub use bevy_material_macros::ShaderLabel; use bevy_render::renderer::RenderAdapterInfo; -pub use bevy_render_macros::ShaderLabel; use core::{fmt::Debug, hash::Hash, iter, marker::PhantomData, ops::Range, slice::SliceIndex}; use smallvec::SmallVec; use tracing::warn; -define_label!( - #[diagnostic::on_unimplemented( - note = "consider annotating `{Self}` with `#[derive(ShaderLabel)]`" - )] - /// Labels used to uniquely identify types of material shaders - ShaderLabel, - SHADER_LABEL_INTERNER -); - -/// A shorthand for `Interned`. -pub type InternedShaderLabel = Interned; - -pub use bevy_render_macros::DrawFunctionLabel; - -define_label!( - #[diagnostic::on_unimplemented( - note = "consider annotating `{Self}` with `#[derive(DrawFunctionLabel)]`" - )] - /// Labels used to uniquely identify types of material shaders - DrawFunctionLabel, - DRAW_FUNCTION_LABEL_INTERNER -); - -pub type InternedDrawFunctionLabel = Interned; - /// Stores the rendering instructions for a single phase that uses bins in all /// views. /// diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index 10d3760f45f6f..84f4a21814617 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -6,7 +6,7 @@ use crate::{ }; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::system::{SystemParam, SystemParamItem}; -use bevy_render::render_resource::BindGroupLayoutDescriptor; +use bevy_material::descriptor::BindGroupLayoutDescriptor; pub use bevy_render_macros::AsBindGroup; use bevy_utils::define_atomic_id; use core::ops::Deref; diff --git a/crates/bevy_render/src/render_resource/bindless.rs b/crates/bevy_render/src/render_resource/bindless.rs index dc3bf00eee95c..21bd770ecc348 100644 --- a/crates/bevy_render/src/render_resource/bindless.rs +++ b/crates/bevy_render/src/render_resource/bindless.rs @@ -11,10 +11,9 @@ use wgpu::{ BindGroupLayoutEntry, SamplerBindingType, ShaderStages, TextureSampleType, TextureViewDimension, }; -use crate::render_resource::binding_types::storage_buffer_read_only_sized; - -use super::binding_types::{ - sampler, texture_1d, texture_2d, texture_2d_array, texture_3d, texture_cube, texture_cube_array, +use bevy_material::bind_group_layout_entries::binding_types::{ + sampler, storage_buffer_read_only_sized, texture_1d, texture_2d, texture_2d_array, texture_3d, + texture_cube, texture_cube_array, }; /// The default value for the number of resources that can be stored in a slab diff --git a/crates/bevy_render/src/render_resource/gpu_array_buffer.rs b/crates/bevy_render/src/render_resource/gpu_array_buffer.rs index c99903394ed78..12ca04500ef6b 100644 --- a/crates/bevy_render/src/render_resource/gpu_array_buffer.rs +++ b/crates/bevy_render/src/render_resource/gpu_array_buffer.rs @@ -1,7 +1,9 @@ -use super::{ +use bevy_material::bind_group_layout_entries::{ binding_types::{storage_buffer_read_only, uniform_buffer_sized}, - BindGroupLayoutEntryBuilder, BufferVec, + BindGroupLayoutEntryBuilder, }; + +use super::BufferVec; use crate::{ render_resource::batched_uniform_buffer::BatchedUniformBuffer, renderer::{RenderDevice, RenderQueue}, diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index 70a2d160a1c56..20fb3e823e85e 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -2,7 +2,6 @@ mod batched_uniform_buffer; mod bind_group; mod bind_group_entries; mod bind_group_layout; -mod bind_group_layout_entries; mod bindless; mod buffer; mod buffer_vec; @@ -18,7 +17,6 @@ mod uniform_buffer; pub use bind_group::*; pub use bind_group_entries::*; pub use bind_group_layout::*; -pub use bind_group_layout_entries::*; pub use bindless::*; pub use buffer::*; pub use buffer_vec::*; @@ -71,3 +69,17 @@ pub mod encase { pub use self::encase::{ShaderSize, ShaderType}; pub use naga::ShaderStage; + +pub use bevy_material::{ + bind_group_layout_entries::{ + binding_types, BindGroupLayoutEntries, BindGroupLayoutEntryBuilder, + DynamicBindGroupLayoutEntries, IntoBindGroupLayoutEntryBuilder, + IntoBindGroupLayoutEntryBuilderArray, IntoIndexedBindGroupLayoutEntryBuilderArray, + }, + descriptor::{ + BindGroupLayoutDescriptor, CachedComputePipelineId, CachedRenderPipelineId, + ComputePipelineDescriptor, FragmentState, PipelineDescriptor, RenderPipelineDescriptor, + VertexState, + }, + specialize::SpecializedMeshPipelineError, +}; diff --git a/crates/bevy_render/src/render_resource/pipeline.rs b/crates/bevy_render/src/render_resource/pipeline.rs index 93a7e596d8354..427cfb5d6c3a4 100644 --- a/crates/bevy_render/src/render_resource/pipeline.rs +++ b/crates/bevy_render/src/render_resource/pipeline.rs @@ -1,16 +1,6 @@ use crate::renderer::WgpuWrapper; -use alloc::borrow::Cow; -use bevy_asset::Handle; -use bevy_mesh::VertexBufferLayout; -use bevy_shader::{Shader, ShaderDefVal}; use bevy_utils::define_atomic_id; -use core::iter; use core::ops::Deref; -use thiserror::Error; -use wgpu::{ - BindGroupLayoutEntry, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState, - PushConstantRange, -}; define_atomic_id!(RenderPipelineId); @@ -86,114 +76,3 @@ impl Deref for ComputePipeline { &self.value } } - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] -pub struct BindGroupLayoutDescriptor { - /// Debug label of the bind group layout descriptor. This will show up in graphics debuggers for easy identification. - pub label: Cow<'static, str>, - pub entries: Vec, -} - -impl BindGroupLayoutDescriptor { - pub fn new(label: impl Into>, entries: &[BindGroupLayoutEntry]) -> Self { - Self { - label: label.into(), - entries: entries.into(), - } - } -} - -/// Describes a render (graphics) pipeline. -#[derive(Clone, Debug, PartialEq, Default)] -pub struct RenderPipelineDescriptor { - /// Debug label of the pipeline. This will show up in graphics debuggers for easy identification. - pub label: Option>, - /// The layout of bind groups for this pipeline. - pub layout: Vec, - /// The push constant ranges for this pipeline. - /// Supply an empty vector if the pipeline doesn't use push constants. - pub push_constant_ranges: Vec, - /// The compiled vertex stage, its entry point, and the input buffers layout. - pub vertex: VertexState, - /// The properties of the pipeline at the primitive assembly and rasterization level. - pub primitive: PrimitiveState, - /// The effect of draw calls on the depth and stencil aspects of the output target, if any. - pub depth_stencil: Option, - /// The multi-sampling properties of the pipeline. - pub multisample: MultisampleState, - /// The compiled fragment stage, its entry point, and the color targets. - pub fragment: Option, - /// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true. - /// If this is false, reading from workgroup variables before writing to them will result in garbage values. - pub zero_initialize_workgroup_memory: bool, -} - -#[derive(Copy, Clone, Debug, Error)] -#[error("RenderPipelineDescriptor has no FragmentState configured")] -pub struct NoFragmentStateError; - -impl RenderPipelineDescriptor { - pub fn fragment_mut(&mut self) -> Result<&mut FragmentState, NoFragmentStateError> { - self.fragment.as_mut().ok_or(NoFragmentStateError) - } - - pub fn set_layout(&mut self, index: usize, layout: BindGroupLayoutDescriptor) { - filling_set_at(&mut self.layout, index, bevy_utils::default(), layout); - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Default)] -pub struct VertexState { - /// The compiled shader module for this stage. - pub shader: Handle, - pub shader_defs: Vec, - /// The name of the entry point in the compiled shader, or `None` if the default entry point - /// is used. - pub entry_point: Option>, - /// The format of any vertex buffers used with this pipeline. - pub buffers: Vec, -} - -/// Describes the fragment process in a render pipeline. -#[derive(Clone, Debug, PartialEq, Eq, Default)] -pub struct FragmentState { - /// The compiled shader module for this stage. - pub shader: Handle, - pub shader_defs: Vec, - /// The name of the entry point in the compiled shader, or `None` if the default entry point - /// is used. - pub entry_point: Option>, - /// The color state of the render targets. - pub targets: Vec>, -} - -impl FragmentState { - pub fn set_target(&mut self, index: usize, target: ColorTargetState) { - filling_set_at(&mut self.targets, index, None, Some(target)); - } -} - -/// Describes a compute pipeline. -#[derive(Clone, Debug, PartialEq, Eq, Default)] -pub struct ComputePipelineDescriptor { - pub label: Option>, - pub layout: Vec, - pub push_constant_ranges: Vec, - /// The compiled shader module for this stage. - pub shader: Handle, - pub shader_defs: Vec, - /// The name of the entry point in the compiled shader, or `None` if the default entry point - /// is used. - pub entry_point: Option>, - /// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true. - /// If this is false, reading from workgroup variables before writing to them will result in garbage values. - pub zero_initialize_workgroup_memory: bool, -} - -// utility function to set a value at the specified index, extending with -// a filler value if the index is out of bounds. -fn filling_set_at(vec: &mut Vec, index: usize, filler: T, value: T) { - let num_to_fill = (index + 1).saturating_sub(vec.len()); - vec.extend(iter::repeat_n(filler, num_to_fill)); - vec[index] = value; -} diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 93e985a44b31f..bbe08d80bea4f 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -1,3 +1,8 @@ +use bevy_material::descriptor::{ + BindGroupLayoutDescriptor, CachedComputePipelineId, CachedRenderPipelineId, + ComputePipelineDescriptor, PipelineDescriptor, RenderPipelineDescriptor, +}; + use crate::{ render_resource::*, renderer::{RenderAdapter, RenderDevice, WgpuWrapper}, @@ -17,20 +22,11 @@ use bevy_shader::{ }; use bevy_tasks::Task; use bevy_utils::default; -use core::{future::Future, hash::Hash, mem}; +use core::{future::Future, mem}; use std::sync::{Mutex, PoisonError}; use tracing::error; use wgpu::{PipelineCompilationOptions, VertexBufferLayout as RawVertexBufferLayout}; -/// A descriptor for a [`Pipeline`]. -/// -/// Used to store a heterogenous collection of render and compute pipeline descriptors together. -#[derive(Debug)] -pub enum PipelineDescriptor { - RenderPipelineDescriptor(Box), - ComputePipelineDescriptor(Box), -} - /// A pipeline defining the data layout and shader logic for a specific GPU task. /// /// Used to store a heterogenous collection of render and compute pipelines together. @@ -40,34 +36,6 @@ pub enum Pipeline { ComputePipeline(ComputePipeline), } -/// Index of a cached render pipeline in a [`PipelineCache`]. -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct CachedRenderPipelineId(CachedPipelineId); - -impl CachedRenderPipelineId { - /// An invalid cached render pipeline index, often used to initialize a variable. - pub const INVALID: Self = CachedRenderPipelineId(usize::MAX); - - #[inline] - pub fn id(&self) -> usize { - self.0 - } -} - -/// Index of a cached compute pipeline in a [`PipelineCache`]. -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub struct CachedComputePipelineId(CachedPipelineId); - -impl CachedComputePipelineId { - /// An invalid cached compute pipeline index, often used to initialize a variable. - pub const INVALID: Self = CachedComputePipelineId(usize::MAX); - - #[inline] - pub fn id(&self) -> usize { - self.0 - } -} - pub struct CachedPipeline { pub descriptor: PipelineDescriptor, pub state: CachedPipelineState, @@ -302,7 +270,7 @@ impl PipelineCache { pub fn get_render_pipeline_state(&self, id: CachedRenderPipelineId) -> &CachedPipelineState { // If the pipeline id isn't in `pipelines`, it's queued in `new_pipelines` self.pipelines - .get(id.0) + .get(id.id()) .map_or(&CachedPipelineState::Queued, |pipeline| &pipeline.state) } @@ -313,7 +281,7 @@ impl PipelineCache { pub fn get_compute_pipeline_state(&self, id: CachedComputePipelineId) -> &CachedPipelineState { // If the pipeline id isn't in `pipelines`, it's queued in `new_pipelines` self.pipelines - .get(id.0) + .get(id.id()) .map_or(&CachedPipelineState::Queued, |pipeline| &pipeline.state) } @@ -328,7 +296,7 @@ impl PipelineCache { &self, id: CachedRenderPipelineId, ) -> &RenderPipelineDescriptor { - match &self.pipelines[id.0].descriptor { + match &self.pipelines[id.id()].descriptor { PipelineDescriptor::RenderPipelineDescriptor(descriptor) => descriptor, PipelineDescriptor::ComputePipelineDescriptor(_) => unreachable!(), } @@ -345,7 +313,7 @@ impl PipelineCache { &self, id: CachedComputePipelineId, ) -> &ComputePipelineDescriptor { - match &self.pipelines[id.0].descriptor { + match &self.pipelines[id.id()].descriptor { PipelineDescriptor::RenderPipelineDescriptor(_) => unreachable!(), PipelineDescriptor::ComputePipelineDescriptor(descriptor) => descriptor, } @@ -361,7 +329,7 @@ impl PipelineCache { #[inline] pub fn get_render_pipeline(&self, id: CachedRenderPipelineId) -> Option<&RenderPipeline> { if let CachedPipelineState::Ok(Pipeline::RenderPipeline(pipeline)) = - &self.pipelines.get(id.0)?.state + &self.pipelines.get(id.id())?.state { Some(pipeline) } else { @@ -372,11 +340,11 @@ impl PipelineCache { /// Wait for a render pipeline to finish compiling. #[inline] pub fn block_on_render_pipeline(&mut self, id: CachedRenderPipelineId) { - if self.pipelines.len() <= id.0 { + if self.pipelines.len() <= id.id() { self.process_queue(); } - let state = &mut self.pipelines[id.0].state; + let state = &mut self.pipelines[id.id()].state; if let CachedPipelineState::Creating(task) = state { *state = match bevy_tasks::block_on(task) { Ok(p) => CachedPipelineState::Ok(p), @@ -395,7 +363,7 @@ impl PipelineCache { #[inline] pub fn get_compute_pipeline(&self, id: CachedComputePipelineId) -> Option<&ComputePipeline> { if let CachedPipelineState::Ok(Pipeline::ComputePipeline(pipeline)) = - &self.pipelines.get(id.0)?.state + &self.pipelines.get(id.id())?.state { Some(pipeline) } else { @@ -424,7 +392,7 @@ impl PipelineCache { .new_pipelines .lock() .unwrap_or_else(PoisonError::into_inner); - let id = CachedRenderPipelineId(self.pipelines.len() + new_pipelines.len()); + let id = CachedRenderPipelineId::new(self.pipelines.len() + new_pipelines.len()); new_pipelines.push(CachedPipeline { descriptor: PipelineDescriptor::RenderPipelineDescriptor(Box::new(descriptor)), state: CachedPipelineState::Queued, @@ -453,7 +421,7 @@ impl PipelineCache { .new_pipelines .lock() .unwrap_or_else(PoisonError::into_inner); - let id = CachedComputePipelineId(self.pipelines.len() + new_pipelines.len()); + let id = CachedComputePipelineId::new(self.pipelines.len() + new_pipelines.len()); new_pipelines.push(CachedPipeline { descriptor: PipelineDescriptor::ComputePipelineDescriptor(Box::new(descriptor)), state: CachedPipelineState::Queued, diff --git a/crates/bevy_render/src/render_resource/pipeline_specializer.rs b/crates/bevy_render/src/render_resource/pipeline_specializer.rs index f2e84a2fc3575..ff10eed4c65e6 100644 --- a/crates/bevy_render/src/render_resource/pipeline_specializer.rs +++ b/crates/bevy_render/src/render_resource/pipeline_specializer.rs @@ -1,9 +1,12 @@ -use crate::render_resource::{ - CachedComputePipelineId, CachedRenderPipelineId, ComputePipelineDescriptor, PipelineCache, +use bevy_material::descriptor::{ + CachedComputePipelineId, CachedRenderPipelineId, ComputePipelineDescriptor, RenderPipelineDescriptor, }; + +use crate::render_resource::PipelineCache; use bevy_ecs::resource::Resource; -use bevy_mesh::{MeshVertexBufferLayoutRef, MissingVertexAttributeError, VertexBufferLayout}; +use bevy_material::specialize::SpecializedMeshPipelineError; +use bevy_mesh::{MeshVertexBufferLayoutRef, VertexBufferLayout}; use bevy_platform::{ collections::{ hash_map::{Entry, RawEntryMut, VacantEntry}, @@ -12,8 +15,7 @@ use bevy_platform::{ hash::FixedHasher, }; use bevy_utils::default; -use core::{fmt::Debug, hash::Hash}; -use thiserror::Error; +use core::hash::Hash; use tracing::error; /// A trait that allows constructing different variants of a render pipeline from a key. @@ -251,9 +253,3 @@ impl SpecializedMeshPipelines { } } } - -#[derive(Error, Debug)] -pub enum SpecializedMeshPipelineError { - #[error(transparent)] - MissingVertexAttribute(#[from] MissingVertexAttributeError), -} diff --git a/crates/bevy_render/src/render_resource/specializer.rs b/crates/bevy_render/src/render_resource/specializer.rs index 2dc52577db690..668de9eb88c06 100644 --- a/crates/bevy_render/src/render_resource/specializer.rs +++ b/crates/bevy_render/src/render_resource/specializer.rs @@ -1,7 +1,9 @@ -use super::{ - CachedComputePipelineId, CachedRenderPipelineId, ComputePipeline, ComputePipelineDescriptor, - PipelineCache, RenderPipeline, RenderPipelineDescriptor, +use bevy_material::descriptor::{ + CachedComputePipelineId, CachedRenderPipelineId, ComputePipelineDescriptor, + RenderPipelineDescriptor, }; + +use super::{ComputePipeline, PipelineCache, RenderPipeline}; use bevy_ecs::error::BevyError; use bevy_platform::{ collections::{ diff --git a/crates/bevy_render/src/view/window/screenshot.rs b/crates/bevy_render/src/view/window/screenshot.rs index 655b9b30bbe4e..ffb3120df5213 100644 --- a/crates/bevy_render/src/view/window/screenshot.rs +++ b/crates/bevy_render/src/view/window/screenshot.rs @@ -3,10 +3,8 @@ use crate::{ gpu_readback, render_asset::RenderAssets, render_resource::{ - binding_types::texture_2d, BindGroup, BindGroupEntries, BindGroupLayoutDescriptor, - BindGroupLayoutEntries, Buffer, BufferUsages, CachedRenderPipelineId, FragmentState, - PipelineCache, RenderPipelineDescriptor, SpecializedRenderPipeline, - SpecializedRenderPipelines, Texture, TextureUsages, TextureView, VertexState, + BindGroup, BindGroupEntries, Buffer, BufferUsages, PipelineCache, + SpecializedRenderPipeline, SpecializedRenderPipelines, Texture, TextureUsages, TextureView, }, renderer::RenderDevice, texture::{GpuImage, ManualTextureViews, OutputColorAttachment}, @@ -22,6 +20,13 @@ use bevy_ecs::{ entity::EntityHashMap, message::message_update_system, prelude::*, system::SystemState, }; use bevy_image::{Image, TextureFormatPixelInfo, ToExtents}; +use bevy_material::{ + bind_group_layout_entries::{binding_types::texture_2d, BindGroupLayoutEntries}, + descriptor::{ + BindGroupLayoutDescriptor, CachedRenderPipelineId, FragmentState, RenderPipelineDescriptor, + VertexState, + }, +}; use bevy_platform::collections::HashSet; use bevy_reflect::Reflect; use bevy_shader::Shader; diff --git a/crates/bevy_sprite_render/Cargo.toml b/crates/bevy_sprite_render/Cargo.toml index c607255280cb9..ddf62433219dd 100644 --- a/crates/bevy_sprite_render/Cargo.toml +++ b/crates/bevy_sprite_render/Cargo.toml @@ -25,6 +25,7 @@ bevy_camera = { path = "../bevy_camera", version = "0.18.0-dev" } bevy_mesh = { path = "../bevy_mesh", version = "0.18.0-dev" } bevy_math = { path = "../bevy_math", version = "0.18.0-dev" } bevy_shader = { path = "../bevy_shader", version = "0.18.0-dev" } +bevy_material = { path = "../bevy_material", version = "0.18.0-dev" } bevy_sprite = { path = "../bevy_sprite", version = "0.18.0-dev" } bevy_text = { path = "../bevy_text", version = "0.18.0-dev", optional = true } bevy_reflect = { path = "../bevy_reflect", version = "0.18.0-dev" } diff --git a/crates/bevy_sprite_render/src/mesh2d/material.rs b/crates/bevy_sprite_render/src/mesh2d/material.rs index d4f64fa87acc0..72e223ec725d7 100644 --- a/crates/bevy_sprite_render/src/mesh2d/material.rs +++ b/crates/bevy_sprite_render/src/mesh2d/material.rs @@ -235,7 +235,7 @@ impl AsAssetId for MeshMaterial2d { /// Sets how a 2d material's base color alpha channel is used for transparency. /// Currently, this only works with [`Mesh2d`]. Sprites are always transparent. /// -/// This is very similar to [`AlphaMode`](bevy_render::alpha::AlphaMode) but this only applies to 2d meshes. +/// This is very similar to [`AlphaMode`](bevy_material::AlphaMode) but this only applies to 2d meshes. /// We use a separate type because 2d doesn't support all the transparency modes that 3d does. #[derive(Debug, Default, Reflect, Copy, Clone, PartialEq)] #[reflect(Default, Debug, Clone)] diff --git a/docs/cargo_features.md b/docs/cargo_features.md index 231038b9e1f31..62f1020f8ea8f 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -84,6 +84,7 @@ This is the complete `bevy` cargo feature list, without "profiles" or "collectio |bevy_input_focus|Enable input focus subsystem| |bevy_light|Provides light types such as point lights, directional lights, spotlights.| |bevy_log|Enable integration with `tracing` and `log`| +|bevy_material|Provides materials.| |bevy_mesh|Provides a mesh format and some primitive meshing routines.| |bevy_mikktspace|Provides vertex tangent generation for use with bevy_mesh.| |bevy_pbr|Adds PBR rendering| diff --git a/examples/3d/deferred_rendering.rs b/examples/3d/deferred_rendering.rs index ff3656d7a6ecb..7ab00ee971793 100644 --- a/examples/3d/deferred_rendering.rs +++ b/examples/3d/deferred_rendering.rs @@ -9,8 +9,9 @@ use bevy::{ light::{ CascadeShadowConfigBuilder, DirectionalLightShadowMap, NotShadowCaster, NotShadowReceiver, }, + material::OpaqueRendererMethod, math::ops, - pbr::{DefaultOpaqueRendererMethod, OpaqueRendererMethod}, + pbr::DefaultOpaqueRendererMethod, prelude::*, }; diff --git a/examples/shader/extended_material.rs b/examples/shader/extended_material.rs index 0c6011f976367..dd0c3b9ae3c5c 100644 --- a/examples/shader/extended_material.rs +++ b/examples/shader/extended_material.rs @@ -2,7 +2,8 @@ use bevy::{ color::palettes::basic::RED, - pbr::{ExtendedMaterial, MaterialExtension, OpaqueRendererMethod}, + material::OpaqueRendererMethod, + pbr::{ExtendedMaterial, MaterialExtension}, prelude::*, render::render_resource::*, shader::ShaderRef, diff --git a/examples/shader_advanced/manual_material.rs b/examples/shader_advanced/manual_material.rs index f7ac7c66cdec7..4243cbb8c8e58 100644 --- a/examples/shader_advanced/manual_material.rs +++ b/examples/shader_advanced/manual_material.rs @@ -7,13 +7,14 @@ use bevy::{ lifetimeless::{SRes, SResMut}, SystemChangeTick, SystemParamItem, }, + material::MaterialProperties, pbr::{ late_sweep_material_instances, DrawMaterial, EntitiesNeedingSpecialization, EntitySpecializationTickPair, EntitySpecializationTicks, MainPassOpaqueDrawFunction, MaterialBindGroupAllocator, MaterialBindGroupAllocators, MaterialExtractEntitiesNeedingSpecializationSystems, MaterialExtractionSystems, - MaterialFragmentShader, MaterialProperties, PreparedMaterial, RenderMaterialBindings, - RenderMaterialInstance, RenderMaterialInstances, SpecializedMaterialPipelineCache, + MaterialFragmentShader, PreparedMaterial, RenderMaterialBindings, RenderMaterialInstance, + RenderMaterialInstances, SpecializedMaterialPipelineCache, }, platform::collections::hash_map::Entry, prelude::*, diff --git a/release-content/migration-guides/bevy_material.md b/release-content/migration-guides/bevy_material.md new file mode 100644 index 0000000000000..a09cd29e67eab --- /dev/null +++ b/release-content/migration-guides/bevy_material.md @@ -0,0 +1,23 @@ +--- +title: "New crate `bevy_material`" +pull_requests: [22426] +--- + +Various material-related machinery where extracted from `bevy_pbr` and `bevy_render` into a new crate called `bevy_material`. + +The following were moved from `bevy_render` to `bevy_material`: + +- `AlphaMode` +- `SpecializedMeshPipelineError` + +The following were moved from `bevy_pbr` to `bevy_material`: + +- `OpaqueRendererMethod` +- `ErasedMeshPipelineKey`, `ErasedMaterialPipelineKey`, `ErasedMaterialKey`, `ErasedMaterialKeyVTable`, `RenderPhaseType` +- `MaterialProperties` + +The following were moved from `bevy_render` to `bevy_material` but do not require migration thanks to re-exports: + +- `BindGroupLayoutDescriptor`, `RenderPipelineDescriptor`, `NoFragmentStateError`, `VertexState`, `FragmentState`, `ComputePipelineDescriptor` +- `ShaderLabel`, `DrawFunctionLabel`, `DrawFunctionId` +- `BindGroupLayoutEntryBuilder`, `BindGroupLayoutEntries`, `DynamicBindGroupLayoutEntries`, `IntoBindGroupLayoutEntryBuilder`, `IntoIndexedBindGroupLayoutEntryBuilderArray`