mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 10:17:02 -06:00
85 lines
2.4 KiB
Rust
85 lines
2.4 KiB
Rust
//! Background rendering (native): heavy documents render off the UI thread while the canvas shows
|
|
//! the previous frame reprojected to the current view. Light documents render synchronously so
|
|
//! edits never lag behind overlays.
|
|
|
|
use std::sync::Arc;
|
|
use std::sync::mpsc::{Receiver, Sender, channel};
|
|
|
|
use vectorcraft_doc::Document;
|
|
use vectorcraft_geom::Affine;
|
|
use vectorcraft_render::{RenderOptions, Rendered, Renderer};
|
|
|
|
use crate::CacheKey;
|
|
|
|
pub struct Job {
|
|
pub key: CacheKey,
|
|
pub doc: Arc<Document>,
|
|
pub w: u32,
|
|
pub h: u32,
|
|
pub view: Affine,
|
|
pub opts: RenderOptions,
|
|
}
|
|
|
|
pub struct Done {
|
|
pub key: CacheKey,
|
|
pub img: Rendered,
|
|
pub ms: f64,
|
|
}
|
|
|
|
pub struct Worker {
|
|
tx: Sender<Job>,
|
|
rx: Receiver<Done>,
|
|
pub pending: Option<CacheKey>,
|
|
}
|
|
|
|
impl Worker {
|
|
/// Spawn the worker thread (None on wasm, where rendering stays synchronous).
|
|
pub fn spawn(ctx: egui::Context) -> Option<Self> {
|
|
if cfg!(target_arch = "wasm32") {
|
|
return None;
|
|
}
|
|
let (tx, jobs) = channel::<Job>();
|
|
let (done_tx, rx) = channel::<Done>();
|
|
std::thread::Builder::new()
|
|
.name("vectorcraft-render".into())
|
|
.spawn(move || {
|
|
let mut r = Renderer::new();
|
|
while let Ok(mut job) = jobs.recv() {
|
|
// Skip stale jobs: only the newest matters.
|
|
while let Ok(newer) = jobs.try_recv() {
|
|
job = newer;
|
|
}
|
|
let t0 = crate::now_ms();
|
|
let img = r.render(&job.doc, job.w, job.h, job.view, &job.opts);
|
|
if done_tx.send(Done { key: job.key, img, ms: crate::now_ms() - t0 }).is_err() {
|
|
break;
|
|
}
|
|
ctx.request_repaint();
|
|
}
|
|
})
|
|
.ok()?;
|
|
Some(Self { tx, rx, pending: None })
|
|
}
|
|
|
|
pub fn submit(&mut self, job: Job) {
|
|
if self.pending.as_ref() == Some(&job.key) {
|
|
return;
|
|
}
|
|
self.pending = Some(job.key.clone());
|
|
let _ = self.tx.send(job);
|
|
}
|
|
|
|
pub fn poll(&mut self) -> Option<Done> {
|
|
let mut last = None;
|
|
while let Ok(d) = self.rx.try_recv() {
|
|
last = Some(d);
|
|
}
|
|
if let Some(d) = &last
|
|
&& self.pending.as_ref() == Some(&d.key)
|
|
{
|
|
self.pending = None;
|
|
}
|
|
last
|
|
}
|
|
}
|