mirror of
https://github.com/SFML/SFML.git
synced 2024-11-25 04:41:05 +08:00
DRM Implementation
Ported sfml-pi DRM/KMS backend written by @mickelson Port co-authored by @substring Co-authored-by: Andrew Mickelson <andrew.mickelson@gmail.com> Co-authored-by: Gil Delescluse <frog2wah@gmail.com>
This commit is contained in:
parent
f7c88ee7ef
commit
b6ca47e128
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -31,13 +31,17 @@ jobs:
|
||||
config: { name: x86, flags: -DCMAKE_ANDROID_ARCH_ABI=x86 -DCMAKE_SYSTEM_NAME=Android -DSFML_BUILD_TEST_SUITE=FALSE -DCMAKE_ANDROID_NDK=$GITHUB_WORKSPACE/android-ndk-r18b -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang -DCMAKE_ANDROID_STL_TYPE=c++_shared -DCMAKE_ANDROID_API=26 }
|
||||
- platform: { name: Android, os: ubuntu-latest }
|
||||
config: { name: armeabi-v7a, flags: -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a -DCMAKE_SYSTEM_NAME=Android -DSFML_BUILD_TEST_SUITE=FALSE -DCMAKE_ANDROID_NDK=$GITHUB_WORKSPACE/android-ndk-r18b -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang -DCMAKE_ANDROID_STL_TYPE=c++_shared -DCMAKE_ANDROID_API=26 }
|
||||
- platform: { name: Linux GCC, os: ubuntu-latest }
|
||||
config: { name: Static DRM, flags: -DBUILD_SHARED_LIBS=FALSE -DSFML_USE_DRM=TRUE }
|
||||
- platform: { name: Linux GCC, os: ubuntu-latest }
|
||||
config: { name: Shared DRM, flags: -DBUILD_SHARED_LIBS=TRUE -DSFML_USE_DRM=TRUE }
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Linux Dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev
|
||||
run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev
|
||||
|
||||
|
||||
- name: Install Android Components
|
||||
|
18
cmake/Modules/FindDRM.cmake
Normal file
18
cmake/Modules/FindDRM.cmake
Normal file
@ -0,0 +1,18 @@
|
||||
#
|
||||
# Try to find EGL library and include path.
|
||||
# Once done this will define
|
||||
#
|
||||
# DRM_FOUND
|
||||
# DRM_INCLUDE_PATH
|
||||
# DRM_LIBRARY
|
||||
#
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_DRM drm QUIET)
|
||||
endif()
|
||||
|
||||
find_path(DRM_INCLUDE_DIR NAMES libdrm/drm.h)
|
||||
find_library(DRM_LIBRARY NAMES drm)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(DRM DEFAULT_MSG DRM_LIBRARY DRM_INCLUDE_DIR)
|
18
cmake/Modules/FindGBM.cmake
Normal file
18
cmake/Modules/FindGBM.cmake
Normal file
@ -0,0 +1,18 @@
|
||||
#
|
||||
# Try to find GBM library and include path.
|
||||
# Once done this will define
|
||||
#
|
||||
# GBM_FOUND
|
||||
# GBM_INCLUDE_PATH
|
||||
# GBM_LIBRARY
|
||||
#
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_GBM gbm QUIET)
|
||||
endif()
|
||||
|
||||
find_path(GBM_INCLUDE_DIR NAMES gbm.h)
|
||||
find_library(GBM_LIBRARY NAMES gbm)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GBM DEFAULT_MSG GBM_LIBRARY GBM_INCLUDE_DIR)
|
@ -31,7 +31,9 @@ if(SFML_BUILD_GRAPHICS)
|
||||
if(SFML_OS_WINDOWS)
|
||||
add_subdirectory(win32)
|
||||
elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
|
||||
add_subdirectory(X11)
|
||||
if(NOT SFML_USE_DRM)
|
||||
add_subdirectory(X11)
|
||||
endif()
|
||||
elseif(SFML_OS_MACOSX AND ${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
add_subdirectory(cocoa)
|
||||
endif()
|
||||
|
358
extlibs/headers/drm/drm-common.c
vendored
Normal file
358
extlibs/headers/drm/drm-common.c
vendored
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
#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 (!ret)
|
||||
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 preferred mode or the highest resolution mode: */
|
||||
if (!drm->mode)
|
||||
{
|
||||
for (i = 0, area = 0; i < connector->count_modes; i++)
|
||||
{
|
||||
drmModeModeInfo *current_mode = &connector->modes[i];
|
||||
|
||||
if (current_mode->type & DRM_MODE_TYPE_PREFERRED)
|
||||
{
|
||||
drm->mode = current_mode;
|
||||
break;
|
||||
}
|
||||
|
||||
int current_area = current_mode->hdisplay * current_mode->vdisplay;
|
||||
if (current_area > area)
|
||||
{
|
||||
drm->mode = current_mode;
|
||||
area = current_area;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!drm->mode)
|
||||
{
|
||||
printf("could not find mode!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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
Normal file
86
extlibs/headers/drm/drm-common.h
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 */
|
@ -82,28 +82,44 @@ if(SFML_OS_WINDOWS)
|
||||
# make sure that we use the Unicode version of the Win API functions
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
|
||||
set(PLATFORM_SRC
|
||||
${SRCROOT}/Unix/CursorImpl.hpp
|
||||
${SRCROOT}/Unix/CursorImpl.cpp
|
||||
${SRCROOT}/Unix/ClipboardImpl.hpp
|
||||
${SRCROOT}/Unix/ClipboardImpl.cpp
|
||||
${SRCROOT}/Unix/Display.cpp
|
||||
${SRCROOT}/Unix/Display.hpp
|
||||
${SRCROOT}/Unix/InputImpl.cpp
|
||||
${SRCROOT}/Unix/InputImpl.hpp
|
||||
${SRCROOT}/Unix/SensorImpl.cpp
|
||||
${SRCROOT}/Unix/SensorImpl.hpp
|
||||
${SRCROOT}/Unix/VideoModeImpl.cpp
|
||||
${SRCROOT}/Unix/VulkanImplX11.cpp
|
||||
${SRCROOT}/Unix/VulkanImplX11.hpp
|
||||
${SRCROOT}/Unix/WindowImplX11.cpp
|
||||
${SRCROOT}/Unix/WindowImplX11.hpp
|
||||
)
|
||||
if(NOT SFML_OS_ANDROID)
|
||||
if(SFML_USE_DRM)
|
||||
add_definitions(-DSFML_USE_DRM)
|
||||
set(PLATFORM_SRC
|
||||
${PLATFORM_SRC}
|
||||
${SRCROOT}/DRM/CursorImpl.hpp
|
||||
${SRCROOT}/DRM/CursorImpl.cpp
|
||||
${SRCROOT}/DRM/ClipboardImpl.hpp
|
||||
${SRCROOT}/DRM/ClipboardImpl.cpp
|
||||
${SRCROOT}/Unix/SensorImpl.cpp
|
||||
${SRCROOT}/Unix/SensorImpl.hpp
|
||||
${SRCROOT}/DRM/InputImplUDev.cpp
|
||||
${SRCROOT}/DRM/InputImplUDev.hpp
|
||||
${SRCROOT}/DRM/VideoModeImpl.cpp
|
||||
${SRCROOT}/DRM/DRMContext.cpp
|
||||
${SRCROOT}/DRM/DRMContext.hpp
|
||||
${SRCROOT}/DRM/WindowImplDRM.cpp
|
||||
${SRCROOT}/DRM/WindowImplDRM.hpp
|
||||
)
|
||||
else()
|
||||
set(PLATFORM_SRC
|
||||
${PLATFORM_SRC}
|
||||
${SRCROOT}/Unix/CursorImpl.hpp
|
||||
${SRCROOT}/Unix/CursorImpl.cpp
|
||||
${SRCROOT}/Unix/ClipboardImpl.hpp
|
||||
${SRCROOT}/Unix/ClipboardImpl.cpp
|
||||
${SRCROOT}/Unix/InputImpl.cpp
|
||||
${SRCROOT}/Unix/InputImpl.hpp
|
||||
${SRCROOT}/Unix/SensorImpl.cpp
|
||||
${SRCROOT}/Unix/SensorImpl.hpp
|
||||
${SRCROOT}/Unix/Display.cpp
|
||||
${SRCROOT}/Unix/Display.hpp
|
||||
${SRCROOT}/Unix/GlxContext.cpp
|
||||
${SRCROOT}/Unix/GlxContext.hpp
|
||||
${SRCROOT}/Unix/VideoModeImpl.cpp
|
||||
${SRCROOT}/Unix/VulkanImplX11.cpp
|
||||
${SRCROOT}/Unix/VulkanImplX11.hpp
|
||||
${SRCROOT}/Unix/WindowImplX11.cpp
|
||||
${SRCROOT}/Unix/WindowImplX11.hpp
|
||||
)
|
||||
endif()
|
||||
if(SFML_OS_LINUX)
|
||||
@ -236,6 +252,21 @@ endif()
|
||||
# define the sfml-window target
|
||||
sfml_add_library(sfml-window
|
||||
SOURCES ${SRC} ${PLATFORM_SRC})
|
||||
# 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)
|
||||
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)
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(sfml-window PUBLIC sfml-system)
|
||||
|
||||
# glad sources
|
||||
@ -249,12 +280,6 @@ endif()
|
||||
# Vulkan headers
|
||||
target_include_directories(sfml-window PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/vulkan")
|
||||
|
||||
# find and setup usage for external libraries
|
||||
if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
|
||||
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)
|
||||
endif()
|
||||
|
||||
# CMake 3.11 and later prefer to choose GLVND, but we choose legacy OpenGL for backward compability
|
||||
# (unless the OpenGL_GL_PREFERENCE was explicitly set)
|
||||
# See CMP0072 for more details (cmake --help-policy CMP0072)
|
||||
@ -268,7 +293,6 @@ if(SFML_OS_IOS)
|
||||
target_link_libraries(sfml-window PRIVATE GLES)
|
||||
elseif(SFML_OS_ANDROID)
|
||||
sfml_find_package(GLES INCLUDE "GLES_INCLUDE_DIR" LINK "GLES_LIBRARY")
|
||||
|
||||
sfml_find_package(EGL INCLUDE "EGL_INCLUDE_DIR" LINK "EGL_LIBRARY")
|
||||
target_link_libraries(sfml-window PRIVATE EGL)
|
||||
target_link_libraries(sfml-window PRIVATE GLES)
|
||||
|
@ -33,7 +33,11 @@
|
||||
#if defined(SFML_SYSTEM_WINDOWS)
|
||||
#include <SFML/Window/Win32/ClipboardImpl.hpp>
|
||||
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
|
||||
#include <SFML/Window/Unix/ClipboardImpl.hpp>
|
||||
#if defined(SFML_USE_DRM)
|
||||
#include <SFML/Window/DRM/ClipboardImpl.hpp>
|
||||
#else
|
||||
#include <SFML/Window/Unix/ClipboardImpl.hpp>
|
||||
#endif
|
||||
#elif defined(SFML_SYSTEM_MACOS)
|
||||
#include <SFML/Window/OSX/ClipboardImpl.hpp>
|
||||
#elif defined(SFML_SYSTEM_IOS)
|
||||
|
@ -31,25 +31,19 @@
|
||||
#include <SFML/Config.hpp>
|
||||
|
||||
#if defined(SFML_SYSTEM_WINDOWS)
|
||||
|
||||
#include <SFML/Window/Win32/CursorImpl.hpp>
|
||||
|
||||
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
|
||||
|
||||
#include <SFML/Window/Unix/CursorImpl.hpp>
|
||||
|
||||
#if defined(SFML_USE_DRM)
|
||||
#include <SFML/Window/DRM/CursorImpl.hpp>
|
||||
#else
|
||||
#include <SFML/Window/Unix/CursorImpl.hpp>
|
||||
#endif
|
||||
#elif defined(SFML_SYSTEM_MACOS)
|
||||
|
||||
#include <SFML/Window/OSX/CursorImpl.hpp>
|
||||
|
||||
#elif defined(SFML_SYSTEM_IOS)
|
||||
|
||||
#include <SFML/Window/iOS/CursorImpl.hpp>
|
||||
|
||||
#elif defined(SFML_SYSTEM_ANDROID)
|
||||
|
||||
#include <SFML/Window/Android/CursorImpl.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
49
src/SFML/Window/DRM/ClipboardImpl.cpp
Normal file
49
src/SFML/Window/DRM/ClipboardImpl.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2022 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/DRM/ClipboardImpl.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
String ClipboardImpl::getString()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ClipboardImpl::setString(const String& /*text*/)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
76
src/SFML/Window/DRM/ClipboardImpl.hpp
Normal file
76
src/SFML/Window/DRM/ClipboardImpl.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2022 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_CLIPBOARDIMPLDRM_HPP
|
||||
#define SFML_CLIPBOARDIMPLDRM_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/System/String.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Give access to the system clipboard
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class ClipboardImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the content of the clipboard as string data
|
||||
///
|
||||
/// This function returns the content of the clipboard
|
||||
/// as a string. If the clipboard does not contain string
|
||||
/// it returns an empty sf::String object.
|
||||
///
|
||||
/// \return Current content of the clipboard
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static String getString();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the content of the clipboard as string data
|
||||
///
|
||||
/// This function sets the content of the clipboard as a
|
||||
/// string.
|
||||
///
|
||||
/// \param text sf::String object containing the data to be sent
|
||||
/// to the clipboard
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void setString(const String& text);
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_CLIPBOARDIMPLDRM_HPP
|
90
src/SFML/Window/DRM/CursorImpl.cpp
Normal file
90
src/SFML/Window/DRM/CursorImpl.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2022 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/DRM/CursorImpl.hpp>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
CursorImpl::CursorImpl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
CursorImpl::~CursorImpl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool CursorImpl::loadFromPixels(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool CursorImpl::loadFromPixelsARGB(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool CursorImpl::loadFromPixelsMonochrome(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool CursorImpl::loadFromSystem(Cursor::Type /*type*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool CursorImpl::isColorCursorSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void CursorImpl::release()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
119
src/SFML/Window/DRM/CursorImpl.hpp
Normal file
119
src/SFML/Window/DRM/CursorImpl.hpp
Normal file
@ -0,0 +1,119 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2022 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_CURSORIMPLDRM_HPP
|
||||
#define SFML_CURSORIMPLDRM_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Cursor.hpp>
|
||||
#include <SFML/System/NonCopyable.hpp>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Unix implementation of Cursor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class CursorImpl : NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
/// Refer to sf::Cursor::Cursor().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CursorImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
/// Refer to sf::Cursor::~Cursor().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~CursorImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a cursor with the provided image
|
||||
///
|
||||
/// Refer to sf::Cursor::loadFromPixels().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a native system cursor
|
||||
///
|
||||
/// Refer to sf::Cursor::loadFromSystem().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadFromSystem(Cursor::Type type);
|
||||
|
||||
private:
|
||||
|
||||
friend class WindowImplDRM;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Checks if colored cursors are supported for this display.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool isColorCursorSupported();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a cursor with the provided image (ARGB support)
|
||||
///
|
||||
/// Refer to sf::Cursor::loadFromPixels().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadFromPixelsARGB(const Uint8* pixels, Vector2u size, Vector2u hotspot);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a cursor with the provided image (monochrome)
|
||||
///
|
||||
/// Refer to sf::Cursor::loadFromPixels().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadFromPixelsMonochrome(const Uint8* pixels, Vector2u size, Vector2u hotspot);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Release the cursor, if we have loaded one.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void release();
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_CUSROSIMPLDRM_HPP
|
555
src/SFML/Window/DRM/DRMContext.cpp
Normal file
555
src/SFML/Window/DRM/DRMContext.cpp
Normal file
@ -0,0 +1,555 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2020 Andrew Mickelson
|
||||
// 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/DRM/DRMContext.hpp>
|
||||
#include <SFML/Window/DRM/WindowImplDRM.hpp>
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/Sleep.hpp>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
bool initialized = false;
|
||||
drm drmNode;
|
||||
drmEventContext drmEventCtx;
|
||||
pollfd pollFD;
|
||||
gbm_device* gbmDevice = NULL;
|
||||
int contextCount = 0;
|
||||
EGLDisplay display = EGL_NO_DISPLAY;
|
||||
int waitingForFlip = 0;
|
||||
|
||||
static void pageFlipHandler(int fd, unsigned int frame,
|
||||
unsigned int sec, unsigned int usec, void* data)
|
||||
{
|
||||
// suppress unused param warning
|
||||
(void)fd, (void)frame, (void)sec, (void)usec;
|
||||
|
||||
int* temp = static_cast<int*>(data);
|
||||
*temp = 0;
|
||||
}
|
||||
|
||||
static bool waitForFlip(int timeout)
|
||||
{
|
||||
while (waitingForFlip)
|
||||
{
|
||||
pollFD.revents = 0;
|
||||
|
||||
if (poll(&pollFD, 1, timeout) < 0)
|
||||
return false;
|
||||
|
||||
if (pollFD.revents & (POLLHUP | POLLERR))
|
||||
return false;
|
||||
|
||||
if (pollFD.revents & POLLIN)
|
||||
{
|
||||
drmHandleEvent(drmNode.fd, &drmEventCtx);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
drmModeSetCrtc(drmNode.fd,
|
||||
drmNode.original_crtc->crtc_id,
|
||||
drmNode.original_crtc->buffer_id,
|
||||
drmNode.original_crtc->x,
|
||||
drmNode.original_crtc->y,
|
||||
&drmNode.connector_id,
|
||||
1,
|
||||
&drmNode.original_crtc->mode);
|
||||
|
||||
drmModeFreeConnector(drmNode.saved_connector);
|
||||
drmModeFreeEncoder(drmNode.saved_encoder);
|
||||
drmModeFreeCrtc(drmNode.original_crtc);
|
||||
|
||||
eglTerminate(display);
|
||||
display = EGL_NO_DISPLAY;
|
||||
|
||||
gbm_device_destroy(gbmDevice);
|
||||
gbmDevice = NULL;
|
||||
|
||||
close(drmNode.fd);
|
||||
|
||||
drmNode.fd = -1;
|
||||
drmNode.mode = 0;
|
||||
|
||||
std::memset(&pollFD, 0, sizeof(pollfd));
|
||||
std::memset(&drmEventCtx, 0, sizeof(drmEventContext));
|
||||
|
||||
waitingForFlip = 0;
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
void checkInit()
|
||||
{
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
// Use environment variable "SFML_DRM_DEVICE" (or NULL if not set)
|
||||
char* deviceString = std::getenv("SFML_DRM_DEVICE");
|
||||
if (deviceString && !*deviceString)
|
||||
deviceString = NULL;
|
||||
|
||||
// Use environment variable "SFML_DRM_MODE" (or NULL if not set)
|
||||
char* modeString = std::getenv("SFML_DRM_MODE");
|
||||
|
||||
// Use environment variable "SFML_DRM_REFRESH" (or 0 if not set)
|
||||
// Use in combination with mode to request specific refresh rate for the mode
|
||||
// if multiple refresh rates for same mode might be supported
|
||||
unsigned int refreshRate = 0;
|
||||
char* refreshString = std::getenv("SFML_DRM_REFRESH");
|
||||
|
||||
if (refreshString)
|
||||
refreshRate = static_cast<unsigned int>(atoi(refreshString));
|
||||
|
||||
if (init_drm(&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);
|
||||
|
||||
std::atexit(cleanup);
|
||||
initialized = true;
|
||||
|
||||
pollFD.fd = drmNode.fd;
|
||||
pollFD.events = POLLIN;
|
||||
drmEventCtx.version = 2;
|
||||
drmEventCtx.page_flip_handler = pageFlipHandler;
|
||||
}
|
||||
|
||||
|
||||
EGLDisplay getInitializedDisplay()
|
||||
{
|
||||
checkInit();
|
||||
|
||||
if (display == EGL_NO_DISPLAY)
|
||||
{
|
||||
display = eglCheck(eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(gbmDevice)));
|
||||
|
||||
EGLint major, minor;
|
||||
eglCheck(eglInitialize(display, &major, &minor));
|
||||
|
||||
#if defined(SFML_OPENGL_ES)
|
||||
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||
{
|
||||
sf::err() << "failed to bind api EGL_OPENGL_ES_API" << std::endl;
|
||||
}
|
||||
#else
|
||||
if (!eglBindAPI(EGL_OPENGL_API))
|
||||
{
|
||||
sf::err() << "failed to bind api EGL_OPENGL_API" << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return display;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
DRMContext::DRMContext(DRMContext* shared) :
|
||||
m_display (EGL_NO_DISPLAY),
|
||||
m_context (EGL_NO_CONTEXT),
|
||||
m_surface (EGL_NO_SURFACE),
|
||||
m_config (NULL),
|
||||
m_currentBO (NULL),
|
||||
m_nextBO (NULL),
|
||||
m_gbmSurface (NULL),
|
||||
m_width (0),
|
||||
m_height (0),
|
||||
m_shown (false),
|
||||
m_scanOut (false)
|
||||
{
|
||||
contextCount++;
|
||||
|
||||
// Get the initialized EGL display
|
||||
m_display = getInitializedDisplay();
|
||||
|
||||
// Get the best EGL config matching the default video settings
|
||||
m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings());
|
||||
updateSettings();
|
||||
|
||||
// Create EGL context
|
||||
createContext(shared);
|
||||
|
||||
if (shared)
|
||||
createSurface(shared->m_width, shared->m_height, VideoMode::getDesktopMode().bitsPerPixel, false);
|
||||
else // create a surface to force the GL to initialize (seems to be required for glGetString() etc )
|
||||
createSurface(1, 1, VideoMode::getDesktopMode().bitsPerPixel, false);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) :
|
||||
m_display (EGL_NO_DISPLAY),
|
||||
m_context (EGL_NO_CONTEXT),
|
||||
m_surface (EGL_NO_SURFACE),
|
||||
m_config (NULL),
|
||||
m_currentBO (NULL),
|
||||
m_nextBO (NULL),
|
||||
m_gbmSurface (NULL),
|
||||
m_width (0),
|
||||
m_height (0),
|
||||
m_shown (false),
|
||||
m_scanOut (false)
|
||||
{
|
||||
contextCount++;
|
||||
|
||||
// Get the initialized EGL display
|
||||
m_display = getInitializedDisplay();
|
||||
|
||||
// Get the best EGL config matching the requested video settings
|
||||
m_config = getBestConfig(m_display, bitsPerPixel, settings);
|
||||
updateSettings();
|
||||
|
||||
// Create EGL context
|
||||
createContext(shared);
|
||||
|
||||
if (owner)
|
||||
{
|
||||
Vector2u size = owner->getSize();
|
||||
createSurface(size.x, size.y, bitsPerPixel, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) :
|
||||
m_display (EGL_NO_DISPLAY),
|
||||
m_context (EGL_NO_CONTEXT),
|
||||
m_surface (EGL_NO_SURFACE),
|
||||
m_config (NULL),
|
||||
m_currentBO (NULL),
|
||||
m_nextBO (NULL),
|
||||
m_gbmSurface (NULL),
|
||||
m_width (0),
|
||||
m_height (0),
|
||||
m_shown (false),
|
||||
m_scanOut (false)
|
||||
{
|
||||
contextCount++;
|
||||
|
||||
// Get the initialized EGL display
|
||||
m_display = getInitializedDisplay();
|
||||
|
||||
// Get the best EGL config matching the requested video settings
|
||||
m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, settings);
|
||||
updateSettings();
|
||||
|
||||
// Create EGL context
|
||||
createContext(shared);
|
||||
createSurface(width, height, VideoMode::getDesktopMode().bitsPerPixel, false);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
DRMContext::~DRMContext()
|
||||
{
|
||||
// Deactivate the current context
|
||||
EGLContext currentContext = eglCheck(eglGetCurrentContext());
|
||||
|
||||
if (currentContext == m_context)
|
||||
{
|
||||
eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
|
||||
}
|
||||
|
||||
// Destroy context
|
||||
if (m_context != EGL_NO_CONTEXT)
|
||||
{
|
||||
eglCheck(eglDestroyContext(m_display, m_context));
|
||||
m_context = EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
// Destroy surface
|
||||
if (m_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
eglCheck(eglDestroySurface(m_display, m_surface));
|
||||
m_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if (m_currentBO)
|
||||
gbm_surface_release_buffer(m_gbmSurface, m_currentBO);
|
||||
|
||||
if (m_nextBO)
|
||||
gbm_surface_release_buffer(m_gbmSurface, m_nextBO);
|
||||
|
||||
if (m_gbmSurface)
|
||||
gbm_surface_destroy(m_gbmSurface);
|
||||
|
||||
contextCount--;
|
||||
if (contextCount == 0)
|
||||
cleanup();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool DRMContext::makeCurrent(bool current)
|
||||
{
|
||||
const EGLSurface surface = current ? m_surface : EGL_NO_SURFACE;
|
||||
const EGLContext context = current ? m_context : EGL_NO_CONTEXT;
|
||||
return m_surface != EGL_NO_SURFACE && eglMakeCurrent(m_display, surface, surface, context);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void DRMContext::display()
|
||||
{
|
||||
if (m_surface == EGL_NO_SURFACE)
|
||||
return;
|
||||
|
||||
if (!m_scanOut)
|
||||
{
|
||||
eglCheck(eglSwapBuffers(m_display, m_surface));
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle display of buffer to the screen
|
||||
drm_fb* fb = NULL;
|
||||
|
||||
if (!waitForFlip(-1))
|
||||
return;
|
||||
|
||||
if (m_currentBO)
|
||||
{
|
||||
gbm_surface_release_buffer(m_gbmSurface, m_currentBO);
|
||||
m_currentBO = NULL;
|
||||
}
|
||||
|
||||
eglCheck(eglSwapBuffers(m_display, m_surface));
|
||||
|
||||
m_currentBO = m_nextBO;
|
||||
|
||||
// This call must be preceeded by a single call to eglSwapBuffers()
|
||||
m_nextBO = gbm_surface_lock_front_buffer(m_gbmSurface);
|
||||
|
||||
if (!m_nextBO)
|
||||
return;
|
||||
|
||||
fb = drm_fb_get_from_bo(m_nextBO);
|
||||
if (!fb)
|
||||
{
|
||||
err() << "Failed to get FB from buffer object" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 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))
|
||||
{
|
||||
err() << "Failed to set mode: " << std::strerror(errno) << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
m_shown = true;
|
||||
}
|
||||
|
||||
// Do page flip
|
||||
if (!drmModePageFlip(drmNode.fd, drmNode.crtc_id, fb->fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip))
|
||||
waitingForFlip = 1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void DRMContext::setVerticalSyncEnabled(bool enabled)
|
||||
{
|
||||
eglCheck(eglSwapInterval(m_display, enabled ? 1 : 0));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void DRMContext::createContext(DRMContext* shared)
|
||||
{
|
||||
const EGLint contextVersion[] =
|
||||
{
|
||||
EGL_CONTEXT_CLIENT_VERSION, 1,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLContext toShared;
|
||||
|
||||
if (shared)
|
||||
toShared = shared->m_context;
|
||||
else
|
||||
toShared = EGL_NO_CONTEXT;
|
||||
|
||||
if (toShared != EGL_NO_CONTEXT)
|
||||
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
// Create EGL context
|
||||
m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion));
|
||||
if (m_context == EGL_NO_CONTEXT)
|
||||
err() << "Failed to create EGL context" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void DRMContext::createSurface(unsigned int width, unsigned int height, unsigned int /*bpp*/, bool scanout)
|
||||
{
|
||||
sf::Uint32 flags = GBM_BO_USE_RENDERING;
|
||||
|
||||
m_scanOut = scanout;
|
||||
if (m_scanOut)
|
||||
flags |= GBM_BO_USE_SCANOUT;
|
||||
|
||||
m_gbmSurface = gbm_surface_create(
|
||||
gbmDevice,
|
||||
width,
|
||||
height,
|
||||
GBM_FORMAT_ARGB8888,
|
||||
flags);
|
||||
|
||||
if (!m_gbmSurface)
|
||||
{
|
||||
err() << "Failed to create gbm surface." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
m_surface = eglCheck(eglCreateWindowSurface(m_display, m_config, reinterpret_cast<EGLNativeWindowType>(m_gbmSurface), NULL));
|
||||
|
||||
if (m_surface == EGL_NO_SURFACE)
|
||||
{
|
||||
err() << "Failed to create EGL Surface" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void DRMContext::destroySurface()
|
||||
{
|
||||
eglCheck(eglDestroySurface(m_display, m_surface));
|
||||
m_surface = EGL_NO_SURFACE;
|
||||
|
||||
gbm_surface_destroy(m_gbmSurface);
|
||||
m_gbmSurface = NULL;
|
||||
|
||||
// Ensure that this context is no longer active since our surface is now destroyed
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
EGLConfig DRMContext::getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings)
|
||||
{
|
||||
// Set our video settings constraint
|
||||
const EGLint attributes[] =
|
||||
{
|
||||
EGL_BUFFER_SIZE, static_cast<EGLint>(bitsPerPixel),
|
||||
EGL_DEPTH_SIZE, static_cast<EGLint>(settings.depthBits),
|
||||
EGL_STENCIL_SIZE, static_cast<EGLint>(settings.stencilBits),
|
||||
EGL_SAMPLE_BUFFERS, static_cast<EGLint>(settings.antialiasingLevel),
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
#if defined(SFML_OPENGL_ES)
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
|
||||
#else
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
||||
#endif
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLint configCount;
|
||||
EGLConfig configs[1];
|
||||
|
||||
// Ask EGL for the best config matching our video settings
|
||||
eglCheck(eglChooseConfig(display, attributes, configs, 1, &configCount));
|
||||
|
||||
return configs[0];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void DRMContext::updateSettings()
|
||||
{
|
||||
EGLint tmp;
|
||||
|
||||
// Update the internal context settings with the current config
|
||||
eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_DEPTH_SIZE, &tmp));
|
||||
m_settings.depthBits = static_cast<unsigned int>(tmp);
|
||||
|
||||
eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_STENCIL_SIZE, &tmp));
|
||||
m_settings.stencilBits = static_cast<unsigned int>(tmp);
|
||||
|
||||
eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_SAMPLES, &tmp));
|
||||
m_settings.antialiasingLevel = static_cast<unsigned int>(tmp);
|
||||
|
||||
m_settings.majorVersion = 1;
|
||||
m_settings.minorVersion = 1;
|
||||
m_settings.attributeFlags = ContextSettings::Default;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
GlFunctionPointer DRMContext::getFunction(const char* name)
|
||||
{
|
||||
return reinterpret_cast<GlFunctionPointer>(eglGetProcAddress(name));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
drm* DRMContext::getDRM()
|
||||
{
|
||||
checkInit();
|
||||
return &drmNode;
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
214
src/SFML/Window/DRM/DRMContext.hpp
Normal file
214
src/SFML/Window/DRM/DRMContext.hpp
Normal file
@ -0,0 +1,214 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2020 Andrew Mickelson
|
||||
// 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_DRMCONTEXT_HPP
|
||||
#define SFML_DRMCONTEXT_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/ContextSettings.hpp>
|
||||
#include <SFML/Window/EGLCheck.hpp>
|
||||
#include <SFML/Window/GlContext.hpp>
|
||||
#include <SFML/Window/VideoMode.hpp>
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include <drm-common.h>
|
||||
#define EGL_NO_X11
|
||||
#define MESA_EGL_NO_X11_HEADERS
|
||||
#include <EGL/egl.h>
|
||||
#include <gbm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
class WindowImplDRM;
|
||||
|
||||
class DRMContext : public GlContext
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a new context, not associated to a window
|
||||
///
|
||||
/// \param shared Context to share the new one with (can be NULL)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
DRMContext(DRMContext* shared);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a new context attached to a window
|
||||
///
|
||||
/// \param shared Context to share the new one with
|
||||
/// \param settings Creation parameters
|
||||
/// \param owner Pointer to the owner window
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
DRMContext(DRMContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a new context that embeds its own rendering target
|
||||
///
|
||||
/// \param shared Context to share the new one with
|
||||
/// \param settings Creation parameters
|
||||
/// \param width Back buffer width, in pixels
|
||||
/// \param height Back buffer height, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
DRMContext(DRMContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~DRMContext();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Activate the context as the current target
|
||||
/// for rendering
|
||||
///
|
||||
/// \param current Whether to make the context current or no longer current
|
||||
///
|
||||
/// \return True on success, false if any error happened
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool makeCurrent(bool current);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Display what has been rendered to the context so far
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void display();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable vertical synchronization
|
||||
///
|
||||
/// Activating vertical synchronization will limit the number
|
||||
/// of frames displayed to the refresh rate of the monitor.
|
||||
/// This can avoid some visual artifacts, and limit the framerate
|
||||
/// to a good value (but not constant across different computers).
|
||||
///
|
||||
/// \param enabled: True to enable v-sync, false to deactivate
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setVerticalSyncEnabled(bool enabled);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the EGL context
|
||||
///
|
||||
/// \param shared Context to share the new one with (can be NULL)
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
/// \param settings Creation parameters
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void createContext(DRMContext* shared);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the EGL surface
|
||||
///
|
||||
/// \param width Back buffer width, in pixels
|
||||
/// \param height Back buffer height, in pixels
|
||||
/// \param bpp Pixel depth, in bits per pixel
|
||||
/// \param scanout True to present the surface to the screen
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void createSurface(unsigned int width, unsigned int height, unsigned int bpp, bool scanout);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destroy the EGL surface
|
||||
///
|
||||
/// This function must be called when the activity is stopped, or
|
||||
/// when the orientation change.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void destroySurface();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the best EGL visual for a given set of video settings
|
||||
///
|
||||
/// \param display EGL display
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
/// \param settings Requested context settings
|
||||
///
|
||||
/// \return The best EGL config
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static EGLConfig getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the address of an OpenGL function
|
||||
///
|
||||
/// \param name Name of the function to get the address of
|
||||
///
|
||||
/// \return Address of the OpenGL function, 0 on failure
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static GlFunctionPointer getFunction(const char* name);
|
||||
|
||||
protected:
|
||||
|
||||
friend class VideoModeImpl;
|
||||
friend class WindowImplDRM;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get Direct Rendering Manager pointer
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static drm* getDRM();
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Helper to copy the picked EGL configuration
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void updateSettings();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
EGLDisplay m_display; ///< The internal EGL display
|
||||
EGLContext m_context; ///< The internal EGL context
|
||||
EGLSurface m_surface; ///< The internal EGL surface
|
||||
EGLConfig m_config; ///< The internal EGL config
|
||||
|
||||
gbm_bo* m_currentBO;
|
||||
gbm_bo* m_nextBO;
|
||||
gbm_surface* m_gbmSurface;
|
||||
unsigned int m_width;
|
||||
unsigned int m_height;
|
||||
bool m_shown;
|
||||
bool m_scanOut;
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_DRMCONTEXT_HPP
|
716
src/SFML/Window/DRM/InputImplUDev.cpp
Normal file
716
src/SFML/Window/DRM/InputImplUDev.cpp
Normal file
@ -0,0 +1,716 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2016 Andrew Mickelson
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/DRM/InputImplUDev.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
struct TouchSlot
|
||||
{
|
||||
int oldId;
|
||||
int id;
|
||||
sf::Vector2i pos;
|
||||
|
||||
TouchSlot() :
|
||||
oldId(-1),
|
||||
id(-1),
|
||||
pos(0, 0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
sf::Mutex inputMutex; // threadsafe? maybe...
|
||||
sf::Vector2i mousePos; // current mouse position
|
||||
|
||||
std::vector<int> fileDescriptors; // list of open file descriptors for /dev/input
|
||||
std::vector<bool> mouseMap(sf::Mouse::ButtonCount, false); // track whether keys are down
|
||||
std::vector<bool> keyMap(sf::Keyboard::KeyCount, false); // track whether mouse buttons are down
|
||||
|
||||
int touchFd = -1; // file descriptor we have seen MT events on; assumes only 1
|
||||
std::vector<TouchSlot> touchSlots; // track the state of each touch "slot"
|
||||
int currentSlot = 0; // which slot are we currently updating?
|
||||
|
||||
std::queue<sf::Event> eventQueue; // events received and waiting to be consumed
|
||||
const int MAX_QUEUE = 64; // The maximum size we let eventQueue grow to
|
||||
|
||||
termios newTerminalConfig, oldTerminalConfig; // Terminal configurations
|
||||
|
||||
bool altDown() { return (keyMap[sf::Keyboard::LAlt] || keyMap[sf::Keyboard::RAlt]); }
|
||||
bool controlDown() { return (keyMap[sf::Keyboard::LControl] || keyMap[sf::Keyboard::RControl]); }
|
||||
bool shiftDown() { return (keyMap[sf::Keyboard::LShift] || keyMap[sf::Keyboard::RShift]); }
|
||||
bool systemDown() { return (keyMap[sf::Keyboard::LSystem] || keyMap[sf::Keyboard::RSystem]); }
|
||||
|
||||
void uninitFileDescriptors(void)
|
||||
{
|
||||
for (std::vector<int>::iterator itr = fileDescriptors.begin(); itr != fileDescriptors.end(); ++itr)
|
||||
close(*itr);
|
||||
}
|
||||
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
#define NBITS(x) (((x - 1) / BITS_PER_LONG) + 1)
|
||||
#define OFF(x) (x % BITS_PER_LONG)
|
||||
#define LONG(x) (x / BITS_PER_LONG)
|
||||
#define TEST_BIT(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
||||
|
||||
// Only keep fileDescriptors that we think are a keyboard, mouse or touchpad/touchscreen
|
||||
// Joysticks are handled in /src/SFML/Window/Unix/JoystickImpl.cpp
|
||||
bool keepFileDescriptor(int fileDesc)
|
||||
{
|
||||
unsigned long bitmask_ev[NBITS(EV_MAX)];
|
||||
unsigned long bitmask_key[NBITS(KEY_MAX)];
|
||||
unsigned long bitmask_abs[NBITS(ABS_MAX)];
|
||||
unsigned long bitmask_rel[NBITS(REL_MAX)];
|
||||
|
||||
ioctl(fileDesc, EVIOCGBIT(0, sizeof(bitmask_ev)), &bitmask_ev);
|
||||
ioctl(fileDesc, EVIOCGBIT(EV_KEY, sizeof(bitmask_key)), &bitmask_key);
|
||||
ioctl(fileDesc, EVIOCGBIT(EV_ABS, sizeof(bitmask_abs)), &bitmask_abs);
|
||||
ioctl(fileDesc, EVIOCGBIT(EV_REL, sizeof(bitmask_rel)), &bitmask_rel);
|
||||
|
||||
// This is the keyboard test used by SDL.
|
||||
// The first 32 bits are ESC, numbers and Q to D; If we have any of those,
|
||||
// consider it a keyboard device; do not test for KEY_RESERVED, though
|
||||
bool is_keyboard = (bitmask_key[0] & 0xFFFFFFFE);
|
||||
|
||||
bool is_abs = TEST_BIT(EV_ABS, bitmask_ev)
|
||||
&& TEST_BIT(ABS_X, bitmask_abs) && TEST_BIT(ABS_Y, bitmask_abs);
|
||||
|
||||
bool is_rel = TEST_BIT(EV_REL, bitmask_ev)
|
||||
&& TEST_BIT(REL_X, bitmask_rel) && TEST_BIT(REL_Y, bitmask_rel);
|
||||
|
||||
bool is_mouse = (is_abs || is_rel) && TEST_BIT(BTN_MOUSE, bitmask_key);
|
||||
|
||||
bool is_touch = is_abs && (TEST_BIT(BTN_TOOL_FINGER, bitmask_key) || TEST_BIT(BTN_TOUCH, bitmask_key));
|
||||
|
||||
return is_keyboard || is_mouse || is_touch;
|
||||
}
|
||||
|
||||
void initFileDescriptors()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
initialized = true;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
std::string name("/dev/input/event");
|
||||
std::ostringstream stream;
|
||||
stream << i;
|
||||
name += stream.str();
|
||||
|
||||
int tempFD = open(name.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
|
||||
if (tempFD < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
sf::err() << "Error opening " << name << ": " << std::strerror(errno) << std::endl;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keepFileDescriptor(tempFD))
|
||||
fileDescriptors.push_back(tempFD);
|
||||
else
|
||||
close(tempFD);
|
||||
}
|
||||
|
||||
std::atexit(uninitFileDescriptors);
|
||||
}
|
||||
|
||||
sf::Mouse::Button toMouseButton(int code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case BTN_LEFT: return sf::Mouse::Left;
|
||||
case BTN_RIGHT: return sf::Mouse::Right;
|
||||
case BTN_MIDDLE: return sf::Mouse::Middle;
|
||||
case BTN_SIDE: return sf::Mouse::XButton1;
|
||||
case BTN_EXTRA: return sf::Mouse::XButton2;
|
||||
|
||||
default:
|
||||
return sf::Mouse::ButtonCount;
|
||||
}
|
||||
}
|
||||
|
||||
sf::Keyboard::Key toKey(int code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case KEY_ESC: return sf::Keyboard::Escape;
|
||||
case KEY_1: return sf::Keyboard::Num1;
|
||||
case KEY_2: return sf::Keyboard::Num2;
|
||||
case KEY_3: return sf::Keyboard::Num3;
|
||||
case KEY_4: return sf::Keyboard::Num4;
|
||||
case KEY_5: return sf::Keyboard::Num5;
|
||||
case KEY_6: return sf::Keyboard::Num6;
|
||||
case KEY_7: return sf::Keyboard::Num7;
|
||||
case KEY_8: return sf::Keyboard::Num8;
|
||||
case KEY_9: return sf::Keyboard::Num9;
|
||||
case KEY_0: return sf::Keyboard::Num0;
|
||||
case KEY_MINUS: return sf::Keyboard::Hyphen;
|
||||
case KEY_EQUAL: return sf::Keyboard::Equal;
|
||||
case KEY_BACKSPACE: return sf::Keyboard::Backspace;
|
||||
case KEY_TAB: return sf::Keyboard::Tab;
|
||||
case KEY_Q: return sf::Keyboard::Q;
|
||||
case KEY_W: return sf::Keyboard::W;
|
||||
case KEY_E: return sf::Keyboard::E;
|
||||
case KEY_R: return sf::Keyboard::R;
|
||||
case KEY_T: return sf::Keyboard::T;
|
||||
case KEY_Y: return sf::Keyboard::Y;
|
||||
case KEY_U: return sf::Keyboard::U;
|
||||
case KEY_I: return sf::Keyboard::I;
|
||||
case KEY_O: return sf::Keyboard::O;
|
||||
case KEY_P: return sf::Keyboard::P;
|
||||
case KEY_LEFTBRACE: return sf::Keyboard::LBracket;
|
||||
case KEY_RIGHTBRACE: return sf::Keyboard::RBracket;
|
||||
case KEY_KPENTER:
|
||||
case KEY_ENTER: return sf::Keyboard::Enter;
|
||||
case KEY_LEFTCTRL: return sf::Keyboard::LControl;
|
||||
case KEY_A: return sf::Keyboard::A;
|
||||
case KEY_S: return sf::Keyboard::S;
|
||||
case KEY_D: return sf::Keyboard::D;
|
||||
case KEY_F: return sf::Keyboard::F;
|
||||
case KEY_G: return sf::Keyboard::G;
|
||||
case KEY_H: return sf::Keyboard::H;
|
||||
case KEY_J: return sf::Keyboard::J;
|
||||
case KEY_K: return sf::Keyboard::K;
|
||||
case KEY_L: return sf::Keyboard::L;
|
||||
case KEY_SEMICOLON: return sf::Keyboard::Semicolon;
|
||||
case KEY_APOSTROPHE: return sf::Keyboard::Quote;
|
||||
case KEY_GRAVE: return sf::Keyboard::Tilde;
|
||||
case KEY_LEFTSHIFT: return sf::Keyboard::LShift;
|
||||
case KEY_BACKSLASH: return sf::Keyboard::Backslash;
|
||||
case KEY_Z: return sf::Keyboard::Z;
|
||||
case KEY_X: return sf::Keyboard::X;
|
||||
case KEY_C: return sf::Keyboard::C;
|
||||
case KEY_V: return sf::Keyboard::V;
|
||||
case KEY_B: return sf::Keyboard::B;
|
||||
case KEY_N: return sf::Keyboard::N;
|
||||
case KEY_M: return sf::Keyboard::M;
|
||||
case KEY_COMMA: return sf::Keyboard::Comma;
|
||||
case KEY_DOT: return sf::Keyboard::Period;
|
||||
case KEY_SLASH: return sf::Keyboard::Slash;
|
||||
case KEY_RIGHTSHIFT: return sf::Keyboard::RShift;
|
||||
case KEY_KPASTERISK: return sf::Keyboard::Multiply;
|
||||
case KEY_LEFTALT: return sf::Keyboard::LAlt;
|
||||
case KEY_SPACE: return sf::Keyboard::Space;
|
||||
case KEY_F1: return sf::Keyboard::F1;
|
||||
case KEY_F2: return sf::Keyboard::F2;
|
||||
case KEY_F3: return sf::Keyboard::F3;
|
||||
case KEY_F4: return sf::Keyboard::F4;
|
||||
case KEY_F5: return sf::Keyboard::F5;
|
||||
case KEY_F6: return sf::Keyboard::F6;
|
||||
case KEY_F7: return sf::Keyboard::F7;
|
||||
case KEY_F8: return sf::Keyboard::F8;
|
||||
case KEY_F9: return sf::Keyboard::F9;
|
||||
case KEY_F10: return sf::Keyboard::F10;
|
||||
case KEY_F11: return sf::Keyboard::F11;
|
||||
case KEY_F12: return sf::Keyboard::F12;
|
||||
case KEY_F13: return sf::Keyboard::F13;
|
||||
case KEY_F14: return sf::Keyboard::F14;
|
||||
case KEY_F15: return sf::Keyboard::F15;
|
||||
case KEY_KP7: return sf::Keyboard::Numpad7;
|
||||
case KEY_KP8: return sf::Keyboard::Numpad8;
|
||||
case KEY_KP9: return sf::Keyboard::Numpad9;
|
||||
case KEY_KPMINUS: return sf::Keyboard::Subtract;
|
||||
case KEY_KP4: return sf::Keyboard::Numpad4;
|
||||
case KEY_KP5: return sf::Keyboard::Numpad5;
|
||||
case KEY_KP6: return sf::Keyboard::Numpad6;
|
||||
case KEY_KPPLUS: return sf::Keyboard::Add;
|
||||
case KEY_KP1: return sf::Keyboard::Numpad1;
|
||||
case KEY_KP2: return sf::Keyboard::Numpad2;
|
||||
case KEY_KP3: return sf::Keyboard::Numpad3;
|
||||
case KEY_KP0: return sf::Keyboard::Numpad0;
|
||||
case KEY_KPDOT: return sf::Keyboard::Delete;
|
||||
case KEY_RIGHTCTRL: return sf::Keyboard::RControl;
|
||||
case KEY_KPSLASH: return sf::Keyboard::Divide;
|
||||
case KEY_RIGHTALT: return sf::Keyboard::RAlt;
|
||||
case KEY_HOME: return sf::Keyboard::Home;
|
||||
case KEY_UP: return sf::Keyboard::Up;
|
||||
case KEY_PAGEUP: return sf::Keyboard::PageUp;
|
||||
case KEY_LEFT: return sf::Keyboard::Left;
|
||||
case KEY_RIGHT: return sf::Keyboard::Right;
|
||||
case KEY_END: return sf::Keyboard::End;
|
||||
case KEY_DOWN: return sf::Keyboard::Down;
|
||||
case KEY_PAGEDOWN: return sf::Keyboard::PageDown;
|
||||
case KEY_INSERT: return sf::Keyboard::Insert;
|
||||
case KEY_DELETE: return sf::Keyboard::Delete;
|
||||
case KEY_PAUSE: return sf::Keyboard::Pause;
|
||||
case KEY_LEFTMETA: return sf::Keyboard::LSystem;
|
||||
case KEY_RIGHTMETA: return sf::Keyboard::RSystem;
|
||||
|
||||
case KEY_RESERVED:
|
||||
case KEY_SYSRQ:
|
||||
case KEY_CAPSLOCK:
|
||||
case KEY_NUMLOCK:
|
||||
case KEY_SCROLLLOCK:
|
||||
default:
|
||||
return sf::Keyboard::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void pushEvent(sf::Event& event)
|
||||
{
|
||||
if (eventQueue.size() >= MAX_QUEUE)
|
||||
eventQueue.pop();
|
||||
|
||||
eventQueue.push(event);
|
||||
}
|
||||
|
||||
TouchSlot& atSlot(int idx)
|
||||
{
|
||||
if (idx >= static_cast<int>(touchSlots.size()))
|
||||
touchSlots.resize(static_cast<size_t>(idx + 1));
|
||||
return touchSlots.at(static_cast<size_t>(idx));
|
||||
}
|
||||
|
||||
void processSlots()
|
||||
{
|
||||
for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
|
||||
{
|
||||
sf::Event event;
|
||||
|
||||
event.touch.x = slot->pos.x;
|
||||
event.touch.y = slot->pos.y;
|
||||
|
||||
if (slot->oldId == slot->id)
|
||||
{
|
||||
event.type = sf::Event::TouchMoved;
|
||||
event.touch.finger = static_cast<unsigned int>(slot->id);
|
||||
pushEvent(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (slot->oldId != -1)
|
||||
{
|
||||
event.type = sf::Event::TouchEnded;
|
||||
event.touch.finger = static_cast<unsigned int>(slot->oldId);
|
||||
pushEvent(event);
|
||||
}
|
||||
if (slot->id != -1)
|
||||
{
|
||||
event.type = sf::Event::TouchBegan;
|
||||
event.touch.finger = static_cast<unsigned int>(slot->id);
|
||||
pushEvent(event);
|
||||
}
|
||||
|
||||
slot->oldId = slot->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool eventProcess(sf::Event& event)
|
||||
{
|
||||
sf::Lock lock(inputMutex);
|
||||
|
||||
// Ensure that we are initialized
|
||||
initFileDescriptors();
|
||||
|
||||
// This is for handling the Backspace and DEL text events, which we
|
||||
// generate based on keystrokes (and not stdin)
|
||||
static unsigned int doDeferredText = 0;
|
||||
if (doDeferredText)
|
||||
{
|
||||
event.type = sf::Event::TextEntered;
|
||||
event.text.unicode = doDeferredText;
|
||||
doDeferredText = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t bytesRead;
|
||||
|
||||
// Check all the open file descriptors for the next event
|
||||
for (std::vector<int>::iterator itr = fileDescriptors.begin(); itr != fileDescriptors.end(); ++itr)
|
||||
{
|
||||
input_event inputEvent;
|
||||
bytesRead = read(*itr, &inputEvent, sizeof(inputEvent));
|
||||
|
||||
while (bytesRead > 0)
|
||||
{
|
||||
if (inputEvent.type == EV_KEY)
|
||||
{
|
||||
sf::Mouse::Button mb = toMouseButton(inputEvent.code);
|
||||
if (mb != sf::Mouse::ButtonCount)
|
||||
{
|
||||
event.type = inputEvent.value ? sf::Event::MouseButtonPressed : sf::Event::MouseButtonReleased;
|
||||
event.mouseButton.button = mb;
|
||||
event.mouseButton.x = mousePos.x;
|
||||
event.mouseButton.y = mousePos.y;
|
||||
|
||||
mouseMap[mb] = inputEvent.value;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sf::Keyboard::Key kb = toKey(inputEvent.code);
|
||||
|
||||
unsigned int special = 0;
|
||||
if ((kb == sf::Keyboard::Delete)
|
||||
|| (kb == sf::Keyboard::Backspace))
|
||||
special = (kb == sf::Keyboard::Delete) ? 127 : 8;
|
||||
|
||||
if (inputEvent.value == 2)
|
||||
{
|
||||
// key repeat events
|
||||
//
|
||||
if (special)
|
||||
{
|
||||
event.type = sf::Event::TextEntered;
|
||||
event.text.unicode = special;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (kb != sf::Keyboard::Unknown)
|
||||
{
|
||||
// key down and key up events
|
||||
//
|
||||
event.type = inputEvent.value ? sf::Event::KeyPressed : sf::Event::KeyReleased;
|
||||
event.key.code = kb;
|
||||
event.key.alt = altDown();
|
||||
event.key.control = controlDown();
|
||||
event.key.shift = shiftDown();
|
||||
event.key.system = systemDown();
|
||||
|
||||
keyMap[kb] = inputEvent.value;
|
||||
|
||||
if (special && inputEvent.value)
|
||||
doDeferredText = special;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (inputEvent.type == EV_REL)
|
||||
{
|
||||
bool posChange = false;
|
||||
switch (inputEvent.code)
|
||||
{
|
||||
case REL_X:
|
||||
mousePos.x += inputEvent.value;
|
||||
posChange = true;
|
||||
break;
|
||||
|
||||
case REL_Y:
|
||||
mousePos.y += inputEvent.value;
|
||||
posChange = true;
|
||||
break;
|
||||
|
||||
case REL_WHEEL:
|
||||
event.type = sf::Event::MouseWheelScrolled;
|
||||
event.mouseWheelScroll.delta = static_cast<float>(inputEvent.value);
|
||||
event.mouseWheelScroll.x = mousePos.x;
|
||||
event.mouseWheelScroll.y = mousePos.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (posChange)
|
||||
{
|
||||
event.type = sf::Event::MouseMoved;
|
||||
event.mouseMove.x = mousePos.x;
|
||||
event.mouseMove.y = mousePos.y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (inputEvent.type == EV_ABS)
|
||||
{
|
||||
switch (inputEvent.code)
|
||||
{
|
||||
case ABS_MT_SLOT:
|
||||
currentSlot = inputEvent.value;
|
||||
touchFd = *itr;
|
||||
break;
|
||||
case ABS_MT_TRACKING_ID:
|
||||
atSlot(currentSlot).id = inputEvent.value;
|
||||
touchFd = *itr;
|
||||
break;
|
||||
case ABS_MT_POSITION_X:
|
||||
atSlot(currentSlot).pos.x = inputEvent.value;
|
||||
touchFd = *itr;
|
||||
break;
|
||||
case ABS_MT_POSITION_Y:
|
||||
atSlot(currentSlot).pos.y = inputEvent.value;
|
||||
touchFd = *itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (inputEvent.type == EV_SYN && inputEvent.code == SYN_REPORT &&
|
||||
*itr == touchFd)
|
||||
{
|
||||
// This pushes events directly to the queue, because it
|
||||
// can generate more than one event.
|
||||
processSlots();
|
||||
}
|
||||
|
||||
bytesRead = read(*itr, &inputEvent, sizeof(inputEvent));
|
||||
}
|
||||
|
||||
if ((bytesRead < 0) && (errno != EAGAIN))
|
||||
sf::err() << " Error: " << std::strerror(errno) << std::endl;
|
||||
}
|
||||
|
||||
// Finally check if there is a Text event on stdin
|
||||
//
|
||||
// We only clear the ICANON flag for the time of reading
|
||||
|
||||
newTerminalConfig.c_lflag &= ~(tcflag_t)ICANON;
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig);
|
||||
|
||||
timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
unsigned char code = 0;
|
||||
|
||||
fd_set readFDSet;
|
||||
FD_ZERO(&readFDSet);
|
||||
FD_SET(STDIN_FILENO, &readFDSet);
|
||||
int ready = select(STDIN_FILENO + 1, &readFDSet, NULL, NULL, &timeout);
|
||||
|
||||
if (ready > 0 && FD_ISSET(STDIN_FILENO, &readFDSet))
|
||||
bytesRead = read(STDIN_FILENO, &code, 1);
|
||||
|
||||
if ((code == 127) || (code == 8)) // Suppress 127 (DEL) to 8 (BACKSPACE)
|
||||
code = 0;
|
||||
else if (code == 27) // ESC
|
||||
{
|
||||
// Suppress ANSI escape sequences
|
||||
FD_ZERO(&readFDSet);
|
||||
FD_SET(STDIN_FILENO, &readFDSet);
|
||||
ready = select(STDIN_FILENO + 1, &readFDSet, NULL, NULL, &timeout);
|
||||
if (ready > 0 && FD_ISSET(STDIN_FILENO, &readFDSet))
|
||||
{
|
||||
unsigned char tempBuffer[16];
|
||||
bytesRead = read(STDIN_FILENO, tempBuffer, 16);
|
||||
code = 0;
|
||||
}
|
||||
}
|
||||
|
||||
newTerminalConfig.c_lflag |= ICANON;
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig);
|
||||
|
||||
if (code > 0)
|
||||
{
|
||||
// TODO: Proper unicode handling
|
||||
event.type = sf::Event::TextEntered;
|
||||
event.text.unicode = code;
|
||||
return true;
|
||||
}
|
||||
|
||||
// No events available
|
||||
return false;
|
||||
}
|
||||
|
||||
// assumes inputMutex is locked
|
||||
void update()
|
||||
{
|
||||
sf::Event event;
|
||||
while (eventProcess(event))
|
||||
{
|
||||
pushEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
bool InputImpl::isKeyPressed(Keyboard::Key key)
|
||||
{
|
||||
Lock lock(inputMutex);
|
||||
if ((key < 0) || (key >= static_cast<int>(keyMap.size())))
|
||||
return false;
|
||||
|
||||
update();
|
||||
return keyMap[key];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
|
||||
{
|
||||
// Not applicable
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool InputImpl::isMouseButtonPressed(Mouse::Button button)
|
||||
{
|
||||
Lock lock(inputMutex);
|
||||
if ((button < 0) || (button >= static_cast<int>(mouseMap.size())))
|
||||
return false;
|
||||
|
||||
update();
|
||||
return mouseMap[button];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i InputImpl::getMousePosition()
|
||||
{
|
||||
Lock lock(inputMutex);
|
||||
return mousePos;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i InputImpl::getMousePosition(const WindowBase& /*relativeTo*/)
|
||||
{
|
||||
return getMousePosition();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void InputImpl::setMousePosition(const Vector2i& position)
|
||||
{
|
||||
Lock lock(inputMutex);
|
||||
mousePos = position;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void InputImpl::setMousePosition(const Vector2i& position, const WindowBase& /*relativeTo*/)
|
||||
{
|
||||
setMousePosition(position);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool InputImpl::isTouchDown(unsigned int finger)
|
||||
{
|
||||
for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
|
||||
{
|
||||
if (slot->id == static_cast<int>(finger))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i InputImpl::getTouchPosition(unsigned int finger)
|
||||
{
|
||||
for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
|
||||
{
|
||||
if (slot->id == static_cast<int>(finger))
|
||||
return slot->pos;
|
||||
}
|
||||
|
||||
return Vector2i();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i InputImpl::getTouchPosition(unsigned int finger, const WindowBase& /*relativeTo*/)
|
||||
{
|
||||
return getTouchPosition(finger);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool InputImpl::checkEvent(sf::Event& event)
|
||||
{
|
||||
Lock lock(inputMutex);
|
||||
if (!eventQueue.empty())
|
||||
{
|
||||
event = eventQueue.front();
|
||||
eventQueue.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (eventProcess(event))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the case of multitouch, eventProcess() could have returned false
|
||||
// but added events directly to the queue. (This is ugly, but I'm not
|
||||
// sure of a good way to handle generating multiple events at once.)
|
||||
if (!eventQueue.empty())
|
||||
{
|
||||
event = eventQueue.front();
|
||||
eventQueue.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void InputImpl::setTerminalConfig()
|
||||
{
|
||||
sf::Lock lock(inputMutex);
|
||||
initFileDescriptors();
|
||||
|
||||
tcgetattr(STDIN_FILENO, &newTerminalConfig); // get current terminal config
|
||||
oldTerminalConfig = newTerminalConfig; // create a backup
|
||||
newTerminalConfig.c_lflag &= ~(tcflag_t)ECHO; // disable console feedback
|
||||
newTerminalConfig.c_lflag &= ~(tcflag_t)ISIG; // disable signals
|
||||
newTerminalConfig.c_lflag |= ICANON; // disable noncanonical mode
|
||||
newTerminalConfig.c_iflag |= IGNCR; // ignore carriage return
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig); // set our new config
|
||||
tcflush(STDIN_FILENO, TCIFLUSH); // flush the buffer
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void InputImpl::restoreTerminalConfig()
|
||||
{
|
||||
sf::Lock lock(inputMutex);
|
||||
initFileDescriptors();
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldTerminalConfig); // restore terminal config
|
||||
tcflush(STDIN_FILENO, TCIFLUSH); // flush the buffer
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
193
src/SFML/Window/DRM/InputImplUDev.hpp
Normal file
193
src/SFML/Window/DRM/InputImplUDev.hpp
Normal file
@ -0,0 +1,193 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2016 Andrew Mickelson
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_INPUTIMPLUDEV_HPP
|
||||
#define SFML_INPUTIMPLUDEV_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Keyboard.hpp>
|
||||
#include <SFML/Window/Mouse.hpp>
|
||||
#include <SFML/Window/Event.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Linux (DRM) implementation of inputs (keyboard + mouse)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class InputImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a key is pressed
|
||||
///
|
||||
/// \param key Key to check
|
||||
///
|
||||
/// \return True if the key is pressed, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isKeyPressed(Keyboard::Key key);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Show or hide the virtual keyboard
|
||||
///
|
||||
/// \param visible True to show, false to hide
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void setVirtualKeyboardVisible(bool visible);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a mouse button is pressed
|
||||
///
|
||||
/// \param button Button to check
|
||||
///
|
||||
/// \return True if the button is pressed, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isMouseButtonPressed(Mouse::Button button);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the current position of the mouse in desktop coordinates
|
||||
///
|
||||
/// This function returns the current position of the mouse
|
||||
/// cursor, in global (desktop) coordinates.
|
||||
///
|
||||
/// \return Current position of the mouse
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Vector2i getMousePosition();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the current position of the mouse in window coordinates
|
||||
///
|
||||
/// This function returns the current position of the mouse
|
||||
/// cursor, relative to the given window.
|
||||
/// If no window is used, it returns desktop coordinates.
|
||||
///
|
||||
/// \param relativeTo Reference window
|
||||
///
|
||||
/// \return Current position of the mouse
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Vector2i getMousePosition(const WindowBase& relativeTo);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the current position of the mouse in desktop coordinates
|
||||
///
|
||||
/// This function sets the current position of the mouse
|
||||
/// cursor in global (desktop) coordinates.
|
||||
/// If no window is used, it sets the position in desktop coordinates.
|
||||
///
|
||||
/// \param position New position of the mouse
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void setMousePosition(const Vector2i& position);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the current position of the mouse in window coordinates
|
||||
///
|
||||
/// This function sets the current position of the mouse
|
||||
/// cursor, relative to the given window.
|
||||
/// If no window is used, it sets the position in desktop coordinates.
|
||||
///
|
||||
/// \param position New position of the mouse
|
||||
/// \param relativeTo Reference window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void setMousePosition(const Vector2i& position, const WindowBase& relativeTo);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a touch event is currently down
|
||||
///
|
||||
/// \param finger Finger index
|
||||
///
|
||||
/// \return True if \a finger is currently touching the screen, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isTouchDown(unsigned int finger);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the current position of a touch in desktop coordinates
|
||||
///
|
||||
/// This function returns the current touch position
|
||||
/// in global (desktop) coordinates.
|
||||
///
|
||||
/// \param finger Finger index
|
||||
///
|
||||
/// \return Current position of \a finger, or undefined if it's not down
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Vector2i getTouchPosition(unsigned int finger);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the current position of a touch in window coordinates
|
||||
///
|
||||
/// This function returns the current touch position
|
||||
/// in global (desktop) coordinates.
|
||||
///
|
||||
/// \param finger Finger index
|
||||
/// \param relativeTo Reference window
|
||||
///
|
||||
/// \return Current position of \a finger, or undefined if it's not down
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Vector2i getTouchPosition(unsigned int finger, const WindowBase& relativeTo);
|
||||
|
||||
private:
|
||||
|
||||
friend class WindowImplDRM;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Fetch input event from event queue
|
||||
///
|
||||
/// \return False if event queue is empty
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool checkEvent(sf::Event& event);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Backup terminal configuration and disable console feedback
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void setTerminalConfig();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Restore terminal configuration from backup
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void restoreTerminalConfig();
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_INPUTIMPLUDEV_HPP
|
73
src/SFML/Window/DRM/VideoModeImpl.cpp
Normal file
73
src/SFML/Window/DRM/VideoModeImpl.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2020 Andrew Mickelson
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/VideoModeImpl.hpp>
|
||||
#include <SFML/Window/DRM/DRMContext.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <drm-common.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
|
||||
{
|
||||
std::vector<VideoMode> modes;
|
||||
|
||||
drm* drm = sf::priv::DRMContext::getDRM();
|
||||
drmModeConnectorPtr conn = drm->saved_connector;
|
||||
|
||||
if (conn)
|
||||
{
|
||||
for (int i = 0; i < conn->count_modes; i++)
|
||||
modes.push_back(
|
||||
VideoMode(conn->modes[i].hdisplay,
|
||||
conn->modes[i].vdisplay));
|
||||
}
|
||||
else
|
||||
modes.push_back(getDesktopMode());
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VideoMode VideoModeImpl::getDesktopMode()
|
||||
{
|
||||
drm* drm = sf::priv::DRMContext::getDRM();
|
||||
drmModeModeInfoPtr ptr = drm->mode;
|
||||
if (ptr)
|
||||
return VideoMode(ptr->hdisplay, ptr->vdisplay);
|
||||
else
|
||||
return VideoMode(0, 0);
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
161
src/SFML/Window/DRM/WindowImplDRM.cpp
Normal file
161
src/SFML/Window/DRM/WindowImplDRM.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2020 Andrew Mickelson
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/DRM/WindowImplDRM.hpp>
|
||||
#include <SFML/Window/DRM/DRMContext.hpp>
|
||||
#include <SFML/Window/DRM/InputImplUDev.hpp>
|
||||
#include <SFML/Window/Event.hpp>
|
||||
#include <SFML/Window/WindowStyle.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <drm-common.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImplDRM::WindowImplDRM(WindowHandle /*handle*/) :
|
||||
m_size(0, 0)
|
||||
{
|
||||
sf::priv::InputImpl::setTerminalConfig();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImplDRM::WindowImplDRM(VideoMode mode, const String& /*title*/, unsigned long /*style*/, const ContextSettings& /*settings*/) :
|
||||
m_size(mode.width, mode.height)
|
||||
{
|
||||
sf::priv::InputImpl::setTerminalConfig();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImplDRM::~WindowImplDRM()
|
||||
{
|
||||
sf::priv::InputImpl::restoreTerminalConfig();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowHandle WindowImplDRM::getSystemHandle() const
|
||||
{
|
||||
drm* drm = sf::priv::DRMContext::getDRM();
|
||||
return static_cast<WindowHandle>(drm->fd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i WindowImplDRM::getPosition() const
|
||||
{
|
||||
return Vector2i(0, 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setPosition(const Vector2i& /*position*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2u WindowImplDRM::getSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setSize(const Vector2u& /*size*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setTitle(const String& /*title*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setIcon(unsigned int /*width*/, unsigned int /*height*/, const Uint8* /*pixels*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setVisible(bool /*visible*/)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setMouseCursorVisible(bool /*visible*/)
|
||||
{
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setMouseCursorGrabbed(bool /*grabbed*/)
|
||||
{
|
||||
//TODO: not implemented
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setMouseCursor(const CursorImpl& /*cursor*/)
|
||||
{
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::setKeyRepeatEnabled(bool /*enabled*/)
|
||||
{
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplDRM::requestFocus()
|
||||
{
|
||||
// Not applicable
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool WindowImplDRM::hasFocus() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowImplDRM::processEvents()
|
||||
{
|
||||
sf::Event ev;
|
||||
while (sf::priv::InputImpl::checkEvent(ev))
|
||||
pushEvent(ev);
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
205
src/SFML/Window/DRM/WindowImplDRM.hpp
Normal file
205
src/SFML/Window/DRM/WindowImplDRM.hpp
Normal file
@ -0,0 +1,205 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2020 Andrew Mickelson
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_WINDOWIMPLDRM_HPP
|
||||
#define SFML_WINDOWIMPLDRM_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Event.hpp>
|
||||
#include <SFML/Window/WindowImpl.hpp>
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief DRM implementation of WindowImpl
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class WindowImplDRM : public WindowImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct the window implementation from an existing control
|
||||
///
|
||||
/// \param handle Platform-specific handle of the control
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImplDRM(WindowHandle handle);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the window implementation
|
||||
///
|
||||
/// \param mode Video mode to use
|
||||
/// \param title Title of the window
|
||||
/// \param style Window style (resizable, fixed, or fullscren)
|
||||
/// \param settings Additional settings for the underlying OpenGL context
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImplDRM(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~WindowImplDRM();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the OS-specific handle of the window
|
||||
///
|
||||
/// \return Handle of the window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual WindowHandle getSystemHandle() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the position of the window
|
||||
///
|
||||
/// \return Position of the window, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Vector2i getPosition() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the position of the window on screen
|
||||
///
|
||||
/// \param position New position of the window, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setPosition(const Vector2i& position);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the client size of the window
|
||||
///
|
||||
/// \return Size of the window, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Vector2u getSize() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the size of the rendering region of the window
|
||||
///
|
||||
/// \param size New size, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setSize(const Vector2u& size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the title of the window
|
||||
///
|
||||
/// \param title New title
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setTitle(const String& title);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the window's icon
|
||||
///
|
||||
/// \param width Icon's width, in pixels
|
||||
/// \param height Icon's height, in pixels
|
||||
/// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Show or hide the window
|
||||
///
|
||||
/// \param visible True to show, false to hide
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Show or hide the mouse cursor
|
||||
///
|
||||
/// \param visible True to show, false to hide
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setMouseCursorVisible(bool visible);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Grab or release the mouse cursor
|
||||
///
|
||||
/// \param grabbed True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setMouseCursorGrabbed(bool grabbed);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the displayed cursor to a native system cursor
|
||||
///
|
||||
/// \param cursor Native system cursor type to display
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setMouseCursor(const CursorImpl& cursor);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable automatic key-repeat
|
||||
///
|
||||
/// \param enabled True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setKeyRepeatEnabled(bool enabled);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Request the current window to be made the active
|
||||
/// foreground window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void requestFocus();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check whether the window has the input focus
|
||||
///
|
||||
/// \return True if window has focus, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool hasFocus() const;
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Process incoming events from the operating system
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void processEvents();
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2u m_size; ///< Window size
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_WINDOWIMPLDRM_HPP
|
@ -35,7 +35,7 @@
|
||||
#ifdef SFML_SYSTEM_ANDROID
|
||||
#include <SFML/System/Android/Activity.hpp>
|
||||
#endif
|
||||
#ifdef SFML_SYSTEM_LINUX
|
||||
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
@ -361,7 +361,7 @@ void EglContext::updateSettings()
|
||||
}
|
||||
|
||||
|
||||
#ifdef SFML_SYSTEM_LINUX
|
||||
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
|
||||
////////////////////////////////////////////////////////////
|
||||
XVisualInfo EglContext::selectBestVisual(::Display* XDisplay, unsigned int bitsPerPixel, const ContextSettings& settings)
|
||||
{
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include <SFML/Window/GlContext.hpp>
|
||||
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
|
||||
#include <glad/egl.h>
|
||||
#ifdef SFML_SYSTEM_LINUX
|
||||
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
@ -165,7 +165,7 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
static EGLConfig getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings);
|
||||
|
||||
#ifdef SFML_SYSTEM_LINUX
|
||||
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Select the best EGL visual for a given set of settings
|
||||
///
|
||||
|
@ -63,6 +63,11 @@
|
||||
|
||||
typedef sf::priv::EglContext ContextType;
|
||||
|
||||
#elif defined(SFML_USE_DRM)
|
||||
|
||||
#include <SFML/Window/DRM/DRMContext.hpp>
|
||||
typedef sf::priv::DRMContext ContextType;
|
||||
|
||||
#else
|
||||
|
||||
#include <SFML/Window/Unix/GlxContext.hpp>
|
||||
|
@ -33,7 +33,11 @@
|
||||
#if defined(SFML_SYSTEM_WINDOWS)
|
||||
#include <SFML/Window/Win32/InputImpl.hpp>
|
||||
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
|
||||
#include <SFML/Window/Unix/InputImpl.hpp>
|
||||
#if defined(SFML_USE_DRM)
|
||||
#include <SFML/Window/DRM/InputImplUDev.hpp>
|
||||
#else
|
||||
#include <SFML/Window/Unix/InputImpl.hpp>
|
||||
#endif
|
||||
#elif defined(SFML_SYSTEM_MACOS)
|
||||
#include <SFML/Window/OSX/InputImpl.hpp>
|
||||
#elif defined(SFML_SYSTEM_IOS)
|
||||
@ -42,5 +46,4 @@
|
||||
#include <SFML/Window/Android/InputImpl.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
#endif // SFML_INPUTIMPL_HPP
|
||||
|
@ -29,13 +29,21 @@
|
||||
|
||||
#if defined(SFML_SYSTEM_WINDOWS)
|
||||
|
||||
#include <SFML/Window/Win32/VulkanImplWin32.hpp>
|
||||
typedef sf::priv::VulkanImplWin32 VulkanImplType;
|
||||
#include <SFML/Window/Win32/VulkanImplWin32.hpp>
|
||||
typedef sf::priv::VulkanImplWin32 VulkanImplType;
|
||||
|
||||
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
|
||||
|
||||
#include <SFML/Window/Unix/VulkanImplX11.hpp>
|
||||
typedef sf::priv::VulkanImplX11 VulkanImplType;
|
||||
#if defined(SFML_USE_DRM)
|
||||
|
||||
#define SFML_VULKAN_IMPLEMENTATION_NOT_AVAILABLE
|
||||
|
||||
#else
|
||||
|
||||
#include <SFML/Window/Unix/VulkanImplX11.hpp>
|
||||
typedef sf::priv::VulkanImplX11 VulkanImplType;
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
|
@ -43,11 +43,22 @@
|
||||
|
||||
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
|
||||
|
||||
#include <SFML/Window/Unix/WindowImplX11.hpp>
|
||||
typedef sf::priv::WindowImplX11 WindowImplType;
|
||||
#if defined(SFML_USE_DRM)
|
||||
|
||||
#include <SFML/Window/Unix/VulkanImplX11.hpp>
|
||||
typedef sf::priv::VulkanImplX11 VulkanImplType;
|
||||
#include <SFML/Window/DRM/WindowImplDRM.hpp>
|
||||
typedef sf::priv::WindowImplDRM WindowImplType;
|
||||
|
||||
#define SFML_VULKAN_IMPLEMENTATION_NOT_AVAILABLE
|
||||
|
||||
#else
|
||||
|
||||
#include <SFML/Window/Unix/WindowImplX11.hpp>
|
||||
typedef sf::priv::WindowImplX11 WindowImplType;
|
||||
|
||||
#include <SFML/Window/Unix/VulkanImplX11.hpp>
|
||||
typedef sf::priv::VulkanImplX11 VulkanImplType;
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(SFML_SYSTEM_MACOS)
|
||||
|
||||
@ -77,6 +88,7 @@ namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImpl* WindowImpl::create(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user