🔒 Repository is read-only – file editing is disabled.

PaganDE/smithay-0.7.0/src/backend/renderer/element/mod.rs main

1424 linii Raw ← Powrót
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424
//! Common base for elements that can be drawn by a [`Renderer`]
//!
//! A [`RenderElement`] defines what should be [`draw`](RenderElement::draw)n where.
//! Additionally it provides the foundation for effective damage tracked rendering
//! by allowing to query for damage between two [`CommitCounter`]s.
//!
//! For specialized renderers it can optionally provide access to the [`UnderlyingStorage`]
//! of the element.
//!
//! Out of the box smithay provides the following elements
//! - [`memory`] - Memory based render element
//! - [`texture`] - Texture based render element
//! - [`surface`] - Wayland surface render element
//! - [`solid`] - Solid color render element
//!
//! The [`render_elements!`] macro provides an easy way to aggregate multiple different [RenderElement]s
//! into a single enum.
//!
//! See the [`damage`](crate::backend::renderer::damage) module for more information on
//! damage tracking.

use std::{collections::HashMap, sync::Arc};

#[cfg(feature = "wayland_frontend")]
use wayland_server::{backend::ObjectId, Resource};

use crate::{
    output::{Output, WeakOutput},
    utils::{Buffer as BufferCoords, Physical, Point, Rectangle, Scale, Transform},
};

#[cfg(feature = "wayland_frontend")]
use super::utils::Buffer;
use super::{
    utils::{CommitCounter, DamageSet, OpaqueRegions},
    Renderer,
};

pub mod memory;
pub mod solid;
#[cfg(feature = "wayland_frontend")]
pub mod surface;
pub mod texture;
pub mod utils;

crate::utils::ids::id_gen!(external_id);

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
/// A unique id for a [`RenderElement`]
pub struct Id(InnerId);

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
enum InnerId {
    #[cfg(feature = "wayland_frontend")]
    WaylandResource(ObjectId),
    External(Arc<ExternalId>),
}

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
struct ExternalId(usize);

impl ExternalId {
    fn new() -> Self {
        ExternalId(external_id::next())
    }
}

impl Drop for ExternalId {
    fn drop(&mut self) {
        external_id::remove(self.0);
    }
}

impl Id {
    /// Create an id from a [`Resource`]
    ///
    /// Note: Calling this function for the same [`Resource`]
    /// multiple times will return the same id.
    #[cfg(feature = "wayland_frontend")]
    pub fn from_wayland_resource<R: Resource>(resource: &R) -> Self {
        Id(InnerId::WaylandResource(resource.id()))
    }

    /// Create a new unique id
    ///
    /// Note: The id will be re-used once all instances of this [`Id`]
    /// are dropped.
    pub fn new() -> Self {
        Id(InnerId::External(Arc::new(ExternalId::new())))
    }
}

#[cfg(feature = "wayland_frontend")]
impl<R: Resource> From<&R> for Id {
    #[inline]
    fn from(resource: &R) -> Self {
        Id::from_wayland_resource(resource)
    }
}

/// The underlying storage for a element
#[derive(Debug, Clone)]
pub enum UnderlyingStorage<'a> {
    /// A wayland buffer
    #[cfg(feature = "wayland_frontend")]
    Wayland(&'a Buffer),
    /// A memory backed buffer
    Memory(&'a memory::MemoryBuffer),
}

/// Defines the (optional) reason why a [`Element`] was selected for
/// rendering instead of direct scan-out
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RenderingReason {
    /// The element buffer format is unsuited for direct scan-out
    FormatUnsupported,
    /// Element was selected for direct scan-out but failed
    ScanoutFailed,
}

/// Defines the presentation state of an element after rendering
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RenderElementPresentationState {
    /// The element was selected for rendering
    Rendering {
        /// Optional reason why the element was selected for rendering
        ///
        /// Can be used to make a decision on sending an dmabuf feedback
        /// scan-out tranche.
        reason: Option<RenderingReason>,
    },
    /// The element was selected for zero-copy scan-out
    ZeroCopy,
    /// The element was skipped as it is current not visible
    Skipped,
}

/// Defines the element render state after rendering
#[derive(Debug, Clone, Copy)]
pub struct RenderElementState {
    /// Holds the physical visible area of the element on the output in pixels.
    ///  
    /// Note: If the presentation_state is [`RenderElementPresentationState::Skipped`] this will be zero.
    pub visible_area: usize,
    /// Holds the presentation state of the element on the output
    pub presentation_state: RenderElementPresentationState,
}

impl RenderElementState {
    pub(crate) fn skipped() -> Self {
        RenderElementState {
            visible_area: Default::default(),
            presentation_state: RenderElementPresentationState::Skipped,
        }
    }

    pub(crate) fn rendered(visible_area: usize) -> Self {
        RenderElementState {
            visible_area,
            presentation_state: RenderElementPresentationState::Rendering { reason: None },
        }
    }
}

/// Holds the primary scanout output for a surface
#[derive(Debug, Default)]
pub struct PrimaryScanoutOutput(Option<(WeakOutput, RenderElementState)>);

impl PrimaryScanoutOutput {
    /// Update the primary scan-out output from [`RenderElementStates`]
    ///
    /// If the current primary scan-out output is different than the
    /// provided output and the element is present according to the states
    /// the provided compare function will be run to select the preferred
    /// output. Smithay provides a [`default`](`default_primary_scanout_output_compare`)
    /// compare function for convenience.
    ///
    /// Returns the updated primary scan-out output if any
    pub fn update_from_render_element_states<F>(
        &mut self,
        element_id: impl Into<Id>,
        output: &Output,
        states: &RenderElementStates,
        compare: F,
    ) -> Option<Output>
    where
        F: for<'a> Fn(&'a Output, &'a RenderElementState, &'a Output, &'a RenderElementState) -> &'a Output,
    {
        let element_id = element_id.into();
        let element_was_presented = states.element_was_presented(element_id.clone());
        let element_state = states.element_render_state(element_id);
        let primary_scanout_output = &mut self.0;

        let has_valid_output = primary_scanout_output
            .as_ref()
            .map(|(current, _)| current.is_alive())
            .unwrap_or(false);
        let same_output = primary_scanout_output
            .as_ref()
            .map(|(current, _)| current == output)
            .unwrap_or(false);

        // If the element was not presented and we have no valid output
        // there is nothing we can do
        if !element_was_presented && !has_valid_output {
            return None;
        }

        // If our current output is the one we received for the update
        // and the element was not presented remove it, no need to check further
        if !element_was_presented && same_output {
            *primary_scanout_output = None;
            return None;
        }

        // If the element was presented but we have no current valid output
        // just directly update and exit early
        if element_was_presented && !has_valid_output {
            *primary_scanout_output = Some((output.downgrade(), element_state.unwrap()));
            return Some(output.clone());
        }

        // If the element was presented on the same output there
        // is no need to check
        if element_was_presented && has_valid_output && same_output {
            primary_scanout_output.as_mut().unwrap().1 = element_state.unwrap();
            return Some(output.clone());
        }

        // If the element was presented on a different output and we have a
        // valid current output, run the provided check
        if element_was_presented && has_valid_output && !same_output {
            let (current_output, current_state) = primary_scanout_output
                .as_ref()
                .map(|(output, state)| (output.upgrade().unwrap(), state))
                .unwrap();
            let updated = compare(
                &current_output,
                current_state,
                output,
                element_state.as_ref().unwrap(),
            )
            .clone();
            *primary_scanout_output = Some((updated.downgrade(), element_state.unwrap()));
            return Some(updated);
        }

        // The element was not presented on that output and the current scan-out output
        // is a different than we currently have, so we can just leave it as is
        primary_scanout_output
            .as_ref()
            .and_then(|(output, _)| output.upgrade())
    }

    /// Gets the current primary scanout output if any
    ///
    /// Return `None` if there is no primary scanout output or
    /// the stored output is longer alive
    pub fn current_output(&self) -> Option<Output> {
        self.0.as_ref().and_then(|(o, _)| o.upgrade())
    }
}

/// Default function for primary scan-out selection
///
/// This will prefer the next output when the visible portion of
/// the element on screen is at least twice the size of the
/// current visible portion. Otherwise it will prefer the output
/// with the higher refresh rate.
pub fn default_primary_scanout_output_compare<'a>(
    current_output: &'a Output,
    current_state: &RenderElementState,
    next_output: &'a Output,
    next_state: &RenderElementState,
) -> &'a Output {
    const VISIBLE_AREA_THRESHOLD: usize = 2;

    let current_mode = current_output.current_mode();
    let next_mode = next_output.current_mode();

    // We don't expect to be called with an output that has no mode,
    // but to be safe we do not unwrap here
    let next_mode_has_higher_refresh = next_mode
        .map(|next_mode| {
            current_mode
                .map(|current_mode| next_mode.refresh > current_mode.refresh)
                .unwrap_or(false)
        })
        .unwrap_or(false);

    let current_visible_area_threshold = current_state.visible_area * VISIBLE_AREA_THRESHOLD;
    let next_mode_visible_area_greater = next_state.visible_area >= current_visible_area_threshold;

    if next_mode_visible_area_greater || next_mode_has_higher_refresh {
        next_output
    } else {
        current_output
    }
}

/// Holds the states for a set of [`RenderElement`]s
#[derive(Default, Debug, Clone)]
pub struct RenderElementStates {
    /// Holds the render states of the elements
    pub states: HashMap<Id, RenderElementState>,
}

impl RenderElementStates {
    /// Return the [`RenderElementState`] for the specified [`Id`]
    ///
    /// Return `None` if the element is not included in the states
    pub fn element_render_state(&self, id: impl Into<Id>) -> Option<RenderElementState> {
        self.states.get(&id.into()).copied()
    }

    /// Returns whether the element with the specified id was presented
    ///
    /// Returns `false` if the element with the id was not found or skipped
    pub fn element_was_presented(&self, id: impl Into<Id>) -> bool {
        self.element_render_state(id)
            .map(|state| state.presentation_state != RenderElementPresentationState::Skipped)
            .unwrap_or(false)
    }
}

/// Defines the kind of an [`Element`]
///
/// This can give the backend a hint about how to handle the element
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub enum Kind {
    /// The element represents a cursor
    ///
    /// An element representing a cursor is expected to change infrequently.
    /// Not marking a cursor element as `Cursor` may result in lower performance and increased power usage.
    /// In contrast, marking elements that change frequently as `Cursor` can degrade performance significantly.
    Cursor,
    /// The element kind is unspecified
    #[default]
    Unspecified,
}

/// A single element
pub trait Element {
    /// Get the unique id of this element
    fn id(&self) -> &Id;
    /// Get the current commit position of this element
    fn current_commit(&self) -> CommitCounter;
    /// Get the location relative to the output
    fn location(&self, scale: Scale<f64>) -> Point<i32, Physical> {
        self.geometry(scale).loc
    }
    /// Get the src of the underlying buffer
    fn src(&self) -> Rectangle<f64, BufferCoords>;
    /// Get the transform of the underlying buffer
    fn transform(&self) -> Transform {
        Transform::Normal
    }
    /// Get the geometry relative to the output
    fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical>;
    /// Get the damage since the provided commit relative to the element
    fn damage_since(&self, scale: Scale<f64>, commit: Option<CommitCounter>) -> DamageSet<i32, Physical> {
        if commit != Some(self.current_commit()) {
            DamageSet::from_slice(&[Rectangle::from_size(self.geometry(scale).size)])
        } else {
            DamageSet::default()
        }
    }
    /// Get the opaque regions of the element relative to the element
    fn opaque_regions(&self, _scale: Scale<f64>) -> OpaqueRegions<i32, Physical> {
        OpaqueRegions::default()
    }
    /// Returns an alpha value the element should be drawn with regardless of any
    /// already encoded alpha in it's underlying representation.
    fn alpha(&self) -> f32 {
        1.0
    }
    /// Returns the [`Kind`] for this element
    fn kind(&self) -> Kind {
        Kind::default()
    }
}

/// A single render element
pub trait RenderElement<R: Renderer>: Element {
    /// Draw this element
    fn draw(
        &self,
        frame: &mut R::Frame<'_, '_>,
        src: Rectangle<f64, BufferCoords>,
        dst: Rectangle<i32, Physical>,
        damage: &[Rectangle<i32, Physical>],
        opaque_regions: &[Rectangle<i32, Physical>],
    ) -> Result<(), R::Error>;

    /// Get the underlying storage of this element, may be used to optimize rendering (eg. drm planes)
    #[inline]
    fn underlying_storage(&self, renderer: &mut R) -> Option<UnderlyingStorage<'_>> {
        let _ = renderer;
        None
    }
}

/// Types that can be converted into [`RenderElement`]s
pub trait AsRenderElements<R>
where
    R: Renderer,
{
    /// Type of the render element
    type RenderElement: RenderElement<R>;
    /// Returns render elements for a given position and scale
    fn render_elements<C: From<Self::RenderElement>>(
        &self,
        renderer: &mut R,
        location: Point<i32, Physical>,
        scale: Scale<f64>,
        alpha: f32,
    ) -> Vec<C>;
}

impl<E> Element for &E
where
    E: Element,
{
    fn id(&self) -> &Id {
        (*self).id()
    }

    fn current_commit(&self) -> CommitCounter {
        (*self).current_commit()
    }

    fn location(&self, scale: Scale<f64>) -> Point<i32, Physical> {
        (*self).location(scale)
    }

    fn src(&self) -> Rectangle<f64, BufferCoords> {
        (*self).src()
    }

    fn transform(&self) -> Transform {
        (*self).transform()
    }

    fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
        (*self).geometry(scale)
    }

    fn damage_since(&self, scale: Scale<f64>, commit: Option<CommitCounter>) -> DamageSet<i32, Physical> {
        (*self).damage_since(scale, commit)
    }

    fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> {
        (*self).opaque_regions(scale)
    }

    fn alpha(&self) -> f32 {
        (*self).alpha()
    }

    fn kind(&self) -> Kind {
        (*self).kind()
    }
}

impl<R, E> RenderElement<R> for &E
where
    R: Renderer,
    E: RenderElement<R> + Element,
{
    #[inline]
    fn underlying_storage(&self, renderer: &mut R) -> Option<UnderlyingStorage<'_>> {
        (*self).underlying_storage(renderer)
    }

    fn draw(
        &self,
        frame: &mut R::Frame<'_, '_>,
        src: Rectangle<f64, BufferCoords>,
        dst: Rectangle<i32, Physical>,
        damage: &[Rectangle<i32, Physical>],
        opaque_regions: &[Rectangle<i32, Physical>],
    ) -> Result<(), R::Error> {
        (*self).draw(frame, src, dst, damage, opaque_regions)
    }
}

// Clippy: `large_enum_variant` is easily triggered here, as the `_GenericCatcher` is always zero-size.
//          Thus we disable the lint.

#[macro_export]
#[doc(hidden)]
macro_rules! render_elements_internal {
    (@enum $(#[$attr:meta])* $vis:vis $name:ident; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher(std::convert::Infallible),
        }
    };
    (@enum $(#[$attr:meta])* $vis:vis $name:ident $($custom:ident)+; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name<$($custom),+> {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher(std::convert::Infallible),
        }
    };
    (@enum $(#[$attr:meta])* $vis:vis $name:ident $lt:lifetime; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name<$lt> {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher(std::convert::Infallible),
        }
    };
    (@enum $(#[$attr:meta])* $vis:vis $name:ident $lt:lifetime $($custom:ident)+; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name<$lt, $($custom),+> {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher(std::convert::Infallible),
        }
    };

    (@enum $(#[$attr:meta])* $vis:vis $name:ident<$renderer:ident>; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name<$renderer>
        where
            $renderer: $crate::backend::renderer::Renderer,
        {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher((std::marker::PhantomData<$renderer>, std::convert::Infallible)),
        }
    };
    (@enum $(#[$attr:meta])* $vis:vis $name:ident<$renderer:ident, $($custom:ident),+>; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name<$renderer, $($custom),+>
        where
            $renderer: $crate::backend::renderer::Renderer,
            $(
                $custom: $crate::backend::renderer::element::RenderElement<$renderer>,
            )+
        {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher((std::marker::PhantomData<$renderer>, std::convert::Infallible)),
        }
    };
    (@enum $(#[$attr:meta])* $vis:vis $name:ident<$lt:lifetime, $renderer:ident>; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name<$lt, $renderer>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
        {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher((std::marker::PhantomData<$renderer>, std::convert::Infallible)),
        }
    };
    (@enum $(#[$attr:meta])* $vis:vis $name:ident<$lt:lifetime, $renderer:ident, $($custom:ident),+>; $($(#[$meta:meta])* $body:ident=$field:ty$( as <$other_renderer:ty>)?),* $(,)?) => {
        $(#[$attr])*
        #[allow(clippy::large_enum_variant)]
        $vis enum $name<$lt, $renderer, $($custom),+>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $(
                $custom: $crate::backend::renderer::element::RenderElement<$renderer>,
            )+
        {
            $(
                $(
                    #[$meta]
                )*
                $body($field)
            ),*,
            #[doc(hidden)]
            _GenericCatcher((std::marker::PhantomData<$renderer>, std::convert::Infallible)),
        }
    };
    (@call $name:ident; $($x:ident),*) => {
        $crate::backend::renderer::element::Element::$name($($x),*)
    };
    (@call $renderer:ty; $name:ident; $($x:ident),*) => {
        $crate::backend::renderer::element::RenderElement::<$renderer>::$name($($x),*)
    };
    (@call $renderer:ty as $other:ty; draw; $x:ident, $renderer_ref:ident, $frame:ident, $($tail:ident),*) => {
        $crate::backend::renderer::element::RenderElement::<$other>::draw($x, $renderer_ref.as_mut(), $frame.as_mut(), $($tail),*).map_err(Into::into)
    };
    (@call $renderer:ty as $other:ty; $name:ident; $($x:ident),*) => {
        $crate::backend::renderer::element::RenderElement::<$other>::$name($($x),*)
    };
    (@body $($(#[$meta:meta])* $body:ident=$field:ty),* $(,)?) => {
        fn id(&self) -> &$crate::backend::renderer::element::Id {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call id; x)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn location(&self, scale: $crate::utils::Scale<f64>) -> $crate::utils::Point<i32, $crate::utils::Physical> {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call location; x, scale)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn src(&self) -> $crate::utils::Rectangle<f64, $crate::utils::Buffer> {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call src; x)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn transform(&self) -> $crate::utils::Transform {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call transform; x)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn geometry(&self, scale: $crate::utils::Scale<f64>) -> $crate::utils::Rectangle<i32, $crate::utils::Physical> {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call geometry; x, scale)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn current_commit(&self) -> $crate::backend::renderer::utils::CommitCounter {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call current_commit; x)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn damage_since(&self, scale: $crate::utils::Scale<f64>, commit: Option<$crate::backend::renderer::utils::CommitCounter>) -> $crate::backend::renderer::utils::DamageSet<i32, $crate::utils::Physical> {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call damage_since; x, scale, commit)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn opaque_regions(&self, scale: $crate::utils::Scale<f64>) -> $crate::backend::renderer::utils::OpaqueRegions<i32, $crate::utils::Physical> {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call opaque_regions; x, scale)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn alpha(&self) -> f32 {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call alpha; x)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        fn kind(&self) -> $crate::backend::renderer::element::Kind {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call kind; x)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }
    };
    (@draw <$renderer:ty>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        fn draw(
            &self,
            frame: &mut <$renderer as $crate::backend::renderer::RendererSuper>::Frame<'_, '_>,
            src: $crate::utils::Rectangle<f64, $crate::utils::Buffer>,
            dst: $crate::utils::Rectangle<i32, $crate::utils::Physical>,
            damage: &[$crate::utils::Rectangle<i32, $crate::utils::Physical>],
            opaque_regions: &[$crate::utils::Rectangle<i32, $crate::utils::Physical>],
        ) -> Result<(), <$renderer as $crate::backend::renderer::RendererSuper>::Error>
        where
        $(
            $(
                $renderer: std::convert::AsMut<$other_renderer>,
                <$renderer as $crate::backend::renderer::RendererSuper>::Frame: std::convert::AsMut<<$other_renderer as $crate::backend::renderer::RendererSuper>::Frame>,
                <$other_renderer as $crate::backend::renderer::RendererSuper>::Error: Into<<$renderer as $crate::backend::renderer::RendererSuper>::Error>,
            )*
        )*
        {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; draw; x, frame, src, dst, damage, opaque_regions)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        #[inline]
        fn underlying_storage(&self, renderer: &mut $renderer) -> Option<$crate::backend::renderer::element::UnderlyingStorage<'_>>
        {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; underlying_storage; x, renderer)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }
    };
    (@draw $renderer:ty; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        fn draw(
            &self,
            frame: &mut <$renderer as $crate::backend::renderer::RendererSuper>::Frame<'_, '_>,
            src: $crate::utils::Rectangle<f64, $crate::utils::Buffer>,
            dst: $crate::utils::Rectangle<i32, $crate::utils::Physical>,
            damage: &[$crate::utils::Rectangle<i32, $crate::utils::Physical>],
            opaque_regions: &[$crate::utils::Rectangle<i32, $crate::utils::Physical>],
        ) -> Result<(), <$renderer as $crate::backend::renderer::RendererSuper>::Error>
        {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; draw; x, frame, src, dst, damage, opaque_regions)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }

        #[inline]
        fn underlying_storage(&self, renderer: &mut $renderer) -> Option<$crate::backend::renderer::element::UnderlyingStorage<'_>>
        {
            match self {
                $(
                    #[allow(unused_doc_comments)]
                    $(
                        #[$meta]
                    )*
                    Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; underlying_storage; x, renderer)
                ),*,
                Self::_GenericCatcher(_) => unreachable!(),
            }
        }
    };
    // Generic renderer
    (@impl $name:ident<$renderer:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        impl<$renderer> $crate::backend::renderer::element::Element for $name<$renderer>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$renderer> $crate::backend::renderer::element::RenderElement<$renderer> for $name<$renderer>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@draw <$renderer>; $($tail)*);
        }
    };
    (@impl $name:ident<$lt:lifetime, $renderer:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        impl<$lt, $renderer> $crate::backend::renderer::element::Element for $name<$lt, $renderer>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$lt, $renderer> $crate::backend::renderer::element::RenderElement<$renderer> for $name<$lt, $renderer>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@draw <$renderer>; $($tail)*);
        }
    };
    (@impl $name:ident<$renderer:ident, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        impl<$renderer, $($custom),+> $crate::backend::renderer::element::Element for $name<$renderer, $($custom),+>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $(
                $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
            )+
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$renderer, $($custom),+> $crate::backend::renderer::element::RenderElement<$renderer> for $name<$renderer, $($custom),+>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $(
                $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
            )+
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@draw <$renderer>; $($tail)*);
        }
    };
    (@impl $name:ident<$lt:lifetime, $renderer:ident, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        impl<$lt, $renderer, $($custom),+> $crate::backend::renderer::element::Element for $name<$lt, $renderer, $($custom),+>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $(
                $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
            )+
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$lt, $renderer, $($custom),+> $crate::backend::renderer::element::RenderElement<$renderer> for $name<$lt, $renderer, $($custom),+>
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
            $(
                $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
            )+
            $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@draw <$renderer>; $($tail)*);
        }
    };
    (@impl $name:ident; $renderer:ident; $($tail:tt)*) => {
        impl $crate::backend::renderer::element::Element for $name
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$renderer> $crate::backend::renderer::element::RenderElement<$renderer> for $name
        where
            $renderer: $crate::backend::renderer::Renderer,
            <$renderer as $crate::backend::renderer::RendererSuper>::TextureId: 'static,
        {
            $crate::render_elements_internal!(@draw <$renderer>; $($tail)*);
        }
    };

    // Specific renderer
    (@impl $name:ident<=$renderer:ty>; $($tail:tt)*) => {
        impl $crate::backend::renderer::element::Element for $name
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl $crate::backend::renderer::element::RenderElement<$renderer> for $name
        {
            $crate::render_elements_internal!(@draw $renderer; $($tail)*);
        }
    };
    (@impl $name:ident<=$renderer:ty, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        impl<$($custom),+> $crate::backend::renderer::element::Element for $name<$($custom),+>
        where
        $(
            $custom: $crate::backend::renderer::element::Element,
        )+
        $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$($custom),+> $crate::backend::renderer::element::RenderElement<$renderer> for $name<$($custom),+>
        where
        $(
            $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
        )+
        $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@draw $renderer; $($tail)*);
        }
    };

    (@impl $name:ident<=$renderer:ty, $lt:lifetime>; $($tail:tt)*) => {
        impl<$lt> $crate::backend::renderer::element::Element for $name<$lt>
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$lt> $crate::backend::renderer::element::RenderElement<$renderer> for $name<$lt>
        {
            $crate::render_elements_internal!(@draw $renderer; $($tail)*);
        }
    };

    (@impl $name:ident<=$renderer:ty, $lt:lifetime, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        impl<$lt, $($custom),+> $crate::backend::renderer::element::Element for $name<$lt, $($custom),+>
        where
        $(
            $custom: $crate::backend::renderer::element::Element,
        )+
        $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@body $($tail)*);
        }
        impl<$lt, $($custom),+> $crate::backend::renderer::element::RenderElement<$renderer> for $name<$lt, $($custom),+>
        where
        $(
            $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
        )+
        $($($target: $bound $(+ $additional_bound)*),+)?
        {
            $crate::render_elements_internal!(@draw $renderer; $($tail)*);
        }
    };


    (@from $name:ident<$renderer:ident>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        $(
            $(
                #[$meta]
            )*
            impl<$renderer> From<$field> for $name<$renderer>
            where
                $renderer: $crate::backend::renderer::Renderer,
                $(
                    $($renderer: std::convert::AsMut<$other_renderer>,)?
                )*
            {
                #[inline]
                fn from(field: $field) -> $name<$renderer> {
                    $name::$body(field)
                }
            }
        )*
    };
    (@from $name:ident<$renderer:ident, $custom:ident>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        $(
            $(
                #[$meta]
            )*
            impl<$renderer, $custom> From<$field> for $name<$renderer, $custom>
            where
                $renderer: $crate::backend::renderer::Renderer,
                $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
                $(
                    $($renderer: std::convert::AsMut<$other_renderer>,)?
                )*
            {
                #[inline]
                fn from(field: $field) -> $name<$renderer, $custom> {
                    $name::$body(field)
                }
            }
        )*
    };
    (@from $name:ident<$lt:lifetime, $renderer:ident>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        $(
            $(
                #[$meta]
            )*
            impl<$lt, $renderer> From<$field> for $name<$lt, $renderer>
            where
                $renderer: $crate::backend::renderer::Renderer,
                $(
                    $($renderer: std::convert::AsMut<$other_renderer>,)?
                )*
            {
                #[inline]
                fn from(field: $field) -> $name<$lt, $renderer> {
                    $name::$body(field)
                }
            }
        )*
    };
    (@from $name:ident<$lt:lifetime, $renderer:ident, $custom:ident>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        $(
            $(
                #[$meta]
            )*
            impl<$lt, $renderer, $custom> From<$field> for $name<$lt, $renderer, $custom>
            where
                $renderer: $crate::backend::renderer::Renderer,
                $custom: $crate::backend::renderer::element::RenderElement<$renderer> + $crate::backend::renderer::element::Element,
                $(
                    $($renderer: std::convert::AsMut<$other_renderer>,)?
                )*
            {
                #[inline]
                fn from(field: $field) -> $name<$lt, $renderer, $custom> {
                    $name::$body(field)
                }
            }
        )*
    };
    (@from $name:ident; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        $(
            $(
                #[$meta]
            )*
            impl From<$field> for $name {
                #[inline]
                fn from(field: $field) -> $name {
                    $name::$body(field)
                }
            }
        )*
    };
    (@from $name:ident<$lt:lifetime>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
        $(
            $(
                #[$meta]
            )*
            impl<$lt> From<$field> for $name<$lt> {
                #[inline]
                fn from(field: $field) -> $name<$lt> {
                    $name::$body(field)
                }
            }
        )*
    };
}

/// Aggregate multiple types implementing [`RenderElement`] into a single enum type
///
/// ```
/// # use smithay::{
/// #     backend::{
/// #         allocator::Fourcc,
/// #         renderer::{
/// #             element::{Element, Id, RenderElement},
/// #             utils::CommitCounter,
/// #             Renderer,
/// #         },
/// #     },
/// #     utils::{Buffer, Point, Physical, Rectangle, Scale, Transform},
/// # };
/// #
/// # struct MyRenderElement1;
/// # struct MyRenderElement2;
/// #
/// # impl Element for MyRenderElement1 {
/// #     fn id(&self) -> &Id {
/// #         unimplemented!()
/// #     }
/// #
/// #     fn current_commit(&self) -> CommitCounter {
/// #         unimplemented!()
/// #     }
/// #
/// #     fn geometry(&self, _scale: Scale<f64>) -> Rectangle<i32, Physical> {
/// #         unimplemented!()
/// #     }
/// #
/// #     fn src(&self) -> Rectangle<f64, Buffer> {
/// #         unimplemented!()
/// #     }
/// # }
/// #
/// # impl<R: Renderer> RenderElement<R> for MyRenderElement1 {
/// #     fn draw(
/// #         &self,
/// #         _frame: &mut R::Frame<'_, '_>,
/// #         _src: Rectangle<f64, Buffer>,
/// #         _dst: Rectangle<i32, Physical>,
/// #         _damage: &[Rectangle<i32, Physical>],
/// #         _opaque_regions: &[Rectangle<i32, Physical>],
/// #     ) -> Result<(), R::Error> {
/// #         unimplemented!()
/// #     }
/// # }
/// #
/// # impl Element for MyRenderElement2 {
/// #     fn id(&self) -> &Id {
/// #         unimplemented!()
/// #     }
/// #
/// #     fn current_commit(&self) -> CommitCounter {
/// #         unimplemented!()
/// #     }
/// #
/// #     fn geometry(&self, _scale: Scale<f64>) -> Rectangle<i32, Physical> {
/// #         unimplemented!()
/// #     }
/// #
/// #     fn src(&self) -> Rectangle<f64, Buffer> {
/// #         unimplemented!()
/// #     }
/// # }
/// #
/// # impl<R: Renderer> RenderElement<R> for MyRenderElement2 {
/// #     fn draw(
/// #         &self,
/// #         _frame: &mut R::Frame<'_, '_>,
/// #         _src: Rectangle<f64, Buffer>,
/// #         _dst: Rectangle<i32, Physical>,
/// #         _damage: &[Rectangle<i32, Physical>],
/// #         _opaque_regions: &[Rectangle<i32, Physical>],
/// #     ) -> Result<(), R::Error> {
/// #         unimplemented!()
/// #     }
/// # }
/// use smithay::backend::renderer::element::render_elements;
///
/// render_elements! {
///     MyRenderElements;
///     First=MyRenderElement1,
///     Second=MyRenderElement2,
/// }
/// ```
///
/// If the [`RenderElement`] has special requirements on the [`Renderer`] you can
/// express them with a syntax similar to HRTBs.
///
/// For example the [`MemoryRenderBufferRenderElement`](crate::backend::renderer::element::memory::MemoryRenderBufferRenderElement) requires
/// the [`Renderer`] to implement the [`ImportMem`](crate::backend::renderer::ImportMem) trait.
///
/// ```
/// use smithay::backend::renderer::{
///     element::{memory::MemoryRenderBufferRenderElement, render_elements},
///     ImportMem,
/// };
///
/// render_elements! {
///     MyRenderElements<R> where R: ImportMem;
///     Memory=MemoryRenderBufferRenderElement<R>,
/// }
/// ```
///
/// In case you want to use a reference or an element with an explicit lifetime the macro
/// additionally takes a lifetime on the defined enum.
///
/// ```
/// use smithay::backend::renderer::{
///     element::{memory::MemoryRenderBufferRenderElement, render_elements},
///     ImportMem,
/// };
///
/// render_elements! {
///     MyRenderElements<'a, R> where R: ImportMem;
///     Memory=&'a MemoryRenderBufferRenderElement<R>,
/// }
/// ```
///
/// Additionally the macro can be used to define generic enums
///
/// ```
/// use smithay::backend::renderer::{
///     element::{memory::MemoryRenderBufferRenderElement, render_elements},
///     ImportMem,
/// };
///
/// render_elements! {
///     MyRenderElements<'a, R, A, B> where R: ImportMem;
///     Memory=&'a MemoryRenderBufferRenderElement<R>,
///     Owned=A,
///     Borrowed=&'a B,
/// }
/// ```
///
/// If your elements require a specific [`Renderer`] instead of being
/// generic over it you can specify the type like in the following example.
///
/// ```
/// # use smithay::{
/// #     backend::{
/// #         allocator::Fourcc,
/// #         renderer::{Color32F, DebugFlags, Frame, Renderer, Texture, TextureFilter, sync::SyncPoint, gles::{GlesRenderer, GlesTexture}},
/// #     },
/// #     utils::{Buffer, Physical, Rectangle, Size, Transform},
/// # };
/// use smithay::backend::renderer::element::{render_elements, texture::TextureRenderElement};
///
/// render_elements! {
///     MyRenderElements<=GlesRenderer>;
///     Texture=TextureRenderElement<GlesTexture>,
/// }
/// ```
#[macro_export]
macro_rules! render_elements {
    ($(#[$attr:meta])* $vis:vis $name:ident<=$lt:lifetime, $renderer:ty, $custom:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name $lt $custom; $($tail)*);
        $crate::render_elements_internal!(@impl $name<=$renderer, $lt, $custom> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
        $crate::render_elements_internal!(@from $name<$lt, $custom>; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<=$lt:lifetime, $renderer:ty, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name $lt $($custom)+; $($tail)*);
        $crate::render_elements_internal!(@impl $name<=$renderer, $lt, $($custom)+> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<=$lt:lifetime, $renderer:ty>; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name $lt; $($tail)*);
        $crate::render_elements_internal!(@impl $name<=$renderer, $lt>; $($tail)*);
        $crate::render_elements_internal!(@from $name<$lt>; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<=$renderer:ty, $custom:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name $custom; $($tail)*);
        $crate::render_elements_internal!(@impl $name<=$renderer, $custom> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
        $crate::render_elements_internal!(@from $name<$custom>; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<=$renderer:ty, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name $custom1 $custom2; $($tail)*);
        $crate::render_elements_internal!(@impl $name<=$renderer, $($custom),+> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<=$renderer:ty>; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name; $($tail)*);
        $crate::render_elements_internal!(@impl $name<=$renderer>; $($tail)*);
        $crate::render_elements_internal!(@from $name; $($tail)*);
    };

    ($(#[$attr:meta])* $vis:vis $name:ident<$lt:lifetime, $renderer:ident, $custom:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name<$lt, $renderer, $custom>; $($tail)*);
        $crate::render_elements_internal!(@impl $name<$lt, $renderer, $custom> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
        $crate::render_elements_internal!(@from $name<$lt, $renderer, $custom>; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<$lt:lifetime, $renderer:ident, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name<$lt, $renderer, $($custom),+>; $($tail)*);
        $crate::render_elements_internal!(@impl $name<$lt, $renderer, $($custom),+> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<$lt:lifetime, $renderer:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name<$lt, $renderer>; $($tail)*);
        $crate::render_elements_internal!(@impl $name<$lt, $renderer> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
        $crate::render_elements_internal!(@from $name<$lt, $renderer>; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<$renderer:ident, $custom:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name<$renderer, $custom>; $($tail)*);
        $crate::render_elements_internal!(@impl $name<$renderer, $custom> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
        $crate::render_elements_internal!(@from $name<$renderer, $custom>; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<$renderer:ident, $($custom:ident),+> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name<$renderer, $($custom),+>; $($tail)*);
        $crate::render_elements_internal!(@impl $name<$renderer, $($custom),+> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident<$renderer:ident> $(where $($target:ty: $bound:tt $(+ $additional_bound:tt)*),+)?; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name<$renderer>; $($tail)*);
        $crate::render_elements_internal!(@impl $name<$renderer> $(where $($target: $bound $(+ $additional_bound)*),+)?; $($tail)*);
        $crate::render_elements_internal!(@from $name<$renderer>; $($tail)*);
    };
    ($(#[$attr:meta])* $vis:vis $name:ident; $($tail:tt)*) => {
        $crate::render_elements_internal!(@enum $(#[$attr])* $vis $name; $($tail)*);
        $crate::render_elements_internal!(@impl $name; R; $($tail)*);
        $crate::render_elements_internal!(@from $name; $($tail)*);
    };
}

pub use render_elements;

/// New-type wrapper for wrapping owned elements
/// in render_elements!
#[derive(Debug)]
pub struct Wrap<C>(C);

impl<C> From<C> for Wrap<C> {
    fn from(from: C) -> Self {
        Self(from)
    }
}

impl<C> Element for Wrap<C>
where
    C: Element,
{
    fn id(&self) -> &Id {
        self.0.id()
    }

    fn current_commit(&self) -> CommitCounter {
        self.0.current_commit()
    }

    fn location(&self, scale: Scale<f64>) -> Point<i32, Physical> {
        self.0.location(scale)
    }

    fn src(&self) -> Rectangle<f64, BufferCoords> {
        self.0.src()
    }

    fn transform(&self) -> Transform {
        self.0.transform()
    }

    fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
        self.0.geometry(scale)
    }

    fn damage_since(&self, scale: Scale<f64>, commit: Option<CommitCounter>) -> DamageSet<i32, Physical> {
        self.0.damage_since(scale, commit)
    }

    fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> {
        self.0.opaque_regions(scale)
    }

    fn alpha(&self) -> f32 {
        self.0.alpha()
    }

    fn kind(&self) -> Kind {
        self.0.kind()
    }
}

impl<R, C> RenderElement<R> for Wrap<C>
where
    R: Renderer,
    C: RenderElement<R>,
{
    fn draw(
        &self,
        frame: &mut R::Frame<'_, '_>,
        src: Rectangle<f64, BufferCoords>,
        dst: Rectangle<i32, Physical>,
        damage: &[Rectangle<i32, Physical>],
        opaque_regions: &[Rectangle<i32, Physical>],
    ) -> Result<(), R::Error> {
        self.0.draw(frame, src, dst, damage, opaque_regions)
    }

    #[inline]
    fn underlying_storage(&self, renderer: &mut R) -> Option<UnderlyingStorage<'_>> {
        self.0.underlying_storage(renderer)
    }
}

#[cfg(all(test, feature = "renderer_gl"))]
#[allow(dead_code)]
mod tests;