Skip to content

[Merged by Bors] - Avoid creating SurfaceConfiguration in prepare_windows#6255

Closed
MDeiml wants to merge 2 commits into
bevyengine:mainfrom
MDeiml:avoid-creating-surface-config
Closed

[Merged by Bors] - Avoid creating SurfaceConfiguration in prepare_windows#6255
MDeiml wants to merge 2 commits into
bevyengine:mainfrom
MDeiml:avoid-creating-surface-config

Conversation

@MDeiml

@MDeiml MDeiml commented Oct 14, 2022

Copy link
Copy Markdown
Contributor

Objective

  • Avoids creating a SurfaceConfiguration for every window in every frame for the prepare_windows system
  • As such also avoid calling get_supported_formats for every window in every frame

Solution

  • Construct SurfaceConfiguration lazyly in prepare_windows

This also changes the error message for failed initial surface configuration from "Failed to acquire next swapchain texture" to "Error configuring surface".

This changes `prepare_windows` to only create a `SurfaceConfiguration`
if it is acutally needed. Without this change, `SurfaceConfiguration`
is built for every window in every frame. This also includes calling
`get_supported_formats` for every window.
@nicopap nicopap added A-Windowing Platform-agnostic interface layer to run your app in C-Performance A change motivated by improving speed, memory usage or compile times A-Rendering Drawing game state to the screen labels Oct 14, 2022

@nicopap nicopap left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So the basic change is to replace the:

let swap_chain_descriptor = wgpu…

with

let create_swap_chain_descriptor = || wgpu…

And call the closure when relevant. I've no idea on the perf profile of get_supported_formats (defined here https://docs.rs/wgpu/latest/src/wgpu/backend/direct.rs.html#963-975) So this might be an improvement.

The other change is to split the render_device.configure_surface(…) into two separate branches. The only benefit is to have a distinct error message ("error configuring" vs "error reconfiguring"), but I find it makes it much more difficult to read the code and I don't see how having a slightly different error message in the case of initial configuration helps, IMO this should be reverted, and only the "lazification" of swap_chain_descriptor should be kept.

Obviously if you have a good reason for this I'm missing I'd be glad to hear it out.

@MDeiml

MDeiml commented Oct 14, 2022

Copy link
Copy Markdown
Contributor Author

Without changing the control flow the SurfaceConfiguration might be needed twice, if the surface is configured and then get_current_texture() immediately returns Outdated. Covering this case would mean either storing SurfaceConfiguration in an Option or creating it twice.

I think that this case should never happen though, as it does not make sense for the surface to be outdated immediately after being configured. So calling the closure twice should be ok. I just think that the control flow I used represents the actual logic better, since the intent is to call configure_surface at most once. But I'm happy to change it to make it more readable.

@MDeiml

MDeiml commented Oct 14, 2022

Copy link
Copy Markdown
Contributor Author

I also had a shallow look at how get_supported_formats is implemented and it seems to end up calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR among other things, so this should make a change performance-wise (albeit maybe a small one).

@nicopap

nicopap commented Oct 14, 2022

Copy link
Copy Markdown
Contributor

Of course! Yeah naturally, the || … you did is a welcome change. Regarding the complexity of the code, here is a suggestion:

let force_update_surface = window_surfaces.configured_windows.insert(window.id)
            || window.size_changed
            || window.present_mode_changed;
let frame = match (surface.get_current_texture(), force_update_surface) {
  (_, true) | (Err(Outdated), _) => {
                    render_device.configure_surface(surface, &create_swap_chain_descriptor());
                    surface
                        .get_current_texture()
                        .expect("Error reconfiguring surface")
  }
  (Ok(swap…), false) => …
  …
};
        window.swap_chain_texture = Some(TextureView::from(frame));

A more "imperative" alternative would make judicious use of an early return and inline the window.swap_chain_texture = Some(TextureView::from(frame)) bit where relevant rather than returning the frame value from the match/if.

Regardless, you made a good point, and the code is acceptable as is.

