mirror of
https://github.com/penpot/penpot.git
synced 2026-08-09 06:18:47 +00:00
⚡ Soft-drain GPU mid-walk on progressive Partials (#11127)
Release packs far more cheap Current draws (e.g. fills_none paths) into one Partial than debug; a single end-of-Partial flush_and_submit then stalls the browser. Soft-flush every N walker nodes (and on Partial yield) keeps ops buffers bounded while Full still submits via present_frame.
This commit is contained in:
parent
e1c51442cd
commit
43b12bc4b9
@ -1386,8 +1386,8 @@ impl RenderState {
|
||||
// the layered path without Fills/Strokes blits.
|
||||
// Non-SrcOver blend, frame clip blur, and masked groups stay layered.
|
||||
// Stroke-only (fills_none) can go direct: empty fills are a no-op and
|
||||
// strokes paint into Current. Requires Partial GPU drain (dc1ab) so
|
||||
// large SVG-icon files do not backlog commands until Full present.
|
||||
// strokes paint into Current. Large files need mid-walk GPU drains so
|
||||
// release builds do not backlog a huge ops buffer in one Partial.
|
||||
let can_render_directly = apply_to_current_surface
|
||||
&& offset.is_none()
|
||||
&& parent_shadows.is_none()
|
||||
@ -2461,12 +2461,9 @@ impl RenderState {
|
||||
panic!("FrameType::None");
|
||||
}
|
||||
FrameType::Partial => {
|
||||
// Drain tile GPU work (Current / tile atlas / cache) without
|
||||
// presenting Target and without re-snapshotting the tile atlas —
|
||||
// composition stays deferred to Full. A Backbuffer flush alone
|
||||
// left commands queued until present_frame's flush_and_submit,
|
||||
// which stalled the browser on large files.
|
||||
crate::get_gpu_state().context.flush_and_submit();
|
||||
// Final soft drain for this yield (mid-walk also drains; see
|
||||
// `drain_partial_gpu_soft`). Full still submits via present_frame.
|
||||
Self::drain_partial_gpu_soft();
|
||||
}
|
||||
FrameType::Full => {
|
||||
// A full-quality frame is now complete. Rebuild the per-shape crop
|
||||
@ -2669,6 +2666,15 @@ impl RenderState {
|
||||
true
|
||||
}
|
||||
|
||||
/// Soft-drain GPU command buffers during progressive tile walks.
|
||||
/// Release packs far more cheap Current draws (e.g. fills_none paths) into
|
||||
/// one Partial than debug; flushing only at Partial end then stalls. Call
|
||||
/// periodically so each flush stays small. Full present still submits.
|
||||
#[inline]
|
||||
fn drain_partial_gpu_soft() {
|
||||
crate::get_gpu_state().context.flush(None);
|
||||
}
|
||||
|
||||
/// Skip all drop/inner shadows in fast mode, or when even a large design-space
|
||||
/// shadow would be subpixel. Otherwise filter per shadow via
|
||||
/// [`Shadow::is_perceptible_at_scale_for`] (stricter for recursive shapes).
|
||||
@ -3775,6 +3781,12 @@ impl RenderState {
|
||||
if allow_stop && self.should_stop_rendering(iteration, timestamp) {
|
||||
return Ok((is_empty, true));
|
||||
}
|
||||
// Keep GPU ops buffers bounded when many shapes paint cheaply to
|
||||
// Current (release packs far more per Partial than debug).
|
||||
let drain_every = self.options.partial_gpu_drain_every_n;
|
||||
if allow_stop && drain_every > 0 && iteration > 0 && iteration % drain_every == 0 {
|
||||
Self::drain_partial_gpu_soft();
|
||||
}
|
||||
iteration += 1;
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,10 @@ const VIEWPORT_INTEREST_AREA_THRESHOLD: i32 = 1;
|
||||
const MIN_DPR_VIEWPORT_INTEREST_AREA_THRESHOLD: i32 = 2;
|
||||
const MAX_BLOCKING_TIME_MS: i32 = 32;
|
||||
const NODE_BATCH_THRESHOLD: i32 = 3;
|
||||
/// Soft-drain GPU every N walker nodes on progressive Partials. Keeps ops
|
||||
/// buffers bounded when many shapes paint cheaply to Current (release packs
|
||||
/// far more per budget than debug).
|
||||
const PARTIAL_GPU_DRAIN_EVERY_N: i32 = 64;
|
||||
const BLUR_DOWNSCALE_THRESHOLD: f32 = 8.0;
|
||||
const ANTIALIAS_THRESHOLD: f32 = 7.0;
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@ -29,6 +33,9 @@ pub struct RenderOptions {
|
||||
pub dpr_viewport_interest_area_threshold: i32,
|
||||
pub max_blocking_time_ms: i32,
|
||||
pub node_batch_threshold: i32,
|
||||
/// Soft-flush GPU every N nodes during progressive tile walks (see
|
||||
/// [`PARTIAL_GPU_DRAIN_EVERY_N`]).
|
||||
pub partial_gpu_drain_every_n: i32,
|
||||
pub blur_downscale_threshold: f32,
|
||||
pub capture_frames: i32,
|
||||
}
|
||||
@ -45,6 +52,7 @@ impl Default for RenderOptions {
|
||||
dpr_viewport_interest_area_threshold: VIEWPORT_INTEREST_AREA_THRESHOLD,
|
||||
max_blocking_time_ms: MAX_BLOCKING_TIME_MS,
|
||||
node_batch_threshold: NODE_BATCH_THRESHOLD,
|
||||
partial_gpu_drain_every_n: PARTIAL_GPU_DRAIN_EVERY_N,
|
||||
blur_downscale_threshold: BLUR_DOWNSCALE_THRESHOLD,
|
||||
capture_frames: 0,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user