Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'

This commit is contained in:
2023-07-25 22:27:55 +02:00
1663 changed files with 627495 additions and 0 deletions

View File

@ -0,0 +1,157 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifdef SDL_VIDEO_DRIVER_KMSDRM
#define DEBUG_DYNAMIC_KMSDRM 0
#include "SDL_kmsdrmdyn.h"
#ifdef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
typedef struct
{
void *lib;
const char *libname;
} kmsdrmdynlib;
#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_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 */

View File

@ -0,0 +1,51 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_kmsdrmdyn_h_
#define SDL_kmsdrmdyn_h_
#include "SDL_internal.h"
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#ifdef __cplusplus
extern "C" {
#endif
int SDL_KMSDRM_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 /* SDL_kmsdrmdyn_h_ */

View File

@ -0,0 +1,44 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifdef SDL_VIDEO_DRIVER_KMSDRM
#include "SDL_kmsdrmvideo.h"
#include "SDL_kmsdrmevents.h"
#ifdef SDL_INPUT_LINUXEV
#include "../../core/linux/SDL_evdev.h"
#elif defined SDL_INPUT_WSCONS
#include "../../core/openbsd/SDL_wscons.h"
#endif
void KMSDRM_PumpEvents(SDL_VideoDevice *_this)
{
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Poll();
#elif defined SDL_INPUT_WSCONS
SDL_WSCONS_PumpEvents();
#endif
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_kmsdrmevents_h_
#define SDL_kmsdrmevents_h_
extern void KMSDRM_PumpEvents(SDL_VideoDevice *_this);
extern void KMSDRM_EventInit(SDL_VideoDevice *_this);
extern void KMSDRM_EventQuit(SDL_VideoDevice *_this);
#endif /* SDL_kmsdrmevents_h_ */

View File

@ -0,0 +1,437 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifdef SDL_VIDEO_DRIVER_KMSDRM
#include "SDL_kmsdrmvideo.h"
#include "SDL_kmsdrmmouse.h"
#include "SDL_kmsdrmdyn.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/default_cursor.h"
#include "../SDL_pixels_c.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 int KMSDRM_MoveCursor(SDL_Cursor *cursor);
static void KMSDRM_FreeCursor(SDL_Cursor *cursor);
/**************************************************************************************/
/* BEFORE CODING ANYTHING MOUSE/CURSOR RELATED, REMEMBER THIS. */
/* How does SDL manage cursors internally? First, mouse =! cursor. The mouse can have */
/* many cursors in mouse->cursors. */
/* -SDL tells us to create a cursor with KMSDRM_CreateCursor(). It can create many */
/* cursosr with this, not only one. */
/* -SDL stores those cursors in a cursors array, in mouse->cursors. */
/* -Whenever it wants (or the programmer wants) takes a cursor from that array */
/* and shows it on screen with KMSDRM_ShowCursor(). */
/* KMSDRM_ShowCursor() simply shows or hides the cursor it receives: it does NOT */
/* mind if it's mouse->cur_cursor, etc. */
/* -If KMSDRM_ShowCursor() returns successfully, that cursor becomes */
/* mouse->cur_cursor and mouse->cursor_shown is 1. */
/**************************************************************************************/
static SDL_Cursor *KMSDRM_CreateDefaultCursor(void)
{
return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
}
/* Given a display's driverdata, destroy the cursor BO for it.
To be called from KMSDRM_DestroyWindow(), as that's where we
destroy the driverdata for the window's display. */
void KMSDRM_DestroyCursorBO(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
{
SDL_DisplayData *dispdata = display->driverdata;
/* Destroy the curso GBM BO. */
if (dispdata->cursor_bo) {
KMSDRM_gbm_bo_destroy(dispdata->cursor_bo);
dispdata->cursor_bo = NULL;
dispdata->cursor_bo_drm_fd = -1;
}
}
/* Given a display's driverdata, create the cursor BO for it.
To be called from KMSDRM_CreateWindow(), as that's where we
build a window and assign a display to it. */
int KMSDRM_CreateCursorBO(SDL_VideoDisplay *display)
{
SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *viddata = dev->driverdata;
SDL_DisplayData *dispdata = display->driverdata;
if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev,
GBM_FORMAT_ARGB8888,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) {
return SDL_SetError("Unsupported pixel format for cursor");
}
if (KMSDRM_drmGetCap(viddata->drm_fd,
DRM_CAP_CURSOR_WIDTH, &dispdata->cursor_w) ||
KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_HEIGHT,
&dispdata->cursor_h)) {
return SDL_SetError("Could not get the recommended GBM cursor size");
}
if (dispdata->cursor_w == 0 || dispdata->cursor_h == 0) {
return SDL_SetError("Could not get an usable GBM cursor size");
}
dispdata->cursor_bo = KMSDRM_gbm_bo_create(viddata->gbm_dev,
dispdata->cursor_w, dispdata->cursor_h,
GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE | GBM_BO_USE_LINEAR);
if (!dispdata->cursor_bo) {
return SDL_SetError("Could not create GBM cursor BO");
}
dispdata->cursor_bo_drm_fd = viddata->drm_fd;
return 0;
}
/* Remove a cursor buffer from a display's DRM cursor BO. */
static int KMSDRM_RemoveCursorFromBO(SDL_VideoDisplay *display)
{
int ret = 0;
SDL_DisplayData *dispdata = display->driverdata;
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
SDL_VideoData *viddata = video_device->driverdata;
ret = KMSDRM_drmModeSetCursor(viddata->drm_fd,
dispdata->crtc->crtc_id, 0, 0, 0);
if (ret) {
ret = SDL_SetError("Could not hide current cursor with drmModeSetCursor().");
}
return ret;
}
/* Dump a cursor buffer to a display's DRM cursor BO. */
static int KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Cursor *cursor)
{
SDL_DisplayData *dispdata = display->driverdata;
KMSDRM_CursorData *curdata = (KMSDRM_CursorData *)cursor->driverdata;
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
SDL_VideoData *viddata = video_device->driverdata;
uint32_t bo_handle;
size_t bo_stride;
size_t bufsize;
uint8_t *ready_buffer = NULL;
uint8_t *src_row;
int i;
int ret;
if (curdata == NULL || !dispdata->cursor_bo) {
return SDL_SetError("Cursor or display not initialized properly.");
}
/* Prepare a buffer we can dump to our GBM BO (different
size, alpha premultiplication...) */
bo_stride = KMSDRM_gbm_bo_get_stride(dispdata->cursor_bo);
bufsize = bo_stride * dispdata->cursor_h;
ready_buffer = (uint8_t *)SDL_calloc(1, bufsize);
if (ready_buffer == NULL) {
ret = SDL_OutOfMemory();
goto cleanup;
}
/* Copy from the cursor buffer to a buffer that we can dump to the GBM BO. */
for (i = 0; i < curdata->h; i++) {
src_row = &((uint8_t *)curdata->buffer)[i * curdata->w * 4];
SDL_memcpy(ready_buffer + (i * bo_stride), src_row, (size_t)4 * curdata->w);
}
/* Dump the cursor buffer to our GBM BO. */
if (KMSDRM_gbm_bo_write(dispdata->cursor_bo, ready_buffer, bufsize)) {
ret = SDL_SetError("Could not write to GBM cursor BO");
goto cleanup;
}
/* Put the GBM BO buffer on screen using the DRM interface. */
bo_handle = KMSDRM_gbm_bo_get_handle(dispdata->cursor_bo).u32;
if (curdata->hot_x == 0 && curdata->hot_y == 0) {
ret = KMSDRM_drmModeSetCursor(viddata->drm_fd, dispdata->crtc->crtc_id,
bo_handle, dispdata->cursor_w, dispdata->cursor_h);
} else {
ret = KMSDRM_drmModeSetCursor2(viddata->drm_fd, dispdata->crtc->crtc_id,
bo_handle, dispdata->cursor_w, dispdata->cursor_h, curdata->hot_x, curdata->hot_y);
}
if (ret) {
ret = SDL_SetError("Failed to set DRM cursor.");
goto cleanup;
}
if (ret) {
ret = SDL_SetError("Failed to reset cursor position.");
goto cleanup;
}
cleanup:
if (ready_buffer) {
SDL_free(ready_buffer);
}
return ret;
}
/* This is only for freeing the SDL_cursor.*/
static void KMSDRM_FreeCursor(SDL_Cursor *cursor)
{
KMSDRM_CursorData *curdata;
/* Even if the cursor is not ours, free it. */
if (cursor) {
curdata = (KMSDRM_CursorData *)cursor->driverdata;
/* Free cursor buffer */
if (curdata->buffer) {
SDL_free(curdata->buffer);
curdata->buffer = NULL;
}
/* Free cursor itself */
if (cursor->driverdata) {
SDL_free(cursor->driverdata);
}
SDL_free(cursor);
}
}
/* This simply gets the cursor soft-buffer ready.
We don't copy it to a GBO BO until ShowCursor() because the cusor GBM BO (living
in dispata) is destroyed and recreated when we recreate windows, etc. */
static SDL_Cursor *KMSDRM_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
KMSDRM_CursorData *curdata;
SDL_Cursor *cursor, *ret;
curdata = NULL;
ret = NULL;
cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
if (cursor == NULL) {
SDL_OutOfMemory();
goto cleanup;
}
curdata = (KMSDRM_CursorData *)SDL_calloc(1, sizeof(*curdata));
if (curdata == NULL) {
SDL_OutOfMemory();
goto cleanup;
}
/* hox_x and hot_y are the coordinates of the "tip of the cursor" from it's base. */
curdata->hot_x = hot_x;
curdata->hot_y = hot_y;
curdata->w = surface->w;
curdata->h = surface->h;
curdata->buffer = NULL;
/* Configure the cursor buffer info.
This buffer has the original size of the cursor surface we are given. */
curdata->buffer_pitch = surface->w;
curdata->buffer_size = (size_t)surface->w * surface->h * 4;
curdata->buffer = (uint32_t *)SDL_malloc(curdata->buffer_size);
if (!curdata->buffer) {
SDL_OutOfMemory();
goto cleanup;
}
/* All code below assumes ARGB8888 format for the cursor surface,
like other backends do. Also, the GBM BO pixels have to be
alpha-premultiplied, but the SDL surface we receive has
straight-alpha pixels, so we always have to convert. */
SDL_PremultiplyAlpha(surface->w, surface->h,
surface->format->format, surface->pixels, surface->pitch,
SDL_PIXELFORMAT_ARGB8888, curdata->buffer, surface->w * 4);
cursor->driverdata = curdata;
ret = cursor;
cleanup:
if (ret == NULL) {
if (curdata) {
if (curdata->buffer) {
SDL_free(curdata->buffer);
}
SDL_free(curdata);
}
if (cursor) {
SDL_free(cursor);
}
}
return ret;
}
/* Show the specified cursor, or hide if cursor is NULL or has no focus. */
static int KMSDRM_ShowCursor(SDL_Cursor *cursor)
{
SDL_VideoDisplay *display;
SDL_Window *window;
SDL_Mouse *mouse;
int i;
int ret = 0;
/* Get the mouse focused window, if any. */
mouse = SDL_GetMouse();
if (mouse == NULL) {
return SDL_SetError("No mouse.");
}
window = mouse->focus;
if (window == NULL || cursor == NULL) {
/* If no window is focused by mouse or cursor is NULL,
since we have no window (no mouse->focus) and hence
we have no display, we simply hide mouse on all displays.
This happens on video quit, where we get here after
the mouse focus has been unset, yet SDL wants to
restore the system default cursor (makes no sense here). */
SDL_DisplayID *displays = SDL_GetDisplays(NULL);
if (displays) {
/* Iterate on the displays, hiding the cursor. */
for (i = 0; i < displays[i]; i++) {
display = SDL_GetVideoDisplay(displays[i]);
ret = KMSDRM_RemoveCursorFromBO(display);
}
SDL_free(displays);
}
} else {
display = SDL_GetVideoDisplayForWindow(window);
if (display) {
if (cursor) {
/* Dump the cursor to the display DRM cursor BO so it becomes visible
on that display. */
ret = KMSDRM_DumpCursorToBO(display, cursor);
} else {
/* Hide the cursor on that display. */
ret = KMSDRM_RemoveCursorFromBO(display);
}
}
}
return ret;
}
static int KMSDRM_WarpMouseGlobal(float x, float y)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse && mouse->cur_cursor && mouse->focus) {
SDL_Window *window = mouse->focus;
SDL_DisplayData *dispdata = SDL_GetDisplayDriverDataForWindow(window);
/* Update internal mouse position. */
SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 0, x, y);
/* And now update the cursor graphic position on screen. */
if (dispdata->cursor_bo) {
int ret = 0;
ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, (int)x, (int)y);
if (ret) {
SDL_SetError("drmModeMoveCursor() failed.");
}
return ret;
} else {
return SDL_SetError("Cursor not initialized properly.");
}
} else {
return SDL_SetError("No mouse or current cursor.");
}
}
static int KMSDRM_WarpMouse(SDL_Window *window, float x, float y)
{
/* Only one global/fullscreen window is supported */
return KMSDRM_WarpMouseGlobal(x, y);
}
void KMSDRM_InitMouse(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_DisplayData *dispdata = display->driverdata;
mouse->CreateCursor = KMSDRM_CreateCursor;
mouse->ShowCursor = KMSDRM_ShowCursor;
mouse->MoveCursor = KMSDRM_MoveCursor;
mouse->FreeCursor = KMSDRM_FreeCursor;
mouse->WarpMouse = KMSDRM_WarpMouse;
mouse->WarpMouseGlobal = KMSDRM_WarpMouseGlobal;
/* Only create the default cursor for this display if we haven't done so before,
we don't want several cursors to be created for the same display. */
if (!dispdata->default_cursor_init) {
SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor());
dispdata->default_cursor_init = SDL_TRUE;
}
}
void KMSDRM_QuitMouse(SDL_VideoDevice *_this)
{
/* TODO: ? */
}
/* This is called when a mouse motion event occurs */
static int KMSDRM_MoveCursor(SDL_Cursor *cursor)
{
SDL_Mouse *mouse = SDL_GetMouse();
int ret = 0;
/* 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->focus) {
SDL_Window *window = mouse->focus;
SDL_DisplayData *dispdata = SDL_GetDisplayDriverDataForWindow(window);
if (!dispdata->cursor_bo) {
return SDL_SetError("Cursor not initialized properly.");
}
ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, mouse->x, mouse->y);
if (ret) {
return SDL_SetError("drmModeMoveCursor() failed.");
}
}
return 0;
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */

View File

@ -0,0 +1,53 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_KMSDRM_mouse_h_
#define SDL_KMSDRM_mouse_h_
#include <gbm.h>
#define MAX_CURSOR_W 512
#define MAX_CURSOR_H 512
typedef struct KMSDRM_CursorData
{
int hot_x, hot_y;
int w, h;
/* The buffer where we store the mouse bitmap ready to be used.
We get it ready and filled in CreateCursor(), and copy it
to a GBM BO in ShowCursor().*/
uint32_t *buffer;
size_t buffer_size;
size_t buffer_pitch;
} KMSDRM_CursorData;
extern void KMSDRM_InitMouse(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern void KMSDRM_QuitMouse(SDL_VideoDevice *_this);
extern int KMSDRM_CreateCursorBO(SDL_VideoDisplay *display);
extern void KMSDRM_DestroyCursorBO(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern void KMSDRM_InitCursor(void);
#endif /* SDL_KMSDRM_mouse_h_ */

View File

@ -0,0 +1,203 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifdef SDL_VIDEO_DRIVER_KMSDRM
#include "SDL_kmsdrmvideo.h"
#include "SDL_kmsdrmopengles.h"
#include "SDL_kmsdrmdyn.h"
#include <errno.h>
#ifndef EGL_PLATFORM_GBM_MESA
#define EGL_PLATFORM_GBM_MESA 0x31D7
#endif
/* EGL implementation of SDL OpenGL support */
void KMSDRM_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor)
{
/* if SDL was _also_ built with the Raspberry Pi driver (so we're
definitely a Pi device) or with the ROCKCHIP video driver
(it's a ROCKCHIP device), default to GLES2. */
#if defined(SDL_VIDEO_DRIVER_RPI) || defined(SDL_VIDEO_DRIVER_ROCKCHIP)
*mask = SDL_GL_CONTEXT_PROFILE_ES;
*major = 2;
*minor = 0;
#endif
}
int KMSDRM_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
/* Just pretend you do this here, but don't do it until KMSDRM_CreateWindow(),
where we do the same library load we would normally do here.
because this gets called by SDL_CreateWindow() before KMSDR_CreateWindow(),
so gbm dev isn't yet created when this is called, AND we can't alter the
call order in SDL_CreateWindow(). */
#if 0
NativeDisplayType display = (NativeDisplayType)_this->driverdata->gbm_dev;
return SDL_EGL_LoadLibrary(_this, path, display, EGL_PLATFORM_GBM_MESA);
#endif
return 0;
}
void KMSDRM_GLES_UnloadLibrary(SDL_VideoDevice *_this)
{
/* As with KMSDRM_GLES_LoadLibrary(), we define our own "dummy" unloading function
so we manually unload the library whenever we want. */
}
SDL_EGL_CreateContext_impl(KMSDRM)
int KMSDRM_GLES_SetSwapInterval(SDL_VideoDevice *_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(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *windata = window->driverdata;
SDL_DisplayData *dispdata = SDL_GetDisplayDriverDataForWindow(window);
SDL_VideoData *viddata = _this->driverdata;
KMSDRM_FBInfo *fb_info;
int ret = 0;
/* Always wait for the previous issued flip before issuing a new one,
even if you do async flips. */
uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT;
/* Recreate the GBM / EGL surfaces if the display mode has changed */
if (windata->egl_surface_dirty) {
KMSDRM_CreateSurfaces(_this, window);
}
/* Wait for confirmation that the next front buffer has been flipped, at which
point the previous front buffer can be released */
if (!KMSDRM_WaitPageflip(_this, windata)) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Wait for previous pageflip failed");
return 0;
}
/* Release the previous front buffer */
if (windata->bo) {
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
windata->bo = NULL;
}
windata->bo = windata->next_bo;
/* Mark a buffer to becume the next front buffer.
This won't happen until pagelip completes. */
if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display,
windata->egl_surface))) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed");
return 0;
}
/* From the GBM surface, get the next BO to become the next front buffer,
and lock it so it can't be allocated as a back buffer (to prevent EGL
from drawing into it!) */
windata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(windata->gs);
if (!windata->next_bo) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not lock front buffer on GBM surface");
return 0;
}
/* Get an actual usable fb for the next front buffer. */
fb_info = KMSDRM_FBFromBO(_this, windata->next_bo);
if (fb_info == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not get a framebuffer");
return 0;
}
if (!windata->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_drmModeSetCrtc(viddata->drm_fd,
dispdata->crtc->crtc_id, fb_info->fb_id, 0, 0,
&dispdata->connector->connector_id, 1, &dispdata->mode);
if (ret) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not set videomode on CRTC.");
return 0;
}
} else {
/* On subsequent swaps, queue the new front buffer to be flipped during
the next vertical blank
Remember: drmModePageFlip() never blocks, it just issues the flip,
which will be done during the next vblank, or immediately if
we pass the DRM_MODE_PAGE_FLIP_ASYNC flag.
Since calling drmModePageFlip() will return EBUSY if we call it
without having completed the last issued flip, we must pass the
DRM_MODE_PAGE_FLIP_ASYNC if we don't block on EGL (egl_swapinterval = 0).
That makes it flip immediately, without waiting for the next vblank
to do so, so even if we don't block on EGL, the flip will have completed
when we get here again. */
if (_this->egl_data->egl_swapinterval == 0 && viddata->async_pageflip_support) {
flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC;
}
ret = KMSDRM_drmModePageFlip(viddata->drm_fd, dispdata->crtc->crtc_id,
fb_info->fb_id, flip_flags, &windata->waiting_for_flip);
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).
Even if we are already doing a WaitPageflip at the beginning of this
function, this is NOT redundant because here we wait immediately
after submitting the image to the screen, reducing lag, and if
we have waited here, there won't be a pending pageflip so the
WaitPageflip at the beginning of this function will be a no-op.
Just leave it here and don't worry.
Run your SDL program with "SDL_KMSDRM_DOUBLE_BUFFER=1 <program_name>"
to enable this. */
if (windata->double_buffer) {
if (!KMSDRM_WaitPageflip(_this, windata)) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Immediate wait for previous pageflip failed");
return 0;
}
}
}
return 1;
}
SDL_EGL_MakeCurrent_impl(KMSDRM)
#endif /* SDL_VIDEO_DRIVER_KMSDRM */

View File

@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_
#ifdef SDL_VIDEO_DRIVER_KMSDRM
#include "../SDL_sysvideo.h"
#include "../SDL_egl_c.h"
/* OpenGLES functions */
#define KMSDRM_GLES_GetAttribute SDL_EGL_GetAttribute
#define KMSDRM_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
#define KMSDRM_GLES_DeleteContext SDL_EGL_DeleteContext
#define KMSDRM_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
extern void KMSDRM_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor);
extern int KMSDRM_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval);
extern int KMSDRM_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_GLContext KMSDRM_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int KMSDRM_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int KMSDRM_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
#endif /* SDL_kmsdrmopengles_h_ */

View File

@ -0,0 +1,127 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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* */ /* clang-format 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(int,drmGetCap,(int fd, uint64_t capability, uint64_t *value))
SDL_KMSDRM_SYM(int,drmSetMaster,(int fd))
SDL_KMSDRM_SYM(int,drmAuthMagic,(int fd, drm_magic_t magic))
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,drmModeAddFB2,(int fd, uint32_t width, uint32_t height,
uint32_t pixel_format, const uint32_t bo_handles[4],
const uint32_t pitches[4], const uint32_t offsets[4],
uint32_t *buf_id, uint32_t flags))
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))
/* Planes stuff. */
SDL_KMSDRM_SYM(int,drmSetClientCap,(int fd, uint64_t capability, uint64_t value))
SDL_KMSDRM_SYM(drmModePlaneResPtr,drmModeGetPlaneResources,(int fd))
SDL_KMSDRM_SYM(drmModePlanePtr,drmModeGetPlane,(int fd, uint32_t plane_id))
SDL_KMSDRM_SYM(drmModeObjectPropertiesPtr,drmModeObjectGetProperties,(int fd,uint32_t object_id,uint32_t object_type))
SDL_KMSDRM_SYM(int,drmModeObjectSetProperty,(int fd, uint32_t object_id,
uint32_t object_type, uint32_t property_id,
uint64_t value))
SDL_KMSDRM_SYM(drmModePropertyPtr,drmModeGetProperty,(int fd, uint32_t propertyId))
SDL_KMSDRM_SYM(void,drmModeFreeProperty,(drmModePropertyPtr ptr))
SDL_KMSDRM_SYM(void,drmModeFreeObjectProperties,(drmModeObjectPropertiesPtr ptr))
SDL_KMSDRM_SYM(void,drmModeFreePlane,(drmModePlanePtr ptr))
SDL_KMSDRM_SYM(void,drmModeFreePlaneResources,(drmModePlaneResPtr ptr))
SDL_KMSDRM_SYM(int,drmModeSetPlane,(int fd, uint32_t plane_id, uint32_t crtc_id,
uint32_t fb_id, uint32_t flags,
int32_t crtc_x, int32_t crtc_y,
uint32_t crtc_w, uint32_t crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h))
/* Planes stuff ends. */
SDL_KMSDRM_MODULE(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(uint32_t,gbm_bo_get_format,(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* */ /* clang-format on */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_kmsdrmvideo_h
#define SDL_kmsdrmvideo_h
#include "../SDL_sysvideo.h"
#include <fcntl.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include <EGL/egl.h>
struct SDL_VideoData
{
int devindex; /* device index that was passed on creation */
int drm_fd; /* DRM file desc */
char devpath[32]; /* DRM dev path. */
struct gbm_device *gbm_dev;
SDL_bool video_init; /* Has VideoInit succeeded? */
SDL_bool vulkan_mode; /* Are we in Vulkan mode? One VK window is enough to be. */
SDL_bool async_pageflip_support; /* Does the hardware support async. pageflips? */
SDL_Window **windows;
int max_windows;
int num_windows;
/* Even if we have several displays, we only have to
open 1 FD and create 1 gbm device. */
SDL_bool gbm_init;
};
struct SDL_DisplayModeData
{
int mode_index;
};
struct SDL_DisplayData
{
drmModeConnector *connector;
drmModeCrtc *crtc;
drmModeModeInfo mode;
drmModeModeInfo original_mode;
drmModeModeInfo fullscreen_mode;
drmModeCrtc *saved_crtc; /* CRTC to restore on quit */
SDL_bool saved_vrr;
/* DRM & GBM cursor stuff lives here, not in an SDL_Cursor's driverdata struct,
because setting/unsetting up these is done on window creation/destruction,
where we may not have an SDL_Cursor at all (so no SDL_Cursor driverdata).
There's only one cursor GBM BO because we only support one cursor. */
struct gbm_bo *cursor_bo;
int cursor_bo_drm_fd;
uint64_t cursor_w, cursor_h;
SDL_bool default_cursor_init;
};
struct SDL_WindowData
{
SDL_VideoData *viddata;
/* SDL internals expect EGL surface to be here, and in KMSDRM the GBM surface is
what supports the EGL surface on the driver side, so all these surfaces and buffers
are expected to be here, in the struct pointed by SDL_Window driverdata pointer:
this one. So don't try to move these to dispdata! */
struct gbm_surface *gs;
struct gbm_bo *bo;
struct gbm_bo *next_bo;
SDL_bool waiting_for_flip;
SDL_bool double_buffer;
EGLSurface egl_surface;
SDL_bool egl_surface_dirty;
};
typedef struct KMSDRM_FBInfo
{
int drm_fd; /* DRM file desc */
uint32_t fb_id; /* DRM framebuffer ID */
} KMSDRM_FBInfo;
/* Helper functions */
int KMSDRM_CreateSurfaces(SDL_VideoDevice *_this, SDL_Window *window);
KMSDRM_FBInfo *KMSDRM_FBFromBO(SDL_VideoDevice *_this, struct gbm_bo *bo);
KMSDRM_FBInfo *KMSDRM_FBFromBO2(SDL_VideoDevice *_this, struct gbm_bo *bo, int w, int h);
SDL_bool KMSDRM_WaitPageflip(SDL_VideoDevice *_this, SDL_WindowData *windata);
/****************************************************************************/
/* SDL_VideoDevice functions declaration */
/****************************************************************************/
/* Display and window functions */
int KMSDRM_VideoInit(SDL_VideoDevice *_this);
void KMSDRM_VideoQuit(SDL_VideoDevice *_this);
int KMSDRM_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
int KMSDRM_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
int KMSDRM_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window);
int KMSDRM_CreateWindowFrom(SDL_VideoDevice *_this, SDL_Window *window, const void *data);
void KMSDRM_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
int KMSDRM_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *_display, SDL_bool fullscreen);
void KMSDRM_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_HideWindow(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window);
void KMSDRM_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
/* Window manager function */
int KMSDRM_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, struct SDL_SysWMinfo *info);
/* OpenGL/OpenGL ES functions */
int KMSDRM_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
SDL_FunctionPointer KMSDRM_GLES_GetProcAddress(SDL_VideoDevice *_this, const char *proc);
void KMSDRM_GLES_UnloadLibrary(SDL_VideoDevice *_this);
SDL_GLContext KMSDRM_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
int KMSDRM_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
int KMSDRM_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval);
int KMSDRM_GLES_GetSwapInterval(SDL_VideoDevice *_this);
int KMSDRM_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
int KMSDRM_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
#endif /* SDL_kmsdrmvideo_h */

View File

@ -0,0 +1,513 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Manuel Alfayate Corchere <redwindwanderer@gmail.com>.
* Based on Jacob Lifshay's SDL_x11vulkan.c.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_KMSDRM)
#include "SDL_kmsdrmvideo.h"
#include "SDL_kmsdrmdyn.h"
#include "SDL_kmsdrmvulkan.h"
#include <SDL3/SDL_syswm.h>
#include <sys/ioctl.h>
#ifdef __OpenBSD__
#define DEFAULT_VULKAN "libvulkan.so"
#else
#define DEFAULT_VULKAN "libvulkan.so.1"
#endif
int KMSDRM_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
VkExtensionProperties *extensions = NULL;
Uint32 i, extensionCount = 0;
SDL_bool hasSurfaceExtension = SDL_FALSE;
SDL_bool hasDisplayExtension = SDL_FALSE;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan already loaded");
}
/* Load the Vulkan library */
if (path == NULL) {
path = SDL_getenv("SDL_VULKAN_LIBRARY");
}
if (path == NULL) {
path = DEFAULT_VULKAN;
}
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
if (!_this->vulkan_config.loader_handle) {
return -1;
}
SDL_strlcpy(_this->vulkan_config.loader_path, path,
SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
if (!vkGetInstanceProcAddr) {
goto fail;
}
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
goto fail;
}
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
(PFN_vkEnumerateInstanceExtensionProperties)
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
&extensionCount);
if (extensions == NULL) {
goto fail;
}
for (i = 0; i < extensionCount; i++) {
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_KHR_DISPLAY_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasDisplayExtension = SDL_TRUE;
}
}
SDL_free(extensions);
if (!hasSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail;
} else if (!hasDisplayExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_DISPLAY_EXTENSION_NAME "extension");
goto fail;
}
return 0;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return -1;
}
void KMSDRM_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
{
if (_this->vulkan_config.loader_handle) {
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
}
}
/*********************************************************************/
/* Here we can put whatever Vulkan extensions we want to be enabled */
/* at instance creation, which is done in the programs, not in SDL. */
/* So: programs call SDL_Vulkan_GetInstanceExtensions() and here */
/* we put the extensions specific to this backend so the programs */
/* get a list with the extension we want, so they can include that */
/* list in the ppEnabledExtensionNames and EnabledExtensionCount */
/* members of the VkInstanceCreateInfo struct passed to */
/* vkCreateInstance(). */
/*********************************************************************/
SDL_bool KMSDRM_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names)
{
static const char *const extensionsForKMSDRM[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_DISPLAY_EXTENSION_NAME
};
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
return SDL_Vulkan_GetInstanceExtensions_Helper(
count, names, SDL_arraysize(extensionsForKMSDRM),
extensionsForKMSDRM);
}
/***********************************************************************/
/* First thing to know is that we don't call vkCreateInstance() here. */
/* Instead, programs using SDL and Vulkan create their Vulkan instance */
/* and we get it here, ready to use. */
/* Extensions specific for this platform are activated in */
/* KMSDRM_Vulkan_GetInstanceExtensions(), like we do with */
/* VK_KHR_DISPLAY_EXTENSION_NAME, which is what we need for x-less VK. */
/***********************************************************************/
SDL_bool KMSDRM_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface)
{
VkPhysicalDevice gpu = NULL;
uint32_t gpu_count;
uint32_t display_count;
uint32_t mode_count;
uint32_t plane_count;
uint32_t plane = UINT32_MAX;
VkPhysicalDevice *physical_devices = NULL;
VkPhysicalDeviceProperties *device_props = NULL;
VkDisplayPropertiesKHR *display_props = NULL;
VkDisplayModePropertiesKHR *mode_props = NULL;
VkDisplayPlanePropertiesKHR *plane_props = NULL;
VkDisplayPlaneCapabilitiesKHR plane_caps;
VkDisplayModeCreateInfoKHR display_mode_create_info;
VkDisplaySurfaceCreateInfoKHR display_plane_surface_create_info;
VkExtent2D image_size;
VkDisplayKHR display;
VkDisplayModeKHR display_mode = (VkDisplayModeKHR)0;
VkDisplayModePropertiesKHR display_mode_props = { 0 };
VkDisplayModeParametersKHR new_mode_parameters = { { 0, 0 }, 0 };
/* Prefer a plane that supports per-pixel alpha. */
VkDisplayPlaneAlphaFlagBitsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
VkResult result;
SDL_bool ret = SDL_FALSE;
SDL_bool valid_gpu = SDL_FALSE;
SDL_bool mode_found = SDL_FALSE;
SDL_bool plane_supports_display = SDL_FALSE;
/* Get the display index from the display being used by the window. */
int display_index = SDL_GetDisplayIndex(SDL_GetDisplayForWindow(window));
int i, j;
/* Get the function pointers for the functions we will use. */
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR =
(PFN_vkCreateDisplayPlaneSurfaceKHR)vkGetInstanceProcAddr(
instance, "vkCreateDisplayPlaneSurfaceKHR");
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices =
(PFN_vkEnumeratePhysicalDevices)vkGetInstanceProcAddr(
instance, "vkEnumeratePhysicalDevices");
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties =
(PFN_vkGetPhysicalDeviceProperties)vkGetInstanceProcAddr(
instance, "vkGetPhysicalDeviceProperties");
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR =
(PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)vkGetInstanceProcAddr(
instance, "vkGetPhysicalDeviceDisplayPropertiesKHR");
PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR =
(PFN_vkGetDisplayModePropertiesKHR)vkGetInstanceProcAddr(
instance, "vkGetDisplayModePropertiesKHR");
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR =
(PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)vkGetInstanceProcAddr(
instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR =
(PFN_vkGetDisplayPlaneSupportedDisplaysKHR)vkGetInstanceProcAddr(
instance, "vkGetDisplayPlaneSupportedDisplaysKHR");
PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR =
(PFN_vkGetDisplayPlaneCapabilitiesKHR)vkGetInstanceProcAddr(
instance, "vkGetDisplayPlaneCapabilitiesKHR");
PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR =
(PFN_vkCreateDisplayModeKHR)vkGetInstanceProcAddr(
instance, "vkCreateDisplayModeKHR");
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
goto clean;
}
/*************************************/
/* Block for vulkan surface creation */
/*************************************/
/****************************************************************/
/* If we got vkCreateDisplayPlaneSurfaceKHR() pointer, it means */
/* that the VK_KHR_Display extension is active on the instance. */
/* That's the central extension we need for x-less VK! */
/****************************************************************/
if (!vkCreateDisplayPlaneSurfaceKHR) {
SDL_SetError(VK_KHR_DISPLAY_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
goto clean;
}
/* A GPU (or physical_device, in vkcube terms) is a physical GPU.
A machine with more than one video output doesn't need to have more than one GPU,
like the Pi4 which has 1 GPU and 2 video outputs.
Just in case, we test that the GPU we choose is Vulkan-capable.
If there are new reports about VK init failures, hardcode
gpu = physical_devices[0], instead of probing, and go with that.
*/
/* Get the physical device count. */
vkEnumeratePhysicalDevices(instance, &gpu_count, NULL);
if (gpu_count == 0) {
SDL_SetError("Vulkan can't find physical devices (gpus).");
goto clean;
}
/* Get the physical devices. */
physical_devices = SDL_malloc(sizeof(VkPhysicalDevice) * gpu_count);
device_props = SDL_malloc(sizeof(VkPhysicalDeviceProperties));
vkEnumeratePhysicalDevices(instance, &gpu_count, physical_devices);
/* Iterate on the physical devices. */
for (i = 0; i < gpu_count; i++) {
/* Get the physical device properties. */
vkGetPhysicalDeviceProperties(
physical_devices[i],
device_props);
/* Is this device a real GPU that supports API version 1 at least? */
if (device_props->apiVersion >= 1 &&
(device_props->deviceType == 1 || device_props->deviceType == 2)) {
gpu = physical_devices[i];
valid_gpu = SDL_TRUE;
break;
}
}
if (!valid_gpu) {
SDL_SetError("Vulkan can't find a valid physical device (gpu).");
goto clean;
}
/* A display is a video output. 1 GPU can have N displays.
Vulkan only counts the connected displays.
Get the display count of the GPU. */
vkGetPhysicalDeviceDisplayPropertiesKHR(gpu, &display_count, NULL);
if (display_count == 0) {
SDL_SetError("Vulkan can't find any displays.");
goto clean;
}
/* Get the props of the displays of the physical device. */
display_props = (VkDisplayPropertiesKHR *)SDL_malloc(display_count * sizeof(*display_props));
vkGetPhysicalDeviceDisplayPropertiesKHR(gpu,
&display_count,
display_props);
/* Get the chosen display based on the display index. */
display = display_props[display_index].display;
/* Get the list of the display videomodes. */
vkGetDisplayModePropertiesKHR(gpu,
display,
&mode_count, NULL);
if (mode_count == 0) {
SDL_SetError("Vulkan can't find any video modes for display %i (%s)\n", 0,
display_props[display_index].displayName);
goto clean;
}
mode_props = (VkDisplayModePropertiesKHR *)SDL_malloc(mode_count * sizeof(*mode_props));
vkGetDisplayModePropertiesKHR(gpu,
display,
&mode_count, mode_props);
/* Get a video mode equal to the window size among the predefined ones,
if possible.
REMEMBER: We have to get a small enough videomode for the window size,
because videomode determines how big the scanout region is and we can't
scanout a region bigger than the window (we would be reading past the
buffer, and Vulkan would give us a confusing VK_ERROR_SURFACE_LOST_KHR). */
for (i = 0; i < mode_count; i++) {
if (mode_props[i].parameters.visibleRegion.width == window->w &&
mode_props[i].parameters.visibleRegion.height == window->h) {
display_mode_props = mode_props[i];
mode_found = SDL_TRUE;
break;
}
}
if (mode_found &&
display_mode_props.parameters.visibleRegion.width > 0 &&
display_mode_props.parameters.visibleRegion.height > 0) {
/* Found a suitable mode among the predefined ones. Use that. */
display_mode = display_mode_props.displayMode;
} else {
/* Couldn't find a suitable mode among the predefined ones, so try to create our own.
This won't work for some video chips atm (like Pi's VideoCore) so these are limited
to supported resolutions. Don't try to use "closest" resolutions either, because
those are often bigger than the window size, thus causing out-of-bunds scanout. */
new_mode_parameters.visibleRegion.width = window->w;
new_mode_parameters.visibleRegion.height = window->h;
/* SDL (and DRM, if we look at drmModeModeInfo vrefresh) uses plain integer Hz for
display mode refresh rate, but Vulkan expects higher precision. */
new_mode_parameters.refreshRate = window->current_fullscreen_mode.refresh_rate * 1000;
SDL_zero(display_mode_create_info);
display_mode_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR;
display_mode_create_info.parameters = new_mode_parameters;
result = vkCreateDisplayModeKHR(gpu,
display,
&display_mode_create_info,
NULL, &display_mode);
if (result != VK_SUCCESS) {
SDL_SetError("Vulkan couldn't find a predefined mode for that window size and couldn't create a suitable mode.");
goto clean;
}
}
/* Just in case we get here without a display_mode. */
if (!display_mode) {
SDL_SetError("Vulkan couldn't get a display mode.");
goto clean;
}
/* Get the list of the physical device planes. */
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, NULL);
if (plane_count == 0) {
SDL_SetError("Vulkan can't find any planes.");
goto clean;
}
plane_props = SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * plane_count);
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, plane_props);
/* Iterate on the list of planes of the physical device
to find a plane that matches these criteria:
-It must be compatible with the chosen display + mode.
-It isn't currently bound to another display.
-It supports per-pixel alpha, if possible. */
for (i = 0; i < plane_count; i++) {
uint32_t supported_displays_count = 0;
VkDisplayKHR *supported_displays;
/* See if the plane is compatible with the current display. */
vkGetDisplayPlaneSupportedDisplaysKHR(gpu, i, &supported_displays_count, NULL);
if (supported_displays_count == 0) {
/* This plane doesn't support any displays. Continue to the next plane. */
continue;
}
/* Get the list of displays supported by this plane. */
supported_displays = (VkDisplayKHR *)SDL_malloc(sizeof(VkDisplayKHR) * supported_displays_count);
vkGetDisplayPlaneSupportedDisplaysKHR(gpu, i,
&supported_displays_count, supported_displays);
/* The plane must be bound to the chosen display, or not in use.
If none of these is true, iterate to another plane. */
if (!((plane_props[i].currentDisplay == display) || (plane_props[i].currentDisplay == VK_NULL_HANDLE))) {
continue;
}
/* Iterate the list of displays supported by this plane
in order to find out if the chosen display is among them. */
plane_supports_display = SDL_FALSE;
for (j = 0; j < supported_displays_count; j++) {
if (supported_displays[j] == display) {
plane_supports_display = SDL_TRUE;
break;
}
}
/* Free the list of displays supported by this plane. */
if (supported_displays) {
SDL_free(supported_displays);
}
/* If the display is not supported by this plane, iterate to the next plane. */
if (!plane_supports_display) {
continue;
}
/* Want a plane that supports the alpha mode we have chosen. */
vkGetDisplayPlaneCapabilitiesKHR(gpu, display_mode, i, &plane_caps);
if (plane_caps.supportedAlpha == alpha_mode) {
/* Yep, this plane is alright. */
plane = i;
break;
}
}
/* If we couldn't find an appropriate plane, error out. */
if (plane == UINT32_MAX) {
SDL_SetError("Vulkan couldn't find an appropriate plane.");
goto clean;
}
/********************************************/
/* Let's finally create the Vulkan surface! */
/********************************************/
image_size.width = window->w;
image_size.height = window->h;
SDL_zero(display_plane_surface_create_info);
display_plane_surface_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
display_plane_surface_create_info.displayMode = display_mode;
display_plane_surface_create_info.planeIndex = plane;
display_plane_surface_create_info.imageExtent = image_size;
display_plane_surface_create_info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
display_plane_surface_create_info.alphaMode = alpha_mode;
result = vkCreateDisplayPlaneSurfaceKHR(instance,
&display_plane_surface_create_info,
NULL,
surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateDisplayPlaneSurfaceKHR failed: %s",
SDL_Vulkan_GetResultString(result));
goto clean;
}
ret = SDL_TRUE;
clean:
if (physical_devices) {
SDL_free(physical_devices);
}
if (display_props) {
SDL_free(display_props);
}
if (device_props) {
SDL_free(device_props);
}
if (plane_props) {
SDL_free(plane_props);
}
if (mode_props) {
SDL_free(mode_props);
}
return ret;
}
#endif

View File

@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Manuel Alfayate Corchere <redwindwanderer@gmail.com>.
* Based on Jacob Lifshay's SDL_x11vulkan.c.
*/
#include "SDL_internal.h"
#ifndef SDL_kmsdrm_vulkan_h_
#define SDL_kmsdrm_vulkan_h_
#include "../SDL_vulkan_internal.h"
#include "../SDL_sysvideo.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_KMSDRM)
int KMSDRM_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
void KMSDRM_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
SDL_bool KMSDRM_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names);
SDL_bool KMSDRM_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface);
#endif
#endif /* SDL_kmsdrm_vulkan_h_ */