Fixed bug 3980 - Fix for KMSDRM driver where cursor would not be shown on some gfx hardware because of unsupported cursor size
authorSam Lantinga <slouken@libsdl.org>
Fri, 24 Nov 2017 12:03:28 -0800
changeset 11714f10f06ee8207
parent 11713 0083f778ede4
child 11715 35da714ed287
Fixed bug 3980 - Fix for KMSDRM driver where cursor would not be shown on some gfx hardware because of unsupported cursor size

Manuel Alfayate Corchete

This fixes a problem with KMSDRM on some graphics hardware where only bigger cursor sizes are supported, such as current Intel gfx. (The kernel-side driver is what limits this: had to look for failing IOCTLs...)
That caused SDL_SetCursor() to fail silently, and we were left with a missing cursor without further explanation.
With this patch, different "standard" sizes are tried and a bigger one is used (with an intermediate and clean buffer only used to write the new cursor to the BO where it will live after) if we get, let's say, 16x16 which is pretty common but our hardware does not support that.
src/video/kmsdrm/SDL_kmsdrmmouse.c
src/video/kmsdrm/SDL_kmsdrmmouse.h
src/video/kmsdrm/SDL_kmsdrmvideo.c
src/video/kmsdrm/SDL_kmsdrmvideo.h
     1.1 --- a/src/video/kmsdrm/SDL_kmsdrmmouse.c	Fri Nov 24 03:01:07 2017 -0800
     1.2 +++ b/src/video/kmsdrm/SDL_kmsdrmmouse.c	Fri Nov 24 12:03:28 2017 -0800
     1.3 @@ -44,6 +44,40 @@
     1.4      return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
     1.5  }
     1.6  
     1.7 +/* Evaluate if a given cursor size is supported or not. Notably, current Intel gfx only support 64x64 and up. */
     1.8 +static SDL_bool
     1.9 +KMSDRM_IsCursorSizeSupported (int w, int h, uint32_t bo_format) {
    1.10 +
    1.11 +    SDL_VideoDevice *dev = SDL_GetVideoDevice();
    1.12 +    SDL_VideoData *vdata = ((SDL_VideoData *)dev->driverdata);
    1.13 +    int ret;
    1.14 +    uint32_t bo_handle;
    1.15 +    struct gbm_bo *bo = KMSDRM_gbm_bo_create(vdata->gbm, w, h, bo_format,
    1.16 +                                       GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
    1.17 +
    1.18 +    if (bo == NULL) {
    1.19 +        SDL_SetError("Could not create GBM cursor BO width size %dx%d for size testing", w, h);
    1.20 +        goto cleanup;
    1.21 +    }
    1.22 +
    1.23 +    bo_handle = KMSDRM_gbm_bo_get_handle(bo).u32;
    1.24 +    ret = KMSDRM_drmModeSetCursor(vdata->drm_fd, vdata->crtc_id, bo_handle, w, h);
    1.25 +
    1.26 +    if (ret) {
    1.27 +        goto cleanup;
    1.28 +    }
    1.29 +    else {
    1.30 +        KMSDRM_gbm_bo_destroy(bo);
    1.31 +        return SDL_TRUE;
    1.32 +    }
    1.33 +
    1.34 +cleanup:
    1.35 +    if (bo != NULL) {
    1.36 +        KMSDRM_gbm_bo_destroy(bo);
    1.37 +    }
    1.38 +    return SDL_FALSE;
    1.39 +}
    1.40 +
    1.41  /* Create a cursor from a surface */
    1.42  static SDL_Cursor *
    1.43  KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
    1.44 @@ -53,7 +87,8 @@
    1.45      SDL_PixelFormat *pixlfmt = surface->format;
    1.46      KMSDRM_CursorData *curdata;
    1.47      SDL_Cursor *cursor;
    1.48 -    int i, ret;
    1.49 +    SDL_bool cursor_supported = SDL_FALSE;
    1.50 +    int i, ret, usable_cursor_w, usable_cursor_h;
    1.51      uint32_t bo_format, bo_stride;
    1.52      char *buffer = NULL;
    1.53      size_t bufsize;
    1.54 @@ -143,20 +178,43 @@
    1.55          return NULL;
    1.56      }
    1.57  
    1.58 +    /* We have to know beforehand if a cursor with the same size as the surface is supported.
    1.59 +     * If it's not, we have to find an usable cursor size and use an intermediate and clean buffer.
    1.60 +     * If we can't find a cursor size supported by the hardware, we won't go on trying to 
    1.61 +     * call SDL_SetCursor() later. */
    1.62 +
    1.63 +    usable_cursor_w = surface->w;
    1.64 +    usable_cursor_h = surface->h;
    1.65 +
    1.66 +    while (usable_cursor_w <= MAX_CURSOR_W && usable_cursor_h <= MAX_CURSOR_H) { 
    1.67 +        if (KMSDRM_IsCursorSizeSupported(usable_cursor_w, usable_cursor_h, bo_format)) {
    1.68 +            cursor_supported = SDL_TRUE;
    1.69 +            break;
    1.70 +        }
    1.71 +        usable_cursor_w += usable_cursor_w;
    1.72 +        usable_cursor_h += usable_cursor_h;
    1.73 +    }
    1.74 +
    1.75 +    if (!cursor_supported) {
    1.76 +        SDL_SetError("Could not find a cursor size supported by the kernel driver");
    1.77 +        goto cleanup;
    1.78 +    }
    1.79 +
    1.80      curdata->hot_x = hot_x;
    1.81      curdata->hot_y = hot_y;
    1.82 -    curdata->w = surface->w;
    1.83 -    curdata->h = surface->h;
    1.84 +    curdata->w = usable_cursor_w;
    1.85 +    curdata->h = usable_cursor_h;
    1.86  
    1.87 -    curdata->bo = KMSDRM_gbm_bo_create(vdata->gbm, surface->w, surface->h, bo_format,
    1.88 +    curdata->bo = KMSDRM_gbm_bo_create(vdata->gbm, usable_cursor_w, usable_cursor_h, bo_format,
    1.89                                         GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
    1.90 +
    1.91      if (curdata->bo == NULL) {
    1.92          SDL_SetError("Could not create GBM cursor BO");
    1.93          goto cleanup;
    1.94      }
    1.95  
    1.96      bo_stride = KMSDRM_gbm_bo_get_stride(curdata->bo);
    1.97 -    bufsize = bo_stride * surface->h;
    1.98 +    bufsize = bo_stride * curdata->h;
    1.99  
   1.100      if (surface->pitch != bo_stride) {
   1.101          /* pitch doesn't match stride, must be copied to temp buffer  */
   1.102 @@ -173,6 +231,9 @@
   1.103              }
   1.104          }
   1.105  
   1.106 +        /* Clean the whole temporary buffer */
   1.107 +        SDL_memset(buffer, 0x00, bo_stride * curdata->h);
   1.108 +
   1.109          /* Copy to temporary buffer */
   1.110          for (i = 0; i < surface->h; i++) {
   1.111              SDL_memcpy(buffer + (i * bo_stride),
     2.1 --- a/src/video/kmsdrm/SDL_kmsdrmmouse.h	Fri Nov 24 03:01:07 2017 -0800
     2.2 +++ b/src/video/kmsdrm/SDL_kmsdrmmouse.h	Fri Nov 24 12:03:28 2017 -0800
     2.3 @@ -26,6 +26,9 @@
     2.4  
     2.5  #include <gbm.h>
     2.6  
     2.7 +#define MAX_CURSOR_W 512
     2.8 +#define MAX_CURSOR_H 512
     2.9 +
    2.10  typedef struct _KMSDRM_CursorData
    2.11  {
    2.12      struct gbm_bo *bo;
     3.1 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c	Fri Nov 24 03:01:07 2017 -0800
     3.2 +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c	Fri Nov 24 12:03:28 2017 -0800
     3.3 @@ -362,6 +362,7 @@
     3.4                   vdata->saved_crtc->y, vdata->saved_crtc->width, vdata->saved_crtc->height);
     3.5      data->crtc_id = encoder->crtc_id;
     3.6      data->cur_mode = vdata->saved_crtc->mode;
     3.7 +    vdata->crtc_id = encoder->crtc_id;
     3.8  
     3.9      SDL_zero(current_mode);
    3.10  
     4.1 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.h	Fri Nov 24 03:01:07 2017 -0800
     4.2 +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h	Fri Nov 24 12:03:28 2017 -0800
     4.3 @@ -45,6 +45,7 @@
     4.4      struct pollfd drm_pollfd;   /* pollfd containing DRM file desc */
     4.5      drmModeCrtc *saved_crtc;    /* Saved CRTC to restore on quit */
     4.6      uint32_t saved_conn_id;     /* Saved DRM connector ID */
     4.7 +    uint32_t crtc_id;           /* CRTC in use */
     4.8  } SDL_VideoData;
     4.9  
    4.10