//! Element to render a solid color //! //! # How to use it //! //! ```no_run //! # use smithay::{ //! # backend::{ //! # allocator::Fourcc, //! # renderer::{Color32F, DebugFlags, Frame, ImportMem, Renderer, Texture, TextureFilter, sync::SyncPoint, test::{DummyRenderer, DummyFramebuffer}}, //! # }, //! # utils::{Buffer, Physical, Rectangle, Transform}, //! # }; //! use smithay::{ //! backend::renderer::{ //! damage::OutputDamageTracker, //! element::{ //! Kind, //! solid::{SolidColorBuffer, SolidColorRenderElement}, //! }, //! }, //! utils::{Point, Size}, //! }; //! //! const WIDTH: i32 = 10; //! const HEIGHT: i32 = 10; //! const COLOR: [f32; 4] = [1f32, 0.9f32, 0.78f32, 1f32]; //! //! // Initialize the solid color buffer //! let buffer = SolidColorBuffer::new((WIDTH, HEIGHT), COLOR); //! //! // Initialize a static damage tracked renderer //! let mut damage_tracker = OutputDamageTracker::new((800, 600), 1.0, Transform::Normal); //! # let mut renderer = DummyRenderer::default(); //! # let mut framebuffer = DummyFramebuffer; //! //! loop { //! // Create a render element from the buffer //! let location = Point::from((100, 100)); //! let render_element = SolidColorRenderElement::from_buffer(&buffer, location, 1f64, 1.0, Kind::Unspecified); //! //! // Render the element(s) //! damage_tracker //! .render_output(&mut renderer, &mut framebuffer, 0, &[&render_element], [0.8, 0.8, 0.9, 1.0]) //! .expect("failed to render output"); //! } //! ``` use crate::{ backend::renderer::{ utils::{CommitCounter, OpaqueRegions}, Color32F, Frame, Renderer, }, utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Size, Transform}, }; use super::{AsRenderElements, Element, Id, Kind, RenderElement}; /// A single color buffer #[derive(Debug, Clone)] pub struct SolidColorBuffer { id: Id, size: Size, commit: CommitCounter, color: Color32F, } impl Default for SolidColorBuffer { fn default() -> Self { Self { id: Id::new(), size: Default::default(), commit: Default::default(), color: Default::default(), } } } impl SolidColorBuffer { /// Initialize a new solid color buffer with the specified size and color pub fn new(size: impl Into>, color: impl Into) -> Self { SolidColorBuffer { id: Id::new(), color: color.into(), commit: CommitCounter::default(), size: size.into(), } } /// Set the new size of this solid color buffer /// /// Note: If the size matches the current size this will do nothing pub fn resize(&mut self, size: impl Into>) { let size = size.into(); if size != self.size { self.size = size; self.commit.increment(); } } /// Set a new color on this solid color buffer /// /// Note: If the color matches the current color this will do nothing pub fn set_color(&mut self, color: impl Into) { let color = color.into(); if color != self.color { self.color = color; self.commit.increment(); } } /// Update the size and color of this solid color buffer /// /// Note: If the size and color match the current size and color this will do nothing pub fn update(&mut self, size: impl Into>, color: impl Into) { let color = color.into(); let size = size.into(); if size != self.size || color != self.color { self.size = size; self.color = color; self.commit.increment(); } } /// Get the current color of this buffer pub fn color(&self) -> Color32F { self.color } } /// [`Element`] to render a solid color #[derive(Debug, Clone)] pub struct SolidColorRenderElement { id: Id, geometry: Rectangle, src: Rectangle, opaque_regions: Vec>, commit: CommitCounter, color: Color32F, kind: Kind, } impl SolidColorRenderElement { /// Create a render element from a [`SolidColorBuffer`] pub fn from_buffer( buffer: &SolidColorBuffer, location: impl Into>, scale: impl Into>, alpha: f32, kind: Kind, ) -> Self { let geo = Rectangle::new(location.into(), buffer.size.to_physical_precise_round(scale)); let color = buffer.color * alpha; Self::new(buffer.id.clone(), geo, buffer.commit, color, kind) } /// Create a new solid color render element with the specified geometry and color pub fn new( id: impl Into, geometry: Rectangle, commit: impl Into, color: impl Into, kind: Kind, ) -> Self { let color = color.into(); let src = Rectangle::from_size(geometry.size) .to_f64() .to_logical(1f64) .to_buffer(1f64, Transform::Normal, &geometry.size.to_f64().to_logical(1f64)); let opaque_regions = if color.is_opaque() { vec![Rectangle::from_size(geometry.size)] } else { vec![] }; SolidColorRenderElement { id: id.into(), geometry, src, opaque_regions, commit: commit.into(), color, kind, } } /// Get the current color of this element pub fn color(&self) -> Color32F { self.color } } impl Element for SolidColorRenderElement { fn id(&self) -> &Id { &self.id } fn current_commit(&self) -> CommitCounter { self.commit } fn src(&self) -> Rectangle { self.src } fn geometry(&self, _scale: Scale) -> Rectangle { self.geometry } fn opaque_regions(&self, _scale: Scale) -> OpaqueRegions { OpaqueRegions::from_slice(&self.opaque_regions) } fn alpha(&self) -> f32 { self.color.a() } fn kind(&self) -> Kind { self.kind } } impl RenderElement for SolidColorRenderElement { #[profiling::function] fn draw( &self, frame: &mut R::Frame<'_, '_>, _src: Rectangle, dst: Rectangle, damage: &[Rectangle], _opaque_regions: &[Rectangle], ) -> Result<(), R::Error> { frame.draw_solid(dst, damage, self.color) } #[inline] fn underlying_storage(&self, _renderer: &mut R) -> Option> { None } } impl AsRenderElements for SolidColorBuffer where R: Renderer, { type RenderElement = SolidColorRenderElement; fn render_elements>( &self, _renderer: &mut R, location: crate::utils::Point, scale: crate::utils::Scale, alpha: f32, ) -> Vec { vec![SolidColorRenderElement::from_buffer(self, location, scale, alpha, Kind::Unspecified).into()] } }