<NME> udev.rs
<BEF> use std::{
    borrow::Cow,
    cell::RefCell,
    collections::hash_map::{Entry, HashMap},
    os::unix::io::{AsRawFd, RawFd},
    path::PathBuf,
    rc::Rc,
    sync::{atomic::Ordering, Mutex},
    time::Duration,
};

use glium::Surface as GliumSurface;
use slog::Logger;

#[cfg(feature = "egl")]
use smithay::backend::egl::{display::EGLBufferReader, EGLGraphicsBackend};
use smithay::{
    backend::{
        drm_old::{
            atomic::{AtomicDrmDevice, AtomicDrmSurface},
            common::fallback::{FallbackDevice, FallbackSurface},
            device_bind,
            egl::{EglDevice, EglSurface},
            eglstream::{egl::EglStreamDeviceBackend, EglStreamDevice, EglStreamSurface},
            gbm::{egl::Gbm as EglGbmBackend, GbmDevice, GbmSurface},
            legacy::{LegacyDrmDevice, LegacyDrmSurface},
            DevPath, Device, DeviceHandler, Surface,
        },
        graphics::{CursorBackend, SwapBuffersError},
        libinput::{LibinputInputBackend, LibinputSessionInterface},
        session::{auto::AutoSession, Session, Signal as SessionSignal},
        udev::{primary_gpu, UdevBackend, UdevEvent},
        renderer::{
            damage::{DamageTrackedRenderer, DamageTrackedRendererError},
            element::{texture::TextureBuffer, AsRenderElements, RenderElementStates},
            gles2::{Gles2Renderbuffer, Gles2Renderer},
            multigpu::{egl::EglGlesBackend, GpuManager, MultiRenderer, MultiTexture},
            Bind, Frame, Renderer,
        },
        drm::{
            self,
            control::{
                connector::{Info as ConnectorInfo, State as ConnectorState},
                crtc,
                encoder::Info as EncoderInfo,
            },
        },
        image::{ImageBuffer, Rgba},
        input::Libinput,
        nix::{fcntl::OFlag, sys::stat::dev_t},
        wayland_server::{
            self,
            control::{
                connector::{Info as ConnectorInfo, State as ConnectorState},
                crtc,
                encoder::Info as EncoderInfo,
                Device as ControlDevice,
            },
        },
        gbm::Device as GbmDevice,
        input::Libinput,
        nix::{fcntl::OFlag, sys::stat::dev_t},
};

use crate::buffer_utils::BufferUtils;
use crate::glium_drawer::{schedule_initial_render, GliumDrawer};
use crate::shell::{MyWindowMap, Roles};
use crate::state::AnvilState;

#[derive(Clone)]
pub struct SessionFd(RawFd);
    },
};

    }
}

type RenderDevice = FallbackDevice<
    EglDevice<
        EglGbmBackend<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
        GbmDevice<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
    >,
    EglDevice<
        EglStreamDeviceBackend<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
        EglStreamDevice<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
    >,
>;
type RenderSurface = FallbackSurface<
    EglSurface<GbmSurface<FallbackSurface<AtomicDrmSurface<SessionFd>, LegacyDrmSurface<SessionFd>>>>,
    EglSurface<EglStreamSurface<FallbackSurface<AtomicDrmSurface<SessionFd>, LegacyDrmSurface<SessionFd>>>>,
>;

pub fn run_udev(
    display: Rc<RefCell<Display>>,
    event_loop: &mut EventLoop<AnvilState>,
    fn as_raw_fd(&self) -> RawFd {
        self.0
    }
}

#[derive(Debug, PartialEq)]
struct UdevOutputId {
    device_id: DrmNode,
    info!(log, "Listening on wayland socket"; "name" => name.clone());
    ::std::env::set_var("WAYLAND_DISPLAY", name);

    #[cfg(feature = "egl")]
    let egl_buffer_reader = Rc::new(RefCell::new(None));

    #[cfg(feature = "egl")]
    let buffer_utils = BufferUtils::new(egl_buffer_reader.clone(), log.clone());
    #[cfg(not(feature = "egl"))]
    let buffer_utils = BufferUtils::new(log.clone());

    let output_map = Rc::new(RefCell::new(Vec::new()));
    fps_texture: MultiTexture,
    signaler: Signaler<SessionSignal>,
    pointer_image: crate::cursor::Cursor,
    logger: slog::Logger,
}

#[cfg(feature = "egl")]
impl DmabufHandler for AnvilState<UdevData> {
    fn dmabuf_state(&mut self) -> &mut DmabufState {
        &mut self.backend_data.dmabuf_state.as_mut().unwrap().0
    }

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

impl Backend for UdevData {
    fn seat_name(&self) -> String {
        self.session.seat()
    }

    fn reset_buffers(&mut self, output: &Output) {
        if let Some(id) = output.user_data().get::<UdevOutputId>() {
            if let Some(gpu) = self.backends.get(&id.device_id) {
                let surfaces = gpu.surfaces.borrow();
                if let Some(surface) = surfaces.get(&id.crtc) {
                    surface.borrow_mut().surface.reset_buffers();
                }
            }
        }
    }

    fn early_import(&mut self, surface: &wl_surface::WlSurface) {
        if let Err(err) = self
            .gpus
            .early_import(Some(self.primary_gpu), self.primary_gpu, surface)
        {
            warn!(self.logger, "Early buffer import failed: {}", err);
        }
    }
}

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

    /*
     * Initialize session
     */
    let (session, notifier) = match AutoSession::new(log.clone()) {
        Some(ret) => ret,
        None => {
            crit!(log, "Could not initialize a session");
            return;
        }
    };
    let session_signal = notifier.signaler();

    /*
     * Initialize the compositor
     */
    let primary_gpu = if let Ok(var) = std::env::var("ANVIL_DRM_DEVICE") {
        DrmNode::from_path(var).expect("Invalid drm device path")
    } else {
        primary_gpu(&session.seat())
            .unwrap()
            .and_then(|x| DrmNode::from_path(x).ok()?.node_with_type(NodeType::Render)?.ok())
            .unwrap_or_else(|| {
                all_gpus(&session.seat())
                    .unwrap()
                    .into_iter()
                    .find_map(|x| DrmNode::from_path(x).ok())
                    .expect("No GPU!")
            })
    };
    info!(log, "Using {} as primary gpu.", primary_gpu);

