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:
1 parent
ad00e55fe4
commit
b66b19e4d9
1 file changed
+72
-39
@@ -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}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user