2017-08-02 19:22:48 +02:00
|
|
|
/*
|
|
|
|
Simple DirectMedia Layer
|
2020-01-17 05:49:25 +01:00
|
|
|
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "../../SDL_internal.h"
|
|
|
|
|
|
|
|
#if SDL_VIDEO_DRIVER_KMSDRM
|
|
|
|
|
|
|
|
/* SDL internals */
|
|
|
|
#include "../SDL_sysvideo.h"
|
|
|
|
#include "SDL_syswm.h"
|
2017-10-27 01:37:20 +02:00
|
|
|
#include "SDL_hints.h"
|
2020-02-09 20:44:22 +01:00
|
|
|
#include "../../events/SDL_events_c.h"
|
2017-08-02 19:22:48 +02:00
|
|
|
#include "../../events/SDL_mouse_c.h"
|
|
|
|
#include "../../events/SDL_keyboard_c.h"
|
|
|
|
|
|
|
|
#ifdef SDL_INPUT_LINUXEV
|
|
|
|
#include "../../core/linux/SDL_evdev.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* KMS/DRM declarations */
|
|
|
|
#include "SDL_kmsdrmvideo.h"
|
2017-08-22 02:20:50 +02:00
|
|
|
#include "SDL_kmsdrmevents.h"
|
2017-08-02 19:22:48 +02:00
|
|
|
#include "SDL_kmsdrmopengles.h"
|
|
|
|
#include "SDL_kmsdrmmouse.h"
|
|
|
|
#include "SDL_kmsdrmdyn.h"
|
2018-10-09 06:27:55 +02:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <errno.h>
|
2020-02-09 20:44:22 +01:00
|
|
|
#include <poll.h>
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2018-10-09 06:27:55 +02:00
|
|
|
#define KMSDRM_DRI_PATH "/dev/dri/"
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
static int
|
2020-07-20 03:46:41 +02:00
|
|
|
check_modesetting(int devindex)
|
2017-08-02 19:22:48 +02:00
|
|
|
{
|
2018-10-09 06:27:55 +02:00
|
|
|
SDL_bool available = SDL_FALSE;
|
|
|
|
char device[512];
|
|
|
|
int drm_fd;
|
|
|
|
|
|
|
|
SDL_snprintf(device, sizeof (device), "%scard%d", KMSDRM_DRI_PATH, devindex);
|
2020-07-20 03:48:17 +02:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "check_modesetting: probing \"%s\"", device);
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2018-10-09 06:27:55 +02:00
|
|
|
drm_fd = open(device, O_RDWR | O_CLOEXEC);
|
2017-08-02 19:22:48 +02:00
|
|
|
if (drm_fd >= 0) {
|
|
|
|
if (SDL_KMSDRM_LoadSymbols()) {
|
|
|
|
drmModeRes *resources = KMSDRM_drmModeGetResources(drm_fd);
|
2020-02-09 20:44:22 +01:00
|
|
|
if (resources) {
|
2018-12-01 22:31:56 +01:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "%scard%d connector, encoder and CRTC counts are: %d %d %d",
|
|
|
|
KMSDRM_DRI_PATH, devindex,
|
|
|
|
resources->count_connectors, resources->count_encoders, resources->count_crtcs);
|
|
|
|
|
|
|
|
if (resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0) {
|
2020-07-20 03:48:17 +02:00
|
|
|
for (int i = 0; i < resources->count_connectors; i++) {
|
|
|
|
drmModeConnector *conn = KMSDRM_drmModeGetConnector(drm_fd, resources->connectors[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
|
|
|
|
available = SDL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreeConnector(conn);
|
2020-07-20 19:09:07 +02:00
|
|
|
if (available) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-20 03:48:17 +02:00
|
|
|
}
|
2018-12-01 22:31:56 +01:00
|
|
|
}
|
2017-08-02 19:22:48 +02:00
|
|
|
KMSDRM_drmModeFreeResources(resources);
|
|
|
|
}
|
|
|
|
SDL_KMSDRM_UnloadSymbols();
|
|
|
|
}
|
|
|
|
close(drm_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return available;
|
|
|
|
}
|
|
|
|
|
2018-10-09 06:27:55 +02:00
|
|
|
static int get_dricount(void)
|
|
|
|
{
|
|
|
|
int devcount = 0;
|
|
|
|
struct dirent *res;
|
|
|
|
struct stat sb;
|
|
|
|
DIR *folder;
|
|
|
|
|
|
|
|
if (!(stat(KMSDRM_DRI_PATH, &sb) == 0
|
|
|
|
&& S_ISDIR(sb.st_mode))) {
|
|
|
|
printf("The path %s cannot be opened or is not available\n",
|
|
|
|
KMSDRM_DRI_PATH);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (access(KMSDRM_DRI_PATH, F_OK) == -1) {
|
|
|
|
printf("The path %s cannot be opened\n",
|
|
|
|
KMSDRM_DRI_PATH);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
folder = opendir(KMSDRM_DRI_PATH);
|
|
|
|
if (folder) {
|
|
|
|
while ((res = readdir(folder))) {
|
2019-06-19 10:11:38 +02:00
|
|
|
int len = SDL_strlen(res->d_name);
|
2019-06-19 15:40:50 +02:00
|
|
|
if (len > 4 && SDL_strncmp(res->d_name, "card", 4) == 0) {
|
2018-10-09 06:27:55 +02:00
|
|
|
devcount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(folder);
|
|
|
|
}
|
|
|
|
|
|
|
|
return devcount;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_driindex(void)
|
|
|
|
{
|
|
|
|
const int devcount = get_dricount();
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < devcount; i++) {
|
2020-07-20 03:46:41 +02:00
|
|
|
if (check_modesetting(i)) {
|
2018-10-09 06:27:55 +02:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
/*********************************/
|
|
|
|
/* Atomic helper functions block */
|
|
|
|
/*********************************/
|
|
|
|
|
|
|
|
#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
static int add_connector_property(drmModeAtomicReq *req, struct connector *connector,
|
2020-07-28 21:11:25 +02:00
|
|
|
const char *name, uint64_t value)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int prop_id = 0;
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
for (i = 0 ; i < connector->props->count_props ; i++) {
|
|
|
|
if (strcmp(connector->props_info[i]->name, name) == 0) {
|
|
|
|
prop_id = connector->props_info[i]->prop_id;
|
2020-07-28 21:11:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prop_id < 0) {
|
|
|
|
printf("no connector property: %s\n", name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
return KMSDRM_drmModeAtomicAddProperty(req, connector->connector->connector_id, prop_id, value);
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
static int add_crtc_property(drmModeAtomicReq *req, struct crtc *crtc,
|
2020-07-28 21:11:25 +02:00
|
|
|
const char *name, uint64_t value)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int prop_id = -1;
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
for (i = 0 ; i < crtc->props->count_props ; i++) {
|
|
|
|
if (strcmp(crtc->props_info[i]->name, name) == 0) {
|
|
|
|
prop_id = crtc->props_info[i]->prop_id;
|
2020-07-28 21:11:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prop_id < 0) {
|
|
|
|
printf("no crtc property: %s\n", name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
return KMSDRM_drmModeAtomicAddProperty(req, crtc->crtc->crtc_id, prop_id, value);
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
static int add_plane_property(drmModeAtomicReq *req, struct plane *plane,
|
2020-07-28 21:11:25 +02:00
|
|
|
const char *name, uint64_t value)
|
|
|
|
{
|
2020-08-08 14:27:55 +02:00
|
|
|
unsigned int i;
|
|
|
|
int prop_id = -1;
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
for (i = 0 ; i < plane->props->count_props ; i++) {
|
|
|
|
if (strcmp(plane->props_info[i]->name, name) == 0) {
|
|
|
|
prop_id = plane->props_info[i]->prop_id;
|
2020-08-08 14:27:55 +02:00
|
|
|
break;
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
2020-08-08 14:27:55 +02:00
|
|
|
}
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
if (prop_id < 0) {
|
|
|
|
printf("no plane property: %s\n", name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
return KMSDRM_drmModeAtomicAddProperty(req, plane->plane->plane_id, prop_id, value);
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 15:28:51 +02:00
|
|
|
#if 0
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
void print_plane_info(_THIS, drmModePlanePtr plane)
|
|
|
|
{
|
|
|
|
char *plane_type;
|
|
|
|
drmModeRes *resources;
|
|
|
|
uint32_t type = 0;
|
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
|
|
|
|
|
|
|
drmModeObjectPropertiesPtr props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
|
|
|
|
plane->plane_id, DRM_MODE_OBJECT_PLANE);
|
|
|
|
|
|
|
|
/* Search the plane props for the plane type. */
|
|
|
|
for (int j = 0; j < props->count_props; j++) {
|
|
|
|
|
|
|
|
drmModePropertyPtr p = KMSDRM_drmModeGetProperty(viddata->drm_fd, props->props[j]);
|
|
|
|
|
|
|
|
if ((strcmp(p->name, "type") == 0)) {
|
|
|
|
type = props->prop_values[j];
|
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreeProperty(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case DRM_PLANE_TYPE_OVERLAY:
|
|
|
|
plane_type = "overlay";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DRM_PLANE_TYPE_PRIMARY:
|
|
|
|
plane_type = "primary";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DRM_PLANE_TYPE_CURSOR:
|
|
|
|
plane_type = "cursor";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Remember that to present a plane on screen, it has to be
|
|
|
|
connected to a CRTC so the CRTC scans it,
|
2020-07-28 21:11:25 +02:00
|
|
|
scales it, etc... and presents it on screen. */
|
|
|
|
|
|
|
|
/* Now we look for the CRTCs supported by the plane. */
|
|
|
|
resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
|
|
|
|
if (!resources)
|
|
|
|
return;
|
|
|
|
|
|
|
|
printf("--PLANE ID: %d\nPLANE TYPE: %s\nCRTC READING THIS PLANE: %d\nCRTCS SUPPORTED BY THIS PLANE: ", plane->plane_id, plane_type, plane->crtc_id);
|
|
|
|
for (int i = 0; i < resources->count_crtcs; i++) {
|
|
|
|
if (plane->possible_crtcs & (1 << i)) {
|
|
|
|
uint32_t crtc_id = resources->crtcs[i];
|
|
|
|
printf ("%d", crtc_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printf ("\n\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_planes_info(_THIS)
|
|
|
|
{
|
|
|
|
drmModePlaneResPtr plane_resources;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
|
|
|
|
|
|
|
plane_resources = KMSDRM_drmModeGetPlaneResources(viddata->drm_fd);
|
|
|
|
if (!plane_resources) {
|
|
|
|
printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("--Number of planes found: %d-- \n", plane_resources->count_planes);
|
2020-08-17 18:35:04 +02:00
|
|
|
printf("--Usable CRTC that we have chosen: %d-- \n", dispdata->crtc->crtc->crtc_id);
|
2020-07-28 21:11:25 +02:00
|
|
|
|
|
|
|
/* Iterate on all the available planes. */
|
|
|
|
for (i = 0; (i < plane_resources->count_planes); i++) {
|
|
|
|
|
|
|
|
uint32_t plane_id = plane_resources->planes[i];
|
|
|
|
|
|
|
|
drmModePlanePtr plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id);
|
|
|
|
if (!plane) {
|
|
|
|
printf("drmModeGetPlane(%u) failed: %s\n", plane_id, strerror(errno));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print plane info. */
|
|
|
|
print_plane_info(_this, plane);
|
|
|
|
KMSDRM_drmModeFreePlane(plane);
|
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreePlaneResources(plane_resources);
|
|
|
|
}
|
|
|
|
|
2020-08-05 15:28:51 +02:00
|
|
|
#endif
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Get the plane_id of a plane that is of the specified plane type (primary,
|
|
|
|
overlay, cursor...) and can use the CRTC we have chosen previously. */
|
|
|
|
static uint32_t get_plane_id(_THIS, drmModeRes *resources, uint32_t plane_type)
|
2020-07-28 21:11:25 +02:00
|
|
|
{
|
|
|
|
drmModePlaneResPtr plane_resources;
|
|
|
|
uint32_t i, j;
|
2020-08-05 18:55:22 +02:00
|
|
|
uint32_t crtc_index = 0;
|
2020-08-17 18:35:04 +02:00
|
|
|
uint32_t ret = -EINVAL;
|
|
|
|
int found = 0;
|
2020-07-28 21:11:25 +02:00
|
|
|
|
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Get the crtc_index for the current CRTC.
|
|
|
|
It's needed to find out if a plane supports the CRTC. */
|
2020-08-05 18:55:22 +02:00
|
|
|
for (i = 0; i < resources->count_crtcs; i++) {
|
2020-08-17 18:35:04 +02:00
|
|
|
if (resources->crtcs[i] == dispdata->crtc->crtc->crtc_id) {
|
2020-08-05 18:55:22 +02:00
|
|
|
crtc_index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
plane_resources = KMSDRM_drmModeGetPlaneResources(viddata->drm_fd);
|
|
|
|
if (!plane_resources) {
|
|
|
|
printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate on all the available planes. */
|
2020-08-17 18:35:04 +02:00
|
|
|
for (i = 0; (i < plane_resources->count_planes) && !found; i++) {
|
2020-07-28 21:11:25 +02:00
|
|
|
|
|
|
|
uint32_t plane_id = plane_resources->planes[i];
|
|
|
|
|
|
|
|
drmModePlanePtr plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id);
|
|
|
|
if (!plane) {
|
|
|
|
printf("drmModeGetPlane(%u) failed: %s\n", plane_id, strerror(errno));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See if the current CRTC is available for this plane. */
|
2020-08-05 18:55:22 +02:00
|
|
|
if (plane->possible_crtcs & (1 << crtc_index)) {
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-05 18:55:22 +02:00
|
|
|
drmModeObjectPropertiesPtr props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
|
|
|
|
plane_id, DRM_MODE_OBJECT_PLANE);
|
2020-07-28 21:11:25 +02:00
|
|
|
ret = plane_id;
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Iterate on the plane props to find the type of the plane,
|
|
|
|
to see if it's of the type we want. */
|
2020-07-28 21:11:25 +02:00
|
|
|
for (j = 0; j < props->count_props; j++) {
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
drmModePropertyPtr p = KMSDRM_drmModeGetProperty(viddata->drm_fd,
|
|
|
|
props->props[j]);
|
2020-07-28 21:11:25 +02:00
|
|
|
|
|
|
|
if ((strcmp(p->name, "type") == 0) &&
|
2020-08-17 18:35:04 +02:00
|
|
|
(props->prop_values[j] == plane_type)) {
|
|
|
|
/* found our plane, use that: */
|
|
|
|
found = 1;
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 18:55:22 +02:00
|
|
|
KMSDRM_drmModeFreeProperty(p);
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreeObjectProperties(props);
|
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreePlane(plane);
|
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreePlaneResources(plane_resources);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/**********************************************************************************/
|
|
|
|
/* The most important ATOMIC fn of the backend. */
|
|
|
|
/* A PLANE reads a BUFFER, and a CRTC reads a PLANE and sends it's contents */
|
|
|
|
/* over to a CONNECTOR->ENCODER system. */
|
|
|
|
/* Think of a plane as a "frame" sorrounding a picture, where the "picture" */
|
|
|
|
/* is the buffer, and we move the "frame" from a picture to another, */
|
|
|
|
/* and the one that has the "frame" is the one sent over to the screen */
|
|
|
|
/* via the CONNECTOR->ENCODER system. */
|
|
|
|
/* Think of a PLANE as being "in the middle", it's the CENTRAL part */
|
|
|
|
/* bewteen the CRTC and the BUFFER that is shown on screen. */
|
|
|
|
/* What we do here is connect a PLANE to a CRTC and a BUFFER. */
|
|
|
|
/* -ALWAYS set the CRTC_ID and FB_ID attribs of a plane at the same time, */
|
|
|
|
/* meaning IN THE SAME atomic request. */
|
|
|
|
/* -And NEVER destroy a GBM surface whose buffers are being read by a plane: */
|
|
|
|
/* first, move the plane away from those buffers and ONLY THEN destroy the */
|
|
|
|
/* buffers and/or the GBM surface containig them. */
|
|
|
|
/**********************************************************************************/
|
2020-08-08 14:27:55 +02:00
|
|
|
void
|
2020-08-17 18:35:04 +02:00
|
|
|
drm_atomic_setbuffer(_THIS, struct plane *plane, uint32_t fb_id)
|
2020-07-28 21:11:25 +02:00
|
|
|
{
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
2020-08-08 14:27:55 +02:00
|
|
|
|
|
|
|
/* Do we have a set of changes already in the making? If not, allocate a new one. */
|
|
|
|
if (!dispdata->atomic_req)
|
|
|
|
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
|
2020-08-17 18:35:04 +02:00
|
|
|
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "FB_ID", fb_id);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "CRTC_ID", dispdata->crtc->crtc->crtc_id);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "SRC_W", dispdata->mode.hdisplay << 16);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "SRC_H", dispdata->mode.vdisplay << 16);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "SRC_X", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "SRC_Y", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "CRTC_W", dispdata->mode.hdisplay);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "CRTC_H", dispdata->mode.vdisplay);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "CRTC_X", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, plane, "CRTC_Y", 0);
|
2020-08-08 14:27:55 +02:00
|
|
|
|
|
|
|
if (dispdata->kms_in_fence_fd != -1) {
|
2020-08-17 18:35:04 +02:00
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "OUT_FENCE_PTR",
|
2020-08-08 14:27:55 +02:00
|
|
|
VOID2U64(&dispdata->kms_out_fence_fd));
|
2020-08-17 18:35:04 +02:00
|
|
|
add_plane_property(dispdata->atomic_req, plane, "IN_FENCE_FD", dispdata->kms_in_fence_fd);
|
2020-08-08 14:27:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-08-17 18:35:04 +02:00
|
|
|
drm_atomic_modeset(_THIS, int mode_index)
|
2020-08-08 14:27:55 +02:00
|
|
|
{
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
2020-08-17 18:35:04 +02:00
|
|
|
drmModeModeInfo mode;
|
2020-07-28 21:11:25 +02:00
|
|
|
uint32_t blob_id;
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
mode = dispdata->connector->connector->modes[mode_index];
|
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
/* Do we have a set of changes already in the making? If not, allocate a new one. */
|
|
|
|
if (!dispdata->atomic_req)
|
|
|
|
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
dispdata->atomic_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
add_connector_property(dispdata->atomic_req, dispdata->connector, "CRTC_ID", dispdata->crtc->crtc->crtc_id);
|
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "ACTIVE", 1);
|
|
|
|
KMSDRM_drmModeCreatePropertyBlob(viddata->drm_fd, &mode, sizeof(mode), &blob_id);
|
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "MODE_ID", blob_id);
|
|
|
|
|
|
|
|
/* Update video mode in use. */
|
|
|
|
dispdata->mode = mode;
|
2020-08-08 14:27:55 +02:00
|
|
|
}
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
int
|
|
|
|
drm_atomic_setcursor(KMSDRM_CursorData *curdata, int x, int y)
|
|
|
|
{
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
|
|
|
|
|
|
|
/* Do we have a set of changes already in the making? If not, allocate a new one. */
|
|
|
|
if (!dispdata->atomic_req)
|
|
|
|
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
|
|
|
|
|
|
|
|
if (curdata)
|
|
|
|
{
|
|
|
|
KMSDRM_FBInfo *fb = KMSDRM_FBFromBO(curdata->video, curdata->bo);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "FB_ID", fb->fb_id);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_ID", dispdata->crtc->crtc->crtc_id);
|
|
|
|
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_X", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_Y", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_W", curdata->w << 16);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_H", curdata->h << 16);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_X", x);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_Y", y);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_W", curdata->w);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_H", curdata->h);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "FB_ID", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_ID", 0);
|
|
|
|
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_X", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_Y", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_W", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "SRC_H", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_W", 0);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_H", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* GPU <-> DISPLAY synchronization is done ON the display_plane,
|
|
|
|
so no need to set any fence props here, we do that only on the main
|
|
|
|
display plane. */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
drm_atomic_movecursor(KMSDRM_CursorData *curdata, int x, int y)
|
|
|
|
{
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
|
|
|
|
|
|
|
/* Do we have a set of changes already in the making? If not, allocate a new one. */
|
|
|
|
if (!dispdata->atomic_req)
|
|
|
|
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
|
|
|
|
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_X", x - curdata->hot_x);
|
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_Y", y - curdata->hot_y);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
int drm_atomic_commit(_THIS, SDL_bool blocking)
|
|
|
|
{
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
|
|
|
int ret;
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
if (!blocking)
|
|
|
|
dispdata->atomic_flags |= DRM_MODE_ATOMIC_NONBLOCK;
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
/* Never issue a new atomic commit if previous has not yet completed, or it will error. */
|
2020-08-17 18:35:04 +02:00
|
|
|
drm_atomic_waitpending(_this);
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
ret = KMSDRM_drmModeAtomicCommit(viddata->drm_fd, dispdata->atomic_req, dispdata->atomic_flags, NULL);
|
2020-08-17 18:35:04 +02:00
|
|
|
if (ret) {
|
|
|
|
//SDL_SetError("Atomic commit failed, returned %d.", ret);
|
|
|
|
printf("ATOMIC COMMIT FAILED: %d.\n", ret);
|
2020-07-28 21:11:25 +02:00
|
|
|
goto out;
|
2020-08-17 18:35:04 +02:00
|
|
|
}
|
2020-07-28 21:11:25 +02:00
|
|
|
|
|
|
|
if (dispdata->kms_in_fence_fd != -1) {
|
|
|
|
close(dispdata->kms_in_fence_fd);
|
|
|
|
dispdata->kms_in_fence_fd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2020-08-08 14:27:55 +02:00
|
|
|
KMSDRM_drmModeAtomicFree(dispdata->atomic_req);
|
|
|
|
dispdata->atomic_req = NULL;
|
|
|
|
dispdata->atomic_flags = 0;
|
2020-07-28 21:11:25 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-08-07 11:53:04 +02:00
|
|
|
void
|
2020-08-17 18:35:04 +02:00
|
|
|
drm_atomic_waitpending(_THIS)
|
2020-08-07 11:53:04 +02:00
|
|
|
{
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
|
|
|
|
|
|
|
/* Will return immediately if we have already destroyed the fence, because we NULL-ify it just after.
|
|
|
|
Also, will return immediately in double-buffer mode, because kms_fence will alsawys be NULL. */
|
|
|
|
if (dispdata->kms_fence) {
|
|
|
|
EGLint status;
|
|
|
|
|
|
|
|
do {
|
|
|
|
status = _this->egl_data->eglClientWaitSyncKHR(_this->egl_data->egl_display,
|
|
|
|
dispdata->kms_fence, 0, EGL_FOREVER_KHR);
|
|
|
|
} while (status != EGL_CONDITION_SATISFIED_KHR);
|
|
|
|
|
|
|
|
_this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->kms_fence);
|
|
|
|
dispdata->kms_fence = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
/***************************************/
|
|
|
|
/* End of Atomic helper functions block*/
|
|
|
|
/***************************************/
|
|
|
|
|
2018-10-09 06:27:55 +02:00
|
|
|
static int
|
|
|
|
KMSDRM_Available(void)
|
|
|
|
{
|
|
|
|
int ret = -ENOENT;
|
|
|
|
|
|
|
|
ret = get_driindex();
|
|
|
|
if (ret >= 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
static void
|
2020-02-09 20:44:22 +01:00
|
|
|
KMSDRM_DeleteDevice(SDL_VideoDevice * device)
|
2017-08-02 19:22:48 +02:00
|
|
|
{
|
2020-02-09 20:44:22 +01:00
|
|
|
if (device->driverdata) {
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_free(device->driverdata);
|
|
|
|
device->driverdata = NULL;
|
|
|
|
}
|
2017-08-02 22:51:14 +02:00
|
|
|
|
|
|
|
SDL_free(device);
|
2020-02-09 20:44:22 +01:00
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_KMSDRM_UnloadSymbols();
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDL_VideoDevice *
|
2020-02-09 20:44:22 +01:00
|
|
|
KMSDRM_CreateDevice(int devindex)
|
2017-08-02 19:22:48 +02:00
|
|
|
{
|
|
|
|
SDL_VideoDevice *device;
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_VideoData *viddata;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-07-13 01:11:15 +02:00
|
|
|
if (!KMSDRM_Available()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-10-09 06:27:55 +02:00
|
|
|
if (!devindex || (devindex > 99)) {
|
|
|
|
devindex = get_driindex();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devindex < 0) {
|
2020-08-17 18:35:04 +02:00
|
|
|
SDL_SetError("devindex (%d) must be between 0 and 99.", devindex);
|
2017-08-02 19:22:48 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!SDL_KMSDRM_LoadSymbols()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
|
2020-02-09 20:44:22 +01:00
|
|
|
if (!device) {
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_OutOfMemory();
|
2017-08-02 19:24:47 +02:00
|
|
|
return NULL;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
viddata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
|
|
|
|
if (!viddata) {
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_OutOfMemory();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2020-02-09 20:44:22 +01:00
|
|
|
viddata->devindex = devindex;
|
|
|
|
viddata->drm_fd = -1;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
device->driverdata = viddata;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
Fixed bug 5140 - KMSDRM: Dynamic vsync toggle does not work
Manuel Alfayate Corchete
The KMSDRM backend was doing things wrong because of some small (but important) misconceptions on how KMS/DRM works: to implement a largely broken non-vsync refresh mechanism, the SwapWindow() function was issuing new pageflips before previous ones had completed, thus causing EBUSY returns, buffer mismanagement, etc... resulting in general breakage on vsync disabling from apps, that would not allow vsync to work again without KMSDRM video re-initialization.
To further clarify, on most DRM drivers async pageflips are NOT working nowadays, so all issued pageflips will complete on next VBLANK, NOT ASAP (calling drmModePageFlip() with the DRM_MODE_PAGE_FLIP_ASYNC flag will return error).
The old code was assuming that can just issue a synchronous (=on VBLANK) pageflip and then pass a 0 timeout to the pull() function so we do not wait for the pageflip event, thinking that this will lead to correct non-vsynced screen updates from the program: That is plain wrong.
Each pageflip has to be waite before issuing a new one, ALWAYS. And if we do not support ASYNC pageflips on the DRM driver level, then we are forced to wait for the next VBLANK. There is no way around it.
I have also added many comments on the KMSDRM code. This is needed for future reference for me or others who may need to look at this code: KMS/DRM terminology regarding what SYNC and ASYNC mean in pageflip terms, and where to do certain things and why, is not trivial. It is not desirable or possible to invest time on researching the same concepts every time there is need to dive into this code. So please leave all these comments in the patch.
2020-05-27 01:27:00 +02:00
|
|
|
/* Setup all functions that can be handled from this backend. */
|
2017-08-02 19:22:48 +02:00
|
|
|
device->VideoInit = KMSDRM_VideoInit;
|
|
|
|
device->VideoQuit = KMSDRM_VideoQuit;
|
|
|
|
device->GetDisplayModes = KMSDRM_GetDisplayModes;
|
|
|
|
device->SetDisplayMode = KMSDRM_SetDisplayMode;
|
2017-08-28 09:43:14 +02:00
|
|
|
device->CreateSDLWindow = KMSDRM_CreateWindow;
|
|
|
|
device->CreateSDLWindowFrom = KMSDRM_CreateWindowFrom;
|
2017-08-02 19:22:48 +02:00
|
|
|
device->SetWindowTitle = KMSDRM_SetWindowTitle;
|
|
|
|
device->SetWindowIcon = KMSDRM_SetWindowIcon;
|
|
|
|
device->SetWindowPosition = KMSDRM_SetWindowPosition;
|
|
|
|
device->SetWindowSize = KMSDRM_SetWindowSize;
|
|
|
|
device->ShowWindow = KMSDRM_ShowWindow;
|
|
|
|
device->HideWindow = KMSDRM_HideWindow;
|
|
|
|
device->RaiseWindow = KMSDRM_RaiseWindow;
|
|
|
|
device->MaximizeWindow = KMSDRM_MaximizeWindow;
|
|
|
|
device->MinimizeWindow = KMSDRM_MinimizeWindow;
|
|
|
|
device->RestoreWindow = KMSDRM_RestoreWindow;
|
|
|
|
device->SetWindowGrab = KMSDRM_SetWindowGrab;
|
|
|
|
device->DestroyWindow = KMSDRM_DestroyWindow;
|
|
|
|
device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo;
|
2017-08-04 23:00:47 +02:00
|
|
|
#if SDL_VIDEO_OPENGL_EGL
|
2017-08-02 19:22:48 +02:00
|
|
|
device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary;
|
|
|
|
device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress;
|
|
|
|
device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary;
|
|
|
|
device->GL_CreateContext = KMSDRM_GLES_CreateContext;
|
|
|
|
device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent;
|
|
|
|
device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval;
|
|
|
|
device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval;
|
2020-08-05 02:06:59 +02:00
|
|
|
|
|
|
|
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE))
|
|
|
|
device->GL_SwapWindow = KMSDRM_GLES_SwapWindowDB;
|
|
|
|
else
|
|
|
|
device->GL_SwapWindow = KMSDRM_GLES_SwapWindow;
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
device->GL_DeleteContext = KMSDRM_GLES_DeleteContext;
|
2017-08-04 23:00:47 +02:00
|
|
|
#endif
|
2017-08-02 19:22:48 +02:00
|
|
|
device->PumpEvents = KMSDRM_PumpEvents;
|
2020-02-09 20:44:22 +01:00
|
|
|
device->free = KMSDRM_DeleteDevice;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
return device;
|
|
|
|
|
|
|
|
cleanup:
|
2020-02-09 20:44:22 +01:00
|
|
|
if (device)
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_free(device);
|
2020-02-09 20:44:22 +01:00
|
|
|
if (viddata)
|
|
|
|
SDL_free(viddata);
|
2017-08-02 19:22:48 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoBootStrap KMSDRM_bootstrap = {
|
|
|
|
"KMSDRM",
|
|
|
|
"KMS/DRM Video Driver",
|
2020-02-09 20:44:22 +01:00
|
|
|
KMSDRM_CreateDevice
|
2017-08-02 19:22:48 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data)
|
|
|
|
{
|
|
|
|
KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data;
|
|
|
|
|
2019-03-13 14:54:51 +01:00
|
|
|
if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) {
|
2017-08-02 19:22:48 +02:00
|
|
|
KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
|
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
|
|
|
|
}
|
|
|
|
|
2019-03-11 15:22:40 +01:00
|
|
|
SDL_free(fb_info);
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_FBInfo *
|
|
|
|
KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
|
|
|
|
{
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
2020-08-17 18:35:04 +02:00
|
|
|
unsigned width, height;
|
|
|
|
uint32_t format, strides[4] = {0}, handles[4] = {0}, offsets[4] = {0};
|
|
|
|
const int num_planes = KMSDRM_gbm_bo_get_plane_count(bo);
|
2020-02-15 01:17:17 +01:00
|
|
|
int ret;
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
/* Check for an existing framebuffer */
|
|
|
|
KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
|
|
|
|
|
|
|
|
if (fb_info) {
|
2017-08-02 19:22:48 +02:00
|
|
|
return fb_info;
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Create a structure that contains the info about framebuffer
|
|
|
|
that we need to use it. */
|
2017-08-02 19:22:48 +02:00
|
|
|
fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo));
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
if (!fb_info) {
|
2017-08-05 22:10:36 +02:00
|
|
|
SDL_OutOfMemory();
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
fb_info->drm_fd = viddata->drm_fd;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
width = KMSDRM_gbm_bo_get_width(bo);
|
|
|
|
height = KMSDRM_gbm_bo_get_height(bo);
|
|
|
|
format = KMSDRM_gbm_bo_get_format(bo);
|
|
|
|
|
|
|
|
for (int i = 0; i < num_planes; i++) {
|
|
|
|
strides[i] = KMSDRM_gbm_bo_get_stride_for_plane(bo, i);
|
|
|
|
handles[i] = KMSDRM_gbm_bo_get_handle(bo).u32;
|
|
|
|
offsets[i] = KMSDRM_gbm_bo_get_offset(bo, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create framebuffer object for the buffer.
|
|
|
|
It's VERY important to note that fb_id is what we ise to set the FB_ID prop of a plane
|
|
|
|
when using the ATOMIC interface, and we get fb_id it here. */
|
|
|
|
ret = KMSDRM_drmModeAddFB2(viddata->drm_fd, width, height, format,
|
|
|
|
handles, strides, offsets, &fb_info->fb_id, 0);
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (ret) {
|
|
|
|
SDL_free(fb_info);
|
|
|
|
return NULL;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
2020-02-09 20:44:22 +01:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Set the userdata pointer. This pointer is used to store custom data that we need
|
|
|
|
to access in the future, so we store the fb_id here for later use, because fb_id is
|
|
|
|
what we need to set the FB_ID property of a plane when using the ATOMIC interface. */
|
2017-08-02 19:22:48 +02:00
|
|
|
KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);
|
2020-02-09 20:44:22 +01:00
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
return fb_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* SDL Video and Display initialization/handling functions */
|
|
|
|
/* _this is a SDL_VideoDevice * */
|
|
|
|
/*****************************************************************************/
|
2020-08-17 18:35:04 +02:00
|
|
|
|
2020-02-27 17:20:34 +01:00
|
|
|
static void
|
2020-02-09 20:44:22 +01:00
|
|
|
KMSDRM_DestroySurfaces(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
|
2020-08-17 18:35:04 +02:00
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
2020-02-09 20:44:22 +01:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* CAUTION: Before destroying the GBM ane EGL surfaces, we must disconnect the display plane
|
|
|
|
from the GBM surface buffer it's reading, and make it read the original buffer stored
|
|
|
|
on the CRTC while we recreate the GBM surface.
|
|
|
|
The plane will be pointed to one of the buffers of the new GBM surface on the next pageflip
|
|
|
|
(if there is another pageflip: we could arrive here because we are exiting the program...). */
|
|
|
|
drm_atomic_setbuffer(_this, dispdata->display_plane, dispdata->crtc->crtc->buffer_id);
|
|
|
|
drm_atomic_commit(_this, SDL_TRUE);
|
2020-08-07 11:53:04 +02:00
|
|
|
|
2020-08-05 02:06:59 +02:00
|
|
|
if (windata->bo) {
|
|
|
|
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
|
|
|
|
windata->bo = NULL;
|
2020-02-09 20:44:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (windata->next_bo) {
|
|
|
|
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->next_bo);
|
|
|
|
windata->next_bo = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SDL_VIDEO_OPENGL_EGL
|
|
|
|
SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
|
|
|
|
|
|
if (windata->egl_surface != EGL_NO_SURFACE) {
|
|
|
|
SDL_EGL_DestroySurface(_this, windata->egl_surface);
|
|
|
|
windata->egl_surface = EGL_NO_SURFACE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (windata->gs) {
|
|
|
|
KMSDRM_gbm_surface_destroy(windata->gs);
|
|
|
|
windata->gs = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
|
|
|
SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
|
|
|
Uint32 width = dispdata->mode.hdisplay;
|
|
|
|
Uint32 height = dispdata->mode.vdisplay;
|
2020-08-17 18:35:04 +02:00
|
|
|
Uint32 surface_fmt = GBM_FORMAT_ARGB8888;
|
2020-02-09 20:44:22 +01:00
|
|
|
Uint32 surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
|
2020-03-25 17:38:45 +01:00
|
|
|
#if SDL_VIDEO_OPENGL_EGL
|
2020-02-15 01:17:17 +01:00
|
|
|
EGLContext egl_context;
|
2020-03-25 17:38:45 +01:00
|
|
|
#endif
|
2020-02-09 20:44:22 +01:00
|
|
|
|
2020-07-20 11:42:23 +02:00
|
|
|
if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, surface_fmt, surface_flags)) {
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SDL_VIDEO_OPENGL_EGL
|
|
|
|
SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
|
2020-02-15 01:17:17 +01:00
|
|
|
egl_context = (EGLContext)SDL_GL_GetCurrentContext();
|
2020-02-09 20:44:22 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
KMSDRM_DestroySurfaces(_this, window);
|
|
|
|
|
2020-07-20 11:42:23 +02:00
|
|
|
windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, width, height, surface_fmt, surface_flags);
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
if (!windata->gs) {
|
|
|
|
return SDL_SetError("Could not create GBM surface");
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SDL_VIDEO_OPENGL_EGL
|
|
|
|
windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs);
|
|
|
|
|
|
|
|
if (windata->egl_surface == EGL_NO_SURFACE) {
|
|
|
|
return SDL_SetError("Could not create EGL window surface");
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
|
|
|
|
|
2020-07-19 18:45:29 +02:00
|
|
|
windata->egl_surface_dirty = SDL_FALSE;
|
2020-02-09 20:44:22 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
int
|
|
|
|
KMSDRM_VideoInit(_THIS)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
|
|
|
SDL_DisplayData *dispdata = NULL;
|
2017-08-02 19:22:48 +02:00
|
|
|
drmModeRes *resources = NULL;
|
|
|
|
drmModeEncoder *encoder = NULL;
|
2020-02-15 01:17:17 +01:00
|
|
|
char devname[32];
|
|
|
|
SDL_VideoDisplay display = {0};
|
2020-08-17 18:35:04 +02:00
|
|
|
uint32_t display_plane_id, cursor_plane_id;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->display_plane = calloc(1, sizeof(*dispdata->display_plane));
|
|
|
|
dispdata->cursor_plane = calloc(1, sizeof(*dispdata->cursor_plane));
|
|
|
|
dispdata->crtc = calloc(1, sizeof(*dispdata->crtc));
|
|
|
|
dispdata->connector = calloc(1, sizeof(*dispdata->connector));
|
|
|
|
|
|
|
|
dispdata->atomic_flags = 0;
|
|
|
|
dispdata->atomic_req = NULL;
|
|
|
|
dispdata->kms_fence = NULL;
|
|
|
|
dispdata->gpu_fence = NULL;
|
|
|
|
dispdata->kms_out_fence_fd = -1;
|
|
|
|
dispdata->kms_in_fence_fd = -1;
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
if (!dispdata) {
|
2017-08-02 19:22:48 +02:00
|
|
|
return SDL_OutOfMemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()");
|
|
|
|
|
|
|
|
/* Open /dev/dri/cardNN */
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_snprintf(devname, sizeof(devname), "/dev/dri/card%d", viddata->devindex);
|
|
|
|
|
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", devname);
|
|
|
|
viddata->drm_fd = open(devname, O_RDWR | O_CLOEXEC);
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (viddata->drm_fd < 0) {
|
|
|
|
ret = SDL_SetError("Could not open %s", devname);
|
2017-08-02 19:22:48 +02:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd);
|
|
|
|
|
2020-07-20 11:42:23 +02:00
|
|
|
viddata->gbm_dev = KMSDRM_gbm_create_device(viddata->drm_fd);
|
|
|
|
if (!viddata->gbm_dev) {
|
2017-08-02 19:22:48 +02:00
|
|
|
ret = SDL_SetError("Couldn't create gbm device.");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
/* Get all of the available connectors / devices / crtcs */
|
|
|
|
resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
|
2017-08-02 19:22:48 +02:00
|
|
|
if (!resources) {
|
2020-02-09 20:44:22 +01:00
|
|
|
ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd);
|
2017-08-02 19:22:48 +02:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
/* Iterate on the available connectors to find a connected connector. */
|
2020-02-09 20:44:22 +01:00
|
|
|
for (int i = 0; i < resources->count_connectors; i++) {
|
|
|
|
drmModeConnector *conn = KMSDRM_drmModeGetConnector(viddata->drm_fd, resources->connectors[i]);
|
|
|
|
|
|
|
|
if (!conn) {
|
2017-08-02 19:22:48 +02:00
|
|
|
continue;
|
2020-02-09 20:44:22 +01:00
|
|
|
}
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
|
2020-02-09 20:44:22 +01:00
|
|
|
conn->connector_id, conn->count_modes);
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->connector->connector = conn;
|
2017-08-02 19:22:48 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
KMSDRM_drmModeFreeConnector(conn);
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
if (!dispdata->connector->connector) {
|
2017-08-02 19:22:48 +02:00
|
|
|
ret = SDL_SetError("No currently active connector found.");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
/* Try to find the connector's current encoder */
|
|
|
|
for (int i = 0; i < resources->count_encoders; i++) {
|
|
|
|
encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
|
2018-12-01 19:09:00 +01:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (!encoder) {
|
|
|
|
continue;
|
2018-12-01 19:09:00 +01:00
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
if (encoder->encoder_id == dispdata->connector->connector->encoder_id) {
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
|
2017-08-02 19:22:48 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreeEncoder(encoder);
|
2017-08-11 19:05:45 +02:00
|
|
|
encoder = NULL;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (!encoder) {
|
|
|
|
/* No encoder was connected, find the first supported one */
|
|
|
|
for (int i = 0, j; i < resources->count_encoders; i++) {
|
|
|
|
encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
|
|
|
|
|
|
|
|
if (!encoder) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
for (j = 0; j < dispdata->connector->connector->count_encoders; j++) {
|
|
|
|
if (dispdata->connector->connector->encoders[j] == encoder->encoder_id) {
|
2020-02-09 20:44:22 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
if (j != dispdata->connector->connector->count_encoders) {
|
2020-02-09 20:44:22 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
KMSDRM_drmModeFreeEncoder(encoder);
|
|
|
|
encoder = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!encoder) {
|
2017-08-02 19:22:48 +02:00
|
|
|
ret = SDL_SetError("No connected encoder found.");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
|
2018-12-01 19:09:00 +01:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
/* Try to find a CRTC connected to this encoder */
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->crtc->crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
|
2020-02-09 20:44:22 +01:00
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
/* If no CRTC was connected to the encoder, find the first CRTC that is supported by the encoder, and use that. */
|
2020-08-17 18:35:04 +02:00
|
|
|
if (!dispdata->crtc->crtc) {
|
2020-02-09 20:44:22 +01:00
|
|
|
for (int i = 0; i < resources->count_crtcs; i++) {
|
2018-12-01 19:09:00 +01:00
|
|
|
if (encoder->possible_crtcs & (1 << i)) {
|
|
|
|
encoder->crtc_id = resources->crtcs[i];
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->crtc->crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
|
2018-12-01 19:09:00 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
if (!dispdata->crtc->crtc) {
|
2017-08-02 19:22:48 +02:00
|
|
|
ret = SDL_SetError("No CRTC found.");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
/* Figure out the default mode to be set. If the current CRTC's mode isn't
|
|
|
|
valid, select the first mode supported by the connector
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
FIXME find first mode that specifies DRM_MODE_TYPE_PREFERRED */
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->mode = dispdata->crtc->crtc->mode;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
if (dispdata->crtc->crtc->mode_valid == 0) {
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO,
|
|
|
|
"Current mode is invalid, selecting connector's mode #0.");
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->mode = dispdata->connector->connector->modes[0];
|
2020-02-09 20:44:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup the single display that's available */
|
2020-02-15 01:17:17 +01:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
display.desktop_mode.w = dispdata->mode.hdisplay;
|
|
|
|
display.desktop_mode.h = dispdata->mode.vdisplay;
|
|
|
|
display.desktop_mode.refresh_rate = dispdata->mode.vrefresh;
|
|
|
|
#if 1
|
|
|
|
display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
|
|
|
|
#else
|
|
|
|
/* FIXME */
|
2020-07-28 21:11:25 +02:00
|
|
|
drmModeFB *fb = drmModeGetFB(viddata->drm_fd, dispdata->crtc->buffer_id);
|
2020-02-09 20:44:22 +01:00
|
|
|
display.desktop_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
|
|
|
|
drmModeFreeFB(fb);
|
|
|
|
#endif
|
Fixed bug 5147 - KMSDRM: SetWindowFullscreen() failing with SDL_WINDOW_FULLSCREEN_DESKTOP
Manuel Alfayate Corchete
This patch is needed so programs that do this work as expected:
1) Start in a different video mode than the mode used by the system and then...
2) Try to go fullscreen with the mode originally used by the system via SetWindowFullScreen() with the SDL_WINDOW_FULLSCREEN_DESKTOP flag.
An example would be pt2-clone in https://github.com/8bitbubsy/pt2-clone.
This program does this:
Starts with:
video.window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, screenW, screenH, windowFlags);
and then, *IF* the user has configured it in fullscreen mode in its .ini, it tries to go fullscreen with the desktop mode:
SDL_SetWindowFullscreen(video.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
This sequence of operations is currently failing because SDL_SetDisplayModeForDisplay() in SDL_video.c fails because display->desktop_mode is not being initialized with its correct value: SetDisplayMode() in SDL_kmsdrmvideo.c will not be able to set the mode because it detects the mode to have a driverdata of 0x0 ("if (!modedata)") and rightfully returns an error.
So, the included patch fixes this small problem, and programs that first change the video mode and then try to go fullscreen with the system video mode will now work.
The patch simply fixes an small omission, but its really needed now that dynamic video mode changing was implemented on the KMSDRM backend.
2020-06-03 01:57:20 +02:00
|
|
|
|
|
|
|
/* DRM mode index for the desktop mode is needed to complete desktop mode init NOW,
|
2020-08-05 15:28:51 +02:00
|
|
|
so look for it in the DRM modes array.
|
|
|
|
This is needed because SetDisplayMode() uses the mode index, and some programs
|
|
|
|
change to fullscreen desktop video mode as they start. */
|
2020-08-17 18:35:04 +02:00
|
|
|
for (int i = 0; i < dispdata->connector->connector->count_modes; i++) {
|
|
|
|
if (!SDL_memcmp(dispdata->connector->connector->modes + i, &dispdata->crtc->crtc->mode, sizeof(drmModeModeInfo))) {
|
Fixed bug 5147 - KMSDRM: SetWindowFullscreen() failing with SDL_WINDOW_FULLSCREEN_DESKTOP
Manuel Alfayate Corchete
This patch is needed so programs that do this work as expected:
1) Start in a different video mode than the mode used by the system and then...
2) Try to go fullscreen with the mode originally used by the system via SetWindowFullScreen() with the SDL_WINDOW_FULLSCREEN_DESKTOP flag.
An example would be pt2-clone in https://github.com/8bitbubsy/pt2-clone.
This program does this:
Starts with:
video.window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, screenW, screenH, windowFlags);
and then, *IF* the user has configured it in fullscreen mode in its .ini, it tries to go fullscreen with the desktop mode:
SDL_SetWindowFullscreen(video.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
This sequence of operations is currently failing because SDL_SetDisplayModeForDisplay() in SDL_video.c fails because display->desktop_mode is not being initialized with its correct value: SetDisplayMode() in SDL_kmsdrmvideo.c will not be able to set the mode because it detects the mode to have a driverdata of 0x0 ("if (!modedata)") and rightfully returns an error.
So, the included patch fixes this small problem, and programs that first change the video mode and then try to go fullscreen with the system video mode will now work.
The patch simply fixes an small omission, but its really needed now that dynamic video mode changing was implemented on the KMSDRM backend.
2020-06-03 01:57:20 +02:00
|
|
|
SDL_DisplayModeData *modedata = SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
|
|
|
if (modedata) {
|
|
|
|
modedata->mode_index = i;
|
|
|
|
display.desktop_mode.driverdata = modedata;
|
2020-08-05 15:28:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Fixed bug 5147 - KMSDRM: SetWindowFullscreen() failing with SDL_WINDOW_FULLSCREEN_DESKTOP
Manuel Alfayate Corchete
This patch is needed so programs that do this work as expected:
1) Start in a different video mode than the mode used by the system and then...
2) Try to go fullscreen with the mode originally used by the system via SetWindowFullScreen() with the SDL_WINDOW_FULLSCREEN_DESKTOP flag.
An example would be pt2-clone in https://github.com/8bitbubsy/pt2-clone.
This program does this:
Starts with:
video.window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, screenW, screenH, windowFlags);
and then, *IF* the user has configured it in fullscreen mode in its .ini, it tries to go fullscreen with the desktop mode:
SDL_SetWindowFullscreen(video.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
This sequence of operations is currently failing because SDL_SetDisplayModeForDisplay() in SDL_video.c fails because display->desktop_mode is not being initialized with its correct value: SetDisplayMode() in SDL_kmsdrmvideo.c will not be able to set the mode because it detects the mode to have a driverdata of 0x0 ("if (!modedata)") and rightfully returns an error.
So, the included patch fixes this small problem, and programs that first change the video mode and then try to go fullscreen with the system video mode will now work.
The patch simply fixes an small omission, but its really needed now that dynamic video mode changing was implemented on the KMSDRM backend.
2020-06-03 01:57:20 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
display.current_mode = display.desktop_mode;
|
|
|
|
display.driverdata = dispdata;
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_AddVideoDisplay(&display);
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
/****************/
|
|
|
|
/* Atomic block */
|
|
|
|
/****************/
|
|
|
|
|
|
|
|
ret = KMSDRM_drmSetClientCap(viddata->drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
|
|
|
|
if (ret) {
|
|
|
|
ret = SDL_SetError("no atomic modesetting support.");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = KMSDRM_drmSetClientCap(viddata->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
|
|
|
if (ret) {
|
|
|
|
ret = SDL_SetError("no universal planes support.");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-08-05 15:28:51 +02:00
|
|
|
/* Use this if you ever need to see info on all available planes. */
|
|
|
|
#if 0
|
|
|
|
get_planes_info(_this);
|
|
|
|
#endif
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Get DISPLAY PLANE (simply a primary plane that can use our CRTC).
|
|
|
|
It has to be a PRIMARY plane because there's no guarantee that
|
|
|
|
we have overlays in every hardware: we can really only count
|
|
|
|
on having one primary plane). */
|
|
|
|
display_plane_id = get_plane_id(_this, resources, DRM_PLANE_TYPE_PRIMARY);
|
|
|
|
if (!display_plane_id) {
|
|
|
|
ret = SDL_SetError("could not find a suitable display plane.");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
dispdata->display_plane->plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, display_plane_id);
|
|
|
|
|
|
|
|
/* Get DISPLAY PLANE properties */
|
|
|
|
dispdata->display_plane->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
|
|
|
|
dispdata->display_plane->plane->plane_id, DRM_MODE_OBJECT_PLANE);
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->display_plane->props_info = SDL_calloc(dispdata->display_plane->props->count_props,
|
|
|
|
sizeof(dispdata->display_plane->props_info));
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
for (int i = 0; i < dispdata->display_plane->props->count_props; i++) {
|
|
|
|
dispdata->display_plane->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd,
|
|
|
|
dispdata->display_plane->props->props[i]);
|
|
|
|
}
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Get CURSOR PLANE (simply a cursor plane that can use our CRTC).
|
|
|
|
Not having a cursor plane available should not be fatal, just throw an error.
|
|
|
|
All functions using this plane should first test if it exists. */
|
|
|
|
cursor_plane_id = get_plane_id(_this, resources, DRM_PLANE_TYPE_CURSOR);
|
|
|
|
if (!cursor_plane_id) {
|
|
|
|
SDL_SetError("could not find a suitable cursor plane.");
|
|
|
|
}
|
|
|
|
dispdata->cursor_plane->plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, cursor_plane_id);
|
|
|
|
|
|
|
|
/* Get CURSOR PLANE properties */
|
|
|
|
if (dispdata->cursor_plane->plane) {
|
|
|
|
dispdata->cursor_plane->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
|
|
|
|
dispdata->cursor_plane->plane->plane_id, DRM_MODE_OBJECT_PLANE);
|
|
|
|
|
|
|
|
dispdata->cursor_plane->props_info = SDL_calloc(dispdata->cursor_plane->props->count_props,
|
|
|
|
sizeof(dispdata->cursor_plane->props_info));
|
|
|
|
|
|
|
|
for (int i = 0; i < dispdata->cursor_plane->props->count_props; i++) {
|
|
|
|
dispdata->cursor_plane->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd,
|
|
|
|
dispdata->cursor_plane->props->props[i]);
|
|
|
|
}
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get CRTC properties */
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->crtc->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
|
|
|
|
dispdata->crtc->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->crtc->props_info = SDL_calloc(dispdata->crtc->props->count_props,
|
|
|
|
sizeof(dispdata->crtc->props_info));
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
for (int i = 0; i < dispdata->crtc->props->count_props; i++) {
|
|
|
|
dispdata->crtc->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd,
|
|
|
|
dispdata->crtc->props->props[i]);
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get connector properties */
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->connector->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd,
|
|
|
|
dispdata->connector->connector->connector_id, DRM_MODE_OBJECT_CONNECTOR);
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
dispdata->connector->props_info = SDL_calloc(dispdata->connector->props->count_props,
|
|
|
|
sizeof(dispdata->connector->props_info));
|
2020-07-28 21:11:25 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
for (int i = 0; i < dispdata->connector->props->count_props; i++) {
|
|
|
|
dispdata->connector->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd,
|
|
|
|
dispdata->connector->props->props[i]);
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
/* Atomic block ends */
|
|
|
|
/*********************/
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
#ifdef SDL_INPUT_LINUXEV
|
|
|
|
SDL_EVDEV_Init();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
KMSDRM_InitMouse(_this);
|
|
|
|
|
|
|
|
cleanup:
|
2020-08-17 18:35:04 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (encoder)
|
2017-08-02 19:22:48 +02:00
|
|
|
KMSDRM_drmModeFreeEncoder(encoder);
|
2020-02-09 20:44:22 +01:00
|
|
|
if (resources)
|
2017-08-02 19:22:48 +02:00
|
|
|
KMSDRM_drmModeFreeResources(resources);
|
|
|
|
if (ret != 0) {
|
|
|
|
/* Error (complete) cleanup */
|
2020-08-17 18:35:04 +02:00
|
|
|
if (dispdata->connector->connector) {
|
|
|
|
KMSDRM_drmModeFreeConnector(dispdata->connector->connector);
|
2020-07-28 21:11:25 +02:00
|
|
|
dispdata->connector = NULL;
|
2020-02-09 20:44:22 +01:00
|
|
|
}
|
2020-08-17 18:35:04 +02:00
|
|
|
if (dispdata->crtc->crtc) {
|
|
|
|
KMSDRM_drmModeFreeCrtc(dispdata->crtc->crtc);
|
2020-07-28 21:11:25 +02:00
|
|
|
dispdata->crtc = NULL;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
2020-07-20 11:42:23 +02:00
|
|
|
if (viddata->gbm_dev) {
|
|
|
|
KMSDRM_gbm_device_destroy(viddata->gbm_dev);
|
|
|
|
viddata->gbm_dev = NULL;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
2020-02-09 20:44:22 +01:00
|
|
|
if (viddata->drm_fd >= 0) {
|
|
|
|
close(viddata->drm_fd);
|
|
|
|
viddata->drm_fd = -1;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_free(dispdata);
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
2020-08-17 18:35:04 +02:00
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KMSDRM_VideoQuit(_THIS)
|
|
|
|
{
|
2020-08-06 01:36:56 +02:00
|
|
|
int ret;
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()");
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
/* Clear out the window list */
|
|
|
|
SDL_free(viddata->windows);
|
|
|
|
viddata->windows = NULL;
|
|
|
|
viddata->max_windows = 0;
|
|
|
|
viddata->num_windows = 0;
|
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
/* Restore original buffer. */
|
2020-08-17 18:35:04 +02:00
|
|
|
if (viddata->drm_fd >= 0 && dispdata && dispdata->connector->connector && dispdata->crtc->crtc) {
|
2020-08-06 01:36:56 +02:00
|
|
|
/***********************************************************/
|
2020-08-08 14:27:55 +02:00
|
|
|
/* Atomic block for original crt->buffer restoration */
|
2020-08-06 01:36:56 +02:00
|
|
|
/***********************************************************/
|
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
/* Issue sync/blocking atomic commit that points crtc to original buffer.
|
2020-08-17 18:35:04 +02:00
|
|
|
SDL_video has already called SetDisplayMode() to set the original
|
|
|
|
display mode at this point.
|
|
|
|
We are not doing pageflips anymore, so we can't rely on the SwapWindow()
|
|
|
|
atomic_commit() call, hence we are explicitly calling atomic_commit() here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
drm_atomic_setbuffer(_this, dispdata->display_plane, dispdata->crtc->crtc->buffer_id);
|
2020-08-08 14:27:55 +02:00
|
|
|
ret = drm_atomic_commit(_this, SDL_TRUE);
|
2020-08-07 11:53:04 +02:00
|
|
|
|
2020-08-06 01:36:56 +02:00
|
|
|
/*********************/
|
|
|
|
/* Atomic block ends */
|
|
|
|
/*********************/
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
if (ret != 0) {
|
2020-08-05 18:55:22 +02:00
|
|
|
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original videomode");
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-06 01:36:56 +02:00
|
|
|
|
|
|
|
if (_this->gl_config.driver_loaded) {
|
|
|
|
SDL_GL_UnloadLibrary();
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/**********************************************/
|
|
|
|
/* Atomic block for freeing up property sets. */
|
|
|
|
/**********************************************/
|
|
|
|
if (dispdata && dispdata->connector->props_info) {
|
|
|
|
SDL_free(dispdata->connector->props_info);
|
|
|
|
dispdata->connector->props_info = NULL;
|
2020-08-05 15:28:51 +02:00
|
|
|
}
|
2020-08-17 18:35:04 +02:00
|
|
|
if (dispdata && dispdata->crtc->props_info) {
|
|
|
|
SDL_free(dispdata->crtc->props_info);
|
|
|
|
dispdata->crtc->props_info = NULL;
|
2020-08-05 15:28:51 +02:00
|
|
|
}
|
2020-08-17 18:35:04 +02:00
|
|
|
if (dispdata && dispdata->display_plane->props_info) {
|
|
|
|
SDL_free(dispdata->display_plane->props_info);
|
|
|
|
dispdata->display_plane->props_info = NULL;
|
2020-08-05 15:28:51 +02:00
|
|
|
}
|
|
|
|
/*********************/
|
|
|
|
/* Atomic block ends */
|
|
|
|
/*********************/
|
2020-08-06 01:36:56 +02:00
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
if (dispdata && dispdata->connector->connector != NULL) {
|
|
|
|
KMSDRM_drmModeFreeConnector(dispdata->connector->connector);
|
2020-07-28 21:11:25 +02:00
|
|
|
dispdata->connector = NULL;
|
2020-02-09 20:44:22 +01:00
|
|
|
}
|
2020-08-17 18:35:04 +02:00
|
|
|
if (dispdata && dispdata->crtc->crtc != NULL) {
|
|
|
|
KMSDRM_drmModeFreeCrtc(dispdata->crtc->crtc);
|
|
|
|
dispdata->crtc->crtc = NULL;
|
2020-02-09 20:44:22 +01:00
|
|
|
}
|
2020-07-20 11:42:23 +02:00
|
|
|
if (viddata->gbm_dev) {
|
|
|
|
KMSDRM_gbm_device_destroy(viddata->gbm_dev);
|
|
|
|
viddata->gbm_dev = NULL;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
2020-02-09 20:44:22 +01:00
|
|
|
if (viddata->drm_fd >= 0) {
|
|
|
|
close(viddata->drm_fd);
|
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", viddata->drm_fd);
|
|
|
|
viddata->drm_fd = -1;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
#ifdef SDL_INPUT_LINUXEV
|
|
|
|
SDL_EVDEV_Quit();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
|
|
|
{
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_DisplayData *dispdata = display->driverdata;
|
2020-08-17 18:35:04 +02:00
|
|
|
drmModeConnector *conn = dispdata->connector->connector;
|
2020-02-15 01:17:17 +01:00
|
|
|
SDL_DisplayMode mode;
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < conn->count_modes; i++) {
|
|
|
|
SDL_DisplayModeData *modedata = SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
|
|
|
|
|
|
|
if (modedata) {
|
|
|
|
modedata->mode_index = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
mode.w = conn->modes[i].hdisplay;
|
|
|
|
mode.h = conn->modes[i].vdisplay;
|
|
|
|
mode.refresh_rate = conn->modes[i].vrefresh;
|
|
|
|
mode.format = SDL_PIXELFORMAT_ARGB8888;
|
|
|
|
mode.driverdata = modedata;
|
|
|
|
|
|
|
|
if (!SDL_AddDisplayMode(display, &mode)) {
|
|
|
|
SDL_free(modedata);
|
|
|
|
}
|
|
|
|
}
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
|
|
|
{
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
|
|
|
|
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
|
|
|
|
|
|
|
|
if (!modedata) {
|
|
|
|
return SDL_SetError("Mode doesn't have an associated index");
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:35:04 +02:00
|
|
|
/* Set new videomode for the connector in use. */
|
|
|
|
drm_atomic_modeset(_this, modedata->mode_index);
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < viddata->num_windows; i++) {
|
|
|
|
SDL_Window *window = viddata->windows[i];
|
|
|
|
|
2020-07-19 19:09:15 +02:00
|
|
|
/* Re-create GBM and EGL surfaces everytime we change the display mode. */
|
2020-08-17 18:35:04 +02:00
|
|
|
KMSDRM_DestroySurfaces(_this, window);
|
|
|
|
KMSDRM_CreateSurfaces(_this, window);
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
/* Tell app about the resize */
|
|
|
|
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode->w, mode->h);
|
|
|
|
}
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
KMSDRM_CreateWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
|
2020-02-15 01:17:17 +01:00
|
|
|
SDL_WindowData *windata;
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
#if SDL_VIDEO_OPENGL_EGL
|
|
|
|
if (!_this->egl_data) {
|
|
|
|
if (SDL_GL_LoadLibrary(NULL) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
/* Allocate window internal data */
|
2020-02-15 01:17:17 +01:00
|
|
|
windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
if (!windata) {
|
2017-08-04 23:00:47 +02:00
|
|
|
SDL_OutOfMemory();
|
|
|
|
goto error;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 18:55:22 +02:00
|
|
|
/* Init fields. */
|
2020-07-19 18:45:29 +02:00
|
|
|
windata->egl_surface_dirty = SDL_FALSE;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-07-19 19:53:57 +02:00
|
|
|
/* First remember that certain functions in SDL_Video.c will call *_SetDisplayMode when the
|
|
|
|
SDL_WINDOW_FULLSCREEN is set and SDL_WINDOW_FULLSCREEN_DESKTOP is not set.
|
|
|
|
So I am determining here that the behavior when creating an SDL_Window() in KMSDRM, is:
|
|
|
|
|
|
|
|
-Creating a normal non-fullscreen window won't change the display mode.
|
|
|
|
They won't cover the full screen area, either, because that breaks the image aspect ratio.
|
|
|
|
-Creating a SDL_WINDOW_FULLSCREEN window will change the display mode,
|
|
|
|
because SDL_WINDOW_FULLSCREEN flag is set.
|
|
|
|
-Creating a SDL_WINDOW_FULLSCREEN_DESKTOP window will not change the display mode,
|
|
|
|
because even if the SDL_WINDOW_FULLSCREEN flag is set, SDL_WINDOW_FULLSCREEN_DESKTOP prevents it.
|
|
|
|
|
|
|
|
If we ever decide that we want to have normal windows (non-SDL_WINDOW_FULLSCREEN) should cause a display
|
|
|
|
mode change, we could force the SDL_WINDOW_FULLSCREEN flag again on every window.
|
|
|
|
But remember that it will break games that check if a window is FULLSCREEN or not before setting
|
|
|
|
a fullscreen mode with SDL_SetWindowFullscreen(), like sm64ex (sm64 pc port).
|
|
|
|
If we ever decide that we want normal windows to cover the whole screen area, we can force window->w
|
|
|
|
and window->h to the original display mode dimensions.
|
|
|
|
|
|
|
|
Commented reference code for all this:
|
|
|
|
|
|
|
|
window->flags |= (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
|
|
|
|
|
|
|
|
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
|
|
|
|
|
|
|
window->w = display->desktop_mode.w;
|
|
|
|
window->h = display->desktop_mode.h; */
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
/* Setup driver data for this window */
|
2020-06-19 19:37:14 +02:00
|
|
|
windata->viddata = viddata;
|
2020-02-09 20:44:22 +01:00
|
|
|
window->driverdata = windata;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (KMSDRM_CreateSurfaces(_this, window)) {
|
|
|
|
goto error;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
/* Add window to the internal list of tracked windows. Note, while it may
|
|
|
|
seem odd to support multiple fullscreen windows, some apps create an
|
|
|
|
extra window as a dummy surface when working with multiple contexts */
|
|
|
|
if (viddata->num_windows >= viddata->max_windows) {
|
|
|
|
int new_max_windows = viddata->max_windows + 1;
|
|
|
|
viddata->windows = (SDL_Window **)SDL_realloc(viddata->windows,
|
|
|
|
new_max_windows * sizeof(SDL_Window *));
|
|
|
|
viddata->max_windows = new_max_windows;
|
2017-10-21 13:20:57 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
if (!viddata->windows) {
|
|
|
|
SDL_OutOfMemory();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-02-09 20:44:22 +01:00
|
|
|
viddata->windows[viddata->num_windows++] = window;
|
2017-08-02 19:22:48 +02:00
|
|
|
|
2020-03-07 17:48:04 +01:00
|
|
|
/* Focus on the newly created window */
|
|
|
|
SDL_SetMouseFocus(window);
|
|
|
|
SDL_SetKeyboardFocus(window);
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2020-02-09 20:44:22 +01:00
|
|
|
KMSDRM_DestroyWindow(_this, window);
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KMSDRM_DestroyWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
|
2020-02-15 01:17:17 +01:00
|
|
|
SDL_VideoData *viddata;
|
2020-02-09 20:44:22 +01:00
|
|
|
if (!windata) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove from the internal window list */
|
2020-02-15 01:17:17 +01:00
|
|
|
viddata = windata->viddata;
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < viddata->num_windows; i++) {
|
|
|
|
if (viddata->windows[i] == window) {
|
|
|
|
viddata->num_windows--;
|
|
|
|
|
|
|
|
for (int j = i; j < viddata->num_windows; j++) {
|
|
|
|
viddata->windows[j] = viddata->windows[j + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
}
|
2020-02-09 20:44:22 +01:00
|
|
|
|
|
|
|
KMSDRM_DestroySurfaces(_this, window);
|
|
|
|
|
|
|
|
window->driverdata = NULL;
|
|
|
|
|
|
|
|
SDL_free(windata);
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KMSDRM_SetWindowTitle(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_SetWindowPosition(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_SetWindowSize(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_ShowWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_HideWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_RaiseWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_MaximizeWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_MinimizeWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_RestoreWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
|
|
KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* SDL Window Manager function */
|
|
|
|
/*****************************************************************************/
|
|
|
|
SDL_bool
|
|
|
|
KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
|
|
|
|
{
|
|
|
|
if (info->version.major <= SDL_MAJOR_VERSION) {
|
|
|
|
return SDL_TRUE;
|
|
|
|
} else {
|
|
|
|
SDL_SetError("application not compiled with SDL %d.%d\n",
|
|
|
|
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Failed to get window manager information */
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
|
|
|
|
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|