    #[cfg_attr(not(feature = "egl"), allow(unused_mut))]
    let mut gpus = GpuManager::new(EglGlesBackend::default(), log.clone()).unwrap();
    #[cfg_attr(not(feature = "egl"), allow(unused_mut))]
    #[cfg(any(feature = "egl", feature = "debug"))]
    let mut renderer = gpus
        .renderer::<Gles2Renderbuffer>(&primary_gpu, &primary_gpu)
        .unwrap();

    #[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 = 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");

    // init dmabuf support with format list from our primary gpu
    // TODO: This does not necessarily depend on egl, but mesa makes no use of it without wl_drm right now
    #[cfg(feature = "egl")]
    let dmabuf_state = {
        info!(
            log,
            "Trying to initialize EGL Hardware Acceleration via {:?}", primary_gpu
        );

        if renderer.bind_wl_display(&display.handle()).is_ok() {
            info!(log, "EGL hardware-acceleration enabled");
            let dmabuf_formats = renderer.dmabuf_formats().cloned().collect::<Vec<_>>();
            let mut state = DmabufState::new();
            let global = state.create_global::<AnvilState<UdevData>, _>(
                &display.handle(),
                dmabuf_formats,
                log.clone(),
            );
            Some((state, global))
        } else {
            None
        }
    };

    let data = UdevData {
        dh: display.handle(),
        #[cfg(feature = "egl")]
        dmabuf_state,
        session,
        primary_gpu,
        gpus,
        backends: HashMap::new(),
        signaler: session_signal.clone(),
        pointer_image: crate::cursor::Cursor::load(&log),
        pointer_images: Vec::new(),
        pointer_element: PointerElement::default(),
        #[cfg(feature = "debug")]
        fps_texture,
        logger: log.clone(),
    };
    let mut state = AnvilState::init(&mut display, event_loop.handle(), data, log.clone(), true);

    /*
     * Initialize the udev backend
     */
    let udev_backend = match UdevBackend::new(&state.seat_name, log.clone()) {
        Ok(ret) => ret,
        Err(err) => {
            crit!(log, "Failed to initialize udev backend"; "error" => err);
            return;
        }
    };

    /*
     * Initialize a fake output (we render one screen to every device in this example)
     */

    /*
     * Initialize libinput backend
     */
    let mut libinput_context = Libinput::new_with_udev::<LibinputSessionInterface<AutoSession>>(
        state.backend_data.session.clone().into(),
    );
    libinput_context.udev_assign_seat(&state.seat_name).unwrap();
    let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
    libinput_backend.link(session_signal);
    }
}

struct BackendData {
    _restart_token: SignalToken,
    event_source: Source<Generic<RenderDevice>>,
    surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>,
}

struct UdevHandlerImpl<Data: 'static> {
    compositor_token: CompositorToken<Roles>,
    buffer_utils: BufferUtils,
    #[cfg(feature = "egl")]
    egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
    session: AutoSession,
    backends: HashMap<dev_t, BackendData>,
    display: Rc<RefCell<Display>>,
            UdevEvent::Added { device_id, path } => {
                data.state.device_added(&mut data.display, device_id, path)
            }
            UdevEvent::Changed { device_id } => data.state.device_changed(&mut data.display, device_id),
            UdevEvent::Removed { device_id } => data.state.device_removed(device_id),
        })
        .unwrap();

    /*
     * Start XWayland if supported
     */

impl<Data: 'static> UdevHandlerImpl<Data> {
    pub fn scan_connectors(
        device: &mut RenderDevice,
        buffer_utils: &BufferUtils,
        display: &mut Display,
        output_map: &mut Vec<MyOutput>,
        logger: &::slog::Logger,
    ) -> HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>> {
        // Get a set of all modesetting resource handles (excluding planes):
        let res_handles = device.resource_handles().unwrap();

            state.space.refresh();
        let connector_infos: Vec<ConnectorInfo> = res_handles
            .connectors()
            .iter()
            .map(|conn| device.get_connector_info(*conn).unwrap())
            .filter(|conn| conn.state() == ConnectorState::Connected)
            .inspect(|conn| info!(logger, "Connected: {:?}", conn.interface()))
            .collect();

struct SurfaceData {
    dh: DisplayHandle,
    device_id: DrmNode,
    render_node: DrmNode,
    surface: RenderSurface,
                .encoders()
                .iter()
                .filter_map(|e| *e)
                .flat_map(|encoder_handle| device.get_encoder_info(encoder_handle))
                .collect::<Vec<EncoderInfo>>();
            'outer: for encoder_info in encoder_infos {
                for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
                    if let Entry::Vacant(entry) = backends.entry(crtc) {
                        let renderer = GliumDrawer::init(
                            device
                                .create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()])
                                .unwrap(),
                            buffer_utils.clone(),
                            logger.clone(),
                        );
                        output_map.push(MyOutput::new(
                            display,
                            device.device_id(),
        (node, context.dmabuf_render_formats().clone())
    };
                            logger.clone(),
                        ));

                        entry.insert(Rc::new(renderer));
                        break 'outer;
                    }
                }
            .collect::<Vec<EncoderInfo>>();

        let crtcs = encoder_infos
            .iter()
            .flat_map(|encoder_info| res_handles.filter_crtcs(encoder_info.possible_crtcs()));

        for crtc in crtcs {
impl<Data: 'static> UdevHandlerImpl<Data> {
    fn device_added(&mut self, device_id: dev_t, path: PathBuf) {
        // Try to open the device
        if let Some(mut device) = self
            .session
            .open(
                &path,
                logger,
            )
            .ok()
            .and_then(|fd| {
                match FallbackDevice::<AtomicDrmDevice<_>, LegacyDrmDevice<_>>::new(
                    SessionFd(fd),
                    true,
                    self.logger.clone(),
                ) {
                    Ok(drm) => Some(drm),
                    Err(err) => {
                        warn!(self.logger, "Skipping drm device, because of error: {}", err);
                        None
                    }
                }
            })
            .and_then(|drm| {
                match FallbackDevice::<GbmDevice<_>, EglStreamDevice<_>>::new(drm, self.logger.clone()) {
                    Ok(dev) => Some(dev),
                    Err(err) => {
                        warn!(self.logger, "Skipping device, because of error: {}", err);
                        None
                    }
                }
            })
            .and_then(|dev| match FallbackDevice::new_egl(dev, self.logger.clone()) {
                Ok(egl) => Some(egl),
                Err(err) => {
                    warn!(self.logger, "Skipping egl device, because of error: {}", err);
                    None
                }
            })
        {
            // init hardware acceleration on the primary gpu.
            #[cfg(feature = "egl")]
            {
                if path.canonicalize().ok() == self.primary_gpu {
                drm::control::connector::Interface::SVideo => Cow::Borrowed("S-VIDEO"),
                drm::control::connector::Interface::DisplayPort => Cow::Borrowed("DP"),
                drm::control::connector::Interface::HDMIA => Cow::Borrowed("HDMI-A"),
                drm::control::connector::Interface::HDMIB => Cow::Borrowed("HDMI-B"),
                drm::control::connector::Interface::EmbeddedDisplayPort => Cow::Borrowed("eDP"),
                        device.bind_wl_display(&*self.display.borrow()).ok();
                }
            }

            let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
                &mut device,
                &self.buffer_utils,
                &mut *self.display.borrow_mut(),
                &mut *self.output_map.borrow_mut(),
            output
                .user_data()
                .insert_if_missing(|| UdevOutputId { crtc, device_id });

            let damage_tracked_renderer = DamageTrackedRenderer::from_output(&output);
            #[cfg(feature = "debug")]
            let fps_element = FpsElement::new(fps_texture.clone());

            entry.insert(Rc::new(RefCell::new(SurfaceData {
                dh: display.handle(),
                device_id,
                render_node,
                surface: gbm_surface,
                global: Some(global),
                damage_tracked_renderer,
                #[cfg(feature = "debug")]
                fps: fps_ticker::Fps::default(),
                #[cfg(feature = "debug")]
                fps_element,
            })));

            break;
        }
    }

    backends
}

