Potential fix for bug 5393 - KMSDRM: using atomic mode setting breaks GPU compatibility

Substring

I was trying the KMSDRM video backend with some very simple programs that were working ok on 2.0.12. The same code won?t work on the current dev branch and I get:

DEBUG: check_modesetting: probing ?/dev/dri/card0?
DEBUG: /dev/dri/card0 connector, encoder and CRTC counts are: 4 5 6
DEBUG: check_modesetting: probing ?/dev/dri/card0?
DEBUG: /dev/dri/card0 connector, encoder and CRTC counts are: 4 5 6
DEBUG: KMSDRM_VideoInit()
DEBUG: Opening device /dev/dri/card0
DEBUG: Opened DRM FD (3)
DEBUG: no atomic modesetting support.
DEBUG: Video subsystem has not been initialized
INFO: Using SDL video driver: (null)
DEBUG: Video subsystem has not been initialized

After carefully checking, the radeon driver doesn?t support atomic modesetting. That?s not the only problem : the same happens with the amdgpu driver if we disable Display Core (kernel parameter amdgpu.dc=0, which is required to get analogue outputs working).

This is a major regression in the KMSDRM driver.

Using atomic mode setting is great, but having no fallback to the "standard KMS" is bad.
This commit is contained in:
Sam Lantinga 2020-12-15 12:22:48 -08:00
parent c02d88dd12
commit f8839289b0
16 changed files with 2203 additions and 1 deletions

View File

@ -1163,7 +1163,8 @@ macro(CheckKMSDRM)
set(HAVE_SDL_VIDEO TRUE) set(HAVE_SDL_VIDEO TRUE)
file(GLOB KMSDRM_SOURCES ${SDL2_SOURCE_DIR}/src/video/kmsdrm/*.c) file(GLOB KMSDRM_SOURCES ${SDL2_SOURCE_DIR}/src/video/kmsdrm/*.c)
set(SOURCE_FILES ${SOURCE_FILES} ${KMSDRM_SOURCES}) file(GLOB KMSDRM_LEGACY_SOURCES ${SDL2_SOURCE_DIR}/src/video/kmsdrm_legacy/*.c)
set(SOURCE_FILES ${SOURCE_FILES} ${KMSDRM_SOURCES} ${KMSDRM_LEGACY_SOURCES})
list(APPEND EXTRA_CFLAGS ${KMSDRM_CFLAGS}) list(APPEND EXTRA_CFLAGS ${KMSDRM_CFLAGS})

1
configure vendored
View File

@ -22119,6 +22119,7 @@ fi
$as_echo "#define SDL_VIDEO_DRIVER_KMSDRM 1" >>confdefs.h $as_echo "#define SDL_VIDEO_DRIVER_KMSDRM 1" >>confdefs.h
SOURCES="$SOURCES $srcdir/src/video/kmsdrm/*.c" SOURCES="$SOURCES $srcdir/src/video/kmsdrm/*.c"
SOURCES="$SOURCES $srcdir/src/video/kmsdrm_legacy/*.c"
EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBDRM_CFLAGS $LIBGBM_CFLAGS" EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBDRM_CFLAGS $LIBGBM_CFLAGS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kmsdrm dynamic loading support" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kmsdrm dynamic loading support" >&5

View File

@ -2253,6 +2253,7 @@ AS_HELP_STRING([--enable-kmsdrm-shared], [dynamically load kmsdrm support [[defa
AC_DEFINE(SDL_VIDEO_DRIVER_KMSDRM, 1, [ ]) AC_DEFINE(SDL_VIDEO_DRIVER_KMSDRM, 1, [ ])
SOURCES="$SOURCES $srcdir/src/video/kmsdrm/*.c" SOURCES="$SOURCES $srcdir/src/video/kmsdrm/*.c"
SOURCES="$SOURCES $srcdir/src/video/kmsdrm_legacy/*.c"
EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBDRM_CFLAGS $LIBGBM_CFLAGS" EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBDRM_CFLAGS $LIBGBM_CFLAGS"
AC_MSG_CHECKING(for kmsdrm dynamic loading support) AC_MSG_CHECKING(for kmsdrm dynamic loading support)

View File

@ -429,6 +429,7 @@ extern VideoBootStrap Android_bootstrap;
extern VideoBootStrap PSP_bootstrap; extern VideoBootStrap PSP_bootstrap;
extern VideoBootStrap RPI_bootstrap; extern VideoBootStrap RPI_bootstrap;
extern VideoBootStrap KMSDRM_bootstrap; extern VideoBootStrap KMSDRM_bootstrap;
extern VideoBootStrap KMSDRM_LEGACY_bootstrap;
extern VideoBootStrap DUMMY_bootstrap; extern VideoBootStrap DUMMY_bootstrap;
extern VideoBootStrap Wayland_bootstrap; extern VideoBootStrap Wayland_bootstrap;
extern VideoBootStrap NACL_bootstrap; extern VideoBootStrap NACL_bootstrap;

View File

@ -96,6 +96,7 @@ static VideoBootStrap *bootstrap[] = {
#endif #endif
#if SDL_VIDEO_DRIVER_KMSDRM #if SDL_VIDEO_DRIVER_KMSDRM
&KMSDRM_bootstrap, &KMSDRM_bootstrap,
&KMSDRM_LEGACY_bootstrap,
#endif #endif
#if SDL_VIDEO_DRIVER_RPI #if SDL_VIDEO_DRIVER_RPI
&RPI_bootstrap, &RPI_bootstrap,

View File

@ -0,0 +1,167 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_KMSDRM
#define DEBUG_DYNAMIC_KMSDRM_LEGACY 0
#include "SDL_kmsdrm_legacy_dyn.h"
#ifdef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
typedef struct
{
void *lib;
const char *libname;
} kmsdrmdynlib;
#ifndef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
#define SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC NULL
#endif
#ifndef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM
#define SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM NULL
#endif
static kmsdrmdynlib kmsdrmlibs[] = {
{NULL, SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM},
{NULL, SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC}
};
static void *
KMSDRM_LEGACY_GetSym(const char *fnname, int *pHasModule)
{
int i;
void *fn = NULL;
for (i = 0; i < SDL_TABLESIZE(kmsdrmlibs); i++) {
if (kmsdrmlibs[i].lib != NULL) {
fn = SDL_LoadFunction(kmsdrmlibs[i].lib, fnname);
if (fn != NULL)
break;
}
}
#if DEBUG_DYNAMIC_KMSDRM_LEGACY
if (fn != NULL)
SDL_Log("KMSDRM_LEGACY: Found '%s' in %s (%p)\n", fnname, kmsdrmlibs[i].libname, fn);
else
SDL_Log("KMSDRM_LEGACY: Symbol '%s' NOT FOUND!\n", fnname);
#endif
if (fn == NULL)
*pHasModule = 0; /* kill this module. */
return fn;
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC */
/* Define all the function pointers and wrappers... */
#define SDL_KMSDRM_LEGACY_MODULE(modname) int SDL_KMSDRM_HAVE_##modname = 0;
#define SDL_KMSDRM_LEGACY_SYM(rc,fn,params) SDL_DYNKMSDRMFN_##fn KMSDRM_##fn = NULL;
#define SDL_KMSDRM_LEGACY_SYM_CONST(type,name) SDL_DYNKMSDRMCONST_##name KMSDRM_##name = NULL;
#include "SDL_kmsdrm_legacy_sym.h"
static int kmsdrm_load_refcount = 0;
void
SDL_KMSDRM_LEGACY_UnloadSymbols(void)
{
/* Don't actually unload if more than one module is using the libs... */
if (kmsdrm_load_refcount > 0) {
if (--kmsdrm_load_refcount == 0) {
#ifdef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
int i;
#endif
/* set all the function pointers to NULL. */
#define SDL_KMSDRM_LEGACY_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 0;
#define SDL_KMSDRM_LEGACY_SYM(rc,fn,params) KMSDRM_##fn = NULL;
#define SDL_KMSDRM_LEGACY_SYM_CONST(type,name) KMSDRM_##name = NULL;
#include "SDL_kmsdrm_legacy_sym.h"
#ifdef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
for (i = 0; i < SDL_TABLESIZE(kmsdrmlibs); i++) {
if (kmsdrmlibs[i].lib != NULL) {
SDL_UnloadObject(kmsdrmlibs[i].lib);
kmsdrmlibs[i].lib = NULL;
}
}
#endif
}
}
}
/* returns non-zero if all needed symbols were loaded. */
int
SDL_KMSDRM_LEGACY_LoadSymbols(void)
{
int rc = 1; /* always succeed if not using Dynamic KMSDRM_LEGACY stuff. */
/* deal with multiple modules needing these symbols... */
if (kmsdrm_load_refcount++ == 0) {
#ifdef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
int i;
int *thismod = NULL;
for (i = 0; i < SDL_TABLESIZE(kmsdrmlibs); i++) {
if (kmsdrmlibs[i].libname != NULL) {
kmsdrmlibs[i].lib = SDL_LoadObject(kmsdrmlibs[i].libname);
}
}
#define SDL_KMSDRM_LEGACY_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 1; /* default yes */
#include "SDL_kmsdrm_legacy_sym.h"
#define SDL_KMSDRM_LEGACY_MODULE(modname) thismod = &SDL_KMSDRM_HAVE_##modname;
#define SDL_KMSDRM_LEGACY_SYM(rc,fn,params) KMSDRM_##fn = (SDL_DYNKMSDRMFN_##fn) KMSDRM_GetSym(#fn,thismod);
#define SDL_KMSDRM_LEGACY_SYM_CONST(type,name) KMSDRM_##name = *(SDL_DYNKMSDRMCONST_##name*) KMSDRM_GetSym(#name,thismod);
#include "SDL_kmsdrm_legacy_sym.h"
if ((SDL_KMSDRM_LEGACY_HAVE_LIBDRM) && (SDL_KMSDRM_HAVE_GBM)) {
/* all required symbols loaded. */
SDL_ClearError();
} else {
/* in case something got loaded... */
SDL_KMSDRM_LEGACY_UnloadSymbols();
rc = 0;
}
#else /* no dynamic KMSDRM_LEGACY */
#define SDL_KMSDRM_LEGACY_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 1; /* default yes */
#define SDL_KMSDRM_LEGACY_SYM(rc,fn,params) KMSDRM_##fn = fn;
#define SDL_KMSDRM_LEGACY_SYM_CONST(type,name) KMSDRM_##name = name;
#include "SDL_kmsdrm_legacy_sym.h"
#endif
}
return rc;
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,53 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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 SDL_kmsdrmdyn_h_
#define SDL_kmsdrmdyn_h_
#include "../../SDL_internal.h"
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#ifdef __cplusplus
extern "C" {
#endif
int SDL_KMSDRM_LEGACY_LoadSymbols(void);
void SDL_KMSDRM_LEGACY_UnloadSymbols(void);
/* Declare all the function pointers and wrappers... */
#define SDL_KMSDRM_LEGACY_SYM(rc,fn,params) \
typedef rc (*SDL_DYNKMSDRM_LEGACYFN_##fn) params; \
extern SDL_DYNKMSDRM_LEGACYFN_##fn KMSDRM_##fn;
#define SDL_KMSDRM_LEGACY_SYM_CONST(type, name) \
typedef type SDL_DYNKMSDRM_LEGACYCONST_##name; \
extern SDL_DYNKMSDRM_LEGACYCONST_##name KMSDRM_##name;
#include "SDL_kmsdrm_legacy_sym.h"
#ifdef __cplusplus
}
#endif
#endif /* SDL_kmsdrmdyn_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_KMSDRM
#include "SDL_kmsdrm_legacy_video.h"
#include "SDL_kmsdrm_legacy_events.h"
#ifdef SDL_INPUT_LINUXEV
#include "../../core/linux/SDL_evdev.h"
#endif
void KMSDRM_LEGACY_PumpEvents(_THIS)
{
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Poll();
#endif
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#ifndef SDL_kmsdrmevents_h_
#define SDL_kmsdrmevents_h_
extern void KMSDRM_LEGACY_PumpEvents(_THIS);
extern void KMSDRM_LEGACY_EventInit(_THIS);
extern void KMSDRM_LEGACY_EventQuit(_THIS);
#endif /* SDL_kmsdrmevents_h_ */

View File

@ -0,0 +1,502 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_KMSDRM
#include "SDL_kmsdrm_legacy_video.h"
#include "SDL_kmsdrm_legacy_mouse.h"
#include "SDL_kmsdrm_legacy_dyn.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/default_cursor.h"
static SDL_Cursor *KMSDRM_LEGACY_CreateDefaultCursor(void);
static SDL_Cursor *KMSDRM_LEGACY_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
static int KMSDRM_LEGACY_ShowCursor(SDL_Cursor * cursor);
static void KMSDRM_LEGACY_MoveCursor(SDL_Cursor * cursor);
static void KMSDRM_LEGACY_FreeCursor(SDL_Cursor * cursor);
static void KMSDRM_LEGACY_WarpMouse(SDL_Window * window, int x, int y);
static int KMSDRM_LEGACY_WarpMouseGlobal(int x, int y);
static SDL_Cursor *
KMSDRM_LEGACY_CreateDefaultCursor(void)
{
return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
}
/* Evaluate if a given cursor size is supported or not. Notably, current Intel gfx only support 64x64 and up. */
static SDL_bool
KMSDRM_LEGACY_IsCursorSizeSupported (int w, int h, uint32_t bo_format) {
SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
int ret;
uint32_t bo_handle;
struct gbm_bo *bo = KMSDRM_LEGACY_gbm_bo_create(viddata->gbm, w, h, bo_format,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo) {
SDL_SetError("Could not create GBM cursor BO width size %dx%d for size testing", w, h);
goto cleanup;
}
bo_handle = KMSDRM_LEGACY_gbm_bo_get_handle(bo).u32;
ret = KMSDRM_LEGACY_drmModeSetCursor(viddata->drm_fd, dispdata->crtc_id, bo_handle, w, h);
if (ret) {
goto cleanup;
}
else {
KMSDRM_LEGACY_gbm_bo_destroy(bo);
return SDL_TRUE;
}
cleanup:
if (bo) {
KMSDRM_LEGACY_gbm_bo_destroy(bo);
}
return SDL_FALSE;
}
/* Create a cursor from a surface */
static SDL_Cursor *
KMSDRM_LEGACY_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
{
SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
SDL_PixelFormat *pixlfmt = surface->format;
KMSDRM_LEGACY_CursorData *curdata;
SDL_Cursor *cursor;
SDL_bool cursor_supported = SDL_FALSE;
int i, ret, usable_cursor_w, usable_cursor_h;
uint32_t bo_format, bo_stride;
char *buffer = NULL;
size_t bufsize;
switch(pixlfmt->format) {
case SDL_PIXELFORMAT_RGB332:
bo_format = GBM_FORMAT_RGB332;
break;
case SDL_PIXELFORMAT_ARGB4444:
bo_format = GBM_FORMAT_ARGB4444;
break;
case SDL_PIXELFORMAT_RGBA4444:
bo_format = GBM_FORMAT_RGBA4444;
break;
case SDL_PIXELFORMAT_ABGR4444:
bo_format = GBM_FORMAT_ABGR4444;
break;
case SDL_PIXELFORMAT_BGRA4444:
bo_format = GBM_FORMAT_BGRA4444;
break;
case SDL_PIXELFORMAT_ARGB1555:
bo_format = GBM_FORMAT_ARGB1555;
break;
case SDL_PIXELFORMAT_RGBA5551:
bo_format = GBM_FORMAT_RGBA5551;
break;
case SDL_PIXELFORMAT_ABGR1555:
bo_format = GBM_FORMAT_ABGR1555;
break;
case SDL_PIXELFORMAT_BGRA5551:
bo_format = GBM_FORMAT_BGRA5551;
break;
case SDL_PIXELFORMAT_RGB565:
bo_format = GBM_FORMAT_RGB565;
break;
case SDL_PIXELFORMAT_BGR565:
bo_format = GBM_FORMAT_BGR565;
break;
case SDL_PIXELFORMAT_RGB888:
case SDL_PIXELFORMAT_RGB24:
bo_format = GBM_FORMAT_RGB888;
break;
case SDL_PIXELFORMAT_BGR888:
case SDL_PIXELFORMAT_BGR24:
bo_format = GBM_FORMAT_BGR888;
break;
case SDL_PIXELFORMAT_RGBX8888:
bo_format = GBM_FORMAT_RGBX8888;
break;
case SDL_PIXELFORMAT_BGRX8888:
bo_format = GBM_FORMAT_BGRX8888;
break;
case SDL_PIXELFORMAT_ARGB8888:
bo_format = GBM_FORMAT_ARGB8888;
break;
case SDL_PIXELFORMAT_RGBA8888:
bo_format = GBM_FORMAT_RGBA8888;
break;
case SDL_PIXELFORMAT_ABGR8888:
bo_format = GBM_FORMAT_ABGR8888;
break;
case SDL_PIXELFORMAT_BGRA8888:
bo_format = GBM_FORMAT_BGRA8888;
break;
case SDL_PIXELFORMAT_ARGB2101010:
bo_format = GBM_FORMAT_ARGB2101010;
break;
default:
SDL_SetError("Unsupported pixel format for cursor");
return NULL;
}
if (!KMSDRM_LEGACY_gbm_device_is_format_supported(viddata->gbm, bo_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) {
SDL_SetError("Unsupported pixel format for cursor");
return NULL;
}
cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
if (!cursor) {
SDL_OutOfMemory();
return NULL;
}
curdata = (KMSDRM_LEGACY_CursorData *) SDL_calloc(1, sizeof(*curdata));
if (!curdata) {
SDL_OutOfMemory();
SDL_free(cursor);
return NULL;
}
/* We have to know beforehand if a cursor with the same size as the surface is supported.
* If it's not, we have to find an usable cursor size and use an intermediate and clean buffer.
* If we can't find a cursor size supported by the hardware, we won't go on trying to
* call SDL_SetCursor() later. */
usable_cursor_w = surface->w;
usable_cursor_h = surface->h;
while (usable_cursor_w <= MAX_CURSOR_W && usable_cursor_h <= MAX_CURSOR_H) {
if (KMSDRM_LEGACY_IsCursorSizeSupported(usable_cursor_w, usable_cursor_h, bo_format)) {
cursor_supported = SDL_TRUE;
break;
}
usable_cursor_w += usable_cursor_w;
usable_cursor_h += usable_cursor_h;
}
if (!cursor_supported) {
SDL_SetError("Could not find a cursor size supported by the kernel driver");
goto cleanup;
}
curdata->hot_x = hot_x;
curdata->hot_y = hot_y;
curdata->w = usable_cursor_w;
curdata->h = usable_cursor_h;
curdata->bo = KMSDRM_LEGACY_gbm_bo_create(viddata->gbm, usable_cursor_w, usable_cursor_h, bo_format,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!curdata->bo) {
SDL_SetError("Could not create GBM cursor BO");
goto cleanup;
}
bo_stride = KMSDRM_LEGACY_gbm_bo_get_stride(curdata->bo);
bufsize = bo_stride * curdata->h;
if (surface->pitch != bo_stride) {
/* pitch doesn't match stride, must be copied to temp buffer */
buffer = SDL_malloc(bufsize);
if (!buffer) {
SDL_OutOfMemory();
goto cleanup;
}
if (SDL_MUSTLOCK(surface)) {
if (SDL_LockSurface(surface) < 0) {
/* Could not lock surface */
goto cleanup;
}
}
/* Clean the whole temporary buffer */
SDL_memset(buffer, 0x00, bo_stride * curdata->h);
/* Copy to temporary buffer */
for (i = 0; i < surface->h; i++) {
SDL_memcpy(buffer + (i * bo_stride),
((char *)surface->pixels) + (i * surface->pitch),
surface->w * pixlfmt->BytesPerPixel);
}
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
if (KMSDRM_LEGACY_gbm_bo_write(curdata->bo, buffer, bufsize)) {
SDL_SetError("Could not write to GBM cursor BO");
goto cleanup;
}
/* Free temporary buffer */
SDL_free(buffer);
buffer = NULL;
} else {
/* surface matches BO format */
if (SDL_MUSTLOCK(surface)) {
if (SDL_LockSurface(surface) < 0) {
/* Could not lock surface */
goto cleanup;
}
}
ret = KMSDRM_LEGACY_gbm_bo_write(curdata->bo, surface->pixels, bufsize);
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
if (ret) {
SDL_SetError("Could not write to GBM cursor BO");
goto cleanup;
}
}
cursor->driverdata = curdata;
return cursor;
cleanup:
if (buffer) {
SDL_free(buffer);
}
if (cursor) {
SDL_free(cursor);
}
if (curdata) {
if (curdata->bo) {
KMSDRM_LEGACY_gbm_bo_destroy(curdata->bo);
}
SDL_free(curdata);
}
return NULL;
}
/* Show the specified cursor, or hide if cursor is NULL */
static int
KMSDRM_LEGACY_ShowCursor(SDL_Cursor * cursor)
{
SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
SDL_Mouse *mouse;
KMSDRM_LEGACY_CursorData *curdata;
SDL_VideoDisplay *display = NULL;
SDL_DisplayData *dispdata = NULL;
int ret;
uint32_t bo_handle;
mouse = SDL_GetMouse();
if (!mouse) {
return SDL_SetError("No mouse.");
}
if (mouse->focus) {
display = SDL_GetDisplayForWindow(mouse->focus);
if (display) {
dispdata = (SDL_DisplayData*) display->driverdata;
}
}
if (!cursor) {
/* Hide current cursor */
if (mouse->cur_cursor && mouse->cur_cursor->driverdata) {
curdata = (KMSDRM_LEGACY_CursorData *) mouse->cur_cursor->driverdata;
if (curdata->crtc_id != 0) {
ret = KMSDRM_LEGACY_drmModeSetCursor(viddata->drm_fd, curdata->crtc_id, 0, 0, 0);
if (ret) {
SDL_SetError("Could not hide current cursor with drmModeSetCursor().");
return ret;
}
/* Mark previous cursor as not-displayed */
curdata->crtc_id = 0;
return 0;
}
}
/* otherwise if possible, hide global cursor */
if (dispdata && dispdata->crtc_id != 0) {
ret = KMSDRM_LEGACY_drmModeSetCursor(viddata->drm_fd, dispdata->crtc_id, 0, 0, 0);
if (ret) {
SDL_SetError("Could not hide display's cursor with drmModeSetCursor().");
return ret;
}
return 0;
}
return SDL_SetError("Couldn't find cursor to hide.");
}
/* If cursor != NULL, show new cursor on display */
if (!display) {
return SDL_SetError("Could not get display for mouse.");
}
if (!dispdata) {
return SDL_SetError("Could not get display driverdata.");
}
curdata = (KMSDRM_LEGACY_CursorData *) cursor->driverdata;
if (!curdata || !curdata->bo) {
return SDL_SetError("Cursor not initialized properly.");
}
bo_handle = KMSDRM_LEGACY_gbm_bo_get_handle(curdata->bo).u32;
if (curdata->hot_x == 0 && curdata->hot_y == 0) {
ret = KMSDRM_LEGACY_drmModeSetCursor(viddata->drm_fd, dispdata->crtc_id, bo_handle,
curdata->w, curdata->h);
} else {
ret = KMSDRM_LEGACY_drmModeSetCursor2(viddata->drm_fd, dispdata->crtc_id, bo_handle,
curdata->w, curdata->h, curdata->hot_x, curdata->hot_y);
}
if (ret) {
SDL_SetError("drmModeSetCursor failed.");
return ret;
}
curdata->crtc_id = dispdata->crtc_id;
return 0;
}
/* Free a window manager cursor */
static void
KMSDRM_LEGACY_FreeCursor(SDL_Cursor * cursor)
{
KMSDRM_LEGACY_CursorData *curdata;
int drm_fd;
if (cursor) {
curdata = (KMSDRM_LEGACY_CursorData *) cursor->driverdata;
if (curdata) {
if (curdata->bo) {
if (curdata->crtc_id != 0) {
drm_fd = KMSDRM_LEGACY_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(curdata->bo));
/* Hide the cursor if previously shown on a CRTC */
KMSDRM_LEGACY_drmModeSetCursor(drm_fd, curdata->crtc_id, 0, 0, 0);
curdata->crtc_id = 0;
}
KMSDRM_LEGACY_gbm_bo_destroy(curdata->bo);
curdata->bo = NULL;
}
SDL_free(cursor->driverdata);
}
SDL_free(cursor);
}
}
/* Warp the mouse to (x,y) */
static void
KMSDRM_LEGACY_WarpMouse(SDL_Window * window, int x, int y)
{
/* Only one global/fullscreen window is supported */
KMSDRM_LEGACY_WarpMouseGlobal(x, y);
}
/* Warp the mouse to (x,y) */
static int
KMSDRM_LEGACY_WarpMouseGlobal(int x, int y)
{
KMSDRM_LEGACY_CursorData *curdata;
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
/* Update internal mouse position. */
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x, y);
/* And now update the cursor graphic position on screen. */
curdata = (KMSDRM_LEGACY_CursorData *) mouse->cur_cursor->driverdata;
if (curdata->bo) {
if (curdata->crtc_id != 0) {
int ret, drm_fd;
drm_fd = KMSDRM_LEGACY_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(curdata->bo));
ret = KMSDRM_LEGACY_drmModeMoveCursor(drm_fd, curdata->crtc_id, x, y);
if (ret) {
SDL_SetError("drmModeMoveCursor() failed.");
}
return ret;
} else {
return SDL_SetError("Cursor is not currently shown.");
}
} else {
return SDL_SetError("Cursor not initialized properly.");
}
} else {
return SDL_SetError("No mouse or current cursor.");
}
}
void
KMSDRM_LEGACY_InitMouse(_THIS)
{
/* FIXME: Using UDEV it should be possible to scan all mice
* but there's no point in doing so as there's no multimice support...yet!
*/
SDL_Mouse *mouse = SDL_GetMouse();
mouse->CreateCursor = KMSDRM_LEGACY_CreateCursor;
mouse->ShowCursor = KMSDRM_LEGACY_ShowCursor;
mouse->MoveCursor = KMSDRM_LEGACY_MoveCursor;
mouse->FreeCursor = KMSDRM_LEGACY_FreeCursor;
mouse->WarpMouse = KMSDRM_LEGACY_WarpMouse;
mouse->WarpMouseGlobal = KMSDRM_LEGACY_WarpMouseGlobal;
SDL_SetDefaultCursor(KMSDRM_LEGACY_CreateDefaultCursor());
}
void
KMSDRM_LEGACY_QuitMouse(_THIS)
{
/* TODO: ? */
}
/* This is called when a mouse motion event occurs */
static void
KMSDRM_LEGACY_MoveCursor(SDL_Cursor * cursor)
{
SDL_Mouse *mouse = SDL_GetMouse();
KMSDRM_LEGACY_CursorData *curdata;
int drm_fd, ret;
/* We must NOT call SDL_SendMouseMotion() here or we will enter recursivity!
That's why we move the cursor graphic ONLY. */
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
curdata = (KMSDRM_LEGACY_CursorData *) mouse->cur_cursor->driverdata;
drm_fd = KMSDRM_LEGACY_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(curdata->bo));
ret = KMSDRM_LEGACY_drmModeMoveCursor(drm_fd, curdata->crtc_id, mouse->x, mouse->y);
if (ret) {
SDL_SetError("drmModeMoveCursor() failed.");
}
}
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#ifndef SDL_KMSDRM_LEGACY_mouse_h_
#define SDL_KMSDRM_LEGACY_mouse_h_
#include <gbm.h>
#define MAX_CURSOR_W 512
#define MAX_CURSOR_H 512
typedef struct _KMSDRM_LEGACY_CursorData
{
struct gbm_bo *bo;
uint32_t crtc_id;
int hot_x, hot_y;
int w, h;
} KMSDRM_LEGACY_CursorData;
extern void KMSDRM_LEGACY_InitMouse(_THIS);
extern void KMSDRM_LEGACY_QuitMouse(_THIS);
#endif /* SDL_KMSDRM_LEGACY_mouse_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,152 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_KMSDRM && SDL_VIDEO_OPENGL_EGL
#include "SDL_log.h"
#include "SDL_kmsdrm_legacy_video.h"
#include "SDL_kmsdrm_legacy_opengles.h"
#include "SDL_kmsdrm_legacy_dyn.h"
#ifndef EGL_PLATFORM_GBM_MESA
#define EGL_PLATFORM_GBM_MESA 0x31D7
#endif
/* EGL implementation of SDL OpenGL support */
int
KMSDRM_LEGACY_GLES_LoadLibrary(_THIS, const char *path) {
NativeDisplayType display = (NativeDisplayType)((SDL_VideoData *)_this->driverdata)->gbm;
return SDL_EGL_LoadLibrary(_this, path, display, EGL_PLATFORM_GBM_MESA);
}
SDL_EGL_CreateContext_impl(KMSDRM_LEGACY)
int KMSDRM_LEGACY_GLES_SetSwapInterval(_THIS, int interval) {
if (!_this->egl_data) {
return SDL_SetError("EGL not initialized");
}
if (interval == 0 || interval == 1) {
_this->egl_data->egl_swapinterval = interval;
} else {
return SDL_SetError("Only swap intervals of 0 or 1 are supported");
}
return 0;
}
int
KMSDRM_LEGACY_GLES_SwapWindow(_THIS, SDL_Window * window) {
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
KMSDRM_LEGACY_FBInfo *fb_info;
int ret, timeout;
/* Recreate the GBM / EGL surfaces if the display mode has changed */
if (windata->egl_surface_dirty) {
KMSDRM_LEGACY_CreateSurfaces(_this, window);
}
/* Wait for confirmation that the next front buffer has been flipped, at which
point the previous front buffer can be released */
timeout = 0;
if (_this->egl_data->egl_swapinterval == 1) {
timeout = -1;
}
if (!KMSDRM_LEGACY_WaitPageFlip(_this, windata, timeout)) {
return 0;
}
/* Release the previous front buffer */
if (windata->curr_bo) {
KMSDRM_LEGACY_gbm_surface_release_buffer(windata->gs, windata->curr_bo);
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Released GBM surface %p", (void *)windata->curr_bo); */
windata->curr_bo = NULL;
}
windata->curr_bo = windata->next_bo;
/* Make the current back buffer the next front buffer */
if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, windata->egl_surface))) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed.");
return 0;
}
/* Lock the next front buffer so it can't be allocated as a back buffer */
windata->next_bo = KMSDRM_LEGACY_gbm_surface_lock_front_buffer(windata->gs);
if (!windata->next_bo) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not lock GBM surface front buffer");
return 0;
/* } else {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Locked GBM surface %p", (void *)windata->next_bo); */
}
fb_info = KMSDRM_LEGACY_FBFromBO(_this, windata->next_bo);
if (!fb_info) {
return 0;
}
if (!windata->curr_bo) {
/* On the first swap, immediately present the new front buffer. Before
drmModePageFlip can be used the CRTC has to be configured to use
the current connector and mode with drmModeSetCrtc */
ret = KMSDRM_LEGACY_drmModeSetCrtc(viddata->drm_fd, dispdata->crtc_id, fb_info->fb_id, 0,
0, &dispdata->conn->connector_id, 1, &dispdata->mode);
if (ret) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not configure CRTC");
}
} else {
/* On subsequent swaps, queue the new front buffer to be flipped during
the next vertical blank */
ret = KMSDRM_LEGACY_drmModePageFlip(viddata->drm_fd, dispdata->crtc_id, fb_info->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, &windata->waiting_for_flip);
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "drmModePageFlip(%d, %u, %u, DRM_MODE_PAGE_FLIP_EVENT, &windata->waiting_for_flip)",
viddata->drm_fd, displaydata->crtc_id, fb_info->fb_id); */
if (_this->egl_data->egl_swapinterval == 1) {
if (ret == 0) {
windata->waiting_for_flip = SDL_TRUE;
} else {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
}
}
/* Wait immediately for vsync (as if we only had two buffers), for low input-lag scenarios.
Run your SDL2 program with "SDL_KMSDRM_LEGACY_DOUBLE_BUFFER=1 <program_name>" to enable this. */
if (_this->egl_data->egl_swapinterval == 1 && windata->double_buffer) {
KMSDRM_LEGACY_WaitPageFlip(_this, windata, -1);
}
}
return 0;
}
SDL_EGL_MakeCurrent_impl(KMSDRM_LEGACY)
#endif /* SDL_VIDEO_DRIVER_KMSDRM && SDL_VIDEO_OPENGL_EGL */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,48 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#ifndef SDL_kmsdrmopengles_h_
#define SDL_kmsdrmopengles_h_
#if SDL_VIDEO_DRIVER_KMSDRM && SDL_VIDEO_OPENGL_EGL
#include "../SDL_sysvideo.h"
#include "../SDL_egl_c.h"
/* OpenGLES functions */
#define KMSDRM_LEGACY_GLES_GetAttribute SDL_EGL_GetAttribute
#define KMSDRM_LEGACY_GLES_GetProcAddress SDL_EGL_GetProcAddress
#define KMSDRM_LEGACY_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define KMSDRM_LEGACY_GLES_DeleteContext SDL_EGL_DeleteContext
#define KMSDRM_LEGACY_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
extern int KMSDRM_LEGACY_GLES_SetSwapInterval(_THIS, int interval);
extern int KMSDRM_LEGACY_GLES_LoadLibrary(_THIS, const char *path);
extern SDL_GLContext KMSDRM_LEGACY_GLES_CreateContext(_THIS, SDL_Window * window);
extern int KMSDRM_LEGACY_GLES_SwapWindow(_THIS, SDL_Window * window);
extern int KMSDRM_LEGACY_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
#endif /* SDL_VIDEO_DRIVER_KMSDRM && SDL_VIDEO_OPENGL_EGL */
#endif /* SDL_kmsdrmopengles_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,99 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
/* *INDENT-OFF* */
#ifndef SDL_KMSDRM_LEGACY_MODULE
#define SDL_KMSDRM_LEGACY_MODULE(modname)
#endif
#ifndef SDL_KMSDRM_LEGACY_SYM
#define SDL_KMSDRM_LEGACY_SYM(rc,fn,params)
#endif
#ifndef SDL_KMSDRM_LEGACY_SYM_CONST
#define SDL_KMSDRM_LEGACY_SYM_CONST(type, name)
#endif
SDL_KMSDRM_LEGACY_MODULE(LIBDRM)
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeResources,(drmModeResPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeFB,(drmModeFBPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeCrtc,(drmModeCrtcPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeConnector,(drmModeConnectorPtr ptr))
SDL_KMSDRM_LEGACY_SYM(void,drmModeFreeEncoder,(drmModeEncoderPtr ptr))
SDL_KMSDRM_LEGACY_SYM(drmModeResPtr,drmModeGetResources,(int fd))
SDL_KMSDRM_LEGACY_SYM(int,drmModeAddFB,(int fd, uint32_t width, uint32_t height, uint8_t depth,
uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
uint32_t *buf_id))
SDL_KMSDRM_LEGACY_SYM(int,drmModeRmFB,(int fd, uint32_t bufferId))
SDL_KMSDRM_LEGACY_SYM(drmModeFBPtr,drmModeGetFB,(int fd, uint32_t buf))
SDL_KMSDRM_LEGACY_SYM(drmModeCrtcPtr,drmModeGetCrtc,(int fd, uint32_t crtcId))
SDL_KMSDRM_LEGACY_SYM(int,drmModeSetCrtc,(int fd, uint32_t crtcId, uint32_t bufferId,
uint32_t x, uint32_t y, uint32_t *connectors, int count,
drmModeModeInfoPtr mode))
SDL_KMSDRM_LEGACY_SYM(int,drmModeSetCursor,(int fd, uint32_t crtcId, uint32_t bo_handle,
uint32_t width, uint32_t height))
SDL_KMSDRM_LEGACY_SYM(int,drmModeSetCursor2,(int fd, uint32_t crtcId, uint32_t bo_handle,
uint32_t width, uint32_t height,
int32_t hot_x, int32_t hot_y))
SDL_KMSDRM_LEGACY_SYM(int,drmModeMoveCursor,(int fd, uint32_t crtcId, int x, int y))
SDL_KMSDRM_LEGACY_SYM(drmModeEncoderPtr,drmModeGetEncoder,(int fd, uint32_t encoder_id))
SDL_KMSDRM_LEGACY_SYM(drmModeConnectorPtr,drmModeGetConnector,(int fd, uint32_t connector_id))
SDL_KMSDRM_LEGACY_SYM(int,drmHandleEvent,(int fd,drmEventContextPtr evctx))
SDL_KMSDRM_LEGACY_SYM(int,drmModePageFlip,(int fd, uint32_t crtc_id, uint32_t fb_id,
uint32_t flags, void *user_data))
SDL_KMSDRM_LEGACY_MODULE(GBM)
SDL_KMSDRM_LEGACY_SYM(int,gbm_device_get_fd,(struct gbm_device *gbm))
SDL_KMSDRM_LEGACY_SYM(int,gbm_device_is_format_supported,(struct gbm_device *gbm,
uint32_t format, uint32_t usage))
SDL_KMSDRM_LEGACY_SYM(void,gbm_device_destroy,(struct gbm_device *gbm))
SDL_KMSDRM_LEGACY_SYM(struct gbm_device *,gbm_create_device,(int fd))
SDL_KMSDRM_LEGACY_SYM(unsigned int,gbm_bo_get_width,(struct gbm_bo *bo))
SDL_KMSDRM_LEGACY_SYM(unsigned int,gbm_bo_get_height,(struct gbm_bo *bo))
SDL_KMSDRM_LEGACY_SYM(uint32_t,gbm_bo_get_stride,(struct gbm_bo *bo))
SDL_KMSDRM_LEGACY_SYM(union gbm_bo_handle,gbm_bo_get_handle,(struct gbm_bo *bo))
SDL_KMSDRM_LEGACY_SYM(int,gbm_bo_write,(struct gbm_bo *bo, const void *buf, size_t count))
SDL_KMSDRM_LEGACY_SYM(struct gbm_device *,gbm_bo_get_device,(struct gbm_bo *bo))
SDL_KMSDRM_LEGACY_SYM(void,gbm_bo_set_user_data,(struct gbm_bo *bo, void *data,
void (*destroy_user_data)(struct gbm_bo *, void *)))
SDL_KMSDRM_LEGACY_SYM(void *,gbm_bo_get_user_data,(struct gbm_bo *bo))
SDL_KMSDRM_LEGACY_SYM(void,gbm_bo_destroy,(struct gbm_bo *bo))
SDL_KMSDRM_LEGACY_SYM(struct gbm_bo *,gbm_bo_create,(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t usage))
SDL_KMSDRM_LEGACY_SYM(struct gbm_surface *,gbm_surface_create,(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t flags))
SDL_KMSDRM_LEGACY_SYM(void,gbm_surface_destroy,(struct gbm_surface *surf))
SDL_KMSDRM_LEGACY_SYM(struct gbm_bo *,gbm_surface_lock_front_buffer,(struct gbm_surface *surf))
SDL_KMSDRM_LEGACY_SYM(void,gbm_surface_release_buffer,(struct gbm_surface *surf, struct gbm_bo *bo))
#undef SDL_KMSDRM_LEGACY_MODULE
#undef SDL_KMSDRM_LEGACY_SYM
#undef SDL_KMSDRM_LEGACY_SYM_CONST
/* *INDENT-ON* */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,926 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_KMSDRM
/* SDL internals */
#include "../SDL_sysvideo.h"
#include "SDL_syswm.h"
#include "SDL_log.h"
#include "SDL_hints.h"
#include "../../events/SDL_events_c.h"
#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_kmsdrm_legacy_video.h"
#include "SDL_kmsdrm_legacy_events.h"
#include "SDL_kmsdrm_legacy_opengles.h"
#include "SDL_kmsdrm_legacy_mouse.h"
#include "SDL_kmsdrm_legacy_dyn.h"
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <poll.h>
#define KMSDRM_LEGACY_DRI_PATH "/dev/dri/"
static int
check_modestting(int devindex)
{
SDL_bool available = SDL_FALSE;
char device[512];
int drm_fd;
SDL_snprintf(device, sizeof (device), "%scard%d", KMSDRM_LEGACY_DRI_PATH, devindex);
drm_fd = open(device, O_RDWR | O_CLOEXEC);
if (drm_fd >= 0) {
if (SDL_KMSDRM_LEGACY_LoadSymbols()) {
drmModeRes *resources = KMSDRM_LEGACY_drmModeGetResources(drm_fd);
if (resources) {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "%scard%d connector, encoder and CRTC counts are: %d %d %d",
KMSDRM_LEGACY_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) {
available = SDL_TRUE;
}
KMSDRM_LEGACY_drmModeFreeResources(resources);
}
SDL_KMSDRM_LEGACY_UnloadSymbols();
}
close(drm_fd);
}
return available;
}
static int get_dricount(void)
{
int devcount = 0;
struct dirent *res;
struct stat sb;
DIR *folder;
if (!(stat(KMSDRM_LEGACY_DRI_PATH, &sb) == 0
&& S_ISDIR(sb.st_mode))) {
printf("The path %s cannot be opened or is not available\n",
KMSDRM_LEGACY_DRI_PATH);
return 0;
}
if (access(KMSDRM_LEGACY_DRI_PATH, F_OK) == -1) {
printf("The path %s cannot be opened\n",
KMSDRM_LEGACY_DRI_PATH);
return 0;
}
folder = opendir(KMSDRM_LEGACY_DRI_PATH);
if (folder) {
while ((res = readdir(folder))) {
int len = SDL_strlen(res->d_name);
if (len > 4 && SDL_strncmp(res->d_name, "card", 4) == 0) {
devcount++;
}
}
closedir(folder);
}
return devcount;
}
static int
get_driindex(void)
{
const int devcount = get_dricount();
int i;
for (i = 0; i < devcount; i++) {
if (check_modestting(i)) {
return i;
}
}
return -ENOENT;
}
static int
KMSDRM_LEGACY_Available(void)
{
int ret = -ENOENT;
ret = get_driindex();
if (ret >= 0)
return 1;
return ret;
}
static void
KMSDRM_LEGACY_DeleteDevice(SDL_VideoDevice * device)
{
if (device->driverdata) {
SDL_free(device->driverdata);
device->driverdata = NULL;
}
SDL_free(device);
SDL_KMSDRM_LEGACY_UnloadSymbols();
}
static SDL_VideoDevice *
KMSDRM_LEGACY_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
SDL_VideoData *viddata;
if (!devindex || (devindex > 99)) {
devindex = get_driindex();
}
if (devindex < 0) {
SDL_SetError("devindex (%d) must be between 0 and 99.\n", devindex);
return NULL;
}
if (!SDL_KMSDRM_LEGACY_LoadSymbols()) {
return NULL;
}
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
if (!device) {
SDL_OutOfMemory();
return NULL;
}
viddata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
if (!viddata) {
SDL_OutOfMemory();
goto cleanup;
}
viddata->devindex = devindex;
viddata->drm_fd = -1;
device->driverdata = viddata;
/* Setup all functions which we can handle */
device->VideoInit = KMSDRM_LEGACY_VideoInit;
device->VideoQuit = KMSDRM_LEGACY_VideoQuit;
device->GetDisplayModes = KMSDRM_LEGACY_GetDisplayModes;
device->SetDisplayMode = KMSDRM_LEGACY_SetDisplayMode;
device->CreateSDLWindow = KMSDRM_LEGACY_CreateWindow;
device->CreateSDLWindowFrom = KMSDRM_LEGACY_CreateWindowFrom;
device->SetWindowTitle = KMSDRM_LEGACY_SetWindowTitle;
device->SetWindowIcon = KMSDRM_LEGACY_SetWindowIcon;
device->SetWindowPosition = KMSDRM_LEGACY_SetWindowPosition;
device->SetWindowSize = KMSDRM_LEGACY_SetWindowSize;
device->ShowWindow = KMSDRM_LEGACY_ShowWindow;
device->HideWindow = KMSDRM_LEGACY_HideWindow;
device->RaiseWindow = KMSDRM_LEGACY_RaiseWindow;
device->MaximizeWindow = KMSDRM_LEGACY_MaximizeWindow;
device->MinimizeWindow = KMSDRM_LEGACY_MinimizeWindow;
device->RestoreWindow = KMSDRM_LEGACY_RestoreWindow;
device->SetWindowGrab = KMSDRM_LEGACY_SetWindowGrab;
device->DestroyWindow = KMSDRM_LEGACY_DestroyWindow;
device->GetWindowWMInfo = KMSDRM_LEGACY_GetWindowWMInfo;
#if SDL_VIDEO_OPENGL_EGL
device->GL_LoadLibrary = KMSDRM_LEGACY_GLES_LoadLibrary;
device->GL_GetProcAddress = KMSDRM_LEGACY_GLES_GetProcAddress;
device->GL_UnloadLibrary = KMSDRM_LEGACY_GLES_UnloadLibrary;
device->GL_CreateContext = KMSDRM_LEGACY_GLES_CreateContext;
device->GL_MakeCurrent = KMSDRM_LEGACY_GLES_MakeCurrent;
device->GL_SetSwapInterval = KMSDRM_LEGACY_GLES_SetSwapInterval;
device->GL_GetSwapInterval = KMSDRM_LEGACY_GLES_GetSwapInterval;
device->GL_SwapWindow = KMSDRM_LEGACY_GLES_SwapWindow;
device->GL_DeleteContext = KMSDRM_LEGACY_GLES_DeleteContext;
#endif
device->PumpEvents = KMSDRM_LEGACY_PumpEvents;
device->free = KMSDRM_LEGACY_DeleteDevice;
return device;
cleanup:
if (device)
SDL_free(device);
if (viddata)
SDL_free(viddata);
return NULL;
}
VideoBootStrap KMSDRM_LEGACY_bootstrap = {
"KMSDRM_LEGACY",
"KMS/DRM Video Driver",
KMSDRM_LEGACY_Available,
KMSDRM_LEGACY_CreateDevice
};
static void
KMSDRM_LEGACY_FBDestroyCallback(struct gbm_bo *bo, void *data)
{
KMSDRM_LEGACY_FBInfo *fb_info = (KMSDRM_FBInfo *)data;
if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) {
KMSDRM_LEGACY_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
}
SDL_free(fb_info);
}
KMSDRM_LEGACY_FBInfo *
KMSDRM_LEGACY_FBFromBO(_THIS, struct gbm_bo *bo)
{
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
unsigned w,h;
int ret;
Uint32 stride, handle;
/* Check for an existing framebuffer */
KMSDRM_LEGACY_FBInfo *fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
if (fb_info) {
return fb_info;
}
/* Create a structure that contains enough info to remove the framebuffer
when the backing buffer is destroyed */
fb_info = (KMSDRM_LEGACY_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo));
if (!fb_info) {
SDL_OutOfMemory();
return NULL;
}
fb_info->drm_fd = viddata->drm_fd;
/* Create framebuffer object for the buffer */
w = KMSDRM_LEGACY_gbm_bo_get_width(bo);
h = KMSDRM_LEGACY_gbm_bo_get_height(bo);
stride = KMSDRM_LEGACY_gbm_bo_get_stride(bo);
handle = KMSDRM_LEGACY_gbm_bo_get_handle(bo).u32;
ret = KMSDRM_LEGACY_drmModeAddFB(viddata->drm_fd, w, h, 24, 32, stride, handle,
&fb_info->fb_id);
if (ret) {
SDL_free(fb_info);
return NULL;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "New DRM FB (%u): %ux%u, stride %u from BO %p",
fb_info->fb_id, w, h, stride, (void *)bo);
/* Associate our DRM framebuffer with this buffer object */
KMSDRM_LEGACY_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);
return fb_info;
}
static void
KMSDRM_LEGACY_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
{
*((SDL_bool *) data) = SDL_FALSE;
}
SDL_bool
KMSDRM_LEGACY_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
drmEventContext ev = {0};
struct pollfd pfd = {0};
ev.version = DRM_EVENT_CONTEXT_VERSION;
ev.page_flip_handler = KMSDRM_LEGACY_FlipHandler;
pfd.fd = viddata->drm_fd;
pfd.events = POLLIN;
while (windata->waiting_for_flip) {
pfd.revents = 0;
if (poll(&pfd, 1, timeout) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
return SDL_FALSE;
}
if (pfd.revents & (POLLHUP | POLLERR)) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
return SDL_FALSE;
}
if (pfd.revents & POLLIN) {
/* Page flip? If so, drmHandleEvent will unset windata->waiting_for_flip */
KMSDRM_LEGACY_drmHandleEvent(viddata->drm_fd, &ev);
} else {
/* Timed out and page flip didn't happen */
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
return SDL_FALSE;
}
}
return SDL_TRUE;
}
/*****************************************************************************/
/* SDL Video and Display initialization/handling functions */
/* _this is a SDL_VideoDevice * */
/*****************************************************************************/
static void
KMSDRM_LEGACY_DestroySurfaces(_THIS, SDL_Window * window)
{
SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
KMSDRM_LEGACY_WaitPageFlip(_this, windata, -1);
if (windata->curr_bo) {
KMSDRM_LEGACY_gbm_surface_release_buffer(windata->gs, windata->curr_bo);
windata->curr_bo = NULL;
}
if (windata->next_bo) {
KMSDRM_LEGACY_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_LEGACY_gbm_surface_destroy(windata->gs);
windata->gs = NULL;
}
}
int
KMSDRM_LEGACY_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;
Uint32 surface_fmt = GBM_FORMAT_XRGB8888;
Uint32 surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
EGLContext egl_context;
if (!KMSDRM_LEGACY_gbm_device_is_format_supported(viddata->gbm, surface_fmt, surface_flags)) {
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
}
#if SDL_VIDEO_OPENGL_EGL
SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
egl_context = (EGLContext)SDL_GL_GetCurrentContext();
#endif
KMSDRM_LEGACY_DestroySurfaces(_this, window);
windata->gs = KMSDRM_LEGACY_gbm_surface_create(viddata->gbm, width, height, surface_fmt, surface_flags);
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);
windata->egl_surface_dirty = 0;
#endif
return 0;
}
int
KMSDRM_LEGACY_VideoInit(_THIS)
{
int ret = 0;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
SDL_DisplayData *dispdata = NULL;
drmModeRes *resources = NULL;
drmModeEncoder *encoder = NULL;
char devname[32];
SDL_VideoDisplay display = {0};
dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
if (!dispdata) {
return SDL_OutOfMemory();
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_LEGACY_VideoInit()");
/* Open /dev/dri/cardNN */
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);
if (viddata->drm_fd < 0) {
ret = SDL_SetError("Could not open %s", devname);
goto cleanup;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd);
viddata->gbm = KMSDRM_LEGACY_gbm_create_device(viddata->drm_fd);
if (!viddata->gbm) {
ret = SDL_SetError("Couldn't create gbm device.");
goto cleanup;
}
/* Get all of the available connectors / devices / crtcs */
resources = KMSDRM_LEGACY_drmModeGetResources(viddata->drm_fd);
if (!resources) {
ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd);
goto cleanup;
}
for (int i = 0; i < resources->count_connectors; i++) {
drmModeConnector *conn = KMSDRM_LEGACY_drmModeGetConnector(viddata->drm_fd, resources->connectors[i]);
if (!conn) {
continue;
}
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
conn->connector_id, conn->count_modes);
dispdata->conn = conn;
break;
}
KMSDRM_LEGACY_drmModeFreeConnector(conn);
}
if (!dispdata->conn) {
ret = SDL_SetError("No currently active connector found.");
goto cleanup;
}
/* Try to find the connector's current encoder */
for (int i = 0; i < resources->count_encoders; i++) {
encoder = KMSDRM_LEGACY_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
if (!encoder) {
continue;
}
if (encoder->encoder_id == dispdata->conn->encoder_id) {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
break;
}
KMSDRM_LEGACY_drmModeFreeEncoder(encoder);
encoder = NULL;
}
if (!encoder) {
/* No encoder was connected, find the first supported one */
for (int i = 0, j; i < resources->count_encoders; i++) {
encoder = KMSDRM_LEGACY_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
if (!encoder) {
continue;
}
for (j = 0; j < dispdata->conn->count_encoders; j++) {
if (dispdata->conn->encoders[j] == encoder->encoder_id) {
break;
}
}
if (j != dispdata->conn->count_encoders) {
break;
}
KMSDRM_LEGACY_drmModeFreeEncoder(encoder);
encoder = NULL;
}
}
if (!encoder) {
ret = SDL_SetError("No connected encoder found.");
goto cleanup;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
/* Try to find a CRTC connected to this encoder */
dispdata->saved_crtc = KMSDRM_LEGACY_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
if (!dispdata->saved_crtc) {
/* No CRTC was connected, find the first CRTC that can be connected */
for (int i = 0; i < resources->count_crtcs; i++) {
if (encoder->possible_crtcs & (1 << i)) {
encoder->crtc_id = resources->crtcs[i];
dispdata->saved_crtc = KMSDRM_LEGACY_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
break;
}
}
}
if (!dispdata->saved_crtc) {
ret = SDL_SetError("No CRTC found.");
goto cleanup;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Saved crtc_id %u, fb_id %u, (%u,%u), %ux%u",
dispdata->saved_crtc->crtc_id, dispdata->saved_crtc->buffer_id, dispdata->saved_crtc->x,
dispdata->saved_crtc->y, dispdata->saved_crtc->width, dispdata->saved_crtc->height);
dispdata->crtc_id = encoder->crtc_id;
/* 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
FIXME find first mode that specifies DRM_MODE_TYPE_PREFERRED */
dispdata->mode = dispdata->saved_crtc->mode;
if (dispdata->saved_crtc->mode_valid == 0) {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO,
"Current mode is invalid, selecting connector's mode #0.");
dispdata->mode = dispdata->conn->modes[0];
}
/* Setup the single display that's available */
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 */
drmModeFB *fb = drmModeGetFB(viddata->drm_fd, dispdata->saved_crtc->buffer_id);
display.desktop_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
drmModeFreeFB(fb);
#endif
display.current_mode = display.desktop_mode;
display.driverdata = dispdata;
SDL_AddVideoDisplay(&display);
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Init();
#endif
KMSDRM_LEGACY_InitMouse(_this);
return ret;
cleanup:
if (encoder)
KMSDRM_LEGACY_drmModeFreeEncoder(encoder);
if (resources)
KMSDRM_LEGACY_drmModeFreeResources(resources);
if (ret != 0) {
/* Error (complete) cleanup */
if (dispdata->conn) {
KMSDRM_LEGACY_drmModeFreeConnector(dispdata->conn);
dispdata->conn = NULL;
}
if (dispdata->saved_crtc) {
KMSDRM_LEGACY_drmModeFreeCrtc(dispdata->saved_crtc);
dispdata->saved_crtc = NULL;
}
if (viddata->gbm) {
KMSDRM_LEGACY_gbm_device_destroy(viddata->gbm);
viddata->gbm = NULL;
}
if (viddata->drm_fd >= 0) {
close(viddata->drm_fd);
viddata->drm_fd = -1;
}
SDL_free(dispdata);
}
return ret;
}
void
KMSDRM_LEGACY_VideoQuit(_THIS)
{
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_LEGACY_VideoQuit()");
if (_this->gl_config.driver_loaded) {
SDL_GL_UnloadLibrary();
}
/* Clear out the window list */
SDL_free(viddata->windows);
viddata->windows = NULL;
viddata->max_windows = 0;
viddata->num_windows = 0;
/* Restore saved CRTC settings */
if (viddata->drm_fd >= 0 && dispdata && dispdata->conn && dispdata->saved_crtc) {
drmModeConnector *conn = dispdata->conn;
drmModeCrtc *crtc = dispdata->saved_crtc;
int ret = KMSDRM_LEGACY_drmModeSetCrtc(viddata->drm_fd, crtc->crtc_id, crtc->buffer_id,
crtc->x, crtc->y, &conn->connector_id, 1, &crtc->mode);
if (ret != 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original CRTC mode");
}
}
if (dispdata && dispdata->conn) {
KMSDRM_LEGACY_drmModeFreeConnector(dispdata->conn);
dispdata->conn = NULL;
}
if (dispdata && dispdata->saved_crtc) {
KMSDRM_LEGACY_drmModeFreeCrtc(dispdata->saved_crtc);
dispdata->saved_crtc = NULL;
}
if (viddata->gbm) {
KMSDRM_LEGACY_gbm_device_destroy(viddata->gbm);
viddata->gbm = NULL;
}
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;
}
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Quit();
#endif
}
void
KMSDRM_LEGACY_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
SDL_DisplayData *dispdata = display->driverdata;
drmModeConnector *conn = dispdata->conn;
SDL_DisplayMode mode;
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);
}
}
}
int
KMSDRM_LEGACY_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
SDL_DisplayData *dispdata = (SDL_DisplayData *)display->driverdata;
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
drmModeConnector *conn = dispdata->conn;
if (!modedata) {
return SDL_SetError("Mode doesn't have an associated index");
}
dispdata->mode = conn->modes[modedata->mode_index];
for (int i = 0; i < viddata->num_windows; i++) {
SDL_Window *window = viddata->windows[i];
SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
#if SDL_VIDEO_OPENGL_EGL
/* Can't recreate EGL surfaces right now, need to wait until SwapWindow
so the correct thread-local surface and context state are available */
windata->egl_surface_dirty = 1;
#else
if (KMSDRM_LEGACY_CreateSurfaces(_this, window)) {
return -1;
}
#endif
/* Tell app about the resize */
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode->w, mode->h);
}
return 0;
}
int
KMSDRM_LEGACY_CreateWindow(_THIS, SDL_Window * window)
{
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
SDL_WindowData *windata;
SDL_VideoDisplay *display;
#if SDL_VIDEO_OPENGL_EGL
if (!_this->egl_data) {
if (SDL_GL_LoadLibrary(NULL) < 0) {
goto error;
}
}
#endif
/* Allocate window internal data */
windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
if (!windata) {
SDL_OutOfMemory();
goto error;
}
/* Windows have one size for now */
display = SDL_GetDisplayForWindow(window);
window->w = display->desktop_mode.w;
window->h = display->desktop_mode.h;
/* Maybe you didn't ask for a fullscreen OpenGL window, but that's what you get */
window->flags |= (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
/* In case we want low-latency, double-buffer video, we take note here */
windata->double_buffer = SDL_FALSE;
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
windata->double_buffer = SDL_TRUE;
}
/* Setup driver data for this window */
window->driverdata = windata;
if (KMSDRM_LEGACY_CreateSurfaces(_this, window)) {
goto error;
}
/* 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 */
windata->viddata = viddata;
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;
if (!viddata->windows) {
SDL_OutOfMemory();
goto error;
}
}
viddata->windows[viddata->num_windows++] = window;
/* Focus on the newly created window */
SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window);
return 0;
error:
KMSDRM_LEGACY_DestroyWindow(_this, window);
return -1;
}
void
KMSDRM_LEGACY_DestroyWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
SDL_VideoData *viddata;
if (!windata) {
return;
}
/* Remove from the internal window list */
viddata = windata->viddata;
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;
}
}
KMSDRM_LEGACY_DestroySurfaces(_this, window);
window->driverdata = NULL;
SDL_free(windata);
}
int
KMSDRM_LEGACY_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
{
return -1;
}
void
KMSDRM_LEGACY_SetWindowTitle(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
{
}
void
KMSDRM_LEGACY_SetWindowPosition(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_SetWindowSize(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_ShowWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_HideWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_RaiseWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_MaximizeWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_MinimizeWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_RestoreWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_LEGACY_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
{
}
/*****************************************************************************/
/* SDL Window Manager function */
/*****************************************************************************/
SDL_bool
KMSDRM_LEGACY_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: */

View File

@ -0,0 +1,132 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.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.
*/
#include "../../SDL_internal.h"
#ifndef __SDL_KMSDRM_LEGACYVIDEO_H__
#define __SDL_KMSDRM_LEGACYVIDEO_H__
#include "../SDL_sysvideo.h"
#include <fcntl.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#if SDL_VIDEO_OPENGL_EGL
#include <EGL/egl.h>
#endif
typedef struct SDL_VideoData
{
int devindex; /* device index that was passed on creation */
int drm_fd; /* DRM file desc */
struct gbm_device *gbm;
SDL_Window **windows;
int max_windows;
int num_windows;
} SDL_VideoData;
typedef struct SDL_DisplayModeData
{
int mode_index;
} SDL_DisplayModeData;
typedef struct SDL_DisplayData
{
uint32_t crtc_id;
drmModeConnector *conn;
drmModeModeInfo mode;
drmModeCrtc *saved_crtc; /* CRTC to restore on quit */
} SDL_DisplayData;
typedef struct SDL_WindowData
{
SDL_VideoData *viddata;
struct gbm_surface *gs;
struct gbm_bo *curr_bo;
struct gbm_bo *next_bo;
struct gbm_bo *crtc_bo;
SDL_bool waiting_for_flip;
SDL_bool double_buffer;
#if SDL_VIDEO_OPENGL_EGL
int egl_surface_dirty;
EGLSurface egl_surface;
#endif
} SDL_WindowData;
typedef struct KMSDRM_LEGACY_FBInfo
{
int drm_fd; /* DRM file desc */
uint32_t fb_id; /* DRM framebuffer ID */
} KMSDRM_LEGACY_FBInfo;
/* Helper functions */
int KMSDRM_LEGACY_CreateSurfaces(_THIS, SDL_Window * window);
KMSDRM_LEGACY_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
SDL_bool KMSDRM_LEGACY_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout);
/****************************************************************************/
/* SDL_VideoDevice functions declaration */
/****************************************************************************/
/* Display and window functions */
int KMSDRM_LEGACY_VideoInit(_THIS);
void KMSDRM_LEGACY_VideoQuit(_THIS);
void KMSDRM_LEGACY_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
int KMSDRM_LEGACY_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
int KMSDRM_LEGACY_CreateWindow(_THIS, SDL_Window * window);
int KMSDRM_LEGACY_CreateWindowFrom(_THIS, SDL_Window * window, const void *data);
void KMSDRM_LEGACY_SetWindowTitle(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon);
void KMSDRM_LEGACY_SetWindowPosition(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_SetWindowSize(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_ShowWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_HideWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_RaiseWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_MaximizeWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_MinimizeWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_RestoreWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
void KMSDRM_LEGACY_DestroyWindow(_THIS, SDL_Window * window);
/* Window manager function */
SDL_bool KMSDRM_LEGACY_GetWindowWMInfo(_THIS, SDL_Window * window,
struct SDL_SysWMinfo *info);
/* OpenGL/OpenGL ES functions */
int KMSDRM_LEGACY_GLES_LoadLibrary(_THIS, const char *path);
void *KMSDRM_LEGACY_GLES_GetProcAddress(_THIS, const char *proc);
void KMSDRM_LEGACY_GLES_UnloadLibrary(_THIS);
SDL_GLContext KMSDRM_LEGACY_GLES_CreateContext(_THIS, SDL_Window * window);
int KMSDRM_LEGACY_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
int KMSDRM_LEGACY_GLES_SetSwapInterval(_THIS, int interval);
int KMSDRM_LEGACY_GLES_GetSwapInterval(_THIS);
int KMSDRM_LEGACY_GLES_SwapWindow(_THIS, SDL_Window * window);
void KMSDRM_LEGACY_GLES_DeleteContext(_THIS, SDL_GLContext context);
#endif /* __SDL_KMSDRM_LEGACYVIDEO_H__ */
/* vi: set ts=4 sw=4 expandtab: */