Merge pull request #2296 from 2.6.x

This commit is contained in:
Lukas Dürrenberger 2022-12-14 18:08:32 +01:00 committed by GitHub
commit 09ec31eeea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 377 additions and 505 deletions

View File

@ -69,9 +69,14 @@ sfml_set_option(SFML_BUILD_NETWORK TRUE BOOL "TRUE to build SFML's Network modul
# add an option for building the API documentation # add an option for building the API documentation
sfml_set_option(SFML_BUILD_DOC FALSE BOOL "TRUE to generate the API documentation, FALSE to ignore it") sfml_set_option(SFML_BUILD_DOC FALSE BOOL "TRUE to generate the API documentation, FALSE to ignore it")
# add an option for choosing the OpenGL implementation
if(SFML_BUILD_WINDOW) if(SFML_BUILD_WINDOW)
# add an option for choosing the OpenGL implementation
sfml_set_option(SFML_OPENGL_ES ${OPENGL_ES} BOOL "TRUE to use an OpenGL ES implementation, FALSE to use a desktop OpenGL implementation") sfml_set_option(SFML_OPENGL_ES ${OPENGL_ES} BOOL "TRUE to use an OpenGL ES implementation, FALSE to use a desktop OpenGL implementation")
# add an option for choosing whether to use the DRM windowing backend
if(SFML_OS_LINUX)
sfml_set_option(SFML_USE_DRM FALSE BOOL "TRUE to use DRM windowing backend")
endif()
endif() endif()
# add an option for building the test suite # add an option for building the test suite

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

@ -72,6 +72,9 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Check if a mouse button is pressed /// \brief Check if a mouse button is pressed
/// ///
/// \warning Checking the state of buttons Mouse::XButton1 and
/// Mouse::XButton2 is not supported on Linux with X11.
///
/// \param button Button to check /// \param button Button to check
/// ///
/// \return True if the button is pressed, false otherwise /// \return True if the button is pressed, false otherwise

View File

@ -274,13 +274,10 @@ sfml_add_library(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

@ -34,8 +34,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.
@ -47,8 +49,14 @@
namespace namespace
{ {
struct DrmFb
{
gbm_bo* bo;
std::uint32_t fbId;
};
bool initialized = false; bool initialized = false;
drm drmNode; sf::priv::Drm drmNode;
drmEventContext drmEventCtx; drmEventContext drmEventCtx;
pollfd pollFD; pollfd pollFD;
gbm_device* gbmDevice = nullptr; gbm_device* gbmDevice = nullptr;
@ -76,7 +84,7 @@ static bool waitForFlip(int timeout)
if (pollFD.revents & POLLIN) if (pollFD.revents & POLLIN)
{ {
drmHandleEvent(drmNode.fd, &drmEventCtx); drmHandleEvent(drmNode.fileDescriptor, &drmEventCtx);
} }
else else
{ {
@ -91,22 +99,18 @@ void cleanup()
if (!initialized) if (!initialized)
return; return;
/* Avoid a modeswitch if possible */ drmModeSetCrtc(drmNode.fileDescriptor,
if (drmNode.mode != &drmNode.original_crtc->mode) drmNode.originalCrtc->crtc_id,
drmModeSetCrtc(drmNode.fd, drmNode.originalCrtc->buffer_id,
drmNode.original_crtc->crtc_id, drmNode.originalCrtc->x,
drmNode.original_crtc->buffer_id, drmNode.originalCrtc->y,
drmNode.original_crtc->x, &drmNode.connectorId,
drmNode.original_crtc->y,
&drmNode.connector_id,
1, 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); 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;
@ -114,9 +118,9 @@ void cleanup()
gbm_device_destroy(gbmDevice); gbm_device_destroy(gbmDevice);
gbmDevice = nullptr; gbmDevice = nullptr;
close(drmNode.fd); close(drmNode.fileDescriptor);
drmNode.fd = -1; drmNode.fileDescriptor = -1;
drmNode.mode = 0; drmNode.mode = 0;
pollFD = {}; pollFD = {};
@ -127,6 +131,306 @@ void cleanup()
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 std::uint32_t width = gbm_bo_get_width(&bo);
const std::uint32_t height = gbm_bo_get_height(&bo);
const std::uint32_t format = gbm_bo_get_format(&bo);
std::uint32_t strides[4] = {0};
std::uint32_t handles[4] = {0};
std::uint32_t offsets[4] = {0};
std::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];
}
std::uint32_t 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 nullptr;
}
gbm_bo_set_user_data(&bo, fb, drmFbDestroyCallback);
return fb;
}
std::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 std::uint32_t crtcMask = 1U << i;
const std::uint32_t crtcId = resources.crtcs[i];
if (encoder.possible_crtcs & crtcMask)
{
return crtcId;
}
}
// No match found
return 0;
}
std::uint32_t findCrtcForConnector(const sf::priv::Drm& drm, const drmModeRes& resources, const drmModeConnector& connector)
{
for (int i = 0; i < connector.count_encoders; ++i)
{
const std::uint32_t encoderId = connector.encoders[i];
const drmModeEncoderPtr encoder = drmModeGetEncoder(drm.fileDescriptor, encoderId);
if (encoder)
{
const std::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 == nullptr)
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 = nullptr;
return 1;
}
drmModeFreeConnector(connector);
connector = nullptr;
}
return 0;
}
int findDrmDevice(drmModeResPtr& resources)
{
static const int maxDrmDevices = 64;
drmDevicePtr devices[maxDrmDevices] = {nullptr};
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 = nullptr;
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 = nullptr;
}
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 = nullptr;
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 = nullptr;
}
if (encoder)
{
drm.crtcId = encoder->crtc_id;
}
else
{
const std::uint32_t 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)
@ -149,7 +453,7 @@ void checkInit()
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
@ -158,18 +462,17 @@ void checkInit()
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();
@ -360,7 +663,7 @@ void DRMContext::display()
} }
// Handle display of buffer to the screen // Handle display of buffer to the screen
drm_fb* fb = nullptr; DrmFb* fb = nullptr;
if (!waitForFlip(-1)) if (!waitForFlip(-1))
return; return;
@ -381,7 +684,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;
@ -391,7 +694,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, &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; err() << "Failed to set mode: " << std::strerror(errno) << std::endl;
std::abort(); std::abort();
@ -400,7 +703,7 @@ void DRMContext::display()
} }
// Do page flip // 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; waitingForFlip = 1;
} }
@ -549,10 +852,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

@ -36,7 +36,6 @@
#include <glad/egl.h> #include <glad/egl.h>
#include <drm-common.h>
#include <gbm.h> #include <gbm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
@ -45,6 +44,20 @@ namespace sf
{ {
namespace priv namespace priv
{ {
struct Drm
{
int fileDescriptor;
drmModeModeInfoPtr mode;
std::uint32_t crtcId;
std::uint32_t connectorId;
drmModeCrtcPtr originalCrtc;
drmModeConnectorPtr savedConnector;
drmModeEncoderPtr savedEncoder;
};
class WindowImplDRM; class WindowImplDRM;
class DRMContext : public GlContext class DRMContext : public GlContext
@ -174,7 +187,7 @@ protected:
/// \brief Get Direct Rendering Manager pointer /// \brief Get Direct Rendering Manager pointer
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static drm* getDRM(); static Drm& getDRM();
private: private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -29,8 +29,6 @@
#include <SFML/Window/DRM/DRMContext.hpp> #include <SFML/Window/DRM/DRMContext.hpp>
#include <SFML/Window/VideoModeImpl.hpp> #include <SFML/Window/VideoModeImpl.hpp>
#include <drm-common.h>
namespace sf namespace sf
{ {
@ -41,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)
{ {
@ -59,8 +57,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

@ -32,8 +32,6 @@
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowStyle.hpp> #include <SFML/Window/WindowStyle.hpp>
#include <drm-common.h>
namespace sf namespace sf
{ {
@ -64,8 +62,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);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -25,7 +25,6 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/InputImpl.hpp> #include <SFML/Window/Unix/InputImpl.hpp>
#include <SFML/Window/Window.hpp> #include <SFML/Window/Window.hpp>
@ -207,6 +206,9 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button)
// Close the connection with the X server // Close the connection with the X server
closeDisplay(display); closeDisplay(display);
// Buttons 4 and 5 are the vertical wheel and 6 and 7 the horizontal wheel.
// There is no mask for buttons 8 and 9, so checking the state of buttons
// Mouse::XButton1 and Mouse::XButton2 is not supported.
// clang-format off // clang-format off
switch (button) switch (button)
{ {

View File

@ -2030,8 +2030,7 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
// Mouse button pressed // Mouse button pressed
case ButtonPress: case ButtonPress:
{ {
// XXX: Why button 8 and 9? // Buttons 4 and 5 are the vertical wheel and 6 and 7 the horizontal wheel.
// Because 4 and 5 are the vertical wheel and 6 and 7 are horizontal wheel ;)
unsigned int button = windowEvent.xbutton.button; unsigned int button = windowEvent.xbutton.button;
if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9)) if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9))
{ {

View File

@ -85,8 +85,12 @@ void setProcessDpiAware()
{ {
// We only check for E_INVALIDARG because we would get // We only check for E_INVALIDARG because we would get
// E_ACCESSDENIED if the DPI was already set previously // E_ACCESSDENIED if the DPI was already set previously
// and S_OK means the call was successful // and S_OK means the call was successful.
if (SetProcessDpiAwarenessFunc(ProcessSystemDpiAware) == E_INVALIDARG) // We intentionally don't use Per Monitor V2 which can be
// enabled with SetProcessDpiAwarenessContext, because that
// would scale the title bar and thus change window size
// by default when moving the window between monitors.
if (SetProcessDpiAwarenessFunc(ProcessPerMonitorDpiAware) == E_INVALIDARG)
{ {
sf::err() << "Failed to set process DPI awareness" << std::endl; sf::err() << "Failed to set process DPI awareness" << std::endl;
} }