impl AnvilState<UdevData> {
    fn device_added(&mut self, display: &mut Display<Self>, device_id: dev_t, path: PathBuf) {
        // Try to open the device
        let open_flags = OFlag::O_RDWR | OFlag::O_CLOEXEC | OFlag::O_NOCTTY | OFlag::O_NONBLOCK;
        let device_fd = self.backend_data.session.open(&path, open_flags).ok();
        let devices = device_fd
            .map(SessionFd)
                .map_err(|e| -> IoError { e.into() })
                .unwrap();

            for renderer in backends.borrow_mut().values() {
                // render first frame
                schedule_initial_render(renderer.clone(), &self.loop_handle);
            }

            self.backends.insert(
            }
            Some((_, Err(err))) => {
                    _restart_token: restart_token,
                    event_source,
                    surfaces: backends,
                },
            );
        }

        let gbm = Rc::new(RefCell::new(gbm));
        let node = match DrmNode::from_dev_id(device_id) {
        //quick and dirty, just re-init all backends
        let buffer_utils = &self.buffer_utils;
        if let Some(ref mut backend_data) = self.backends.get_mut(&device) {
            let logger = &self.logger;
            let loop_handle = self.loop_handle.clone();
            let mut display = self.display.borrow_mut();
            let mut output_map = self.output_map.borrow_mut();
            node,
            &device,
            &gbm,
                    let mut backends = backend_data.surfaces.borrow_mut();
                    *backends = UdevHandlerImpl::<Data>::scan_connectors(
                        &mut source.file,
                        buffer_utils,
                        &mut *display,
                        &mut *output_map,
                        logger,
                    );

                    for renderer in backends.values() {
                        // render first frame
                        schedule_initial_render(renderer.clone(), &loop_handle);
                    }
                });
        }
                DrmEvent::VBlank(crtc) => data.state.render(node, Some(crtc)),
                DrmEvent::Error(error) => {
                    error!(data.state.log, "{:?}", error);
                }
            });
        let registration_token = self.handle.register_dispatcher(event_dispatcher.clone()).unwrap();

        for backend in backends.borrow_mut().values() {
            // render first frame
            trace!(self.log, "Scheduling frame");
            schedule_initial_render(
                &mut self.backend_data.gpus,
                backend.clone(),
                &self.handle,
                self.log.clone(),
            );
        }

        self.backend_data.backends.insert(
            node,
            BackendData {
                _restart_token: restart_token,
                registration_token,
                event_dispatcher,
                surfaces: backends,
                gbm,
            },
        );
    }

}

