What is required to implement `Send` and `Sync`?
J-Cake opened this issue · comments
In the process of integrating Raqote into several lower-level projects involving frame buffers and DRM etc, I'm looking into multithreadded applications, and noticed that DrawTarget
s don't seem to support this.
NonNull<raqote::rasterizer::ActiveEdge>
cannot be sent between threads safely.
I'm wondering what's involved in order to achieve thread-safety, such as locking a mutex before rasterisation etc, as well as whether there are plans for this?
Thanks heaps. Love the library.
I'm also a bit puzzled by this, but I got around it by just sending the
width, height, and underlying buffer around. Naturally, this loses the
other bits of state on a DrawTarget
(layers, clips, transforms), but
if you're just trying to pass around the image data then it works fine:
use std::sync::{Arc, Mutex};
struct Output {
i: u32,
// `DrawTarget` is `!Send`, so we break it down into its components.
width: i32,
height: i32,
data: Vec<u32>,
}
let outputs = Arc::new(Mutex::new(Vec::<Output>::new()));
std::thread::scope(|s| {
for i in 0..steps {
let outputs = outputs.clone();
s.spawn(move || {
let mut dt = DrawTarget::new(...);
// ... paint onto `dt` (expensive) ...
let output = Output {
i,
width: dt.width(),
height: dt.height(),
data: dt.into_inner(),
};
// lock the mutex just briefly to push our results
outputs.lock().expect("poison").push(output);
});
}
});
let mut composite = DrawTarget::new(...);
for output in outputs.lock().expect("poison").iter() {
let img = raqote::Image {
width: output.width,
height: output.height,
data: output.data.as_slice(),
};
composite.draw_image_at(some_x, some_y, &img, DrawOptions::new());
}
My work-around is using the SendWrapper to wrap the font in a static parameter.
use font_kit::font::Font;
use send_wrapper::SendWrapper;
lazy_static! {
pub static ref RES_FONT_ID_MAP: Mutex<HashMap<String, SendWrapper<Font>>> = {
let m = HashMap::new();
Mutex::new(m)
};
}