Commit graph

4987 commits

Author SHA1 Message Date
Patrick Walton
e67d63aa79
Refactor the render instance logic in #9903 so that it's easier for other components to adopt. (#10002)
# Objective

Currently, the only way for custom components that participate in
rendering to opt into the higher-performance extraction method in #9903
is to implement the `RenderInstances` data structure and the extraction
logic manually. This is inconvenient compared to the `ExtractComponent`
API.

## Solution

This commit creates a new `RenderInstance` trait that mirrors the
existing `ExtractComponent` method but uses the higher-performance
approach that #9903 uses. Additionally, `RenderInstance` is more
flexible than `ExtractComponent`, because it can extract multiple
components at once. This makes high-performance rendering components
essentially as easy to write as the existing ones based on component
extraction.

---

## Changelog

### Added

A new `RenderInstance` trait is available mirroring `ExtractComponent`,
but using a higher-performance method to extract one or more components
to the render world. If you have custom components that rendering takes
into account, you may consider migration from `ExtractComponent` to
`RenderInstance` for higher performance.
2023-10-08 10:34:44 +00:00
JMS55
1f95a484ed
PCF For DirectionalLight/SpotLight Shadows (#8006)
# Objective

- Improve antialiasing for non-point light shadow edges.
- Very partially addresses
https://github.com/bevyengine/bevy/issues/3628.

## Solution

- Implements "The Witness"'s shadow map sampling technique.
  - Ported from @superdump's old branch, all credit to them :)
- Implements "Call of Duty: Advanced Warfare"'s stochastic shadow map
sampling technique when the velocity prepass is enabled, for use with
TAA.
- Uses interleaved gradient noise to generate a random angle, and then
averages 8 samples in a spiral pattern, rotated by the random angle.
- I also tried spatiotemporal blue noise, but it was far too noisy to be
filtered by TAA alone. In the future, we should try spatiotemporal blue
noise + a specialized shadow denoiser such as
https://gpuopen.com/fidelityfx-denoiser/#shadow. This approach would
also be useful for hybrid rasterized applications with raytraced
shadows.
- The COD presentation has an interesting temporal dithering of the
noise for use with temporal supersampling that we should revisit when we
get DLSS/FSR/other TSR.

---

## Changelog

* Added `ShadowFilteringMethod`. Improved directional light and
spotlight shadow edges to be less aliased.

## Migration Guide

* Shadows cast by directional lights or spotlights now have smoother
edges. To revert to the old behavior, add
`ShadowFilteringMethod::Hardware2x2` to your cameras.

---------

Co-authored-by: IceSentry <c.giguere42@gmail.com>
Co-authored-by: Daniel Chia <danstryder@gmail.com>
Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Brandon Dyer <brandondyer64@gmail.com>
Co-authored-by: Edgar Geier <geieredgar@gmail.com>
Co-authored-by: Robert Swain <robert.swain@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
2023-10-07 17:13:29 +00:00
François
154a490445
fix example mesh2d_manual (#9941)
# Objective

- After https://github.com/bevyengine/bevy/pull/9903, example
`mesh2d_manual` doesn't render anything

## Solution

- Fix the example using the new `RenderMesh2dInstances`
2023-10-06 20:13:09 +00:00
s-puig
a31ebdc1a6
Fix TextureAtlasBuilder padding (#10031)
# Objective

- Fix TextureAtlasBuilder padding issue

TextureAtlasBuilder padding is reserved during add_texture() but can
still be changed afterwards. This means that changing padding after the
textures will be wrongly applied, either distorting the textures or
panicking if new padding is higher than texture+old padding.


## Solution

- Delay applying padding until finish()
2023-10-06 15:33:57 +00:00
Torstein Grindvik
8b21ee45c0
Allow Bevy to start from non-main threads on supported platforms (#10020)
# Objective

Allow Bevy apps to run without requiring to start from the main thread.
This allows other projects and applications to do things like spawning a
normal or scoped
thread and run Bevy applications there.

The current behaviour if you try this is a panic.

## Solution

Allow this by default on platforms winit supports this behaviour on
(x11, Wayland, Windows).

---

## Changelog

### Added

- Added the ability to start Bevy apps outside of the main thread on
x11, Wayland, Windows

---------

Signed-off-by: Torstein Grindvik <torstein.grindvik@nordicsemi.no>
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: James Liu <contact@jamessliu.com>
2023-10-06 13:26:06 +00:00
Zachary Harrold
dd46fd3aee
Removed anyhow (#10003)
# Objective

- Fixes #8140

## Solution

- Added Explicit Error Typing for `AssetLoader` and `AssetSaver`, which
were the last instances of `anyhow` in use across Bevy.

---

## Changelog

- Added an associated type `Error` to `AssetLoader` and `AssetSaver` for
use with the `load` and `save` methods respectively.
- Changed `ErasedAssetLoader` and `ErasedAssetSaver` `load` and `save`
methods to use `Box<dyn Error + Send + Sync + 'static>` to allow for
arbitrary `Error` types from the non-erased trait variants. Note the
strict requirements match the pre-existing requirements around
`anyhow::Error`.

## Migration Guide

- `anyhow` is no longer exported by `bevy_asset`; Add it to your own
project (if required).
- `AssetLoader` and `AssetSaver` have an associated type `Error`; Define
an appropriate error type (e.g., using `thiserror`), or use a pre-made
error type (e.g., `anyhow::Error`). Note that using `anyhow::Error` is a
drop-in replacement.
- `AssetLoaderError` has been removed; Define a new error type, or use
an alternative (e.g., `anyhow::Error`)
- All the first-party `AssetLoader`'s and `AssetSaver`'s now return
relevant (and narrow) error types instead of a single ambiguous type;
Match over the specific error type, or encapsulate (`Box<dyn>`,
`thiserror`, `anyhow`, etc.)

## Notes

A simpler PR to resolve this issue would simply define a Bevy `Error`
type defined as `Box<dyn std::error::Error + Send + Sync + 'static>`,
but I think this type of error handling should be discouraged when
possible. Since only 2 traits required the use of `anyhow`, it isn't a
substantive body of work to solidify these error types, and remove
`anyhow` entirely. End users are still encouraged to use `anyhow` if
that is their preferred error handling style. Arguably, adding the
`Error` associated type gives more freedom to end-users to decide
whether they want more or less explicit error handling (`anyhow` vs
`thiserror`).

As an aside, I didn't perform any testing on Android or WASM. CI passed
locally, but there may be mistakes for those platforms I missed.
2023-10-06 07:20:13 +00:00
robtfm
30cb95d96e
fix custom shader imports (#10030)
# Objective

assets v2 broke custom shader imports. fix them

## Solution

store handles of any file dependencies in the `Shader` to avoid them
being immediately dropped.
also added a use into the `shader_material` example so that it'll be
harder to break support in future.
2023-10-06 01:34:57 +00:00
Mike
687e379800
Updates for rust 1.73 (#10035)
# Objective

- Updates for rust 1.73

## Solution

- new doc check for `redundant_explicit_links`
- updated to text for compile fail tests

---

## Changelog

- updates for rust 1.73
2023-10-06 00:31:10 +00:00
IceSentry
a962240866
Alternate wireframe override api (#10023)
# Objective

https://github.com/bevyengine/bevy/pull/7328 introduced an API to
override the global wireframe config. I believe it is flawed for a few
reasons.

This PR uses a non-breaking API. Instead of making the `Wireframe` an
enum I introduced the `NeverRenderWireframe` component. Here's the
reason why I think this is better:
- Easier to migrate since it doesn't change the old behaviour.
Essentially nothing to migrate. Right now this PR is a breaking change
but I don't think it has to be.
- It's similar to other "per mesh" rendering features like
NotShadowCaster/NotShadowReceiver
- It doesn't force new users to also think about global vs not global if
all they want is to render a wireframe
- This would also let you filter at the query definition level instead
of filtering when running the query

## Solution

- Introduce a `NeverRenderWireframe` component that ignores the global
config

---

## Changelog

- Added a `NeverRenderWireframe` component that ignores the global
`WireframeConfig`
2023-10-05 12:12:08 +00:00
ickshonpe
2e887b856f
UI node outlines (#9931)
# Objective

Add support for drawing outlines outside the borders of UI nodes.

## Solution
Add a new `Outline` component with `width`, `offset` and `color` fields.
Added `outline_width` and `outline_offset` fields to `Node`. This is set
after layout recomputation by the `resolve_outlines_system`.

Properties of outlines:
* Unlike borders, outlines have to be the same width on each edge.
* Outlines do not occupy any space in the layout.
* The `Outline` component won't be added to any of the UI node bundles,
it needs to be inserted separately.
* Outlines are drawn outside the node's border, so they are clipped
using the clipping rect of their entity's parent UI node (if it exists).
* `Val::Percent` outline widths are resolved based on the width of the
outlined UI node.
* The offset of the `Outline` adds space between an outline and the edge
of its node.

I was leaning towards adding an `outline` field to `Style` but a
separate component seems more efficient for queries and change
detection. The `Outline` component isn't added to bundles for the same
reason.

---
## Examples

* This image is from the `borders` example from the Bevy UI examples but
modified to include outlines. The UI nodes are the dark red rectangles,
the bright red rectangles are borders and the white lines offset from
each node are the outlines. The yellow rectangles are separate nodes
contained with the dark red nodes:
 
<img width="406" alt="outlines"
src="https://github.com/bevyengine/bevy/assets/27962798/4e6f315a-019f-42a4-94ee-cca8e684d64a">

* This is from the same example but using a branch that implements
border-radius. Here the the outlines are in orange and there is no
offset applied. I broke the borders implementation somehow during the
merge, which is why some of the borders from the first screenshot are
missing 😅. The outlines work nicely though (as long as you
can forgive the lack of anti-aliasing):


![image](https://github.com/bevyengine/bevy/assets/27962798/d15560b6-6cd6-42e5-907b-56ccf2ad5e02)

---
## Notes

As I explained above, I don't think the `Outline` component should be
added to UI node bundles. We can have helper functions though, perhaps
something as simple as:

```rust
impl NodeBundle {
    pub fn with_outline(self, outline: Outline) -> (Self, Outline) {
        (self, outline)
    }
}
```

I didn't include anything like this as I wanted to keep the PR's scope
as narrow as possible. Maybe `with_outline` should be in a trait that we
implement for each UI node bundle.

---

## Changelog
Added support for outlines to Bevy UI.
* The `Outline` component adds an outline to a UI node.
* The `outline_width` field added to `Node` holds the resolved width of
the outline, which is set by the `resolve_outlines_system` after layout
recomputation.
* Outlines are drawn by the system `extract_uinode_outlines`.
2023-10-05 12:10:32 +00:00
Mike
202b9fce18
add test for nested scopes (#10026)
# Objective

- When I've tested alternative async executors with bevy a common
problem is that they deadlock when we try to run nested scopes. i.e.
running a multithreaded schedule from inside another multithreaded
schedule. This adds a test to bevy_tasks for that so the issue can be
spotted earlier while developing.

## Changelog

- add a test for nested scopes.
2023-10-05 06:05:43 +00:00
Ame :]
7541bf862c
Fix some warnings shown in nightly (#10012)
# Objective

Fix warnings:
- #[warn(clippy::needless_pass_by_ref_mut)]
- #[warn(elided_lifetimes_in_associated_constant)]

## Solution

- Remove mut
- add &'static

## Errors

```rust
warning: this argument is a mutable reference, but not used mutably
   --> crates/bevy_hierarchy/src/child_builder.rs:672:31
    |
672 |     fn assert_children(world: &mut World, parent: Entity, children: Option<&[Entity]>) {
    |                               ^^^^^^^^^^ help: consider changing to: `&World`
    |
    = note: this is cfg-gated and may require further changes
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
    = note: `#[warn(clippy::needless_pass_by_ref_mut)]` on by default
```


```rust
warning: `&` without an explicit lifetime name cannot be used here
   --> examples/shader/post_processing.rs:120:21
    |
120 |     pub const NAME: &str = "post_process";
    |                     ^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
    = note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default
help: use the `'static` lifetime
    |
120 |     pub const NAME: &'static str = "post_process";
    |                      +++++++


```
2023-10-05 05:41:09 +00:00
Kanabenki
86f7ef1bd7
Finish documenting bevy_gilrs (#10010)
# Objective

Finish documenting `bevy_gilrs`.

## Solution

Document the remaining items, add a `warn(missing_docs)` attribute for
the crate.
2023-10-04 21:10:20 +00:00
François
9086e60c20
wireframes: workaround for DX12 (#10022)
# Objective

- Fixes #10019

## Solution

- Uses a workaround for DX12
2023-10-04 18:29:29 +00:00
Wybe Westra
f9e50e767b
Allow overriding global wireframe setting. (#7328)
# Objective

Allow the user to choose between "Add wireframes to these specific
entities" or "Add wireframes to everything _except_ these specific
entities".
Fixes #7309

# Solution
Make the `Wireframe` component act like an override to the global
configuration.
Having `global` set to `false`, and adding a `Wireframe` with `enable:
true` acts exactly as before.
But now the opposite is also possible: Set `global` to `true` and add a
`Wireframe` with `enable: false` will draw wireframes for everything
_except_ that entity.

Updated the example to show how overriding the global config works.
2023-10-04 02:34:44 +00:00
Mike
7c5b324484
Ignore ambiguous components or resources (#9895)
# Objective

- Fixes #9884
- Add API for ignoring ambiguities on certain resource or components.

## Solution

- Add a `IgnoreSchedulingAmbiguitiy` resource to the world which holds
the `ComponentIds` to be ignored
- Filter out ambiguities with those component id's.

## Changelog

- add `allow_ambiguous_component` and `allow_ambiguous_resource` apis
for ignoring ambiguities

---------

Co-authored-by: Ryan Johnson <ryanj00a@gmail.com>
2023-10-04 02:34:28 +00:00
Kanabenki
375af64e8c
Finish documenting bevy_gltf (#9998)
# Objective

- Finish documenting `bevy_gltf`.

## Solution

- Document the remaining items, add links to the glTF spec where
relevant. Add the `warn(missing_doc)` attribute.
2023-10-03 10:13:52 +00:00
dependabot[bot]
4eb9b9f7d7
Update notify-debouncer-full requirement from 0.2.0 to 0.3.1 (#9757)
Updates the requirements on
[notify-debouncer-full](https://github.com/notify-rs/notify) to permit
the latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/notify-rs/notify/blob/main/CHANGELOG.md">notify-debouncer-full's
changelog</a>.</em></p>
<blockquote>
<h2>debouncer-full 0.3.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<h2>debouncer-mini 0.4.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<h2>notify 6.1.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<h2>file-id 0.2.1 (2023-08-21)</h2>
<ul>
<li>CHANGE: remove serde binary experiment opt-out after it got removed
<a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a></li>
</ul>
<p><a
href="https://redirect.github.com/notify-rs/notify/issues/530">#530</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/530">notify-rs/notify#530</a></p>
<h2>debouncer-full 0.3.0 (2023-08-18)</h2>
<ul>
<li>CHANGE: opt-out of the serde binary experiment by restricting it to
&lt; 1.0.172 <a
href="https://redirect.github.com/notify-rs/notify/issues/528">#528</a></li>
<li>CHANGE: license changed to dual-license of MIT OR Apache-2.0 <a
href="https://redirect.github.com/notify-rs/notify/issues/520">#520</a></li>
<li>CHANGE: upgrade to file-id 0.2.0 for high resolution file IDs <a
href="https://redirect.github.com/notify-rs/notify/issues/494">#494</a></li>
<li>FEATURE: derive debug for the debouncer struct <a
href="https://redirect.github.com/notify-rs/notify/issues/510">#510</a></li>
</ul>
<h2>debouncer-mini 0.4.0 (2023-08-18)</h2>
<ul>
<li>CHANGE: opt-out of the serde binary experiment by restricting it to
&lt; 1.0.172 <a
href="https://redirect.github.com/notify-rs/notify/issues/528">#528</a></li>
<li>CHANGE: license changed to dual-license of MIT OR Apache-2.0 <a
href="https://redirect.github.com/notify-rs/notify/issues/520">#520</a></li>
<li>CHANGE: replace active polling with passive loop, removing empty
ticks <a
href="https://redirect.github.com/notify-rs/notify/issues/467">#467</a></li>
<li>FEATURE: derive debug for the debouncer struct <a
href="https://redirect.github.com/notify-rs/notify/issues/510">#510</a></li>
</ul>
<p><a
href="https://redirect.github.com/notify-rs/notify/issues/467">#467</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/467">notify-rs/notify#467</a>
<a
href="https://redirect.github.com/notify-rs/notify/issues/510">#510</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/510">notify-rs/notify#510</a></p>
<h2>notify 6.1.0 (2023-08-18)</h2>
<ul>
<li>CHANGE: opt-out of the serde binary experiment by restricting it to
&lt; 1.0.172 <a
href="https://redirect.github.com/notify-rs/notify/issues/528">#528</a></li>
<li>CHANGE: license changed to only CC0-1.0 <a
href="https://redirect.github.com/notify-rs/notify/issues/520">#520</a></li>
<li>CHANGE: use logging <a
href="https://redirect.github.com/notify-rs/notify/issues/499">#499</a></li>
<li>CHANGE: upgrade windows-sys to 0.48 <a
href="https://redirect.github.com/notify-rs/notify/issues/479">#479</a></li>
<li>CHANGE: bump filetime to 0.2.22 <a
href="https://redirect.github.com/notify-rs/notify/issues/521">#521</a></li>
<li>FEATURE: support manual polling of PollWatcher and disabling
automatic polling <a
href="https://redirect.github.com/notify-rs/notify/issues/524">#524</a></li>
<li>FEATURE: support listening to the initial pollwatcher file scan <a
href="https://redirect.github.com/notify-rs/notify/issues/507">#507</a></li>
<li>FIX: fix moved folders not being watched on linux <a
href="https://redirect.github.com/notify-rs/notify/issues/498">#498</a></li>
<li>FIX: fixup potential future double free on windows <a
href="https://redirect.github.com/notify-rs/notify/issues/517">#517</a></li>
<li>FIX: require bitflags only on macos and upgrade the crate <a
href="https://redirect.github.com/notify-rs/notify/issues/505">#505</a></li>
<li>DOCS: add more known issues, typos and cleanup examples <a
href="https://redirect.github.com/notify-rs/notify/issues/523">#523</a>
<a
href="https://redirect.github.com/notify-rs/notify/issues/502">#502</a>
<a
href="https://redirect.github.com/notify-rs/notify/issues/522">#522</a></li>
</ul>
<p><a
href="https://redirect.github.com/notify-rs/notify/issues/524">#524</a>:
<a
href="https://redirect.github.com/notify-rs/notify/pull/524">notify-rs/notify#524</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4a001215b3"><code>4a00121</code></a>
remove serde restriction and publish new versions</li>
<li><a
href="03ac300d36"><code>03ac300</code></a>
Fix a filename of example</li>
<li><a
href="2e971e59db"><code>2e971e5</code></a>
cleanup removed used-by entries</li>
<li><a
href="1cdf75fdc9"><code>1cdf75f</code></a>
fixup changelog to correct serde version</li>
<li>See full diff in <a
href="https://github.com/notify-rs/notify/compare/file-id-0.2.0...debouncer-full-0.3.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 22:10:20 +00:00
Bruce Mitchener
9a798aa100
Allow clippy::type_complexity in more places. (#9796)
# Objective

- See fewer warnings when running `cargo clippy` locally.

## Solution

- allow `clippy::type_complexity` in more places, which also signals to
users they should do the same.
2023-10-02 21:55:16 +00:00
Nolan Darilek
73e0ac26ca
Various accessibility API updates. (#9989)
# Objective

`bevy_a11y` was impossible to integrate into some third-party projects
in part because it insisted on managing the accessibility tree on its
own.

## Solution

The changes in this PR were necessary to get `bevy_egui` working with
Bevy's AccessKit integration. They were tested on a fork of 0.11,
developed against `bevy_egui`, then ported to main and tested against
the `ui` example.

## Changelog

### Changed

* Add `bevy_a11y::ManageAccessibilityUpdates` to indicate whether the
ECS should manage accessibility tree updates.
* Add getter/setter to `bevy_a11y::AccessibilityRequested`.
* Add `bevy_a11y::AccessibilitySystem` `SystemSet` for ordering relative
to accessibility tree updates.
* Upgrade `accesskit` to v0.12.0.

### Fixed

* Correctly set initial accessibility focus to new windows on creation.

## Migration Guide

### Change direct accesses of `AccessibilityRequested` to use
`AccessibilityRequested.::get()`/`AccessibilityRequested::set()`

#### Before

```
use std::sync::atomic::Ordering;

// To access
accessibility_requested.load(Ordering::SeqCst)
// To update
accessibility_requested.store(true, Ordering::SeqCst);
```

#### After

```
// To access
accessibility_requested.get()
// To update
accessibility_requested.set(true);
```

---------

Co-authored-by: StaffEngineer <111751109+StaffEngineer@users.noreply.github.com>
2023-10-02 21:22:52 +00:00
Patrick Walton
44a9a4cc86
Import the second UV map if present in glTF files. (#9992)
Conventionally, the second UV map (`TEXCOORD1`, `UV1`) is used for
lightmap UVs. This commit allows Bevy to import them, so that a custom
shader that applies lightmaps can use those UVs if desired.

Note that this doesn't actually apply lightmaps to Bevy meshes; that
will be a followup. It does, however, open the door to future Bevy
plugins that implement baked global illumination.

## Changelog

### Added

The Bevy glTF loader now imports a second UV channel (`TEXCOORD1`,
`UV1`) from meshes if present. This can be used by custom shaders to
implement lightmapping.
2023-10-02 21:07:03 +00:00
SykiK
019649422b
Fixed: README.md (#9994)
# Objective

fixed readme.md.

## Solution

removed 'iOS cron CI' badge as its source
(https://github.com/bevyengine/bevy/workflows/iOS%20cron%20CI/badge.svg)
is not available anymore
2023-10-02 13:07:29 +00:00
François
eb1effa643
Android: handle suspend / resume (#9937)
# Objective

- Handle suspend / resume events on Android without exiting

## Solution

- On suspend: despawn the window, and set the control flow to wait for
events from the OS
- On resume: spawn a new window, and set the control flow to poll


In this video, you can see the Android example being suspended, stopping
receiving events, and working again after being resumed



https://github.com/bevyengine/bevy/assets/8672791/aaaf4b09-ee6a-4a0d-87ad-41f05def7945
2023-10-02 13:06:13 +00:00
Nicola Papale
1bf271d56e
Add a public API to ArchetypeGeneration/Id (#9825)
Objective
---------

- Since #6742, It is not possible to build an `ArchetypeId` from a
`ArchetypeGeneration`
- This was useful to 3rd party crate extending the base bevy ECS
capabilities, such as [`bevy_ecs_dynamic`] and now
[`bevy_mod_dynamic_query`]
- Making `ArchetypeGeneration` opaque this way made it completely
useless, and removed the ability to limit archetype updates to a subset
of archetypes.
- Making the `index` method on `ArchetypeId` private prevented the use
of bitfields and other optimized data structure to store sets of
archetype ids. (without `transmute`)

This PR is not a simple reversal of the change. It exposes a different
API, rethought to keep the private stuff private and the public stuff
less error-prone.

- Add a `StartRange<ArchetypeGeneration>` `Index` implementation to
`Archetypes`
- Instead of converting the generation into an index, then creating a
ArchetypeId from that index, and indexing `Archetypes` with it, use
directly the old `ArchetypeGeneration` to get the range of new
archetypes.

From careful benchmarking, it seems to also be a performance improvement
(~0-5%) on add_archetypes.

---

Changelog
---------

- Added `impl Index<RangeFrom<ArchetypeGeneration>> for Archetypes` this
allows you to get a slice of newly added archetypes since the last
recorded generation.
- Added `ArchetypeId::index` and `ArchetypeId::new` methods. It should
enable 3rd party crates to use the `Archetypes` API in a meaningful way.

[`bevy_ecs_dynamic`]:
https://github.com/jakobhellermann/bevy_ecs_dynamic/tree/main
[`bevy_mod_dynamic_query`]:
https://github.com/nicopap/bevy_mod_dynamic_query/

---------

Co-authored-by: vero <email@atlasdostal.com>
2023-10-02 12:54:45 +00:00
Nicola Papale
47409c8a72
Add inline(never) to bench systems (#9824)
# Objective

It is difficult to inspect the generated assembly of benchmark systems
using a tool such as `cargo-asm`

## Solution

Mark the related functions as `#[inline(never)]`. This way, you can pass
the module name as argument to `cargo-asm` to get the generated assembly
for the given function.

It may have as side effect to make benchmarks a bit more predictable and
useful too. As it prevents inlining where in bevy no inlining could
possibly take place.

### Measurements

Following the recommendations in
<https://easyperf.net/blog/2019/08/02/Perf-measurement-environment-on-Linux>,
I

1. Put my CPU in "AMD ECO" mode, which surprisingly is the equivalent of
disabling turboboost, giving more consistent performances
2. Disabled all hyperthreading cores using `echo 0 >
/sys/devices/system/cpu/cpu{11,12…}/online`
3. Set the scaling governor to `performance`
4. Manually disabled AMD boost with `echo 0 >
/sys/devices/system/cpu/cpufreq/boost`
5. Set the nice level of the criterion benchmark using `cargo bench … &
sudo renice -n -5 -p $! ; fg`
6. Not running any other program than the benchmarks (outside of system
daemons and the X11 server)

With this setup, running multiple times the same benchmarks on `main`
gives me a lot of "regression" and "improvement" messages, which is
absurd given that no code changed.

On this branch, there is still some spurious performance change
detection, but they are much less frequent.

This only accounts for `iter_simple` and `iter_frag` benchmarks of
course.
2023-10-02 12:52:18 +00:00
Joseph
8cc255c2f0
Hide UnsafeWorldCell::unsafe_world (#9741)
# Objective

We've done a lot of work to remove the pattern of a `&World` with
interior mutability (#6404, #8833). However, this pattern still persists
within `bevy_ecs` via the `unsafe_world` method.

## Solution

* Make `unsafe_world` private. Adjust any callsites to use
`UnsafeWorldCell` for interior mutability.
* Add `UnsafeWorldCell::removed_components`, since it is always safe to
access the removed components collection through `UnsafeWorldCell`.

## Future Work

Remove/hide `UnsafeWorldCell::world_metadata`, once we have provided
safe ways of accessing all world metadata.

---

## Changelog

+ Added `UnsafeWorldCell::removed_components`, which provides read-only
access to a world's collection of removed components.
2023-10-02 12:46:43 +00:00
Zachary Harrold
450328d15e
Replaced parking_lot with std::sync (#9545)
# Objective

- Fixes #4610 

## Solution

- Replaced all instances of `parking_lot` locks with equivalents from
`std::sync`. Acquiring locks within `std::sync` can fail, so
`.expect("Lock Poisoned")` statements were added where required.

## Comments

In [this
comment](https://github.com/bevyengine/bevy/issues/4610#issuecomment-1592407881),
the lack of deadlock detection was mentioned as a potential reason to
not make this change. From what I can gather, Bevy doesn't appear to be
using this functionality within the engine. Unless it was expected that
a Bevy consumer was expected to enable and use this functionality, it
appears to be a feature lost without consequence.

Unfortunately, `cpal` and `wgpu` both still rely on `parking_lot`,
leaving it in the dependency graph even after this change.

From my basic experimentation, this change doesn't appear to have any
performance impacts, positive or negative. I tested this using
`bevymark` with 50,000 entities and observed 20ms of frame-time before
and after the change. More extensive testing with larger/real projects
should probably be done.
2023-10-02 12:44:34 +00:00
Tristan Guichaoua
44c769f7b9
Improve TypeUuid's derive macro error messages (#9315)
# Objective

- Better error message
- More idiomatic code

## Solution

Refactorize `TypeUuid` macros to use `syn::Result` instead of panic.

## Before/After error messages

### Missing `#[uuid]` attribtue

#### Before
```
error: proc-macro derive panicked
 --> src\main.rs:1:10
  |
1 | #[derive(TypeUuid)]
  |          ^^^^^^^^
  |
  = help: message: No `#[uuid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"` attribute found.
```

#### After
```
error: No `#[uuid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"]` attribute found.
 --> src\main.rs:3:10
  |
3 | #[derive(TypeUuid)]
  |          ^^^^^^^^
  |
  = note: this error originates in the derive macro `TypeUuid` (in Nightly builds, run with -Z macro-backtrace for more info)
```

### Malformed attribute

#### Before

```
error: proc-macro derive panicked
 --> src\main.rs:3:10
  |
3 | #[derive(TypeUuid)]
  |          ^^^^^^^^
  |
  = help: message: `uuid` attribute must take the form `#[uuid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"`.
```

#### After

```
error: `uuid` attribute must take the form `#[uuid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"]`.
 --> src\main.rs:4:1
  |
4 | #[uuid = 42]
  | ^^^^^^^^^^^^
```

### UUID parse fail

#### Before
```
error: proc-macro derive panicked
 --> src\main.rs:3:10
  |
3 | #[derive(TypeUuid)]
  |          ^^^^^^^^
  |
  = help: message: Value specified to `#[uuid]` attribute is not a valid UUID.: Error(SimpleLength { len: 3 })
```

#### After

```
error: Invalid UUID: invalid length: expected length 32 for simple format, found 3
 --> src\main.rs:4:10
  |
4 | #[uuid = "000"]
  |          ^^^^^
```

### With [Error
Lens](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens)

#### Before

![image](https://github.com/bevyengine/bevy/assets/33934311/415247fa-ff5c-4513-8012-7a9ff77445fb)

#### After

![image](https://github.com/bevyengine/bevy/assets/33934311/d124eeaa-9213-49e0-8860-539ad0218a40)


---

## Changelog

- `#[derive(TypeUuid)]` provide better error messages.
2023-10-02 12:42:01 +00:00
James Liu
21518de0de
refactor: Change Option<With<T>> query params to Has<T> (#9959)
# Objective
`Has<T>` was added to bevy_ecs, but we're still using the
`Option<With<T>>` pattern in multiple locations.

## Solution
Replace them with `Has<T>`.
2023-10-02 01:21:41 +00:00
Testare
dfdc9f8369
as_deref_mut() method for Mut-like types (#9912)
# Objective

Add a new method so you can do `set_if_neq` with dereferencing
components: `as_deref_mut()`!

## Solution

Added an as_deref_mut method so that we can use `set_if_neq()` without
having to wrap up types for derefencable components

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com>
2023-10-02 00:53:12 +00:00
Ame :]
f69e923c27
Revert "macOS Sonoma (14.0) / Xcode 15.0 — Compatibility Fixes + Docs… (#9991)
… (#9905)"

This reverts commit 20ed3e0e76.

Issue was already fixed:
https://github.com/rust-windowing/winit/pull/3118
2023-10-02 00:37:03 +00:00
Zachary Harrold
e5dbde86fb
Moved fq_std from bevy_reflect_derive to bevy_macro_utils (#9956)
# Objective

- Fixes #9363

## Solution

Moved `fq_std` from `bevy_reflect_derive` to `bevy_macro_utils`. This
does make the `FQ*` types public where they were previously private,
which is a change to the public-facing API, but I don't believe a
breaking one. Additionally, I've done a basic QA pass over the
`bevy_macro_utils` crate, adding `deny(unsafe)`, `warn(missing_docs)`,
and documentation where required.
2023-10-02 00:22:57 +00:00
Ricky Taylor
0f20cfaa57
Only attempt to copy resources that still exist from scenes (#9984)
# Objective

Avert a panic when removing resources from Scenes.

### Reproduction Steps
```rust
let mut scene = Scene::new(World::default());
scene.world.init_resource::<Time>();
scene.world.remove_resource::<Time>();
scene.clone_with(&app.resource::<AppTypeRegistry>());
```

### Panic Message
```
thread 'Compute Task Pool (10)' panicked at 'Requested resource bevy_time::time::Time does not exist in the `World`. 
                Did you forget to add it using `app.insert_resource` / `app.init_resource`? 
                Resources are also implicitly added via `app.add_event`,
                and can be added by plugins.', .../bevy/crates/bevy_ecs/src/reflect/resource.rs:203:52

```

## Solution

Check that the resource actually still exists before copying.

---

## Changelog

- resolved a panic caused by removing resources from scenes
2023-10-02 00:05:36 +00:00
JMS55
0792dde8d5
Fix comment grammar (#9990) 2023-10-01 20:18:34 +00:00
Kanabenki
ec34fe01d1
Finish documenting bevy_scene (#9949)
# Objective

Finish documenting `bevy_scene`.

## Solution

Document the remaining items and add a crate-level `warn(missing_doc)`
attribute as for the other crates with completed documentation.
2023-10-01 17:54:19 +00:00
James Liu
a1a81e5721
Parallelize extract_meshes (#9966)
# Objective
`extract_meshes` can easily be one of the most expensive operations in
the blocking extract schedule for 3D apps. It also has no fundamentally
serialized parts and can easily be run across multiple threads. Let's
speed it up by parallelizing it!

## Solution
Use the `ThreadLocal<Cell<Vec<T>>>` approach utilized by #7348 in
conjunction with `Query::par_iter` to build a set of thread-local
queues, and collect them after going wide.

## Performance
Using `cargo run --profile stress-test --features trace_tracy --example
many_cubes`. Yellow is this PR. Red is main.

`extract_meshes`:


![image](https://github.com/bevyengine/bevy/assets/3137680/9d45aa2e-3cfa-4fad-9c08-53498b51a73b)

An average reduction from 1.2ms to 770us is seen, a 41.6% improvement.

Note: this is still not including #9950's changes, so this may actually
result in even faster speedups once that's merged in.
2023-10-01 09:44:03 +00:00
Mike
1d7577fc42
ignore time channel error (#9981)
# Objective

- sometimes when bevy shuts down on certain machines the render thread
tries to send the time after the main world has been dropped.
- fixes an error mentioned in a reply in
https://github.com/bevyengine/bevy/issues/9543

---

## Changelog

- ignore disconnected errors from the time channel.
2023-10-01 07:55:17 +00:00
Christian Hughes
9c004439b8
Remove States::variants and remove enum-only restriction its derive (#9945)
# Objective

The `States::variants` method was once used to construct `OnExit` and
`OnEnter` schedules for every possible value of a given `States` type.
[Since the switch to lazily initialized
schedules](https://github.com/bevyengine/bevy/pull/8028/files#diff-b2fba3a0c86e496085ce7f0e3f1de5960cb754c7d215ed0f087aa556e529f97f),
we no longer need to track every possible value.

This also opens the door to `States` types that aren't enums.

## Solution

- Remove the unused `States::variants` method and its associated type.
- Remove the enum-only restriction on derived States types.

---

## Changelog

- Removed `States::variants` and its associated type.
- Derived `States` can now be datatypes other than enums.

## Migration Guide

- `States::variants` no longer exists. If you relied on this function,
consider using a library that provides enum iterators.
2023-09-30 22:32:39 +00:00
James Liu
95813b87f7
Cache parallel iteration spans (#9950)
# Objective
We cached system spans in #9390, but another common span seen in most
Bevy apps when enabling tracing are Query::par_iter(_mut) related spans.

## Solution
Cache them in QueryState. The one downside to this is that we pay for
the memory for every Query(State) instantiated, not just those that are
used for parallel iteration, but this shouldn't be a significant cost
unless the app is creating hundreds of thousands of Query(State)s
regularly.

## Metrics
Tested against `cargo run --profile stress-test --features trace_tracy
--example many_cubes`. Yellow is this PR, red is main.

`sync_simple_transforms`:


![image](https://github.com/bevyengine/bevy/assets/3137680/d60f6d69-5586-4424-9d78-aac78992aacd)

`check_visibility`:


![image](https://github.com/bevyengine/bevy/assets/3137680/096a58d2-a330-4a32-b806-09cd524e6e15)

Full frame:


![image](https://github.com/bevyengine/bevy/assets/3137680/3b088cf8-9487-4bc7-a308-026e172d6672)
2023-09-30 08:03:35 +00:00
Jacques Schutte
857fb9c724
Remove monkey.gltf (#9974)
# Objective

- Fixes #9967

## Solution

- Remove `monkey.gltf`
- Added `torus.gltf`, which is two torus meshes joined together, to
replace `monkey.gltf` in the examples

## Examples

I made `torus.gltf` mainly so that the multiple_windows example clearly
shows the different camera angles

### asset_loading

![image](https://github.com/bevyengine/bevy/assets/425184/0ee51013-973d-4b23-9aa6-d254fecde7f1)

### hot_asset_reloading

![image](https://github.com/bevyengine/bevy/assets/425184/b2a2b1d8-167e-478b-b954-756ca0bbe469)

### multiple_windows:

![image](https://github.com/bevyengine/bevy/assets/425184/cb23de2c-9ff8-4843-a5c0-981e4d29ae49)

![image](https://github.com/bevyengine/bevy/assets/425184/b00bc2c7-66e8-4881-8fab-08269e223961)
2023-09-30 02:50:31 +00:00
cyqsimon
14db5b38dc
Clarify behaviour of Timer::finished() for repeating timers (#9939)
# Objective

I was wondering whether to use `Timer::finished` or
`Timer::just_finished` for my repeating timer. This PR clarifies their
difference (or rather, lack thereof).

## Solution

More docs & examples.
2023-09-29 21:57:01 +00:00
SADIK KUZU
483f2464a8
Fix typos (#9965)
# Objective

- There were a few typos in the project.
- This PR fixes these typos.

## Solution

- Fixing the typos.

Signed-off-by: SADIK KUZU <sadikkuzu@hotmail.com>
2023-09-29 12:26:41 +00:00
Christian Hughes
f8fd93f418
Add TypePath to the prelude (#9963)
# Objective

In order to derive `Asset`s (v2), `TypePath` must also be implemented.
`TypePath` is not currently in the prelude, but given it is *required*
when deriving something that *is* in the prelude, I think it deserves to
be added.

## Solution

Add `TypePath` to `bevy_reflect::prelude`.
2023-09-29 08:27:30 +00:00
Christian Hughes
7a72bac779
Fix unused variable warning for simple AssetV2 derives (#9961)
# Objective

Fix #9960 

## Solution

Make the `visit` parameter `_visit` if there are no dependencies.

New `cargo expand` output:
```rust
pub struct Rarity {
    pub name: SharedStr,
    pub color: Color,
}
impl bevy::asset::Asset for Rarity {}
impl bevy::asset::VisitAssetDependencies for Rarity {
    fn visit_dependencies(
        &self,
        _visit: &mut impl FnMut(bevy::asset::UntypedAssetId), // <-- fixed
    ) {}
}
impl bevy::reflect::TypePath for Rarity {
    fn type_path() -> &'static str {
        "myasset::item::Rarity"
    }
    fn short_type_path() -> &'static str {
        "Rarity"
    }
    fn type_ident() -> Option<&'static str> {
        ::core::option::Option::Some("Rarity")
    }
    fn crate_name() -> Option<&'static str> {
        ::core::option::Option::Some(
            "myasset::item".split(':').next().unwrap(),
        )
    }
    fn module_path() -> Option<&'static str> {
        ::core::option::Option::Some("myasset::item")
    }
}
```
2023-09-29 08:08:13 +00:00
Bruce Mitchener
a5a457c3c8
docs: Use intradoc links for method references. (#9958)
# Objective

- Use intradoc links to let the compiler verify correctness.

## Solution

- Use intradoc links.
2023-09-29 07:09:14 +00:00
ickshonpe
edba496697
Store both the rounded and unrounded node size in Node (#9923)
# Objective

Text bounds are computed by the layout algorithm using the text's
measurefunc so that text will only wrap after it's used the maximum
amount of available horizontal space.

When the layout size is returned the layout coordinates are rounded and
this sometimes results in the final size of the Node not matching the
size computed with the measurefunc. This means that the text may no
longer fit the horizontal available space and instead wrap onto a new
line. However, no glyphs will be generated for this new line because no
vertical space for the extra line was allocated.

fixes #9874

## Solution

Store both the rounded and unrounded node sizes in `Node`.

Rounding is used to eliminate pixel-wide gaps between nodes that should
be touching edge to edge, but this isn't necessary for text nodes as
they don't have solid edges.

## Changelog

* Added the `rounded_size: Vec2` field to `Node`.
* `text_system` uses the unrounded node size when computing a text
layout.

---------

Co-authored-by: Rob Parrett <robparrett@gmail.com>
2023-09-28 22:42:13 +00:00
François
96a7b4a777
run mobile tests on more devices / OS versions (#9936)
# Objective

- run mobile tests on more devices / OS versions

## Solution

- Add more recent iOS devices / OS versions
- Add older Android devices / OS versions

You can check the results of a recent run on those devices here:
https://percy.io/dede4209/Bevy-Mobile-Example/builds/30355307
2023-09-28 22:40:13 +00:00
ickshonpe
418405046a
text_wrap_debug scale factor commandline args (#9951)
# Objective

Add commandline arguments to `text_wrap_debug` to set the window and UI
scale factors.
2023-09-28 21:15:55 +00:00
Marco Buono
20ed3e0e76
macOS Sonoma (14.0) / Xcode 15.0 — Compatibility Fixes + Docs (#9905)
# Objective

Improve compatibility with macOS Sonoma and Xcode 15.0.

## Solution

- Adds the workaround by @ptxmac to ignore the invalid window sizes
provided by `winit` on macOS 14.0
- This still provides a slightly wrong content size when resizing (it
fails to account for the window title bar, so some content gets clipped
at the bottom) but it's _much better_ than crashing.
- Adds docs on how to work around the `bindgen` bug on Xcode 15.0.

## Related Issues:

- https://github.com/RustAudio/coreaudio-sys/issues/85
- https://github.com/rust-windowing/winit/issues/2876

---

## Changelog

- Added a workaround for a `winit`-related crash under macOS Sonoma
(14.0)

---------

Co-authored-by: Peter Kristensen <peter@ptx.dk>
2023-09-27 22:41:16 +00:00
Robert Swain
b6ead2be95
Use EntityHashMap<Entity, T> for render world entity storage for better performance (#9903)
# Objective

- Improve rendering performance, particularly by avoiding the large
system commands costs of using the ECS in the way that the render world
does.

## Solution

- Define `EntityHasher` that calculates a hash from the
`Entity.to_bits()` by `i | (i.wrapping_mul(0x517cc1b727220a95) << 32)`.
`0x517cc1b727220a95` is something like `u64::MAX / N` for N that gives a
value close to π and that works well for hashing. Thanks for @SkiFire13
for the suggestion and to @nicopap for alternative suggestions and
discussion. This approach comes from `rustc-hash` (a.k.a. `FxHasher`)
with some tweaks for the case of hashing an `Entity`. `FxHasher` and
`SeaHasher` were also tested but were significantly slower.
- Define `EntityHashMap` type that uses the `EntityHashser`
- Use `EntityHashMap<Entity, T>` for render world entity storage,
including:
- `RenderMaterialInstances` - contains the `AssetId<M>` of the material
associated with the entity. Also for 2D.
- `RenderMeshInstances` - contains mesh transforms, flags and properties
about mesh entities. Also for 2D.
- `SkinIndices` and `MorphIndices` - contains the skin and morph index
for an entity, respectively
  - `ExtractedSprites`
  - `ExtractedUiNodes`

## Benchmarks

All benchmarks have been conducted on an M1 Max connected to AC power.
The tests are run for 1500 frames. The 1000th frame is captured for
comparison to check for visual regressions. There were none.

### 2D Meshes

`bevymark --benchmark --waves 160 --per-wave 1000 --mode mesh2d`

#### `--ordered-z`

This test spawns the 2D meshes with z incrementing back to front, which
is the ideal arrangement allocation order as it matches the sorted
render order which means lookups have a high cache hit rate.

<img width="1112" alt="Screenshot 2023-09-27 at 07 50 45"
src="https://github.com/bevyengine/bevy/assets/302146/e140bc98-7091-4a3b-8ae1-ab75d16d2ccb">

-39.1% median frame time.

#### Random

This test spawns the 2D meshes with random z. This not only makes the
batching and transparent 2D pass lookups get a lot of cache misses, it
also currently means that the meshes are almost certain to not be
batchable.

<img width="1108" alt="Screenshot 2023-09-27 at 07 51 28"
src="https://github.com/bevyengine/bevy/assets/302146/29c2e813-645a-43ce-982a-55df4bf7d8c4">

-7.2% median frame time.

### 3D Meshes

`many_cubes --benchmark`

<img width="1112" alt="Screenshot 2023-09-27 at 07 51 57"
src="https://github.com/bevyengine/bevy/assets/302146/1a729673-3254-4e2a-9072-55e27c69f0fc">

-7.7% median frame time.

### Sprites

**NOTE: On `main` sprites are using `SparseSet<Entity, T>`!**

`bevymark --benchmark --waves 160 --per-wave 1000 --mode sprite`

#### `--ordered-z`

This test spawns the sprites with z incrementing back to front, which is
the ideal arrangement allocation order as it matches the sorted render
order which means lookups have a high cache hit rate.

<img width="1116" alt="Screenshot 2023-09-27 at 07 52 31"
src="https://github.com/bevyengine/bevy/assets/302146/bc8eab90-e375-4d31-b5cd-f55f6f59ab67">

+13.0% median frame time.

#### Random

This test spawns the sprites with random z. This makes the batching and
transparent 2D pass lookups get a lot of cache misses.

<img width="1109" alt="Screenshot 2023-09-27 at 07 53 01"
src="https://github.com/bevyengine/bevy/assets/302146/22073f5d-99a7-49b0-9584-d3ac3eac3033">

+0.6% median frame time.

### UI

**NOTE: On `main` UI is using `SparseSet<Entity, T>`!**

`many_buttons`

<img width="1111" alt="Screenshot 2023-09-27 at 07 53 26"
src="https://github.com/bevyengine/bevy/assets/302146/66afd56d-cbe4-49e7-8b64-2f28f6043d85">

+15.1% median frame time.

## Alternatives

- Cart originally suggested trying out `SparseSet<Entity, T>` and indeed
that is slightly faster under ideal conditions. However,
`PassHashMap<Entity, T>` has better worst case performance when data is
randomly distributed, rather than in sorted render order, and does not
have the worst case memory usage that `SparseSet`'s dense `Vec<usize>`
that maps from the `Entity` index to sparse index into `Vec<T>`. This
dense `Vec` has to be as large as the largest Entity index used with the
`SparseSet`.
- I also tested `PassHashMap<u32, T>`, intending to use `Entity.index()`
as the key, but this proved to sometimes be slower and mostly no
different.
- The only outstanding approach that has not been implemented and tested
is to _not_ clear the render world of its entities each frame. That has
its own problems, though they could perhaps be solved.
- Performance-wise, if the entities and their component data were not
cleared, then they would incur table moves on spawn, and should not
thereafter, rather just their component data would be overwritten.
Ideally we would have a neat way of either updating data in-place via
`&mut T` queries, or inserting components if not present. This would
likely be quite cumbersome to have to remember to do everywhere, but
perhaps it only needs to be done in the more performance-sensitive
systems.
- The main problem to solve however is that we want to both maintain a
mapping between main world entities and render world entities, be able
to run the render app and world in parallel with the main app and world
for pipelined rendering, and at the same time be able to spawn entities
in the render world in such a way that those Entity ids do not collide
with those spawned in the main world. This is potentially quite
solvable, but could well be a lot of ECS work to do it in a way that
makes sense.

---

## Changelog

- Changed: Component data for entities to be drawn are no longer stored
on entities in the render world. Instead, data is stored in a
`EntityHashMap<Entity, T>` in various resources. This brings significant
performance benefits due to the way the render app clears entities every
frame. Resources of most interest are `RenderMeshInstances` and
`RenderMaterialInstances`, and their 2D counterparts.

## Migration Guide

Previously the render app extracted mesh entities and their component
data from the main world and stored them as entities and components in
the render world. Now they are extracted into essentially
`EntityHashMap<Entity, T>` where `T` are structs containing an
appropriate group of data. This means that while extract set systems
will continue to run extract queries against the main world they will
store their data in hash maps. Also, systems in later sets will either
need to look up entities in the available resources such as
`RenderMeshInstances`, or maintain their own `EntityHashMap<Entity, T>`
for their own data.

Before:
```rust
fn queue_custom(
    material_meshes: Query<(Entity, &MeshTransforms, &Handle<Mesh>), With<InstanceMaterialData>>,
) {
    ...
    for (entity, mesh_transforms, mesh_handle) in &material_meshes {
        ...
    }
}
```

After:
```rust
fn queue_custom(
    render_mesh_instances: Res<RenderMeshInstances>,
    instance_entities: Query<Entity, With<InstanceMaterialData>>,
) {
    ...
    for entity in &instance_entities {
        let Some(mesh_instance) = render_mesh_instances.get(&entity) else { continue; };
        // The mesh handle in `AssetId<Mesh>` form, and the `MeshTransforms` can now
        // be found in `mesh_instance` which is a `RenderMeshInstance`
        ...
    }
}
```

---------

Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
2023-09-27 08:28:28 +00:00