From 866dbee8cbec411103bd9aff6a8fe869c78d5cbf Mon Sep 17 00:00:00 2001
From: Chris Thrasher <chrisjthrasher@gmail.com>
Date: Sun, 23 Oct 2022 18:48:08 -0600
Subject: [PATCH] Add DRM utilities to sfml-window

---
 extlibs/headers/drm/drm-common.c      | 364 -------------------------
 extlibs/headers/drm/drm-common.h      |  86 ------
 src/SFML/Window/CMakeLists.txt        |   5 +-
 src/SFML/Window/DRM/DRMContext.cpp    | 365 +++++++++++++++++++++++---
 src/SFML/Window/DRM/DRMContext.hpp    |  17 +-
 src/SFML/Window/DRM/VideoModeImpl.cpp |   9 +-
 src/SFML/Window/DRM/WindowImplDRM.cpp |   5 +-
 7 files changed, 357 insertions(+), 494 deletions(-)
 delete mode 100644 extlibs/headers/drm/drm-common.c
 delete mode 100644 extlibs/headers/drm/drm-common.h

diff --git a/extlibs/headers/drm/drm-common.c b/extlibs/headers/drm/drm-common.c
deleted file mode 100644
index 9a870054..00000000
--- a/extlibs/headers/drm/drm-common.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (c) 2017 Rob Clark <rclark@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include <errno.h>
-#include <inttypes.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <drm-common.h>
-#include <gbm.h>
-
-#define WEAK __attribute__((weak))
-
-WEAK uint64_t gbm_bo_get_modifier(struct gbm_bo *bo);
-WEAK int gbm_bo_get_plane_count(struct gbm_bo *bo);
-WEAK uint32_t gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane);
-WEAK uint32_t gbm_bo_get_offset(struct gbm_bo *bo, int plane);
-
-static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
-{
-	int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo));
-	struct drm_fb *fb = data;
-
-	if (fb->fb_id)
-		drmModeRmFB(drm_fd, fb->fb_id);
-
-	free(fb);
-}
-
-struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
-{
-	int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo));
-	struct drm_fb *fb = gbm_bo_get_user_data(bo);
-	uint32_t width, height, format,
-		 strides[4] = {0}, handles[4] = {0},
-		 offsets[4] = {0}, flags = 0;
-	int ret = -1;
-
-	if (fb)
-		return fb;
-
-	fb = calloc(1, sizeof *fb);
-	fb->bo = bo;
-
-	width = gbm_bo_get_width(bo);
-	height = gbm_bo_get_height(bo);
-	format = gbm_bo_get_format(bo);
-
-	if (gbm_bo_get_modifier && gbm_bo_get_plane_count &&
-	    gbm_bo_get_stride_for_plane && gbm_bo_get_offset)
-	{
-		uint64_t modifiers[4] = {0};
-		modifiers[0] = gbm_bo_get_modifier(bo);
-		const int num_planes = gbm_bo_get_plane_count(bo);
-		for (int i = 0; i < num_planes; i++)
-		{
-			strides[i] = gbm_bo_get_stride_for_plane(bo, i);
-			handles[i] = gbm_bo_get_handle(bo).u32;
-			offsets[i] = gbm_bo_get_offset(bo, i);
-			modifiers[i] = modifiers[0];
-		}
-
-		if (modifiers[0])
-		{
-			flags = DRM_MODE_FB_MODIFIERS;
-			// printf("Using modifier %" PRIx64 "\n", modifiers[0]);
-		}
-
-		ret = drmModeAddFB2WithModifiers(drm_fd, width, height,
-				format, handles, strides, offsets,
-				modifiers, &fb->fb_id, flags);
-	}
-
-	if (ret)
-	{
-		// if (flags)
-			// fprintf(stderr, "Modifiers failed!\n");
-
-		memcpy(handles, (uint32_t [4]){gbm_bo_get_handle(bo).u32,0,0,0}, 16);
-		memcpy(strides, (uint32_t [4]){gbm_bo_get_stride(bo),0,0,0}, 16);
-		memset(offsets, 0, 16);
-		ret = drmModeAddFB2(drm_fd, width, height, format,
-				handles, strides, offsets, &fb->fb_id, 0);
-	}
-
-	if (ret)
-	{
-		printf("failed to create fb: %s\n", strerror(errno));
-		free(fb);
-		return NULL;
-	}
-
-	gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
-
-	return fb;
-}
-
-static uint32_t find_crtc_for_encoder(const drmModeRes *resources,
-		const drmModeEncoder *encoder)
-{
-
-	for (int i = 0; i < resources->count_crtcs; i++)
-	{
-		/* possible_crtcs is a bitmask as described here:
-		 * https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api
-		 */
-		const uint32_t crtc_mask = 1U << i;
-		const uint32_t crtc_id = resources->crtcs[i];
-		if (encoder->possible_crtcs & crtc_mask)
-		{
-			return crtc_id;
-		}
-	}
-
-	/* no match found */
-	return 0;
-}
-
-static uint32_t find_crtc_for_connector(const struct drm *drm, const drmModeRes *resources, const drmModeConnector *connector)
-{
-	for (int i = 0; i < connector->count_encoders; i++)
-	{
-		const uint32_t encoder_id = connector->encoders[i];
-		drmModeEncoder *encoder = drmModeGetEncoder(drm->fd, encoder_id);
-
-		if (encoder)
-		{
-			const uint32_t crtc_id = find_crtc_for_encoder(resources, encoder);
-
-			drmModeFreeEncoder(encoder);
-			if (crtc_id != 0)
-			{
-				return crtc_id;
-			}
-		}
-	}
-
-	/* no match found */
-	return 0;
-}
-
-static int get_resources(int fd, drmModeRes **resources)
-{
-	*resources = drmModeGetResources(fd);
-	if (*resources == NULL)
-		return -1;
-	return 0;
-}
-
-static int has_monitor_connected(int fd, drmModeRes* resources)
-{
-	int i;
-	drmModeConnector *connector;
-	for (i = 0; i < resources->count_connectors; i++)
-	{
-		connector = drmModeGetConnector(fd, resources->connectors[i]);
-		if (connector->connection == DRM_MODE_CONNECTED)
-		{
-			/* There is a monitor connected */
-			drmModeFreeConnector(connector);
-			connector = NULL;
-			return 1;
-		}
-		drmModeFreeConnector(connector);
-		connector = NULL;
-	}
-	return 0;
-}
-
-#define MAX_DRM_DEVICES 64
-
-static int find_drm_device(drmModeRes **resources)
-{
-	drmDevicePtr devices[MAX_DRM_DEVICES] = { NULL };
-	int num_devices, fd = -1;
-
-	num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
-	if (num_devices < 0)
-	{
-		printf("drmGetDevices2 failed: %s\n", strerror(-num_devices));
-		return -1;
-	}
-
-	for (int i = 0; i < num_devices; i++)
-	{
-		drmDevicePtr device = devices[i];
-		int ret;
-
-		if (!(device->available_nodes & (1 << DRM_NODE_PRIMARY)))
-			continue;
-		/* OK, it's a primary device. If we can get the
-		 * drmModeResources, it means it's also a
-		 * KMS-capable device.
-		 */
-		fd = open(device->nodes[DRM_NODE_PRIMARY], O_RDWR);
-		if (fd < 0)
-			continue;
-		ret = get_resources(fd, resources);
-		if(getenv("SFML_DRM_DEBUG"))
-		{
-			printf("DRM device used: %d\n", i);
-		}
-		if(!ret && has_monitor_connected(fd, *resources) != 0)
-			break;
-		close(fd);
-		fd = -1;
-	}
-	drmFreeDevices(devices, num_devices);
-
-	if (fd < 0)
-		printf("no drm device found!\n");
-	return fd;
-}
-
-int init_drm(struct drm *drm, const char *device, const char *mode_str,
-		unsigned int vrefresh)
-{
-	drmModeRes *resources;
-	drmModeConnector *connector = NULL;
-	drmModeEncoder *encoder = NULL;
-	int i, ret, area;
-
-	if (device)
-	{
-		drm->fd = open(device, O_RDWR);
-		ret = get_resources(drm->fd, &resources);
-		if (ret < 0 && errno == EOPNOTSUPP)
-			printf("%s does not look like a modeset device\n", device);
-	}
-	else
-	{
-		drm->fd = find_drm_device(&resources);
-	}
-
-	if (drm->fd < 0)
-	{
-		printf("could not open drm device\n");
-		return -1;
-	}
-
-	if (!resources)
-	{
-		printf("drmModeGetResources failed: %s\n", strerror(errno));
-		return -1;
-	}
-
-	/* find a connected connector: */
-	for (i = 0; i < resources->count_connectors; i++)
-	{
-		connector = drmModeGetConnector(drm->fd, resources->connectors[i]);
-		if (connector->connection == DRM_MODE_CONNECTED)
-		{
-			/* it's connected, let's use this! */
-			break;
-		}
-		drmModeFreeConnector(connector);
-		connector = NULL;
-	}
-
-	if (!connector)
-	{
-		/* we could be fancy and listen for hotplug events and wait for
-		 * a connector..
-		 */
-		printf("no connected connector!\n");
-		return -1;
-	}
-
-	/* find user requested mode: */
-	if (mode_str && *mode_str)
-	{
-		for (i = 0; i < connector->count_modes; i++)
-		{
-			drmModeModeInfo *current_mode = &connector->modes[i];
-
-			if (strcmp(current_mode->name, mode_str) == 0)
-			{
-				if (vrefresh == 0 || current_mode->vrefresh == vrefresh)
-				{
-					drm->mode = current_mode;
-					break;
-				}
-			}
-		}
-		if (!drm->mode)
-			printf("requested mode not found, using default mode!\n");
-	}
-
-	/* find encoder: */
-	for (i = 0; i < resources->count_encoders; i++)
-	{
-		encoder = drmModeGetEncoder(drm->fd, resources->encoders[i]);
-		if (encoder->encoder_id == connector->encoder_id)
-			break;
-		drmModeFreeEncoder(encoder);
-		encoder = NULL;
-	}
-
-	if (encoder)
-	{
-		drm->crtc_id = encoder->crtc_id;
-	}
-	else
-	{
-		uint32_t crtc_id = find_crtc_for_connector(drm, resources, connector);
-		if (crtc_id == 0)
-		{
-			printf("no crtc found!\n");
-			return -1;
-		}
-
-		drm->crtc_id = crtc_id;
-	}
-
-	drmModeFreeResources(resources);
-
-	drm->connector_id = connector->connector_id;
-
-    drm->saved_connector = connector;
-    drm->saved_encoder = encoder;
-
-    // get original display mode so we can restore display mode after program exits
-    drm->original_crtc = drmModeGetCrtc(drm->fd, drm->crtc_id);
-
-	/* Let's use the current mode rather than the preferred one if the user didn't
-	 * specify a mode with env vars
-	 */
-	if (!drm->mode)
-	{
-		if(getenv("SFML_DRM_DEBUG"))
-			printf("DRM using the current mode\n");
-		drm->mode = &(drm->original_crtc->mode);
-	}
-
-	if (getenv("SFML_DRM_DEBUG"))
-	{
-		printf("DRM Mode used: %s@%d\n", drm->mode->name, drm->mode->vrefresh);
-	}
-
-	return 0;
-}
diff --git a/extlibs/headers/drm/drm-common.h b/extlibs/headers/drm/drm-common.h
deleted file mode 100644
index d388e6d0..00000000
--- a/extlibs/headers/drm/drm-common.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2017 Rob Clark <rclark@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _DRM_COMMON_H
-#define _DRM_COMMON_H
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct gbm;
-struct egl;
-
-struct plane
-{
-	drmModePlane *plane;
-	drmModeObjectProperties *props;
-	drmModePropertyRes **props_info;
-};
-
-struct crtc
-{
-	drmModeCrtc *crtc;
-	drmModeObjectProperties *props;
-	drmModePropertyRes **props_info;
-};
-
-struct connector
-{
-	drmModeConnector *connector;
-	drmModeObjectProperties *props;
-	drmModePropertyRes **props_info;
-};
-
-struct drm
-{
-	int fd;
-
-	drmModeModeInfo *mode;
-	uint32_t crtc_id;
-	uint32_t connector_id;
-
-    drmModeCrtcPtr original_crtc;
-
-    drmModeConnectorPtr saved_connector;
-    drmModeEncoderPtr saved_encoder;
-};
-
-struct drm_fb
-{
-	struct gbm_bo *bo;
-	uint32_t fb_id;
-};
-
-struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo);
-
-int init_drm(struct drm *drm, const char *device, const char *mode_str, unsigned int vrefresh);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DRM_COMMON_H */
diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt
index b6f117e3..133c89ea 100644
--- a/src/SFML/Window/CMakeLists.txt
+++ b/src/SFML/Window/CMakeLists.txt
@@ -280,13 +280,10 @@ sfml_add_library(sfml-window
 # DRM libraries
 if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
     if(SFML_USE_DRM)
-        target_sources(sfml-window PRIVATE $<TARGET_OBJECTS:drm-common>)
         sfml_find_package(DRM INCLUDE "DRM_INCLUDE_DIR" LINK "DRM_LIBRARY")
-        target_include_directories(sfml-window PRIVATE ${PROJECT_SOURCE_DIR}/extlibs/headers/drm ${DRM_INCLUDE_DIR}/libdrm)
+        target_include_directories(sfml-window PRIVATE ${DRM_INCLUDE_DIR}/libdrm)
         sfml_find_package(GBM INCLUDE "GBM_INCLUDE_DIR" LINK "GBM_LIBRARY")
         target_link_libraries(sfml-window PRIVATE drm gbm EGL)
-        add_library(drm-common OBJECT ${PROJECT_SOURCE_DIR}/extlibs/headers/drm/drm-common.c)
-        target_include_directories(drm-common PRIVATE ${PROJECT_SOURCE_DIR}/extlibs/headers/drm ${DRM_INCLUDE_DIR}/libdrm)
     else()
         sfml_find_package(X11 INCLUDE "X11_INCLUDE_DIR" LINK "X11_X11_LIB" "X11_Xrandr_LIB" "X11_Xcursor_LIB")
         target_link_libraries(sfml-window PRIVATE X11)
diff --git a/src/SFML/Window/DRM/DRMContext.cpp b/src/SFML/Window/DRM/DRMContext.cpp
index d92a10a4..e36875ba 100644
--- a/src/SFML/Window/DRM/DRMContext.cpp
+++ b/src/SFML/Window/DRM/DRMContext.cpp
@@ -33,8 +33,10 @@
 #include <cerrno>
 #include <cstdlib>
 #include <cstring>
+#include <fcntl.h>
 #include <poll.h>
 #include <unistd.h>
+#include <xf86drm.h>
 
 // We check for this definition in order to avoid multiple definitions of GLAD
 // entities during unity builds of SFML.
@@ -46,8 +48,14 @@
 
 namespace
 {
+    struct DrmFb
+    {
+        gbm_bo* bo;
+        sf::Uint32 fbId;
+    };
+
     bool initialized = false;
-    drm drmNode;
+    sf::priv::Drm drmNode;
     drmEventContext drmEventCtx;
     pollfd pollFD;
     gbm_device* gbmDevice = NULL;
@@ -79,7 +87,7 @@ namespace
 
             if (pollFD.revents & POLLIN)
             {
-                drmHandleEvent(drmNode.fd, &drmEventCtx);
+                drmHandleEvent(drmNode.fileDescriptor, &drmEventCtx);
             }
             else
             {
@@ -95,21 +103,21 @@ namespace
             return;
 
         /* Avoid a modeswitch if possible */
-        if (drmNode.mode != &drmNode.original_crtc->mode)
-            drmModeSetCrtc(drmNode.fd,
-                           drmNode.original_crtc->crtc_id,
-                           drmNode.original_crtc->buffer_id,
-                           drmNode.original_crtc->x,
-                           drmNode.original_crtc->y,
-                           &drmNode.connector_id,
+        if (drmNode.mode != &drmNode.originalCrtc->mode)
+            drmModeSetCrtc(drmNode.fileDescriptor,
+                           drmNode.originalCrtc->crtc_id,
+                           drmNode.originalCrtc->buffer_id,
+                           drmNode.originalCrtc->x,
+                           drmNode.originalCrtc->y,
+                           &drmNode.connectorId,
                            1,
-                           &drmNode.original_crtc->mode);
+                           &drmNode.originalCrtc->mode);
         else if (getenv("SFML_DRM_DEBUG"))
             printf("DRM keeping the same mode since using the original one\n");
 
-        drmModeFreeConnector(drmNode.saved_connector);
-        drmModeFreeEncoder(drmNode.saved_encoder);
-        drmModeFreeCrtc(drmNode.original_crtc);
+        drmModeFreeConnector(drmNode.savedConnector);
+        drmModeFreeEncoder(drmNode.savedEncoder);
+        drmModeFreeCrtc(drmNode.originalCrtc);
 
         eglTerminate(display);
         display = EGL_NO_DISPLAY;
@@ -117,9 +125,9 @@ namespace
         gbm_device_destroy(gbmDevice);
         gbmDevice = NULL;
 
-        close(drmNode.fd);
+        close(drmNode.fileDescriptor);
 
-        drmNode.fd = -1;
+        drmNode.fileDescriptor = -1;
         drmNode.mode = 0;
 
         std::memset(&pollFD, 0, sizeof(pollfd));
@@ -130,6 +138,306 @@ namespace
         initialized = false;
     }
 
+    void drmFbDestroyCallback(gbm_bo* bo, void* data)
+    {
+        int drmFd = gbm_device_get_fd(gbm_bo_get_device(bo));
+        DrmFb* fb = static_cast<DrmFb*>(data);
+
+        if (fb->fbId)
+            drmModeRmFB(drmFd, fb->fbId);
+
+        delete fb;
+    }
+
+    DrmFb* drmFbGetFromBo(gbm_bo& bo)
+    {
+        int drmFd = gbm_device_get_fd(gbm_bo_get_device(&bo));
+        DrmFb* fb = static_cast<DrmFb*>(gbm_bo_get_user_data(&bo));
+        if (fb)
+            return fb;
+
+        fb = new DrmFb();
+        fb->bo = &bo;
+
+        const sf::Uint32 width = gbm_bo_get_width(&bo);
+        const sf::Uint32 height = gbm_bo_get_height(&bo);
+        const sf::Uint32 format = gbm_bo_get_format(&bo);
+
+        sf::Uint32 strides[4] = {0};
+        sf::Uint32 handles[4] = {0};
+        sf::Uint32 offsets[4] = {0};
+        uint64_t modifiers[4] = {0};
+        modifiers[0] = gbm_bo_get_modifier(&bo);
+        const int num_planes = gbm_bo_get_plane_count(&bo);
+        for (int i = 0; i < num_planes; ++i)
+        {
+            strides[i] = gbm_bo_get_stride_for_plane(&bo, i);
+            handles[i] = gbm_bo_get_handle(&bo).u32;
+            offsets[i] = gbm_bo_get_offset(&bo, i);
+            modifiers[i] = modifiers[0];
+        }
+
+        sf::Uint32 flags = 0;
+        if (modifiers[0])
+        {
+            flags = DRM_MODE_FB_MODIFIERS;
+        }
+
+        int result = drmModeAddFB2WithModifiers(drmFd, width, height, format, handles, strides, offsets, modifiers, &fb->fbId, flags);
+
+        if (result)
+        {
+            std::memset(handles, 0, 16);
+            handles[0] = gbm_bo_get_handle(&bo).u32;
+            std::memset(strides, 0, 16);
+            strides[0] = gbm_bo_get_stride(&bo);
+            std::memset(offsets, 0, 16);
+            result = drmModeAddFB2(drmFd, width, height, format, handles, strides, offsets, &fb->fbId, 0);
+        }
+
+        if (result)
+        {
+            sf::err() << "Failed to create fb: " << std::strerror(errno) << std::endl;
+            delete fb;
+            return NULL;
+        }
+
+        gbm_bo_set_user_data(&bo, fb, drmFbDestroyCallback);
+
+        return fb;
+    }
+
+    sf::Uint32 findCrtcForEncoder(const drmModeRes& resources, const drmModeEncoder& encoder)
+    {
+        for (int i = 0; i < resources.count_crtcs; ++i)
+        {
+            // Possible_crtcs is a bitmask as described here:
+            // https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api
+            const sf::Uint32 crtcMask = 1U << i;
+            const sf::Uint32 crtcId = resources.crtcs[i];
+            if (encoder.possible_crtcs & crtcMask)
+            {
+                return crtcId;
+            }
+        }
+
+        // No match found
+        return 0;
+    }
+
+    sf::Uint32 findCrtcForConnector(const sf::priv::Drm& drm, const drmModeRes& resources, const drmModeConnector& connector)
+    {
+        for (int i = 0; i < connector.count_encoders; ++i)
+        {
+            const sf::Uint32 encoderId = connector.encoders[i];
+            const drmModeEncoderPtr encoder = drmModeGetEncoder(drm.fileDescriptor, encoderId);
+
+            if (encoder)
+            {
+                const sf::Uint32 crtcId = findCrtcForEncoder(resources, *encoder);
+
+                drmModeFreeEncoder(encoder);
+                if (crtcId != 0)
+                {
+                    return crtcId;
+                }
+            }
+        }
+
+        // No match found
+        return 0;
+    }
+
+    int getResources(int fd, drmModeResPtr& resources)
+    {
+        resources = drmModeGetResources(fd);
+        if (resources == NULL)
+            return -1;
+        return 0;
+    }
+
+    int hasMonitorConnected(int fd, drmModeRes& resources)
+    {
+        drmModeConnectorPtr connector;
+        for (int i = 0; i < resources.count_connectors; ++i)
+        {
+            connector = drmModeGetConnector(fd, resources.connectors[i]);
+            if (connector->connection == DRM_MODE_CONNECTED)
+            {
+                // There is a monitor connected
+                drmModeFreeConnector(connector);
+                connector = NULL;
+                return 1;
+            }
+            drmModeFreeConnector(connector);
+            connector = NULL;
+        }
+        return 0;
+    }
+
+    int findDrmDevice(drmModeResPtr& resources)
+    {
+        static const int maxDrmDevices = 64;
+
+        drmDevicePtr devices[maxDrmDevices] = { NULL };
+
+        const int numDevices = drmGetDevices2(0, devices, maxDrmDevices);
+        if (numDevices < 0)
+        {
+            sf::err() << "drmGetDevices2 failed: " << std::strerror(-numDevices) << std::endl;
+            return -1;
+        }
+
+        int fileDescriptor = -1;
+        for (int i = 0; i < numDevices; ++i)
+        {
+            drmDevicePtr device = devices[i];
+            int result = 0;
+
+            if (!(device->available_nodes & (1 << DRM_NODE_PRIMARY)))
+                continue;
+            // OK, it's a primary device. If we can get the drmModeResources, it means it's also a KMS-capable device.
+            fileDescriptor = open(device->nodes[DRM_NODE_PRIMARY], O_RDWR);
+            if (fileDescriptor < 0)
+                continue;
+            result = getResources(fileDescriptor, resources);
+#ifdef SFML_DEBUG
+            sf::err() << "DRM device used: " << i << std::endl;
+#endif
+            if(!result && hasMonitorConnected(fileDescriptor, *resources) != 0)
+                break;
+            close(fileDescriptor);
+            fileDescriptor = -1;
+        }
+        drmFreeDevices(devices, numDevices);
+
+        if (fileDescriptor < 0)
+            sf::err() << "No drm device found!" << std::endl;
+        return fileDescriptor;
+    }
+
+    int initDrm(sf::priv::Drm& drm, const char* device, const char* modeStr, unsigned int vrefresh)
+    {
+        drmModeResPtr resources;
+
+        if (device)
+        {
+            drm.fileDescriptor = open(device, O_RDWR);
+            const int ret = getResources(drm.fileDescriptor, resources);
+            if (ret < 0 && errno == EOPNOTSUPP)
+                sf::err() << device << " does not look like a modeset device" << std::endl;
+        }
+        else
+        {
+            drm.fileDescriptor = findDrmDevice(resources);
+        }
+
+        if (drm.fileDescriptor < 0)
+        {
+            sf::err() << "Could not open drm device" << std::endl;
+            return -1;
+        }
+
+        if (!resources)
+        {
+            sf::err() << "drmModeGetResources failed: " << std::strerror(errno) << std::endl;
+            return -1;
+        }
+
+        // Find a connected connector:
+        drmModeConnectorPtr connector = NULL;
+        for (int i = 0; i < resources->count_connectors; ++i)
+        {
+            connector = drmModeGetConnector(drm.fileDescriptor, resources->connectors[i]);
+            if (connector->connection == DRM_MODE_CONNECTED)
+            {
+                // It's connected, let's use this!
+                break;
+            }
+            drmModeFreeConnector(connector);
+            connector = NULL;
+        }
+
+        if (!connector)
+        {
+            // We could be fancy and listen for hotplug events and wait for a connector..
+            sf::err() << "No connected connector!" << std::endl;
+            return -1;
+        }
+
+        // Find user requested mode:
+        if (modeStr && *modeStr)
+        {
+            for (int i = 0; i < connector->count_modes; ++i)
+            {
+                drmModeModeInfoPtr currentMode = &connector->modes[i];
+
+                if (std::strcmp(currentMode->name, modeStr) == 0)
+                {
+                    if (vrefresh == 0 || currentMode->vrefresh == vrefresh)
+                    {
+                        drm.mode = currentMode;
+                        break;
+                    }
+                }
+            }
+            if (!drm.mode)
+                sf::err() << "Requested mode not found, using default mode!" << std::endl;
+        }
+
+        // Find encoder:
+        drmModeEncoderPtr encoder = NULL;
+        for (int i = 0; i < resources->count_encoders; ++i)
+        {
+            encoder = drmModeGetEncoder(drm.fileDescriptor, resources->encoders[i]);
+            if (encoder->encoder_id == connector->encoder_id)
+                break;
+            drmModeFreeEncoder(encoder);
+            encoder = NULL;
+        }
+
+        if (encoder)
+        {
+            drm.crtcId = encoder->crtc_id;
+        }
+        else
+        {
+            const sf::Uint32 crtcId = findCrtcForConnector(drm, *resources, *connector);
+            if (crtcId == 0)
+            {
+                sf::err() << "No crtc found!" << std::endl;
+                return -1;
+            }
+
+            drm.crtcId = crtcId;
+        }
+
+        drmModeFreeResources(resources);
+
+        drm.connectorId = connector->connector_id;
+
+        drm.savedConnector = connector;
+        drm.savedEncoder = encoder;
+
+        // Get original display mode so we can restore display mode after program exits
+        drm.originalCrtc = drmModeGetCrtc(drm.fileDescriptor, drm.crtcId);
+
+        // Let's use the current mode rather than the preferred one if the user didn't specify a mode with env vars
+        if (!drm.mode)
+        {
+#ifdef SFML_DEBUG
+            sf::err() << "DRM using the current mode" << std::endl;
+#endif
+            drm.mode = &(drm.originalCrtc->mode);
+        }
+
+#ifdef SFML_DEBUG
+        sf::err() << "DRM Mode used: " << drm.mode->name << "@" << drm.mode->vrefresh << std::endl;
+#endif
+
+        return 0;
+    }
+
     void checkInit()
     {
         if (initialized)
@@ -152,27 +460,26 @@ namespace
         if (refreshString)
             refreshRate = static_cast<unsigned int>(atoi(refreshString));
 
-        if (init_drm(&drmNode,
-                     deviceString,     // device
-                     modeString,       // requested mode
-                     refreshRate) < 0) // screen refresh rate
+        if (initDrm(drmNode,
+                    deviceString,     // device
+                    modeString,       // requested mode
+                    refreshRate) < 0) // screen refresh rate
         {
             sf::err() << "Error initializing DRM" << std::endl;
             return;
         }
 
-        gbmDevice = gbm_create_device(drmNode.fd);
+        gbmDevice = gbm_create_device(drmNode.fileDescriptor);
 
         std::atexit(cleanup);
         initialized = true;
 
-        pollFD.fd = drmNode.fd;
+        pollFD.fd = drmNode.fileDescriptor;
         pollFD.events = POLLIN;
         drmEventCtx.version = 2;
         drmEventCtx.page_flip_handler = pageFlipHandler;
     }
 
-
     EGLDisplay getInitializedDisplay()
     {
         checkInit();
@@ -369,7 +676,7 @@ void DRMContext::display()
     }
 
     // Handle display of buffer to the screen
-    drm_fb* fb = NULL;
+    DrmFb* fb = NULL;
 
     if (!waitForFlip(-1))
         return;
@@ -390,7 +697,7 @@ void DRMContext::display()
     if (!m_nextBO)
         return;
 
-    fb = drm_fb_get_from_bo(m_nextBO);
+    fb = drmFbGetFromBo(*m_nextBO);
     if (!fb)
     {
         err() << "Failed to get FB from buffer object" << std::endl;
@@ -400,8 +707,7 @@ void DRMContext::display()
     // If first time, need to first call drmModeSetCrtc()
     if (!m_shown)
     {
-        if (drmModeSetCrtc(drmNode.fd, drmNode.crtc_id, fb->fb_id, 0, 0,
-            &drmNode.connector_id, 1, drmNode.mode))
+        if (drmModeSetCrtc(drmNode.fileDescriptor, drmNode.crtcId, fb->fbId, 0, 0, &drmNode.connectorId, 1, drmNode.mode))
         {
             err() << "Failed to set mode: " << std::strerror(errno) << std::endl;
             std::abort();
@@ -410,8 +716,7 @@ void DRMContext::display()
     }
 
     // Do page flip
-    if (!drmModePageFlip(drmNode.fd, drmNode.crtc_id, fb->fb_id,
-            DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip))
+    if (!drmModePageFlip(drmNode.fileDescriptor, drmNode.crtcId, fb->fbId, DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip))
         waitingForFlip = 1;
 }
 
@@ -560,10 +865,10 @@ GlFunctionPointer DRMContext::getFunction(const char* name)
 
 
 ////////////////////////////////////////////////////////////
-drm* DRMContext::getDRM()
+Drm& DRMContext::getDRM()
 {
     checkInit();
-    return &drmNode;
+    return drmNode;
 }
 
 } // namespace priv
diff --git a/src/SFML/Window/DRM/DRMContext.hpp b/src/SFML/Window/DRM/DRMContext.hpp
index f302a0a7..cde54230 100644
--- a/src/SFML/Window/DRM/DRMContext.hpp
+++ b/src/SFML/Window/DRM/DRMContext.hpp
@@ -33,7 +33,6 @@
 #include <SFML/Window/EGLCheck.hpp>
 #include <SFML/Window/GlContext.hpp>
 #include <SFML/Window/VideoMode.hpp>
-#include <drm-common.h>
 #include <glad/egl.h>
 #include <gbm.h>
 #include <xf86drmMode.h>
@@ -43,6 +42,20 @@ namespace sf
 {
 namespace priv
 {
+struct Drm
+{
+    int fileDescriptor;
+
+    drmModeModeInfoPtr mode;
+    Uint32 crtcId;
+    Uint32 connectorId;
+
+    drmModeCrtcPtr originalCrtc;
+
+    drmModeConnectorPtr savedConnector;
+    drmModeEncoderPtr savedEncoder;
+};
+
 class WindowImplDRM;
 
 class DRMContext : public GlContext
@@ -176,7 +189,7 @@ protected:
     /// \brief Get Direct Rendering Manager pointer
     ///
     ////////////////////////////////////////////////////////////
-    static drm* getDRM();
+    static Drm& getDRM();
 
 private:
 
diff --git a/src/SFML/Window/DRM/VideoModeImpl.cpp b/src/SFML/Window/DRM/VideoModeImpl.cpp
index 13471a47..4f85cad1 100644
--- a/src/SFML/Window/DRM/VideoModeImpl.cpp
+++ b/src/SFML/Window/DRM/VideoModeImpl.cpp
@@ -28,7 +28,6 @@
 #include <SFML/Window/VideoModeImpl.hpp>
 #include <SFML/Window/DRM/DRMContext.hpp>
 #include <SFML/System/Err.hpp>
-#include <drm-common.h>
 
 
 namespace sf
@@ -40,8 +39,8 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
 {
     std::vector<VideoMode> modes;
 
-    drm* drm = sf::priv::DRMContext::getDRM();
-    drmModeConnectorPtr conn = drm->saved_connector;
+    Drm& drm = sf::priv::DRMContext::getDRM();
+    drmModeConnectorPtr conn = drm.savedConnector;
 
     if (conn)
     {
@@ -60,8 +59,8 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
 ////////////////////////////////////////////////////////////
 VideoMode VideoModeImpl::getDesktopMode()
 {
-    drm* drm = sf::priv::DRMContext::getDRM();
-    drmModeModeInfoPtr ptr = drm->mode;
+    Drm& drm = sf::priv::DRMContext::getDRM();
+    drmModeModeInfoPtr ptr = drm.mode;
     if (ptr)
         return VideoMode(ptr->hdisplay, ptr->vdisplay);
     else
diff --git a/src/SFML/Window/DRM/WindowImplDRM.cpp b/src/SFML/Window/DRM/WindowImplDRM.cpp
index 761245c0..e372ca01 100644
--- a/src/SFML/Window/DRM/WindowImplDRM.cpp
+++ b/src/SFML/Window/DRM/WindowImplDRM.cpp
@@ -31,7 +31,6 @@
 #include <SFML/Window/Event.hpp>
 #include <SFML/Window/WindowStyle.hpp>
 #include <SFML/System/Err.hpp>
-#include <drm-common.h>
 
 
 namespace sf
@@ -64,8 +63,8 @@ WindowImplDRM::~WindowImplDRM()
 ////////////////////////////////////////////////////////////
 WindowHandle WindowImplDRM::getSystemHandle() const
 {
-    drm* drm = sf::priv::DRMContext::getDRM();
-    return static_cast<WindowHandle>(drm->fd);
+    Drm& drm = sf::priv::DRMContext::getDRM();
+    return static_cast<WindowHandle>(drm.fileDescriptor);
 }
 
 ////////////////////////////////////////////////////////////