impl<Data: 'static> DeviceHandler for DrmHandlerImpl<Data> {
    type Device = RenderDevice;

    fn vblank(&mut self, crtc: crtc::Handle) {
        self.renderer.clone().render(crtc, None, Some(&self.loop_handle))
    }

    fn error(&mut self, error: <RenderSurface as Surface>::Error) {
        error!(self.renderer.logger, "{:?}", error);
    }
}

            // scan_connectors will recreate the outputs (and sadly also reset the scales)
            for output in self
                .space
                .outputs()
                .filter(|o| {
                    o.user_data()
                        .get::<UdevOutputId>()
                        .map(|id| id.device_id == node)
                        .unwrap_or(false)
                })
                .cloned()
                .collect::<Vec<_>>()
                .into_iter()
            {
                self.space.unmap_output(&output);
pub struct DrmRenderer {
    device_id: dev_t,
    compositor_token: CompositorToken<Roles>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>,
    window_map: Rc<RefCell<MyWindowMap>>,
    output_map: Rc<RefCell<Vec<MyOutput>>>,
    pointer_location: Rc<RefCell<(f64, f64)>>,
                &backend_data.gbm,
                display,
                &mut self.space,
                #[cfg(feature = "debug")]
                &self.backend_data.fps_texture,
                &signaler,
                &logger,
            );

            // fixup window coordinates
            crate::shell::fixup_positions(&mut self.space);

            for surface in backends.values() {
                let logger = logger.clone();
                // render first frame
                schedule_initial_render(&mut self.backend_data.gpus, surface.clone(), &loop_handle, logger);
        timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>,
        evt_handle: Option<&LoopHandle<Data>>,
    ) {
        if let Some(drawer) = self.backends.borrow().get(&crtc) {
            // get output coordinates
            let (x, y) = self
                .output_map
                .borrow()
                .iter()
                .take_while(|output| output.device_id != self.device_id || output.crtc != crtc)
                .fold((0u32, 0u32), |pos, output| (pos.0 + output.size.0, pos.1));
            let (width, height) = self
                .output_map
                .borrow()
                .iter()
                .find(|output| output.device_id == self.device_id && output.crtc == crtc)
                .map(|output| output.size)
                .unwrap_or((0, 0)); // in this case the output will be removed.

            // and draw in sync with our monitor
            let mut frame = drawer.draw();
            frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None);
            // draw the surfaces
            drawer.draw_windows(
                &mut frame,
                &*self.window_map.borrow(),
                Some(Rectangle {
                    x: x as i32,
                    y: y as i32,
                    width: width as i32,
                    height: height as i32,
                }),
                self.compositor_token,
            );

            // get pointer coordinates
            let (ptr_x, ptr_y) = *self.pointer_location.borrow();
            let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
            let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;

            // set cursor
            if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
                let _ = drawer.borrow().set_cursor_position(ptr_x as u32, ptr_y as u32);

                // draw the dnd icon if applicable
                {
                    let guard = self.dnd_icon.lock().unwrap();
                    if let Some(ref surface) = *guard {
                        if surface.as_ref().is_alive() {
                            drawer.draw_dnd_icon(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token);
                        }
                    }
                }
                // draw the cursor as relevant
                {
                    let mut guard = self.cursor_status.lock().unwrap();
                    // reset the cursor if the surface is no longer alive
                    let mut reset = false;
                    if let CursorImageStatus::Image(ref surface) = *guard {
                        reset = !surface.as_ref().is_alive();
                    }
                    if reset {
                        *guard = CursorImageStatus::Default;
                    }
                    if let CursorImageStatus::Image(ref surface) = *guard {
                        drawer.draw_software_cursor(
                            &mut frame,
                            surface,
                            (ptr_x, ptr_y),
                            self.compositor_token,
                        );
                    } else {
                        drawer.draw_hardware_cursor(&self.pointer_image, (2, 2), (ptr_x, ptr_y));
                    }
                }
            } else {
                drawer.clear_cursor();
            }

            if let Err(err) = frame.finish() {
                warn!(self.logger, "Error during rendering: {:?}", err);
                let reschedule =
                    match err {
                        SwapBuffersError::AlreadySwapped => false,
                        SwapBuffersError::TemporaryFailure(err) => {
                            match err.downcast_ref::<smithay::backend::drm_old::common::Error>() {
                                Some(&smithay::backend::drm_old::common::Error::DeviceInactive) => false,
                                Some(&smithay::backend::drm_old::common::Error::Access {
                                    ref source, ..
                                }) if matches!(source.get_ref(), drm::SystemError::PermissionDenied) => false,
                                _ => true,
                            }
                        }
            }
            crate::shell::fixup_positions(&mut self.space);

            self.handle.remove(backend_data.registration_token);
            let _device = backend_data.event_dispatcher.into_source_inner();

            debug!(self.log, "Dropping device");
        }
    }

    // If crtc is `Some()`, render it, else render all crtcs
    fn render(&mut self, dev_id: DrmNode, crtc: Option<crtc::Handle>) {
        let device_backend = match self.backend_data.backends.get_mut(&dev_id) {
            Some(backend) => backend,
            None => {
                error!(self.log, "Trying to render on non-existent backend {}", dev_id);
                return;
            }
        };
        // setup two iterators on the stack, one over all surfaces for this backend, and
        // one containing only the one given as argument.
        // They make a trait-object to dynamically choose between the two
        let surfaces = device_backend.surfaces.borrow();
        let mut surfaces_iter = surfaces.iter();
        let mut option_iter = crtc
            .iter()
            .flat_map(|crtc| surfaces.get(crtc).map(|surface| (crtc, surface)));

        let to_render_iter: &mut dyn Iterator<Item = (&crtc::Handle, &Rc<RefCell<SurfaceData>>)> =
            if crtc.is_some() {
                &mut option_iter
            } else {
                &mut surfaces_iter
            };

        let mut outputs = Vec::new();
        for (&crtc, surface) in to_render_iter {
            // TODO get scale from the rendersurface when supporting HiDPI
            let frame = self
                .backend_data
            }
        }
    }
}
            }
        }

        std::mem::drop(surfaces);
        for (output, states) in outputs {
            // Send frame events so that client start drawing their next frame
            self.send_frames(&output, &states);
        }
    }
}

#[allow(clippy::too_many_arguments)]
fn render_surface<'a>(
    surface: &'a mut SurfaceData,
    renderer: &mut UdevRenderer<'a>,
    space: &mut Space<Window>,
    output: &Output,
    input_method: &InputMethodHandle,
    pointer_location: Point<f64, Logical>,
    pointer_image: &TextureBuffer<MultiTexture>,
    pointer_element: &mut PointerElement<MultiTexture>,
    dnd_icon: &Option<wl_surface::WlSurface>,
    cursor_status: &mut CursorImageStatus,
    logger: &slog::Logger,
) -> Result<(bool, RenderElementStates), SwapBuffersError> {
    surface.surface.frame_submitted()?;

    let output_geometry = space.output_geometry(output).unwrap();
    let scale = Scale::from(output.current_scale().fractional_scale());

    let (dmabuf, age) = surface.surface.next_buffer()?;
    renderer.bind(dmabuf)?;

    let mut elements: Vec<CustomRenderElements<_>> = Vec::new();
    // draw input method surface if any
    let rectangle = input_method.coordinates();
    let position = Point::from((
        rectangle.loc.x + rectangle.size.w,
        rectangle.loc.y + rectangle.size.h,
    ));
    input_method.with_surface(|surface| {
        elements.extend(AsRenderElements::<UdevRenderer<'a>>::render_elements(
            &SurfaceTree::from_surface(surface),
            position.to_physical_precise_round(scale),
            scale,
        ));
    });

    if output_geometry.to_f64().contains(pointer_location) {
        let cursor_hotspot = if let CursorImageStatus::Surface(ref surface) = cursor_status {
            compositor::with_states(surface, |states| {
                states
                    .data_map
                    .get::<Mutex<CursorImageAttributes>>()
                    .unwrap()
                    .lock()
                    .unwrap()
                    .hotspot
            })
        } else {
            (0, 0).into()
        };
        let cursor_pos = pointer_location - output_geometry.loc.to_f64() - cursor_hotspot.to_f64();
        let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round();

        // set cursor
        pointer_element.set_texture(pointer_image.clone());

        // draw the cursor as relevant
        {
            // reset the cursor if the surface is no longer alive
            let mut reset = false;
            if let CursorImageStatus::Surface(ref surface) = *cursor_status {
                reset = !surface.alive();
            }
            if reset {
                *cursor_status = CursorImageStatus::Default;
            }

            pointer_element.set_status(cursor_status.clone());
        }

        elements.extend(pointer_element.render_elements(cursor_pos_scaled, scale));

        // draw the dnd icon if applicable
        {
            if let Some(wl_surface) = dnd_icon.as_ref() {
                if wl_surface.alive() {
                    elements.extend(AsRenderElements::<UdevRenderer<'a>>::render_elements(
                        &SurfaceTree::from_surface(wl_surface),
                        cursor_pos_scaled,
                        scale,
                    ));
                }
            }
        }
    }

    #[cfg(feature = "debug")]
    {
        surface.fps_element.update_fps(surface.fps.avg().round() as u32);
        surface.fps.tick();
        elements.push(CustomRenderElements::Fps(surface.fps_element.clone()));
    }

    // and draw to our buffer
    let render_res = render_output(
        output,
        space,
        &*elements,
        renderer,
        &mut surface.damage_tracked_renderer,
        age.into(),
        logger,
    )
    .map(|(damage, states)| (damage.is_some(), states));

    match render_res.map_err(|err| match err {
        DamageTrackedRendererError::Rendering(err) => err.into(),
        _ => unreachable!(),
    }) {
        Ok((true, states)) => {
            surface
                .surface
                .queue_buffer()
                .map_err(Into::<SwapBuffersError>::into)?;
            Ok((true, states))
        }
        x => x,
    }
}

