Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let query items borrow from query state to avoid needing to clone #15396

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e99a0c1
Don't obtain two NameOrEntity items at once from QueryState::get().
chescock Sep 18, 2024
f295624
Introduce a ReleaseStateQueryData trait that will release borrows on …
chescock Sep 22, 2024
648eb31
Add a 'state lifetime to query items and fetches.
chescock Sep 22, 2024
b870249
Merge remote-tracking branch 'remotes/origin/main' into state-in-quer…
chescock Sep 23, 2024
f6f4259
Fix merge conflicts with traversal changes.
chescock Sep 23, 2024
be7a1de
Merge remote-tracking branch 'remotes/origin/main' into state-in-quer…
chescock Sep 28, 2024
0872293
Link to update_archetypes() and corresponding _manual() methods where…
chescock Sep 29, 2024
70ced02
Merge remote-tracking branch 'remotes/origin/main' into state-in-quer…
chescock Sep 29, 2024
d1fbada
Fix merge conflicts with QuerySingle.
chescock Sep 29, 2024
22eee9e
Merge remote-tracking branch 'remotes/origin/main' into state-in-quer…
chescock Nov 10, 2024
174af45
Fix new uses of Item<'w>.
chescock Nov 10, 2024
18520ef
Merge commit '6be11a8a42c2c73646cc994392bbd628b6de523b' into state-in…
chescock Feb 9, 2025
a080cb0
Fix build.
chescock Feb 9, 2025
ac313fd
Update AssetChanged.
chescock Feb 9, 2025
9a74906
impl ReleaseStateQueryData for Traversal types.
chescock Feb 9, 2025
6188a86
Add `expect` and `reason` for `allow(clippy::unused_unit)` in tuple i…
chescock Feb 9, 2025
9871970
Merge commit '03af547c2898cb905b3917725b13081e48654b15' into state-in…
chescock Feb 9, 2025
371ca14
Merge remote-tracking branch 'remotes/origin/main' into state-in-quer…
chescock Feb 10, 2025
5dce18f
Restore changes lost by bad merging.
chescock Feb 10, 2025
d63f936
impl ReleaseStateQueryData for Option, MainEntity, and RenderEntity.
chescock Feb 10, 2025
7ad98aa
Implement ReleaseStateQueryData for derived QueryData.
chescock Feb 10, 2025
e89a909
Use `collect()` in `QueryIter::sort()`.
chescock Feb 9, 2025
df2fcce
Merge remote-tracking branch 'remotes/origin/main' into state-in-quer…
chescock Feb 12, 2025
f7c3b27
Update new uses of `QueryItem` to include `'s` lifetime.
chescock Feb 12, 2025
4e60256
Document that most QueryData types impl ReleaseStateQueryData.
chescock Feb 12, 2025
42d5aa3
Merge remote-tracking branch 'remotes/origin/main' into state-in-quer…
chescock Mar 7, 2025
a748abe
Add `'s` lifetime to new uses of QueryItem.
chescock Mar 7, 2025
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
26 changes: 16 additions & 10 deletions crates/bevy_asset/src/asset_changed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,22 @@ pub struct AssetChangedState<A: AsAssetId> {
#[expect(unsafe_code, reason = "WorldQuery is an unsafe trait.")]
/// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
type Fetch<'w> = AssetChangedFetch<'w, A>;
type Fetch<'w, 's> = AssetChangedFetch<'w, A>;

type State = AssetChangedState<A>;

fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
fn shrink_fetch<'wlong: 'wshort, 'wshort, 's>(
fetch: Self::Fetch<'wlong, 's>,
) -> Self::Fetch<'wshort, 's> {
fetch
}

unsafe fn init_fetch<'w>(
unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
state: &Self::State,
state: &'s Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
) -> Self::Fetch<'w, 's> {
// SAFETY:
// - `AssetChanges` is private and only accessed mutably in the `AssetEvents` schedule
// - `resource_id` was obtained from the type ID of `AssetChanges<A::Asset>`.
Expand Down Expand Up @@ -202,9 +204,9 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {

const IS_DENSE: bool = <&A>::IS_DENSE;

unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w, 's>,
state: &'s Self::State,
archetype: &'w Archetype,
table: &'w Table,
) {
Expand All @@ -216,7 +218,11 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
}
}

unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
unsafe fn set_table<'w, 's>(
fetch: &mut Self::Fetch<'w, 's>,
state: &Self::State,
table: &'w Table,
) {
if let Some(inner) = &mut fetch.inner {
// SAFETY: We delegate to the inner `set_table` for `A`
unsafe {
Expand Down Expand Up @@ -266,7 +272,7 @@ unsafe impl<A: AsAssetId> QueryFilter for AssetChanged<A> {

#[inline]
unsafe fn filter_fetch(
fetch: &mut Self::Fetch<'_>,
fetch: &mut Self::Fetch<'_, '_>,
entity: Entity,
table_row: TableRow,
) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/bloom/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ impl ExtractComponent for Bloom {
type QueryFilter = ();
type Out = (Self, BloomUniforms);

fn extract_component((bloom, camera): QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
fn extract_component((bloom, camera): QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
match (
camera.physical_viewport_rect(),
camera.physical_viewport_size(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl ViewNode for MainOpaquePass2dNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(camera, view, target, depth): QueryItem<'w, Self::ViewQuery>,
(camera, view, target, depth): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl ViewNode for MainTransparentPass2dNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(camera, view, target, depth): bevy_ecs::query::QueryItem<'w, Self::ViewQuery>,
(camera, view, target, depth): bevy_ecs::query::QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let Some(transparent_phases) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl ViewNode for MainOpaquePass3dNode {
skybox_pipeline,
skybox_bind_group,
view_uniform_offset,
): QueryItem<'w, Self::ViewQuery>,
): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (Some(opaque_phases), Some(alpha_mask_phases)) = (
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_core_pipeline/src/deferred/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl ViewNode for EarlyDeferredGBufferPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
view_query: QueryItem<'w, Self::ViewQuery>,
view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
run_deferred_prepass(
Expand Down Expand Up @@ -74,7 +74,7 @@ impl ViewNode for LateDeferredGBufferPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
view_query: QueryItem<'w, Self::ViewQuery>,
view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (_, _, _, _, occlusion_culling, no_indirect_drawing) = view_query;
Expand Down Expand Up @@ -107,6 +107,7 @@ fn run_deferred_prepass<'w>(
render_context: &mut RenderContext<'w>,
(camera, extracted_view, view_depth_texture, view_prepass_textures, _, _): QueryItem<
'w,
'_,
<LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery,
>,
is_late: bool,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/dof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ impl ViewNode for DepthOfFieldNode {
view_bind_group_layouts,
depth_of_field_uniform_index,
auxiliary_dof_texture,
): QueryItem<'w, Self::ViewQuery>,
): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>();
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/msaa_writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl ViewNode for MsaaWritebackNode {
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(target, blit_pipeline_id, msaa): QueryItem<'w, Self::ViewQuery>,
(target, blit_pipeline_id, msaa): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
if *msaa == Msaa::Off {
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_core_pipeline/src/post_process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ impl ViewNode for PostProcessingNode {
&self,
_: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(view_target, pipeline_id, chromatic_aberration, post_processing_uniform_buffer_offsets): QueryItem<'w, Self::ViewQuery>,
(view_target, pipeline_id, chromatic_aberration, post_processing_uniform_buffer_offsets): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>();
Expand Down Expand Up @@ -497,7 +497,7 @@ impl ExtractComponent for ChromaticAberration {
type Out = ChromaticAberration;

fn extract_component(
chromatic_aberration: QueryItem<'_, Self::QueryData>,
chromatic_aberration: QueryItem<'_, '_, Self::QueryData>,
) -> Option<Self::Out> {
// Skip the postprocessing phase entirely if the intensity is zero.
if chromatic_aberration.intensity > 0.0 {
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_core_pipeline/src/prepass/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl ViewNode for EarlyPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
view_query: QueryItem<'w, Self::ViewQuery>,
view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
run_prepass(graph, render_context, view_query, world, "early prepass")
Expand Down Expand Up @@ -73,7 +73,7 @@ impl ViewNode for LatePrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
query: QueryItem<'w, Self::ViewQuery>,
query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
// We only need a late prepass if we have occlusion culling and indirect
Expand Down Expand Up @@ -112,7 +112,7 @@ fn run_prepass<'w>(
_,
_,
has_deferred,
): QueryItem<'w, <LatePrepassNode as ViewNode>::ViewQuery>,
): QueryItem<'w, '_, <LatePrepassNode as ViewNode>::ViewQuery>,
world: &'w World,
label: &'static str,
) -> Result<(), NodeRunError> {
Expand Down
4 changes: 3 additions & 1 deletion crates/bevy_core_pipeline/src/skybox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ impl ExtractComponent for Skybox {
type QueryFilter = ();
type Out = (Self, SkyboxUniforms);

fn extract_component((skybox, exposure): QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
fn extract_component(
(skybox, exposure): QueryItem<'_, '_, Self::QueryData>,
) -> Option<Self::Out> {
let exposure = exposure
.map(Exposure::exposure)
.unwrap_or_else(|| Exposure::default().exposure());
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/smaa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ impl ViewNode for SmaaNode {
view_smaa_uniform_offset,
smaa_textures,
view_smaa_bind_groups,
): QueryItem<'w, Self::ViewQuery>,
): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>();
Expand Down
53 changes: 39 additions & 14 deletions crates/bevy_ecs/macros/src/query_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
let user_generics_with_world = {
let mut generics = ast.generics;
generics.params.insert(0, parse_quote!('__w));
generics.params.insert(0, parse_quote!('__s));
generics
};
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
Expand Down Expand Up @@ -256,11 +257,11 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
for #read_only_struct_name #user_ty_generics #user_where_clauses {
const IS_READ_ONLY: bool = true;
type ReadOnly = #read_only_struct_name #user_ty_generics;
type Item<'__w> = #read_only_item_struct_name #user_ty_generics_with_world;
type Item<'__w, '__s> = #read_only_item_struct_name #user_ty_generics_with_world;

fn shrink<'__wlong: '__wshort, '__wshort>(
item: Self::Item<'__wlong>
) -> Self::Item<'__wshort> {
fn shrink<'__wlong: '__wshort, '__wshort, '__s>(
item: Self::Item<'__wlong, '__s>
) -> Self::Item<'__wshort, '__s> {
#read_only_item_struct_name {
#(
#field_idents: <#read_only_field_types>::shrink(item.#field_idents),
Expand All @@ -270,16 +271,28 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {

/// SAFETY: we call `fetch` for each member that implements `Fetch`.
#[inline(always)]
unsafe fn fetch<'__w>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
unsafe fn fetch<'__w, '__s>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w, '__s>,
_entity: #path::entity::Entity,
_table_row: #path::storage::TableRow,
) -> Self::Item<'__w> {
) -> Self::Item<'__w, '__s> {
Self::Item {
#(#field_idents: <#read_only_field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
}
}
}

impl #user_impl_generics #path::query::ReleaseStateQueryData
for #read_only_struct_name #user_ty_generics #user_where_clauses
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
// See https://github.com/rust-lang/rust/issues/48214
where #(for<'__a> #field_types: #path::query::QueryData<ReadOnly: #path::query::ReleaseStateQueryData>,)* {
fn release_state<'__w>(_item: Self::Item<'__w, '_>) -> Self::Item<'__w, 'static> {
Self::Item {
#(#field_idents: <#read_only_field_types>::release_state(_item.#field_idents),)*
}
}
}
}
} else {
quote! {}
Expand All @@ -293,11 +306,11 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
for #struct_name #user_ty_generics #user_where_clauses {
const IS_READ_ONLY: bool = #is_read_only;
type ReadOnly = #read_only_struct_name #user_ty_generics;
type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
type Item<'__w, '__s> = #item_struct_name #user_ty_generics_with_world;

fn shrink<'__wlong: '__wshort, '__wshort>(
item: Self::Item<'__wlong>
) -> Self::Item<'__wshort> {
fn shrink<'__wlong: '__wshort, '__wshort, '__s>(
item: Self::Item<'__wlong, '__s>
) -> Self::Item<'__wshort, '__s> {
#item_struct_name {
#(
#field_idents: <#field_types>::shrink(item.#field_idents),
Expand All @@ -307,17 +320,29 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {

/// SAFETY: we call `fetch` for each member that implements `Fetch`.
#[inline(always)]
unsafe fn fetch<'__w>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
unsafe fn fetch<'__w, '__s>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w, '__s>,
_entity: #path::entity::Entity,
_table_row: #path::storage::TableRow,
) -> Self::Item<'__w> {
) -> Self::Item<'__w, '__s> {
Self::Item {
#(#field_idents: <#field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
}
}
}

impl #user_impl_generics #path::query::ReleaseStateQueryData
for #struct_name #user_ty_generics #user_where_clauses
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
// See https://github.com/rust-lang/rust/issues/48214
where #(for<'__a> #field_types: #path::query::ReleaseStateQueryData,)* {
fn release_state<'__w>(_item: Self::Item<'__w, '_>) -> Self::Item<'__w, 'static> {
Self::Item {
#(#field_idents: <#field_types>::release_state(_item.#field_idents),)*
}
}
}

#read_only_data_impl
}
};
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_ecs/macros/src/query_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub fn derive_query_filter_impl(input: TokenStream) -> TokenStream {
let user_generics_with_world = {
let mut generics = ast.generics;
generics.params.insert(0, parse_quote!('__w));
generics.params.insert(0, parse_quote!('__s));
generics
};
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
Expand Down Expand Up @@ -101,8 +102,8 @@ pub fn derive_query_filter_impl(input: TokenStream) -> TokenStream {

#[allow(unused_variables)]
#[inline(always)]
unsafe fn filter_fetch<'__w>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
unsafe fn filter_fetch<'__w, '__s>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w, '__s>,
_entity: #path::entity::Entity,
_table_row: #path::storage::TableRow,
) -> bool {
Expand Down
Loading