Fixed bug 3690 - SDL2 KMS/DRM render context support

Manuel

The attached patch adds support for KMS/DRM context graphics.

It builds with no problem on X86_64 GNU/Linux systems, provided the needed libraries are present, and on ARM GNU/Linux systems that have KMS/DRM support and a GLES2 implementation.
Tested on Raspberry Pi: KMS/DRM is what the Raspberry Pi will use as default in the near future, once the propietary DispmanX API by Broadcom is overtaken by open graphics stack, it's possible to boot current Raspbian system in KMS mode by adding "dtoverlay=vc4-kms-v3d" to config.txt on Raspbian's boot partition.
X86 systems use KMS right away in every current GNU/Linux system.

Simple build instructions:

$./autogen.sh
$./configure --enable-video-kmsdrm
$make
This commit is contained in:
Sam Lantinga 2017-08-02 10:22:48 -07:00
parent 2ffd6d0208
commit 56363ebf61
28 changed files with 2059 additions and 39 deletions

View File

@ -314,6 +314,8 @@ set_option(VIDEO_COCOA "Use Cocoa video driver" ${APPLE})
set_option(DIRECTX "Use DirectX for Windows audio/video" ${WINDOWS})
set_option(RENDER_D3D "Enable the Direct3D render driver" ${WINDOWS})
set_option(VIDEO_VIVANTE "Use Vivante EGL video driver" ${UNIX_SYS})
set_option(VIDEO_KMSDRM "Use KMS DRM video driver" ${UNIX_SYS})
dep_option(KMSDRM_SHARED "Dynamically load KMS DRM support" ON "VIDEO_KMSDRM" OFF)
# TODO: We should (should we?) respect cmake's ${BUILD_SHARED_LIBS} flag here
# The options below are for compatibility to configure's default behaviour.
@ -917,6 +919,7 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID)
CheckOpenGLESX11()
CheckWayland()
CheckVivante()
CheckKMSDRM()
endif()
if(LINUX)

View File

