Skip to content

Commit 1caa64d

Browse files
authored
Refactor AsBindGroup to use a associated SystemParam. (#14909)
# Objective Adding more features to `AsBindGroup` proc macro means making the trait arguments uglier. Downstream implementors of the trait without the proc macro might want to do different things than our default arguments. ## Solution Make `AsBindGroup` take an associated `Param` type. ## Migration Guide `AsBindGroup` now allows the user to specify a `SystemParam` to be used for creating bind groups.
1 parent 3892adc commit 1caa64d

File tree

7 files changed

+44
-65
lines changed

7 files changed

+44
-65
lines changed

crates/bevy_pbr/src/extended_material.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use bevy_asset::{Asset, Handle};
2+
use bevy_ecs::system::SystemParamItem;
23
use bevy_reflect::{impl_type_path, Reflect};
34
use bevy_render::{
45
mesh::MeshVertexBufferLayoutRef,
5-
render_asset::RenderAssets,
66
render_resource::{
77
AsBindGroup, AsBindGroupError, BindGroupLayout, RenderPipelineDescriptor, Shader,
88
ShaderRef, SpecializedMeshPipelineError, UnpreparedBindGroup,
99
},
1010
renderer::RenderDevice,
11-
texture::{FallbackImage, GpuImage},
1211
};
1312

1413
use crate::{Material, MaterialPipeline, MaterialPipelineKey, MeshPipeline, MeshPipelineKey};
@@ -147,26 +146,21 @@ impl_type_path!((in bevy_pbr::extended_material) ExtendedMaterial<B: Material, E
147146

148147
impl<B: Material, E: MaterialExtension> AsBindGroup for ExtendedMaterial<B, E> {
149148
type Data = (<B as AsBindGroup>::Data, <E as AsBindGroup>::Data);
149+
type Param = (<B as AsBindGroup>::Param, <E as AsBindGroup>::Param);
150150

151151
fn unprepared_bind_group(
152152
&self,
153153
layout: &BindGroupLayout,
154154
render_device: &RenderDevice,
155-
images: &RenderAssets<GpuImage>,
156-
fallback_image: &FallbackImage,
155+
(base_param, extended_param): &mut SystemParamItem<'_, '_, Self::Param>,
157156
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError> {
158157
// add together the bindings of the base material and the user material
159158
let UnpreparedBindGroup {
160159
mut bindings,
161160
data: base_data,
162-
} = B::unprepared_bind_group(&self.base, layout, render_device, images, fallback_image)?;
163-
let extended_bindgroup = E::unprepared_bind_group(
164-
&self.extension,
165-
layout,
166-
render_device,
167-
images,
168-
fallback_image,
169-
)?;
161+
} = B::unprepared_bind_group(&self.base, layout, render_device, base_param)?;
162+
let extended_bindgroup =
163+
E::unprepared_bind_group(&self.extension, layout, render_device, extended_param)?;
170164

171165
bindings.extend(extended_bindgroup.bindings);
172166

crates/bevy_pbr/src/material.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use bevy_render::{
3030
render_phase::*,
3131
render_resource::*,
3232
renderer::RenderDevice,
33-
texture::FallbackImage,
3433
view::{ExtractedView, Msaa, RenderVisibilityRanges, VisibleEntities, WithMesh},
3534
};
3635
use bevy_utils::tracing::error;
@@ -908,22 +907,16 @@ impl<M: Material> RenderAsset for PreparedMaterial<M> {
908907

909908
type Param = (
910909
SRes<RenderDevice>,
911-
SRes<RenderAssets<GpuImage>>,
912-
SRes<FallbackImage>,
913910
SRes<MaterialPipeline<M>>,
914911
SRes<DefaultOpaqueRendererMethod>,
912+
M::Param,
915913
);
916914

917915
fn prepare_asset(
918916
material: Self::SourceAsset,
919-
(render_device, images, fallback_image, pipeline, default_opaque_render_method): &mut SystemParamItem<Self::Param>,
917+
(render_device, pipeline, default_opaque_render_method, ref mut material_param): &mut SystemParamItem<Self::Param>,
920918
) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
921-
match material.as_bind_group(
922-
&pipeline.material_layout,
923-
render_device,
924-
images,
925-
fallback_image,
926-
) {
919+
match material.as_bind_group(&pipeline.material_layout, render_device, material_param) {
927920
Ok(prepared) => {
928921
let method = match material.opaque_render_method() {
929922
OpaqueRendererMethod::Forward => OpaqueRendererMethod::Forward,

crates/bevy_render/macros/src/as_bind_group.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
4242
let manifest = BevyManifest::default();
4343
let render_path = manifest.get_path("bevy_render");
4444
let asset_path = manifest.get_path("bevy_asset");
45+
let ecs_path = manifest.get_path("bevy_ecs");
4546

4647
let mut binding_states: Vec<BindingState> = Vec::new();
4748
let mut binding_impls = Vec::new();
@@ -62,7 +63,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
6263
binding_impls.push(quote! {{
6364
use #render_path::render_resource::AsBindGroupShaderType;
6465
let mut buffer = #render_path::render_resource::encase::UniformBuffer::new(Vec::new());
65-
let converted: #converted_shader_type = self.as_bind_group_shader_type(images);
66+
let converted: #converted_shader_type = self.as_bind_group_shader_type(&images);
6667
buffer.write(&converted).unwrap();
6768
(
6869
#binding_index,
@@ -523,6 +524,11 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
523524
impl #impl_generics #render_path::render_resource::AsBindGroup for #struct_name #ty_generics #where_clause {
524525
type Data = #prepared_data;
525526

527+
type Param = (
528+
#ecs_path::system::lifetimeless::SRes<#render_path::render_asset::RenderAssets<#render_path::texture::GpuImage>>,
529+
#ecs_path::system::lifetimeless::SRes<#render_path::texture::FallbackImage>,
530+
);
531+
526532
fn label() -> Option<&'static str> {
527533
Some(#struct_name_literal)
528534
}
@@ -531,8 +537,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
531537
&self,
532538
layout: &#render_path::render_resource::BindGroupLayout,
533539
render_device: &#render_path::renderer::RenderDevice,
534-
images: &#render_path::render_asset::RenderAssets<#render_path::texture::GpuImage>,
535-
fallback_image: &#render_path::texture::FallbackImage,
540+
(images, fallback_image): &mut #ecs_path::system::SystemParamItem<'_, '_, Self::Param>,
536541
) -> Result<#render_path::render_resource::UnpreparedBindGroup<Self::Data>, #render_path::render_resource::AsBindGroupError> {
537542
let bindings = vec![#(#binding_impls,)*];
538543

crates/bevy_render/src/render_resource/bind_group.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use crate::{
33
render_asset::RenderAssets,
44
render_resource::{resource_macros::*, BindGroupLayout, Buffer, Sampler, TextureView},
55
renderer::RenderDevice,
6-
texture::{FallbackImage, GpuImage},
6+
texture::GpuImage,
77
};
8+
use bevy_ecs::system::{SystemParam, SystemParamItem};
89
pub use bevy_render_macros::AsBindGroup;
910
use encase::ShaderType;
1011
use std::ops::Deref;
@@ -57,7 +58,7 @@ impl Deref for BindGroup {
5758
///
5859
/// This is an opinionated trait that is intended to make it easy to generically
5960
/// convert a type into a [`BindGroup`]. It provides access to specific render resources,
60-
/// such as [`RenderAssets<GpuImage>`] and [`FallbackImage`]. If a type has a [`Handle<Image>`](bevy_asset::Handle),
61+
/// such as [`RenderAssets<GpuImage>`] and [`crate::texture::FallbackImage`]. If a type has a [`Handle<Image>`](bevy_asset::Handle),
6162
/// these can be used to retrieve the corresponding [`Texture`](crate::render_resource::Texture) resource.
6263
///
6364
/// [`AsBindGroup::as_bind_group`] is intended to be called once, then the result cached somewhere. It is generally
@@ -115,7 +116,7 @@ impl Deref for BindGroup {
115116
/// * This field's [`Handle<Image>`](bevy_asset::Handle) will be used to look up the matching [`Texture`](crate::render_resource::Texture)
116117
/// GPU resource, which will be bound as a texture in shaders. The field will be assumed to implement [`Into<Option<Handle<Image>>>`]. In practice,
117118
/// most fields should be a [`Handle<Image>`](bevy_asset::Handle) or [`Option<Handle<Image>>`]. If the value of an [`Option<Handle<Image>>`] is
118-
/// [`None`], the [`FallbackImage`] resource will be used instead. This attribute can be used in conjunction with a `sampler` binding attribute
119+
/// [`None`], the [`crate::texture::FallbackImage`] resource will be used instead. This attribute can be used in conjunction with a `sampler` binding attribute
119120
/// (with a different binding index) if a binding of the sampler for the [`Image`](crate::texture::Image) is also required.
120121
///
121122
/// | Arguments | Values | Default |
@@ -130,7 +131,7 @@ impl Deref for BindGroup {
130131
/// * This field's [`Handle<Image>`](bevy_asset::Handle) will be used to look up the matching [`Texture`](crate::render_resource::Texture)
131132
/// GPU resource, which will be bound as a storage texture in shaders. The field will be assumed to implement [`Into<Option<Handle<Image>>>`]. In practice,
132133
/// most fields should be a [`Handle<Image>`](bevy_asset::Handle) or [`Option<Handle<Image>>`]. If the value of an [`Option<Handle<Image>>`] is
133-
/// [`None`], the [`FallbackImage`] resource will be used instead.
134+
/// [`None`], the [`crate::texture::FallbackImage`] resource will be used instead.
134135
///
135136
/// | Arguments | Values | Default |
136137
/// |------------------------|--------------------------------------------------------------------------------------------|---------------|
@@ -143,7 +144,7 @@ impl Deref for BindGroup {
143144
/// * This field's [`Handle<Image>`](bevy_asset::Handle) will be used to look up the matching [`Sampler`] GPU
144145
/// resource, which will be bound as a sampler in shaders. The field will be assumed to implement [`Into<Option<Handle<Image>>>`]. In practice,
145146
/// most fields should be a [`Handle<Image>`](bevy_asset::Handle) or [`Option<Handle<Image>>`]. If the value of an [`Option<Handle<Image>>`] is
146-
/// [`None`], the [`FallbackImage`] resource will be used instead. This attribute can be used in conjunction with a `texture` binding attribute
147+
/// [`None`], the [`crate::texture::FallbackImage`] resource will be used instead. This attribute can be used in conjunction with a `texture` binding attribute
147148
/// (with a different binding index) if a binding of the texture for the [`Image`](crate::texture::Image) is also required.
148149
///
149150
/// | Arguments | Values | Default |
@@ -187,7 +188,7 @@ impl Deref for BindGroup {
187188
/// color_texture: Option<Handle<Image>>,
188189
/// }
189190
/// ```
190-
/// This is useful if you want a texture to be optional. When the value is [`None`], the [`FallbackImage`] will be used for the binding instead, which defaults
191+
/// This is useful if you want a texture to be optional. When the value is [`None`], the [`crate::texture::FallbackImage`] will be used for the binding instead, which defaults
191192
/// to "pure white".
192193
///
193194
/// Field uniforms with the same index will be combined into a single binding:
@@ -284,6 +285,8 @@ pub trait AsBindGroup {
284285
/// Data that will be stored alongside the "prepared" bind group.
285286
type Data: Send + Sync;
286287

288+
type Param: SystemParam + 'static;
289+
287290
/// label
288291
fn label() -> Option<&'static str> {
289292
None
@@ -294,11 +297,10 @@ pub trait AsBindGroup {
294297
&self,
295298
layout: &BindGroupLayout,
296299
render_device: &RenderDevice,
297-
images: &RenderAssets<GpuImage>,
298-
fallback_image: &FallbackImage,
300+
param: &mut SystemParamItem<'_, '_, Self::Param>,
299301
) -> Result<PreparedBindGroup<Self::Data>, AsBindGroupError> {
300302
let UnpreparedBindGroup { bindings, data } =
301-
Self::unprepared_bind_group(self, layout, render_device, images, fallback_image)?;
303+
Self::unprepared_bind_group(self, layout, render_device, param)?;
302304

303305
let entries = bindings
304306
.iter()
@@ -325,8 +327,7 @@ pub trait AsBindGroup {
325327
&self,
326328
layout: &BindGroupLayout,
327329
render_device: &RenderDevice,
328-
images: &RenderAssets<GpuImage>,
329-
fallback_image: &FallbackImage,
330+
param: &mut SystemParamItem<'_, '_, Self::Param>,
330331
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError>;
331332

332333
/// Creates the bind group layout matching all bind groups returned by [`AsBindGroup::as_bind_group`]

crates/bevy_sprite/src/mesh2d/material.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ use bevy_render::{
2828
SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines,
2929
},
3030
renderer::RenderDevice,
31-
texture::{FallbackImage, GpuImage},
3231
view::{ExtractedView, InheritedVisibility, Msaa, ViewVisibility, Visibility, VisibleEntities},
3332
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
3433
};
@@ -581,23 +580,13 @@ impl<T: Material2d> PreparedMaterial2d<T> {
581580
impl<M: Material2d> RenderAsset for PreparedMaterial2d<M> {
582581
type SourceAsset = M;
583582

584-
type Param = (
585-
SRes<RenderDevice>,
586-
SRes<RenderAssets<GpuImage>>,
587-
SRes<FallbackImage>,
588-
SRes<Material2dPipeline<M>>,
589-
);
583+
type Param = (SRes<RenderDevice>, SRes<Material2dPipeline<M>>, M::Param);
590584

591585
fn prepare_asset(
592586
material: Self::SourceAsset,
593-
(render_device, images, fallback_image, pipeline): &mut SystemParamItem<Self::Param>,
587+
(render_device, pipeline, material_param): &mut SystemParamItem<Self::Param>,
594588
) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
595-
match material.as_bind_group(
596-
&pipeline.material2d_layout,
597-
render_device,
598-
images,
599-
fallback_image,
600-
) {
589+
match material.as_bind_group(&pipeline.material2d_layout, render_device, material_param) {
601590
Ok(prepared) => {
602591
let mut mesh_pipeline_key_bits = Mesh2dPipelineKey::empty();
603592
mesh_pipeline_key_bits.insert(alpha_mode_pipeline_key(material.alpha_mode()));

crates/bevy_ui/src/render/ui_material_pipeline.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use bevy_render::{
1616
render_phase::*,
1717
render_resource::{binding_types::uniform_buffer, *},
1818
renderer::{RenderDevice, RenderQueue},
19-
texture::{BevyDefault, FallbackImage, GpuImage},
19+
texture::BevyDefault,
2020
view::*,
2121
Extract, ExtractSchedule, Render, RenderSet,
2222
};
@@ -604,18 +604,13 @@ pub struct PreparedUiMaterial<T: UiMaterial> {
604604
impl<M: UiMaterial> RenderAsset for PreparedUiMaterial<M> {
605605
type SourceAsset = M;
606606

607-
type Param = (
608-
SRes<RenderDevice>,
609-
SRes<RenderAssets<GpuImage>>,
610-
SRes<FallbackImage>,
611-
SRes<UiMaterialPipeline<M>>,
612-
);
607+
type Param = (SRes<RenderDevice>, SRes<UiMaterialPipeline<M>>, M::Param);
613608

614609
fn prepare_asset(
615610
material: Self::SourceAsset,
616-
(render_device, images, fallback_image, pipeline): &mut SystemParamItem<Self::Param>,
611+
(render_device, pipeline, ref mut material_param): &mut SystemParamItem<Self::Param>,
617612
) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
618-
match material.as_bind_group(&pipeline.ui_layout, render_device, images, fallback_image) {
613+
match material.as_bind_group(&pipeline.ui_layout, render_device, material_param) {
619614
Ok(prepared) => Ok(PreparedUiMaterial {
620615
bindings: prepared.bindings,
621616
bind_group: prepared.bind_group,

examples/shader/texture_binding_array.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! A shader that binds several textures onto one
22
//! `binding_array<texture<f32>>` shader binding slot and sample non-uniformly.
33
4+
use bevy::ecs::system::lifetimeless::SRes;
5+
use bevy::ecs::system::SystemParamItem;
46
use bevy::{
57
prelude::*,
68
reflect::TypePath,
@@ -97,12 +99,13 @@ struct BindlessMaterial {
9799
impl AsBindGroup for BindlessMaterial {
98100
type Data = ();
99101

102+
type Param = (SRes<RenderAssets<GpuImage>>, SRes<FallbackImage>);
103+
100104
fn as_bind_group(
101105
&self,
102106
layout: &BindGroupLayout,
103107
render_device: &RenderDevice,
104-
image_assets: &RenderAssets<GpuImage>,
105-
fallback_image: &FallbackImage,
108+
(image_assets, fallback_image): &mut SystemParamItem<'_, '_, Self::Param>,
106109
) -> Result<PreparedBindGroup<Self::Data>, AsBindGroupError> {
107110
// retrieve the render resources from handles
108111
let mut images = vec![];
@@ -140,10 +143,9 @@ impl AsBindGroup for BindlessMaterial {
140143

141144
fn unprepared_bind_group(
142145
&self,
143-
_: &BindGroupLayout,
144-
_: &RenderDevice,
145-
_: &RenderAssets<GpuImage>,
146-
_: &FallbackImage,
146+
_layout: &BindGroupLayout,
147+
_render_device: &RenderDevice,
148+
_param: &mut SystemParamItem<'_, '_, Self::Param>,
147149
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError> {
148150
// we implement as_bind_group directly because
149151
panic!("bindless texture arrays can't be owned")

0 commit comments

Comments
 (0)