Fix onion ghosts: show on blank cels + fault in on seek
- Removed the early `continue` that skipped a layer with no resident content — it also skipped the active raster layer's onion ghosts when the current cel was blank (the exact case you trace a new cel from neighbours). Each render arm already guards its own empty case, so the skip was redundant. - Ghost texture resolution now falls through cache → resident raw_pixels (upload) → in-memory proxy → request fault-in, so neighbours that were paged out (e.g. after a seek, or saved-this-session with no decoded proxy) page in and ghost in, instead of silently rendering nothing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4dc937f9c0
commit
78109cda93
|
|
@ -1250,12 +1250,6 @@ impl egui_wgpu::CallbackTrait for VelloCallback {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if !rendered_layer.has_content && gpu_canvas_kf.is_none() && raster_cache_kf.is_none()
|
|
||||||
&& raster_proxy_blit.is_none()
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
match &rendered_layer.layer_type {
|
match &rendered_layer.layer_type {
|
||||||
RenderedLayerType::Vector => {
|
RenderedLayerType::Vector => {
|
||||||
// Vector/group layer — render Vello scene → sRGB → linear → composite.
|
// Vector/group layer — render Vello scene → sRGB → linear → composite.
|
||||||
|
|
@ -1343,34 +1337,58 @@ impl egui_wgpu::CallbackTrait for VelloCallback {
|
||||||
&instance_resources.hdr_texture_view,
|
&instance_resources.hdr_texture_view,
|
||||||
) {
|
) {
|
||||||
let mut drew = false;
|
let mut drew = false;
|
||||||
|
let mut need_fault = false;
|
||||||
if let Ok(mut gpu_brush) = shared.gpu_brush.lock() {
|
if let Ok(mut gpu_brush) = shared.gpu_brush.lock() {
|
||||||
let has_full = gpu_brush.raster_layer_cache.contains_key(&kf_id);
|
// Resolve a texture, in priority order:
|
||||||
if !has_full {
|
// 1) cached full texture
|
||||||
// Upload the proxy on demand from the keyframe's pixels.
|
// 2) resident raw_pixels → upload full (e.g. an
|
||||||
if let Some(lightningbeam_core::layer::AnyLayer::Raster(rl)) =
|
// unsaved neighbour whose GPU texture evicted)
|
||||||
self.ctx.document.get_layer(&rendered_layer.layer_id)
|
// 3) in-memory proxy → upload proxy
|
||||||
{
|
// 4) none → request a fault-in (seek to a paged-out frame)
|
||||||
if let Some(p) = rl.keyframes.iter().find(|k| k.id == kf_id)
|
let resolved: Option<(u32, u32, bool)> =
|
||||||
.and_then(|k| k.proxy.as_ref())
|
if gpu_brush.raster_layer_cache.contains_key(&kf_id) {
|
||||||
{
|
gpu_brush.raster_layer_cache.get(&kf_id).map(|c| (c.width, c.height, false))
|
||||||
gpu_brush.ensure_proxy_texture(device, queue, kf_id, &p.pixels, p.width, p.height);
|
} else {
|
||||||
|
let kf = match self.ctx.document.get_layer(&rendered_layer.layer_id) {
|
||||||
|
Some(lightningbeam_core::layer::AnyLayer::Raster(rl)) =>
|
||||||
|
rl.keyframes.iter().find(|k| k.id == kf_id),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
match kf {
|
||||||
|
Some(kf) if kf.raw_pixels.len() == (kf.width * kf.height * 4) as usize => {
|
||||||
|
gpu_brush.ensure_layer_texture(device, queue, kf_id, &kf.raw_pixels, kf.width, kf.height, false);
|
||||||
|
Some((kf.width, kf.height, false))
|
||||||
|
}
|
||||||
|
Some(kf) if kf.proxy.is_some() => {
|
||||||
|
let p = kf.proxy.as_ref().unwrap();
|
||||||
|
gpu_brush.ensure_proxy_texture(device, queue, kf_id, &p.pixels, p.width, p.height);
|
||||||
|
Some((lw, lh, true))
|
||||||
|
}
|
||||||
|
Some(kf) if kf.needs_fault_in => { need_fault = true; None }
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if let Some((sw, sh, is_proxy)) = resolved {
|
||||||
|
let tex = if is_proxy {
|
||||||
|
gpu_brush.get_proxy_texture(&kf_id)
|
||||||
|
} else {
|
||||||
|
gpu_brush.raster_layer_cache.get(&kf_id)
|
||||||
|
};
|
||||||
|
if let Some(canvas) = tex {
|
||||||
|
let bt = crate::gpu_brush::BlitTransform::new(*layer_transform, sw, sh, width, height)
|
||||||
|
.with_tint(tint[0], tint[1], tint[2]);
|
||||||
|
if is_proxy {
|
||||||
|
shared.canvas_blit.blit_smooth(device, queue, canvas.src_view(), gv, &bt, None);
|
||||||
|
} else {
|
||||||
|
shared.canvas_blit.blit(device, queue, canvas.src_view(), gv, &bt, None);
|
||||||
|
}
|
||||||
|
drew = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let src = if has_full {
|
}
|
||||||
gpu_brush.raster_layer_cache.get(&kf_id).map(|c| (c, c.width, c.height, false))
|
if need_fault {
|
||||||
} else {
|
if let Ok(mut reqs) = self.ctx.raster_fault_requests.lock() {
|
||||||
gpu_brush.get_proxy_texture(&kf_id).map(|c| (c, lw, lh, true))
|
reqs.insert(kf_id);
|
||||||
};
|
|
||||||
if let Some((canvas, sw, sh, is_proxy)) = src {
|
|
||||||
let bt = crate::gpu_brush::BlitTransform::new(*layer_transform, sw, sh, width, height)
|
|
||||||
.with_tint(tint[0], tint[1], tint[2]);
|
|
||||||
if is_proxy {
|
|
||||||
shared.canvas_blit.blit_smooth(device, queue, canvas.src_view(), gv, &bt, None);
|
|
||||||
} else {
|
|
||||||
shared.canvas_blit.blit(device, queue, canvas.src_view(), gv, &bt, None);
|
|
||||||
}
|
|
||||||
drew = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if drew {
|
if drew {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue