diff --git a/src/video/kmsdrm/SDL_kmsdrmmouse.c b/src/video/kmsdrm/SDL_kmsdrmmouse.c index f44402a2b..f834339a0 100644 --- a/src/video/kmsdrm/SDL_kmsdrmmouse.c +++ b/src/video/kmsdrm/SDL_kmsdrmmouse.c @@ -44,6 +44,40 @@ KMSDRM_CreateDefaultCursor(void) return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY); } +/* Evaluate if a given cursor size is supported or not. Notably, current Intel gfx only support 64x64 and up. */ +static SDL_bool +KMSDRM_IsCursorSizeSupported (int w, int h, uint32_t bo_format) { + + SDL_VideoDevice *dev = SDL_GetVideoDevice(); + SDL_VideoData *vdata = ((SDL_VideoData *)dev->driverdata); + int ret; + uint32_t bo_handle; + struct gbm_bo *bo = KMSDRM_gbm_bo_create(vdata->gbm, w, h, bo_format, + GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE); + + if (bo == NULL) { + SDL_SetError("Could not create GBM cursor BO width size %dx%d for size testing", w, h); + goto cleanup; + } + + bo_handle = KMSDRM_gbm_bo_get_handle(bo).u32; + ret = KMSDRM_drmModeSetCursor(vdata->drm_fd, vdata->crtc_id, bo_handle, w, h); + + if (ret) { + goto cleanup; + } + else { + KMSDRM_gbm_bo_destroy(bo); + return SDL_TRUE; + } + +cleanup: + if (bo != NULL) { + KMSDRM_gbm_bo_destroy(bo); + } + return SDL_FALSE; +} + /* Create a cursor from a surface */ static SDL_Cursor * KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) @@ -53,7 +87,8 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) SDL_PixelFormat *pixlfmt = surface->format; KMSDRM_CursorData *curdata; SDL_Cursor *cursor; - int i, ret; + SDL_bool cursor_supported = SDL_FALSE; + int i, ret, usable_cursor_w, usable_cursor_h; uint32_t bo_format, bo_stride; char *buffer = NULL; size_t bufsize; @@ -143,20 +178,43 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) return NULL; } + /* We have to know beforehand if a cursor with the same size as the surface is supported. + * If it's not, we have to find an usable cursor size and use an intermediate and clean buffer. + * If we can't find a cursor size supported by the hardware, we won't go on trying to + * call SDL_SetCursor() later. */ + + usable_cursor_w = surface->w; + usable_cursor_h = surface->h; + + while (usable_cursor_w <= MAX_CURSOR_W && usable_cursor_h <= MAX_CURSOR_H) { + if (KMSDRM_IsCursorSizeSupported(usable_cursor_w, usable_cursor_h, bo_format)) { + cursor_supported = SDL_TRUE; + break; + } + usable_cursor_w += usable_cursor_w; + usable_cursor_h += usable_cursor_h; + } + + if (!cursor_supported) { + SDL_SetError("Could not find a cursor size supported by the kernel driver"); + goto cleanup; + } + curdata->hot_x = hot_x; curdata->hot_y = hot_y; - curdata->w = surface->w; - curdata->h = surface->h; + curdata->w = usable_cursor_w; + curdata->h = usable_cursor_h; - curdata->bo = KMSDRM_gbm_bo_create(vdata->gbm, surface->w, surface->h, bo_format, + curdata->bo = KMSDRM_gbm_bo_create(vdata->gbm, usable_cursor_w, usable_cursor_h, bo_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE); + if (curdata->bo == NULL) { SDL_SetError("Could not create GBM cursor BO"); goto cleanup; } bo_stride = KMSDRM_gbm_bo_get_stride(curdata->bo); - bufsize = bo_stride * surface->h; + bufsize = bo_stride * curdata->h; if (surface->pitch != bo_stride) { /* pitch doesn't match stride, must be copied to temp buffer */ @@ -173,6 +231,9 @@ KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) } } + /* Clean the whole temporary buffer */ + SDL_memset(buffer, 0x00, bo_stride * curdata->h); + /* Copy to temporary buffer */ for (i = 0; i < surface->h; i++) { SDL_memcpy(buffer + (i * bo_stride), diff --git a/src/video/kmsdrm/SDL_kmsdrmmouse.h b/src/video/kmsdrm/SDL_kmsdrmmouse.h index 05c728895..ef4d81733 100644 --- a/src/video/kmsdrm/SDL_kmsdrmmouse.h +++ b/src/video/kmsdrm/SDL_kmsdrmmouse.h @@ -26,6 +26,9 @@ #include +#define MAX_CURSOR_W 512 +#define MAX_CURSOR_H 512 + typedef struct _KMSDRM_CursorData { struct gbm_bo *bo; diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index 9c1b29181..73f6f60a3 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -362,6 +362,7 @@ KMSDRM_VideoInit(_THIS) vdata->saved_crtc->y, vdata->saved_crtc->width, vdata->saved_crtc->height); data->crtc_id = encoder->crtc_id; data->cur_mode = vdata->saved_crtc->mode; + vdata->crtc_id = encoder->crtc_id; SDL_zero(current_mode); diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h index c4735e430..26ce0bbbf 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.h +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h @@ -45,6 +45,7 @@ typedef struct SDL_VideoData struct pollfd drm_pollfd; /* pollfd containing DRM file desc */ drmModeCrtc *saved_crtc; /* Saved CRTC to restore on quit */ uint32_t saved_conn_id; /* Saved DRM connector ID */ + uint32_t crtc_id; /* CRTC in use */ } SDL_VideoData;