fn schedule_initial_render(
    gpus: &mut GpuManager<EglGlesBackend<Gles2Renderer>>,
    surface: Rc<RefCell<SurfaceData>>,
    evt_handle: &LoopHandle<'static, CalloopData<UdevData>>,
    logger: ::slog::Logger,
) {
    let node = surface.borrow().render_node;
    let result = {
        let mut renderer = gpus.renderer::<Gles2Renderbuffer>(&node, &node).unwrap();
        let mut surface = surface.borrow_mut();
        initial_render(&mut surface.surface, &mut renderer)
    };
    if let Err(err) = result {
        match err {
            SwapBuffersError::AlreadySwapped => {}
            SwapBuffersError::TemporaryFailure(err) => {
                // TODO dont reschedule after 3(?) retries
                warn!(logger, "Failed to submit page_flip: {}", err);
                let handle = evt_handle.clone();
                evt_handle.insert_idle(move |data| {
                    schedule_initial_render(&mut data.state.backend_data.gpus, surface, &handle, logger)
                });
            }
            SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
        }
    }
}

fn initial_render(
    surface: &mut RenderSurface,
    renderer: &mut UdevRenderer<'_>,
) -> Result<(), SwapBuffersError> {
    let (dmabuf, _age) = surface.next_buffer()?;
    renderer.bind(dmabuf)?;
    // Does not matter if we render an empty frame
    renderer
        .render((1, 1).into(), Transform::Normal, |_, frame| {
            frame
                .clear(CLEAR_COLOR, &[Rectangle::from_loc_and_size((0, 0), (1, 1))])
                .map_err(Into::<SwapBuffersError>::into)
        })
        .map_err(Into::<SwapBuffersError>::into)
        .and_then(|x| x.map_err(Into::<SwapBuffersError>::into))?;
    surface.queue_buffer()?;
    surface.reset_buffers();
    Ok(())
}

<MSG> anvil: Fixup udev/tty backend, so that it runs at least

<DFF> @@ -9,24 +9,26 @@ use std::{
     time::Duration,
 };
 
-use glium::Surface as GliumSurface;
+use image::{ImageBuffer, Rgba};
 use slog::Logger;
 
