diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-06-01 12:27:30 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-06-10 18:08:00 +0300 |
| commit | 3c63be6261f3420008366b41b3df6d57b3ec3867 (patch) | |
| tree | c937af80e68e25d6a0d18aeae9338a4a161d83ab /src/render_helpers/texture.rs | |
| parent | e3406ac2556c7f68cd00f11b5856222dcce7f680 (diff) | |
| download | niri-3c63be6261f3420008366b41b3df6d57b3ec3867.tar.gz niri-3c63be6261f3420008366b41b3df6d57b3ec3867.tar.bz2 niri-3c63be6261f3420008366b41b3df6d57b3ec3867.zip | |
Implement our own TextureBuffer/RenderElement
Supports fractional texture scale + has some getters.
Diffstat (limited to 'src/render_helpers/texture.rs')
| -rw-r--r-- | src/render_helpers/texture.rs | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/render_helpers/texture.rs b/src/render_helpers/texture.rs new file mode 100644 index 00000000..c1eec367 --- /dev/null +++ b/src/render_helpers/texture.rs @@ -0,0 +1,207 @@ +use smithay::backend::allocator::Fourcc; +use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage}; +use smithay::backend::renderer::utils::{CommitCounter, OpaqueRegions}; +use smithay::backend::renderer::{Frame as _, ImportMem, Renderer, Texture}; +use smithay::utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Size, Transform}; + +/// Smithay's texture buffer, but with fractional scale. +#[derive(Debug, Clone)] +pub struct TextureBuffer<T> { + id: Id, + commit_counter: CommitCounter, + renderer_id: usize, + texture: T, + scale: Scale<f64>, + transform: Transform, + opaque_regions: Vec<Rectangle<i32, Buffer>>, +} + +/// Render element for a [`TextureBuffer`]. +#[derive(Debug)] +pub struct TextureRenderElement<T> { + buffer: TextureBuffer<T>, + location: Point<f64, Logical>, + alpha: f32, + src: Option<Rectangle<f64, Logical>>, + size: Option<Size<f64, Logical>>, + kind: Kind, +} + +impl<T> TextureBuffer<T> { + pub fn from_texture<R: Renderer<TextureId = T>>( + renderer: &R, + texture: T, + scale: impl Into<Scale<f64>>, + transform: Transform, + opaque_regions: Vec<Rectangle<i32, Buffer>>, + ) -> Self { + TextureBuffer { + id: Id::new(), + commit_counter: CommitCounter::default(), + renderer_id: renderer.id(), + texture, + scale: scale.into(), + transform, + opaque_regions, + } + } + + #[allow(clippy::too_many_arguments)] + pub fn from_memory<R: Renderer<TextureId = T> + ImportMem>( + renderer: &mut R, + data: &[u8], + format: Fourcc, + size: impl Into<Size<i32, Buffer>>, + flipped: bool, + scale: impl Into<Scale<f64>>, + transform: Transform, + opaque_regions: Vec<Rectangle<i32, Buffer>>, + ) -> Result<Self, <R as Renderer>::Error> { + let texture = renderer.import_memory(data, format, size.into(), flipped)?; + Ok(TextureBuffer::from_texture( + renderer, + texture, + scale, + transform, + opaque_regions, + )) + } + + pub fn texture(&self) -> &T { + &self.texture + } + + pub fn texture_scale(&self) -> Scale<f64> { + self.scale + } +} + +impl<T: Texture> TextureBuffer<T> { + pub fn logical_size(&self) -> Size<f64, Logical> { + self.texture + .size() + .to_f64() + .to_logical(self.scale, self.transform) + } +} + +impl<T> TextureRenderElement<T> { + pub fn from_texture_buffer( + buffer: TextureBuffer<T>, + location: impl Into<Point<f64, Logical>>, + alpha: f32, + src: Option<Rectangle<f64, Logical>>, + size: Option<Size<f64, Logical>>, + kind: Kind, + ) -> Self { + TextureRenderElement { + buffer, + location: location.into(), + alpha, + src, + size, + kind, + } + } +} + +impl<T: Texture> TextureRenderElement<T> { + pub fn logical_size(&self) -> Size<f64, Logical> { + self.size + .or_else(|| self.src.map(|src| src.size)) + .unwrap_or_else(|| self.buffer.logical_size()) + } +} + +impl<T: Texture> Element for TextureRenderElement<T> { + fn id(&self) -> &Id { + &self.buffer.id + } + + fn current_commit(&self) -> CommitCounter { + self.buffer.commit_counter + } + + fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> { + let logical_geo = Rectangle::from_loc_and_size(self.location, self.logical_size()); + logical_geo.to_physical_precise_round(scale) + } + + fn transform(&self) -> Transform { + self.buffer.transform + } + + fn src(&self) -> Rectangle<f64, Buffer> { + self.src + .map(|src| { + src.to_buffer( + self.buffer.scale, + self.buffer.transform, + &self.buffer.logical_size(), + ) + }) + .unwrap_or_else(|| { + Rectangle::from_loc_and_size((0, 0), self.buffer.texture.size()).to_f64() + }) + } + + fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> { + let texture_size = self.buffer.texture.size().to_f64(); + let src = self.src(); + + self.buffer + .opaque_regions + .iter() + .filter_map(|region| { + let mut region = region.to_f64().intersection(src)?; + + region.loc -= src.loc; + region.upscale(texture_size / src.size); + + let logical = + region.to_logical(self.buffer.scale, self.buffer.transform, &src.size); + Some(logical.to_physical_precise_down(scale)) + }) + .collect() + } + + fn alpha(&self) -> f32 { + self.alpha + } + + fn kind(&self) -> Kind { + self.kind + } +} + +impl<R, T> RenderElement<R> for TextureRenderElement<T> +where + R: Renderer<TextureId = T>, + T: Texture, +{ + fn draw( + &self, + frame: &mut <R as Renderer>::Frame<'_>, + src: Rectangle<f64, Buffer>, + dest: Rectangle<i32, Physical>, + damage: &[Rectangle<i32, Physical>], + ) -> Result<(), <R as Renderer>::Error> { + if frame.id() != self.buffer.renderer_id { + warn!("trying to render texture from different renderer"); + return Ok(()); + } + + frame.render_texture_from_to( + &self.buffer.texture, + src, + dest, + damage, + self.buffer.transform, + self.alpha, + ) + } + + fn underlying_storage(&self, _renderer: &mut R) -> Option<UnderlyingStorage<'_>> { + None + } +} |
