smithay/backend/renderer/
mod.rs

1//! Rendering functionality and abstractions
2//!
3//! Collection of common traits and implementations
4//! to facilitate (possible hardware-accelerated) rendering.
5//!
6//! Supported rendering apis:
7//!
8//! - Raw OpenGL ES 2
9
10use crate::utils::{ids::id_gen, Buffer as BufferCoord, Physical, Point, Rectangle, Scale, Size, Transform};
11use cgmath::Matrix3;
12use std::{
13    any::TypeId,
14    cmp::Ordering,
15    error::Error,
16    fmt,
17    hash::{Hash, Hasher},
18    marker::PhantomData,
19    sync::Arc,
20};
21
22#[cfg(feature = "wayland_frontend")]
23use crate::wayland::{compositor::SurfaceData, shm::fourcc_to_shm_format};
24#[cfg(feature = "wayland_frontend")]
25use wayland_server::protocol::{wl_buffer, wl_shm};
26
27#[cfg(feature = "renderer_gl")]
28pub mod gles;
29
30#[cfg(feature = "renderer_glow")]
31pub mod glow;
32
33#[cfg(feature = "renderer_pixman")]
34pub mod pixman;
35
36mod color;
37pub use color::Color32F;
38
39use crate::backend::allocator::{dmabuf::Dmabuf, Format, Fourcc};
40#[cfg(all(
41    feature = "wayland_frontend",
42    feature = "backend_egl",
43    feature = "use_system_lib"
44))]
45use crate::backend::egl::{
46    display::{EGLBufferReader, BUFFER_READER},
47    Error as EglError,
48};
49
50use super::allocator::format::FormatSet;
51
52#[cfg(feature = "renderer_multi")]
53pub mod multigpu;
54
55pub mod utils;
56
57pub mod element;
58
59pub mod damage;
60
61pub mod sync;
62
63// Note: This doesn't fully work yet due to <https://github.com/rust-lang/rust/issues/67295>.
64// Use `--features renderer_test` when running doc tests manually.
65#[cfg(any(feature = "renderer_test", test, doctest))]
66pub mod test;
67
68/// Identifies a renderer context for a specific texture type.
69///
70/// Renderers with the same `ContextId` are assumed to be texture-compatible,
71/// meaning textures created by one can be imported into another.
72pub struct ContextId<T: Texture>(Arc<InnerContextId>, PhantomData<fn() -> T>);
73
74/// A type-erased [`ContextId`] without the `Texture` generic.
75///
76/// This allows representing and comparing renderer contexts across different texture types.
77#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub struct ErasedContextId(Arc<InnerContextId>, TypeId);
79
80impl<T: Texture> ContextId<T> {
81    /// Allocates a new `ContextId`.
82    pub fn new() -> Self {
83        ContextId(Arc::new(InnerContextId::new()), PhantomData)
84    }
85
86    /// Maps this `ContextId` to one with another `Texture` type.
87    ///
88    /// This is typically used by wrapper or derivative renderers that define a new `TextureId`
89    /// while reusing the underlying context for rendering.
90    pub fn map<Tex: Texture>(self) -> ContextId<Tex> {
91        ContextId(self.0, PhantomData)
92    }
93
94    /// Returns an [`ErasedContextId`] representing this context without the texture type.
95    ///
96    /// This is useful when storing or comparing contexts across different texture types.
97    pub fn erased(self) -> ErasedContextId
98    where
99        T: 'static,
100    {
101        ErasedContextId(self.0, TypeId::of::<T>())
102    }
103}
104
105impl<T: Texture> Default for ContextId<T> {
106    fn default() -> Self {
107        Self::new()
108    }
109}
110
111impl<T: Texture> fmt::Debug for ContextId<T> {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        f.debug_tuple("ContextId")
114            .field(&self.0)
115            .field(&format_args!("_"))
116            .finish()
117    }
118}
119
120impl<T: Texture> Clone for ContextId<T> {
121    fn clone(&self) -> Self {
122        ContextId(self.0.clone(), PhantomData)
123    }
124}
125
126impl<T: Texture> PartialEq for ContextId<T> {
127    fn eq(&self, other: &Self) -> bool {
128        self.0 == other.0
129    }
130}
131
132impl<T: Texture> Eq for ContextId<T> {}
133
134impl<T: Texture> PartialOrd for ContextId<T> {
135    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
136        Some(self.cmp(other))
137    }
138}
139
140impl<T: Texture> Ord for ContextId<T> {
141    fn cmp(&self, other: &Self) -> Ordering {
142        self.0.cmp(&other.0)
143    }
144}
145
146impl<T: Texture> Hash for ContextId<T> {
147    fn hash<H: Hasher>(&self, state: &mut H) {
148        self.0.hash(state);
149    }
150}
151
152id_gen!(context_id);
153
154#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
155struct InnerContextId(usize);
156
157impl InnerContextId {
158    fn new() -> Self {
159        Self(context_id::next())
160    }
161}
162
163impl Drop for InnerContextId {
164    fn drop(&mut self) {
165        context_id::remove(self.0);
166    }
167}
168
169#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
170/// Texture filtering methods
171pub enum TextureFilter {
172    /// Returns the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured.
173    Linear,
174    /// Returns the weighted average of the four texture elements that are closest to the center of the pixel being textured.
175    Nearest,
176}
177
178impl Transform {
179    /// A projection matrix to apply this transformation
180    #[inline]
181    pub fn matrix(&self) -> Matrix3<f32> {
182        match self {
183            Transform::Normal => Matrix3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
184            Transform::_90 => Matrix3::new(0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
185            Transform::_180 => Matrix3::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0),
186            Transform::_270 => Matrix3::new(0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
187            Transform::Flipped => Matrix3::new(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
188            Transform::Flipped90 => Matrix3::new(0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
189            Transform::Flipped180 => Matrix3::new(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0),
190            Transform::Flipped270 => Matrix3::new(0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
191        }
192    }
193}
194
195#[cfg(feature = "wayland_frontend")]
196impl From<wayland_server::protocol::wl_output::Transform> for Transform {
197    #[inline]
198    fn from(transform: wayland_server::protocol::wl_output::Transform) -> Transform {
199        use wayland_server::protocol::wl_output::Transform as WlTransform;
200        match transform {
201            WlTransform::Normal => Transform::Normal,
202            WlTransform::_90 => Transform::_90,
203            WlTransform::_180 => Transform::_180,
204            WlTransform::_270 => Transform::_270,
205            WlTransform::Flipped => Transform::Flipped,
206            WlTransform::Flipped90 => Transform::Flipped90,
207            WlTransform::Flipped180 => Transform::Flipped180,
208            WlTransform::Flipped270 => Transform::Flipped270,
209            _ => Transform::Normal,
210        }
211    }
212}
213
214/// Abstraction for Renderers, that can render into different targets
215pub trait Bind<Target>: Renderer {
216    /// Initialize a framebuffer with a given rendering target.
217    ///
218    /// This function *may* error, if:
219    /// - The specific given target handle is incompatible with the underlying rendering api
220    ///
221    /// **Note**: Some renderers might only be able to determine if a handle is compatible
222    ///     during a `Renderer::render` call with the resulting `Framebuffer`.
223    fn bind<'a>(&mut self, target: &'a mut Target) -> Result<Self::Framebuffer<'a>, Self::Error>;
224
225    /// Supported pixel formats for given targets, if applicable.
226    fn supported_formats(&self) -> Option<FormatSet> {
227        None
228    }
229}
230
231/// A two dimensional texture
232pub trait Texture: fmt::Debug {
233    /// Size of the texture plane
234    fn size(&self) -> Size<i32, BufferCoord> {
235        Size::from((self.width() as i32, self.height() as i32))
236    }
237
238    /// Width of the texture plane
239    fn width(&self) -> u32;
240    /// Height of the texture plane
241    fn height(&self) -> u32;
242
243    /// Format of the texture, if available.
244    ///
245    /// In case the format is hidden by the implementation,
246    /// it should be assumed, that the pixel representation cannot be read.
247    ///
248    /// Thus [`ExportMem::copy_texture`], if implemented, will not succeed for this texture.
249    /// Note that this does **not** mean every texture with a format is guaranteed to be copyable.
250    fn format(&self) -> Option<Fourcc>;
251}
252
253/// A downloaded texture buffer
254pub trait TextureMapping: Texture {
255    /// Returns if the mapped buffer is flipped on the y-axis
256    /// (compared to the lower left being (0, 0))
257    fn flipped(&self) -> bool;
258
259    /// Format of the texture
260    fn format(&self) -> Fourcc {
261        Texture::format(self).expect("Texture Mappings need to have a format")
262    }
263}
264
265/// Helper trait for [`Renderer`], which defines a rendering api for a currently in-progress frame during [`Renderer::render`].
266///
267/// Dropping the [`Frame`] or explicitly calling [`Frame::finish`] will free any unused resources. If you need explicit control
268/// over resource clean-up take a look at [`Renderer::cleanup_texture_cache`].
269pub trait Frame {
270    /// Error type returned by the rendering operations of this renderer.
271    type Error: Error;
272    /// Texture Handle type used by this renderer.
273    type TextureId: Texture;
274
275    /// Returns the [`ContextId`] of the associated renderer.
276    fn context_id(&self) -> ContextId<Self::TextureId>;
277
278    /// Clear the complete current target with a single given color.
279    ///
280    /// The `at` parameter specifies a set of rectangles to clear in the current target. This allows partially
281    /// clearing the target which may be useful for damaged rendering.
282    ///
283    /// This operation is only valid in between a `begin` and `finish`-call.
284    /// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
285    fn clear(&mut self, color: Color32F, at: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error>;
286
287    /// Draw a solid color to the current target at the specified destination with the specified color.
288    fn draw_solid(
289        &mut self,
290        dst: Rectangle<i32, Physical>,
291        damage: &[Rectangle<i32, Physical>],
292        color: Color32F,
293    ) -> Result<(), Self::Error>;
294
295    /// Render a texture to the current target as a flat 2d-plane at a given
296    /// position and applying the given transformation with the given alpha value.
297    /// (Meaning `src_transform` should match the orientation of surface being rendered).
298    #[allow(clippy::too_many_arguments)]
299    fn render_texture_at(
300        &mut self,
301        texture: &Self::TextureId,
302        pos: Point<i32, Physical>,
303        texture_scale: i32,
304        output_scale: impl Into<Scale<f64>>,
305        src_transform: Transform,
306        damage: &[Rectangle<i32, Physical>],
307        opaque_regions: &[Rectangle<i32, Physical>],
308        alpha: f32,
309    ) -> Result<(), Self::Error> {
310        self.render_texture_from_to(
311            texture,
312            Rectangle::from_size(texture.size()).to_f64(),
313            Rectangle::new(
314                pos,
315                texture
316                    .size()
317                    .to_logical(texture_scale, src_transform)
318                    .to_physical_precise_round(output_scale),
319            ),
320            damage,
321            opaque_regions,
322            src_transform,
323            alpha,
324        )
325    }
326
327    /// Render part of a texture as given by src to the current target into the rectangle described by dst
328    /// as a flat 2d-plane after applying the inverse of the given transformation.
329    /// (Meaning `src_transform` should match the orientation of surface being rendered).
330    #[allow(clippy::too_many_arguments)]
331    fn render_texture_from_to(
332        &mut self,
333        texture: &Self::TextureId,
334        src: Rectangle<f64, BufferCoord>,
335        dst: Rectangle<i32, Physical>,
336        damage: &[Rectangle<i32, Physical>],
337        opaque_regions: &[Rectangle<i32, Physical>],
338        src_transform: Transform,
339        alpha: f32,
340    ) -> Result<(), Self::Error>;
341
342    /// Output transformation that is applied to this frame
343    fn transformation(&self) -> Transform;
344
345    /// Wait for a [`SyncPoint`](sync::SyncPoint) to be signaled
346    fn wait(&mut self, sync: &sync::SyncPoint) -> Result<(), Self::Error>;
347
348    /// Finish this [`Frame`] returning any error that may happen during any cleanup.
349    ///
350    /// Dropping the frame instead may result in any of the following and is implementation dependent:
351    /// - All actions done to the frame vanish and are never executed
352    /// - A partial renderer with undefined framebuffer contents occurs
353    /// - All actions are performed as normal without errors being returned.
354    ///
355    /// Leaking the frame instead will leak resources and can cause any of the previous effects.
356    /// Leaking might make the renderer return Errors and force it's recreation.
357    /// Leaking may not cause otherwise undefined behavior and program execution will always continue normally.
358    fn finish(self) -> Result<sync::SyncPoint, Self::Error>;
359}
360
361bitflags::bitflags! {
362    /// Debug flags that can be enabled at runtime
363    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
364    pub struct DebugFlags: u32 {
365        /// Tint all rendered textures
366        const TINT = 0b00000001;
367    }
368}
369
370/// Workaround for <https://github.com/rust-lang/rust/issues/87479>, please look at [`Renderer`] instead.
371pub trait RendererSuper: fmt::Debug {
372    /// Error type returned by the rendering operations of this renderer.
373    type Error: Error;
374    /// Texture Handle type used by this renderer.
375    type TextureId: Texture;
376    /// Framebuffer to draw onto
377    type Framebuffer<'buffer>: Texture;
378    /// Type representing a currently in-progress frame during the [`Renderer::render`]-call
379    type Frame<'frame, 'buffer>: Frame<Error = Self::Error, TextureId = Self::TextureId>
380    where
381        'buffer: 'frame,
382        Self: 'frame;
383}
384
385/// Abstraction of commonly used rendering operations for compositors.
386///
387/// *Note*: Associated types are defined in [`RendererSuper`].
388pub trait Renderer: RendererSuper {
389    /// Returns the [`ContextId`] of this renderer
390    ///
391    /// See [`ContextId`] for more details.
392    fn context_id(&self) -> ContextId<Self::TextureId>;
393
394    /// Set the filter method to be used when rendering a texture into a smaller area than its size
395    fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error>;
396    /// Set the filter method to be used when rendering a texture into a larger area than its size
397    fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error>;
398
399    /// Set the enabled [`DebugFlags`]
400    fn set_debug_flags(&mut self, flags: DebugFlags);
401    /// Returns the current enabled [`DebugFlags`]
402    fn debug_flags(&self) -> DebugFlags;
403
404    /// Initialize a rendering context on the provided framebuffer with given dimensions and transformation.
405    ///
406    /// The `output_size` specifies the dimensions of the display **before** the `dst_transform` is
407    /// applied.
408    ///
409    /// This function *may* error, if:
410    /// - The given dimensions are unsupported (too large) for this renderer
411    /// - The given Transformation is not supported by the renderer (`Transform::Normal` is always supported).
412    /// - The underlying object of the given framebuffer is incompatible with this particular render instance.
413    fn render<'frame, 'buffer>(
414        &'frame mut self,
415        framebuffer: &'frame mut Self::Framebuffer<'buffer>,
416        output_size: Size<i32, Physical>,
417        dst_transform: Transform,
418    ) -> Result<Self::Frame<'frame, 'buffer>, Self::Error>
419    where
420        'buffer: 'frame;
421
422    /// Wait for a [`SyncPoint`](sync::SyncPoint) to be signaled
423    fn wait(&mut self, sync: &sync::SyncPoint) -> Result<(), Self::Error>;
424
425    /// Forcibly clean up the renderer internal texture cache
426    ///
427    /// Note: Resources used by the renderer will be implicitly cleaned-up after finishing
428    /// a [`Frame`] by either dropping the [`Frame`] or explicitly calling [`Frame::finish`].
429    /// This call can be used to clean-up resources in cases where either no [`Frame`] is used
430    /// at all to prevent resource pile-up or in case of only infrequent access to lower
431    /// system resource usage.
432    fn cleanup_texture_cache(&mut self) -> Result<(), Self::Error> {
433        Ok(())
434    }
435}
436
437/// Trait for renderers that support creating offscreen framebuffers to render into.
438///
439/// Usually also implement [`ExportMem`] to receive the framebuffers contents.
440pub trait Offscreen<Target>: Renderer + Bind<Target> {
441    /// Create a new instance of a framebuffer.
442    ///
443    /// This call *may* fail, if (but not limited to):
444    /// - The maximum amount of framebuffers for this renderer would be exceeded
445    /// - The format is not supported to be rendered into
446    /// - The size is too large for a framebuffer
447    fn create_buffer(&mut self, format: Fourcc, size: Size<i32, BufferCoord>) -> Result<Target, Self::Error>;
448}
449
450/// Trait for Renderers supporting importing wl_buffers using shared memory.
451#[cfg(feature = "wayland_frontend")]
452pub trait ImportMemWl: ImportMem {
453    /// Import a given shm-based buffer into the renderer (see [`buffer_type`]).
454    ///
455    /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
456    /// or implementation-specific functions.
457    ///
458    /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
459    /// This operation needs no bound or default rendering target.
460    ///
461    /// The implementation defines, if the id keeps being valid, if the buffer is released,
462    /// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again.
463    ///
464    /// If provided the `SurfaceAttributes` can be used to do caching of rendering resources and is generally recommended.
465    ///
466    /// The `damage` argument provides a list of rectangle locating parts of the buffer that need to be updated. When provided
467    /// with an empty list `&[]`, the renderer is allowed to not update the texture at all.
468    fn import_shm_buffer(
469        &mut self,
470        buffer: &wl_buffer::WlBuffer,
471        surface: Option<&crate::wayland::compositor::SurfaceData>,
472        damage: &[Rectangle<i32, BufferCoord>],
473    ) -> Result<Self::TextureId, Self::Error>;
474
475    /// Returns supported formats for shared memory buffers.
476    ///
477    /// Will always contain At least `Argb8888` and `Xrgb8888`.
478    fn shm_formats(&self) -> Box<dyn Iterator<Item = wl_shm::Format>> {
479        Box::new(self.mem_formats().flat_map(fourcc_to_shm_format))
480    }
481}
482
483/// Trait for Renderers supporting importing bitmaps from memory.
484pub trait ImportMem: Renderer {
485    /// Import a given chunk of memory into the renderer.
486    ///
487    /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
488    ///  or implementation-specific functions.
489    ///
490    /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
491    /// This operation needs no bound or default rendering target.
492    ///
493    /// Settings flipped to true will cause the buffer to be interpreted like the y-axis is flipped
494    /// (opposed to the lower left begin (0, 0)).
495    /// This is a texture specific property, so future uploads to the same texture via [`ImportMem::update_memory`]
496    /// will also be interpreted as flipped.
497    ///
498    /// The provided data slice needs to be in a format supported as indicated by [`ImportMem::mem_formats`].
499    /// Its length should thus be `size.w * size.h * bits_per_pixel`.
500    /// Anything beyond will be truncated, if the buffer is too small an error will be returned.
501    fn import_memory(
502        &mut self,
503        data: &[u8],
504        format: Fourcc,
505        size: Size<i32, BufferCoord>,
506        flipped: bool,
507    ) -> Result<Self::TextureId, Self::Error>;
508
509    /// Update a portion of a given chunk of memory into an existing texture.
510    ///
511    /// This operation needs no bound or default rendering target.
512    ///
513    /// The provided data slice needs to be in the same format used to create the texture and the same size of the texture.
514    /// Its length should this be `texture.size().w * texture.size().h * bits_per_pixel`.
515    /// Anything beyond will be ignored, if the buffer is too small an error will be returned.
516    ///
517    /// This function *may* error, if (but not limited to):
518    /// - The texture was not created using either [`ImportMemWl::import_shm_buffer`] or [`ImportMem::import_memory`].
519    ///   External textures imported by other means (e.g. via ImportDma) may not be writable. This property is defined
520    ///   by the implementation.
521    /// - The region is out of bounds of the initial size the texture was created with. Implementations are not required
522    ///   to support resizing the original texture.
523    fn update_memory(
524        &mut self,
525        texture: &Self::TextureId,
526        data: &[u8],
527        region: Rectangle<i32, BufferCoord>,
528    ) -> Result<(), Self::Error>;
529
530    /// Returns supported formats for memory imports.
531    fn mem_formats(&self) -> Box<dyn Iterator<Item = Fourcc>>;
532}
533
534#[cfg(all(
535    feature = "wayland_frontend",
536    feature = "backend_egl",
537    feature = "use_system_lib"
538))]
539/// Trait for Renderers supporting importing wl_drm-based buffers.
540pub trait ImportEgl: Renderer {
541    /// Binds the underlying EGL display to the given Wayland display.
542    ///
543    /// This will allow clients to utilize EGL to create hardware-accelerated
544    /// surfaces. This renderer will thus be able to handle wl_drm-based buffers.
545    ///
546    /// ## Errors
547    ///
548    /// This might return [`EglExtensionNotSupported`](super::egl::Error::EglExtensionNotSupported)
549    /// if binding is not supported by the EGL implementation.
550    ///
551    /// This might return [`OtherEGLDisplayAlreadyBound`](super::egl::Error::OtherEGLDisplayAlreadyBound)
552    /// if called for the same [`Display`](wayland_server::Display) multiple times, as only one egl
553    /// display may be bound at any given time.
554    fn bind_wl_display(&mut self, display: &wayland_server::DisplayHandle) -> Result<(), EglError>;
555
556    /// Unbinds a previously bound egl display, if existing.
557    ///
558    /// *Note*: As a result any previously created egl-based WlBuffers will not be readable anymore.
559    /// Your compositor will have to deal with existing buffers of *unknown* type.
560    fn unbind_wl_display(&mut self);
561
562    /// Returns the underlying [`EGLBufferReader`].
563    ///
564    /// The primary use for this is calling [`buffer_dimensions`] or [`buffer_type`].
565    ///
566    /// Returns `None` if no [`Display`](wayland_server::Display) was previously bound to the underlying
567    /// [`EGLDisplay`](super::egl::EGLDisplay) (see [`ImportEgl::bind_wl_display`]).
568    fn egl_reader(&self) -> Option<&EGLBufferReader>;
569
570    /// Import a given wl_drm-based buffer into the renderer (see [`buffer_type`]).
571    ///
572    /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
573    /// or implementation-specific functions.
574    ///
575    /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
576    ///
577    /// This operation needs no bound or default rendering target.
578    ///
579    /// The implementation defines, if the id keeps being valid, if the buffer is released,
580    /// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again.
581    fn import_egl_buffer(
582        &mut self,
583        buffer: &wl_buffer::WlBuffer,
584        surface: Option<&crate::wayland::compositor::SurfaceData>,
585        damage: &[Rectangle<i32, BufferCoord>],
586    ) -> Result<Self::TextureId, Self::Error>;
587}
588
589#[cfg(feature = "wayland_frontend")]
590/// Trait for Renderers supporting importing dmabuf-based wl_buffers
591pub trait ImportDmaWl: ImportDma {
592    /// Import a given dmabuf-based buffer into the renderer (see [`buffer_type`]).
593    ///
594    /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
595    /// or implementation-specific functions.
596    ///
597    /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
598    ///
599    /// This operation needs no bound or default rendering target.
600    ///
601    /// The implementation defines, if the id keeps being valid, if the buffer is released,
602    /// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again.
603    fn import_dma_buffer(
604        &mut self,
605        buffer: &wl_buffer::WlBuffer,
606        _surface: Option<&crate::wayland::compositor::SurfaceData>,
607        damage: &[Rectangle<i32, BufferCoord>],
608    ) -> Result<Self::TextureId, Self::Error> {
609        let dmabuf = crate::wayland::dmabuf::get_dmabuf(buffer)
610            .expect("import_dma_buffer without checking buffer type?");
611        self.import_dmabuf(dmabuf, Some(damage))
612    }
613}
614
615/// Trait for Renderers supporting importing dmabufs.
616pub trait ImportDma: Renderer {
617    /// Returns supported formats for dmabufs.
618    fn dmabuf_formats(&self) -> FormatSet {
619        FormatSet::default()
620    }
621
622    /// Test if a specific dmabuf [`Format`] is supported
623    fn has_dmabuf_format(&self, format: Format) -> bool {
624        self.dmabuf_formats().contains(&format)
625    }
626
627    /// Import a given raw dmabuf into the renderer.
628    ///
629    /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
630    /// or implementation-specific functions.
631    ///
632    /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
633    ///
634    /// This operation needs no bound or default rendering target.
635    ///
636    /// The implementation defines, if the id keeps being valid, if the buffer is released,
637    /// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again.
638    fn import_dmabuf(
639        &mut self,
640        dmabuf: &Dmabuf,
641        damage: Option<&[Rectangle<i32, BufferCoord>]>,
642    ) -> Result<Self::TextureId, Self::Error>;
643}
644
645// TODO: Replace this with a trait_alias, once that is stabilized.
646// pub type ImportAll = Renderer + ImportShm + ImportEgl;
647
648/// Common trait for renderers of any wayland buffer type
649#[cfg(feature = "wayland_frontend")]
650pub trait ImportAll: Renderer {
651    /// Import a given buffer into the renderer.
652    ///
653    /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
654    /// or implementation-specific functions.
655    ///
656    /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
657    ///
658    /// This operation needs no bound or default rendering target.
659    ///
660    /// The implementation defines, if the id keeps being valid, if the buffer is released,
661    /// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again.
662    ///
663    /// If provided the `SurfaceAttributes` can be used to do caching of rendering resources and is generally recommended.
664    ///
665    /// The `damage` argument provides a list of rectangle locating parts of the buffer that need to be updated. When provided
666    /// with an empty list `&[]`, the renderer is allowed to not update the texture at all.
667    ///
668    /// Returns `None`, if the buffer type cannot be determined or does not correspond to a texture (e.g.: single pixel buffer).
669    fn import_buffer(
670        &mut self,
671        buffer: &wl_buffer::WlBuffer,
672        surface: Option<&crate::wayland::compositor::SurfaceData>,
673        damage: &[Rectangle<i32, BufferCoord>],
674    ) -> Option<Result<Self::TextureId, Self::Error>>;
675}
676
677// TODO: Do this with specialization, when possible and do default implementations
678#[cfg(all(
679    feature = "wayland_frontend",
680    feature = "backend_egl",
681    feature = "use_system_lib"
682))]
683impl<R: Renderer + ImportMemWl + ImportEgl + ImportDmaWl> ImportAll for R {
684    #[profiling::function]
685    fn import_buffer(
686        &mut self,
687        buffer: &wl_buffer::WlBuffer,
688        surface: Option<&SurfaceData>,
689        damage: &[Rectangle<i32, BufferCoord>],
690    ) -> Option<Result<Self::TextureId, Self::Error>> {
691        match buffer_type(buffer) {
692            Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)),
693            Some(BufferType::Egl) => Some(self.import_egl_buffer(buffer, surface, damage)),
694            Some(BufferType::Dma) => Some(self.import_dma_buffer(buffer, surface, damage)),
695            _ => None,
696        }
697    }
698}
699
700#[cfg(all(
701    feature = "wayland_frontend",
702    not(all(feature = "backend_egl", feature = "use_system_lib"))
703))]
704impl<R: Renderer + ImportMemWl + ImportDmaWl> ImportAll for R {
705    fn import_buffer(
706        &mut self,
707        buffer: &wl_buffer::WlBuffer,
708        surface: Option<&SurfaceData>,
709        damage: &[Rectangle<i32, BufferCoord>],
710    ) -> Option<Result<Self::TextureId, Self::Error>> {
711        match buffer_type(buffer) {
712            Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)),
713            Some(BufferType::Dma) => Some(self.import_dma_buffer(buffer, surface, damage)),
714            _ => None,
715        }
716    }
717}
718
719/// Trait for renderers supporting exporting contents of framebuffers or textures into memory.
720pub trait ExportMem: Renderer {
721    /// Texture type representing a downloaded pixel buffer.
722    type TextureMapping: TextureMapping;
723
724    /// Copies the contents of the provided target.
725    ///
726    /// This operation is not destructive, the contents of the framebuffer keep being valid.
727    ///
728    /// This function *may* fail, if (but not limited to):
729    /// - The framebuffer is not readable
730    /// - The region is out of bounds of the framebuffer
731    /// - There is not enough space to create the mapping
732    /// - It is not possible to convert the framebuffer into the provided format.
733    fn copy_framebuffer(
734        &mut self,
735        target: &Self::Framebuffer<'_>,
736        region: Rectangle<i32, BufferCoord>,
737        format: Fourcc,
738    ) -> Result<Self::TextureMapping, Self::Error>;
739
740    /// Copies the contents of the passed texture.
741    /// *Note*: This function may change or invalidate the current bind.
742    ///
743    /// Renderers are not required to support any format other than what was returned by `Texture::format`.
744    /// This operation is not destructive, the contents of the texture keep being valid.
745    ///
746    /// This function *may* fail, if:
747    /// - There is not enough space to create the mapping
748    /// - The texture does no allow copying for implementation-specfic reasons
749    /// - It is not possible to convert the texture into the provided format.
750    fn copy_texture(
751        &mut self,
752        texture: &Self::TextureId,
753        region: Rectangle<i32, BufferCoord>,
754        format: Fourcc,
755    ) -> Result<Self::TextureMapping, Self::Error>;
756
757    /// Returns whether the renderer should be able to read-back from the given texture.
758    ///
759    /// No actual copying shall be performed by this function nor is a format specified,
760    /// so it is still legal for [`ExportMem::copy_texture`] to return an error, if this
761    /// method returns `true`.
762    ///
763    /// This function *may* fail, if:
764    /// - A readability test did successfully complete (not that it returned `unreadble`!)
765    /// - Any of the state of the renderer is irrevesibly changed
766    fn can_read_texture(&mut self, texture: &Self::TextureId) -> Result<bool, Self::Error>;
767
768    /// Returns a read-only pointer to a previously created texture mapping.
769    ///
770    /// The format of the returned slice is given by [`Texture::format`] of the texture mapping.
771    ///
772    /// This function *may* fail, if (but not limited to):
773    /// - There is not enough space in memory
774    fn map_texture<'a>(&mut self, texture_mapping: &'a Self::TextureMapping)
775        -> Result<&'a [u8], Self::Error>;
776}
777
778/// Trait for renderers supporting blitting contents from one framebuffer to another.
779// We would like to require the following. But we can't because of <https://github.com/rust-lang/rust/issues/100013>.
780// for<'frame, 'buffer> Self::Frame<'frame, 'buffer>: BlitFrame<Self::Framebuffer<'buffer>>,
781pub trait Blit
782where
783    Self: Renderer,
784{
785    /// Copies the contents of `src` from one provided target to `dst` in the other provided target,
786    /// applying `filter` if necessary.
787    ///
788    /// This operation is non destructive, the contents of the source framebuffer
789    /// are kept intact as is any region not in `dst` for the target framebuffer.
790    ///
791    /// This function *may* fail, if (but not limited to):
792    /// - The source framebuffer is not readable
793    /// - The destination framebuffer is not writable
794    /// - `src` is out of bounds for the source framebuffer
795    /// - `dst` is out of bounds for the destination framebuffer
796    /// - `src` and `dst` sizes are different and interpolation is not supported by this renderer.
797    /// - source and target framebuffer are the same
798    fn blit(
799        &mut self,
800        from: &Self::Framebuffer<'_>,
801        to: &mut Self::Framebuffer<'_>,
802        src: Rectangle<i32, Physical>,
803        dst: Rectangle<i32, Physical>,
804        filter: TextureFilter,
805    ) -> Result<(), Self::Error>;
806}
807
808/// Trait for frames supporting blitting contents from/to the current framebuffer to/from another.
809pub trait BlitFrame<Framebuffer>
810where
811    Self: Frame,
812{
813    /// Copies the contents of the bound framebuffer to `dst` in the provided framebuffer,
814    /// applying `filter` if necessary.
815    ///
816    /// This operation is non destructive, the contents of the current framebuffer
817    /// are kept intact as is any region not in `dst` for the target framebuffer.
818    ///
819    /// This function *may* fail, if (but not limited to):
820    /// - The bound framebuffer is not readable
821    /// - The destination framebuffer is not writable
822    /// - `src` is out of bounds for the bound framebuffer
823    /// - `dst` is out of bounds for the destination framebuffer
824    /// - `src` and `dst` sizes are different and interpolation is not supported by this renderer.
825    /// - bound and target framebuffer are the same
826    fn blit_to(
827        &mut self,
828        to: &mut Framebuffer,
829        src: Rectangle<i32, Physical>,
830        dst: Rectangle<i32, Physical>,
831        filter: TextureFilter,
832    ) -> Result<(), Self::Error>;
833
834    /// Copies the contents of the provided framebuffer to `dst` in the bound framebuffer,
835    /// applying `filter` if necessary.
836    ///
837    /// This operation is non destructive, the contents of the source framebuffer
838    /// are kept intact as is any region not in `dst` for the bound framebuffer.
839    ///
840    /// This function *may* fail, if (but not limited to):
841    /// - The source framebuffer is not readable
842    /// - The bound framebuffer is not writable
843    /// - `src` is out of bounds for the source framebuffer
844    /// - `dst` is out of bounds for the bound framebuffer
845    /// - `src` and `dst` sizes are different and interpolation is not supported by this renderer.
846    /// - source and bound framebuffer are the same
847    fn blit_from(
848        &mut self,
849        from: &Framebuffer,
850        src: Rectangle<i32, Physical>,
851        dst: Rectangle<i32, Physical>,
852        filter: TextureFilter,
853    ) -> Result<(), Self::Error>;
854}
855
856#[cfg(feature = "wayland_frontend")]
857#[non_exhaustive]
858/// Buffer type of a given wl_buffer, if managed by smithay
859#[derive(Debug)]
860pub enum BufferType {
861    /// Buffer is managed by the [`crate::wayland::shm`] global
862    Shm,
863    #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))]
864    /// Buffer is managed by a currently initialized [`crate::backend::egl::display::EGLBufferReader`]
865    Egl,
866    /// Buffer is managed by the [`crate::wayland::dmabuf`] global
867    Dma,
868    /// Buffer represents a singe pixel
869    SinglePixel,
870}
871
872/// Returns the *type* of a wl_buffer
873///
874/// Returns `None` if the type is not known to smithay
875/// or otherwise not supported (e.g. not initialized using one of smithays [`crate::wayland`]-handlers).
876#[cfg(feature = "wayland_frontend")]
877pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option<BufferType> {
878    use crate::wayland::shm::BufferAccessError;
879
880    if crate::wayland::dmabuf::get_dmabuf(buffer).is_ok() {
881        return Some(BufferType::Dma);
882    }
883
884    if !matches!(
885        crate::wayland::shm::with_buffer_contents(buffer, |_, _, _| ()),
886        Err(BufferAccessError::NotManaged)
887    ) {
888        return Some(BufferType::Shm);
889    }
890
891    if crate::wayland::single_pixel_buffer::get_single_pixel_buffer(buffer).is_ok() {
892        return Some(BufferType::SinglePixel);
893    }
894
895    // Not managed, check if this is an EGLBuffer
896    #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))]
897    if BUFFER_READER
898        .lock()
899        .unwrap()
900        .as_ref()
901        .and_then(|x| x.upgrade())
902        .and_then(|x| x.egl_buffer_dimensions(buffer))
903        .is_some()
904    {
905        return Some(BufferType::Egl);
906    }
907
908    None
909}
910
911/// Returns if the buffer has an alpha channel
912///
913/// Returns `None` if the type is not known to smithay
914/// or otherwise not supported (e.g. not initialized using one of smithays [`crate::wayland`]-handlers).
915///
916/// Note: This is on a best-effort, but will never return false for a buffer
917/// with a format that supports alpha.
918#[cfg(feature = "wayland_frontend")]
919pub fn buffer_has_alpha(buffer: &wl_buffer::WlBuffer) -> Option<bool> {
920    use super::allocator::format::has_alpha;
921    use crate::wayland::shm::shm_format_to_fourcc;
922
923    if let Ok(dmabuf) = crate::wayland::dmabuf::get_dmabuf(buffer) {
924        return Some(crate::backend::allocator::format::has_alpha(dmabuf.0.format));
925    }
926
927    if let Ok(has_alpha) = crate::wayland::shm::with_buffer_contents(buffer, |_, _, data| {
928        shm_format_to_fourcc(data.format).is_some_and(has_alpha)
929    }) {
930        return Some(has_alpha);
931    }
932
933    if let Ok(spb) = crate::wayland::single_pixel_buffer::get_single_pixel_buffer(buffer) {
934        return Some(spb.has_alpha());
935    }
936
937    // Not managed, check if this is an EGLBuffer
938    #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))]
939    if let Some(format) = BUFFER_READER
940        .lock()
941        .unwrap()
942        .as_ref()
943        .and_then(|x| x.upgrade())
944        .and_then(|x| x.egl_buffer_contents(buffer).ok())
945        .map(|b| b.format)
946    {
947        return Some(crate::backend::egl::display::EGLBufferReader::egl_buffer_has_alpha(format));
948    }
949
950    None
951}
952
953/// Returns the dimensions of a wl_buffer
954///
955/// *Note*: This will only return dimensions for buffer types known to smithay (see [`buffer_type`])
956#[cfg(feature = "wayland_frontend")]
957pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option<Size<i32, BufferCoord>> {
958    use crate::{
959        backend::allocator::Buffer,
960        wayland::shm::{self, BufferAccessError},
961    };
962
963    if let Ok(buf) = crate::wayland::dmabuf::get_dmabuf(buffer) {
964        return Some((buf.width() as i32, buf.height() as i32).into());
965    }
966
967    if crate::wayland::single_pixel_buffer::get_single_pixel_buffer(buffer).is_ok() {
968        return Some(Size::from((1, 1)));
969    }
970
971    match shm::with_buffer_contents(buffer, |_, _, data| (data.width, data.height).into()) {
972        Ok(data) => Some(data),
973
974        Err(BufferAccessError::NotManaged) => {
975            // Not managed, check if this is an EGLBuffer
976            #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))]
977            if let Some(dim) = BUFFER_READER
978                .lock()
979                .unwrap()
980                .as_ref()
981                .and_then(|x| x.upgrade())
982                .and_then(|x| x.egl_buffer_dimensions(buffer))
983            {
984                return Some(dim);
985            }
986
987            None
988        }
989
990        Err(_) => None,
991    }
992}
993
994/// Returns if the underlying buffer is y-inverted
995///
996/// *Note*: This will only return y-inverted for buffer types known to smithay (see [`buffer_type`])
997#[cfg(feature = "wayland_frontend")]
998#[profiling::function]
999pub fn buffer_y_inverted(buffer: &wl_buffer::WlBuffer) -> Option<bool> {
1000    if let Ok(dmabuf) = crate::wayland::dmabuf::get_dmabuf(buffer) {
1001        return Some(dmabuf.y_inverted());
1002    }
1003
1004    #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))]
1005    if let Some(Ok(egl_buffer)) = BUFFER_READER
1006        .lock()
1007        .unwrap()
1008        .as_ref()
1009        .and_then(|x| x.upgrade())
1010        .map(|x| x.egl_buffer_contents(buffer))
1011    {
1012        return Some(egl_buffer.y_inverted);
1013    }
1014
1015    None
1016}