From 78555c0e5704a9a564790f5809c57fb3b7c57c2e Mon Sep 17 00:00:00 2001 From: Chris Thrasher 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 | 360 +++++++++++++++++++++++-- src/SFML/Window/DRM/DRMContext.hpp | 25 +- src/SFML/Window/DRM/VideoModeImpl.cpp | 7 +- src/SFML/Window/DRM/WindowImplDRM.cpp | 3 +- 7 files changed, 365 insertions(+), 485 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 9a870054ae..0000000000 --- a/extlibs/headers/drm/drm-common.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (c) 2017 Rob Clark - * - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 d388e6d0c0..0000000000 --- a/extlibs/headers/drm/drm-common.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2017 Rob Clark - * - * 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 -#include - -#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 b6f117e3fd..133c89eafc 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 $) 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 d92a10a4e3..69d02f03c4 100644 --- a/src/SFML/Window/DRM/DRMContext.cpp +++ b/src/SFML/Window/DRM/DRMContext.cpp @@ -33,8 +33,10 @@ #include #include #include +#include #include #include +#include // We check for this definition in order to avoid multiple definitions of GLAD // entities during unity builds of SFML. @@ -44,10 +46,17 @@ #include #endif +#define WEAK __attribute__((weak)) + +WEAK uint64_t gbm_bo_get_modifier(gbm_bo* bo); +WEAK int gbm_bo_get_plane_count(gbm_bo* bo); +WEAK uint32_t gbm_bo_get_stride_for_plane(gbm_bo* bo, int plane); +WEAK uint32_t gbm_bo_get_offset(gbm_bo* bo, int plane); + namespace { bool initialized = false; - drm drmNode; + sf::priv::Drm drmNode; drmEventContext drmEventCtx; pollfd pollFD; gbm_device* gbmDevice = NULL; @@ -95,21 +104,21 @@ namespace return; /* Avoid a modeswitch if possible */ - if (drmNode.mode != &drmNode.original_crtc->mode) + if (drmNode.mode != &drmNode.originalCrtc->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, + 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; @@ -130,6 +139,314 @@ namespace initialized = false; } + void drmFbDestroyCallback(gbm_bo* bo, void* data) + { + int drmFd = gbm_device_get_fd(gbm_bo_get_device(bo)); + sf::priv::DrmFb* fb = reinterpret_cast(data); + + if (fb->fbId) + drmModeRmFB(drmFd, fb->fbId); + + std::free(fb); + } + + sf::priv::DrmFb* drmFbGetFromBo(gbm_bo& bo) + { + int drmFd = gbm_device_get_fd(gbm_bo_get_device(&bo)); + sf::priv::DrmFb* fb = reinterpret_cast(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 = reinterpret_cast(std::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; + } + + ret = drmModeAddFB2WithModifiers(drmFd, width, height, + format, handles, strides, offsets, + modifiers, &fb->fbId, flags); + } + + if (ret) + { + 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); + ret = drmModeAddFB2(drmFd, width, height, format, handles, strides, offsets, &fb->fbId, 0); + } + + if (ret) + { + std::printf("failed to create fb: %s\n", std::strerror(errno)); + std::free(fb); + return NULL; + } + + gbm_bo_set_user_data(&bo, fb, drmFbDestroyCallback); + + return fb; + } + + uint32_t 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 uint32_t crtcMask = 1U << i; + const uint32_t crtcId = resources.crtcs[i]; + if (encoder.possible_crtcs & crtcMask) + { + return crtcId; + } + } + + // No match found + return 0; + } + + uint32_t findCrtcForConnector(const sf::priv::Drm& drm, const drmModeRes& resources, const drmModeConnector& connector) + { + for (int i = 0; i < connector.count_encoders; i++) + { + const uint32_t encoderId = connector.encoders[i]; + drmModeEncoderPtr encoder = drmModeGetEncoder(drm.fd, encoderId); + + if (encoder) + { + const uint32_t 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 }; + int numDevices, fd = -1; + + numDevices = drmGetDevices2(0, devices, maxDrmDevices); + if (numDevices < 0) + { + std::printf("drmGetDevices2 failed: %s\n", std::strerror(-numDevices)); + return -1; + } + + for (int i = 0; i < numDevices; 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 = getResources(fd, resources); + if(std::getenv("SFML_DRM_DEBUG")) + { + std::printf("DRM device used: %d\n", i); + } + if(!ret && hasMonitorConnected(fd, *resources) != 0) + break; + close(fd); + fd = -1; + } + drmFreeDevices(devices, numDevices); + + if (fd < 0) + std::printf("no drm device found!\n"); + return fd; + } + + int initDrm(sf::priv::Drm& drm, const char* device, const char* modeStr, unsigned int vrefresh) + { + drmModeResPtr resources; + drmModeConnectorPtr connector = NULL; + drmModeEncoderPtr encoder = NULL; + int ret; + + if (device) + { + drm.fd = open(device, O_RDWR); + ret = getResources(drm.fd, resources); + if (ret < 0 && errno == EOPNOTSUPP) + std::printf("%s does not look like a modeset device\n", device); + } + else + { + drm.fd = findDrmDevice(resources); + } + + if (drm.fd < 0) + { + std::printf("could not open drm device\n"); + return -1; + } + + if (!resources) + { + std::printf("drmModeGetResources failed: %s\n", std::strerror(errno)); + return -1; + } + + // find a connected connector: + for (int 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.. + std::printf("no connected connector!\n"); + return -1; + } + + // find user requested mode: + if (modeStr && *modeStr) + { + for (int i = 0; i < connector->count_modes; i++) + { + drmModeModeInfo* currentMode = &connector->modes[i]; + + if (std::strcmp(currentMode->name, modeStr) == 0) + { + if (vrefresh == 0 || currentMode->vrefresh == vrefresh) + { + drm.mode = currentMode; + break; + } + } + } + if (!drm.mode) + std::printf("requested mode not found, using default mode!\n"); + } + + // find encoder: + for (int 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.crtcId = encoder->crtc_id; + } + else + { + uint32_t crtcId = findCrtcForConnector(drm, *resources, *connector); + if (crtcId == 0) + { + std::printf("no crtc found!\n"); + 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.fd, 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) + { + if(std::getenv("SFML_DRM_DEBUG")) + std::printf("DRM using the current mode\n"); + drm.mode = &(drm.originalCrtc->mode); + } + + if (std::getenv("SFML_DRM_DEBUG")) + { + std::printf("DRM Mode used: %s@%d\n", drm.mode->name, drm.mode->vrefresh); + } + + return 0; + } + void checkInit() { if (initialized) @@ -152,10 +469,10 @@ namespace if (refreshString) refreshRate = static_cast(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; @@ -172,7 +489,6 @@ namespace drmEventCtx.page_flip_handler = pageFlipHandler; } - EGLDisplay getInitializedDisplay() { checkInit(); @@ -369,7 +685,7 @@ void DRMContext::display() } // Handle display of buffer to the screen - drm_fb* fb = NULL; + DrmFb* fb = NULL; if (!waitForFlip(-1)) return; @@ -390,7 +706,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 +716,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.fd, 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 +725,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.fd, drmNode.crtcId, fb->fbId, DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip)) waitingForFlip = 1; } @@ -560,7 +874,7 @@ GlFunctionPointer DRMContext::getFunction(const char* name) //////////////////////////////////////////////////////////// -drm* DRMContext::getDRM() +Drm* DRMContext::getDRM() { checkInit(); return &drmNode; diff --git a/src/SFML/Window/DRM/DRMContext.hpp b/src/SFML/Window/DRM/DRMContext.hpp index f302a0a714..a6fb75b162 100644 --- a/src/SFML/Window/DRM/DRMContext.hpp +++ b/src/SFML/Window/DRM/DRMContext.hpp @@ -33,16 +33,37 @@ #include #include #include -#include #include #include #include +struct gbm_bo; + namespace sf { namespace priv { +struct Drm +{ + int fd; + + drmModeModeInfo* mode; + uint32_t crtcId; + uint32_t connectorId; + + drmModeCrtcPtr originalCrtc; + + drmModeConnectorPtr savedConnector; + drmModeEncoderPtr savedEncoder; +}; + +struct DrmFb +{ + gbm_bo* bo; + uint32_t fbId; +}; + class WindowImplDRM; class DRMContext : public GlContext @@ -176,7 +197,7 @@ class DRMContext : public GlContext /// \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 13471a4747..51ea048f2b 100644 --- a/src/SFML/Window/DRM/VideoModeImpl.cpp +++ b/src/SFML/Window/DRM/VideoModeImpl.cpp @@ -28,7 +28,6 @@ #include #include #include -#include namespace sf @@ -40,8 +39,8 @@ std::vector VideoModeImpl::getFullscreenModes() { std::vector 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,7 +59,7 @@ std::vector VideoModeImpl::getFullscreenModes() //////////////////////////////////////////////////////////// VideoMode VideoModeImpl::getDesktopMode() { - drm* drm = sf::priv::DRMContext::getDRM(); + Drm* drm = sf::priv::DRMContext::getDRM(); drmModeModeInfoPtr ptr = drm->mode; if (ptr) return VideoMode(ptr->hdisplay, ptr->vdisplay); diff --git a/src/SFML/Window/DRM/WindowImplDRM.cpp b/src/SFML/Window/DRM/WindowImplDRM.cpp index 761245c0e5..843f32071f 100644 --- a/src/SFML/Window/DRM/WindowImplDRM.cpp +++ b/src/SFML/Window/DRM/WindowImplDRM.cpp @@ -31,7 +31,6 @@ #include #include #include -#include namespace sf @@ -64,7 +63,7 @@ WindowImplDRM::~WindowImplDRM() //////////////////////////////////////////////////////////// WindowHandle WindowImplDRM::getSystemHandle() const { - drm* drm = sf::priv::DRMContext::getDRM(); + Drm* drm = sf::priv::DRMContext::getDRM(); return static_cast(drm->fd); }