-#[cfg(feature = "egl")]
-use smithay::backend::egl::{display::EGLBufferReader, EGLGraphicsBackend};
 use smithay::{
     backend::{
-        drm_old::{
-            atomic::{AtomicDrmDevice, AtomicDrmSurface},
-            common::fallback::{FallbackDevice, FallbackSurface},
+        SwapBuffersError,
+        drm::{
+            DrmDevice,
+            DeviceHandler,
             device_bind,
-            egl::{EglDevice, EglSurface},
-            eglstream::{egl::EglStreamDeviceBackend, EglStreamDevice, EglStreamSurface},
-            gbm::{egl::Gbm as EglGbmBackend, GbmDevice, GbmSurface},
-            legacy::{LegacyDrmDevice, LegacyDrmSurface},
-            DevPath, Device, DeviceHandler, Surface,
+            DrmRenderSurface,
+            DrmError,
+            DrmRenderError,
+        },
+        egl::{EGLDisplay, EGLContext},
+        renderer::{
+            Renderer,
+            gles2::Gles2Renderer,
+            Transform,
         },
-        graphics::{CursorBackend, SwapBuffersError},
         libinput::{LibinputInputBackend, LibinputSessionInterface},
         session::{auto::AutoSession, Session, Signal as SessionSignal},
         udev::{primary_gpu, UdevBackend, UdevEvent},
@@ -40,12 +42,16 @@ use smithay::{
         drm::{
             self,
             control::{
+                Device as ControlDevice,
                 connector::{Info as ConnectorInfo, State as ConnectorState},
                 crtc,
                 encoder::Info as EncoderInfo,
             },
         },
-        image::{ImageBuffer, Rgba},
+        gbm::{
+            BufferObject as GbmBuffer,
+            Device as GbmDevice,
+        },
         input::Libinput,
         nix::{fcntl::OFlag, sys::stat::dev_t},
         wayland_server::{
@@ -63,9 +69,9 @@ use smithay::{
 };
 
 use crate::buffer_utils::BufferUtils;
-use crate::glium_drawer::{schedule_initial_render, GliumDrawer};
 use crate::shell::{MyWindowMap, Roles};
 use crate::state::AnvilState;
+use crate::drawing::*;
 
 #[derive(Clone)]
 pub struct SessionFd(RawFd);
@@ -75,21 +81,6 @@ impl AsRawFd for SessionFd {
     }
 }
 
-type RenderDevice = FallbackDevice<
-    EglDevice<
-        EglGbmBackend<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
-        GbmDevice<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
-    >,
-    EglDevice<
-        EglStreamDeviceBackend<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
-        EglStreamDevice<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
-    >,
->;
-type RenderSurface = FallbackSurface<
-    EglSurface<GbmSurface<FallbackSurface<AtomicDrmSurface<SessionFd>, LegacyDrmSurface<SessionFd>>>>,
-    EglSurface<EglStreamSurface<FallbackSurface<AtomicDrmSurface<SessionFd>, LegacyDrmSurface<SessionFd>>>>,
->;
-
 pub fn run_udev(
     display: Rc<RefCell<Display>>,
     event_loop: &mut EventLoop<AnvilState>,
@@ -104,12 +95,14 @@ pub fn run_udev(
     info!(log, "Listening on wayland socket"; "name" => name.clone());
     ::std::env::set_var("WAYLAND_DISPLAY", name);
 
+    /*
     #[cfg(feature = "egl")]
     let egl_buffer_reader = Rc::new(RefCell::new(None));
 
     #[cfg(feature = "egl")]
     let buffer_utils = BufferUtils::new(egl_buffer_reader.clone(), log.clone());
     #[cfg(not(feature = "egl"))]
+    */
     let buffer_utils = BufferUtils::new(log.clone());
 
     let output_map = Rc::new(RefCell::new(Vec::new()));
@@ -289,17 +282,22 @@ impl Drop for MyOutput {
     }
 }
 
+type RenderSurface = DrmRenderSurface<SessionFd, GbmDevice<SessionFd>, Gles2Renderer, GbmBuffer<()>>;
+
 struct BackendData {
     _restart_token: SignalToken,
-    event_source: Source<Generic<RenderDevice>>,
-    surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>,
+    surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
+    context: EGLContext,
+    egl: EGLDisplay,
+    gbm: GbmDevice<SessionFd>,
+    event_source: Source<Generic<DrmDevice<SessionFd>>>,
 }
 
 struct UdevHandlerImpl<Data: 'static> {
     compositor_token: CompositorToken<Roles>,
     buffer_utils: BufferUtils,
-    #[cfg(feature = "egl")]
-    egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
+    //#[cfg(feature = "egl")]
+    //egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
     session: AutoSession,
     backends: HashMap<dev_t, BackendData>,
     display: Rc<RefCell<Display>>,
@@ -317,12 +315,15 @@ struct UdevHandlerImpl<Data: 'static> {
 
 impl<Data: 'static> UdevHandlerImpl<Data> {
     pub fn scan_connectors(
-        device: &mut RenderDevice,
+        device: &mut DrmDevice<SessionFd>,
+        gbm: &GbmDevice<SessionFd>,
+        egl: &EGLDisplay,
+        context: &EGLContext,
         buffer_utils: &BufferUtils,
         display: &mut Display,
         output_map: &mut Vec<MyOutput>,
         logger: &::slog::Logger,
-    ) -> HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>> {
+    ) -> HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>> {
         // Get a set of all modesetting resource handles (excluding planes):
         let res_handles = device.resource_handles().unwrap();
 
@@ -330,7 +331,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
         let connector_infos: Vec<ConnectorInfo> = res_handles
             .connectors()
             .iter()
-            .map(|conn| device.get_connector_info(*conn).unwrap())
+            .map(|conn| device.get_connector(*conn).unwrap())
             .filter(|conn| conn.state() == ConnectorState::Connected)
             .inspect(|conn| info!(logger, "Connected: {:?}", conn.interface()))
             .collect();
@@ -343,18 +344,59 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
                 .encoders()
                 .iter()
                 .filter_map(|e| *e)
-                .flat_map(|encoder_handle| device.get_encoder_info(encoder_handle))
+                .flat_map(|encoder_handle| device.get_encoder(encoder_handle))
                 .collect::<Vec<EncoderInfo>>();
             'outer: for encoder_info in encoder_infos {
                 for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
+                    // TODO cursor
+                    let primary = match device.planes(&crtc) {
+                        Ok(planes) => planes.primary,
+                        Err(err) => {
+                            warn!(logger, "Failed to enumerate planes: {}", err);
+                            continue;
+                        }
+                    };
+
                     if let Entry::Vacant(entry) = backends.entry(crtc) {
-                        let renderer = GliumDrawer::init(
-                            device
-                                .create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()])
-                                .unwrap(),
-                            buffer_utils.clone(),
-                            logger.clone(),
+                        info!(logger, "Trying to setup connector {:?}-{} with crtc {:?}",
+                            connector_info.interface(),
+                            connector_info.interface_id(),
+                            crtc,
                         );
+                        let context = match EGLContext::new_shared(egl, context, logger.clone()) {
+                            Ok(context) => context,
+                            Err(err) => {
+                                warn!(logger, "Failed to create EGLContext: {}", err);
+                                continue;
+                            }
+                        };
+                        let renderer = match unsafe { Gles2Renderer::new(context, logger.clone()) } {
+                            Ok(renderer) => renderer,
+                            Err(err) => {
+                                warn!(logger, "Failed to create Gles2 Renderer: {}", err);
+                                continue;
+                            }
+                        };
+                        let surface = match device.create_surface(crtc, primary, connector_info.modes()[0], &[connector_info.handle()]) {
+                            Ok(surface) => surface,
+                            Err(err) => {
+                                warn!(logger, "Failed to create drm surface: {}", err);
+                                continue;
+                            }
+                        };
+                        let renderer = match DrmRenderSurface::new(
+                            surface,
+                            gbm.clone(),
+                            renderer,
+                            logger.clone()
+                        ) {
+                            Ok(renderer) => renderer,
+                            Err(err) => {
+                                warn!(logger, "Failed to create rendering surface: {}", err);
+                                continue;
+                            }
+                        };
+
                         output_map.push(MyOutput::new(
                             display,
                             device.device_id(),
@@ -363,7 +405,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
                             logger.clone(),
                         ));
 
-                        entry.insert(Rc::new(renderer));
+                        entry.insert(Rc::new(RefCell::new(renderer)));
                         break 'outer;
                     }
                 }
@@ -377,7 +419,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
 impl<Data: 'static> UdevHandlerImpl<Data> {
     fn device_added(&mut self, device_id: dev_t, path: PathBuf) {
         // Try to open the device
-        if let Some(mut device) = self
+        if let Some((mut device, gbm)) = self
             .session
             .open(
                 &path,
@@ -385,36 +427,35 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
             )
             .ok()
             .and_then(|fd| {
-                match FallbackDevice::<AtomicDrmDevice<_>, LegacyDrmDevice<_>>::new(
-                    SessionFd(fd),
-                    true,
-                    self.logger.clone(),
-                ) {
-                    Ok(drm) => Some(drm),
-                    Err(err) => {
-                        warn!(self.logger, "Skipping drm device, because of error: {}", err);
-                        None
-                    }
+                match {
+                    let fd = SessionFd(fd);
+                    (
+                        DrmDevice::new(
+                            fd.clone(),
+                            true,
+                            self.logger.clone(),
+                        ),
+                        GbmDevice::new(
+                            fd.clone()
+                        ),
+                    )
                 }
-            })
-            .and_then(|drm| {
-                match FallbackDevice::<GbmDevice<_>, EglStreamDevice<_>>::new(drm, self.logger.clone()) {
-                    Ok(dev) => Some(dev),
-                    Err(err) => {
-                        warn!(self.logger, "Skipping device, because of error: {}", err);
+                {
+                    (Ok(drm), Ok(gbm)) => Some((drm, gbm)),
+                    (Err(err), _) => {
+                        warn!(self.logger, "Skipping device {:?}, because of drm error: {}", device_id, err);
                         None
-                    }
-                }
-            })
-            .and_then(|dev| match FallbackDevice::new_egl(dev, self.logger.clone()) {
-                Ok(egl) => Some(egl),
-                Err(err) => {
-                    warn!(self.logger, "Skipping egl device, because of error: {}", err);
-                    None
+                    },
+                    (_, Err(err)) => {
+                        // TODO try DumbBuffer allocator in this case
+                        warn!(self.logger, "Skipping device {:?}, because of gbm error: {}", device_id, err);
+                        None
+                    },
                 }
             })
         {
             // init hardware acceleration on the primary gpu.
+            /*
             #[cfg(feature = "egl")]
             {
                 if path.canonicalize().ok() == self.primary_gpu {
@@ -426,9 +467,28 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
                         device.bind_wl_display(&*self.display.borrow()).ok();
                 }
             }
+            */
 
+            let egl = match EGLDisplay::new(&gbm, self.logger.clone()) {
+                Ok(display) => display,
+                Err(err) => {
+                    warn!(self.logger, "Skipping device {:?}, because of egl display error: {}", device_id, err);
+                    return;
+                }
+            };
+            let context = match EGLContext::new(&egl, self.logger.clone()) {
+                Ok(context) => context,
+                Err(err) => {
+                    warn!(self.logger, "Skipping device {:?}, because of egl context error: {}", device_id, err);
+                    return;
+                }
+            };
+            
             let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
                 &mut device,
+                &gbm,
+                &egl,
+                &context,
                 &self.buffer_utils,
                 &mut *self.display.borrow_mut(),
                 &mut *self.output_map.borrow_mut(),
@@ -470,9 +530,11 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
                 .map_err(|e| -> IoError { e.into() })
                 .unwrap();
 
+            trace!(self.logger, "Backends: {:?}", backends.borrow().keys());
             for renderer in backends.borrow_mut().values() {
                 // render first frame
-                schedule_initial_render(renderer.clone(), &self.loop_handle);
+                trace!(self.logger, "Scheduling frame");
+                schedule_initial_render(renderer.clone(), &self.loop_handle, self.logger.clone());
             }
 
             self.backends.insert(
@@ -481,6 +543,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
                     _restart_token: restart_token,
                     event_source,
                     surfaces: backends,
+                    egl,
+                    context,
+                    gbm,
                 },
             );
         }
@@ -490,7 +555,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
         //quick and dirty, just re-init all backends
         let buffer_utils = &self.buffer_utils;
         if let Some(ref mut backend_data) = self.backends.get_mut(&device) {
-            let logger = &self.logger;
+            let logger = self.logger.clone();
             let loop_handle = self.loop_handle.clone();
             let mut display = self.display.borrow_mut();
             let mut output_map = self.output_map.borrow_mut();
@@ -500,15 +565,19 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
                     let mut backends = backend_data.surfaces.borrow_mut();
                     *backends = UdevHandlerImpl::<Data>::scan_connectors(
                         &mut source.file,
+                        &backend_data.gbm,
+                        &backend_data.egl,
+                        &backend_data.context,
                         buffer_utils,
                         &mut *display,
                         &mut *output_map,
-                        logger,
+                        &logger,
                     );
 
                     for renderer in backends.values() {
+                        let logger = logger.clone();
                         // render first frame
-                        schedule_initial_render(renderer.clone(), &loop_handle);
+                        schedule_initial_render(renderer.clone(), &loop_handle, logger);
                     }
                 });
         }
@@ -545,13 +614,11 @@ pub struct DrmHandlerImpl<Data: 'static> {
 }
 
 impl<Data: 'static> DeviceHandler for DrmHandlerImpl<Data> {
-    type Device = RenderDevice;
-
     fn vblank(&mut self, crtc: crtc::Handle) {
         self.renderer.clone().render(crtc, None, Some(&self.loop_handle))
     }
 
-    fn error(&mut self, error: <RenderSurface as Surface>::Error) {
+    fn error(&mut self, error: DrmError) {
         error!(self.renderer.logger, "{:?}", error);
     }
 }
@@ -574,7 +641,7 @@ impl<Data: 'static> DrmRendererSessionListener<Data> {
 pub struct DrmRenderer {
     device_id: dev_t,
     compositor_token: CompositorToken<Roles>,
-    backends: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>,
+    backends: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
     window_map: Rc<RefCell<MyWindowMap>>,
     output_map: Rc<RefCell<Vec<MyOutput>>>,
     pointer_location: Rc<RefCell<(f64, f64)>>,
@@ -597,93 +664,29 @@ impl DrmRenderer {
         timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>,
         evt_handle: Option<&LoopHandle<Data>>,
     ) {
-        if let Some(drawer) = self.backends.borrow().get(&crtc) {
-            // get output coordinates
-            let (x, y) = self
-                .output_map
-                .borrow()
-                .iter()
-                .take_while(|output| output.device_id != self.device_id || output.crtc != crtc)
-                .fold((0u32, 0u32), |pos, output| (pos.0 + output.size.0, pos.1));
-            let (width, height) = self
-                .output_map
-                .borrow()
-                .iter()
-                .find(|output| output.device_id == self.device_id && output.crtc == crtc)
-                .map(|output| output.size)
-                .unwrap_or((0, 0)); // in this case the output will be removed.
-
-            // and draw in sync with our monitor
-            let mut frame = drawer.draw();
-            frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None);
-            // draw the surfaces
-            drawer.draw_windows(
-                &mut frame,
-                &*self.window_map.borrow(),
-                Some(Rectangle {
-                    x: x as i32,
-                    y: y as i32,
-                    width: width as i32,
-                    height: height as i32,
-                }),
-                self.compositor_token,
+        if let Some(surface) = self.backends.borrow().get(&crtc) {
+            let result = DrmRenderer::render_surface(
+                  &mut *surface.borrow_mut(),
+                  self.device_id,
+                  crtc,
+                  &mut *self.window_map.borrow_mut(),
+                  &mut *self.output_map.borrow_mut(),
+                  &self.compositor_token,
+                  &*self.pointer_location.borrow(),
+                  &self.logger
             );
-
-            // get pointer coordinates
-            let (ptr_x, ptr_y) = *self.pointer_location.borrow();
-            let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
-            let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
-
-            // set cursor
-            if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
-                let _ = drawer.borrow().set_cursor_position(ptr_x as u32, ptr_y as u32);
-
-                // draw the dnd icon if applicable
-                {
-                    let guard = self.dnd_icon.lock().unwrap();
-                    if let Some(ref surface) = *guard {
-                        if surface.as_ref().is_alive() {
-                            drawer.draw_dnd_icon(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token);
-                        }
-                    }
-                }
-                // draw the cursor as relevant
-                {
-                    let mut guard = self.cursor_status.lock().unwrap();
-                    // reset the cursor if the surface is no longer alive
-                    let mut reset = false;
-                    if let CursorImageStatus::Image(ref surface) = *guard {
-                        reset = !surface.as_ref().is_alive();
-                    }
-                    if reset {
-                        *guard = CursorImageStatus::Default;
-                    }
-                    if let CursorImageStatus::Image(ref surface) = *guard {
-                        drawer.draw_software_cursor(
-                            &mut frame,
-                            surface,
-                            (ptr_x, ptr_y),
-                            self.compositor_token,
-                        );
-                    } else {
-                        drawer.draw_hardware_cursor(&self.pointer_image, (2, 2), (ptr_x, ptr_y));
-                    }
-                }
-            } else {
-                drawer.clear_cursor();
-            }
-
-            if let Err(err) = frame.finish() {
+            if let Err(err) = result {
                 warn!(self.logger, "Error during rendering: {:?}", err);
                 let reschedule =
                     match err {
                         SwapBuffersError::AlreadySwapped => false,
                         SwapBuffersError::TemporaryFailure(err) => {
-                            match err.downcast_ref::<smithay::backend::drm_old::common::Error>() {
-                                Some(&smithay::backend::drm_old::common::Error::DeviceInactive) => false,
-                                Some(&smithay::backend::drm_old::common::Error::Access {
-                                    ref source, ..
-                                }) if matches!(source.get_ref(), drm::SystemError::PermissionDenied) => false,
+                            match err.downcast_ref::<DrmError>() {
+                                Some(&DrmError::DeviceInactive) => false,
+                                Some(&DrmError::Access {
+                                    source: drm::SystemError::PermissionDenied,
+                                    ..
+                                }) => false,
                                 _ => true,
                             }
                         }
@@ -730,4 +733,92 @@ impl DrmRenderer {
             }
         }
     }
-}
+
+    fn render_surface(
+        surface: &mut RenderSurface,
+        device_id: dev_t,
+        crtc: crtc::Handle,
+        window_map: &mut MyWindowMap,
+        output_map: &mut Vec<MyOutput>,
+        compositor_token: &CompositorToken<Roles>,
+        pointer_location: &(f64, f64),
+        logger: &slog::Logger,
+    ) -> Result<(), SwapBuffersError> {
+        surface.frame_submitted()?;
+
+        // get output coordinates
+        let (x, y) = output_map
+            .iter()
+            .take_while(|output| output.device_id != device_id || output.crtc != crtc)
+            .fold((0u32, 0u32), |pos, output| (pos.0 + output.size.0, pos.1));
+        let (width, height) = output_map
+            .iter()
+            .find(|output| output.device_id == device_id && output.crtc == crtc)
+            .map(|output| output.size)
+            .unwrap_or((0, 0)); // in this case the output will be removed.
+
+        // and draw in sync with our monitor
+        surface.queue_frame().unwrap();
+        surface.clear([0.8, 0.8, 0.9, 1.0]).unwrap();
+        // draw the surfaces
+        draw_windows(
+            surface,
+            window_map,
+            Some(Rectangle {
+                x: x as i32,
+                y: y as i32,
+                width: width as i32,
+                height: height as i32,
+            }),
+            compositor_token.clone(),
+            logger,
+        );
+
+        // get pointer coordinates
+        let (ptr_x, ptr_y) = *pointer_location;
+        let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
+        let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
+
+        // set cursor
+        /*
+        if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
+            let _ = drawer.borrow().set_cursor_position(ptr_x as u32, ptr_y as u32);
+
+            // draw the dnd icon if applicable
+            {
+                let guard = self.dnd_icon.lock().unwrap();
+                if let Some(ref surface) = *guard {
+                    if surface.as_ref().is_alive() {
+                        drawer.draw_dnd_icon(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token);
+                    }
+                }
+            }
+            // draw the cursor as relevant
+            {
+                let mut guard = self.cursor_status.lock().unwrap();
+                // reset the cursor if the surface is no longer alive
+                let mut reset = false;
+                if let CursorImageStatus::Image(ref surface) = *guard {
+                    reset = !surface.as_ref().is_alive();
+                }
+                if reset {
+                    *guard = CursorImageStatus::Default;
+                }
+                if let CursorImageStatus::Image(ref surface) = *guard {
+                    drawer.draw_software_cursor(
+                        &mut frame,
+                        surface,
+                        (ptr_x, ptr_y),
+                        self.compositor_token,
+                    );
+                } else {
+                    drawer.draw_hardware_cursor(&self.pointer_image, (2, 2), (ptr_x, ptr_y));
+                }
+            }
+        } else {
+            drawer.clear_cursor();
+        }
+        */
+        surface.finish()
+    }
+}
\ No newline at end of file

anvil: Fixup udev/tty backend, so that it runs at least