1
0
Fork 0
forked from wry/wry

Retain surface textures for animations

This commit is contained in:
atagen 2026-05-21 15:45:32 +10:00
parent 3540cdc4be
commit fba9d65ba1
8 changed files with 365 additions and 19 deletions

View file

@ -1,7 +1,8 @@
use {
crate::{
animation::{RetainedContent, RetainedSurface, RetainedToplevel},
cmm::cmm_render_intent::RenderIntent,
gfx_api::{AcquireSync, AlphaMode, GfxApiOpt, ReleaseSync, SampleRect},
gfx_api::{AcquireSync, AlphaMode, BufferResv, GfxApiOpt, ReleaseSync, SampleRect},
ifs::wl_surface::{
SurfaceBuffer, WlSurface,
x_surface::xwindow::Xwindow,
@ -467,6 +468,167 @@ impl Renderer<'_> {
visual.move_(-container.abs_x1.get(), -container.abs_y1.get())
}
fn render_child_or_snapshot(
&mut self,
child: &Rc<dyn ToplevelNode>,
x: i32,
y: i32,
bounds: Option<&Rect>,
) {
if let Some(retained) = self
.state
.animations
.retained_snapshot(child.node_id(), self.state.now_nsec())
{
self.render_retained_toplevel(&retained, x, y, bounds);
} else {
child.node_render(self, x, y, bounds);
}
}
fn render_retained_toplevel(
&mut self,
retained: &RetainedToplevel,
x: i32,
y: i32,
bounds: Option<&Rect>,
) {
let (x, y) = self
.base
.scale_point(x + retained.offset.0, y + retained.offset.1);
self.render_retained_surface_scaled(&retained.surface, x, y, None, bounds);
}
fn render_retained_surface_scaled(
&mut self,
retained: &RetainedSurface,
x: i32,
y: i32,
pos_rel: Option<(i32, i32)>,
bounds: Option<&Rect>,
) {
let stretch = self.stretch.take();
let corner_radius = self.corner_radius.take();
let mut size = retained.size;
if let Some((x_rel, y_rel)) = pos_rel {
let (x, y) = self.base.scale_point(x_rel, y_rel);
let (w, h) = self.base.scale_point(x_rel + size.0, y_rel + size.1);
size = (w - x, h - y);
} else {
size = self.base.scale_point(size.0, size.1);
}
let mut stretched_source = None;
if let Some(s) = stretch {
if let RetainedContent::Texture { source, .. } = &retained.content {
let mut source = *source;
if size.0 > 0 && size.1 > 0 {
let sx = s.0 as f32 / size.0 as f32;
let sy = s.1 as f32 / size.1 as f32;
source.x2 *= sx;
source.y2 *= sy;
}
stretched_source = Some(source);
}
size = s;
}
for child in &retained.below {
let (x1, y1) = self.base.scale_point(child.offset.0, child.offset.1);
self.render_retained_surface_scaled(child, x + x1, y + y1, Some(child.offset), bounds);
}
self.corner_radius = corner_radius;
self.render_retained_content(retained, stretched_source, x, y, size, bounds);
for child in &retained.above {
let (x1, y1) = self.base.scale_point(child.offset.0, child.offset.1);
self.render_retained_surface_scaled(child, x + x1, y + y1, Some(child.offset), bounds);
}
}
fn render_retained_content(
&mut self,
retained: &RetainedSurface,
stretched_source: Option<SampleRect>,
x: i32,
y: i32,
size: (i32, i32),
bounds: Option<&Rect>,
) {
let corner_radius = self.corner_radius.take();
match &retained.content {
RetainedContent::Texture {
texture,
buffer,
source,
alpha,
color_description,
render_intent,
alpha_mode,
opaque,
} => {
let source = stretched_source.unwrap_or(*source);
if let Some(cr) = corner_radius {
self.base.render_rounded_texture(
texture,
*alpha,
x,
y,
Some(source),
Some(size),
self.base.scale,
bounds,
Some(buffer.clone() as Rc<dyn BufferResv>),
AcquireSync::Unnecessary,
buffer.release_sync,
color_description,
*render_intent,
*alpha_mode,
cr,
);
} else {
self.base.render_texture(
texture,
*alpha,
x,
y,
Some(source),
Some(size),
self.base.scale,
bounds,
Some(buffer.clone() as Rc<dyn BufferResv>),
AcquireSync::Unnecessary,
buffer.release_sync,
*opaque,
color_description,
*render_intent,
*alpha_mode,
);
}
}
RetainedContent::Color {
color,
alpha,
color_description,
render_intent,
} => {
if let Some(rect) = Rect::new_sized(x, y, size.0, size.1) {
let rect = match bounds {
None => rect,
Some(bounds) => rect.intersect(*bounds),
};
if !rect.is_empty() {
self.base.sync();
self.base.fill_scaled_boxes(
&[rect],
color,
*alpha,
&color_description.linear,
*render_intent,
);
}
}
}
}
}
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
self.render_container_decorations(container, x, y);
@ -526,9 +688,12 @@ impl Renderer<'_> {
self.corner_radius = Some(inner_cr);
}
}
child
.node
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
self.render_child_or_snapshot(
&child.node,
x + content.x1(),
y + content.y1(),
Some(&body),
);
self.stretch = None;
self.corner_radius = None;
} else {
@ -579,9 +744,12 @@ impl Renderer<'_> {
}
let body = body.move_(x, y);
let body = self.base.scale_rect(body);
child
.node
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
self.render_child_or_snapshot(
&child.node,
x + content.x1(),
y + content.y1(),
Some(&body),
);
self.stretch = None;
self.corner_radius = None;
}