Add DRM utilities to sfml-window

This commit is contained in:
Chris Thrasher 2022-10-23 18:48:08 -06:00
parent 07bf6f8c12
commit 866dbee8cb
7 changed files with 357 additions and 494 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -280,13 +280,10 @@ sfml_add_library(sfml-window
# DRM libraries # DRM libraries
if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD) if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
if(SFML_USE_DRM) if(SFML_USE_DRM)
target_sources(sfml-window PRIVATE $<TARGET_OBJECTS:drm-common>)
sfml_find_package(DRM INCLUDE "DRM_INCLUDE_DIR" LINK "DRM_LIBRARY") 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") sfml_find_package(GBM INCLUDE "GBM_INCLUDE_DIR" LINK "GBM_LIBRARY")
target_link_libraries(sfml-window PRIVATE drm gbm EGL) 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() else()
sfml_find_package(X11 INCLUDE "X11_INCLUDE_DIR" LINK "X11_X11_LIB" "X11_Xrandr_LIB" "X11_Xcursor_LIB") 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) target_link_libraries(sfml-window PRIVATE X11)

View File

@ -33,8 +33,10 @@
#include <cerrno> #include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <fcntl.h>
#include <poll.h> #include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <xf86drm.h>
// We check for this definition in order to avoid multiple definitions of GLAD // We check for this definition in order to avoid multiple definitions of GLAD
// entities during unity builds of SFML. // entities during unity builds of SFML.
@ -46,8 +48,14 @@
namespace namespace
{ {
struct DrmFb
{
gbm_bo* bo;
sf::Uint32 fbId;
};
bool initialized = false; bool initialized = false;
drm drmNode; sf::priv::Drm drmNode;
drmEventContext drmEventCtx; drmEventContext drmEventCtx;
pollfd pollFD; pollfd pollFD;
gbm_device* gbmDevice = NULL; gbm_device* gbmDevice = NULL;
@ -79,7 +87,7 @@ namespace
if (pollFD.revents & POLLIN) if (pollFD.revents & POLLIN)
{ {
drmHandleEvent(drmNode.fd, &drmEventCtx); drmHandleEvent(drmNode.fileDescriptor, &drmEventCtx);
} }
else else
{ {
@ -95,21 +103,21 @@ namespace
return; return;
/* Avoid a modeswitch if possible */ /* Avoid a modeswitch if possible */
if (drmNode.mode != &drmNode.original_crtc->mode) if (drmNode.mode != &drmNode.originalCrtc->mode)
drmModeSetCrtc(drmNode.fd, drmModeSetCrtc(drmNode.fileDescriptor,
drmNode.original_crtc->crtc_id, drmNode.originalCrtc->crtc_id,
drmNode.original_crtc->buffer_id, drmNode.originalCrtc->buffer_id,
drmNode.original_crtc->x, drmNode.originalCrtc->x,
drmNode.original_crtc->y, drmNode.originalCrtc->y,
&drmNode.connector_id, &drmNode.connectorId,
1, 1,
&drmNode.original_crtc->mode); &drmNode.originalCrtc->mode);
else if (getenv("SFML_DRM_DEBUG")) else if (getenv("SFML_DRM_DEBUG"))
printf("DRM keeping the same mode since using the original one\n"); printf("DRM keeping the same mode since using the original one\n");
drmModeFreeConnector(drmNode.saved_connector); drmModeFreeConnector(drmNode.savedConnector);
drmModeFreeEncoder(drmNode.saved_encoder); drmModeFreeEncoder(drmNode.savedEncoder);
drmModeFreeCrtc(drmNode.original_crtc); drmModeFreeCrtc(drmNode.originalCrtc);
eglTerminate(display); eglTerminate(display);
display = EGL_NO_DISPLAY; display = EGL_NO_DISPLAY;
@ -117,9 +125,9 @@ namespace
gbm_device_destroy(gbmDevice); gbm_device_destroy(gbmDevice);
gbmDevice = NULL; gbmDevice = NULL;
close(drmNode.fd); close(drmNode.fileDescriptor);
drmNode.fd = -1; drmNode.fileDescriptor = -1;
drmNode.mode = 0; drmNode.mode = 0;
std::memset(&pollFD, 0, sizeof(pollfd)); std::memset(&pollFD, 0, sizeof(pollfd));
@ -130,6 +138,306 @@ namespace
initialized = false; 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() void checkInit()
{ {
if (initialized) if (initialized)
@ -152,27 +460,26 @@ namespace
if (refreshString) if (refreshString)
refreshRate = static_cast<unsigned int>(atoi(refreshString)); refreshRate = static_cast<unsigned int>(atoi(refreshString));
if (init_drm(&drmNode, if (initDrm(drmNode,
deviceString, // device deviceString, // device
modeString, // requested mode modeString, // requested mode
refreshRate) < 0) // screen refresh rate refreshRate) < 0) // screen refresh rate
{ {
sf::err() << "Error initializing DRM" << std::endl; sf::err() << "Error initializing DRM" << std::endl;
return; return;
} }
gbmDevice = gbm_create_device(drmNode.fd); gbmDevice = gbm_create_device(drmNode.fileDescriptor);
std::atexit(cleanup); std::atexit(cleanup);
initialized = true; initialized = true;
pollFD.fd = drmNode.fd; pollFD.fd = drmNode.fileDescriptor;
pollFD.events = POLLIN; pollFD.events = POLLIN;
drmEventCtx.version = 2; drmEventCtx.version = 2;
drmEventCtx.page_flip_handler = pageFlipHandler; drmEventCtx.page_flip_handler = pageFlipHandler;
} }
EGLDisplay getInitializedDisplay() EGLDisplay getInitializedDisplay()
{ {
checkInit(); checkInit();
@ -369,7 +676,7 @@ void DRMContext::display()
} }
// Handle display of buffer to the screen // Handle display of buffer to the screen
drm_fb* fb = NULL; DrmFb* fb = NULL;
if (!waitForFlip(-1)) if (!waitForFlip(-1))
return; return;
@ -390,7 +697,7 @@ void DRMContext::display()
if (!m_nextBO) if (!m_nextBO)
return; return;
fb = drm_fb_get_from_bo(m_nextBO); fb = drmFbGetFromBo(*m_nextBO);
if (!fb) if (!fb)
{ {
err() << "Failed to get FB from buffer object" << std::endl; 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 first time, need to first call drmModeSetCrtc()
if (!m_shown) if (!m_shown)
{ {
if (drmModeSetCrtc(drmNode.fd, drmNode.crtc_id, fb->fb_id, 0, 0, if (drmModeSetCrtc(drmNode.fileDescriptor, drmNode.crtcId, fb->fbId, 0, 0, &drmNode.connectorId, 1, drmNode.mode))
&drmNode.connector_id, 1, drmNode.mode))
{ {
err() << "Failed to set mode: " << std::strerror(errno) << std::endl; err() << "Failed to set mode: " << std::strerror(errno) << std::endl;
std::abort(); std::abort();
@ -410,8 +716,7 @@ void DRMContext::display()
} }
// Do page flip // Do page flip
if (!drmModePageFlip(drmNode.fd, drmNode.crtc_id, fb->fb_id, if (!drmModePageFlip(drmNode.fileDescriptor, drmNode.crtcId, fb->fbId, DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip))
DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip))
waitingForFlip = 1; waitingForFlip = 1;
} }
@ -560,10 +865,10 @@ GlFunctionPointer DRMContext::getFunction(const char* name)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
drm* DRMContext::getDRM() Drm& DRMContext::getDRM()
{ {
checkInit(); checkInit();
return &drmNode; return drmNode;
} }
} // namespace priv } // namespace priv

View File

@ -33,7 +33,6 @@
#include <SFML/Window/EGLCheck.hpp> #include <SFML/Window/EGLCheck.hpp>
#include <SFML/Window/GlContext.hpp> #include <SFML/Window/GlContext.hpp>
#include <SFML/Window/VideoMode.hpp> #include <SFML/Window/VideoMode.hpp>
#include <drm-common.h>
#include <glad/egl.h> #include <glad/egl.h>
#include <gbm.h> #include <gbm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
@ -43,6 +42,20 @@ namespace sf
{ {
namespace priv namespace priv
{ {
struct Drm
{
int fileDescriptor;
drmModeModeInfoPtr mode;
Uint32 crtcId;
Uint32 connectorId;
drmModeCrtcPtr originalCrtc;
drmModeConnectorPtr savedConnector;
drmModeEncoderPtr savedEncoder;
};
class WindowImplDRM; class WindowImplDRM;
class DRMContext : public GlContext class DRMContext : public GlContext
@ -176,7 +189,7 @@ protected:
/// \brief Get Direct Rendering Manager pointer /// \brief Get Direct Rendering Manager pointer
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static drm* getDRM(); static Drm& getDRM();
private: private:

View File

@ -28,7 +28,6 @@
#include <SFML/Window/VideoModeImpl.hpp> #include <SFML/Window/VideoModeImpl.hpp>
#include <SFML/Window/DRM/DRMContext.hpp> #include <SFML/Window/DRM/DRMContext.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <drm-common.h>
namespace sf namespace sf
@ -40,8 +39,8 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
{ {
std::vector<VideoMode> modes; std::vector<VideoMode> modes;
drm* drm = sf::priv::DRMContext::getDRM(); Drm& drm = sf::priv::DRMContext::getDRM();
drmModeConnectorPtr conn = drm->saved_connector; drmModeConnectorPtr conn = drm.savedConnector;
if (conn) if (conn)
{ {
@ -60,8 +59,8 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
VideoMode VideoModeImpl::getDesktopMode() VideoMode VideoModeImpl::getDesktopMode()
{ {
drm* drm = sf::priv::DRMContext::getDRM(); Drm& drm = sf::priv::DRMContext::getDRM();
drmModeModeInfoPtr ptr = drm->mode; drmModeModeInfoPtr ptr = drm.mode;
if (ptr) if (ptr)
return VideoMode(ptr->hdisplay, ptr->vdisplay); return VideoMode(ptr->hdisplay, ptr->vdisplay);
else else

View File

@ -31,7 +31,6 @@
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowStyle.hpp> #include <SFML/Window/WindowStyle.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <drm-common.h>
namespace sf namespace sf
@ -64,8 +63,8 @@ WindowImplDRM::~WindowImplDRM()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
WindowHandle WindowImplDRM::getSystemHandle() const WindowHandle WindowImplDRM::getSystemHandle() const
{ {
drm* drm = sf::priv::DRMContext::getDRM(); Drm& drm = sf::priv::DRMContext::getDRM();
return static_cast<WindowHandle>(drm->fd); return static_cast<WindowHandle>(drm.fileDescriptor);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////