mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 19:27:21 -06:00
#1172: rasterize with up to 8 threads instead of 4
The automatic rasterizer thread count was one per core up to 4. On a 10-core Apple M2 Pro, 8 workers are faster (9 are slower again), and vello_cpu draws the same pixels with any number: - fit page, 50,000 paths: 66.7 → 56.6 ms; after a pan 66.4 → 51.2 ms - 400 % zoom, 50,000 paths: 17.8 → 15.7 ms (back under its 16 ms budget) - fit page, 100,000 paths: 137 → 105 ms; 400 % zoom 33.0 → 25.8 ms Machines with 5 cores or fewer keep their count, and Preferences → Performance and VECTORCRAFT_RENDER_THREADS still override it. pixels_do_not_depend_on_the_thread_count renders a page of live effects and 400 overlapping translucent objects with 0, 1, 4 and 8 workers and gets the same pixels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmMmc1J8XeNLxhRihWv9cc
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Opus 5.5
parent
add27cb8fc
commit
f8064ba3ce
@@ -899,6 +899,35 @@ mod tests {
|
||||
assert!(edited.pixels == Renderer::new().render(&e, 400, 400, view, &opts).pixels, "and matches a fresh render");
|
||||
}
|
||||
|
||||
/// The multithreaded rasterizer draws the same pixels with any number of workers, so the
|
||||
/// automatic thread count can follow the machine.
|
||||
#[test]
|
||||
fn pixels_do_not_depend_on_the_thread_count() {
|
||||
let mut d = effects_page();
|
||||
// Overlapping translucent and blended objects on top of the effects.
|
||||
let l = d.layers[0].id;
|
||||
for i in 0..400 {
|
||||
let id = d.alloc_id();
|
||||
let (x, y) = ((i * 37 % 190) as f64, (i * 53 % 190) as f64);
|
||||
let mut n = Node::path(
|
||||
id,
|
||||
shapes::ellipse(Rect::new(x, y, x + 14.0, y + 9.0)),
|
||||
Appearance::basic(Paint::solid(Color::rgb(0.9, 0.3, 0.1)), Paint::solid(Color::BLACK), 0.7),
|
||||
);
|
||||
n.opacity = 0.6;
|
||||
d.insert(Some(l), usize::MAX, n).unwrap();
|
||||
}
|
||||
let opts = RenderOptions { background: Some([255, 255, 255, 255]), ..Default::default() };
|
||||
let mut frames = vec![];
|
||||
for threads in [Some(0), Some(1), Some(4), Some(8)] {
|
||||
crate::set_default_threads(threads);
|
||||
let mut r = Renderer::new();
|
||||
frames.push(r.render(&d, 1200, 900, Affine::scale(6.0), &opts).pixels);
|
||||
}
|
||||
crate::set_default_threads(None);
|
||||
assert!(frames.windows(2).all(|w| w[0] == w[1]), "the thread count changed pixels");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thumbnails_of_glowing_objects_render_without_panicking() {
|
||||
// Regression: thumbnails used vello's default (multithreaded) context, which panics on filters.
|
||||
|
||||
@@ -1767,7 +1767,9 @@ pub fn set_default_threads(n: Option<u16>) {
|
||||
THREADS_OVERRIDE.store(n.map_or(-1, i32::from), std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Rasterizer worker threads: 0 on wasm; otherwise up to 4 (vello's sweet spot), leaving a core free.
|
||||
/// Rasterizer worker threads: 0 on wasm; otherwise one per core up to 8, leaving a core free. On a
|
||||
/// 10-core machine 8 workers render a 50,000-path page 1.4× faster than 4 (9 are slower again);
|
||||
/// the pixels don't depend on the count (`pixels_do_not_depend_on_the_thread_count`).
|
||||
pub fn default_threads() -> u16 {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
@@ -1782,7 +1784,7 @@ pub fn default_threads() -> u16 {
|
||||
if std::env::var_os("VECTORCRAFT_RENDER_THREADS").is_some() {
|
||||
return std::env::var("VECTORCRAFT_RENDER_THREADS").ok().and_then(|v| v.parse().ok()).unwrap_or(0);
|
||||
}
|
||||
std::thread::available_parallelism().map(|n| (n.get().saturating_sub(1)).min(4) as u16).unwrap_or(0)
|
||||
std::thread::available_parallelism().map(|n| (n.get().saturating_sub(1)).min(8) as u16).unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user