mirror of
https://github.com/Ryujinx/SDL.git
synced 2025-01-25 21:11:05 +00:00
[Video/KMSDRM]: Add Vulkan support to the KMSDRM backend.
This commit is contained in:
parent
cbe13d232d
commit
f60f8d5d84
|
@ -19,6 +19,7 @@
|
||||||
misrepresented as being the original software.
|
misrepresented as being the original software.
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../../SDL_internal.h"
|
#include "../../SDL_internal.h"
|
||||||
|
|
||||||
#if SDL_VIDEO_DRIVER_KMSDRM
|
#if SDL_VIDEO_DRIVER_KMSDRM
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
#include "SDL_kmsdrmvideo.h"
|
#include "SDL_kmsdrmvideo.h"
|
||||||
#include "SDL_kmsdrmmouse.h"
|
#include "SDL_kmsdrmmouse.h"
|
||||||
#include "SDL_kmsdrmdyn.h"
|
#include "SDL_kmsdrmdyn.h"
|
||||||
|
#include "SDL_assert.h"
|
||||||
|
|
||||||
#include "../../events/SDL_mouse_c.h"
|
#include "../../events/SDL_mouse_c.h"
|
||||||
#include "../../events/default_cursor.h"
|
#include "../../events/default_cursor.h"
|
||||||
|
@ -54,8 +56,10 @@ drm_atomic_movecursor(KMSDRM_CursorData *curdata, uint16_t x, uint16_t y)
|
||||||
if (!dispdata->atomic_req)
|
if (!dispdata->atomic_req)
|
||||||
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
|
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
|
||||||
|
|
||||||
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_X", x - curdata->hot_x);
|
add_plane_property(dispdata->atomic_req,
|
||||||
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_Y", y - curdata->hot_y);
|
dispdata->cursor_plane, "CRTC_X", x - curdata->hot_x);
|
||||||
|
add_plane_property(dispdata->atomic_req,
|
||||||
|
dispdata->cursor_plane, "CRTC_Y", y - curdata->hot_y);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -66,8 +70,9 @@ drm_atomic_movecursor(KMSDRM_CursorData *curdata, uint16_t x, uint16_t y)
|
||||||
|
|
||||||
/* Converts a pixel from straight-alpha [AA, RR, GG, BB], which the SDL cursor surface has,
|
/* Converts a pixel from straight-alpha [AA, RR, GG, BB], which the SDL cursor surface has,
|
||||||
to premultiplied-alpha [AA. AA*RR, AA*GG, AA*BB].
|
to premultiplied-alpha [AA. AA*RR, AA*GG, AA*BB].
|
||||||
These multiplications have to be done with floats instead of uint32_t's, and the resulting values have
|
These multiplications have to be done with floats instead of uint32_t's,
|
||||||
to be converted to be relative to the 0-255 interval, where 255 is 1.00 and anything between 0 and 255 is 0.xx. */
|
and the resulting values have to be converted to be relative to the 0-255 interval,
|
||||||
|
where 255 is 1.00 and anything between 0 and 255 is 0.xx. */
|
||||||
void alpha_premultiply_ARGB8888 (uint32_t *pixel) {
|
void alpha_premultiply_ARGB8888 (uint32_t *pixel) {
|
||||||
|
|
||||||
uint32_t A, R, G, B;
|
uint32_t A, R, G, B;
|
||||||
|
@ -93,35 +98,28 @@ KMSDRM_CreateDefaultCursor(void)
|
||||||
return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
|
return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a GBM cursor from a surface, which means creating a hardware cursor.
|
/* This simply copies over the cursor bitmap from the SDLSurface we receive to the
|
||||||
Most programs use software cursors, but protracker-clone for example uses
|
cursor GBM BO. Setting up the cursor plane, creating the cursor FB BO, etc.. is
|
||||||
an optional hardware cursor. */
|
done in KMSDRM_InitMouse(): when we get here. everything must be ready. */
|
||||||
static SDL_Cursor *
|
static SDL_Cursor *
|
||||||
KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
|
KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
|
||||||
{
|
{
|
||||||
SDL_VideoDevice *dev = SDL_GetVideoDevice();
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
||||||
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
|
|
||||||
KMSDRM_CursorData *curdata;
|
KMSDRM_CursorData *curdata;
|
||||||
SDL_Cursor *cursor;
|
SDL_Cursor *cursor;
|
||||||
uint64_t usable_cursor_w, usable_cursor_h;
|
|
||||||
uint32_t bo_stride, pixel;
|
uint32_t bo_stride, pixel;
|
||||||
uint32_t *buffer = NULL;
|
uint32_t *buffer = NULL;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
/* All code below assumes ARGB8888 format for the cursor surface, like other backends do.
|
/* All code below assumes ARGB8888 format for the cursor surface,
|
||||||
Also, the GBM BO pixels have to be alpha-premultiplied, but the SDL surface we receive has
|
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. */
|
straight-alpha pixels, so we always have to convert. */
|
||||||
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
|
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
|
||||||
SDL_assert(surface->pitch == surface->w * 4);
|
SDL_assert(surface->pitch == surface->w * 4);
|
||||||
|
|
||||||
if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, GBM_FORMAT_ARGB8888,
|
|
||||||
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));
|
cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
|
||||||
if (!cursor) {
|
if (!cursor) {
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
|
@ -134,34 +132,13 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find out what GBM cursor size is recommended by the driver. */
|
|
||||||
if (KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_WIDTH, &usable_cursor_w) ||
|
|
||||||
KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_HEIGHT, &usable_cursor_h))
|
|
||||||
{
|
|
||||||
SDL_SetError("Could not get the recommended GBM cursor size");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usable_cursor_w == 0 || usable_cursor_h == 0) {
|
|
||||||
SDL_SetError("Could not get an usable GBM cursor size");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* hox_x and hot_y are the coordinates of the "tip of the cursor" from it's base. */
|
/* 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_x = hot_x;
|
||||||
curdata->hot_y = hot_y;
|
curdata->hot_y = hot_y;
|
||||||
curdata->w = usable_cursor_w;
|
curdata->w = dispdata->cursor_w;
|
||||||
curdata->h = usable_cursor_h;
|
curdata->h = dispdata->cursor_h;
|
||||||
|
|
||||||
curdata->bo = KMSDRM_gbm_bo_create(viddata->gbm_dev, usable_cursor_w, usable_cursor_h,
|
bo_stride = KMSDRM_gbm_bo_get_stride(dispdata->cursor_bo);
|
||||||
GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
|
||||||
|
|
||||||
if (!curdata->bo) {
|
|
||||||
SDL_SetError("Could not create GBM cursor BO");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
bo_stride = KMSDRM_gbm_bo_get_stride(curdata->bo);
|
|
||||||
bufsize = bo_stride * curdata->h;
|
bufsize = bo_stride * curdata->h;
|
||||||
|
|
||||||
/* Always use a temp buffer: it serves the purpose of storing the
|
/* Always use a temp buffer: it serves the purpose of storing the
|
||||||
|
@ -197,7 +174,7 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
|
||||||
SDL_UnlockSurface(surface);
|
SDL_UnlockSurface(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (KMSDRM_gbm_bo_write(curdata->bo, buffer, bufsize)) {
|
if (KMSDRM_gbm_bo_write(dispdata->cursor_bo, buffer, bufsize)) {
|
||||||
SDL_SetError("Could not write to GBM cursor BO");
|
SDL_SetError("Could not write to GBM cursor BO");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -218,11 +195,9 @@ cleanup:
|
||||||
SDL_free(cursor);
|
SDL_free(cursor);
|
||||||
}
|
}
|
||||||
if (curdata) {
|
if (curdata) {
|
||||||
if (curdata->bo) {
|
|
||||||
KMSDRM_gbm_bo_destroy(curdata->bo);
|
|
||||||
}
|
|
||||||
SDL_free(curdata);
|
SDL_free(curdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +238,8 @@ KMSDRM_ShowCursor(SDL_Cursor * cursor)
|
||||||
and SDL is stored in mouse->cur_cursor. */
|
and SDL is stored in mouse->cur_cursor. */
|
||||||
if (mouse->cur_cursor && mouse->cur_cursor->driverdata) {
|
if (mouse->cur_cursor && mouse->cur_cursor->driverdata) {
|
||||||
if (dispdata && dispdata->cursor_plane) {
|
if (dispdata && dispdata->cursor_plane) {
|
||||||
info.plane = dispdata->cursor_plane; /* The rest of the members are zeroed. */
|
info.plane = dispdata->cursor_plane;
|
||||||
|
/* The rest of the members are zeroed. */
|
||||||
drm_atomic_set_plane_props(&info);
|
drm_atomic_set_plane_props(&info);
|
||||||
if (drm_atomic_commit(display->device, SDL_TRUE))
|
if (drm_atomic_commit(display->device, SDL_TRUE))
|
||||||
return SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
|
return SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
|
||||||
|
@ -288,18 +264,14 @@ KMSDRM_ShowCursor(SDL_Cursor * cursor)
|
||||||
|
|
||||||
curdata = (KMSDRM_CursorData *) cursor->driverdata;
|
curdata = (KMSDRM_CursorData *) cursor->driverdata;
|
||||||
|
|
||||||
if (!curdata || !curdata->bo) {
|
if (!curdata || !dispdata->cursor_bo) {
|
||||||
return SDL_SetError("Cursor not initialized properly.");
|
return SDL_SetError("Cursor not initialized properly.");
|
||||||
}
|
}
|
||||||
|
|
||||||
curdata->crtc_id = dispdata->crtc->crtc->crtc_id;
|
fb = KMSDRM_FBFromBO(video_device, dispdata->cursor_bo);
|
||||||
curdata->plane = dispdata->cursor_plane;
|
|
||||||
curdata->video = video_device;
|
|
||||||
|
|
||||||
fb = KMSDRM_FBFromBO(curdata->video, curdata->bo);
|
|
||||||
|
|
||||||
info.plane = dispdata->cursor_plane;
|
info.plane = dispdata->cursor_plane;
|
||||||
info.crtc_id = curdata->crtc_id;
|
info.crtc_id = dispdata->crtc->crtc->crtc_id;
|
||||||
info.fb_id = fb->fb_id;
|
info.fb_id = fb->fb_id;
|
||||||
info.src_w = curdata->w;
|
info.src_w = curdata->w;
|
||||||
info.src_h = curdata->h;
|
info.src_h = curdata->h;
|
||||||
|
@ -313,39 +285,17 @@ KMSDRM_ShowCursor(SDL_Cursor * cursor)
|
||||||
if (drm_atomic_commit(display->device, SDL_TRUE)) {
|
if (drm_atomic_commit(display->device, SDL_TRUE)) {
|
||||||
return SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
|
return SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unset the cursor from the cursor plane, and ONLY WHEN THAT'S DONE,
|
/* We have destroyed the cursor by now, in KMSDRM_DestroyCursor.
|
||||||
DONE FOR REAL, and not only requested, destroy it by destroying the curso BO.
|
This is only for freeing the SDL_cursor.*/
|
||||||
Destroying the cursor BO is an special an delicate situation,
|
|
||||||
because drm_atomic_set_plane_props() returns immediately, and we DON'T
|
|
||||||
want to get to gbm_bo_destroy() before the prop changes requested
|
|
||||||
in drm_atomic_set_plane_props() have effectively been done. So we
|
|
||||||
issue a BLOCKING atomic_commit here to avoid that situation.
|
|
||||||
REMEMBER you yan issue an atomic_commit whenever you want, and
|
|
||||||
the changes requested until that moment (for any planes, crtcs, etc.)
|
|
||||||
will be done. */
|
|
||||||
static void
|
static void
|
||||||
KMSDRM_FreeCursor(SDL_Cursor * cursor)
|
KMSDRM_FreeCursor(SDL_Cursor * cursor)
|
||||||
{
|
{
|
||||||
KMSDRM_CursorData *curdata = NULL;
|
/* Even if the cursor is not ours, free it. */
|
||||||
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
|
|
||||||
KMSDRM_PlaneInfo info = {0};
|
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
curdata = (KMSDRM_CursorData *) cursor->driverdata;
|
|
||||||
if (video_device && curdata->bo && curdata->plane) {
|
|
||||||
info.plane = curdata->plane; /* The other members are zeroed. */
|
|
||||||
drm_atomic_set_plane_props(&info);
|
|
||||||
/* Wait until the cursor is unset from the cursor plane before destroying it's BO. */
|
|
||||||
if (drm_atomic_commit(video_device, SDL_TRUE)) {
|
|
||||||
SDL_SetError("Failed atomic commit in KMSDRM_FreeCursor.");
|
|
||||||
}
|
|
||||||
KMSDRM_gbm_bo_destroy(curdata->bo);
|
|
||||||
curdata->bo = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Even if the cursor is not ours, free it. */
|
|
||||||
SDL_free(cursor->driverdata);
|
SDL_free(cursor->driverdata);
|
||||||
SDL_free(cursor);
|
SDL_free(cursor);
|
||||||
}
|
}
|
||||||
|
@ -365,6 +315,7 @@ KMSDRM_WarpMouseGlobal(int x, int y)
|
||||||
{
|
{
|
||||||
KMSDRM_CursorData *curdata;
|
KMSDRM_CursorData *curdata;
|
||||||
SDL_Mouse *mouse = SDL_GetMouse();
|
SDL_Mouse *mouse = SDL_GetMouse();
|
||||||
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
||||||
|
|
||||||
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
|
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
|
||||||
/* Update internal mouse position. */
|
/* Update internal mouse position. */
|
||||||
|
@ -372,7 +323,7 @@ KMSDRM_WarpMouseGlobal(int x, int y)
|
||||||
|
|
||||||
/* And now update the cursor graphic position on screen. */
|
/* And now update the cursor graphic position on screen. */
|
||||||
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
|
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
|
||||||
if (curdata->bo) {
|
if (dispdata->cursor_bo) {
|
||||||
if (drm_atomic_movecursor(curdata, x, y)) {
|
if (drm_atomic_movecursor(curdata, x, y)) {
|
||||||
return SDL_SetError("drm_atomic_movecursor() failed.");
|
return SDL_SetError("drm_atomic_movecursor() failed.");
|
||||||
}
|
}
|
||||||
|
@ -382,7 +333,8 @@ KMSDRM_WarpMouseGlobal(int x, int y)
|
||||||
} else {
|
} else {
|
||||||
return SDL_SetError("No mouse or current cursor.");
|
return SDL_SetError("No mouse or current cursor.");
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -392,8 +344,11 @@ KMSDRM_InitMouse(_THIS)
|
||||||
* but there's no point in doing so as there's no multimice support...yet!
|
* but there's no point in doing so as there's no multimice support...yet!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
SDL_VideoDevice *dev = SDL_GetVideoDevice();
|
||||||
|
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
|
||||||
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
||||||
SDL_Mouse *mouse = SDL_GetMouse();
|
SDL_Mouse *mouse = SDL_GetMouse();
|
||||||
|
uint64_t usable_cursor_w, usable_cursor_h;
|
||||||
|
|
||||||
mouse->CreateCursor = KMSDRM_CreateCursor;
|
mouse->CreateCursor = KMSDRM_CreateCursor;
|
||||||
mouse->ShowCursor = KMSDRM_ShowCursor;
|
mouse->ShowCursor = KMSDRM_ShowCursor;
|
||||||
|
@ -402,20 +357,96 @@ KMSDRM_InitMouse(_THIS)
|
||||||
mouse->WarpMouse = KMSDRM_WarpMouse;
|
mouse->WarpMouse = KMSDRM_WarpMouse;
|
||||||
mouse->WarpMouseGlobal = KMSDRM_WarpMouseGlobal;
|
mouse->WarpMouseGlobal = KMSDRM_WarpMouseGlobal;
|
||||||
|
|
||||||
/* Init cursor plane, if we haven't yet. */
|
/***************************************************************************/
|
||||||
|
/* REMEMBER TO BE SURE OF UNDOING ALL THESE STEPS PROPERLY BEFORE CALLING */
|
||||||
|
/* gbm_device_destroy, OR YOU WON'T BE ABLE TO CREATE A NEW ONE (ERROR -13 */
|
||||||
|
/* ON gbm_create_device). */
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
|
/* 1- Init cursor plane, if we haven't yet. */
|
||||||
if (!dispdata->cursor_plane) {
|
if (!dispdata->cursor_plane) {
|
||||||
setup_plane(_this, &(dispdata->cursor_plane), DRM_PLANE_TYPE_CURSOR);
|
setup_plane(_this, &(dispdata->cursor_plane), DRM_PLANE_TYPE_CURSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 2- Create the cursor GBM BO, if we haven't yet. */
|
||||||
|
if (!dispdata->cursor_bo) {
|
||||||
|
|
||||||
|
if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, GBM_FORMAT_ARGB8888,
|
||||||
|
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
|
||||||
|
{
|
||||||
|
SDL_SetError("Unsupported pixel format for cursor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_WIDTH, &usable_cursor_w) ||
|
||||||
|
KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_HEIGHT, &usable_cursor_h))
|
||||||
|
{
|
||||||
|
SDL_SetError("Could not get the recommended GBM cursor size");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usable_cursor_w == 0 || usable_cursor_h == 0) {
|
||||||
|
SDL_SetError("Could not get an usable GBM cursor size");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispdata->cursor_w = usable_cursor_w;
|
||||||
|
dispdata->cursor_h = usable_cursor_h;
|
||||||
|
|
||||||
|
dispdata->cursor_bo = KMSDRM_gbm_bo_create(viddata->gbm_dev,
|
||||||
|
usable_cursor_w, usable_cursor_h,
|
||||||
|
GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
||||||
|
|
||||||
|
if (!dispdata->cursor_bo) {
|
||||||
|
SDL_SetError("Could not create GBM cursor BO");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SDL expects to set the default cursor on screen when we init the mouse. */
|
||||||
SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor());
|
SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor());
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (dispdata->cursor_bo) {
|
||||||
|
KMSDRM_gbm_bo_destroy(dispdata->cursor_bo);
|
||||||
|
dispdata->cursor_bo = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
KMSDRM_QuitMouse(_THIS)
|
KMSDRM_DeinitMouse(_THIS)
|
||||||
{
|
{
|
||||||
/* Free the plane on which the cursor was being shown. */
|
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
|
||||||
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
|
||||||
free_plane(&dispdata->cursor_plane);
|
KMSDRM_PlaneInfo info = {0};
|
||||||
|
|
||||||
|
/*******************************************/
|
||||||
|
/* UNDO WHAT WE DID IN KMSDRM_InitMouse(). */
|
||||||
|
/*******************************************/
|
||||||
|
|
||||||
|
/* 1- Destroy the curso GBM BO. */
|
||||||
|
if (video_device && dispdata->cursor_bo) {
|
||||||
|
/* Unsethe the cursor BO from the cursor plane.
|
||||||
|
(The other members of the plane info are zeroed). */
|
||||||
|
info.plane = dispdata->cursor_plane;
|
||||||
|
drm_atomic_set_plane_props(&info);
|
||||||
|
/* Wait until the cursor is unset from the cursor plane
|
||||||
|
before destroying it's BO. */
|
||||||
|
if (drm_atomic_commit(video_device, SDL_TRUE)) {
|
||||||
|
SDL_SetError("Failed atomic commit in KMSDRM_DenitMouse.");
|
||||||
|
}
|
||||||
|
/* ..and finally destroy the cursor DRM BO! */
|
||||||
|
KMSDRM_gbm_bo_destroy(dispdata->cursor_bo);
|
||||||
|
dispdata->cursor_bo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2- Free the cursor plane, on which the cursor was being shown. */
|
||||||
|
if (dispdata->cursor_plane) {
|
||||||
|
free_plane(&dispdata->cursor_plane);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called when a mouse motion event occurs */
|
/* This is called when a mouse motion event occurs */
|
||||||
|
@ -429,11 +460,13 @@ KMSDRM_MoveCursor(SDL_Cursor * cursor)
|
||||||
That's why we move the cursor graphic ONLY. */
|
That's why we move the cursor graphic ONLY. */
|
||||||
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
|
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
|
||||||
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
|
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
|
||||||
|
|
||||||
/* Some programs expect cursor movement even while they don't do SwapWindow() calls,
|
/* Some programs expect cursor movement even while they don't do SwapWindow() calls,
|
||||||
and since we ride on the atomic_commit() in SwapWindow() for cursor movement,
|
and since we ride on the atomic_commit() in SwapWindow() for cursor movement,
|
||||||
cursor won't move in these situations. We could do an atomic_commit() for each
|
cursor won't move in these situations. We could do an atomic_commit() here
|
||||||
cursor movement request, but it cripples the movement to 30FPS, so a future solution
|
for each cursor movement request, but it cripples the movement to 30FPS,
|
||||||
is needed. SDLPoP "QUIT?" menu is an example of this situation. */
|
so a future solution is needed. SDLPoP "QUIT?" menu is an example of this
|
||||||
|
situation. */
|
||||||
|
|
||||||
if (drm_atomic_movecursor(curdata, mouse->x, mouse->y)) {
|
if (drm_atomic_movecursor(curdata, mouse->x, mouse->y)) {
|
||||||
SDL_SetError("drm_atomic_movecursor() failed.");
|
SDL_SetError("drm_atomic_movecursor() failed.");
|
||||||
|
|
|
@ -33,19 +33,13 @@
|
||||||
/* Driverdata with driver-side info about the cursor. */
|
/* Driverdata with driver-side info about the cursor. */
|
||||||
typedef struct _KMSDRM_CursorData
|
typedef struct _KMSDRM_CursorData
|
||||||
{
|
{
|
||||||
struct gbm_bo *bo;
|
|
||||||
struct plane *plane;
|
|
||||||
uint32_t crtc_id;
|
|
||||||
uint16_t hot_x, hot_y;
|
uint16_t hot_x, hot_y;
|
||||||
uint16_t w, h;
|
uint16_t w, h;
|
||||||
/* The video devide implemented on SDL_kmsdrmvideo.c
|
|
||||||
* to be used as _THIS pointer in SDL_kmsdrmvideo.c
|
|
||||||
* functions that need it. */
|
|
||||||
SDL_VideoDevice *video;
|
|
||||||
} KMSDRM_CursorData;
|
} KMSDRM_CursorData;
|
||||||
|
|
||||||
extern void KMSDRM_InitMouse(_THIS);
|
extern void KMSDRM_InitMouse(_THIS);
|
||||||
extern void KMSDRM_QuitMouse(_THIS);
|
extern void KMSDRM_DeinitMouse(_THIS);
|
||||||
|
|
||||||
#endif /* SDL_KMSDRM_mouse_h_ */
|
#endif /* SDL_KMSDRM_mouse_h_ */
|
||||||
|
|
||||||
|
|
|
@ -59,11 +59,24 @@ KMSDRM_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
KMSDRM_GLES_LoadLibrary(_THIS, const char *path) {
|
KMSDRM_GLES_LoadLibrary(_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)((SDL_VideoData *)_this->driverdata)->gbm_dev;
|
NativeDisplayType display = (NativeDisplayType)((SDL_VideoData *)_this->driverdata)->gbm_dev;
|
||||||
return SDL_EGL_LoadLibrary(_this, path, display, EGL_PLATFORM_GBM_MESA);
|
return SDL_EGL_LoadLibrary(_this, path, display, EGL_PLATFORM_GBM_MESA);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
KMSDRM_GLES_UnloadLibrary(_THIS) {
|
||||||
|
/* As with KMSDRM_GLES_LoadLibrary(), we define our own unloading function so
|
||||||
|
we manually unload the library whenever we want. */
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_EGL_CreateContext_impl(KMSDRM)
|
SDL_EGL_CreateContext_impl(KMSDRM)
|
||||||
|
@ -94,6 +107,7 @@ static EGLSyncKHR create_fence(int fd, _THIS)
|
||||||
EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd,
|
EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd,
|
||||||
EGL_NONE,
|
EGL_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
EGLSyncKHR fence = _this->egl_data->eglCreateSyncKHR
|
EGLSyncKHR fence = _this->egl_data->eglCreateSyncKHR
|
||||||
(_this->egl_data->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attrib_list);
|
(_this->egl_data->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attrib_list);
|
||||||
|
|
||||||
|
@ -342,16 +356,6 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
|
||||||
{
|
{
|
||||||
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
|
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
|
||||||
|
|
||||||
/* Get the EGL context, now that SDL_CreateRenderer() has already been called,
|
|
||||||
and call eglMakeCurrent() on it and the EGL surface. */
|
|
||||||
#if SDL_VIDEO_OPENGL_EGL
|
|
||||||
if (windata->egl_context_pending) {
|
|
||||||
EGLContext egl_context = (EGLContext)SDL_GL_GetCurrentContext();
|
|
||||||
SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
|
|
||||||
windata->egl_context_pending = SDL_FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (windata->swap_window == NULL) {
|
if (windata->swap_window == NULL) {
|
||||||
/* We want the fenced version by default, but it needs extensions. */
|
/* We want the fenced version by default, but it needs extensions. */
|
||||||
if ( (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) ||
|
if ( (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) ||
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
/* OpenGLES functions */
|
/* OpenGLES functions */
|
||||||
#define KMSDRM_GLES_GetAttribute SDL_EGL_GetAttribute
|
#define KMSDRM_GLES_GetAttribute SDL_EGL_GetAttribute
|
||||||
#define KMSDRM_GLES_GetProcAddress SDL_EGL_GetProcAddress
|
#define KMSDRM_GLES_GetProcAddress SDL_EGL_GetProcAddress
|
||||||
#define KMSDRM_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
|
|
||||||
#define KMSDRM_GLES_DeleteContext SDL_EGL_DeleteContext
|
#define KMSDRM_GLES_DeleteContext SDL_EGL_DeleteContext
|
||||||
#define KMSDRM_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
|
#define KMSDRM_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -85,6 +85,8 @@ typedef struct SDL_VideoData
|
||||||
{
|
{
|
||||||
int devindex; /* device index that was passed on creation */
|
int devindex; /* device index that was passed on creation */
|
||||||
int drm_fd; /* DRM file desc */
|
int drm_fd; /* DRM file desc */
|
||||||
|
char devpath[32]; /* DRM dev path. */
|
||||||
|
|
||||||
struct gbm_device *gbm_dev;
|
struct gbm_device *gbm_dev;
|
||||||
|
|
||||||
SDL_Window **windows;
|
SDL_Window **windows;
|
||||||
|
@ -117,6 +119,7 @@ typedef struct connector {
|
||||||
typedef struct SDL_DisplayData
|
typedef struct SDL_DisplayData
|
||||||
{
|
{
|
||||||
drmModeModeInfo mode;
|
drmModeModeInfo mode;
|
||||||
|
drmModeModeInfo preferred_mode;
|
||||||
uint32_t atomic_flags;
|
uint32_t atomic_flags;
|
||||||
|
|
||||||
plane *display_plane;
|
plane *display_plane;
|
||||||
|
@ -141,6 +144,14 @@ typedef struct SDL_DisplayData
|
||||||
dumb_buffer *dumb_buffer;
|
dumb_buffer *dumb_buffer;
|
||||||
|
|
||||||
SDL_bool modeset_pending;
|
SDL_bool modeset_pending;
|
||||||
|
SDL_bool gbm_init;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
uint64_t cursor_w, cursor_h;
|
||||||
|
|
||||||
} SDL_DisplayData;
|
} SDL_DisplayData;
|
||||||
|
|
||||||
|
@ -167,12 +178,9 @@ typedef struct SDL_WindowData
|
||||||
int32_t output_h;
|
int32_t output_h;
|
||||||
int32_t output_x;
|
int32_t output_x;
|
||||||
|
|
||||||
/* This is for deferred eglMakeCurrent() call: we can't call it until
|
|
||||||
the EGL context is available, but we need the EGL surface sooner. */
|
|
||||||
SDL_bool egl_context_pending;
|
|
||||||
|
|
||||||
/* This dictates what approach we'll use for SwapBuffers. */
|
/* This dictates what approach we'll use for SwapBuffers. */
|
||||||
int (*swap_window)(_THIS, SDL_Window * window);
|
int (*swap_window)(_THIS, SDL_Window * window);
|
||||||
|
|
||||||
} SDL_WindowData;
|
} SDL_WindowData;
|
||||||
|
|
||||||
typedef struct SDL_DisplayModeData
|
typedef struct SDL_DisplayModeData
|
||||||
|
|
395
src/video/kmsdrm/SDL_kmsdrmvulkan.c
Normal file
395
src/video/kmsdrm/SDL_kmsdrmvulkan.c
Normal file
|
@ -0,0 +1,395 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author Manuel Alfayate Corchere <redwindwanderer@gmail.com>.
|
||||||
|
* Based on Jacob Lifshay's SDL_x11vulkan.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../SDL_internal.h"
|
||||||
|
|
||||||
|
#if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_KMSDRM
|
||||||
|
|
||||||
|
#include "SDL_kmsdrmvideo.h"
|
||||||
|
#include "SDL_kmsdrmdyn.h"
|
||||||
|
#include "SDL_assert.h"
|
||||||
|
|
||||||
|
#include "SDL_loadso.h"
|
||||||
|
#include "SDL_kmsdrmvulkan.h"
|
||||||
|
#include "SDL_syswm.h"
|
||||||
|
#include "sys/ioctl.h"
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__)
|
||||||
|
#define DEFAULT_VULKAN "libvulkan.so"
|
||||||
|
#else
|
||||||
|
#define DEFAULT_VULKAN "libvulkan.so.1"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int KMSDRM_Vulkan_LoadLibrary(_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)
|
||||||
|
path = SDL_getenv("SDL_VULKAN_LIBRARY");
|
||||||
|
if(!path)
|
||||||
|
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)
|
||||||
|
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(_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(_THIS,
|
||||||
|
SDL_Window *window,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KMSDRM_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
|
||||||
|
{
|
||||||
|
if (w) {
|
||||||
|
*w = window->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h) {
|
||||||
|
*h = window->h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* 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(_THIS,
|
||||||
|
SDL_Window *window,
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR *surface)
|
||||||
|
{
|
||||||
|
VkPhysicalDevice gpu;
|
||||||
|
uint32_t gpu_count;
|
||||||
|
uint32_t display_count;
|
||||||
|
uint32_t mode_count;
|
||||||
|
uint32_t plane_count;
|
||||||
|
|
||||||
|
VkPhysicalDevice *physical_devices = NULL;
|
||||||
|
VkDisplayPropertiesKHR *displays_props = NULL;
|
||||||
|
VkDisplayModePropertiesKHR *modes_props = NULL;
|
||||||
|
VkDisplayPlanePropertiesKHR *planes_props = NULL;
|
||||||
|
|
||||||
|
VkDisplayModeCreateInfoKHR display_mode_create_info;
|
||||||
|
VkDisplaySurfaceCreateInfoKHR display_plane_surface_create_info;
|
||||||
|
|
||||||
|
VkExtent2D image_size;
|
||||||
|
VkDisplayModeKHR display_mode;
|
||||||
|
VkDisplayModePropertiesKHR display_mode_props = {0};
|
||||||
|
|
||||||
|
VkResult result;
|
||||||
|
SDL_bool ret = SDL_FALSE;
|
||||||
|
|
||||||
|
/* 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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 = malloc(sizeof(VkPhysicalDevice) * gpu_count);
|
||||||
|
vkEnumeratePhysicalDevices(instance, &gpu_count, physical_devices);
|
||||||
|
|
||||||
|
/* For now, just grab the first physical device (gpu = physical_device in vkcube example).*/
|
||||||
|
/* TODO What happens on video systems with multiple display ports like the Rpi4 ? */
|
||||||
|
gpu = physical_devices[0];
|
||||||
|
|
||||||
|
/* Get the display count of the phsysical device. */
|
||||||
|
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. */
|
||||||
|
displays_props = (VkDisplayPropertiesKHR *) malloc(display_count * sizeof(*displays_props));
|
||||||
|
vkGetPhysicalDeviceDisplayPropertiesKHR(gpu,
|
||||||
|
&display_count,
|
||||||
|
displays_props);
|
||||||
|
|
||||||
|
/* Get the videomode count for the first display. */
|
||||||
|
/* TODO What happens on video systems with multiple display ports like the Rpi4 ? */
|
||||||
|
vkGetDisplayModePropertiesKHR(gpu,
|
||||||
|
displays_props[0].display,
|
||||||
|
&mode_count, NULL);
|
||||||
|
|
||||||
|
if (mode_count == 0) {
|
||||||
|
SDL_SetError("Vulkan can't find any video modes for display %i (%s)\n", 0,
|
||||||
|
displays_props[0].displayName);
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the props of the videomodes for the first display. */
|
||||||
|
modes_props = (VkDisplayModePropertiesKHR *) malloc(mode_count * sizeof(*modes_props));
|
||||||
|
vkGetDisplayModePropertiesKHR(gpu,
|
||||||
|
displays_props[0].display,
|
||||||
|
&mode_count, modes_props);
|
||||||
|
|
||||||
|
/* Get the planes count of the physical device. */
|
||||||
|
/* TODO: find out if we need other planes. */
|
||||||
|
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, NULL);
|
||||||
|
if (plane_count == 0) {
|
||||||
|
SDL_SetError("Vulkan can't find any planes.");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the props of the planes for the physical device. */
|
||||||
|
planes_props = malloc(sizeof(VkDisplayPlanePropertiesKHR) * plane_count);
|
||||||
|
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, planes_props);
|
||||||
|
|
||||||
|
/* Get a video mode matching the window size.
|
||||||
|
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 (int i = 0; i < mode_count; i++) {
|
||||||
|
if (modes_props[i].parameters.visibleRegion.width <= window->w &&
|
||||||
|
modes_props[i].parameters.visibleRegion.height <= window->h)
|
||||||
|
{
|
||||||
|
display_mode_props = modes_props[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display_mode_props.parameters.visibleRegion.width == 0
|
||||||
|
|| display_mode_props.parameters.visibleRegion.height == 0)
|
||||||
|
{
|
||||||
|
SDL_SetError("Vulkan can't find a proper display mode for the window size.");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have the props of the display mode, but we need an actual display mode. */
|
||||||
|
display_mode_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR;
|
||||||
|
display_mode_create_info.parameters = display_mode_props.parameters;
|
||||||
|
result = vkCreateDisplayModeKHR(gpu,
|
||||||
|
displays_props[0].display,
|
||||||
|
&display_mode_create_info,
|
||||||
|
NULL, &display_mode);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
SDL_SetError("Vulkan can't create the display mode.");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let's finally create the Vulkan surface! */
|
||||||
|
|
||||||
|
image_size.width = window->w;
|
||||||
|
image_size.height = window->h;
|
||||||
|
|
||||||
|
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 = 0; /* For now, simply use the first plane. */
|
||||||
|
display_plane_surface_create_info.imageExtent = image_size;
|
||||||
|
|
||||||
|
result = vkCreateDisplayPlaneSurfaceKHR(instance,
|
||||||
|
&display_plane_surface_create_info,
|
||||||
|
NULL,
|
||||||
|
surface);
|
||||||
|
|
||||||
|
if(result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
SDL_SetError("vkCreateKMSDRMSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SDL_TRUE;
|
||||||
|
|
||||||
|
clean:
|
||||||
|
if (physical_devices)
|
||||||
|
free (physical_devices);
|
||||||
|
if (displays_props)
|
||||||
|
free (displays_props);
|
||||||
|
if (planes_props)
|
||||||
|
free (planes_props);
|
||||||
|
if (modes_props)
|
||||||
|
free (modes_props);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* vim: set ts=4 sw=4 expandtab: */
|
53
src/video/kmsdrm/SDL_kmsdrmvulkan.h
Normal file
53
src/video/kmsdrm/SDL_kmsdrmvulkan.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author Manuel Alfayate Corchere <redwindwanderer@gmail.com>.
|
||||||
|
* Based on Jacob Lifshay's SDL_x11vulkan.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../SDL_internal.h"
|
||||||
|
|
||||||
|
#ifndef SDL_kmsdrmvulkan_h_
|
||||||
|
#define SDL_kmsdrmvulkan_h_
|
||||||
|
|
||||||
|
#include "../SDL_vulkan_internal.h"
|
||||||
|
#include "../SDL_sysvideo.h"
|
||||||
|
|
||||||
|
#if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_KMSDRM
|
||||||
|
|
||||||
|
int KMSDRM_Vulkan_LoadLibrary(_THIS, const char *path);
|
||||||
|
void KMSDRM_Vulkan_UnloadLibrary(_THIS);
|
||||||
|
SDL_bool KMSDRM_Vulkan_GetInstanceExtensions(_THIS,
|
||||||
|
SDL_Window *window,
|
||||||
|
unsigned *count,
|
||||||
|
const char **names);
|
||||||
|
void KMSDRM_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h);
|
||||||
|
SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
|
||||||
|
SDL_Window *window,
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR *surface);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SDL_kmsdrmvulkan_h_ */
|
||||||
|
|
||||||
|
/* vi: set ts=4 sw=4 expandtab: */
|
Loading…
Reference in a new issue