nuke most of stuff
TODO: migration guide
This commit is contained in:
parent
c9c8964857
commit
0d9f1c81ce
@ -87,7 +87,6 @@ struct FieldInfo {
|
||||
ty: Type,
|
||||
member: Member,
|
||||
key: Key,
|
||||
use_base_descriptor: bool,
|
||||
}
|
||||
|
||||
impl FieldInfo {
|
||||
@ -117,15 +116,6 @@ impl FieldInfo {
|
||||
parse_quote!(#ty: #specialize_path::Specializer<#target_path>)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_base_descriptor_predicate(
|
||||
&self,
|
||||
specialize_path: &Path,
|
||||
target_path: &Path,
|
||||
) -> WherePredicate {
|
||||
let ty = &self.ty;
|
||||
parse_quote!(#ty: #specialize_path::GetBaseDescriptor<#target_path>)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_field_info(
|
||||
@ -190,7 +180,6 @@ fn get_field_info(
|
||||
ty: field_ty,
|
||||
member: field_member,
|
||||
key,
|
||||
use_base_descriptor,
|
||||
});
|
||||
}
|
||||
|
||||
@ -261,41 +250,18 @@ pub fn impl_specializer(input: TokenStream) -> TokenStream {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let base_descriptor_fields = field_info
|
||||
.iter()
|
||||
.filter(|field| field.use_base_descriptor)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if base_descriptor_fields.len() > 1 {
|
||||
return syn::Error::new(
|
||||
Span::call_site(),
|
||||
"Too many #[base_descriptor] attributes found. It must be present on exactly one field",
|
||||
)
|
||||
.into_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let base_descriptor_field = base_descriptor_fields.first().copied();
|
||||
|
||||
match targets {
|
||||
SpecializeImplTargets::All => {
|
||||
let specialize_impl = impl_specialize_all(
|
||||
&specialize_path,
|
||||
&ecs_path,
|
||||
&ast,
|
||||
&field_info,
|
||||
&key_patterns,
|
||||
&key_tuple_idents,
|
||||
);
|
||||
let get_base_descriptor_impl = base_descriptor_field
|
||||
.map(|field_info| impl_get_base_descriptor_all(&specialize_path, &ast, field_info))
|
||||
.unwrap_or_default();
|
||||
[specialize_impl, get_base_descriptor_impl]
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
SpecializeImplTargets::Specific(targets) => {
|
||||
let specialize_impls = targets.iter().map(|target| {
|
||||
SpecializeImplTargets::All => impl_specialize_all(
|
||||
&specialize_path,
|
||||
&ecs_path,
|
||||
&ast,
|
||||
&field_info,
|
||||
&key_patterns,
|
||||
&key_tuple_idents,
|
||||
),
|
||||
SpecializeImplTargets::Specific(targets) => targets
|
||||
.iter()
|
||||
.map(|target| {
|
||||
impl_specialize_specific(
|
||||
&specialize_path,
|
||||
&ecs_path,
|
||||
@ -305,14 +271,8 @@ pub fn impl_specializer(input: TokenStream) -> TokenStream {
|
||||
&key_patterns,
|
||||
&key_tuple_idents,
|
||||
)
|
||||
});
|
||||
let get_base_descriptor_impls = targets.iter().filter_map(|target| {
|
||||
base_descriptor_field.map(|field_info| {
|
||||
impl_get_base_descriptor_specific(&specialize_path, &ast, field_info, target)
|
||||
})
|
||||
});
|
||||
specialize_impls.chain(get_base_descriptor_impls).collect()
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,56 +366,6 @@ fn impl_specialize_specific(
|
||||
})
|
||||
}
|
||||
|
||||
fn impl_get_base_descriptor_specific(
|
||||
specialize_path: &Path,
|
||||
ast: &DeriveInput,
|
||||
base_descriptor_field_info: &FieldInfo,
|
||||
target_path: &Path,
|
||||
) -> TokenStream {
|
||||
let struct_name = &ast.ident;
|
||||
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
|
||||
let field_ty = &base_descriptor_field_info.ty;
|
||||
let field_member = &base_descriptor_field_info.member;
|
||||
TokenStream::from(quote!(
|
||||
impl #impl_generics #specialize_path::GetBaseDescriptor<#target_path> for #struct_name #type_generics #where_clause {
|
||||
fn get_base_descriptor(&self) -> <#target_path as #specialize_path::Specializable>::Descriptor {
|
||||
<#field_ty as #specialize_path::GetBaseDescriptor<#target_path>>::get_base_descriptor(&self.#field_member)
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
fn impl_get_base_descriptor_all(
|
||||
specialize_path: &Path,
|
||||
ast: &DeriveInput,
|
||||
base_descriptor_field_info: &FieldInfo,
|
||||
) -> TokenStream {
|
||||
let target_path = Path::from(format_ident!("T"));
|
||||
let struct_name = &ast.ident;
|
||||
let mut generics = ast.generics.clone();
|
||||
generics.params.insert(
|
||||
0,
|
||||
parse_quote!(#target_path: #specialize_path::Specializable),
|
||||
);
|
||||
|
||||
let where_clause = generics.make_where_clause();
|
||||
where_clause.predicates.push(
|
||||
base_descriptor_field_info.get_base_descriptor_predicate(specialize_path, &target_path),
|
||||
);
|
||||
|
||||
let (_, type_generics, _) = ast.generics.split_for_impl();
|
||||
let (impl_generics, _, where_clause) = &generics.split_for_impl();
|
||||
let field_ty = &base_descriptor_field_info.ty;
|
||||
let field_member = &base_descriptor_field_info.member;
|
||||
TokenStream::from(quote! {
|
||||
impl #impl_generics #specialize_path::GetBaseDescriptor<#target_path> for #struct_name #type_generics #where_clause {
|
||||
fn get_base_descriptor(&self) -> <#target_path as #specialize_path::Specializable>::Descriptor {
|
||||
<#field_ty as #specialize_path::GetBaseDescriptor<#target_path>>::get_base_descriptor(&self.#field_member)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn impl_specializer_key(input: TokenStream) -> TokenStream {
|
||||
let bevy_render_path: Path = crate::bevy_render_path();
|
||||
let specialize_path = {
|
||||
|
||||
@ -2,11 +2,7 @@ use super::{
|
||||
CachedComputePipelineId, CachedRenderPipelineId, ComputePipeline, ComputePipelineDescriptor,
|
||||
PipelineCache, RenderPipeline, RenderPipelineDescriptor,
|
||||
};
|
||||
use bevy_ecs::{
|
||||
error::BevyError,
|
||||
resource::Resource,
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
use bevy_ecs::error::BevyError;
|
||||
use bevy_platform::{
|
||||
collections::{
|
||||
hash_map::{Entry, VacantEntry},
|
||||
@ -260,91 +256,12 @@ macro_rules! impl_specialization_key_tuple {
|
||||
// TODO: How to we fake_variadics this?
|
||||
all_tuples!(impl_specialization_key_tuple, 0, 12, T);
|
||||
|
||||
/// Defines a specializer that can also provide a "base descriptor".
|
||||
///
|
||||
/// In order to be composable, [`Specializer`] implementers don't create full
|
||||
/// descriptors, only transform them. However, [`SpecializedCache`]s need a
|
||||
/// "base descriptor" at creation time in order to have something for the
|
||||
/// [`Specializer`] to work off of. This trait allows [`SpecializedCache`]
|
||||
/// to impl [`FromWorld`] for [`Specializer`]s that also satisfy [`FromWorld`]
|
||||
/// and [`GetBaseDescriptor`].
|
||||
///
|
||||
/// This trait can be also derived with `#[derive(Specializer)]`, by marking
|
||||
/// a field with `#[base_descriptor]` to use its [`GetBaseDescriptor`] implementation.
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
/// # use bevy_ecs::error::BevyError;
|
||||
/// # use bevy_render::render_resource::Specializer;
|
||||
/// # use bevy_render::render_resource::GetBaseDescriptor;
|
||||
/// # use bevy_render::render_resource::SpecializerKey;
|
||||
/// # use bevy_render::render_resource::RenderPipeline;
|
||||
/// # use bevy_render::render_resource::RenderPipelineDescriptor;
|
||||
/// struct A;
|
||||
/// struct B;
|
||||
///
|
||||
/// impl Specializer<RenderPipeline> for A {
|
||||
/// # type Key = ();
|
||||
/// #
|
||||
/// # fn specialize(
|
||||
/// # &self,
|
||||
/// # key: (),
|
||||
/// # _descriptor: &mut RenderPipelineDescriptor
|
||||
/// # ) -> Result<(), BevyError> {
|
||||
/// # Ok(key)
|
||||
/// # }
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// impl Specializer<RenderPipeline> for B {
|
||||
/// # type Key = ();
|
||||
/// #
|
||||
/// # fn specialize(
|
||||
/// # &self,
|
||||
/// # key: (),
|
||||
/// # _descriptor: &mut RenderPipelineDescriptor
|
||||
/// # ) -> Result<(), BevyError> {
|
||||
/// # Ok(key)
|
||||
/// # }
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// impl GetBaseDescriptor<RenderPipeline> for B {
|
||||
/// fn get_base_descriptor(&self) -> RenderPipelineDescriptor {
|
||||
/// # todo!()
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// #[derive(Specializer)]
|
||||
/// #[specialize(RenderPipeline)]
|
||||
/// struct C {
|
||||
/// a: A,
|
||||
/// #[base_descriptor]
|
||||
/// b: B,
|
||||
/// }
|
||||
///
|
||||
/// /*
|
||||
/// The generated implementation:
|
||||
/// impl GetBaseDescriptor for C {
|
||||
/// fn get_base_descriptor(&self) -> RenderPipelineDescriptor {
|
||||
/// self.b.base_descriptor()
|
||||
/// }
|
||||
/// }
|
||||
/// */
|
||||
/// ```
|
||||
pub trait GetBaseDescriptor<T: Specializable>: Specializer<T> {
|
||||
fn get_base_descriptor(&self) -> T::Descriptor;
|
||||
}
|
||||
|
||||
pub type SpecializerFn<T, S> =
|
||||
fn(<S as Specializer<T>>::Key, &mut <T as Specializable>::Descriptor) -> Result<(), BevyError>;
|
||||
|
||||
/// A cache for specializable resources. For a given key type the resulting
|
||||
/// resource will only be created if it is missing, retrieving it from the
|
||||
/// cache otherwise.
|
||||
#[derive(Resource)]
|
||||
pub struct SpecializedCache<T: Specializable, S: Specializer<T>> {
|
||||
specializer: S,
|
||||
user_specializer: Option<SpecializerFn<T, S>>,
|
||||
@ -447,19 +364,3 @@ impl<T: Specializable, S: Specializer<T>> SpecializedCache<T, S> {
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
|
||||
/// [`SpecializedCache`] implements [`FromWorld`] for [`Specializer`]s
|
||||
/// that also satisfy [`FromWorld`] and [`GetBaseDescriptor`]. This will
|
||||
/// create a [`SpecializedCache`] with no user specializer, and the base
|
||||
/// descriptor take from the specializer's [`GetBaseDescriptor`] implementation.
|
||||
impl<T, S> FromWorld for SpecializedCache<T, S>
|
||||
where
|
||||
T: Specializable,
|
||||
S: FromWorld + Specializer<T> + GetBaseDescriptor<T>,
|
||||
{
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let specializer = S::from_world(world);
|
||||
let base_descriptor = specializer.get_base_descriptor();
|
||||
Self::new(specializer, None, base_descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,8 +25,8 @@ use bevy::{
|
||||
},
|
||||
render_resource::{
|
||||
BufferUsages, Canonical, ColorTargetState, ColorWrites, CompareFunction,
|
||||
DepthStencilState, FragmentState, GetBaseDescriptor, IndexFormat, PipelineCache,
|
||||
RawBufferVec, RenderPipeline, RenderPipelineDescriptor, SpecializedCache, Specializer,
|
||||
DepthStencilState, FragmentState, IndexFormat, PipelineCache, RawBufferVec,
|
||||
RenderPipeline, RenderPipelineDescriptor, SpecializedCache, Specializer,
|
||||
SpecializerKey, TextureFormat, VertexAttribute, VertexBufferLayout, VertexFormat,
|
||||
VertexState, VertexStepMode,
|
||||
},
|
||||
@ -165,9 +165,8 @@ fn main() {
|
||||
.add_systems(Startup, setup);
|
||||
|
||||
// We make sure to add these to the render app, not the main app.
|
||||
app.get_sub_app_mut(RenderApp)
|
||||
.unwrap()
|
||||
.init_resource::<SpecializedCache<RenderPipeline, CustomPhaseSpecializer>>()
|
||||
app.sub_app_mut(RenderApp)
|
||||
.init_resource::<CustomPhasePipeline>()
|
||||
.add_render_command::<Opaque3d, DrawCustomPhaseItemCommands>()
|
||||
.add_systems(
|
||||
Render,
|
||||
@ -212,9 +211,9 @@ fn prepare_custom_phase_item_buffers(mut commands: Commands) {
|
||||
/// the opaque render phases of each view.
|
||||
fn queue_custom_phase_item(
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut pipeline: ResMut<CustomPhasePipeline>,
|
||||
mut opaque_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3d>>,
|
||||
opaque_draw_functions: Res<DrawFunctions<Opaque3d>>,
|
||||
mut specializer: ResMut<SpecializedCache<RenderPipeline, CustomPhaseSpecializer>>,
|
||||
views: Query<(&ExtractedView, &RenderVisibleEntities, &Msaa)>,
|
||||
mut next_tick: Local<Tick>,
|
||||
) {
|
||||
@ -237,7 +236,9 @@ fn queue_custom_phase_item(
|
||||
// some per-view settings, such as whether the view is HDR, but for
|
||||
// simplicity's sake we simply hard-code the view's characteristics,
|
||||
// with the exception of number of MSAA samples.
|
||||
let Ok(pipeline_id) = specializer.specialize(&pipeline_cache, CustomPhaseKey(*msaa))
|
||||
let Ok(pipeline_id) = pipeline
|
||||
.specialized_cache
|
||||
.specialize(&pipeline_cache, CustomPhaseKey(*msaa))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
@ -275,44 +276,24 @@ fn queue_custom_phase_item(
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds a reference to our shader.
|
||||
///
|
||||
/// This is loaded at app creation time.
|
||||
struct CustomPhaseSpecializer {
|
||||
struct CustomPhaseSpecializer;
|
||||
|
||||
#[derive(Resource)]
|
||||
struct CustomPhasePipeline {
|
||||
/// Holds a reference to our shader.
|
||||
shader: Handle<Shader>,
|
||||
specialized_cache: SpecializedCache<RenderPipeline, CustomPhaseSpecializer>,
|
||||
}
|
||||
|
||||
impl FromWorld for CustomPhaseSpecializer {
|
||||
impl FromWorld for CustomPhasePipeline {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let asset_server = world.resource::<AssetServer>();
|
||||
Self {
|
||||
shader: asset_server.load("shaders/custom_phase_item.wgsl"),
|
||||
}
|
||||
}
|
||||
}
|
||||
let shader = asset_server.load("shaders/custom_phase_item.wgsl");
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, SpecializerKey)]
|
||||
struct CustomPhaseKey(Msaa);
|
||||
|
||||
impl Specializer<RenderPipeline> for CustomPhaseSpecializer {
|
||||
type Key = CustomPhaseKey;
|
||||
|
||||
fn specialize(
|
||||
&self,
|
||||
key: Self::Key,
|
||||
descriptor: &mut RenderPipelineDescriptor,
|
||||
) -> Result<Canonical<Self::Key>, BevyError> {
|
||||
descriptor.multisample.count = key.0.samples();
|
||||
Ok(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl GetBaseDescriptor<RenderPipeline> for CustomPhaseSpecializer {
|
||||
fn get_base_descriptor(&self) -> RenderPipelineDescriptor {
|
||||
RenderPipelineDescriptor {
|
||||
let base_descriptor = RenderPipelineDescriptor {
|
||||
label: Some("custom render pipeline".into()),
|
||||
vertex: VertexState {
|
||||
shader: self.shader.clone(),
|
||||
shader: shader.clone(),
|
||||
buffers: vec![VertexBufferLayout {
|
||||
array_stride: size_of::<Vertex>() as u64,
|
||||
step_mode: VertexStepMode::Vertex,
|
||||
@ -333,7 +314,7 @@ impl GetBaseDescriptor<RenderPipeline> for CustomPhaseSpecializer {
|
||||
..default()
|
||||
},
|
||||
fragment: Some(FragmentState {
|
||||
shader: self.shader.clone(),
|
||||
shader: shader.clone(),
|
||||
targets: vec![Some(ColorTargetState {
|
||||
// Ordinarily, you'd want to check whether the view has the
|
||||
// HDR format and substitute the appropriate texture format
|
||||
@ -354,10 +335,34 @@ impl GetBaseDescriptor<RenderPipeline> for CustomPhaseSpecializer {
|
||||
bias: default(),
|
||||
}),
|
||||
..default()
|
||||
};
|
||||
|
||||
let specialized_cache =
|
||||
SpecializedCache::new(CustomPhaseSpecializer, None, base_descriptor);
|
||||
|
||||
Self {
|
||||
shader,
|
||||
specialized_cache,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, SpecializerKey)]
|
||||
struct CustomPhaseKey(Msaa);
|
||||
|
||||
impl Specializer<RenderPipeline> for CustomPhaseSpecializer {
|
||||
type Key = CustomPhaseKey;
|
||||
|
||||
fn specialize(
|
||||
&self,
|
||||
key: Self::Key,
|
||||
descriptor: &mut RenderPipelineDescriptor,
|
||||
) -> Result<Canonical<Self::Key>, BevyError> {
|
||||
descriptor.multisample.count = key.0.samples();
|
||||
Ok(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWorld for CustomPhaseItemBuffers {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let render_device = world.resource::<RenderDevice>();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user