From f8839289b00df6fd4fc34a9955b62d257ff49e50 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 15 Dec 2020 12:22:48 -0800 Subject: [PATCH] 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. --- cmake/sdlchecks.cmake | 3 +- configure | 1 + configure.ac | 1 + src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 1 + .../kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.c | 167 ++++ .../kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.h | 53 + .../kmsdrm_legacy/SDL_kmsdrm_legacy_events.c | 42 + .../kmsdrm_legacy/SDL_kmsdrm_legacy_events.h | 31 + .../kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.c | 502 ++++++++++ .../kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.h | 45 + .../SDL_kmsdrm_legacy_opengles.c | 152 +++ .../SDL_kmsdrm_legacy_opengles.h | 48 + .../kmsdrm_legacy/SDL_kmsdrm_legacy_sym.h | 99 ++ .../kmsdrm_legacy/SDL_kmsdrm_legacy_video.c | 926 ++++++++++++++++++ .../kmsdrm_legacy/SDL_kmsdrm_legacy_video.h | 132 +++ 16 files changed, 2203 insertions(+), 1 deletion(-) create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.c create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.h create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.c create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.h create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.c create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.h create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.c create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.h create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_sym.h create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.c create mode 100644 src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.h diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index af5878380..43e345d94 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -1163,7 +1163,8 @@ macro(CheckKMSDRM) set(HAVE_SDL_VIDEO TRUE) 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}) diff --git a/configure b/configure index e2815f433..e83010918 100755 --- a/configure +++ b/configure @@ -22119,6 +22119,7 @@ fi $as_echo "#define SDL_VIDEO_DRIVER_KMSDRM 1" >>confdefs.h SOURCES="$SOURCES $srcdir/src/video/kmsdrm/*.c" + SOURCES="$SOURCES $srcdir/src/video/kmsdrm_legacy/*.c" EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBDRM_CFLAGS $LIBGBM_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kmsdrm dynamic loading support" >&5 diff --git a/configure.ac b/configure.ac index 11f0078a1..66c1e5549 100644 --- a/configure.ac +++ b/configure.ac @@ -2253,6 +2253,7 @@ AS_HELP_STRING([--enable-kmsdrm-shared], [dynamically load kmsdrm support [[defa AC_DEFINE(SDL_VIDEO_DRIVER_KMSDRM, 1, [ ]) SOURCES="$SOURCES $srcdir/src/video/kmsdrm/*.c" + SOURCES="$SOURCES $srcdir/src/video/kmsdrm_legacy/*.c" EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBDRM_CFLAGS $LIBGBM_CFLAGS" AC_MSG_CHECKING(for kmsdrm dynamic loading support) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 056703539..c8c425b6b 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -429,6 +429,7 @@ extern VideoBootStrap Android_bootstrap; extern VideoBootStrap PSP_bootstrap; extern VideoBootStrap RPI_bootstrap; extern VideoBootStrap KMSDRM_bootstrap; +extern VideoBootStrap KMSDRM_LEGACY_bootstrap; extern VideoBootStrap DUMMY_bootstrap; extern VideoBootStrap Wayland_bootstrap; extern VideoBootStrap NACL_bootstrap; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 4703ce3df..a0ca32243 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -96,6 +96,7 @@ static VideoBootStrap *bootstrap[] = { #endif #if SDL_VIDEO_DRIVER_KMSDRM &KMSDRM_bootstrap, + &KMSDRM_LEGACY_bootstrap, #endif #if SDL_VIDEO_DRIVER_RPI &RPI_bootstrap, diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.c b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.c new file mode 100644 index 000000000..26bdc2b13 --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.c @@ -0,0 +1,167 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.h b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.h new file mode 100644 index 000000000..6ff8a317b --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_dyn.h @@ -0,0 +1,53 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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 +#include +#include + +#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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.c b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.c new file mode 100644 index 000000000..a5c765edb --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.c @@ -0,0 +1,42 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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 */ + diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.h b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.h new file mode 100644 index 000000000..24c23bcb6 --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_events.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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_ */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.c b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.c new file mode 100644 index 000000000..0357b83de --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.c @@ -0,0 +1,502 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.h b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.h new file mode 100644 index 000000000..384196718 --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_mouse.h @@ -0,0 +1,45 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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 + +#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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.c b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.c new file mode 100644 index 000000000..890801891 --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.c @@ -0,0 +1,152 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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 " 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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.h b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.h new file mode 100644 index 000000000..5e5ba96dc --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_opengles.h @@ -0,0 +1,48 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_sym.h b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_sym.h new file mode 100644 index 000000000..8c41608fc --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_sym.h @@ -0,0 +1,99 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.c b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.c new file mode 100644 index 000000000..a1e7c571b --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.c @@ -0,0 +1,926 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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 +#include +#include +#include + +#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: */ diff --git a/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.h b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.h new file mode 100644 index 000000000..bb19fe5eb --- /dev/null +++ b/src/video/kmsdrm_legacy/SDL_kmsdrm_legacy_video.h @@ -0,0 +1,132 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + 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 +#include +#include +#include +#include +#if SDL_VIDEO_OPENGL_EGL +#include +#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: */