jrmuizel / raqote

Rust 2D graphics library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 DrawTargets 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)
    };
}