@ -1149,3 +1149,46 @@ macro(CheckRPI)
endif(SDL_VIDEO AND HAVE_VIDEO_RPI)
endif(VIDEO_RPI)
endmacro(CheckRPI)
# Requires:
# - EGL
# - PkgCheckModules
# Optional:
# - KMSDRM_SHARED opt
# - HAVE_DLOPEN opt
macro(CheckKMSDRM)
if(VIDEO_KMSDRM)
pkg_check_modules(KMSDRM libdrm gbm egl)
if(KMSDRM_FOUND)
link_directories(
${KMSDRM_LIBRARY_DIRS}
)
include_directories(
${KMSDRM_INCLUDE_DIRS}
)
set(HAVE_VIDEO_KMSDRM TRUE)
set(HAVE_SDL_VIDEO TRUE)
file(GLOB KMSDRM_SOURCES ${SDL2_SOURCE_DIR}/src/video/kmsdrm/*.c)
set(SOURCE_FILES ${SOURCE_FILES} ${KMSDRM_SOURCES})
list(APPEND EXTRA_CFLAGS ${KMSDRM_CLFLAGS})
set(SDL_VIDEO_DRIVER_KMSDRM 1)
if(KMSDRM_SHARED)
if(NOT HAVE_DLOPEN)
message_warn("You must have SDL_LoadObject() support for dynamic KMS/DRM loading")
else()
FindLibraryAndSONAME(drm)
FindLibraryAndSONAME(gbm)
set(SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC "\"${DRM_LIB_SONAME}\"")
set(SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM "\"${GBM_LIB_SONAME}\"")
set(HAVE_KMSDRM_SHARED TRUE)
endif()
else()
set(EXTRA_LIBS ${KMSDRM_LIBRARIES} ${EXTRA_LIBS})
endif()
endif()
endif()
endmacro()

View File

@ -2084,6 +2084,81 @@ AC_MSG_WARN("directfb $directfb_lib")
fi
}
dnl Find KMSDRM
CheckKMSDRM()
{
AC_ARG_ENABLE(video-kmsdrm,
AC_HELP_STRING([--enable-video-kmsdrm], [use KMSDRM video driver [[default=no]]]),
, enable_video_kmsdrm=no)
if test x$enable_video = xyes -a x$enable_video_kmsdrm = xyes; then
video_kmsdrm=no
libdrm_avail=no
libgbm_avail=no
LIBDRM_REQUIRED_VERSION=2.4.46
LIBGBM_REQUIRED_VERSION=9.0.0
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
if test x$PKG_CONFIG != xno; then
if $PKG_CONFIG --atleast-pkgconfig-version 0.7; then
if $PKG_CONFIG --atleast-version $LIBDRM_REQUIRED_VERSION libdrm; then
LIBDRM_CFLAGS=`$PKG_CONFIG --cflags libdrm`
LIBDRM_LIBS=`$PKG_CONFIG --libs libdrm`
LIBDRM_PREFIX=`$PKG_CONFIG --variable=prefix libdrm`
libdrm_avail=yes
fi
if $PKG_CONFIG --atleast-version $LIBGBM_REQUIRED_VERSION gbm; then
LIBGBM_CFLAGS=`$PKG_CONFIG --cflags gbm`
LIBGBM_LIBS=`$PKG_CONFIG --libs gbm`
LIBGBM_PREFIX=`$PKG_CONFIG --variable=prefix gbm`
libgbm_avail=yes
fi
if test x$libdrm_avail = xyes -a x$libgbm_avail = xyes; then
video_kmsdrm=yes
fi
AC_MSG_CHECKING(for libdrm $LIBDRM_REQUIRED_VERSION library for kmsdrm support)
AC_MSG_RESULT($libdrm_avail)
AC_MSG_CHECKING(for libgbm $LIBGBM_REQUIRED_VERSION library for kmsdrm support)
AC_MSG_RESULT($libgbm_avail)
if test x$video_kmsdrm = xyes; then
AC_ARG_ENABLE(kmsdrm-shared,
AC_HELP_STRING([--enable-kmsdrm-shared], [dynamically load kmsdrm support [[default=yes]]]),
, enable_kmsdrm_shared=yes)
AC_DEFINE(SDL_VIDEO_DRIVER_KMSDRM, 1, [ ])
SOURCES="$SOURCES $srcdir/src/video/kmsdrm/*.c"
EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBDRM_CFLAGS $LIBGBM_CFLAGS"
AC_MSG_CHECKING(for kmsdrm dynamic loading support)
kmsdrm_shared=no
drm_lib=[`find_lib "libdrm.so.*" "$DRM_LIBS"`]
gbm_lib=[`find_lib "libgbm.so.*" "$DRM_LIBS"`]
if test x$have_loadso != xyes && \
test x$enable_kmsdrm_shared = xyes; then
AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic kmsdrm loading])
fi
if test x$have_loadso = xyes && \
test x$enable_kmsdrm_shared = xyes && test x$drm_lib != x && test x$gbm_lib != x; then
kmsdrm_shared=yes
AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC, "$drm_lib", [ ])
AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM, "$gbm_lib", [ ])
AC_DEFINE_UNQUOTED(HAVE_KMSDRM_SHARED, "TRUE", [ ])
SUMMARY_video="${SUMMARY_video} kmsdrm(dynamic)"
else
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBDRM_LIBS $LIBGBM_LIBS"
SUMMARY_video="${SUMMARY_video} kmsdrm"
fi
AC_MSG_RESULT($kmsdrm_shared)
have_video=yes
fi
fi
fi
fi
}
dnl rcg04172001 Set up the Null video driver.
CheckDummyVideo()
{
@ -3148,6 +3223,7 @@ case "$host" in
CheckLibSampleRate
CheckX11
CheckDirectFB
CheckKMSDRM
CheckOpenGLX11
CheckOpenGLESX11
CheckMir

View File

@ -291,6 +291,10 @@
#cmakedefine SDL_VIDEO_DRIVER_VIVANTE @SDL_VIDEO_DRIVER_VIVANTE@
#cmakedefine SDL_VIDEO_DRIVER_VIVANTE_VDK @SDL_VIDEO_DRIVER_VIVANTE_VDK@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM @SDL_VIDEO_DRIVER_KMSDRM@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH @SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL@

View File

@ -294,6 +294,9 @@
#undef SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON
#undef SDL_VIDEO_DRIVER_X11
#undef SDL_VIDEO_DRIVER_RPI
#undef SDL_VIDEO_DRIVER_KMSDRM
#undef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
#undef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM
#undef SDL_VIDEO_DRIVER_ANDROID
#undef SDL_VIDEO_DRIVER_EMSCRIPTEN
#undef SDL_VIDEO_DRIVER_X11_DYNAMIC

View File

@ -30,6 +30,7 @@
#endif
#include "SDL_sysvideo.h"
#include "SDL_log.h"
#include "SDL_egl_c.h"
#include "SDL_loadso.h"
#include "SDL_hints.h"
@ -114,38 +115,82 @@ int SDL_EGL_SetErrorEx(const char * message, const char * eglFunctionName, EGLin
}
/* EGL implementation of SDL OpenGL ES support */
#ifdef EGL_KHR_create_context
static int SDL_EGL_HasExtension(_THIS, const char *ext)
typedef enum {
SDL_EGL_DISPLAY_EXTENSION,
SDL_EGL_CLIENT_EXTENSION
} SDL_EGL_ExtensionType;
static SDL_bool SDL_EGL_HasExtension(_THIS, SDL_EGL_ExtensionType type, const char *ext)
{
int i;
int len = 0;
size_t ext_len;
const char *exts;
const char *ext_word;
const char *ext_override;
const char *egl_extstr;
const char *ext_start;
/* Invalid extensions can be rejected early */
if (ext == NULL || *ext == 0 || SDL_strchr(ext, ' ') != NULL) {
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid EGL extension"); */
return SDL_FALSE;
}
/* Extensions can be masked with an environment variable.
* Unlike the OpenGL override, this will use the set bits of an integer
* to disable the extension.
* Bit Action
* 0 If set, the display extension is masked and not present to SDL.
* 1 If set, the client extension is masked and not present to SDL.
*/
ext_override = SDL_getenv(ext);
if (ext_override != NULL) {
int disable_ext = SDL_atoi(ext_override);
if (disable_ext & 0x01 && type == SDL_EGL_DISPLAY_EXTENSION) {
return SDL_FALSE;
} else if (disable_ext & 0x02 && type == SDL_EGL_CLIENT_EXTENSION) {
return SDL_FALSE;
}
}
ext_len = SDL_strlen(ext);
exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
switch (type) {
case SDL_EGL_DISPLAY_EXTENSION:
egl_extstr = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
break;
case SDL_EGL_CLIENT_EXTENSION:
/* EGL_EXT_client_extensions modifies eglQueryString to return client extensions
* if EGL_NO_DISPLAY is passed. Implementations without it are required to return NULL.
* This behavior is included in EGL 1.5.
*/
egl_extstr = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
break;
default:
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid extension type"); */
return SDL_FALSE;
}
if (exts) {
ext_word = exts;
if (egl_extstr != NULL) {
ext_start = egl_extstr;
for (i = 0; exts[i] != 0; i++) {
if (exts[i] == ' ') {
if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
return 1;
while (*ext_start) {
ext_start = SDL_strstr(ext_start, ext);
if (ext_start == NULL) {
return SDL_FALSE;
}
/* Check if the match is not just a substring of one of the extensions */
if (ext_start == egl_extstr || *(ext_start - 1) == ' ') {
if (ext_start[ext_len] == ' ' || ext_start[ext_len] == 0) {
return SDL_TRUE;
}
len = 0;
ext_word = &exts[i + 1];
} else {
len++;
}
/* If the search stopped in the middle of an extension, skip to the end of it */
ext_start += ext_len;
while (*ext_start != ' ' && *ext_start != 0) {
ext_start++;
}
}
}
return 0;
return SDL_FALSE;
}
#endif /* EGL_KHR_create_context */
void *
SDL_EGL_GetProcAddress(_THIS, const char *proc)
@ -196,10 +241,11 @@ SDL_EGL_UnloadLibrary(_THIS)
}
int
SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display)
SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
{
void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
const char *path = NULL;
int egl_version_major = 0, egl_version_minor = 0;
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
const char *d3dcompiler;
#endif
@ -305,9 +351,41 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
LOAD_FUNC(eglQueryString);
LOAD_FUNC(eglGetError);
if (_this->egl_data->eglQueryString) {
/* EGL 1.5 allows querying for client version */
const char *egl_version = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_VERSION);
if (egl_version != NULL) {
if (SDL_sscanf(egl_version, "%d.%d", &egl_version_major, &egl_version_minor) != 2) {
egl_version_major = 0;
egl_version_minor = 0;
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not parse EGL version string: %s", egl_version);
}
}
}
if (egl_version_major == 1 && egl_version_minor == 5) {
LOAD_FUNC(eglGetPlatformDisplay);
}
_this->egl_data->egl_display = EGL_NO_DISPLAY;
#if !defined(__WINRT__)
_this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
if (!_this->egl_data->egl_display) {
if (platform) {
if (egl_version_major == 1 && egl_version_minor == 5) {
_this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, native_display, NULL);
} else {
if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) {
_this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddress(_this, "eglGetPlatformDisplayEXT");
if (_this->egl_data->eglGetPlatformDisplayEXT) {
_this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(platform, native_display, NULL);
}
}
}
}
/* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
_this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
}
if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
return SDL_SetError("Could not get EGL display");
}
@ -328,11 +406,17 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
int
SDL_EGL_ChooseConfig(_THIS)
{
/* 64 seems nice. */
/* 64 seems nice. */
EGLint attribs[64];
EGLint found_configs = 0, value;
#ifdef SDL_VIDEO_DRIVER_KMSDRM
/* Intel EGL on KMS/DRM (al least) returns invalid configs that confuse the bitdiff search used */
/* later in this function, so we simply use the first one when using the KMSDRM driver for now. */
EGLConfig configs[1];
#else
/* 128 seems even nicer here */
EGLConfig configs[128];
#endif
int i, j, best_bitdiff = -1, bitdiff;
if (!_this->egl_data) {
@ -379,7 +463,7 @@ SDL_EGL_ChooseConfig(_THIS)
if (_this->gl_config.framebuffer_srgb_capable) {
#ifdef EGL_KHR_gl_colorspace
if (SDL_EGL_HasExtension(_this, "EGL_KHR_gl_colorspace")) {
if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace")) {
attribs[i++] = EGL_GL_COLORSPACE_KHR;
attribs[i++] = EGL_GL_COLORSPACE_SRGB_KHR;
} else
@ -393,7 +477,7 @@ SDL_EGL_ChooseConfig(_THIS)
if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
#ifdef EGL_KHR_create_context
if (_this->gl_config.major_version >= 3 &&
SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
} else
#endif
@ -495,7 +579,7 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
/* The Major/minor version, context profiles, and context flags can
* only be specified when this extension is available.
*/
if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
attribs[attr++] = major_version;
attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;

View File

@ -37,6 +37,12 @@ typedef struct SDL_EGL_VideoData
int egl_swapinterval;
EGLDisplay(EGLAPIENTRY *eglGetDisplay) (NativeDisplayType display);
EGLDisplay(EGLAPIENTRY *eglGetPlatformDisplay) (EGLenum platform,
void *native_display,
const EGLint *attrib_list);
EGLDisplay(EGLAPIENTRY *eglGetPlatformDisplayEXT) (EGLenum platform,
void *native_display,
const EGLint *attrib_list);
EGLBoolean(EGLAPIENTRY *eglInitialize) (EGLDisplay dpy, EGLint * major,
EGLint * minor);
EGLBoolean(EGLAPIENTRY *eglTerminate) (EGLDisplay dpy);
@ -85,7 +91,10 @@ typedef struct SDL_EGL_VideoData
/* OpenGLES functions */
extern int SDL_EGL_GetAttribute(_THIS, SDL_GLattr attrib, int *value);
extern int SDL_EGL_LoadLibrary(_THIS, const char *path, NativeDisplayType native_display);
/* SDL_EGL_LoadLibrary can get a display for a specific platform (EGL_PLATFORM_*)
* or, if 0 is passed, let the implementation decide.
*/
extern int SDL_EGL_LoadLibrary(_THIS, const char *path, NativeDisplayType native_display, EGLenum platform);
extern void *SDL_EGL_GetProcAddress(_THIS, const char *proc);
extern void SDL_EGL_UnloadLibrary(_THIS);
extern int SDL_EGL_ChooseConfig(_THIS);

View File

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

View File

@ -105,6 +105,9 @@ static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_RPI
&RPI_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_KMSDRM
&KMSDRM_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_NACL
&NACL_bootstrap,
#endif
@ -2892,7 +2895,7 @@ SDL_GL_ExtensionSupported(const char *extension)
break;
terminator = where + SDL_strlen(extension);
if (where == start || *(where - 1) == ' ')
if (where == extensions || *(where - 1) == ' ')
if (*terminator == ' ' || *terminator == '\0')
return SDL_TRUE;

View File

@ -54,7 +54,7 @@ Android_GLES_SwapWindow(_THIS, SDL_Window * window)
int
Android_GLES_LoadLibrary(_THIS, const char *path) {
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) 0);
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) 0, 0);
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,170 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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 0
#include "SDL_kmsdrmdyn.h"
#if DEBUG_DYNAMIC_KMSDRM
#include "SDL_log.h"
#endif
#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},
{NULL, SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM}
};
static void *
KMSDRM_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
if (fn != NULL)
SDL_Log("KMSDRM: Found '%s' in %s (%p)\n", fnname, kmsdrmlibs[i].libname, fn);
else
SDL_Log("KMSDRM: 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_MODULE(modname) int SDL_KMSDRM_HAVE_##modname = 0;
#define SDL_KMSDRM_SYM(rc,fn,params) SDL_DYNKMSDRMFN_##fn KMSDRM_##fn = NULL;
#define SDL_KMSDRM_SYM_CONST(type,name) SDL_DYNKMSDRMCONST_##name KMSDRM_##name = NULL;
#include "SDL_kmsdrmsym.h"
static int kmsdrm_load_refcount = 0;
void
SDL_KMSDRM_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_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 0;
#define SDL_KMSDRM_SYM(rc,fn,params) KMSDRM_##fn = NULL;
#define SDL_KMSDRM_SYM_CONST(type,name) KMSDRM_##name = NULL;
#include "SDL_kmsdrmsym.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_LoadSymbols(void)
{
int rc = 1; /* always succeed if not using Dynamic KMSDRM 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_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 1; /* default yes */
#include "SDL_kmsdrmsym.h"
#define SDL_KMSDRM_MODULE(modname) thismod = &SDL_KMSDRM_HAVE_##modname;
#define SDL_KMSDRM_SYM(rc,fn,params) KMSDRM_##fn = (SDL_DYNKMSDRMFN_##fn) KMSDRM_GetSym(#fn,thismod);
#define SDL_KMSDRM_SYM_CONST(type,name) KMSDRM_##name = *(SDL_DYNKMSDRMCONST_##name*) KMSDRM_GetSym(#name,thismod);
#include "SDL_kmsdrmsym.h"
if ((SDL_KMSDRM_HAVE_LIBDRM) && (SDL_KMSDRM_HAVE_GBM)) {
/* all required symbols loaded. */
SDL_ClearError();
} else {
/* in case something got loaded... */
SDL_KMSDRM_UnloadSymbols();
rc = 0;
}
#else /* no dynamic KMSDRM */
#define SDL_KMSDRM_MODULE(modname) SDL_KMSDRM_HAVE_##modname = 1; /* default yes */
#define SDL_KMSDRM_SYM(rc,fn,params) KMSDRM_##fn = fn;
#define SDL_KMSDRM_SYM_CONST(type,name) KMSDRM_##name = name;
#include "SDL_kmsdrmsym.h"
#endif
}
return rc;
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,54 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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>
#include <EGL/egl.h>
#ifdef __cplusplus
extern "C" {
#endif
int SDL_KMSDRM_LoadSymbols(void);
void SDL_KMSDRM_UnloadSymbols(void);
/* Declare all the function pointers and wrappers... */
#define SDL_KMSDRM_SYM(rc,fn,params) \
typedef rc (*SDL_DYNKMSDRMFN_##fn) params; \
extern SDL_DYNKMSDRMFN_##fn KMSDRM_##fn;
#define SDL_KMSDRM_SYM_CONST(type, name) \
typedef type SDL_DYNKMSDRMCONST_##name; \
extern SDL_DYNKMSDRMCONST_##name KMSDRM_##name;
#include "SDL_kmsdrmsym.h"
#ifdef __cplusplus
}
#endif
#endif /* !defined _SDL_kmsdrmdyn_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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 "../../events/SDL_sysevents.h"
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_keyboard_c.h"
#include "SDL_kmsdrmvideo.h"
#include "SDL_kmsdrmevents_c.h"
#ifdef SDL_INPUT_LINUXEV
#include "../../core/linux/SDL_evdev.h"
#endif
void KMSDRM_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-2016 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_kmsdrmevents_c_h
#define _SDL_kmsdrmevents_c_h
#include "SDL_kmsdrmvideo.h"
void KMSDRM_PumpEvents(_THIS);
void KMSDRM_EventInit(_THIS);
void KMSDRM_EventQuit(_THIS);
#endif /* _SDL_kmsdrmevents_c_h */

View File

@ -0,0 +1,426 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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_assert.h"
#include "SDL_surface.h"
#include "SDL_kmsdrmvideo.h"
#include "SDL_kmsdrmmouse.h"
#include "SDL_kmsdrmdyn.h"
#include "../SDL_sysvideo.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/default_cursor.h"
static SDL_Cursor *KMSDRM_CreateDefaultCursor(void);
static SDL_Cursor *KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
static int KMSDRM_ShowCursor(SDL_Cursor * cursor);
static void KMSDRM_MoveCursor(SDL_Cursor * cursor);
static void KMSDRM_FreeCursor(SDL_Cursor * cursor);
static void KMSDRM_WarpMouse(SDL_Window * window, int x, int y);
static int KMSDRM_WarpMouseGlobal(int x, int y);
static SDL_Cursor *
KMSDRM_CreateDefaultCursor(void)
{
return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
}
/* Create a cursor from a surface */
static SDL_Cursor *
KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
{
SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *vdata = ((SDL_VideoData *)dev->driverdata);
SDL_PixelFormat *pixlfmt = surface->format;
KMSDRM_CursorData *curdata;
SDL_Cursor *cursor;
int i, ret;
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_gbm_device_is_format_supported(vdata->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 == NULL) {
SDL_OutOfMemory();
return NULL;
}
curdata = (KMSDRM_CursorData *) SDL_calloc(1, sizeof(*curdata));
if (curdata == NULL) {
SDL_OutOfMemory();
SDL_free(cursor);
return NULL;
}
curdata->hot_x = hot_x;
curdata->hot_y = hot_y;
curdata->w = surface->w;
curdata->h = surface->h;
curdata->bo = KMSDRM_gbm_bo_create(vdata->gbm, surface->w, surface->h, bo_format,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (curdata->bo == NULL) {
SDL_SetError("Could not create GBM cursor BO");
goto cleanup;
}
bo_stride = KMSDRM_gbm_bo_get_stride(curdata->bo);
bufsize = bo_stride * surface->h;
if (surface->pitch != bo_stride) {
/* pitch doesn't match stride, must be copied to temp buffer */
buffer = SDL_malloc(bufsize);
if (buffer == NULL) {
SDL_OutOfMemory();
goto cleanup;
}
if (SDL_MUSTLOCK(surface)) {
if (SDL_LockSurface(surface) < 0) {
/* Could not lock surface */
goto cleanup;
}
}
/* 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_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_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 != NULL) {
SDL_free(buffer);
}
if (cursor != NULL) {
SDL_free(cursor);
}
if (curdata != NULL) {
if (curdata->bo != NULL) {
KMSDRM_gbm_bo_destroy(curdata->bo);
}
SDL_free(curdata);
}
return NULL;
}
/* Show the specified cursor, or hide if cursor is NULL */
static int
KMSDRM_ShowCursor(SDL_Cursor * cursor)
{
SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *vdata = ((SDL_VideoData *)dev->driverdata);
SDL_Mouse *mouse;
KMSDRM_CursorData *curdata;
SDL_VideoDisplay *display = NULL;
SDL_DisplayData *ddata = NULL;
int ret;
uint32_t bo_handle;
mouse = SDL_GetMouse();
if (mouse == NULL) {
return SDL_SetError("No mouse.");
}
if (mouse->focus != NULL) {
display = SDL_GetDisplayForWindow(mouse->focus);
if (display != NULL) {
ddata = (SDL_DisplayData*) display->driverdata;
}
}
if (cursor == NULL) {
/* Hide current cursor */
if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
if (curdata->crtc_id != 0) {
ret = KMSDRM_drmModeSetCursor(vdata->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 (ddata != NULL && ddata->crtc_id != 0) {
ret = KMSDRM_drmModeSetCursor(vdata->drm_fd, ddata->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 == NULL) {
return SDL_SetError("Could not get display for mouse.");
}
if (ddata == NULL) {
return SDL_SetError("Could not get display driverdata.");
}
curdata = (KMSDRM_CursorData *) cursor->driverdata;
if (curdata == NULL || curdata->bo == NULL) {
return SDL_SetError("Cursor not initialized properly.");
}
bo_handle = KMSDRM_gbm_bo_get_handle(curdata->bo).u32;
if (curdata->hot_x == 0 && curdata->hot_y == 0) {
ret = KMSDRM_drmModeSetCursor(vdata->drm_fd, ddata->crtc_id, bo_handle,
curdata->w, curdata->h);
} else {
ret = KMSDRM_drmModeSetCursor2(vdata->drm_fd, ddata->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 = ddata->crtc_id;
return 0;
}
/* Free a window manager cursor */
static void
KMSDRM_FreeCursor(SDL_Cursor * cursor)
{
KMSDRM_CursorData *curdata;
int drm_fd;
if (cursor != NULL) {
curdata = (KMSDRM_CursorData *) cursor->driverdata;
if (curdata != NULL) {
if (curdata->bo != NULL) {
if (curdata->crtc_id != 0) {
drm_fd = KMSDRM_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(curdata->bo));
/* Hide the cursor if previously shown on a CRTC */
KMSDRM_drmModeSetCursor(drm_fd, curdata->crtc_id, 0, 0, 0);
curdata->crtc_id = 0;
}
KMSDRM_gbm_bo_destroy(curdata->bo);
curdata->bo = NULL;
}
SDL_free(cursor->driverdata);
}
SDL_free(cursor);
}
}
/* Warp the mouse to (x,y) */
static void
KMSDRM_WarpMouse(SDL_Window * window, int x, int y)
{
/* Only one global/fullscreen window is supported */
KMSDRM_WarpMouseGlobal(x, y);
}
/* Warp the mouse to (x,y) */
static int
KMSDRM_WarpMouseGlobal(int x, int y)
{
KMSDRM_CursorData *curdata;
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
if (curdata->bo != NULL) {
if (curdata->crtc_id != 0) {
int ret, drm_fd;
drm_fd = KMSDRM_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(curdata->bo));
ret = KMSDRM_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_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_CreateCursor;
mouse->ShowCursor = KMSDRM_ShowCursor;
mouse->MoveCursor = KMSDRM_MoveCursor;
mouse->FreeCursor = KMSDRM_FreeCursor;
mouse->WarpMouse = KMSDRM_WarpMouse;
mouse->WarpMouseGlobal = KMSDRM_WarpMouseGlobal;
SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor());
}
void
KMSDRM_QuitMouse(_THIS)
{
/* TODO: ? */
}
/* This is called when a mouse motion event occurs */
static void
KMSDRM_MoveCursor(SDL_Cursor * cursor)
{
SDL_Mouse *mouse = SDL_GetMouse();
KMSDRM_WarpMouse(mouse->focus, mouse->x, mouse->y);
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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_KMSDRM_mouse_h
#define _SDL_KMSDRM_mouse_h
#include <gbm.h>
#include "../SDL_sysvideo.h"
typedef struct _KMSDRM_CursorData
{
struct gbm_bo *bo;
uint32_t crtc_id;
int hot_x, hot_y;
int w, h;
} KMSDRM_CursorData;
extern void KMSDRM_InitMouse(_THIS);
extern void KMSDRM_QuitMouse(_THIS);
#endif /* _SDL_KMSDRM_mouse_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,126 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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_kmsdrmvideo.h"
#include "SDL_kmsdrmopengles.h"
#include "SDL_kmsdrmdyn.h"
#ifndef EGL_PLATFORM_GBM_MESA
#define EGL_PLATFORM_GBM_MESA 0x31D7
#endif
/* EGL implementation of SDL OpenGL support */
int
KMSDRM_GLES_LoadLibrary(_THIS, const char *path) {
return SDL_EGL_LoadLibrary(_this, path, ((SDL_VideoData *)_this->driverdata)->gbm, EGL_PLATFORM_GBM_MESA);
}
SDL_EGL_CreateContext_impl(KMSDRM)
int KMSDRM_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_GLES_SwapWindow(_THIS, SDL_Window * window) {
SDL_WindowData *wdata = ((SDL_WindowData *) window->driverdata);
SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
KMSDRM_FBInfo *fb_info;
int ret;
/* Do we still need to wait for a flip? */
int timeout = 0;
if (_this->egl_data->egl_swapinterval == 1) {
timeout = -1;
}
if (!KMSDRM_WaitPageFlip(_this, wdata, timeout)) {
return 0;
}
/* Release previously displayed buffer (which is now the backbuffer) and lock a new one */
if (wdata->locked_bo != NULL) {
KMSDRM_gbm_surface_release_buffer(wdata->gs, wdata->locked_bo);
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Released GBM surface %p", (void *)wdata->locked_bo); */
wdata->locked_bo = NULL;
}
if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, wdata->egl_surface))) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed.");
return 0;
}
wdata->locked_bo = KMSDRM_gbm_surface_lock_front_buffer(wdata->gs);
if (wdata->locked_bo == NULL) {
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 *)wdata->locked_bo); */
}
fb_info = KMSDRM_FBFromBO(_this, wdata->locked_bo);
if (_this->egl_data->egl_swapinterval == 0) {
/* Swap buffers instantly, possible tearing */
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "drmModeSetCrtc(%d, %u, %u, 0, 0, &%u, 1, &%ux%u@%u)",
vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id, vdata->saved_conn_id,
displaydata->cur_mode.hdisplay, displaydata->cur_mode.vdisplay, displaydata->cur_mode.vrefresh); */
ret = KMSDRM_drmModeSetCrtc(vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id,
0, 0, &vdata->saved_conn_id, 1, &displaydata->cur_mode);
if(ret != 0) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not pageflip with drmModeSetCrtc: %d", ret);
}
} else {
/* Queue page flip at vsync */
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "drmModePageFlip(%d, %u, %u, DRM_MODE_PAGE_FLIP_EVENT, &wdata->waiting_for_flip)",
vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id); */
ret = KMSDRM_drmModePageFlip(vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, &wdata->waiting_for_flip);
if (ret == 0) {
wdata->waiting_for_flip = SDL_TRUE;
} else {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
}
}
return 0;
}
SDL_EGL_MakeCurrent_impl(KMSDRM)
#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-2016 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_GLES_GetAttribute SDL_EGL_GetAttribute
#define KMSDRM_GLES_GetProcAddress SDL_EGL_GetProcAddress
#define KMSDRM_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define KMSDRM_GLES_DeleteContext SDL_EGL_DeleteContext
#define KMSDRM_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
extern int KMSDRM_GLES_SetSwapInterval(_THIS, int interval);
extern int KMSDRM_GLES_LoadLibrary(_THIS, const char *path);
extern SDL_GLContext KMSDRM_GLES_CreateContext(_THIS, SDL_Window * window);
extern int KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window);
extern int KMSDRM_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-2016 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_MODULE
#define SDL_KMSDRM_MODULE(modname)
#endif
#ifndef SDL_KMSDRM_SYM
#define SDL_KMSDRM_SYM(rc,fn,params)
#endif
#ifndef SDL_KMSDRM_SYM_CONST
#define SDL_KMSDRM_SYM_CONST(type, name)
#endif
SDL_KMSDRM_MODULE(LIBDRM)
SDL_KMSDRM_SYM(void,drmModeFreeResources,(drmModeResPtr ptr))
SDL_KMSDRM_SYM(void,drmModeFreeFB,(drmModeFBPtr ptr))
SDL_KMSDRM_SYM(void,drmModeFreeCrtc,(drmModeCrtcPtr ptr))
SDL_KMSDRM_SYM(void,drmModeFreeConnector,(drmModeConnectorPtr ptr))
SDL_KMSDRM_SYM(void,drmModeFreeEncoder,(drmModeEncoderPtr ptr))
SDL_KMSDRM_SYM(drmModeResPtr,drmModeGetResources,(int fd))
SDL_KMSDRM_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_SYM(int,drmModeRmFB,(int fd, uint32_t bufferId))
SDL_KMSDRM_SYM(drmModeFBPtr,drmModeGetFB,(int fd, uint32_t buf))
SDL_KMSDRM_SYM(drmModeCrtcPtr,drmModeGetCrtc,(int fd, uint32_t crtcId))
SDL_KMSDRM_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_SYM(int,drmModeSetCursor,(int fd, uint32_t crtcId, uint32_t bo_handle,
uint32_t width, uint32_t height))
SDL_KMSDRM_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_SYM(int,drmModeMoveCursor,(int fd, uint32_t crtcId, int x, int y))
SDL_KMSDRM_SYM(drmModeEncoderPtr,drmModeGetEncoder,(int fd, uint32_t encoder_id))
SDL_KMSDRM_SYM(drmModeConnectorPtr,drmModeGetConnector,(int fd, uint32_t connector_id))
SDL_KMSDRM_SYM(int,drmHandleEvent,(int fd,drmEventContextPtr evctx))
SDL_KMSDRM_SYM(int,drmModePageFlip,(int fd, uint32_t crtc_id, uint32_t fb_id,
uint32_t flags, void *user_data))
SDL_KMSDRM_MODULE(GBM)
SDL_KMSDRM_SYM(int,gbm_device_get_fd,(struct gbm_device *gbm))
SDL_KMSDRM_SYM(int,gbm_device_is_format_supported,(struct gbm_device *gbm,
uint32_t format, uint32_t usage))
SDL_KMSDRM_SYM(void,gbm_device_destroy,(struct gbm_device *gbm))
SDL_KMSDRM_SYM(struct gbm_device *,gbm_create_device,(int fd))
SDL_KMSDRM_SYM(unsigned int,gbm_bo_get_width,(struct gbm_bo *bo))
SDL_KMSDRM_SYM(unsigned int,gbm_bo_get_height,(struct gbm_bo *bo))
SDL_KMSDRM_SYM(uint32_t,gbm_bo_get_stride,(struct gbm_bo *bo))
SDL_KMSDRM_SYM(union gbm_bo_handle,gbm_bo_get_handle,(struct gbm_bo *bo))
SDL_KMSDRM_SYM(int,gbm_bo_write,(struct gbm_bo *bo, const void *buf, size_t count))
SDL_KMSDRM_SYM(struct gbm_device *,gbm_bo_get_device,(struct gbm_bo *bo))
SDL_KMSDRM_SYM(void,gbm_bo_set_user_data,(struct gbm_bo *bo, void *data,
void (*destroy_user_data)(struct gbm_bo *, void *)))
SDL_KMSDRM_SYM(void *,gbm_bo_get_user_data,(struct gbm_bo *bo))
SDL_KMSDRM_SYM(void,gbm_bo_destroy,(struct gbm_bo *bo))
SDL_KMSDRM_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_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_SYM(void,gbm_surface_destroy,(struct gbm_surface *surf))
SDL_KMSDRM_SYM(struct gbm_bo *,gbm_surface_lock_front_buffer,(struct gbm_surface *surf))
SDL_KMSDRM_SYM(void,gbm_surface_release_buffer,(struct gbm_surface *surf, struct gbm_bo *bo))
#undef SDL_KMSDRM_MODULE
#undef SDL_KMSDRM_SYM
#undef SDL_KMSDRM_SYM_CONST
/* *INDENT-ON* */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,634 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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_version.h"
#include "SDL_syswm.h"
#include "SDL_loadso.h"
#include "SDL_events.h"
#include "SDL_log.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_kmsdrmvideo.h"
#include "SDL_kmsdrmevents_c.h"
#include "SDL_kmsdrmopengles.h"
#include "SDL_kmsdrmmouse.h"
#include "SDL_kmsdrmdyn.h"
#define KMSDRM_DRI_CARD_0 "/dev/dri/card0"
static int
KMSDRM_Available(void)
{
int available = 0;
int drm_fd = open(KMSDRM_DRI_CARD_0, O_RDWR | O_CLOEXEC);
if (drm_fd >= 0) {
if (SDL_KMSDRM_LoadSymbols()) {
drmModeRes *resources = KMSDRM_drmModeGetResources(drm_fd);
if (resources != NULL) {
available = 1;
KMSDRM_drmModeFreeResources(resources);
}
SDL_KMSDRM_UnloadSymbols();
}
close(drm_fd);
}
return available;
}
static void
KMSDRM_Destroy(SDL_VideoDevice * device)
{
if (device->driverdata != NULL) {
SDL_free(device->driverdata);
device->driverdata = NULL;
}
SDL_KMSDRM_UnloadSymbols();
}
static SDL_VideoDevice *
KMSDRM_Create(int devindex)
{
SDL_VideoDevice *device;
SDL_VideoData *vdata;
if (devindex < 0 || devindex > 99) {
SDL_SetError("devindex (%d) must be between 0 and 99.\n", devindex);
return NULL;
}
if (!SDL_KMSDRM_LoadSymbols()) {
return NULL;
}
/* Initialize SDL_VideoDevice structure */
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device == NULL) {
SDL_OutOfMemory();
goto cleanup;
}
/* Initialize internal data */
vdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
if (vdata == NULL) {
SDL_OutOfMemory();
goto cleanup;
}
vdata->devindex = devindex;
vdata->drm_fd = -1;
device->driverdata = vdata;
/* Setup amount of available displays and current display */
device->num_displays = 0;
/* Set device free function */
device->free = KMSDRM_Destroy;
/* Setup all functions which we can handle */
device->VideoInit = KMSDRM_VideoInit;
device->VideoQuit = KMSDRM_VideoQuit;
device->GetDisplayModes = KMSDRM_GetDisplayModes;
device->SetDisplayMode = KMSDRM_SetDisplayMode;
device->CreateWindow = KMSDRM_CreateWindow;
device->CreateWindowFrom = KMSDRM_CreateWindowFrom;
device->SetWindowTitle = KMSDRM_SetWindowTitle;
device->SetWindowIcon = KMSDRM_SetWindowIcon;
device->SetWindowPosition = KMSDRM_SetWindowPosition;
device->SetWindowSize = KMSDRM_SetWindowSize;
device->ShowWindow = KMSDRM_ShowWindow;
device->HideWindow = KMSDRM_HideWindow;
device->RaiseWindow = KMSDRM_RaiseWindow;
device->MaximizeWindow = KMSDRM_MaximizeWindow;
device->MinimizeWindow = KMSDRM_MinimizeWindow;
device->RestoreWindow = KMSDRM_RestoreWindow;
device->SetWindowGrab = KMSDRM_SetWindowGrab;
device->DestroyWindow = KMSDRM_DestroyWindow;
device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo;
device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary;
device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress;
device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary;
device->GL_CreateContext = KMSDRM_GLES_CreateContext;
device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent;
device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval;
device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval;
device->GL_SwapWindow = KMSDRM_GLES_SwapWindow;
device->GL_DeleteContext = KMSDRM_GLES_DeleteContext;
device->PumpEvents = KMSDRM_PumpEvents;
return device;
cleanup:
if (device != NULL)
SDL_free(device);
if (vdata != NULL)
SDL_free(vdata);
return NULL;
}
VideoBootStrap KMSDRM_bootstrap = {
"KMSDRM",
"KMS/DRM Video Driver",
KMSDRM_Available,
KMSDRM_Create
};
static void
KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data)
{
KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data;
if (fb_info && fb_info->drm_fd > 0 && fb_info->fb_id != 0) {
KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
}
free(fb_info);
}
KMSDRM_FBInfo *
KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
{
uint32_t w, h, stride, handle;
int ret;
SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
KMSDRM_FBInfo *fb_info;
fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
if (fb_info != NULL) {
/* Have a previously used framebuffer, return it */
return fb_info;
}
/* Here a new DRM FB must be created */
fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo));
fb_info->drm_fd = vdata->drm_fd;
w = KMSDRM_gbm_bo_get_width(bo);
h = KMSDRM_gbm_bo_get_height(bo);
stride = KMSDRM_gbm_bo_get_stride(bo);
handle = KMSDRM_gbm_bo_get_handle(bo).u32;
ret = KMSDRM_drmModeAddFB(vdata->drm_fd, w, h, 24, 32, stride, handle, &fb_info->fb_id);
if (ret < 0) {
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_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);
return fb_info;
}
SDL_bool
KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *wdata, int timeout) {
SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
while (wdata->waiting_for_flip) {
vdata->drm_pollfd.revents = 0;
if (poll(&vdata->drm_pollfd, 1, timeout) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
return SDL_FALSE;
}
if (vdata->drm_pollfd.revents & (POLLHUP | POLLERR)) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
return SDL_FALSE;
}
if (vdata->drm_pollfd.revents & POLLIN) {
/* Page flip? If so, drmHandleEvent will unset wdata->waiting_for_flip */
KMSDRM_drmHandleEvent(vdata->drm_fd, &vdata->drm_evctx);
} 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;
}
static void
KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
{
*((SDL_bool *) data) = SDL_FALSE;
}
/*****************************************************************************/
/* SDL Video and Display initialization/handling functions */
/* _this is a SDL_VideoDevice * */
/*****************************************************************************/
int
KMSDRM_VideoInit(_THIS)
{
int i;
int ret = 0;
char *devname;
SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
drmModeRes *resources = NULL;
drmModeConnector *connector = NULL;
drmModeEncoder *encoder = NULL;
SDL_DisplayMode current_mode;
SDL_VideoDisplay display;
/* Allocate display internal data */
SDL_DisplayData *data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
if (data == NULL) {
return SDL_OutOfMemory();
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()");
/* Open /dev/dri/cardNN */
devname = (char *) SDL_calloc(1, 16);
SDL_snprintf(devname, 16, "/dev/dri/card%d", vdata->devindex);
vdata->drm_fd = open(devname, O_RDWR | O_CLOEXEC);
SDL_free(devname);
if (vdata->drm_fd < 0) {
ret = SDL_SetError("Could not open /dev/dri/card%d.", vdata->devindex);
goto cleanup;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", vdata->drm_fd);
vdata->gbm = KMSDRM_gbm_create_device(vdata->drm_fd);
if (vdata->gbm == NULL) {
ret = SDL_SetError("Couldn't create gbm device.");
goto cleanup;
}
/* Find the first available connector with modes */
resources = KMSDRM_drmModeGetResources(vdata->drm_fd);
if (!resources) {
ret = SDL_SetError("drmModeGetResources(%d) failed", vdata->drm_fd);
goto cleanup;
}
for (i = 0; i < resources->count_connectors; i++) {
connector = KMSDRM_drmModeGetConnector(vdata->drm_fd, resources->connectors[i]);
if (connector == NULL)
continue;
if (connector->connection == DRM_MODE_CONNECTED &&
connector->count_modes > 0) {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
connector->connector_id, connector->count_modes);
vdata->saved_conn_id = connector->connector_id;
break;
}
KMSDRM_drmModeFreeConnector(connector);
}
if (i == resources->count_connectors) {
ret = SDL_SetError("No currently active connector found.");
goto cleanup;
}
for (i = 0; i < resources->count_encoders; i++) {
encoder = KMSDRM_drmModeGetEncoder(vdata->drm_fd, resources->encoders[i]);
if (encoder == NULL)
continue;
if (encoder->encoder_id == connector->encoder_id) {
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
data->encoder_id = encoder->encoder_id;
break;
}
KMSDRM_drmModeFreeEncoder(encoder);
}
if (i == resources->count_encoders) {
ret = SDL_SetError("No connected encoder found.");
goto cleanup;
}
vdata->saved_crtc = KMSDRM_drmModeGetCrtc(vdata->drm_fd, encoder->crtc_id);
if (vdata->saved_crtc == NULL) {
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",
vdata->saved_crtc->crtc_id, vdata->saved_crtc->buffer_id, vdata->saved_crtc->x,
vdata->saved_crtc->y, vdata->saved_crtc->width, vdata->saved_crtc->height);
data->crtc_id = encoder->crtc_id;
data->cur_mode = vdata->saved_crtc->mode;
SDL_zero(current_mode);
current_mode.w = vdata->saved_crtc->mode.hdisplay;
current_mode.h = vdata->saved_crtc->mode.vdisplay;
current_mode.refresh_rate = vdata->saved_crtc->mode.vrefresh;
/* FIXME ?
drmModeFB *fb = drmModeGetFB(vdata->drm_fd, vdata->saved_crtc->buffer_id);
current_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
drmModeFreeFB(fb);
*/
current_mode.format = SDL_PIXELFORMAT_ARGB8888;
current_mode.driverdata = NULL;
SDL_zero(display);
display.desktop_mode = current_mode;
display.current_mode = current_mode;
display.driverdata = data;
/* SDL_VideoQuit will later SDL_free(display.driverdata) */
SDL_AddVideoDisplay(&display);
/* Setup page flip handler */
vdata->drm_pollfd.fd = vdata->drm_fd;
vdata->drm_pollfd.events = POLLIN;
vdata->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
vdata->drm_evctx.page_flip_handler = KMSDRM_FlipHandler;
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Init();
#endif
KMSDRM_InitMouse(_this);
cleanup:
if (encoder != NULL)
KMSDRM_drmModeFreeEncoder(encoder);
if (connector != NULL)
KMSDRM_drmModeFreeConnector(connector);
if (resources != NULL)
KMSDRM_drmModeFreeResources(resources);
if (ret != 0) {
/* Error (complete) cleanup */
SDL_free(data);
if(vdata->saved_crtc != NULL) {
KMSDRM_drmModeFreeCrtc(vdata->saved_crtc);
vdata->saved_crtc = NULL;
}
if (vdata->gbm != NULL) {
KMSDRM_gbm_device_destroy(vdata->gbm);
vdata->gbm = NULL;
}
if (vdata->drm_fd >= 0) {
close(vdata->drm_fd);
vdata->drm_fd = -1;
}
}
return ret;
}
void
KMSDRM_VideoQuit(_THIS)
{
SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()");
if (_this->gl_config.driver_loaded) {
SDL_GL_UnloadLibrary();
}
if(vdata->saved_crtc != NULL) {
if(vdata->drm_fd > 0 && vdata->saved_conn_id > 0) {
/* Restore saved CRTC settings */
drmModeCrtc *crtc = vdata->saved_crtc;
if(KMSDRM_drmModeSetCrtc(vdata->drm_fd, crtc->crtc_id, crtc->buffer_id,
crtc->x, crtc->y, &vdata->saved_conn_id, 1,
&crtc->mode) != 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original CRTC mode");
}
}
KMSDRM_drmModeFreeCrtc(vdata->saved_crtc);
vdata->saved_crtc = NULL;
}
if (vdata->gbm != NULL) {
KMSDRM_gbm_device_destroy(vdata->gbm);
vdata->gbm = NULL;
}
if (vdata->drm_fd >= 0) {
close(vdata->drm_fd);
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", vdata->drm_fd);
vdata->drm_fd = -1;
}
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Quit();
#endif
}
void
KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
/* Only one display mode available, the current one */
SDL_AddDisplayMode(display, &display->current_mode);
}
int
KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
return 0;
}
int
KMSDRM_CreateWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *wdata;
SDL_VideoDisplay *display;
SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
Uint32 surface_fmt, surface_flags;
/* Allocate window internal data */
wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
if (wdata == NULL) {
return SDL_OutOfMemory();
}
wdata->waiting_for_flip = SDL_FALSE;
display = SDL_GetDisplayForWindow(window);
/* Windows have one size for now */
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);
surface_fmt = GBM_BO_FORMAT_XRGB8888;
surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
if (!KMSDRM_gbm_device_is_format_supported(vdata->gbm, surface_fmt, surface_flags)) {
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
}
wdata->gs = KMSDRM_gbm_surface_create(vdata->gbm, window->w, window->h, surface_fmt, surface_flags);
#if SDL_VIDEO_OPENGL_EGL
if (!_this->egl_data) {
if (SDL_GL_LoadLibrary(NULL) < 0) {
goto error;
}
}
wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) wdata->gs);
if (wdata->egl_surface == EGL_NO_SURFACE) {
SDL_SetError("Could not create EGL window surface");
goto error;
}
#endif /* SDL_VIDEO_OPENGL_EGL */
/* Setup driver data for this window */
window->driverdata = wdata;
/* One window, it always has focus */
SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window);
/* Window has been successfully created */
return 0;
error:
if (wdata != NULL) {
#if SDL_VIDEO_OPENGL_EGL
if (wdata->egl_surface != EGL_NO_SURFACE)
SDL_EGL_DestroySurface(_this, wdata->egl_surface);
#endif /* SDL_VIDEO_OPENGL_EGL */
if (wdata->gs != NULL)
KMSDRM_gbm_surface_destroy(wdata->gs);
SDL_free(wdata);
}
return -1;
}
void
KMSDRM_DestroyWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
if(data) {
/* Wait for any pending page flips and unlock buffer */
KMSDRM_WaitPageFlip(_this, data, -1);
if (data->locked_bo != NULL) {
KMSDRM_gbm_surface_release_buffer(data->gs, data->locked_bo);
data->locked_bo = NULL;
}
#if SDL_VIDEO_OPENGL_EGL
SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_DestroySurface(_this, data->egl_surface);
}
#endif /* SDL_VIDEO_OPENGL_EGL */
if (data->gs != NULL) {
KMSDRM_gbm_surface_destroy(data->gs);
data->gs = NULL;
}
SDL_free(data);
window->driverdata = NULL;
}
}
int
KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
{
return -1;
}
void
KMSDRM_SetWindowTitle(_THIS, SDL_Window * window)
{
}
void
KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
{
}
void
KMSDRM_SetWindowPosition(_THIS, SDL_Window * window)
{
}
void
KMSDRM_SetWindowSize(_THIS, SDL_Window * window)
{
}
void
KMSDRM_ShowWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_HideWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_RaiseWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_MaximizeWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_MinimizeWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_RestoreWindow(_THIS, SDL_Window * window)
{
}
void
KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
{
}
/*****************************************************************************/
/* SDL Window Manager function */
/*****************************************************************************/
SDL_bool
KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
{
if (info->version.major <= SDL_MAJOR_VERSION) {
return SDL_TRUE;
} else {
SDL_SetError("application not compiled with SDL %d.%d\n",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
return SDL_FALSE;
}
/* Failed to get window manager information */
return SDL_FALSE;
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,119 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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_KMSDRMVIDEO_H__
#define __SDL_KMSDRMVIDEO_H__
#include "../../SDL_internal.h"
#include "../SDL_sysvideo.h"
#include <fcntl.h>
#include <unistd.h>
#include <poll.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;
drmEventContext drm_evctx; /* DRM event context */
struct pollfd drm_pollfd; /* pollfd containing DRM file desc */
drmModeCrtc *saved_crtc; /* Saved CRTC to restore on quit */
uint32_t saved_conn_id; /* Saved DRM connector ID */
} SDL_VideoData;
typedef struct SDL_DisplayData
{
uint32_t encoder_id;
uint32_t crtc_id;
drmModeModeInfo cur_mode;
} SDL_DisplayData;
typedef struct SDL_WindowData
{
struct gbm_surface *gs;
struct gbm_bo *locked_bo;
SDL_bool waiting_for_flip;
#if SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
} SDL_WindowData;
typedef struct KMSDRM_FBInfo
{
int drm_fd; /* DRM file desc */
uint32_t fb_id; /* DRM framebuffer ID */
} KMSDRM_FBInfo;
/* Helper functions */
KMSDRM_FBInfo *KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo);
SDL_bool KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *wdata, int timeout);
/****************************************************************************/
/* SDL_VideoDevice functions declaration */
/****************************************************************************/
/* Display and window functions */
int KMSDRM_VideoInit(_THIS);
void KMSDRM_VideoQuit(_THIS);
void KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
int KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
int KMSDRM_CreateWindow(_THIS, SDL_Window * window);
int KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data);
void KMSDRM_SetWindowTitle(_THIS, SDL_Window * window);
void KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon);
void KMSDRM_SetWindowPosition(_THIS, SDL_Window * window);
void KMSDRM_SetWindowSize(_THIS, SDL_Window * window);
void KMSDRM_ShowWindow(_THIS, SDL_Window * window);
void KMSDRM_HideWindow(_THIS, SDL_Window * window);
void KMSDRM_RaiseWindow(_THIS, SDL_Window * window);
void KMSDRM_MaximizeWindow(_THIS, SDL_Window * window);
void KMSDRM_MinimizeWindow(_THIS, SDL_Window * window);
void KMSDRM_RestoreWindow(_THIS, SDL_Window * window);
void KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
void KMSDRM_DestroyWindow(_THIS, SDL_Window * window);
/* Window manager function */
SDL_bool KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window,
struct SDL_SysWMinfo *info);
/* OpenGL/OpenGL ES functions */
int KMSDRM_GLES_LoadLibrary(_THIS, const char *path);
void *KMSDRM_GLES_GetProcAddress(_THIS, const char *proc);
void KMSDRM_GLES_UnloadLibrary(_THIS);
SDL_GLContext KMSDRM_GLES_CreateContext(_THIS, SDL_Window * window);
int KMSDRM_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
int KMSDRM_GLES_SetSwapInterval(_THIS, int interval);
int KMSDRM_GLES_GetSwapInterval(_THIS);
int KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window);
void KMSDRM_GLES_DeleteContext(_THIS, SDL_GLContext context);
#endif /* __SDL_KMSDRMVIDEO_H__ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -66,7 +66,7 @@ MIR_GL_LoadLibrary(_THIS, const char* path)
{
MIR_Data* mir_data = _this->driverdata;
SDL_EGL_LoadLibrary(_this, path, MIR_mir_connection_get_egl_native_display(mir_data->connection));
SDL_EGL_LoadLibrary(_this, path, MIR_mir_connection_get_egl_native_display(mir_data->connection), 0);
SDL_EGL_ChooseConfig(_this);

View File

@ -29,7 +29,7 @@
int
RPI_GLES_LoadLibrary(_THIS, const char *path) {
return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY);
return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0);
}
SDL_EGL_CreateContext_impl(RPI)

View File

@ -34,7 +34,7 @@ VIVANTE_GLES_LoadLibrary(_THIS, const char *path)
displaydata = SDL_GetDisplayDriverData(0);
return SDL_EGL_LoadLibrary(_this, path, displaydata->native_display);
return SDL_EGL_LoadLibrary(_this, path, displaydata->native_display, 0);
}
SDL_EGL_CreateContext_impl(VIVANTE)

View File

@ -35,7 +35,7 @@ Wayland_GLES_LoadLibrary(_THIS, const char *path) {
int ret;
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
ret = SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) data->display);
ret = SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) data->display, 0);
Wayland_PumpEvents(_this);
WAYLAND_wl_display_flush(data->display);

View File

@ -52,7 +52,7 @@ WIN_GLES_LoadLibrary(_THIS, const char *path) {
}
if (_this->egl_data == NULL) {
return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY);
return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, 0);
}
return 0;
@ -110,7 +110,7 @@ WIN_GLES_SetupWindow(_THIS, SDL_Window * window)
if (_this->egl_data == NULL) {
if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY) < 0) {
if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, 0) < 0) {
SDL_EGL_UnloadLibrary(_this);
return -1;
}

View File

@ -58,7 +58,7 @@ WINRT_GLES_LoadLibrary(_THIS, const char *path)
{
SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
if (SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY) != 0) {
if (SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0) != 0) {
return -1;
}

View File

@ -52,7 +52,7 @@ X11_GLES_LoadLibrary(_THIS, const char *path)
#endif
}
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) data->display);
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) data->display, 0);
}
XVisualInfo *