mirror of https://github.com/encounter/SDL.git
[KMS/DRM] Patch for bug #5513. KMSDRM backend can now manage and use several displays.
This commit is contained in:
parent
a78bce9e38
commit
b17c49509b
|
@ -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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
display = SDL_GetDisplayForWindow(window);
|
||||
|
||||
if (display) {
|
||||
|
||||
if (cursor) {
|
||||
/* Dump the cursor to the display DRM cursor BO so it becomes visible
|
||||
on that display. */
|
||||
ret = KMSDRM_DumpCursorToBO(display, cursor);
|
||||
|
||||
} else {
|
||||
/* Hide the cursor on that display. */
|
||||
ret = KMSDRM_RemoveCursorFromBO(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
ret = SDL_SetError("Failed to set DRM cursor.");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
KMSDRM_InitMouse(_THIS, SDL_VideoDisplay *display)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
drm_fd = KMSDRM_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(dispdata->cursor_bo));
|
||||
|
||||
ret = KMSDRM_drmModeMoveCursor(drm_fd, dispdata->crtc->crtc_id, mouse->x, screen_y);
|
||||
|
||||
if (ret) {
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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) {
|
||||
|
||||
/* Free CRTC */
|
||||
if (dispdata && dispdata->crtc) {
|
||||
KMSDRM_drmModeFreeCrtc(dispdata->crtc);
|
||||
dispdata->crtc = NULL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
/* 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) {
|
||||
|
||||
SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
|
||||
|
||||
drmModeRes *resources = NULL;
|
||||
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,11 +603,108 @@ 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;
|
||||
|
||||
/*****************************************/
|
||||
/* Part 2: setup the SDL_Display itself. */
|
||||
/*****************************************/
|
||||
|
||||
/* 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 (ret) {
|
||||
/* Error (complete) cleanup */
|
||||
if (dispdata->connector) {
|
||||
KMSDRM_drmModeFreeConnector(dispdata->connector);
|
||||
dispdata->connector = NULL;
|
||||
}
|
||||
if (dispdata->crtc) {
|
||||
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. */
|
||||
/***********************************/
|
||||
|
@ -627,26 +715,14 @@ int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) {
|
|||
viddata->drm_fd = -1;
|
||||
|
||||
cleanup:
|
||||
if (encoder)
|
||||
KMSDRM_drmModeFreeEncoder(encoder);
|
||||
if (resources)
|
||||
KMSDRM_drmModeFreeResources(resources);
|
||||
if (ret) {
|
||||
/* Error (complete) cleanup */
|
||||
if (dispdata->connector) {
|
||||
KMSDRM_drmModeFreeConnector(dispdata->connector);
|
||||
dispdata->connector = NULL;
|
||||
}
|
||||
if (dispdata->crtc) {
|
||||
KMSDRM_drmModeFreeCrtc(dispdata->crtc);
|
||||
dispdata->crtc = NULL;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue