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
+72 -39
+72 -39
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,48 +712,82 @@ 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 flipped in [false, true] { for straight in [false, true] {
let source = renderer let program = compile_stream_program(&mut renderer, straight).unwrap();
.import_memory(&pixels, Fourcc::Abgr8888, (3, 2).into(), flipped) let mut reference = pixels.clone();
.unwrap(); if straight {
for (transform, expected) in cases { convert_window_pixels(&mut reference);
let size = for pixel in reference.chunks_exact_mut(4) {
transform.transform_size(Size::<i32, smithay::utils::Buffer>::from((3, 2))); pixel.swap(0, 2); // CPU conversion returns BGRA; read back RGBA.
let mut target = }
Offscreen::<GlesTexture>::create_buffer(&mut renderer, Fourcc::Abgr8888, size) }
.unwrap(); for pixel in reference.chunks_exact_mut(4) {
{ pixel[3] = 255;
let mut target = renderer.bind(&mut target).unwrap(); }
let _ = draw_stream_texture( for flipped in [false, true] {
let source = renderer
.import_memory(&pixels, Fourcc::Abgr8888, (3, 2).into(), flipped)
.unwrap();
for (transform, order) in cases {
let size =
transform.transform_size(Size::<i32, smithay::utils::Buffer>::from((3, 2)));
let mut target = Offscreen::<GlesTexture>::create_buffer(
&mut renderer, &mut renderer,
&source, Fourcc::Abgr8888,
&mut target, size,
transform,
&program,
) )
.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 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(
&mut renderer,
&source,
&mut target,
transform,
&program,
)
.unwrap();
}
let mapping = renderer
.copy_texture(&target, Rectangle::from_size(size), Fourcc::Abgr8888)
.unwrap();
let actual = renderer.map_texture(&mapping).unwrap();
// Reverse source rows before applying the output transform
// when the texture reports inverted storage.
let expected: Vec<_> = order
.bytes()
.flat_map(|value| {
let index = usize::from(value - b'a');
let index = if flipped { (index + 3) % 6 } else { index };
reference[index * 4..index * 4 + 4].iter().copied()
})
.collect();
assert_eq!(
actual, expected,
"{transform:?}, texture flipped={flipped}, straight={straight}, destination alpha={alpha}"
);
}
} }
let mapping = renderer
.copy_texture(&target, Rectangle::from_size(size), Fourcc::Abgr8888)
.unwrap();
let actual = renderer.map_texture(&mapping).unwrap();
let actual: Vec<_> = actual.chunks_exact(4).map(|pixel| pixel[0]).collect();
// A flipped texture describes the same image with reversed source
// rows. Derive that reference before applying the output transform.
let expected = if flipped {
expected
.bytes()
.map(|value| if value < b'd' { value + 3 } else { value - 3 })
.collect::<Vec<_>>()
} else {
expected.as_bytes().to_vec()
};
assert_eq!(actual, expected, "{transform:?}, texture flipped={flipped}");
} }
} }
} }