use smithay::backend::allocator::Fourcc; use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage}; use smithay::backend::renderer::gles::GlesTexture; use smithay::backend::renderer::utils::{CommitCounter, OpaqueRegions}; use smithay::backend::renderer::{ContextId, Frame as _, ImportMem, Renderer, Texture}; use smithay::utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Size, Transform}; use super::memory::MemoryBuffer; /// Smithay's texture buffer, but with fractional scale. #[derive(Debug, Clone)] pub struct TextureBuffer { id: Id, commit_counter: CommitCounter, renderer_context_id: ContextId, texture: T, scale: Scale, transform: Transform, opaque_regions: Vec>, } /// Render element for a [`TextureBuffer`]. #[derive(Debug, Clone)] pub struct TextureRenderElement { buffer: TextureBuffer, location: Point, alpha: f32, src: Option>, size: Option>, kind: Kind, } impl TextureBuffer { pub fn from_texture>( renderer: &R, texture: T, scale: impl Into>, transform: Transform, opaque_regions: Vec>, ) -> Self { TextureBuffer { id: Id::new(), commit_counter: CommitCounter::default(), renderer_context_id: renderer.context_id(), texture, scale: scale.into(), transform, opaque_regions, } } #[allow(clippy::too_many_arguments)] pub fn from_memory + ImportMem>( renderer: &mut R, data: &[u8], format: Fourcc, size: impl Into>, flipped: bool, scale: impl Into>, transform: Transform, opaque_regions: Vec>, ) -> Result { let texture = renderer.import_memory(data, format, size.into(), flipped)?; Ok(TextureBuffer::from_texture( renderer, texture, scale, transform, opaque_regions, )) } pub fn from_memory_buffer + ImportMem>( renderer: &mut R, buffer: &MemoryBuffer, ) -> Result { Self::from_memory( renderer, buffer.data(), buffer.format(), buffer.size(), false, buffer.scale(), buffer.transform(), Vec::new(), ) } pub fn texture(&self) -> &T { &self.texture } pub fn texture_scale(&self) -> Scale { self.scale } pub fn set_texture_scale(&mut self, scale: impl Into>) { self.scale = scale.into(); } pub fn texture_transform(&self) -> Transform { self.transform } pub fn set_texture_transform(&mut self, transform: Transform) { self.transform = transform; } } impl TextureBuffer { pub fn logical_size(&self) -> Size { self.texture .size() .to_f64() .to_logical(self.scale, self.transform) } } impl TextureBuffer { pub fn is_texture_reference_unique(&mut self) -> bool { self.texture.is_unique_reference() } } impl TextureRenderElement { pub fn from_texture_buffer( buffer: TextureBuffer, location: impl Into>, alpha: f32, src: Option>, size: Option>, kind: Kind, ) -> Self { TextureRenderElement { buffer, location: location.into(), alpha, src, size, kind, } } pub fn buffer(&self) -> &TextureBuffer { &self.buffer } } impl TextureRenderElement { pub fn logical_size(&self) -> Size { self.size .or_else(|| self.src.map(|src| src.size)) .unwrap_or_else(|| self.buffer.logical_size()) } pub fn logical_src(&self) -> Rectangle { self.src .unwrap_or_else(|| Rectangle::from_size(self.logical_size())) } } impl Element for TextureRenderElement { fn id(&self) -> &Id { &self.buffer.id } fn current_commit(&self) -> CommitCounter { self.buffer.commit_counter } fn geometry(&self, scale: Scale) -> Rectangle { let logical_geo = Rectangle::new(self.location, self.logical_size()); logical_geo.to_physical_precise_round(scale) } fn transform(&self) -> Transform { self.buffer.transform } fn src(&self) -> Rectangle { self.src .map(|src| { src.to_buffer( self.buffer.scale, self.buffer.transform, &self.buffer.logical_size(), ) }) .unwrap_or_else(|| Rectangle::from_size(self.buffer.texture.size()).to_f64()) } fn opaque_regions(&self, scale: Scale) -> OpaqueRegions { 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 = 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 RenderElement for TextureRenderElement where R: Renderer, T: Texture, { fn draw( &self, frame: &mut R::Frame<'_, '_>, src: Rectangle, dest: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], ) -> Result<(), R::Error> { if frame.context_id() != self.buffer.renderer_context_id { warn!("trying to render texture from different renderer"); return Ok(()); } frame.render_texture_from_to( &self.buffer.texture, src, dest, damage, opaque_regions, self.buffer.transform, self.alpha, ) } fn underlying_storage(&self, _renderer: &mut R) -> Option> { None } }