Hey folks,
I'm trying to create my first Rust game using Wasm and SDL. I'm also playing with Specs to compartmentalize everything in systems. Unfortunately, I'm having some issues with the lack of thread-safety of the SDL context, and am wondering what a good fix would be.
To keep everything compartmentalized, I've created a Graphics
system that handles all graphical rendering:
struct Graphics(Sdl);
impl Graphics {
fn new() -> Result<Graphics, String> {
let context = sdl2::init()?;
let video_subsystem = context.video()?;
video_subsystem.window("Game", 800, 600)
.position_centered()
.fullscreen()
.opengl()
.build()
.map_err(|v| v.to_string())?;
Ok(Graphics(context))
}
}
impl<'a> System<'a> for Graphics {
type SystemData = (FetchMut<'a, InputEvents>);
fn run(&mut self, mut data: Self::SystemData) {
let mut event_pump = self.0.event_pump().unwrap();
for event in event_pump.poll_iter() {
match event {
Event::KeyDown {keycode: Some(keycode), ..} => {
data.0.push(InputEvent::KeyDown(keycode));
},
Event::KeyUp {keycode: Some(keycode), ..} => {
data.0.push(InputEvent::KeyUp(keycode));
},
_ => {}
}
}
}
}
At the moment this is intended to render a blank window, retrieve all keyboard events, then make those available as a Specs Resource
so other systems can access it. Next, I initialize the system:
let graphics = Graphics::new()?;
...
let dispatcher = DispatcherBuilder::new()
.add(Controller, "controller", &[])
.add(audio, "audio", &[])
.add(graphics, "graphics", &[])
.build();
This fails:
error[E0277]: the trait bound `std::rc::Rc<sdl2::SdlDrop>: std::marker::Send` is not satisfied in `Graphics`
--> src/main.rs:105:14
|
105 | .add(graphics, "graphics", &[])
| ^^^ `std::rc::Rc<sdl2::SdlDrop>` cannot be sent between threads safely
|
= help: within `Graphics`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<sdl2::SdlDrop>`
= note: required because it appears within the type `sdl2::Sdl`
= note: required because it appears within the type `Graphics`
Pretty sure I understand what this is doing--the SDL context isn't safe to pass across thread boundaries, and the compiler is catching that. What I don't understand is how to fix it. The only place that should access the SDL context is the new
method, which creates it, and the System
implementation which calls it to do rendering and poll for events. How can I compartmentalize that variable so this error will go away? I tried not creating the system myself and letting Specs do it (I.e. passing Graphics
in directly rather than creating an instance) but no change.
Thanks.