Skip redundant stream capture clear (#65)

Remove the full-buffer clear before opaque stream transfers and disable blending for the destination region. Cover both shader modes, all transforms, and reused targets.

Fixes #61.
This commit is contained in:
Samuel Onoja authored and GitHub committed 2026-10-25 14:30:30 +01:00
1 parent ad00e55fe4
commit b66b19e4d9
1 file changed
+53 -20
+53 -20
View File
@@ -582,16 +582,15 @@ fn draw_stream_texture(
.render(target, size, Transform::Normal) .render(target, size, Transform::Normal)
.map_err(|error| error.to_string())?; .map_err(|error| error.to_string())?;
let rect = Rectangle::from_size(size); let rect = Rectangle::from_size(size);
frame // Both stream shaders write alpha 1 over the full target. No clear is
.clear(Color32F::new(0., 0., 0., 1.), &[rect]) // needed; marking the entire destination opaque also disables blending.
.map_err(|error| error.to_string())?;
frame frame
.render_texture_from_to( .render_texture_from_to(
texture, texture,
Rectangle::from_size(source_size).to_f64(), Rectangle::from_size(source_size).to_f64(),
rect, rect,
&[rect], &[rect],
&[], &[rect],
transform, transform,
1.0, 1.0,
Some(program), Some(program),
@@ -713,23 +712,53 @@ mod stream_gpu_tests {
(Flipped180, "defabc"), (Flipped180, "defabc"),
(Flipped270, "fcebda"), (Flipped270, "fcebda"),
]; ];
let program = compile_stream_program(&mut renderer, false).unwrap(); // Include transparent and translucent source pixels: the transfer must
// replace every destination channel regardless of the source alpha.
let pixels: Vec<_> = b"abcdef" let pixels: Vec<_> = b"abcdef"
.iter() .iter()
.flat_map(|value| [*value, 0, 0, 255]) .zip([0, 1, 64, 128, 254, 255])
.flat_map(|(value, alpha)| [*value, value / 2, value / 3, alpha])
.collect(); .collect();
for straight in [false, true] {
let program = compile_stream_program(&mut renderer, straight).unwrap();
let mut reference = pixels.clone();
if straight {
convert_window_pixels(&mut reference);
for pixel in reference.chunks_exact_mut(4) {
pixel.swap(0, 2); // CPU conversion returns BGRA; read back RGBA.
}
}
for pixel in reference.chunks_exact_mut(4) {
pixel[3] = 255;
}
for flipped in [false, true] { for flipped in [false, true] {
let source = renderer let source = renderer
.import_memory(&pixels, Fourcc::Abgr8888, (3, 2).into(), flipped) .import_memory(&pixels, Fourcc::Abgr8888, (3, 2).into(), flipped)
.unwrap(); .unwrap();
for (transform, expected) in cases { for (transform, order) in cases {
let size = let size =
transform.transform_size(Size::<i32, smithay::utils::Buffer>::from((3, 2))); transform.transform_size(Size::<i32, smithay::utils::Buffer>::from((3, 2)));
let mut target = let mut target = Offscreen::<GlesTexture>::create_buffer(
Offscreen::<GlesTexture>::create_buffer(&mut renderer, Fourcc::Abgr8888, size) &mut renderer,
Fourcc::Abgr8888,
size,
)
.unwrap(); .unwrap();
// Exercise reused targets containing unrelated pixels with
// both transparent and opaque destination alpha.
for alpha in [0.0, 1.0] {
{ {
let mut target = renderer.bind(&mut target).unwrap(); let mut target = renderer.bind(&mut target).unwrap();
let mut frame = renderer
.render(&mut target, (size.w, size.h).into(), Transform::Normal)
.unwrap();
frame
.clear(
Color32F::new(1.0, 0.0, 1.0, alpha),
&[Rectangle::from_size((size.w, size.h).into())],
)
.unwrap();
let _ = frame.finish().unwrap();
let _ = draw_stream_texture( let _ = draw_stream_texture(
&mut renderer, &mut renderer,
&source, &source,
@@ -743,18 +772,22 @@ mod stream_gpu_tests {
.copy_texture(&target, Rectangle::from_size(size), Fourcc::Abgr8888) .copy_texture(&target, Rectangle::from_size(size), Fourcc::Abgr8888)
.unwrap(); .unwrap();
let actual = renderer.map_texture(&mapping).unwrap(); let actual = renderer.map_texture(&mapping).unwrap();
let actual: Vec<_> = actual.chunks_exact(4).map(|pixel| pixel[0]).collect(); // Reverse source rows before applying the output transform
// A flipped texture describes the same image with reversed source // when the texture reports inverted storage.
// rows. Derive that reference before applying the output transform. let expected: Vec<_> = order
let expected = if flipped {
expected
.bytes() .bytes()
.map(|value| if value < b'd' { value + 3 } else { value - 3 }) .flat_map(|value| {
.collect::<Vec<_>>() let index = usize::from(value - b'a');
} else { let index = if flipped { (index + 3) % 6 } else { index };
expected.as_bytes().to_vec() reference[index * 4..index * 4 + 4].iter().copied()
}; })
assert_eq!(actual, expected, "{transform:?}, texture flipped={flipped}"); .collect();
assert_eq!(
actual, expected,
"{transform:?}, texture flipped={flipped}, straight={straight}, destination alpha={alpha}"
);
}
}
} }
} }
} }