Skip to content
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

Feature request: split PixmapMut into ranges of scan lines #118

Open
Pr0methean opened this issue Apr 1, 2024 · 5 comments
Open

Feature request: split PixmapMut into ranges of scan lines #118

Pr0methean opened this issue Apr 1, 2024 · 5 comments

Comments

@Pr0methean
Copy link

Pr0methean commented Apr 1, 2024

I have a task that creates a vertical stack of animation frames, where each frame is rendered separately. If I had a separate PixmapMut for each frame, then I'd be able to render the frames in parallel without needing any synchronization. And since a range of scan lines is a contiguous range of bytes, this should be feasible with the existing PixmapMut type.

@Pr0methean Pr0methean changed the title Feature request: mutably borrow ranges of scan lines separately Feature request: split PixmapMut into ranges of scan lines Apr 1, 2024
@RazrFalcon
Copy link
Collaborator

Can you illustrate what you want with some code?

@Pr0methean
Copy link
Author

Pr0methean commented Apr 1, 2024

I'd like to turn this:

    let out = Arc::new(Mutex::new(out));
    let mut join_set = JoinSet::new();
    for (index, frame) in frames.into_vec().into_iter().enumerate() {
        let out = out.clone();
        join_set.spawn(frame.map(async move |frame_pixmap: SimpleArcow<MaybeFromPool<Pixmap>>| {
            out.lock().draw_pixmap(
                0,
                (index as i32) * (frame_height as i32),
                frame_pixmap.as_ref(),
                &PixmapPaint::default(),
                Transform::default(),
                None,
            );
        }));
    }

into this:

    let mut remainder = out;
    for (index, frame) in frames.into_vec().into_iter().enumerate() {
        let (frame_out, remainder) = remainder.split_at_scan_line(frame_height);
        join_set.spawn(frame.map(async move |frame_pixmap: SimpleArcow<MaybeFromPool<Pixmap>>| {
            frame_out.draw_pixmap(
                0,
                0,
                frame_pixmap.as_ref(),
                &PixmapPaint::default(),
                Transform::default(),
                None,
            );
        }));
    }

@RazrFalcon
Copy link
Collaborator

So you basically want a wrapper for slice::split_at_mut? It might be doable, but would take a while to implement.
For now you can do it on your side.

@Pr0methean
Copy link
Author

Pr0methean commented Apr 2, 2024 via email

@Pr0methean
Copy link
Author

Pr0methean commented Apr 3, 2024

I've managed to do it on my end, but it's an ugly solution because variables used from inside a JoinSet have to be &'static.

    let out = Box::leak(Box::new(if clear_output {
        allocate_pixmap_empty(width, total_height)
    } else {
        allocate_pixmap_for_overwrite(background.width(), total_height)
    })) as *mut MaybeFromPool<Pixmap>;
    let background = (*background).as_ref();
    let out_data = unsafe { out.as_mut() }.unwrap().data_mut();
    let mut frame_chunks = out_data.chunks_mut(
        frame_height as usize * width as usize * size_of::<PremultipliedColorU8>()
    );
    let mut join_set = JoinSet::new();
    for frame in frames.into_vec().into_iter() {
        let frame_pixels = frame_chunks.next().unwrap();
        let mut frame_buffer = PixmapMut::from_bytes(frame_pixels, width, frame_height).unwrap();
        frame_buffer.draw_pixmap(
            0,
            0,
            background,
            &PixmapPaint::default(),
            Transform::default(),
            None,
        );
        let frame_buffer = Box::new(frame_buffer);
        join_set.spawn(frame.map(async move |frame_pixmap: SimpleArcow<MaybeFromPool<Pixmap>>| {
            Box::leak(frame_buffer).draw_pixmap(
                0,
                0,
                frame_pixmap.as_ref(),
                &PixmapPaint::default(),
                Transform::default(),
                None,
            );
        }));
    }
    let out = unsafe { Box::from_raw(out) };
    join_all(join_set).await;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants