device 0.0.4

A generative engine
use super::*;

pub(crate) struct CaptureThread {
  handle: JoinHandle<()>,
  tx: mpsc::Sender<Capture>,
}

impl CaptureThread {
  fn capture(capture: Capture) {
    let view = capture.buffer.get_mapped_range(..);

    let bytes_per_row = capture.size.x.get().into_usize() * COLOR_CHANNELS;

    let mut image = Image::default();
    image.resize(capture.size.x.get(), capture.size.y.get());
    for (src, dst) in view
      .chunks(capture.bytes_per_row_with_padding)
      .map(|src| &src[..bytes_per_row])
      .take(capture.size.y.get().into_usize())
      .zip(image.data_mut().chunks_mut(bytes_per_row))
    {
      for (src, dst) in src
        .chunks(COLOR_CHANNELS)
        .zip(dst.chunks_mut(COLOR_CHANNELS))
      {
        capture
          .format
          .swizzle(src.try_into().unwrap(), dst.try_into().unwrap());
      }
    }

    drop(view);

    capture.buffer.unmap();

    capture.pool.lock().unwrap().push(capture.buffer);

    drop(capture.pool);

    (capture.callback)(image);
  }

  pub(crate) fn finish(self) -> Result {
    drop(self.tx);

    match self.handle.join() {
      Ok(()) => Ok(()),
      Err(panic_value) => Err(error::RecordingJoin { panic_value }.build()),
    }
  }

  pub(crate) fn new() -> Result<Self> {
    let (tx, rx) = mpsc::channel();

    let handle = thread_spawn("capture", move || {
      loop {
        let Ok(capture) = rx.recv() else {
          break;
        };

        Self::capture(capture);
      }
    })?;

    Ok(Self { handle, tx })
  }

  pub(crate) fn tx(&self) -> &mpsc::Sender<Capture> {
    &self.tx
  }
}