Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions _release-content/migration-guides/extract-extract-a.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
---
title: Extract Extract
pull_requests: [24420]
pull_requests: [24419, 24420, 24423]
---

Extraction used to be specific of Main World to Render World, but will now be generic

- Use `TemporaryRenderEntity::default()` instead of `TemporaryRenderEntity`
- When using extraction related traits e.g. `SyncComponent`, `ExtractComponent` and `ExtractResource`,
you must specify the `AppLabel` for the target world.

Expand All @@ -14,7 +15,6 @@ Before:
impl SyncComponent for TemporalAntiAliasing { ... }

#[derive(Component, ExtractComponent)]
#[extract_app(RenderApp)]
pub struct Foo { ... }
```

Expand All @@ -28,4 +28,10 @@ impl SyncComponent<RenderApp> for TemporalAntiAliasing { ... }
pub struct Foo { ... }
```

NOTE: more to come
You can now extract a component from the main subapp to multiple subapps. To extract a component to multiple subapps, list them as arguments to `extract_app`:

```rust,ignore
#[derive(Component, Clone, Debug, ExtractComponent)]
#[extract_app(RenderApp, AudioApp)]
struct SomeComponent;
```
14 changes: 11 additions & 3 deletions benches/benches/bevy_render/extract_render_asset.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use bevy_app::{App, AppLabel};
use bevy_asset::{Asset, AssetApp, AssetEvent, AssetId, Assets, RenderAssetUsages};
use bevy_ecs::prelude::*;
use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
use bevy_reflect::TypePath;
use bevy_render::{
extract_plugin::ExtractPlugin,
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin},
RenderApp,
Render, RenderApp, RenderSystems,
};
use criterion::{criterion_group, BenchmarkId, Criterion, Throughput};
use std::time::{Duration, Instant};
Expand Down Expand Up @@ -33,6 +33,8 @@ impl RenderAsset for DummyRenderAsset {
}
}

pub(crate) fn pre_extract(_main_world: &mut World, _render_world: &mut World) {}

fn extract_render_asset_bench(c: &mut Criterion) {
let mut group = c.benchmark_group("extract_render_asset");

Expand All @@ -45,7 +47,13 @@ fn extract_render_asset_bench(c: &mut Criterion) {

app.add_plugins(bevy_asset::AssetPlugin::default());
app.init_asset::<DummyAsset>();
app.add_plugins(ExtractPlugin::default());
app.add_plugins(ExtractPlugin::<RenderApp>::new(
pre_extract,
Render::base_schedule,
Render.intern(),
RenderSystems::ExtractCommands.intern(),
RenderSystems::PostCleanup.intern(),
));
app.add_plugins(RenderAssetPlugin::<DummyRenderAsset>::default());

app.finish();
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ use std::{
};

bevy_ecs::define_label!(
/// A strongly-typed class of labels used to identify an [`App`].
/// A strongly-typed class of labels used to uniquely identify an [`App`].
/// An [`AppLabel`] should not be an enum.
#[diagnostic::on_unimplemented(
note = "consider annotating `{Self}` with `#[derive(AppLabel)]`"
)]
Expand Down Expand Up @@ -1946,7 +1947,7 @@ mod tests {
fn test_extract_sees_changes() {
use super::AppLabel;

#[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug, Default)]
struct MySubApp;

#[derive(Resource)]
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_app/src/sub_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type ExtractFn = Box<dyn FnMut(&mut World, &mut World) + Send>;
/// #[derive(Resource, Default)]
/// struct Val(pub i32);
///
/// #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)]
/// #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel, Default)]
/// struct ExampleApp;
///
/// // Create an app with a certain resource.
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/skybox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Plugin for SkyboxPlugin {
embedded_asset!(app, "skybox.wgsl");

app.add_plugins((
SyncComponentPlugin::<Skybox, Self>::default(),
SyncComponentPlugin::<Skybox, RenderApp, Self>::default(),
UniformComponentPlugin::<SkyboxUniforms>::default(),
));

Expand Down
1 change: 1 addition & 0 deletions crates/bevy_pbr/src/cluster/gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ impl Plugin for GpuClusteringPlugin {

app.add_plugins(ExtractResourcePlugin::<
GlobalClusterSettings,
RenderApp,
GpuClusteringPlugin,
>::default());
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/decal/clustered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl Plugin for ClusteredDecalPlugin {
fn build(&self, app: &mut App) {
load_shader_library!(app, "clustered.wgsl");

app.add_plugins(SyncComponentPlugin::<ClusteredDecal, Self>::default());
app.add_plugins(SyncComponentPlugin::<ClusteredDecal, RenderApp, Self>::default());

let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ impl Plugin for PbrPlugin {
ScreenSpaceAmbientOcclusionPlugin,
FogPlugin,
ExtractResourcePlugin::<DefaultOpaqueRendererMethod>::default(),
SyncComponentPlugin::<ShadowFilteringMethod, Self>::default(),
SyncComponentPlugin::<ShadowFilteringMethod, RenderApp, Self>::default(),
LightmapPlugin,
LightProbePlugin,
GpuMeshPreprocessPlugin {
Expand All @@ -233,11 +233,11 @@ impl Plugin for PbrPlugin {
))
.add_plugins((
decal::ForwardDecalPlugin,
SyncComponentPlugin::<DirectionalLight, Self>::default(),
SyncComponentPlugin::<PointLight, Self>::default(),
SyncComponentPlugin::<SpotLight, Self>::default(),
SyncComponentPlugin::<RectLight, Self>::default(),
SyncComponentPlugin::<AmbientLight, Self>::default(),
SyncComponentPlugin::<DirectionalLight, RenderApp, Self>::default(),
SyncComponentPlugin::<PointLight, RenderApp, Self>::default(),
SyncComponentPlugin::<SpotLight, RenderApp, Self>::default(),
SyncComponentPlugin::<RectLight, RenderApp, Self>::default(),
SyncComponentPlugin::<AmbientLight, RenderApp, Self>::default(),
))
.add_plugins((
ScatteringMediumPlugin,
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_pbr/src/light_probe/environment_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ use bevy_render::{
},
renderer::{RenderAdapter, RenderDevice},
texture::{FallbackImage, GpuImage},
RenderApp,
};

use core::{num::NonZero, ops::Deref};
Expand Down Expand Up @@ -139,7 +140,7 @@ pub struct EnvironmentMapViewLightProbeInfo {
pub(crate) rotation: Quat,
}

impl ExtractInstance for EnvironmentMapIds {
impl ExtractInstance<RenderApp> for EnvironmentMapIds {
type QueryData = Read<EnvironmentMapLight>;

type QueryFilter = ();
Expand Down
6 changes: 5 additions & 1 deletion crates/bevy_pbr/src/light_probe/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ impl Plugin for EnvironmentMapGenerationPlugin {
embedded_asset!(app, "environment_filter.wgsl");
embedded_asset!(app, "copy.wgsl");

app.add_plugins(SyncComponentPlugin::<GeneratedEnvironmentMapLight, Self>::default())
app.add_plugins(SyncComponentPlugin::<
GeneratedEnvironmentMapLight,
RenderApp,
Self,
>::default())
.add_systems(Update, generate_environment_map_light);

let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/light_probe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ impl Plugin for LightProbePlugin {

app.add_plugins((
EnvironmentMapGenerationPlugin,
ExtractInstancesPlugin::<EnvironmentMapIds>::new(),
ExtractInstancesPlugin::<EnvironmentMapIds, RenderApp>::new(),
));

let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/volumetric_fog/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl Plugin for VolumetricFogPlugin {
let plane_mesh = meshes.add(Plane3d::new(Vec3::Z, Vec2::ONE).mesh());
let cube_mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0).mesh());

app.add_plugins(SyncComponentPlugin::<FogVolume, Self>::default());
app.add_plugins(SyncComponentPlugin::<FogVolume, RenderApp, Self>::default());

let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
Expand Down
62 changes: 36 additions & 26 deletions crates/bevy_render/macros/src/extract_component.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy_macro_utils::fq_std::{FQClone, FQOption};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, parse_quote, DeriveInput, Path};
use syn::{parse_macro_input, parse_quote, punctuated::Punctuated, DeriveInput, Path};

pub fn derive_extract_component(input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as DeriveInput);
Expand All @@ -20,21 +20,29 @@ pub fn derive_extract_component(input: TokenStream) -> TokenStream {
let struct_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();

let app_label = match ast.attrs.iter().find(|a| a.path().is_ident("extract_app")) {
Some(attr) => match attr.parse_args::<syn::Type>() {
Ok(label) => label,
Err(e) => return e.to_compile_error().into(),
},
None => {
return syn::Error::new_spanned(
&ast.ident,
"ExtractComponent requires #[extract_app(MyAppLabel)] to specify the target sub-app",
)
.to_compile_error()
.into();
}
let Some(attr) = ast.attrs.iter().find(|a| a.path().is_ident("extract_app")) else {
return syn::Error::new_spanned(
&ast.ident,
"ExtractComponent requires #[extract_app(MyAppLabelA, MyAppLabelB)] to specify the target sub-app(s)",
)
.to_compile_error()
.into();
};

let app_labels: Vec<Path> =
match attr.parse_args_with(Punctuated::<Path, syn::Token![,]>::parse_terminated) {
Ok(labels) if labels.is_empty() => {
return syn::Error::new_spanned(
attr,
"#[extract_app] requires at least one AppLabel, e.g. #[extract_app(RenderApp)]",
)
.to_compile_error()
.into();
}
Ok(labels) => labels.into_iter().collect(),
Err(e) => return e.to_compile_error().into(),
};

let filter = if let Some(attr) = ast
.attrs
.iter()
Expand Down Expand Up @@ -73,20 +81,22 @@ pub fn derive_extract_component(input: TokenStream) -> TokenStream {
}
};

TokenStream::from(quote! {
impl #impl_generics #bevy_render_path::sync_component::SyncComponent<#app_label> for #struct_name #type_generics #where_clause {
type Target = #sync_target;
}
app_labels.iter().map(|app_label|
TokenStream::from(quote! {
impl #impl_generics #bevy_render_path::sync_component::SyncComponent<#app_label> for #struct_name #type_generics #where_clause {
type Target = #sync_target;
}

impl #impl_generics #bevy_render_path::extract_component::ExtractComponent<#app_label> for #struct_name #type_generics #where_clause {
type QueryData = &'static Self;
impl #impl_generics #bevy_render_path::extract_component::ExtractComponent<#app_label> for #struct_name #type_generics #where_clause {
type QueryData = &'static Self;

type QueryFilter = #filter;
type Out = Self;
type QueryFilter = #filter;
type Out = Self;

fn extract_component(item: #bevy_ecs_path::query::QueryItem<'_, '_, Self::QueryData>) -> #FQOption<Self::Out> {
#FQOption::Some(item.clone())
fn extract_component(item: #bevy_ecs_path::query::QueryItem<'_, '_, Self::QueryData>) -> #FQOption<Self::Out> {
#FQOption::Some(item.clone())
}
}
}
})
})
).collect()
}
3 changes: 2 additions & 1 deletion crates/bevy_render/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ impl Plugin for CameraPlugin {
.add_systems(
ExtractSchedule,
(
extract_cameras.after(extract_resource::<ManualTextureViews, ()>),
extract_cameras
.after(extract_resource::<ManualTextureViews, RenderApp, ()>),
clear_dirty_specializations.in_set(DirtySpecializationSystems::Clear),
clear_dirty_wireframe_specializations
.in_set(DirtySpecializationSystems::Clear),
Expand Down
Loading