-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement Send and Sync for softbuffer types
Previously, types in softbuffer were !Send and !Sync. However it would be nice if types could be shared across threads. Therefore I've made the following changes: - Context<D> is Send+Sync iff D is Send+Sync - Surface<D, W> is Send iff D is Send+Sync and W is Send - Buffer<'x, D, W> is Send iff D if Send+Sync and W is Send Materially, I've made the following changes across the backends: - X11, Wayland and KMS use Arc for their displays instead of Rc. - MacOS uses MainThreadBound to secure windowing resources. This restriction was already implicitly enforced anyhow. - Windows creates a thread specifically for allocating and then deallocating device contexts. This lets us get around the thread affinity problem. Closes #205 Signed-off-by: John Nunley <[email protected]> Co-authored-by: Mads Marquart <[email protected]>
- Loading branch information
Showing
12 changed files
with
400 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
//! `Surface` implements `Send`. This makes sure that multithreading can work here. | ||
#[cfg(not(target_family = "wasm"))] | ||
mod ex { | ||
use std::num::NonZeroU32; | ||
use std::sync::{mpsc, Arc, Mutex}; | ||
use winit::event::{Event, KeyEvent, WindowEvent}; | ||
use winit::event_loop::{ControlFlow, EventLoop}; | ||
use winit::keyboard::{Key, NamedKey}; | ||
use winit::window::Window; | ||
|
||
include!("utils/winit_app.rs"); | ||
|
||
type Surface = softbuffer::Surface<Arc<Window>, Arc<Window>>; | ||
|
||
fn render_thread( | ||
window: Arc<Window>, | ||
surface: Arc<Mutex<Surface>>, | ||
do_render: mpsc::Receiver<()>, | ||
done: mpsc::Sender<()>, | ||
) { | ||
loop { | ||
println!("waiting for render..."); | ||
if do_render.recv().is_err() { | ||
// Main thread is dead. | ||
break; | ||
} | ||
|
||
// Perform the rendering. | ||
let mut surface = surface.lock().unwrap(); | ||
if let (Some(width), Some(height)) = { | ||
let size = window.inner_size(); | ||
println!("got size: {size:?}"); | ||
(NonZeroU32::new(size.width), NonZeroU32::new(size.height)) | ||
} { | ||
println!("resizing..."); | ||
surface.resize(width, height).unwrap(); | ||
|
||
let mut buffer = surface.buffer_mut().unwrap(); | ||
for y in 0..height.get() { | ||
for x in 0..width.get() { | ||
let red = x % 255; | ||
let green = y % 255; | ||
let blue = (x * y) % 255; | ||
let index = y as usize * width.get() as usize + x as usize; | ||
buffer[index] = blue | (green << 8) | (red << 16); | ||
} | ||
} | ||
|
||
println!("presenting..."); | ||
buffer.present().unwrap(); | ||
} | ||
|
||
// We're done, tell the main thread to keep going. | ||
done.send(()).ok(); | ||
} | ||
} | ||
|
||
pub(super) fn entry() { | ||
let event_loop = EventLoop::new().unwrap(); | ||
|
||
let app = winit_app::WinitAppBuilder::with_init(|elwt| { | ||
let attributes = Window::default_attributes(); | ||
#[cfg(target_arch = "wasm32")] | ||
let attributes = | ||
winit::platform::web::WindowAttributesExtWebSys::with_append(attributes, true); | ||
let window = Arc::new(elwt.create_window(attributes).unwrap()); | ||
|
||
let context = softbuffer::Context::new(window.clone()).unwrap(); | ||
let surface = { | ||
println!("making surface..."); | ||
let surface = softbuffer::Surface::new(&context, window.clone()).unwrap(); | ||
Arc::new(Mutex::new(surface)) | ||
}; | ||
|
||
// Spawn a thread to handle rendering. | ||
let (start_render, do_render) = mpsc::channel(); | ||
let (render_done, finish_render) = mpsc::channel(); | ||
println!("starting thread..."); | ||
std::thread::spawn({ | ||
let window = window.clone(); | ||
let surface = surface.clone(); | ||
move || render_thread(window, surface, do_render, render_done) | ||
}); | ||
|
||
(window, surface, start_render, finish_render) | ||
}) | ||
.with_event_handler(|state, event, elwt| { | ||
let (window, _surface, start_render, finish_render) = state; | ||
elwt.set_control_flow(ControlFlow::Wait); | ||
|
||
match event { | ||
Event::WindowEvent { | ||
window_id, | ||
event: WindowEvent::RedrawRequested, | ||
} if window_id == window.id() => { | ||
// Start the render and then finish it. | ||
start_render.send(()).unwrap(); | ||
finish_render.recv().unwrap(); | ||
} | ||
Event::WindowEvent { | ||
event: | ||
WindowEvent::CloseRequested | ||
| WindowEvent::KeyboardInput { | ||
event: | ||
KeyEvent { | ||
logical_key: Key::Named(NamedKey::Escape), | ||
.. | ||
}, | ||
.. | ||
}, | ||
window_id, | ||
} if window_id == window.id() => { | ||
elwt.exit(); | ||
} | ||
_ => {} | ||
} | ||
}); | ||
|
||
winit_app::run_app(event_loop, app); | ||
} | ||
} | ||
|
||
#[cfg(target_family = "wasm")] | ||
mod ex { | ||
pub(crate) fn entry() { | ||
eprintln!("winit_multithreaded doesn't work on WASM"); | ||
} | ||
} | ||
|
||
fn main() { | ||
ex::entry(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.