[KMS/DRM] Prevent creating another default cursor everytime a window is created. Other fixes and cleanups.

This commit is contained in:
Manuel Alfayate Corchete 2021-01-08 13:14:42 +01:00
parent 7032539785
commit cef1bd0639
7 changed files with 173 additions and 516 deletions

View File

@ -40,6 +40,21 @@ static void KMSDRM_FreeCursor(SDL_Cursor * cursor);
static void KMSDRM_WarpMouse(SDL_Window * window, int x, int y); static void KMSDRM_WarpMouse(SDL_Window * window, int x, int y);
static int KMSDRM_WarpMouseGlobal(int x, int y); static int KMSDRM_WarpMouseGlobal(int x, int y);
/**************************************************************************************/
/* 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 succesfully, that cursor becomes mouse->cur_cursor */
/* and mouse->cursor_shown is 1. */
/**************************************************************************************/
/**********************************/ /**********************************/
/* Atomic helper functions block. */ /* Atomic helper functions block. */
/**********************************/ /**********************************/
@ -98,8 +113,9 @@ 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);
} }
/* This simply gets the cursor soft-buffer ready. We don't copy it to a GBO BO until ShowCursor() /* This simply gets the cursor soft-buffer ready. We don't copy it to a GBO BO
because the cusor GBM BO (living in dispata) is destroyed and recreated when we recreate windows, etc. */ until ShowCursor() because the cusor GBM BO (living in dispata) is destroyed
and recreated when we recreate windows, etc. */
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)
{ {
@ -204,20 +220,16 @@ KMSDRM_InitCursor()
KMSDRM_ShowCursor(mouse->cur_cursor); KMSDRM_ShowCursor(mouse->cur_cursor);
} }
/* Show the specified cursor, or hide if cursor is NULL. /* Show the specified cursor, or hide if cursor is NULL or has no focus. */
cur_cursor is the current cursor, and cursor is the new cursor.
A cursor is displayed on a display, so we have to add a pointer to dispdata
to the driverdata
*/
static int static int
KMSDRM_ShowCursor(SDL_Cursor * cursor) KMSDRM_ShowCursor(SDL_Cursor * cursor)
{ {
SDL_VideoDevice *video_device = SDL_GetVideoDevice(); SDL_VideoDevice *video_device = SDL_GetVideoDevice();
//SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata); //SDL_VideoData *viddata = ((SDL_VideoData *)video_device->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
SDL_Mouse *mouse; SDL_Mouse *mouse;
KMSDRM_CursorData *curdata; KMSDRM_CursorData *curdata;
SDL_VideoDisplay *display = NULL;
SDL_DisplayData *dispdata = NULL;
KMSDRM_FBInfo *fb; KMSDRM_FBInfo *fb;
KMSDRM_PlaneInfo info = {0}; KMSDRM_PlaneInfo info = {0};
@ -234,41 +246,28 @@ KMSDRM_ShowCursor(SDL_Cursor * cursor)
return SDL_SetError("No mouse."); return SDL_SetError("No mouse.");
} }
if (mouse->focus) { /*********************************************************/
display = SDL_GetDisplayForWindow(mouse->focus); /* Hide cursor if it's NULL or it has no focus(=winwow). */
if (display) { /*********************************************************/
dispdata = (SDL_DisplayData*) display->driverdata; if (!cursor || !mouse->focus) {
} if (dispdata->cursor_plane) {
} /* Hide the drm cursor with no more considerations because
SDL_VideoQuit() takes us here after disabling the mouse
/**********************************/ so there is no mouse->cur_cursor by now. */
/* if cursor == NULL, HIDE cursor */
/**********************************/
if (!cursor) {
/* Hide CURRENT cursor, a cursor that is already on screen
and SDL is stored in mouse->cur_cursor. */
if (mouse->cur_cursor && mouse->cur_cursor->driverdata) {
if (dispdata && dispdata->cursor_plane) {
info.plane = dispdata->cursor_plane; info.plane = dispdata->cursor_plane;
/* The rest of the members are zeroed. */ /* The rest of the members are zeroed, so this takes away the cursor
from the cursor plane. */
drm_atomic_set_plane_props(&info); drm_atomic_set_plane_props(&info);
if (drm_atomic_commit(display->device, SDL_TRUE, SDL_FALSE)) if (drm_atomic_commit(video_device, SDL_TRUE, SDL_FALSE)) {
return SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor."); ret = SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
} }
return 0;
} }
return SDL_SetError("Couldn't find cursor to hide."); return ret;
} }
/************************************************/ /************************************************/
/* If cursor != NULL, DO show cursor on display */ /* If cursor != NULL, DO show cursor on display */
/************************************************/ /************************************************/
if (!display) {
return SDL_SetError("Could not get display for mouse.");
}
if (!dispdata) {
return SDL_SetError("Could not get display driverdata.");
}
if (!dispdata->cursor_plane) { if (!dispdata->cursor_plane) {
return SDL_SetError("Hardware cursor plane not initialized."); return SDL_SetError("Hardware cursor plane not initialized.");
} }
@ -279,7 +278,8 @@ KMSDRM_ShowCursor(SDL_Cursor * cursor)
return SDL_SetError("Cursor not initialized properly."); return SDL_SetError("Cursor not initialized properly.");
} }
/* Prepare a buffer we can dump to our GBM BO (different size, alpha premultiplication...) */ /* Prepare a buffer we can dump to our GBM BO (different
size, alpha premultiplication...) */
bo_stride = KMSDRM_gbm_bo_get_stride(dispdata->cursor_bo); bo_stride = KMSDRM_gbm_bo_get_stride(dispdata->cursor_bo);
bufsize = bo_stride * curdata->h; bufsize = bo_stride * curdata->h;
@ -315,8 +315,8 @@ KMSDRM_ShowCursor(SDL_Cursor * cursor)
info.plane = dispdata->cursor_plane; info.plane = dispdata->cursor_plane;
info.crtc_id = dispdata->crtc->crtc->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 = dispdata->cursor_w;
info.src_h = curdata->h; info.src_h = dispdata->cursor_h;
info.crtc_x = mouse->x - curdata->hot_x; info.crtc_x = mouse->x - curdata->hot_x;
info.crtc_y = mouse->y - curdata->hot_y; info.crtc_y = mouse->y - curdata->hot_y;
info.crtc_w = curdata->w; info.crtc_w = curdata->w;
@ -324,7 +324,7 @@ KMSDRM_ShowCursor(SDL_Cursor * cursor)
drm_atomic_set_plane_props(&info); drm_atomic_set_plane_props(&info);
if (drm_atomic_commit(display->device, SDL_TRUE, SDL_FALSE)) { if (drm_atomic_commit(video_device, SDL_TRUE, SDL_FALSE)) {
ret = SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor."); ret = SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
goto cleanup; goto cleanup;
} }
@ -339,8 +339,7 @@ cleanup:
return ret; return ret;
} }
/* We have destroyed the cursor by now, in KMSDRM_DestroyCursor. /* This is only for freeing the SDL_cursor.*/
This is only for freeing the SDL_cursor.*/
static void static void
KMSDRM_FreeCursor(SDL_Cursor * cursor) KMSDRM_FreeCursor(SDL_Cursor * cursor)
{ {
@ -398,13 +397,40 @@ KMSDRM_WarpMouseGlobal(int x, int y)
return 0; return 0;
} }
/* UNDO WHAT WE DID IN KMSDRM_InitMouse(). */
void
KMSDRM_DeinitMouse(_THIS)
{
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
KMSDRM_PlaneInfo info = {0};
SDL_Mouse *mouse = SDL_GetMouse();
/* 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_FALSE)) {
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);
}
}
void void
KMSDRM_InitMouse(_THIS) KMSDRM_InitMouse(_THIS)
{ {
/* FIXME: Using UDEV it should be possible to scan all mice
* but there's no point in doing so as there's no multimice support...yet!
*/
SDL_VideoDevice *dev = SDL_GetVideoDevice(); SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata); SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
@ -420,7 +446,7 @@ KMSDRM_InitMouse(_THIS)
/***************************************************************************/ /***************************************************************************/
/* REMEMBER TO BE SURE OF UNDOING ALL THESE STEPS PROPERLY BEFORE CALLING */ /* 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 */ /* gbm_device_destroy, OR YOU WON'T BE ABLE TO CREATE A NEW ONE (ERROR -13 */
/* ON gbm_create_device). */ /* on gbm_create_device). */
/***************************************************************************/ /***************************************************************************/
/* 1- Init cursor plane, if we haven't yet. */ /* 1- Init cursor plane, if we haven't yet. */
@ -460,8 +486,16 @@ KMSDRM_InitMouse(_THIS)
} }
} }
/* SDL expects to set the default cursor on screen when we init the mouse. */ /* SDL expects to set the default cursor on screen when we init the mouse,
but since we have moved the KMSDRM_InitMouse() call to KMSDRM_CreateWindow(),
we end up calling KMSDRM_InitMouse() every time we create a window, so we
have to prevent this from being done every time a new window is created.
If we don't, new default cursors would stack up on mouse->cursors and SDL
would have to hide and delete them at quit, not to mention the memory leak... */
if(dispdata->set_default_cursor_pending) {
SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor()); SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor());
dispdata->set_default_cursor_pending = SDL_FALSE;
}
return; return;
@ -472,40 +506,6 @@ cleanup:
} }
} }
void
KMSDRM_DeinitMouse(_THIS)
{
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
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_FALSE)) {
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 */
static void static void
KMSDRM_MoveCursor(SDL_Cursor * cursor) KMSDRM_MoveCursor(SDL_Cursor * cursor)

View File

@ -287,7 +287,8 @@ KMSDRM_GLES_SwapWindowDoubleBuffered(_THIS, SDL_Window * window)
/**********************************************************************************/ /**********************************************************************************/
/* In double-buffer mode, atomic_commit will always be synchronous/blocking (ie: */ /* In double-buffer mode, atomic_commit will always be synchronous/blocking (ie: */
/* won't return until the requested changes are really done). */ /* Also, there's no need to fence KMS or the GPU, because we won't be entering */ /* won't return until the requested changes are really done). */
/* Also, there's no need to fence KMS or the GPU, because we won't be entering */
/* game loop again (hence not building or executing a new cmdstring) until */ /* game loop again (hence not building or executing a new cmdstring) until */
/* pageflip is done, so we don't need to protect the KMS/GPU access to the buffer.*/ /* pageflip is done, so we don't need to protect the KMS/GPU access to the buffer.*/
/**********************************************************************************/ /**********************************************************************************/

View File

@ -57,6 +57,8 @@
#define KMSDRM_DRI_PATH "/dev/dri/" #define KMSDRM_DRI_PATH "/dev/dri/"
static int set_client_caps (int fd) static int set_client_caps (int fd)
{ {
if (KMSDRM_drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1)) { if (KMSDRM_drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1)) {
@ -164,161 +166,6 @@ get_driindex(void)
return -ENOENT; return -ENOENT;
} }
#if 0
/**********************/
/* DUMB BUFFER Block. */
/**********************/
/* Create a dumb buffer, mmap the dumb buffer and fill it with pixels, */
/* then create a KMS framebuffer wrapping the dumb buffer. */
static dumb_buffer *KMSDRM_CreateDumbBuffer(_THIS)
{
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
struct drm_mode_create_dumb create;
struct drm_mode_map_dumb map;
struct drm_mode_destroy_dumb destroy;
dumb_buffer *ret = SDL_calloc(1, sizeof(*ret));
if (!ret) {
SDL_OutOfMemory();
return NULL;
}
/*
* The create ioctl uses the combination of depth and bpp to infer
* a format; 24/32 refers to DRM_FORMAT_XRGB8888 as defined in
* the drm_fourcc.h header. These arguments are the same as given
* to drmModeAddFB, which has since been superseded by
* drmModeAddFB2 as the latter takes an explicit format token.
*
* We only specify these arguments; the driver calculates the
* pitch (also known as stride or row length) and total buffer size
* for us, also returning us the GEM handle.
*/
create = (struct drm_mode_create_dumb) {
.width = dispdata->mode.hdisplay,
.height = dispdata->mode.vdisplay,
.bpp = 32,
};
if (KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)) {
SDL_SetError("failed to create dumb buffer\n");
goto err;
}
ret->gem_handles[0] = create.handle;
ret->format = DRM_FORMAT_XRGB8888;
ret->modifier = DRM_FORMAT_MOD_LINEAR;
ret->width = create.width;
ret->height = create.height;
ret->pitches[0] = create.pitch;
/*
* In order to map the buffer, we call an ioctl specific to the buffer
* type, which returns us a fake offset to use with the mmap syscall.
* mmap itself then works as you expect.
*
* Note this means it is not possible to map arbitrary offsets of
* buffers without specifically requesting it from the kernel.
*/
map = (struct drm_mode_map_dumb) {
.handle = ret->gem_handles[0],
};
if (KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map)) {
SDL_SetError("failed to get mmap offset for the dumb buffer.");
goto err_dumb;
}
ret->dumb.mem = mmap(NULL, create.size, PROT_WRITE, MAP_SHARED,
viddata->drm_fd, map.offset);
if (ret->dumb.mem == MAP_FAILED) {
SDL_SetError("failed to get mmap offset for the dumb buffer.");
goto err_dumb;
}
ret->dumb.size = create.size;
return ret;
err_dumb:
destroy = (struct drm_mode_destroy_dumb) { .handle = create.handle };
KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
err:
SDL_free(ret);
return NULL;
}
static void
KMSDRM_DestroyDumbBuffer(_THIS, dumb_buffer **buffer)
{
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
struct drm_mode_destroy_dumb destroy = {
.handle = (*buffer)->gem_handles[0],
};
KMSDRM_drmModeRmFB(viddata->drm_fd, (*buffer)->fb_id);
munmap((*buffer)->dumb.mem, (*buffer)->dumb.size);
KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
free(*buffer);
*buffer = NULL;
}
/* Using the CPU mapping, fill the dumb buffer with black pixels. */
static void
KMSDRM_FillDumbBuffer(dumb_buffer *buffer)
{
unsigned int x, y;
for (y = 0; y < buffer->height; y++) {
uint32_t *pix = (uint32_t *) ((uint8_t *) buffer->dumb.mem + (y * buffer->pitches[0]));
for (x = 0; x < buffer->width; x++) {
*pix++ = (0x00000000);
}
}
}
static dumb_buffer *KMSDRM_CreateBuffer(_THIS)
{
dumb_buffer *ret;
int err;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
ret = KMSDRM_CreateDumbBuffer(_this);
if (!ret)
return NULL;
/*
* Wrap our GEM buffer in a KMS framebuffer, so we can then attach it
* to a plane. Here's where we get out fb_id!
*/
err = KMSDRM_drmModeAddFB2(viddata->drm_fd, ret->width, ret->height,
ret->format, ret->gem_handles, ret->pitches,
ret->offsets, &ret->fb_id, 0);
if (err != 0 || ret->fb_id == 0) {
SDL_SetError("Failed AddFB2 on dumb buffer\n");
goto err;
}
return ret;
err:
KMSDRM_DestroyDumbBuffer(_this, &ret);
return NULL;
}
/***************************/
/* DUMB BUFFER Block ends. */
/***************************/
#endif
/*********************************/ /*********************************/
/* Atomic helper functions block */ /* Atomic helper functions block */
/*********************************/ /*********************************/
@ -1161,20 +1008,8 @@ int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
/* Figure out the default mode to be set. */ /* Figure out the default mode to be set. */
dispdata->mode = crtc->mode; dispdata->mode = crtc->mode;
/* Find the connector's preferred mode, to be used in case the current mode /* Save the original mode for restoration on quit. */
is not valid, or if restoring the current mode fails. dispdata->original_mode = dispdata->mode;
We can always count on the preferred mode! */
for (i = 0; i < connector->count_modes; i++) {
if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
dispdata->preferred_mode = connector->modes[i];
}
}
/* If the current CRTC's mode isn't valid, select the preferred
mode of the connector. */
if (crtc->mode_valid == 0) {
dispdata->mode = dispdata->preferred_mode;
}
if (dispdata->mode.hdisplay == 0 || dispdata->mode.vdisplay == 0 ) { if (dispdata->mode.hdisplay == 0 || dispdata->mode.vdisplay == 0 ) {
ret = SDL_SetError("Couldn't get a valid connector videomode."); ret = SDL_SetError("Couldn't get a valid connector videomode.");
@ -1360,15 +1195,17 @@ KMSDRM_DestroySurfaces(_THIS, SDL_Window *window)
#if 1 #if 1
/************************************************************/ /************************************************************/
/* Make the display plane point to the original TTY buffer. */ /* Make the display plane point to the original TTY buffer. */
/* We have to configure it's input and output scaling */
/* parameters accordingly. */
/************************************************************/ /************************************************************/
plane_info.plane = dispdata->display_plane; plane_info.plane = dispdata->display_plane;
plane_info.crtc_id = dispdata->crtc->crtc->crtc_id; plane_info.crtc_id = dispdata->crtc->crtc->crtc_id;
plane_info.fb_id = dispdata->crtc->crtc->buffer_id; plane_info.fb_id = dispdata->crtc->crtc->buffer_id;
plane_info.src_w = dispdata->mode.hdisplay; plane_info.src_w = dispdata->original_mode.hdisplay;
plane_info.src_h = dispdata->mode.vdisplay; plane_info.src_h = dispdata->original_mode.vdisplay;
plane_info.crtc_w = dispdata->mode.hdisplay; plane_info.crtc_w = dispdata->original_mode.hdisplay;
plane_info.crtc_h = dispdata->mode.vdisplay; plane_info.crtc_h = dispdata->original_mode.vdisplay;
drm_atomic_set_plane_props(&plane_info); drm_atomic_set_plane_props(&plane_info);
@ -1426,9 +1263,16 @@ KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
int ret = 0; int ret = 0;
if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) || /* If the current window already has surfaces, destroy them before creating other.
((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) { This is mainly for ReconfigureWindow(), where we simply call CreateSurfaces()
for regenerating a window's surfaces. */
if (windata->gs) {
KMSDRM_DestroySurfaces(_this, window);
}
if ( ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
|| ((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN))
{
width = dispdata->mode.hdisplay; width = dispdata->mode.hdisplay;
height = dispdata->mode.vdisplay; height = dispdata->mode.vdisplay;
} else { } else {
@ -1436,11 +1280,14 @@ KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
height = window->h; height = window->h;
} }
if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, surface_fmt, surface_flags)) { if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev,
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway."); surface_fmt, surface_flags)) {
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO,
"GBM surface format not supported. Trying anyway.");
} }
windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, width, height, surface_fmt, surface_flags); windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev,
width, height, surface_fmt, surface_flags);
if (!windata->gs) { if (!windata->gs) {
return SDL_SetError("Could not create GBM surface"); return SDL_SetError("Could not create GBM surface");
@ -1562,8 +1409,10 @@ KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) {
windata->output_x = 0; windata->output_x = 0;
} else { } else {
/* Normal non-fullscreen windows are scaled using the CRTC, /* Normal non-fullscreen windows are scaled using the PRIMARY PLANE, so here we store:
so get output (CRTC) size and position, for AR correction. */ input size (ie: the size of the window buffers),
output size (ie: th mode configured on the CRTC), an X position to compensate for AR correction.
These are used when we set the PRIMARY PLANE props in SwapWindow() */
ratio = (float)window->w / (float)window->h; ratio = (float)window->w / (float)window->h;
windata->src_w = window->w; windata->src_w = window->w;
windata->src_h = window->h; windata->src_h = window->h;
@ -1637,6 +1486,13 @@ KMSDRM_VideoInit(_THIS)
SDL_EVDEV_Init(); SDL_EVDEV_Init();
#endif #endif
/* Since we create and show the default cursor on KMSDRM_InitMouse() and
we call KMSDRM_InitMouse() everytime we create a new window, we have
to be sure to create and show the default cursor only the first time.
If we don't, new default cursors would stack up on mouse->cursors and SDL
would have to hide and delete them at quit, not to mention the memory leak... */
dispdata->set_default_cursor_pending = SDL_TRUE;
viddata->video_init = SDL_TRUE; viddata->video_init = SDL_TRUE;
cleanup: cleanup:
@ -1821,7 +1677,7 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
so we do it here. */ so we do it here. */
KMSDRM_InitMouse(_this); KMSDRM_InitMouse(_this);
/* Since we take cursor buffer way from the cursor plane and /* Since we take cursor buffer away from the cursor plane and
destroy the cursor GBM BO when we destroy a window, we must destroy the cursor GBM BO when we destroy a window, we must
also manually re-show the cursor on screen, if necessary, also manually re-show the cursor on screen, if necessary,
when we create a window. */ when we create a window. */

View File

@ -83,7 +83,7 @@ typedef struct connector {
typedef struct SDL_DisplayData typedef struct SDL_DisplayData
{ {
drmModeModeInfo mode; drmModeModeInfo mode;
drmModeModeInfo preferred_mode; drmModeModeInfo original_mode;
plane *display_plane; plane *display_plane;
plane *cursor_plane; plane *cursor_plane;
@ -110,6 +110,8 @@ typedef struct SDL_DisplayData
struct gbm_bo *cursor_bo; struct gbm_bo *cursor_bo;
uint64_t cursor_w, cursor_h; uint64_t cursor_w, cursor_h;
SDL_bool set_default_cursor_pending;
} SDL_DisplayData; } SDL_DisplayData;
/* Driverdata info that gives KMSDRM-side support and substance to the SDL_Window. */ /* Driverdata info that gives KMSDRM-side support and substance to the SDL_Window. */

View File

@ -38,6 +38,21 @@ static void KMSDRM_LEGACY_FreeCursor(SDL_Cursor * cursor);
static void KMSDRM_LEGACY_WarpMouse(SDL_Window * window, int x, int y); static void KMSDRM_LEGACY_WarpMouse(SDL_Window * window, int x, int y);
static int KMSDRM_LEGACY_WarpMouseGlobal(int x, int y); static int KMSDRM_LEGACY_WarpMouseGlobal(int x, int y);
/**************************************************************************************/
/* 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 succesfully, that cursor becomes mouse->cur_cursor */
/* and mouse->cursor_shown is 1. */
/**************************************************************************************/
static SDL_Cursor * static SDL_Cursor *
KMSDRM_LEGACY_CreateDefaultCursor(void) KMSDRM_LEGACY_CreateDefaultCursor(void)
{ {
@ -68,43 +83,6 @@ void legacy_alpha_premultiply_ARGB8888 (uint32_t *pixel) {
(*pixel) = (((uint32_t)A << 24) | ((uint32_t)R << 16) | ((uint32_t)G << 8)) | ((uint32_t)B << 0); (*pixel) = (((uint32_t)A << 24) | ((uint32_t)R << 16) | ((uint32_t)G << 8)) | ((uint32_t)B << 0);
} }
/* Evaluate if a given cursor size is supported or not.
Notably, current Intel gfx only support 64x64 and up. */
static SDL_bool
KMSDRM_LEGACY_IsCursorSizeSupported (int w, int h, uint32_t bo_format) {
SDL_VideoDevice *dev = SDL_GetVideoDevice();
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
int ret;
uint32_t bo_handle;
struct gbm_bo *bo = KMSDRM_LEGACY_gbm_bo_create(viddata->gbm_dev, w, h, bo_format,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo) {
SDL_SetError("Could not create GBM cursor BO width size %dx%d for size testing", w, h);
goto cleanup;
}
bo_handle = KMSDRM_LEGACY_gbm_bo_get_handle(bo).u32;
ret = KMSDRM_LEGACY_drmModeSetCursor(viddata->drm_fd, dispdata->crtc->crtc_id, bo_handle, w, h);
if (ret) {
goto cleanup;
}
else {
KMSDRM_LEGACY_gbm_bo_destroy(bo);
return SDL_TRUE;
}
cleanup:
if (bo) {
KMSDRM_LEGACY_gbm_bo_destroy(bo);
}
return SDL_FALSE;
}
/* This simply gets the cursor soft-buffer ready. /* 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 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. */ in dispata) is destroyed and recreated when we recreate windows, etc. */
@ -212,7 +190,7 @@ KMSDRM_LEGACY_InitCursor()
KMSDRM_LEGACY_ShowCursor(mouse->cur_cursor); KMSDRM_LEGACY_ShowCursor(mouse->cur_cursor);
} }
/* Show the specified cursor, or hide if cursor is NULL. */ /* Show the specified cursor, or hide if cursor is NULL or has no focus. */
static int static int
KMSDRM_LEGACY_ShowCursor(SDL_Cursor * cursor) KMSDRM_LEGACY_ShowCursor(SDL_Cursor * cursor)
{ {
@ -255,10 +233,6 @@ KMSDRM_LEGACY_ShowCursor(SDL_Cursor * cursor)
/************************************************/ /************************************************/
/* If cursor != NULL, DO show cursor on display */ /* If cursor != NULL, DO show cursor on display */
/************************************************/ /************************************************/
if (!dispdata) {
return SDL_SetError("Could not get display driverdata.");
}
curdata = (KMSDRM_LEGACY_CursorData *) cursor->driverdata; curdata = (KMSDRM_LEGACY_CursorData *) cursor->driverdata;
if (!curdata || !dispdata->cursor_bo) { if (!curdata || !dispdata->cursor_bo) {
@ -318,8 +292,7 @@ cleanup:
return ret; return ret;
} }
/* We have destroyed the cursor by now, in KMSDRM_DestroyCursor. /* This is only for freeing the SDL_cursor.*/
This is only for freeing the SDL_cursor.*/
static void static void
KMSDRM_LEGACY_FreeCursor(SDL_Cursor * cursor) KMSDRM_LEGACY_FreeCursor(SDL_Cursor * cursor)
{ {
@ -450,8 +423,16 @@ KMSDRM_LEGACY_InitMouse(_THIS)
} }
} }
/* SDL expects to set the default cursor on screen when we init the mouse. */ /* SDL expects to set the default cursor on screen when we init the mouse,
but since we have moved the KMSDRM_InitMouse() call to KMSDRM_CreateWindow(),
we end up calling KMSDRM_InitMouse() every time we create a window, so we
have to prevent this from being done every time a new window is created.
If we don't, new default cursors would stack up on mouse->cursors and SDL
would have to hide and delete them at quit, not to mention the memory leak... */
if(dispdata->set_default_cursor_pending) {
SDL_SetDefaultCursor(KMSDRM_LEGACY_CreateDefaultCursor()); SDL_SetDefaultCursor(KMSDRM_LEGACY_CreateDefaultCursor());
dispdata->set_default_cursor_pending = SDL_FALSE;
}
return; return;

View File

@ -62,145 +62,6 @@
#define KMSDRM_LEGACY_DRI_CARDPATHFMT "/dev/dri/card%d" #define KMSDRM_LEGACY_DRI_CARDPATHFMT "/dev/dri/card%d"
#endif #endif
#if 0
/**************************************************************************************/
/* UNUSED function because any plane compatible with the CRTC we chose is good enough */
/* for us, whatever it's type is. Keep it here for documentation purposes. */
/* It cold be needed sometime in the future, too. */
/**************************************************************************************/
SDL_bool KMSDRM_IsPlanePrimary (_THIS, drmModePlane *plane) {
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
SDL_bool ret = SDL_FALSE;
int j;
/* Find out if it's a primary plane. */
drmModeObjectProperties *plane_props =
KMSDRM_LEGACY_drmModeObjectGetProperties(viddata->drm_fd,
plane->plane_id, DRM_MODE_OBJECT_ANY);
for (j = 0; (j < plane_props->count_props); j++) {
drmModePropertyRes *prop = KMSDRM_LEGACY_drmModeGetProperty(viddata->drm_fd,
plane_props->props[j]);
if ((strcmp(prop->name, "type") == 0) &&
(plane_props->prop_values[j] == DRM_PLANE_TYPE_PRIMARY))
{
ret = SDL_TRUE;
}
KMSDRM_LEGACY_drmModeFreeProperty(prop);
}
KMSDRM_LEGACY_drmModeFreeObjectProperties(plane_props);
return ret;
}
#endif
#if 0
/***********************************************/
/* Use these functions if you ever need info */
/* about the available planes on your machine. */
/***********************************************/
void print_plane_info(_THIS, drmModePlanePtr plane)
{
char *plane_type;
drmModeRes *resources;
uint32_t type = 0;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
int i;
drmModeObjectPropertiesPtr props = KMSDRM_LEGACY_drmModeObjectGetProperties(viddata->drm_fd,
plane->plane_id, DRM_MODE_OBJECT_PLANE);
/* Search the plane props for the plane type. */
for (i = 0; i < props->count_props; i++) {
drmModePropertyPtr p = KMSDRM_LEGACY_drmModeGetProperty(viddata->drm_fd, props->props[i]);
if ((strcmp(p->name, "type") == 0)) {
type = props->prop_values[i];
}
KMSDRM_LEGACY_drmModeFreeProperty(p);
}
switch (type) {
case DRM_PLANE_TYPE_OVERLAY:
plane_type = "overlay";
break;
case DRM_PLANE_TYPE_PRIMARY:
plane_type = "primary";
break;
case DRM_PLANE_TYPE_CURSOR:
plane_type = "cursor";
break;
}
/* Remember that to present a plane on screen, it has to be
connected to a CRTC so the CRTC scans it,
scales it, etc... and presents it on screen. */
/* Now we look for the CRTCs supported by the plane. */
resources = KMSDRM_LEGACY_drmModeGetResources(viddata->drm_fd);
if (!resources)
return;
printf("--PLANE ID: %d\nPLANE TYPE: %s\nCRTC READING THIS PLANE: %d\nCRTCS SUPPORTED BY THIS PLANE: ", plane->plane_id, plane_type, plane->crtc_id);
for (i = 0; i < resources->count_crtcs; i++) {
if (plane->possible_crtcs & (1 << i)) {
uint32_t crtc_id = resources->crtcs[i];
printf ("%d", crtc_id);
break;
}
}
printf ("\n\n");
}
void get_planes_info(_THIS)
{
drmModePlaneResPtr plane_resources;
uint32_t i;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
plane_resources = KMSDRM_LEGACY_drmModeGetPlaneResources(viddata->drm_fd);
if (!plane_resources) {
printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
return;
}
printf("--Number of planes found: %d-- \n", plane_resources->count_planes);
printf("--Usable CRTC that we have chosen: %d-- \n", dispdata->crtc->crtc_id);
/* Iterate on all the available planes. */
for (i = 0; (i < plane_resources->count_planes); i++) {
uint32_t plane_id = plane_resources->planes[i];
drmModePlanePtr plane = KMSDRM_LEGACY_drmModeGetPlane(viddata->drm_fd, plane_id);
if (!plane) {
printf("drmModeGetPlane(%u) failed: %s\n", plane_id, strerror(errno));
continue;
}
/* Print plane info. */
print_plane_info(_this, plane);
KMSDRM_LEGACY_drmModeFreePlane(plane);
}
KMSDRM_LEGACY_drmModeFreePlaneResources(plane_resources);
}
#endif
static int static int
check_modestting(int devindex) check_modestting(int devindex)
{ {
@ -545,13 +406,10 @@ int KMSDRM_LEGACY_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
drmModeRes *resources = NULL; drmModeRes *resources = NULL;
drmModePlaneRes *plane_resources = NULL;
drmModeEncoder *encoder = NULL; drmModeEncoder *encoder = NULL;
drmModeConnector *connector = NULL; drmModeConnector *connector = NULL;
drmModeCrtc *crtc = NULL; drmModeCrtc *crtc = NULL;
uint32_t crtc_index = 0;
int ret = 0; int ret = 0;
unsigned i,j; unsigned i,j;
@ -560,8 +418,6 @@ int KMSDRM_LEGACY_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
dispdata->cursor_bo = NULL; dispdata->cursor_bo = NULL;
dispdata->plane_id = 0;
/* Open /dev/dri/cardNN (/dev/drmN if on OpenBSD) */ /* Open /dev/dri/cardNN (/dev/drmN if on OpenBSD) */
SDL_snprintf(viddata->devpath, sizeof(viddata->devpath), KMSDRM_LEGACY_DRI_CARDPATHFMT, viddata->devindex); SDL_snprintf(viddata->devpath, sizeof(viddata->devpath), KMSDRM_LEGACY_DRI_CARDPATHFMT, viddata->devindex);
@ -662,7 +518,6 @@ int KMSDRM_LEGACY_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
for (i = 0; i < resources->count_crtcs; i++) { for (i = 0; i < resources->count_crtcs; i++) {
if (encoder->possible_crtcs & (1 << i)) { if (encoder->possible_crtcs & (1 << i)) {
encoder->crtc_id = resources->crtcs[i]; encoder->crtc_id = resources->crtcs[i];
crtc_index = i;
crtc = KMSDRM_LEGACY_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id); crtc = KMSDRM_LEGACY_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
break; break;
} }
@ -680,57 +535,13 @@ int KMSDRM_LEGACY_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
/* Save the original mode for restoration on quit. */ /* Save the original mode for restoration on quit. */
dispdata->original_mode = dispdata->mode; dispdata->original_mode = dispdata->mode;
/* Find the connector's preferred mode, to be used in case the current mode
is not valid, or if restoring the current mode fails. */
for (i = 0; i < connector->count_modes; i++) {
if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
dispdata->preferred_mode = connector->modes[i];
}
}
/* If the current CRTC's mode isn't valid, select the preferred
mode of the connector. */
if (crtc->mode_valid == 0) {
dispdata->mode = dispdata->preferred_mode;
}
if (dispdata->mode.hdisplay == 0 || dispdata->mode.vdisplay == 0 ) { if (dispdata->mode.hdisplay == 0 || dispdata->mode.vdisplay == 0 ) {
ret = SDL_SetError("Couldn't get a valid connector videomode."); ret = SDL_SetError("Couldn't get a valid connector videomode.");
goto cleanup; goto cleanup;
} }
/*******************************************************/ /* Store the connector and crtc for future use. These are all we keep
/* Look for a plane that can be connected to our CRTC. */ from this function, and these are just structs, inoffensive to VK. */
/*******************************************************/
plane_resources = KMSDRM_LEGACY_drmModeGetPlaneResources(viddata->drm_fd);
for (i = 0; (i < plane_resources->count_planes); i++) {
drmModePlane *plane = KMSDRM_LEGACY_drmModeGetPlane(viddata->drm_fd,
plane_resources->planes[i]);
/* 1 - Does this plane support our CRTC?
2 - Is this plane unused or used by our CRTC? Both possibilities are good.
We don't mind if it's primary or overlay. */
if ((plane->possible_crtcs & (1 << crtc_index)) &&
(plane->crtc_id == crtc->crtc_id || plane->crtc_id == 0 ))
{
dispdata->plane_id = plane->plane_id;
break;
}
KMSDRM_LEGACY_drmModeFreePlane(plane);
}
KMSDRM_LEGACY_drmModeFreePlaneResources(plane_resources);
if (!dispdata->plane_id) {
ret = SDL_SetError("Could not locate a primary plane compatible with active CRTC.");
goto cleanup;
}
/* Store the connector and crtc for future use. These and the plane_id is
all we keep from this function, and these are just structs, inoffensive to VK. */
dispdata->connector = connector; dispdata->connector = connector;
dispdata->crtc = crtc; dispdata->crtc = crtc;
@ -900,15 +711,15 @@ KMSDRM_LEGACY_CreateSurfaces(_THIS, SDL_Window * window)
int ret = 0; int ret = 0;
/* If the current window already has surfaces, destroy them before creating other. /* If the current window already has surfaces, destroy them before creating other.
This is mainly for ReconfigureWindow, where we simply call CreateSurfaces() This is mainly for ReconfigureWindow(), where we simply call CreateSurfaces()
for regenerating a window's surfaces. */ for regenerating a window's surfaces. */
if (windata->gs) { if (windata->gs) {
KMSDRM_LEGACY_DestroySurfaces(_this, window); KMSDRM_LEGACY_DestroySurfaces(_this, window);
} }
if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) || if ( ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) { || ((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN))
{
width = dispdata->mode.hdisplay; width = dispdata->mode.hdisplay;
height = dispdata->mode.vdisplay; height = dispdata->mode.vdisplay;
} else { } else {
@ -1001,6 +812,13 @@ KMSDRM_LEGACY_VideoInit(_THIS)
SDL_EVDEV_Init(); SDL_EVDEV_Init();
#endif #endif
/* Since we create and show the default cursor on KMSDRM_InitMouse() and
we call KMSDRM_InitMouse() everytime we create a new window, we have
to be sure to create and show the default cursor only the first time.
If we don't, new default cursors would stack up on mouse->cursors and SDL
would have to hide and delete them at quit, not to mention the memory leak... */
dispdata->set_default_cursor_pending = SDL_TRUE;
viddata->video_init = SDL_TRUE; viddata->video_init = SDL_TRUE;
cleanup: cleanup:

View File

@ -62,12 +62,9 @@ typedef struct SDL_DisplayData
drmModeCrtc *crtc; drmModeCrtc *crtc;
drmModeModeInfo mode; drmModeModeInfo mode;
drmModeModeInfo original_mode; drmModeModeInfo original_mode;
drmModeModeInfo preferred_mode;
drmModeCrtc *saved_crtc; /* CRTC to restore on quit */ drmModeCrtc *saved_crtc; /* CRTC to restore on quit */
uint32_t plane_id; /* ID of the primary plane used by the CRTC */
SDL_bool gbm_init; SDL_bool gbm_init;
/* DRM & GBM cursor stuff lives here, not in an SDL_Cursor's driverdata struct, /* DRM & GBM cursor stuff lives here, not in an SDL_Cursor's driverdata struct,
@ -79,6 +76,8 @@ typedef struct SDL_DisplayData
SDL_bool modeset_pending; SDL_bool modeset_pending;
SDL_bool set_default_cursor_pending;
} SDL_DisplayData; } SDL_DisplayData;
typedef struct SDL_WindowData typedef struct SDL_WindowData