summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Alfayate Corchete <redwindwanderer@gmail.com>2021-01-29 18:08:04 +0100
committerManuel Alfayate Corchete <redwindwanderer@gmail.com>2021-01-29 18:08:04 +0100
commit64f76964e04d3edf406ee5b1b46a82e215129898 (patch)
tree6b17b00f38bf2c5699dc8c289e14c2c89f256bac
parent56b74131c1d67128a0d066aa5b30e9df4022764e (diff)
downloadsdl-64f76964e04d3edf406ee5b1b46a82e215129898.tar.gz
[KMS/DRM] Patch for bug #5513. KMSDRM backend can now manage and use several displays.
-rw-r--r--src/video/kmsdrm/SDL_kmsdrmmouse.c406
-rw-r--r--src/video/kmsdrm/SDL_kmsdrmmouse.h5
-rw-r--r--src/video/kmsdrm/SDL_kmsdrmvideo.c313
-rw-r--r--src/video/kmsdrm/SDL_kmsdrmvideo.h1
4 files changed, 407 insertions, 318 deletions
diff --git a/src/video/kmsdrm/SDL_kmsdrmmouse.c b/src/video/kmsdrm/SDL_kmsdrmmouse.c
index a2a7c2eaf..e66953ad9 100644
--- a/src/video/kmsdrm/SDL_kmsdrmmouse.c
+++ b/src/video/kmsdrm/SDL_kmsdrmmouse.c
@@ -83,6 +83,182 @@ 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);
}
+/* 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 (_THIS, SDL_VideoDisplay *display)
+{
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) display->driverdata;
+
+ /* Destroy the curso GBM BO. */
+ if (dispdata->cursor_bo) {
+ KMSDRM_gbm_bo_destroy(dispdata->cursor_bo);
+ dispdata->cursor_bo = NULL;
+ }
+}
+
+/* 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. */
+void
+KMSDRM_CreateCursorBO (SDL_VideoDisplay *display) {
+
+ SDL_VideoDevice *dev = SDL_GetVideoDevice();
+ SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) display->driverdata;
+
+ 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, &dispdata->cursor_w) ||
+ KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_HEIGHT,
+ &dispdata->cursor_h))
+ {
+ SDL_SetError("Could not get the recommended GBM cursor size");
+ return;
+ }
+
+ if (dispdata->cursor_w == 0 || dispdata->cursor_h == 0) {
+ SDL_SetError("Could not get an usable GBM cursor size");
+ return;
+ }
+
+ 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) {
+ SDL_SetError("Could not create GBM cursor BO");
+ return;
+ }
+}
+
+/* Remove a cursor buffer from a display's DRM cursor BO. */
+int
+KMSDRM_RemoveCursorFromBO(SDL_VideoDisplay *display)
+{
+ int ret = 0;
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) display->driverdata;
+ SDL_VideoDevice *video_device = SDL_GetVideoDevice();
+ SDL_VideoData *viddata = ((SDL_VideoData *)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. */
+int
+KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Cursor *cursor)
+{
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) display->driverdata;
+ KMSDRM_CursorData *curdata = (KMSDRM_CursorData *) cursor->driverdata;
+ SDL_VideoDevice *video_device = SDL_GetVideoDevice();
+ SDL_VideoData *viddata = ((SDL_VideoData *)video_device->driverdata);
+
+ uint32_t bo_handle;
+ size_t bo_stride;
+ size_t bufsize;
+ uint32_t *ready_buffer = NULL;
+ uint32_t pixel;
+
+ int i,j;
+ int ret;
+
+ if (!curdata || !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 = (uint32_t*)SDL_calloc(1, bufsize);
+
+ if (!ready_buffer) {
+ ret = SDL_OutOfMemory();
+ goto cleanup;
+ }
+
+ /* Copy from the cursor buffer to a buffer that we can dump to the GBM BO,
+ pre-multiplying by alpha each pixel as we go. */
+ for (i = 0; i < curdata->h; i++) {
+ for (j = 0; j < curdata->w; j++) {
+ pixel = ((uint32_t*)curdata->buffer)[i * curdata->w + j];
+ legacy_alpha_premultiply_ARGB8888 (&pixel);
+ SDL_memcpy(ready_buffer + (i * dispdata->cursor_w) + j, &pixel, 4);
+ }
+ }
+
+ /* 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. */
@@ -176,17 +352,11 @@ KMSDRM_InitCursor()
SDL_Mouse *mouse = NULL;
mouse = SDL_GetMouse();
- if (!mouse) {
- return;
- }
- if (!(mouse->cur_cursor)) {
- return;
- }
-
- if (!(mouse->cursor_shown)) {
+ if (!mouse || !mouse->cur_cursor || !mouse->cursor_shown) {
return;
}
+ /* Re-dump cursor buffer to the GBM BO of the focused window display. */
KMSDRM_ShowCursor(mouse->cur_cursor);
}
@@ -194,124 +364,60 @@ KMSDRM_InitCursor()
static int
KMSDRM_ShowCursor(SDL_Cursor * cursor)
{
- SDL_VideoDevice *video_device = SDL_GetVideoDevice();
- SDL_VideoData *viddata = ((SDL_VideoData *)video_device->driverdata);
- SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
+ SDL_VideoDisplay *display;
+ SDL_Window *window;
SDL_Mouse *mouse;
- KMSDRM_CursorData *curdata;
- uint32_t bo_handle;
+ int num_displays, i;
+ int ret = 0;
- size_t bo_stride;
- size_t bufsize;
- uint32_t *ready_buffer = NULL;
- uint32_t pixel;
-
- int i,j;
- int ret;
+ /* Get the mouse focused window, if any. */
mouse = SDL_GetMouse();
if (!mouse) {
return SDL_SetError("No mouse.");
}
- /*********************************************************/
- /* Hide cursor if it's NULL or it has no focus(=winwow). */
- /*********************************************************/
- if (!cursor || !mouse->focus) {
- /* 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. */
- 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;
- }
+ window = mouse->focus;
- /*****************************************************/
- /* If cursor != NULL, DO show cursor on it's window. */
- /*****************************************************/
- curdata = (KMSDRM_CursorData *) cursor->driverdata;
+ if (!window || !cursor) {
- if (!curdata || !dispdata->cursor_bo) {
- return SDL_SetError("Cursor not initialized properly.");
- }
+ /* 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). */
- /* 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;
+ num_displays = SDL_GetNumVideoDisplays();
- ready_buffer = (uint32_t*)SDL_calloc(1, bufsize);
+ /* Iterate on the displays hidding the cursor. */
+ for (i = 0; i < num_displays; i++) {
+ display = SDL_GetDisplay(i);
+ ret = KMSDRM_RemoveCursorFromBO(display);
+ }
- if (!ready_buffer) {
- ret = SDL_OutOfMemory();
- goto cleanup;
- }
+ } else {
- /* Copy from the cursor buffer to a buffer that we can dump to the GBM BO,
- pre-multiplying by alpha each pixel as we go. */
- for (i = 0; i < curdata->h; i++) {
- for (j = 0; j < curdata->w; j++) {
- pixel = ((uint32_t*)curdata->buffer)[i * curdata->w + j];
- legacy_alpha_premultiply_ARGB8888 (&pixel);
- SDL_memcpy(ready_buffer + (i * dispdata->cursor_w) + j, &pixel, 4);
- }
- }
+ display = SDL_GetDisplayForWindow(window);
- /* 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;
- }
+ if (display) {
- /* 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 (cursor) {
+ /* Dump the cursor to the display DRM cursor BO so it becomes visible
+ on that display. */
+ ret = KMSDRM_DumpCursorToBO(display, cursor);
- if (ret) {
- ret = SDL_SetError("Failed to set DRM cursor.");
- goto cleanup;
+ } else {
+ /* Hide the cursor on that display. */
+ ret = KMSDRM_RemoveCursorFromBO(display);
+ }
+ }
}
-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);
- }
-}
-
/* Warp the mouse to (x,y) */
static void
KMSDRM_WarpMouse(SDL_Window * window, int x, int y)
@@ -325,9 +431,12 @@ static int
KMSDRM_WarpMouseGlobal(int x, int y)
{
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->focus) {
+
+ SDL_Window *window = mouse->focus;
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
+
/* Update internal mouse position. */
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x, y);
@@ -354,28 +463,11 @@ KMSDRM_WarpMouseGlobal(int x, int y)
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);
-
- /* Destroy the curso GBM BO. */
- if (video_device && dispdata->cursor_bo) {
- KMSDRM_gbm_bo_destroy(dispdata->cursor_bo);
- dispdata->cursor_bo = NULL;
- }
-}
-
-/* Create cursor BO. */
void
-KMSDRM_InitMouse(_THIS)
+KMSDRM_InitMouse(_THIS, SDL_VideoDisplay *display)
{
- SDL_VideoDevice *dev = SDL_GetVideoDevice();
- SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
- SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
SDL_Mouse *mouse = SDL_GetMouse();
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) display->driverdata;
mouse->CreateCursor = KMSDRM_CreateCursor;
mouse->ShowCursor = KMSDRM_ShowCursor;
@@ -384,61 +476,17 @@ KMSDRM_InitMouse(_THIS)
mouse->WarpMouse = KMSDRM_WarpMouse;
mouse->WarpMouseGlobal = KMSDRM_WarpMouseGlobal;
- /************************************************/
- /* 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, &dispdata->cursor_w) ||
- KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_HEIGHT,
- &dispdata->cursor_h))
- {
- SDL_SetError("Could not get the recommended GBM cursor size");
- goto cleanup;
- }
-
- if (dispdata->cursor_w == 0 || dispdata->cursor_h == 0) {
- SDL_SetError("Could not get an usable GBM cursor size");
- goto cleanup;
- }
-
- 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) {
- 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 expects to set the default cursor of the display 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());
dispdata->set_default_cursor_pending = SDL_FALSE;
}
-
- return;
-
-cleanup:
- if (dispdata->cursor_bo) {
- KMSDRM_gbm_bo_destroy(dispdata->cursor_bo);
- dispdata->cursor_bo = NULL;
- }
}
void
@@ -452,23 +500,25 @@ static void
KMSDRM_MoveCursor(SDL_Cursor * cursor)
{
SDL_Mouse *mouse = SDL_GetMouse();
- SDL_Window *window;
- SDL_DisplayData *dispdata;
-
int drm_fd, ret, screen_y;
/* We must NOT call SDL_SendMouseMotion() here or we will enter recursivity!
That's why we move the cursor graphic ONLY. */
- if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata && mouse->focus) {
+ if (mouse && mouse->cur_cursor && mouse->focus) {
- window = mouse->focus;
- dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
+ SDL_Window *window = mouse->focus;
+ SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
- /* Correct the Y coordinate, because DRM mouse coordinates start on screen top. */
- screen_y = dispdata->mode.vdisplay - window->h + mouse->y;
+ if (!dispdata->cursor_bo) {
+ SDL_SetError("Cursor not initialized properly.");
+ return;
+ }
drm_fd = KMSDRM_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(dispdata->cursor_bo));
+ /* Correct the Y coordinate, because DRM mouse coordinates start on screen top. */
+ screen_y = dispdata->mode.vdisplay - window->h + mouse->y;
+
ret = KMSDRM_drmModeMoveCursor(drm_fd, dispdata->crtc->crtc_id, mouse->x, screen_y);
if (ret) {
diff --git a/src/video/kmsdrm/SDL_kmsdrmmouse.h b/src/video/kmsdrm/SDL_kmsdrmmouse.h
index 9a6bad0bd..36625acdb 100644
--- a/src/video/kmsdrm/SDL_kmsdrmmouse.h
+++ b/src/video/kmsdrm/SDL_kmsdrmmouse.h
@@ -43,10 +43,11 @@ typedef struct _KMSDRM_CursorData
} KMSDRM_CursorData;
-extern void KMSDRM_InitMouse(_THIS);
-extern void KMSDRM_DeinitMouse(_THIS);
+extern void KMSDRM_InitMouse(_THIS, SDL_VideoDisplay *display);
extern void KMSDRM_QuitMouse(_THIS);
+extern void KMSDRM_CreateCursorBO(SDL_VideoDisplay *display);
+extern void KMSDRM_DestroyCursorBO(_THIS, SDL_VideoDisplay *display);
extern void KMSDRM_InitCursor();
#endif /* SDL_KMSDRM_mouse_h_ */
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 8af915218..79e2a7748 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -457,83 +457,64 @@ uint32_t width, uint32_t height, uint32_t refresh_rate){
/* _this is a SDL_VideoDevice * */
/*****************************************************************************/
-/* Deinitializes the dispdata members needed for KMSDRM operation that are
- inoffeensive for VK compatibility. */
-void KMSDRM_DisplayDataDeinit (_THIS, SDL_DisplayData *dispdata) {
- /* Free connector */
- if (dispdata && dispdata->connector) {
- KMSDRM_drmModeFreeConnector(dispdata->connector);
- dispdata->connector = NULL;
- }
+/* Deinitializes the driverdata of the SDL Displays in the SDL display list. */
+void KMSDRM_DeinitDisplays (_THIS) {
+
+ SDL_DisplayData *dispdata;
+ int num_displays, i;
+
+ num_displays = SDL_GetNumVideoDisplays();
+
+ /* Iterate on the SDL Display list. */
+ for (i = 0; i < num_displays; i++) {
+
+ /* Get the driverdata for this display */
+ dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(i);
+
+ /* Free connector */
+ if (dispdata && dispdata->connector) {
+ KMSDRM_drmModeFreeConnector(dispdata->connector);
+ dispdata->connector = NULL;
+ }
- /* Free CRTC */
- if (dispdata && dispdata->crtc) {
- KMSDRM_drmModeFreeCrtc(dispdata->crtc);
- dispdata->crtc = NULL;
+ /* Free CRTC */
+ if (dispdata && dispdata->crtc) {
+ KMSDRM_drmModeFreeCrtc(dispdata->crtc);
+ dispdata->crtc = NULL;
+ }
}
}
-/* Initializes the dispdata members needed for KMSDRM operation that are
- inoffeensive for VK compatibility, except we must leave the drm_fd
- closed when we get to the end of this function.
- This is to be called early, in VideoInit(), because it gets us
- the videomode information, which SDL needs immediately after VideoInit(). */
-int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
- SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
+/* Gets a DRM connector, builds an SDL_Display with it, and adds it to the
+ list of SDL Displays. */
+void KMSDRM_AddDisplay (_THIS, drmModeConnector *connector, drmModeRes *resources) {
- drmModeRes *resources = NULL;
+ SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
+ SDL_DisplayData *dispdata = NULL;
+ SDL_VideoDisplay display = {0};
drmModeEncoder *encoder = NULL;
- drmModeConnector *connector = NULL;
drmModeCrtc *crtc = NULL;
-
+ int i, j;
int ret = 0;
- unsigned i,j;
+ /* Reserve memory for the new display's driverdata. */
+ dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
+ if (!dispdata) {
+ ret = SDL_OutOfMemory();
+ }
+
+ /* Initialize some of the members of the new display's driverdata
+ to sane values. */
dispdata->gbm_init = SDL_FALSE;
dispdata->modeset_pending = SDL_FALSE;
dispdata->cursor_bo = NULL;
- /* Open /dev/dri/cardNN (/dev/drmN if on OpenBSD) */
- SDL_snprintf(viddata->devpath, sizeof(viddata->devpath), KMSDRM_DRI_CARDPATHFMT, viddata->devindex);
-
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", viddata->devpath);
- viddata->drm_fd = open(viddata->devpath, O_RDWR | O_CLOEXEC);
-
- if (viddata->drm_fd < 0) {
- ret = SDL_SetError("Could not open %s", viddata->devpath);
- goto cleanup;
- }
-
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd);
-
- /* Get all of the available connectors / devices / crtcs */
- resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
- if (!resources) {
- ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd);
- goto cleanup;
- }
-
- /* Iterate on the available connectors to find a connected connector. */
- for (i = 0; i < resources->count_connectors; i++) {
- drmModeConnector *conn = KMSDRM_drmModeGetConnector(viddata->drm_fd,
- resources->connectors[i]);
-
- if (!conn) {
- continue;
- }
-
- if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
- connector = conn;
- break;
- }
-
- KMSDRM_drmModeFreeConnector(conn);
- }
-
- if (!connector) {
- ret = SDL_SetError("No currently active connector found.");
- goto cleanup;
- }
+ /* 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;
/* Try to find the connector's current encoder */
for (i = 0; i < resources->count_encoders; i++) {
@@ -558,7 +539,7 @@ int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
resources->encoders[i]);
if (!encoder) {
- continue;
+ continue;
}
for (j = 0; j < connector->count_encoders; j++) {
@@ -568,7 +549,7 @@ int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
}
if (j != connector->count_encoders) {
- break;
+ break;
}
KMSDRM_drmModeFreeEncoder(encoder);
@@ -577,7 +558,7 @@ int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
}
if (!encoder) {
- ret = SDL_SetError("No connected encoder found.");
+ ret = SDL_SetError("No connected encoder found for connector.");
goto cleanup;
}
@@ -597,11 +578,21 @@ int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
}
if (!crtc) {
- ret = SDL_SetError("No CRTC found.");
+ ret = SDL_SetError("No CRTC found for connector.");
goto cleanup;
}
- /* Figure out the default mode to be set. */
+ /*********************************************/
+ /* Create an SDL Display for this connector. */
+ /*********************************************/
+
+ /*********************************************/
+ /* Part 1: setup the SDL_Display driverdata. */
+ /*********************************************/
+
+ /* Get the mode currently setup for this display,
+ which is the mode currently setup on the CRTC
+ we found for the active connector. */
dispdata->mode = crtc->mode;
/* Save the original mode for restoration on quit. */
@@ -612,25 +603,29 @@ int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
goto cleanup;
}
- /* Store the connector and crtc for future use. These are all we keep
- from this function, and these are just structs, inoffensive to VK. */
+ /* Store the connector and crtc for this display. */
dispdata->connector = connector;
dispdata->crtc = crtc;
- /***********************************/
- /* Block for Vulkan compatibility. */
- /***********************************/
+ /*****************************************/
+ /* Part 2: setup the SDL_Display itself. */
+ /*****************************************/
- /* THIS IS FOR VULKAN! Leave the FD closed, so VK can work.
- Will reopen this in CreateWindow, but only if requested a non-VK window. */
- close (viddata->drm_fd);
- viddata->drm_fd = -1;
+ /* Setup the display.
+ There's no problem with it being still incomplete. */
+ display.driverdata = dispdata;
+ display.desktop_mode.w = dispdata->mode.hdisplay;
+ display.desktop_mode.h = dispdata->mode.vdisplay;
+ display.desktop_mode.refresh_rate = dispdata->mode.vrefresh;
+ display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
+ display.current_mode = display.desktop_mode;
+
+ /* Add the display to the list of SDL displays. */
+ SDL_AddVideoDisplay(&display, SDL_FALSE);
cleanup:
if (encoder)
KMSDRM_drmModeFreeEncoder(encoder);
- if (resources)
- KMSDRM_drmModeFreeResources(resources);
if (ret) {
/* Error (complete) cleanup */
if (dispdata->connector) {
@@ -641,12 +636,93 @@ cleanup:
KMSDRM_drmModeFreeCrtc(dispdata->crtc);
dispdata->crtc = NULL;
}
+ if (dispdata) {
+ SDL_free(dispdata);
+ }
+ }
+}
+
+/* Initializes the list of SDL displays: we build a new display for each
+ connecter connector we find.
+ Inoffeensive for VK compatibility, except we must leave the drm_fd
+ closed when we get to the end of this function.
+ This is to be called early, in VideoInit(), because it gets us
+ the videomode information, which SDL needs immediately after VideoInit(). */
+int KMSDRM_InitDisplays (_THIS) {
+
+ SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
+ drmModeRes *resources = NULL;
+
+ int ret = 0;
+ int i;
+
+ /* Open /dev/dri/cardNN (/dev/drmN if on OpenBSD) */
+ SDL_snprintf(viddata->devpath, sizeof(viddata->devpath), KMSDRM_DRI_CARDPATHFMT, viddata->devindex);
+
+ SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", viddata->devpath);
+ viddata->drm_fd = open(viddata->devpath, O_RDWR | O_CLOEXEC);
+
+ if (viddata->drm_fd < 0) {
+ ret = SDL_SetError("Could not open %s", viddata->devpath);
+ goto cleanup;
+ }
+
+ SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd);
+
+ /* Get all of the available connectors / devices / crtcs */
+ resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
+ if (!resources) {
+ ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd);
+ goto cleanup;
+ }
+
+ /* Iterate on the available connectors. For every connected connector,
+ we create an SDL_Display and add it to the list of SDL Displays. */
+ for (i = 0; i < resources->count_connectors; i++) {
+ drmModeConnector *connector = KMSDRM_drmModeGetConnector(viddata->drm_fd,
+ resources->connectors[i]);
+
+ if (!connector) {
+ continue;
+ }
+
+ if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes) {
+ /* If it's a connected connector with available videomodes, try to add
+ an SDL Display representing it. KMSDRM_AddDisplay() is purposely void,
+ so if it fails (no encoder for connector, no valid video mode for
+ connector etc...) we can keep looking for connected connectors. */
+ KMSDRM_AddDisplay (_this, connector, resources);
+ }
+ else {
+ /* If it's not, free it now. */
+ KMSDRM_drmModeFreeConnector(connector);
+ }
+ }
+
+ /* Have we added any SDL displays? */
+ if (!SDL_GetNumVideoDisplays()) {
+ ret = SDL_SetError("No connected displays found.");
+ goto cleanup;
+ }
+
+ /***********************************/
+ /* Block for Vulkan compatibility. */
+ /***********************************/
+
+ /* THIS IS FOR VULKAN! Leave the FD closed, so VK can work.
+ Will reopen this in CreateWindow, but only if requested a non-VK window. */
+ close (viddata->drm_fd);
+ viddata->drm_fd = -1;
+
+cleanup:
+ if (resources)
+ KMSDRM_drmModeFreeResources(resources);
+ if (ret) {
if (viddata->drm_fd >= 0) {
close(viddata->drm_fd);
viddata->drm_fd = -1;
}
}
-
return ret;
}
@@ -838,68 +914,26 @@ KMSDRM_VideoInit(_THIS)
int ret = 0;
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
- SDL_DisplayData *dispdata = NULL;
- SDL_VideoDisplay display = {0};
-
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()");
viddata->video_init = SDL_FALSE;
- dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
- if (!dispdata) {
- return SDL_OutOfMemory();
- }
-
/* Get KMSDRM resources info and store what we need. Getting and storing
this info isn't a problem for VK compatibility.
For VK-incompatible initializations we have KMSDRM_GBMInit(), which is
called on window creation, and only when we know it's not a VK window. */
- if (KMSDRM_DisplayDataInit(_this, dispdata)) {
+ if (KMSDRM_InitDisplays(_this)) {
ret = SDL_SetError("error getting KMS/DRM information");
- goto cleanup;
}
- /* Setup the single display that's available.
- There's no problem with it being still incomplete. */
- display.driverdata = dispdata;
- display.desktop_mode.w = dispdata->mode.hdisplay;
- display.desktop_mode.h = dispdata->mode.vdisplay;
- display.desktop_mode.refresh_rate = dispdata->mode.vrefresh;
- display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
- display.current_mode = display.desktop_mode;
-
- /* Add the display only when it's ready, */
- SDL_AddVideoDisplay(&display, SDL_FALSE);
-
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Init();
#elif defined(SDL_INPUT_WSCONS)
SDL_WSCONS_Init();
#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;
-cleanup:
-
- if (ret) {
- /* Error (complete) cleanup */
- if (dispdata->crtc) {
- SDL_free(dispdata->crtc);
- }
- if (dispdata->connector) {
- SDL_free(dispdata->connector);
- }
-
- SDL_free(dispdata);
- }
-
return ret;
}
@@ -909,9 +943,8 @@ void
KMSDRM_VideoQuit(_THIS)
{
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
- SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
- KMSDRM_DisplayDataDeinit(_this, dispdata);
+ KMSDRM_DeinitDisplays(_this);
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Quit();
@@ -1010,8 +1043,8 @@ KMSDRM_DestroyWindow(_THIS, SDL_Window *window)
if ( !is_vulkan && dispdata->gbm_init ) {
- /* Destroy cursor GBM plane. */
- KMSDRM_DeinitMouse(_this);
+ /* Destroy the window display's cursor GBM BO. */
+ KMSDRM_DestroyCursorBO(_this, SDL_GetDisplayForWindow(window));
/* Destroy GBM surface and buffers. */
KMSDRM_DestroySurfaces(_this, window);
@@ -1126,15 +1159,20 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
goto cleanup;
}
}
-
- /* Can't init mouse stuff sooner because cursor plane is not ready,
- so we do it here. */
- KMSDRM_InitMouse(_this);
-
- /* Since we take cursor buffer way from the cursor plane and
- destroy the cursor GBM BO when we destroy a window, we must
- also manually re-show the cursor on screen, if necessary,
- when we create a window. */
+
+ /* Create the cursor BO for the display of this window,
+ now that we know this is not a VK window. */
+ KMSDRM_CreateCursorBO(display);
+
+ /* Init mouse (=create and set the default cursor),
+ now that we know this is not a VK window. */
+ KMSDRM_InitMouse(_this, display);
+
+ /* When we destroy a window, we remove the cursor buffer from
+ the cursor plane and destroy the cursor GBM BO, but SDL expects
+ that we keep showing the visible cursors bewteen window
+ destruction/creation cycles. So we must manually re-show the
+ visible cursors, if necessary, when we create a window. */
KMSDRM_InitCursor();
}
@@ -1256,7 +1294,6 @@ KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) {
as pending so it's done on SwapWindow. */
KMSDRM_CreateSurfaces(_this, window);
dispdata->modeset_pending = SDL_TRUE;
-
}
int
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h
index 29cfc1833..9b5a573b9 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.h
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h
@@ -138,6 +138,7 @@ void KMSDRM_RaiseWindow(_THIS, SDL_Window * window);
void KMSDRM_MaximizeWindow(_THIS, SDL_Window * window);
void KMSDRM_MinimizeWindow(_THIS, SDL_Window * window);
void KMSDRM_RestoreWindow(_THIS, SDL_Window * window);
+void KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
void KMSDRM_DestroyWindow(_THIS, SDL_Window * window);
/* Window manager function */