Skip to content

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

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

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

Conversation

@MDeiml
Copy link
Contributor

@MDeiml MDeiml commented Oct 14, 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".

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
Copy link
Contributor

@nicopap nicopap left a comment

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
Copy link
Contributor Author

MDeiml commented Oct 14, 2022

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
Copy link
Contributor Author

MDeiml commented Oct 14, 2022

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
Copy link
Contributor

nicopap commented Oct 14, 2022

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.

Copy link
Member

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

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
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
Copy link
Contributor

bors bot commented Oct 24, 2022

Build failed (retrying...):

@mockersf
Copy link
Member

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

@bors
Copy link
Contributor

bors bot commented Oct 24, 2022

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
Copy link
Contributor Author

MDeiml commented Oct 24, 2022

Fixed it

@alice-i-cecile
Copy link
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