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

Arc-d assets #15813

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open

Arc-d assets #15813

wants to merge 17 commits into from

Conversation

andriyDev
Copy link
Contributor

@andriyDev andriyDev commented Oct 10, 2024

Objective

Fixes #15723. This is an alternative to #15346 (and the associated PR #15359) obsolete. Note if we decide asset locking is preferable, there are learnings from this PR we can apply to #15359.

Solution

  1. Assets are now stored as Arc<A> instead of just A.

  2. get remains the same, but I've added an alternative called get_arc which returns a clone of the Arc that stores an asset.

  3. Replaced the get_mut with one of get_cloned_mut, get_inplace_mut, and get_reflect_cloned_mut (this last one is just because it's necessary for reflection, but not necessarily needed for users).

  4. Added add_arc and insert_arc to allow adding Arc types directly.

    1. add currently takes Into<A>. Trying to change this to Into<Arc<A>> breaks a lot of callsites like meshes.add(Rectangle::new(1.0, 2.0)) (since this requires two Into calls, which Rust can't figure out).
    2. As a result, making add_arc take Into<Arc<A>> is a fine middle ground to allow both Arc-ed assets and owned assets.
    3. For completeness, I also added insert_arc.
  5. RenderAsset now takes an Arc<Self::SourceAsset>. This means in most cases, cloning the asset can be skipped when passing data to the render world. Data only needs to be cloned if you mutate an asset.

Testing

  • Added an example that shows off using an Arc-d asset in an async context.

Showcase

fn my_task_launcher(configs: Res<Assets<ProceduralGenerationConfig>>, selected_config: Res<SelectedConfigHandle>) {
    let config = configs.get_arc(&selected_config.0).expect("The asset is loaded");
    
    AsyncComputeTaskPool::get().spawn(move async || {
        // Do something with the `config` in a task!
        std::thread::sleep(std::time::Duration::from_secs(config.time_it_takes_to_generate));
        println!("Done generating a level!");
    });
}

Migration Guide

  • Assets::get_mut has been removed. Use get_cloned_mut for Clone assets, or get_in_place_mut for non-Clone assets (and handle the case where the asset is aliased).
  • Assets::iter_mut now returns an iterator of &mut Arc<A>. Consider using Arc::make_mut for Clone assets, or Arc::get_mut for non-Clone assets (and handle the case where the asset is aliased).
  • RenderAssets now take an Arc<Self::SourceAsset>. Consider using Arc::try_unwrap() and falling back to a clone if the asset is aliased (try_unwrap returns an error). Otherwise, prefer borrowing the source asset's data instead of moving it.

@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Assets Load files from disk to use for things like images, models, and sounds X-Contentious There are nontrivial implications that should be thought through S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 10, 2024
@BenjaminBrienen BenjaminBrienen added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 31, 2024
@BenjaminBrienen BenjaminBrienen added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Oct 31, 2024
@BenjaminBrienen
Copy link
Contributor

BenjaminBrienen commented Nov 1, 2024

Can you fix the inconsistency between "[Arc]-ed" and "[Arc]d"? I prefer the latter.

Copy link
Contributor

@aecsocket aecsocket left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the concept of storing assets in an Arc. I find that I very rarely mutate existing assets, only add/remove/swap, so Arcs for assets make perfect sense to me. I am somewhat worried about a lot of usages of get_cloned_mut that this causes in the rest of the codebase though.

crates/bevy_asset/src/assets.rs Show resolved Hide resolved
crates/bevy_asset/src/assets.rs Show resolved Hide resolved
crates/bevy_asset/src/assets.rs Outdated Show resolved Hide resolved
crates/bevy_asset/src/direct_access_ext.rs Show resolved Hide resolved
crates/bevy_asset/src/direct_access_ext.rs Show resolved Hide resolved
crates/bevy_asset/src/assets.rs Outdated Show resolved Hide resolved
@@ -0,0 +1,251 @@
//! This example illustrates how to use assets in an async context (through locking).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//! This example illustrates how to use assets in an async context (through locking).
//! This example illustrates how to use assets in an async context (through cloning the underlying `Arc`, effectively locking the asset from mutation).

Copy link
Contributor Author

@andriyDev andriyDev Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dropped the whole "locking" wording, that was actually just an artifact from my "asset locking" PR (which I stole this example from, lol). Done!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still do like the naming of "locking" an asset, since that is effectively what you're doing when you've got 2+ ref counts to an asset - you're locking it for mutation. Maybe this term could be used in docs somewhere?

/// When an asset has a reference count of more than 1, this asset is considered *locked* for mutation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I intentionally want to avoid calling it "locked" because you can still replace the asset entirely. So the asset isn't locked, only the particular "instance" of that asset? The terminology gets a little unclear. I also think the comment on get_arc makes it more clear what the tradeoffs are:

    /// Be careful with holding the Arc indefinitely: holding the
    /// [`Arc`] (or a [`Weak`]) prevents the asset from being mutated in place. This can incur
    /// clones when using `get_cloned_mut`, or can just entirely block mutation when using
    /// `get_in_place_mut`.

Copy link
Contributor

@aecsocket aecsocket Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense to me. I feel like there still needs to be a term for an asset which is in the state of "ref count more than 1". Aliased? Regardless, this won't block my approval.

@andriyDev
Copy link
Contributor Author

Can you fix the inconsistency between "[Arc]-ed" and "[Arc]d"? I prefer the latter.

Done!

@andriyDev andriyDev changed the title Arc-ed assets Arc-d assets Nov 1, 2024
Removing these functions makes it simpler to redesign them for when assets are Arc'd.
Many callers expect to be able to call `meshes.add(Rectangle::new(50.0,
100.0))`. Now we can keep all these callsites the same (while still
supporting inserting/adding `Arc`s directly).
Now for assets that impl `Clone`, we can get a mutable borrow to the asset always by cloning.
Now we can mutate assets in place as long as there are no more Arcs or Weaks for that asset.
This is basically the same as `get_cloned_mut` but using reflection. This is not really intended to be used publicly, but the reflect.rs needs a clone that only relies on reflection, so making it public seems fine.
@andriyDev
Copy link
Contributor Author

andriyDev commented Dec 11, 2024

No-op rebase to handle conflicts with #16368, and updated error to using thiserror after #16684.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Assets Load files from disk to use for things like images, models, and sounds C-Feature A new feature, making something new possible S-Needs-Review Needs reviewer attention (from anyone!) to move forward X-Contentious There are nontrivial implications that should be thought through
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Arc-ed assets
4 participants