Comment thread crates/bevy_render/src/view/window.rs

@alice-i-cecile alice-i-cecile left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Makes sense, and I've checked to ensure that the logic is equivalent.

Added a small comment to make this logic a bit easier to skim; 0 parameter closures can be hard to read.

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Oct 17, 2022
@alice-i-cecile

Copy link
Copy Markdown
Member

Great work, this is a nice little optimization.

bors r+

bors Bot pushed a commit that referenced this pull request Oct 24, 2022
# Objective

- Avoids creating a `SurfaceConfiguration` for every window in every frame for the `prepare_windows` system
- As such also avoid calling `get_supported_formats` for every window in every frame

## Solution

- Construct `SurfaceConfiguration` lazyly in `prepare_windows`

---

This also changes the error message for failed initial surface configuration from "Failed to acquire next swapchain texture" to "Error configuring surface".
@bors

bors Bot commented Oct 24, 2022

Copy link
Copy Markdown

Build failed (retrying...):

@mockersf

Copy link
Copy Markdown
Member

bors r-
cancelling Bors as there is a formatting issue in this PR

@bors

bors Bot commented Oct 24, 2022

Copy link
Copy Markdown

Canceled.

@MDeiml
MDeiml force-pushed the avoid-creating-surface-config branch from a82c3fb to 1a7a539 Compare October 24, 2022 14:50
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
@MDeiml
MDeiml force-pushed the avoid-creating-surface-config branch from 1a7a539 to fb287c0 Compare October 24, 2022 14:54
@MDeiml

MDeiml commented Oct 24, 2022

Copy link
Copy Markdown
Contributor Author

Fixed it

@alice-i-cecile

Copy link
Copy Markdown
Member

bors r+

bors Bot pushed a commit that referenced this pull request Oct 24, 2022
# Objective

- Avoids creating a `SurfaceConfiguration` for every window in every frame for the `prepare_windows` system
- As such also avoid calling `get_supported_formats` for every window in every frame

## Solution

- Construct `SurfaceConfiguration` lazyly in `prepare_windows`

---

This also changes the error message for failed initial surface configuration from "Failed to acquire next swapchain texture" to "Error configuring surface".
@bors bors Bot changed the title Avoid creating SurfaceConfiguration in prepare_windows [Merged by Bors] - Avoid creating SurfaceConfiguration in prepare_windows Oct 24, 2022
@bors bors Bot closed this Oct 24, 2022
@MDeiml
MDeiml deleted the avoid-creating-surface-config branch October 24, 2022 19:23
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 28, 2022
…e#6255)

# Objective

- Avoids creating a `SurfaceConfiguration` for every window in every frame for the `prepare_windows` system
- As such also avoid calling `get_supported_formats` for every window in every frame

## Solution

- Construct `SurfaceConfiguration` lazyly in `prepare_windows`

---

This also changes the error message for failed initial surface configuration from "Failed to acquire next swapchain texture" to "Error configuring surface".
Pietrek14 pushed a commit to Pietrek14/bevy that referenced this pull request Dec 17, 2022
…e#6255)

# Objective

- Avoids creating a `SurfaceConfiguration` for every window in every frame for the `prepare_windows` system
- As such also avoid calling `get_supported_formats` for every window in every frame

## Solution

- Construct `SurfaceConfiguration` lazyly in `prepare_windows`

---

This also changes the error message for failed initial surface configuration from "Failed to acquire next swapchain texture" to "Error configuring surface".
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
…e#6255)

# Objective

- Avoids creating a `SurfaceConfiguration` for every window in every frame for the `prepare_windows` system
- As such also avoid calling `get_supported_formats` for every window in every frame

## Solution

- Construct `SurfaceConfiguration` lazyly in `prepare_windows`

---

This also changes the error message for failed initial surface configuration from "Failed to acquire next swapchain texture" to "Error configuring surface".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen A-Windowing Platform-agnostic interface layer to run your app in C-Performance A change motivated by improving speed, memory usage or compile times S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants