mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 14:21:04 +08:00
Add DRM utilities to sfml-window
This commit is contained in:
parent
07bf6f8c12
commit
866dbee8cb
364
extlibs/headers/drm/drm-common.c
vendored
364
extlibs/headers/drm/drm-common.c
vendored
@ -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;
|
||||
}
|
86
extlibs/headers/drm/drm-common.h
vendored
86
extlibs/headers/drm/drm-common.h
vendored
@ -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 */
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user