Skip to content

Support all wgpu surface targets #18936

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

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

Conversation

brianreavis
Copy link
Contributor

@brianreavis brianreavis commented Apr 25, 2025

Objective

This PR refactors window handles / surface creation to support all the surface targets that wgpu supports (defined here) instead of just the subset that can be represented by raw-window-handle.

Although not supported out-of-the-box, the primary point for doing this is to unlock the ability to run Bevy entirely off the main thread on iOS and MacOS via wgpu’s SurfaceTargetUnsafe::CoreAnimationLayer.

Solution

Introduce a SurfaceTargetSource component on window entities that's very similar to RawHandleWrapper. It hands out a wgpu::SurfaceTarget or wgpu::SurfaceTargetUnsafe instead of a raw-window-handle handle.

Could this have been achieved by adding CoreAnimationLayer to raw-window-handle? Yes, but then that crate would need a new release and wgpu would need updated. The approach in this PR ensures Bevy supports all that wgpu supports without the potential for future drift.

Although it's now unused, RawHandleWrapper was left in place for anyone implementing custom renderers that aren't necessarily wgpu-based.

Showcase

struct CoreAnimationLayerHandle(*mut std::ffi::c_void);

unsafe impl Send for CoreAnimationLayerHandle {}
unsafe impl Sync for CoreAnimationLayerHandle {}

impl HasSurfaceTarget for CoreAnimationLayerHandle {
    unsafe fn surface_target(&self) -> Option<SurfaceTargetWrapper> {
        Some(SurfaceTargetWrapper::SurfaceTargetUnsafe(
            SurfaceTargetUnsafe::CoreAnimationLayer(self.0),
        ))
    }
}

// The basic idea:

let ca_layer_handle = CoreAnimationLayerHandle(ptr);
std::thread::spawn(move || {
    // (Bevy initialization goes here)
    // Spawn primary window
    let thread_constraint = SurfaceTargetThreadConstraint::None;
    let surface_target_source = SurfaceTargetSource::new(thread_constraint, ca_layer_handle);
    let primary_window = app
        .world_mut()
        .spawn((Window { ... }, PrimaryWindow, surface_target_source))
        .id();
    // (Custom render loop goes here)
});

Testing

  • I tried to compartmentalize unsafe / minimize unsoundness, but could use another set of eyes on it.
  • I tested the following configurations:
    • Run Bevy fully on a background thread on MacOS/iOS via SurfaceTargetUnsafe::CoreAnimationLayer (note: this isn’t supported out of the box in Bevy, but with this PR, it can be achieved with custom initialization similar to what’s shown in the Showcase section above)
    • Run on UiKit / AppKit on main thread via custom implementation
    • Run normal Bevy with bevy_winit on MacOS

Migration Guide

  • If you are not using bevy_winit but are using bevy_render (uncommon), you must insert a SurfaceTargetSource component on window entities. It's nearly identical to RawHandleWrapper, but supports additional surface targets that cannot be represented by raw-window-handle.
  • RawHandleWrapperHolder has been removed. Use RawHandleWrapper to get a handle instead.

@brianreavis brianreavis marked this pull request as draft April 25, 2025 18:25
@brianreavis brianreavis added A-Windowing Platform-agnostic interface layer to run your app in D-Unsafe Touches with unsafe code in some way labels Apr 25, 2025
@brianreavis brianreavis marked this pull request as ready for review April 28, 2025 19:19
@brianreavis brianreavis added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Apr 28, 2025
@mockersf mockersf self-requested a review April 28, 2025 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Windowing Platform-agnostic interface layer to run your app in D-Unsafe Touches with unsafe code in some way S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant