<NME> winit.rs
<BEF> use std::{sync::atomic::Ordering, time::Duration};

use slog::Logger;
#[cfg(feature = "debug")]
use smithay::backend::renderer::{gles2::Gles2Texture, ImportMem};
#[cfg(feature = "egl")]
use smithay::{
    backend::{
        allocator::dmabuf::Dmabuf,
        renderer::{ImportDma, ImportEgl},
    },
    delegate_dmabuf,
    wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportError},
};
use smithay::{
    backend::{
        renderer::gles2::Gles2Renderer,
        winit::{self, WinitEvent, WinitGraphicsBackend},
        SwapBuffersError,
    },
    desktop::space::RenderError,
    input::pointer::CursorImageStatus,
    output::{Mode, Output, PhysicalProperties, Subpixel},
    reexports::{
        calloop::EventLoop,
        wayland_server::{protocol::wl_surface, Display},
    },
    utils::{IsAlive, Transform},
    wayland::input_method::InputMethodSeat,
};

use crate::{
    drawing::*,
    state::{AnvilState, Backend, CalloopData},
};

pub const OUTPUT_NAME: &str = "winit";

pub struct WinitData {
    backend: WinitGraphicsBackend,
    #[cfg(feature = "egl")]
    dmabuf_state: Option<(DmabufState, DmabufGlobal)>,
    full_redraw: u8,
    #[cfg(feature = "debug")]
    fps_texture: Gles2Texture,
    #[cfg(feature = "debug")]
    pub fps: fps_ticker::Fps,
}


    fn dmabuf_imported(&mut self, _global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<(), ImportError> {
        self.backend_data
            .backend
            .renderer()
            .import_dmabuf(&dmabuf, None)
            .map(|_| ())
            .map_err(|_| ImportError::Failed)
    }
}
#[cfg(feature = "egl")]
delegate_dmabuf!(AnvilState<WinitData>);

impl Backend for WinitData {
    fn seat_name(&self) -> String {
        String::from("winit")
    }
    fn reset_buffers(&mut self, _output: &Output) {
        self.full_redraw = 4;
    }
    fn early_import(&mut self, _surface: &wl_surface::WlSurface) {}
}

pub fn run_winit(log: Logger) {
    let mut event_loop = EventLoop::try_new().unwrap();
    let mut display = Display::new().unwrap();

    #[cfg_attr(not(feature = "egl"), allow(unused_mut))]
    let (mut backend, mut winit) = match winit::init(log.clone()) {
        Ok(ret) => ret,
        Err(err) => {
            slog::crit!(log, "Failed to initialize Winit backend: {}", err);
            return;
        }
    };
    let size = backend.window_size().physical_size;

    let mode = Mode {
        size,
    };
    let size = backend.window_size().physical_size;

    let data = {
        #[cfg(feature = "egl")]
        let dmabuf_state = if backend.renderer().bind_wl_display(&display.handle()).is_ok() {
                dmabuf_formats,
                log.clone(),
            );
            Some((state, global))
        } else {
            None
        };

        let damage_tracked_renderer = DamageTrackedRenderer::from_output(&output);
        } else {
            None
        };
        #[cfg(feature = "debug")]
        let fps_image =
            image::io::Reader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png)
                .decode()
                .unwrap();

        #[cfg(feature = "debug")]
        let fps_texture = backend
            .renderer()
            .import_memory(
                &fps_image.to_rgba8(),
                (fps_image.width() as i32, fps_image.height() as i32).into(),
                false,
            )
            .expect("Unable to upload FPS texture");

        WinitData {
            backend,
            #[cfg(feature = "egl")]
            dmabuf_state,
            full_redraw: 0,
            #[cfg(feature = "debug")]
            fps_texture,
            #[cfg(feature = "debug")]
            fps: fps_ticker::Fps::default(),
        }
    };
    let mut state = AnvilState::init(&mut display, event_loop.handle(), data, log.clone(), true);

    let mode = Mode {
        size,
        refresh: 60_000,
    };
    let output = Output::new(
        OUTPUT_NAME.to_string(),
        PhysicalProperties {
            size: (0, 0).into(),
            subpixel: Subpixel::Unknown,
            make: "Smithay".into(),
            model: "Winit".into(),
        },
        log.clone(),
    );
    let _global = output.create_global::<AnvilState<WinitData>>(&display.handle());
    output.change_current_state(Some(mode), Some(Transform::Flipped180), None, Some((0, 0).into()));
    output.set_preferred(mode);
    state.space.map_output(&output, (0, 0));

    let start_time = std::time::Instant::now();

    while state.running.load(Ordering::SeqCst) {
        if winit
            .dispatch_new_events(|event| match event {
                WinitEvent::Resized { size, .. } => {
                    // We only have one output
                    let output = state.space.outputs().next().unwrap().clone();
                    state.space.map_output(&output, (0, 0));
                    let mode = Mode {
                        size,
                        refresh: 60_000,
                    };
                    output.change_current_state(Some(mode), None, None, None);
                    output.set_preferred(mode);
                    crate::shell::fixup_positions(&mut state.space);
                }
                WinitEvent::Input(event) => {
                    state.process_input_event_windowed(&display.handle(), event, OUTPUT_NAME)
                }
                _ => (),
            })
            .is_err()
        {
            state.running.store(false, Ordering::SeqCst);
            break;
        }

        // drawing logic
        {
            let backend = &mut state.backend_data.backend;

            let mut cursor_guard = state.cursor_status.lock().unwrap();

            // draw the cursor as relevant
            // reset the cursor if the surface is no longer alive
            let backend = &mut state.backend_data.backend;
            let cursor_visible: bool;

            let mut elements = Vec::<CustomElem<Gles2Renderer>>::new();
            let mut cursor_guard = state.cursor_status.lock().unwrap();

            // draw the dnd icon if any
            if let Some(surface) = state.dnd_icon.as_ref() {
                if surface.alive() {
                    elements.push(
                        draw_dnd_icon(surface.clone(), state.pointer_location.to_i32_round(), &log).into(),
                    );
                }
            }

            let space = &mut state.space;
            let damage_tracked_renderer = &mut state.backend_data.damage_tracked_renderer;

            let input_method = state.seat.input_method().unwrap();
            let dnd_icon = state.dnd_icon.as_ref();

            let scale = Scale::from(output.current_scale().fractional_scale());
            let cursor_hotspot = if let CursorImageStatus::Surface(ref surface) = *cursor_guard {
                compositor::with_states(surface, |states| {
                    states
                        .data_map
                        .get::<Mutex<CursorImageAttributes>>()
                        .unwrap()
                        .lock()
                        .unwrap()
                        .hotspot
                })
            } else {
                (0, 0).into()
            };
            let cursor_pos = state.pointer_location - cursor_hotspot.to_f64();
            let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round();

            let render_res = backend.bind().and_then(|_| {
            }
            if let CursorImageStatus::Surface(ref surface) = *cursor_guard {
                cursor_visible = false;
                elements
                    .push(draw_cursor(surface.clone(), state.pointer_location.to_i32_round(), &log).into());
            } else {
                cursor_visible = true;
            }

            // draw FPS
            #[cfg(feature = "debug")]
            {
                let fps = state.backend_data.fps.avg().round() as u32;
                let fps_texture = &state.backend_data.fps_texture;
                elements.push(draw_fps::<Gles2Renderer>(fps_texture, fps).into());
            }

            let full_redraw = &mut state.backend_data.full_redraw;
            *full_redraw = full_redraw.saturating_sub(1);
                            &smithay::desktop::space::SurfaceTree::from_surface(surface),
                            cursor_pos_scaled,
                            scale,
                backend.buffer_age().unwrap_or(0)
            };
            let space = &mut state.space;
            let render_res = backend.bind().and_then(|_| {
                let renderer = backend.renderer();
                crate::render::render_output(&output, space, renderer, age, &*elements, &log).map_err(|err| {
                    match err {
                        RenderError::Rendering(err) => err.into(),
                        _ => unreachable!(),
                    }
                })
            });

            match render_res {
            }
        }

        let mut calloop_data = CalloopData { state, display };
        let result = event_loop.dispatch(Some(Duration::from_millis(16)), &mut calloop_data);
        CalloopData { state, display } = calloop_data;

        if result.is_err() {
            state.running.store(false, Ordering::SeqCst);
        } else {
            state.space.refresh();
            state.popups.cleanup();
            display.flush_clients().unwrap();
        }

        #[cfg(feature = "debug")]
        state.backend_data.fps.tick();
    }
}
        state.backend_data.fps.tick();
    }
}

<MSG> re-enable winit backend

<DFF> @@ -1,8 +1,11 @@
-use std::{sync::atomic::Ordering, time::Duration};
+use std::{
+    sync::{atomic::Ordering, Mutex},
+    time::Duration,
+};
 
 use slog::Logger;
-#[cfg(feature = "debug")]
-use smithay::backend::renderer::{gles2::Gles2Texture, ImportMem};
+#[cfg(not(feature = "debug"))]
+use smithay::desktop::space::SpaceRenderElements;
 #[cfg(feature = "egl")]
 use smithay::{
     backend::{
@@ -14,36 +17,41 @@ use smithay::{
 };
 use smithay::{
     backend::{
-        renderer::gles2::Gles2Renderer,
+        renderer::{
+            output::{element::surface::WaylandSurfaceRenderElement, OutputRender},
+            ImportMem, Renderer,
+        },
         winit::{self, WinitEvent, WinitGraphicsBackend},
         SwapBuffersError,
     },
-    desktop::space::RenderError,
-    input::pointer::CursorImageStatus,
+    desktop::space::SurfaceTree,
+    input::pointer::{CursorImageAttributes, CursorImageStatus},
     output::{Mode, Output, PhysicalProperties, Subpixel},
     reexports::{
         calloop::EventLoop,
-        wayland_server::{protocol::wl_surface, Display},
+        wayland_server::{
+            protocol::{wl_output, wl_surface},
+            Display,
+        },
     },
+    utils::IsAlive,
     utils::{IsAlive, Transform},
     wayland::input_method::InputMethodSeat,
+    wayland::{compositor, input_method::InputMethodSeat},
 };
 
-use crate::{
-    drawing::*,
-    state::{AnvilState, Backend, CalloopData},
-};
+use crate::drawing::*;
+use crate::state::{AnvilState, Backend, CalloopData};
 
 pub const OUTPUT_NAME: &str = "winit";
 
 pub struct WinitData {
     backend: WinitGraphicsBackend,
+    output_render: OutputRender,
     #[cfg(feature = "egl")]
     dmabuf_state: Option<(DmabufState, DmabufGlobal)>,
     full_redraw: u8,
     #[cfg(feature = "debug")]
-    fps_texture: Gles2Texture,
-    #[cfg(feature = "debug")]
     pub fps: fps_ticker::Fps,
 }
 
@@ -89,6 +97,41 @@ pub fn run_winit(log: Logger) {
     };
     let size = backend.window_size().physical_size;
 
+    let mode = Mode {
+        size,
+        refresh: 60_000,
+    };
+    let output = Output::new(
+        OUTPUT_NAME.to_string(),
+        PhysicalProperties {
+            size: (0, 0).into(),
+            subpixel: Subpixel::Unknown,
+            make: "Smithay".into(),
+            model: "Winit".into(),
+        },
+        log.clone(),
+    );
+    let _global = output.create_global::<AnvilState<WinitData>>(&display.handle());
+    output.change_current_state(Some(mode), Some(Transform::Flipped180), None, Some((0, 0).into()));
+    output.set_preferred(mode);
+
+    #[cfg(feature = "debug")]
+    let fps_image =
+        image::io::Reader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png)
+            .decode()
+            .unwrap();
+    #[cfg(feature = "debug")]
+    let fps_texture = backend
+        .renderer()
+        .import_memory(
+            &fps_image.to_rgba8(),
+            (fps_image.width() as i32, fps_image.height() as i32).into(),
+            false,
+        )
+        .expect("Unable to upload FPS texture");
+    #[cfg(feature = "debug")]
+    let mut fps_element = FpsElement::new(fps_texture);
+
     let data = {
         #[cfg(feature = "egl")]
         let dmabuf_state = if backend.renderer().bind_wl_display(&display.handle()).is_ok() {
@@ -104,52 +147,20 @@ pub fn run_winit(log: Logger) {
         } else {
             None
         };
-        #[cfg(feature = "debug")]
-        let fps_image =
-            image::io::Reader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png)
-                .decode()
-                .unwrap();
 
-        #[cfg(feature = "debug")]
-        let fps_texture = backend
-            .renderer()
-            .import_memory(
-                &fps_image.to_rgba8(),
-                (fps_image.width() as i32, fps_image.height() as i32).into(),
-                false,
-            )
-            .expect("Unable to upload FPS texture");
+        let output_render = OutputRender::new(&output);
 
         WinitData {
             backend,
+            output_render,
             #[cfg(feature = "egl")]
             dmabuf_state,
             full_redraw: 0,
             #[cfg(feature = "debug")]
-            fps_texture,
-            #[cfg(feature = "debug")]
             fps: fps_ticker::Fps::default(),
         }
     };
     let mut state = AnvilState::init(&mut display, event_loop.handle(), data, log.clone(), true);
-
-    let mode = Mode {
-        size,
-        refresh: 60_000,
-    };
-    let output = Output::new(
-        OUTPUT_NAME.to_string(),
-        PhysicalProperties {
-            size: (0, 0).into(),
-            subpixel: Subpixel::Unknown,
-            make: "Smithay".into(),
-            model: "Winit".into(),
-        },
-        log.clone(),
-    );
-    let _global = output.create_global::<AnvilState<WinitData>>(&display.handle());
-    output.change_current_state(Some(mode), Some(Transform::Flipped180), None, Some((0, 0).into()));
-    output.set_preferred(mode);
     state.space.map_output(&output, (0, 0));
 
     let start_time = std::time::Instant::now();
@@ -191,15 +202,18 @@ pub fn run_winit(log: Logger) {
             let backend = &mut state.backend_data.backend;
             let cursor_visible: bool;
 
-            let mut elements = Vec::<CustomElem<Gles2Renderer>>::new();
+            let mut elements = Vec::<CustomSpaceElements>::new();
             let mut cursor_guard = state.cursor_status.lock().unwrap();
 
             // draw the dnd icon if any
             if let Some(surface) = state.dnd_icon.as_ref() {
                 if surface.alive() {
-                    elements.push(
-                        draw_dnd_icon(surface.clone(), state.pointer_location.to_i32_round(), &log).into(),
-                    );
+                    elements.push(CustomSpaceElements::SurfaceTree(
+                        smithay::desktop::space::SurfaceTree::from_surface(
+                            surface,
+                            state.pointer_location.to_i32_round(),
+                        ),
+                    ));
                 }
             }
 
@@ -230,19 +244,30 @@ pub fn run_winit(log: Logger) {
             }
             if let CursorImageStatus::Surface(ref surface) = *cursor_guard {
                 cursor_visible = false;
-                elements
-                    .push(draw_cursor(surface.clone(), state.pointer_location.to_i32_round(), &log).into());
+                let hotspot = compositor::with_states(surface, |states| {
+                    states
+                        .data_map
+                        .get::<Mutex<CursorImageAttributes>>()
+                        .unwrap()
+                        .lock()
+                        .unwrap()
+                        .hotspot
+                });
+
+                elements.push(CustomSpaceElements::SurfaceTree(
+                    smithay::desktop::space::SurfaceTree::from_surface(
+                        surface,
+                        state.pointer_location.to_i32_round() - hotspot,
+                    ),
+                ));
             } else {
                 cursor_visible = true;
             }
 
-            // draw FPS
             #[cfg(feature = "debug")]
-            {
-                let fps = state.backend_data.fps.avg().round() as u32;
-                let fps_texture = &state.backend_data.fps_texture;
-                elements.push(draw_fps::<Gles2Renderer>(fps_texture, fps).into());
-            }
+            let fps = state.backend_data.fps.avg().round() as u32;
+            #[cfg(feature = "debug")]
+            fps_element.update_fps(fps);
 
             let full_redraw = &mut state.backend_data.full_redraw;
             *full_redraw = full_redraw.saturating_sub(1);
@@ -252,14 +277,39 @@ pub fn run_winit(log: Logger) {
                 backend.buffer_age().unwrap_or(0)
             };
             let space = &mut state.space;
+            let output_render = &mut state.backend_data.output_render;
             let render_res = backend.bind().and_then(|_| {
                 let renderer = backend.renderer();
-                crate::render::render_output(&output, space, renderer, age, &*elements, &log).map_err(|err| {
-                    match err {
-                        RenderError::Rendering(err) => err.into(),
-                        _ => unreachable!(),
-                    }
-                })
+
+                #[cfg(feature = "debug")]
+                let res = smithay::desktop::space::render_output::<_, _, CustomRenderElements<'_, _>>(
+                    renderer,
+                    age,
+                    &[(&space, &*elements)],
+                    &[CustomRenderElements::Fps(&fps_element)],
+                    output_render,
+                    &log,
+                )
+                .map_err(|err| match err {
+                    smithay::backend::renderer::output::OutputRenderError::Rendering(err) => err.into(),
+                    _ => unreachable!(),
+                });
+
+                #[cfg(not(feature = "debug"))]
+                let res = smithay::desktop::space::render_output::<_, _, SpaceRenderElements<_>>(
+                    renderer,
+                    age,
+                    &[(&space, &*elements)],
+                    &[],
+                    output_render,
+                    &log,
+                )
+                .map_err(|err| match err {
+                    smithay::backend::renderer::output::OutputRenderError::Rendering(err) => err.into(),
+                    _ => unreachable!(),
+                });
+
+                res
             });
 
             match render_res {
@@ -297,3 +347,18 @@ pub fn run_winit(log: Logger) {
         state.backend_data.fps.tick();
     }
 }
+
+#[cfg(feature = "debug")]
+smithay::backend::renderer::output::element::render_elements! {
+    pub CustomRenderElements<'a, R>;
+    Surface=smithay::backend::renderer::output::element::surface::WaylandSurfaceRenderElement,
+    Texture=smithay::backend::renderer::output::element::texture::TextureRenderElement<<R as Renderer>::TextureId>,
+    Fps=&'a FpsElement<<R as Renderer>::TextureId>
+}
+
+smithay::desktop::space::space_elements! {
+    CustomSpaceElements[
+        WaylandSurfaceRenderElement,
+    ];
+    SurfaceTree=SurfaceTree,
+}

re-enable winit backend