src/video/kmsdrm/SDL_kmsdrmvideo.c
author Fabrice Fontaine <fontaine.fabrice@gmail.com>
Wed, 25 Mar 2020 09:38:45 -0700
changeset 13672 389ce8cfa2a3
parent 13592 3ff45857428d
child 13696 ea20a7434b98
permissions -rw-r--r--
src/video/kmsdrm/SDL_kmsdrmvideo.c: fix build
Build is broken without EGL since version 2.0.12 and
https://hg.libsdl.org/SDL/rev/9761858bd6a3:

/home/giuliobenetti/autobuild/run/instance-1/output-1/build/sdl2-2.0.12/src/video/kmsdrm/SDL_kmsdrmvideo.c: In function 'KMSDRM_CreateSurfaces':
/home/giuliobenetti/autobuild/run/instance-1/output-1/build/sdl2-2.0.12/src/video/kmsdrm/SDL_kmsdrmvideo.c:394:5: error: unknown type name 'EGLContext'
EGLContext egl_context;
^

Fixes:
- http://autobuild.buildroot.org/results/fafd20a01591032662f9ca025fcea3478239cf3c

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 #include "../../SDL_internal.h"
    23 
    24 #if SDL_VIDEO_DRIVER_KMSDRM
    25 
    26 /* SDL internals */
    27 #include "../SDL_sysvideo.h"
    28 #include "SDL_syswm.h"
    29 #include "SDL_log.h"
    30 #include "SDL_hints.h"
    31 #include "../../events/SDL_events_c.h"
    32 #include "../../events/SDL_mouse_c.h"
    33 #include "../../events/SDL_keyboard_c.h"
    34 
    35 #ifdef SDL_INPUT_LINUXEV
    36 #include "../../core/linux/SDL_evdev.h"
    37 #endif
    38 
    39 /* KMS/DRM declarations */
    40 #include "SDL_kmsdrmvideo.h"
    41 #include "SDL_kmsdrmevents.h"
    42 #include "SDL_kmsdrmopengles.h"
    43 #include "SDL_kmsdrmmouse.h"
    44 #include "SDL_kmsdrmdyn.h"
    45 #include <sys/stat.h>
    46 #include <dirent.h>
    47 #include <errno.h>
    48 #include <poll.h>
    49 
    50 #define KMSDRM_DRI_PATH "/dev/dri/"
    51 
    52 static int
    53 check_modestting(int devindex)
    54 {
    55     SDL_bool available = SDL_FALSE;
    56     char device[512];
    57     int drm_fd;
    58 
    59     SDL_snprintf(device, sizeof (device), "%scard%d", KMSDRM_DRI_PATH, devindex);
    60 
    61     drm_fd = open(device, O_RDWR | O_CLOEXEC);
    62     if (drm_fd >= 0) {
    63         if (SDL_KMSDRM_LoadSymbols()) {
    64             drmModeRes *resources = KMSDRM_drmModeGetResources(drm_fd);
    65             if (resources) {
    66                 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "%scard%d connector, encoder and CRTC counts are: %d %d %d",
    67                              KMSDRM_DRI_PATH, devindex,
    68                              resources->count_connectors, resources->count_encoders, resources->count_crtcs);
    69 
    70                 if (resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0) {
    71                     available = SDL_TRUE;
    72                 }
    73                 KMSDRM_drmModeFreeResources(resources);
    74             }
    75             SDL_KMSDRM_UnloadSymbols();
    76         }
    77         close(drm_fd);
    78     }
    79 
    80     return available;
    81 }
    82 
    83 static int get_dricount(void)
    84 {
    85     int devcount = 0;
    86     struct dirent *res;
    87     struct stat sb;
    88     DIR *folder;
    89 
    90     if (!(stat(KMSDRM_DRI_PATH, &sb) == 0
    91                 && S_ISDIR(sb.st_mode))) {
    92         printf("The path %s cannot be opened or is not available\n",
    93                KMSDRM_DRI_PATH);
    94         return 0;
    95     }
    96 
    97     if (access(KMSDRM_DRI_PATH, F_OK) == -1) {
    98         printf("The path %s cannot be opened\n",
    99                KMSDRM_DRI_PATH);
   100         return 0;
   101     }
   102 
   103     folder = opendir(KMSDRM_DRI_PATH);
   104     if (folder) {
   105         while ((res = readdir(folder))) {
   106             int len = SDL_strlen(res->d_name);
   107             if (len > 4 && SDL_strncmp(res->d_name, "card", 4) == 0) {
   108                 devcount++;
   109             }
   110         }
   111         closedir(folder);
   112     }
   113 
   114     return devcount;
   115 }
   116 
   117 static int
   118 get_driindex(void)
   119 {
   120     const int devcount = get_dricount();
   121     int i;
   122 
   123     for (i = 0; i < devcount; i++) {
   124         if (check_modestting(i)) {
   125             return i;
   126         }
   127     }
   128 
   129     return -ENOENT;
   130 }
   131 
   132 static int
   133 KMSDRM_Available(void)
   134 {
   135     int ret = -ENOENT;
   136 
   137     ret = get_driindex();
   138     if (ret >= 0)
   139         return 1;
   140 
   141     return ret;
   142 }
   143 
   144 static void
   145 KMSDRM_DeleteDevice(SDL_VideoDevice * device)
   146 {
   147     if (device->driverdata) {
   148         SDL_free(device->driverdata);
   149         device->driverdata = NULL;
   150     }
   151 
   152     SDL_free(device);
   153 
   154     SDL_KMSDRM_UnloadSymbols();
   155 }
   156 
   157 static SDL_VideoDevice *
   158 KMSDRM_CreateDevice(int devindex)
   159 {
   160     SDL_VideoDevice *device;
   161     SDL_VideoData *viddata;
   162 
   163     if (!devindex || (devindex > 99)) {
   164         devindex = get_driindex();
   165     }
   166 
   167     if (devindex < 0) {
   168         SDL_SetError("devindex (%d) must be between 0 and 99.\n", devindex);
   169         return NULL;
   170     }
   171 
   172     if (!SDL_KMSDRM_LoadSymbols()) {
   173         return NULL;
   174     }
   175 
   176     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
   177     if (!device) {
   178         SDL_OutOfMemory();
   179         return NULL;
   180     }
   181 
   182     viddata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
   183     if (!viddata) {
   184         SDL_OutOfMemory();
   185         goto cleanup;
   186     }
   187     viddata->devindex = devindex;
   188     viddata->drm_fd = -1;
   189 
   190     device->driverdata = viddata;
   191 
   192     /* Setup all functions which we can handle */
   193     device->VideoInit = KMSDRM_VideoInit;
   194     device->VideoQuit = KMSDRM_VideoQuit;
   195     device->GetDisplayModes = KMSDRM_GetDisplayModes;
   196     device->SetDisplayMode = KMSDRM_SetDisplayMode;
   197     device->CreateSDLWindow = KMSDRM_CreateWindow;
   198     device->CreateSDLWindowFrom = KMSDRM_CreateWindowFrom;
   199     device->SetWindowTitle = KMSDRM_SetWindowTitle;
   200     device->SetWindowIcon = KMSDRM_SetWindowIcon;
   201     device->SetWindowPosition = KMSDRM_SetWindowPosition;
   202     device->SetWindowSize = KMSDRM_SetWindowSize;
   203     device->ShowWindow = KMSDRM_ShowWindow;
   204     device->HideWindow = KMSDRM_HideWindow;
   205     device->RaiseWindow = KMSDRM_RaiseWindow;
   206     device->MaximizeWindow = KMSDRM_MaximizeWindow;
   207     device->MinimizeWindow = KMSDRM_MinimizeWindow;
   208     device->RestoreWindow = KMSDRM_RestoreWindow;
   209     device->SetWindowGrab = KMSDRM_SetWindowGrab;
   210     device->DestroyWindow = KMSDRM_DestroyWindow;
   211     device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo;
   212 #if SDL_VIDEO_OPENGL_EGL
   213     device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary;
   214     device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress;
   215     device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary;
   216     device->GL_CreateContext = KMSDRM_GLES_CreateContext;
   217     device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent;
   218     device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval;
   219     device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval;
   220     device->GL_SwapWindow = KMSDRM_GLES_SwapWindow;
   221     device->GL_DeleteContext = KMSDRM_GLES_DeleteContext;
   222 #endif
   223     device->PumpEvents = KMSDRM_PumpEvents;
   224     device->free = KMSDRM_DeleteDevice;
   225 
   226     return device;
   227 
   228 cleanup:
   229     if (device)
   230         SDL_free(device);
   231     if (viddata)
   232         SDL_free(viddata);
   233     return NULL;
   234 }
   235 
   236 VideoBootStrap KMSDRM_bootstrap = {
   237     "KMSDRM",
   238     "KMS/DRM Video Driver",
   239     KMSDRM_Available,
   240     KMSDRM_CreateDevice
   241 };
   242 
   243 
   244 static void
   245 KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data)
   246 {
   247     KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data;
   248 
   249     if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) {
   250         KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
   251         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
   252     }
   253 
   254     SDL_free(fb_info);
   255 }
   256 
   257 KMSDRM_FBInfo *
   258 KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
   259 {
   260     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
   261     unsigned w,h;
   262     int ret;
   263     Uint32 stride, handle;
   264 
   265     /* Check for an existing framebuffer */
   266     KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
   267 
   268     if (fb_info) {
   269         return fb_info;
   270     }
   271 
   272     /* Create a structure that contains enough info to remove the framebuffer
   273        when the backing buffer is destroyed */
   274     fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo));
   275 
   276     if (!fb_info) {
   277         SDL_OutOfMemory();
   278         return NULL;
   279     }
   280 
   281     fb_info->drm_fd = viddata->drm_fd;
   282 
   283     /* Create framebuffer object for the buffer */
   284     w = KMSDRM_gbm_bo_get_width(bo);
   285     h = KMSDRM_gbm_bo_get_height(bo);
   286     stride = KMSDRM_gbm_bo_get_stride(bo);
   287     handle = KMSDRM_gbm_bo_get_handle(bo).u32;
   288     ret = KMSDRM_drmModeAddFB(viddata->drm_fd, w, h, 24, 32, stride, handle,
   289                                   &fb_info->fb_id);
   290     if (ret) {
   291       SDL_free(fb_info);
   292       return NULL;
   293     }
   294 
   295     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "New DRM FB (%u): %ux%u, stride %u from BO %p",
   296                  fb_info->fb_id, w, h, stride, (void *)bo);
   297 
   298     /* Associate our DRM framebuffer with this buffer object */
   299     KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);
   300 
   301     return fb_info;
   302 }
   303 
   304 static void
   305 KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
   306 {
   307     *((SDL_bool *) data) = SDL_FALSE;
   308 }
   309 
   310 SDL_bool
   311 KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
   312     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
   313     drmEventContext ev = {0};
   314     struct pollfd pfd = {0};
   315 
   316     ev.version = DRM_EVENT_CONTEXT_VERSION;
   317     ev.page_flip_handler = KMSDRM_FlipHandler;
   318 
   319     pfd.fd = viddata->drm_fd;
   320     pfd.events = POLLIN;
   321 
   322     while (windata->waiting_for_flip) {
   323         pfd.revents = 0;
   324 
   325         if (poll(&pfd, 1, timeout) < 0) {
   326             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
   327             return SDL_FALSE;
   328         }
   329 
   330         if (pfd.revents & (POLLHUP | POLLERR)) {
   331             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
   332             return SDL_FALSE;
   333         }
   334 
   335         if (pfd.revents & POLLIN) {
   336             /* Page flip? If so, drmHandleEvent will unset windata->waiting_for_flip */
   337             KMSDRM_drmHandleEvent(viddata->drm_fd, &ev);
   338         } else {
   339             /* Timed out and page flip didn't happen */
   340             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
   341             return SDL_FALSE;
   342         }
   343     }
   344 
   345     return SDL_TRUE;
   346 }
   347 
   348 /*****************************************************************************/
   349 /* SDL Video and Display initialization/handling functions                   */
   350 /* _this is a SDL_VideoDevice *                                              */
   351 /*****************************************************************************/
   352 static void
   353 KMSDRM_DestroySurfaces(_THIS, SDL_Window * window)
   354 {
   355     SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
   356 
   357     KMSDRM_WaitPageFlip(_this, windata, -1);
   358 
   359     if (windata->curr_bo) {
   360         KMSDRM_gbm_surface_release_buffer(windata->gs, windata->curr_bo);
   361         windata->curr_bo = NULL;
   362     }
   363 
   364     if (windata->next_bo) {
   365         KMSDRM_gbm_surface_release_buffer(windata->gs, windata->next_bo);
   366         windata->next_bo = NULL;
   367     }
   368 
   369 #if SDL_VIDEO_OPENGL_EGL
   370     SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   371 
   372     if (windata->egl_surface != EGL_NO_SURFACE) {
   373         SDL_EGL_DestroySurface(_this, windata->egl_surface);
   374         windata->egl_surface = EGL_NO_SURFACE;
   375     }
   376 #endif
   377 
   378     if (windata->gs) {
   379         KMSDRM_gbm_surface_destroy(windata->gs);
   380         windata->gs = NULL;
   381     }
   382 }
   383 
   384 int
   385 KMSDRM_CreateSurfaces(_THIS, SDL_Window * window)
   386 {
   387     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
   388     SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
   389     SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   390     Uint32 width = dispdata->mode.hdisplay;
   391     Uint32 height = dispdata->mode.vdisplay;
   392     Uint32 surface_fmt = GBM_FORMAT_XRGB8888;
   393     Uint32 surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
   394 #if SDL_VIDEO_OPENGL_EGL
   395     EGLContext egl_context;
   396 #endif
   397 
   398     if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm, surface_fmt, surface_flags)) {
   399         SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
   400     }
   401 
   402 #if SDL_VIDEO_OPENGL_EGL
   403     SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
   404     egl_context = (EGLContext)SDL_GL_GetCurrentContext();
   405 #endif
   406 
   407     KMSDRM_DestroySurfaces(_this, window);
   408 
   409     windata->gs = KMSDRM_gbm_surface_create(viddata->gbm, width, height, surface_fmt, surface_flags);
   410 
   411     if (!windata->gs) {
   412         return SDL_SetError("Could not create GBM surface");
   413     }
   414 
   415 #if SDL_VIDEO_OPENGL_EGL
   416     windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs);
   417 
   418     if (windata->egl_surface == EGL_NO_SURFACE) {
   419         return SDL_SetError("Could not create EGL window surface");
   420     }
   421 
   422     SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
   423 
   424     windata->egl_surface_dirty = 0;
   425 #endif
   426 
   427     return 0;
   428 }
   429 
   430 int
   431 KMSDRM_VideoInit(_THIS)
   432 {
   433     int ret = 0;
   434     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
   435     SDL_DisplayData *dispdata = NULL;
   436     drmModeRes *resources = NULL;
   437     drmModeEncoder *encoder = NULL;
   438     char devname[32];
   439     SDL_VideoDisplay display = {0};
   440 
   441     dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
   442 
   443     if (!dispdata) {
   444         return SDL_OutOfMemory();
   445     }
   446 
   447     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()");
   448 
   449     /* Open /dev/dri/cardNN */
   450     SDL_snprintf(devname, sizeof(devname), "/dev/dri/card%d", viddata->devindex);
   451 
   452     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", devname);
   453     viddata->drm_fd = open(devname, O_RDWR | O_CLOEXEC);
   454 
   455     if (viddata->drm_fd < 0) {
   456         ret = SDL_SetError("Could not open %s", devname);
   457         goto cleanup;
   458     }
   459 
   460     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd);
   461 
   462     viddata->gbm = KMSDRM_gbm_create_device(viddata->drm_fd);
   463     if (!viddata->gbm) {
   464         ret = SDL_SetError("Couldn't create gbm device.");
   465         goto cleanup;
   466     }
   467 
   468     /* Get all of the available connectors / devices / crtcs */
   469     resources = KMSDRM_drmModeGetResources(viddata->drm_fd);
   470     if (!resources) {
   471         ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd);
   472         goto cleanup;
   473     }
   474 
   475     for (int i = 0; i < resources->count_connectors; i++) {
   476         drmModeConnector *conn = KMSDRM_drmModeGetConnector(viddata->drm_fd, resources->connectors[i]);
   477 
   478         if (!conn) {
   479             continue;
   480         }
   481 
   482         if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
   483             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
   484                          conn->connector_id, conn->count_modes);
   485             dispdata->conn = conn;
   486             break;
   487         }
   488 
   489         KMSDRM_drmModeFreeConnector(conn);
   490     }
   491 
   492     if (!dispdata->conn) {
   493         ret = SDL_SetError("No currently active connector found.");
   494         goto cleanup;
   495     }
   496 
   497     /* Try to find the connector's current encoder */
   498     for (int i = 0; i < resources->count_encoders; i++) {
   499         encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
   500 
   501         if (!encoder) {
   502           continue;
   503         }
   504 
   505         if (encoder->encoder_id == dispdata->conn->encoder_id) {
   506             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
   507             break;
   508         }
   509 
   510         KMSDRM_drmModeFreeEncoder(encoder);
   511         encoder = NULL;
   512     }
   513 
   514     if (!encoder) {
   515         /* No encoder was connected, find the first supported one */
   516         for (int i = 0, j; i < resources->count_encoders; i++) {
   517             encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
   518 
   519             if (!encoder) {
   520               continue;
   521             }
   522 
   523             for (j = 0; j < dispdata->conn->count_encoders; j++) {
   524                 if (dispdata->conn->encoders[j] == encoder->encoder_id) {
   525                     break;
   526                 }
   527             }
   528 
   529             if (j != dispdata->conn->count_encoders) {
   530               break;
   531             }
   532 
   533             KMSDRM_drmModeFreeEncoder(encoder);
   534             encoder = NULL;
   535         }
   536     }
   537 
   538     if (!encoder) {
   539         ret = SDL_SetError("No connected encoder found.");
   540         goto cleanup;
   541     }
   542 
   543     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
   544 
   545     /* Try to find a CRTC connected to this encoder */
   546     dispdata->saved_crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
   547 
   548     if (!dispdata->saved_crtc) {
   549         /* No CRTC was connected, find the first CRTC that can be connected */
   550         for (int i = 0; i < resources->count_crtcs; i++) {
   551             if (encoder->possible_crtcs & (1 << i)) {
   552                 encoder->crtc_id = resources->crtcs[i];
   553                 dispdata->saved_crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
   554                 break;
   555             }
   556         }
   557     }
   558 
   559     if (!dispdata->saved_crtc) {
   560         ret = SDL_SetError("No CRTC found.");
   561         goto cleanup;
   562     }
   563 
   564     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Saved crtc_id %u, fb_id %u, (%u,%u), %ux%u",
   565                  dispdata->saved_crtc->crtc_id, dispdata->saved_crtc->buffer_id, dispdata->saved_crtc->x,
   566                  dispdata->saved_crtc->y, dispdata->saved_crtc->width, dispdata->saved_crtc->height);
   567 
   568     dispdata->crtc_id = encoder->crtc_id;
   569 
   570     /* Figure out the default mode to be set. If the current CRTC's mode isn't
   571        valid, select the first mode supported by the connector
   572 
   573        FIXME find first mode that specifies DRM_MODE_TYPE_PREFERRED */
   574     dispdata->mode = dispdata->saved_crtc->mode;
   575 
   576     if (dispdata->saved_crtc->mode_valid == 0) {
   577         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO,
   578             "Current mode is invalid, selecting connector's mode #0.");
   579         dispdata->mode = dispdata->conn->modes[0];
   580     }
   581 
   582     /* Setup the single display that's available */
   583 
   584     display.desktop_mode.w = dispdata->mode.hdisplay;
   585     display.desktop_mode.h = dispdata->mode.vdisplay;
   586     display.desktop_mode.refresh_rate = dispdata->mode.vrefresh;
   587 #if 1
   588     display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
   589 #else
   590     /* FIXME */
   591     drmModeFB *fb = drmModeGetFB(viddata->drm_fd, dispdata->saved_crtc->buffer_id);
   592     display.desktop_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
   593     drmModeFreeFB(fb);
   594 #endif
   595     display.current_mode = display.desktop_mode;
   596     display.driverdata = dispdata;
   597     SDL_AddVideoDisplay(&display);
   598 
   599 #ifdef SDL_INPUT_LINUXEV
   600     SDL_EVDEV_Init();
   601 #endif
   602 
   603     KMSDRM_InitMouse(_this);
   604 
   605     return ret;
   606 
   607 cleanup:
   608     if (encoder)
   609         KMSDRM_drmModeFreeEncoder(encoder);
   610     if (resources)
   611         KMSDRM_drmModeFreeResources(resources);
   612 
   613     if (ret != 0) {
   614         /* Error (complete) cleanup */
   615         if (dispdata->conn) {
   616             KMSDRM_drmModeFreeConnector(dispdata->conn);
   617             dispdata->conn = NULL;
   618         }
   619         if (dispdata->saved_crtc) {
   620             KMSDRM_drmModeFreeCrtc(dispdata->saved_crtc);
   621             dispdata->saved_crtc = NULL;
   622         }
   623         if (viddata->gbm) {
   624             KMSDRM_gbm_device_destroy(viddata->gbm);
   625             viddata->gbm = NULL;
   626         }
   627         if (viddata->drm_fd >= 0) {
   628             close(viddata->drm_fd);
   629             viddata->drm_fd = -1;
   630         }
   631         SDL_free(dispdata);
   632     }
   633     return ret;
   634 }
   635 
   636 void
   637 KMSDRM_VideoQuit(_THIS)
   638 {
   639     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
   640     SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
   641 
   642     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()");
   643 
   644     if (_this->gl_config.driver_loaded) {
   645         SDL_GL_UnloadLibrary();
   646     }
   647 
   648     /* Clear out the window list */
   649     SDL_free(viddata->windows);
   650     viddata->windows = NULL;
   651     viddata->max_windows = 0;
   652     viddata->num_windows = 0;
   653 
   654     /* Restore saved CRTC settings */
   655     if (viddata->drm_fd >= 0 && dispdata && dispdata->conn && dispdata->saved_crtc) {
   656         drmModeConnector *conn = dispdata->conn;
   657         drmModeCrtc *crtc = dispdata->saved_crtc;
   658 
   659         int ret = KMSDRM_drmModeSetCrtc(viddata->drm_fd, crtc->crtc_id, crtc->buffer_id,
   660                                         crtc->x, crtc->y, &conn->connector_id, 1, &crtc->mode);
   661 
   662         if (ret != 0) {
   663             SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original CRTC mode");
   664         }
   665     }
   666     if (dispdata && dispdata->conn) {
   667         KMSDRM_drmModeFreeConnector(dispdata->conn);
   668         dispdata->conn = NULL;
   669     }
   670     if (dispdata && dispdata->saved_crtc) {
   671         KMSDRM_drmModeFreeCrtc(dispdata->saved_crtc);
   672         dispdata->saved_crtc = NULL;
   673     }
   674     if (viddata->gbm) {
   675         KMSDRM_gbm_device_destroy(viddata->gbm);
   676         viddata->gbm = NULL;
   677     }
   678     if (viddata->drm_fd >= 0) {
   679         close(viddata->drm_fd);
   680         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", viddata->drm_fd);
   681         viddata->drm_fd = -1;
   682     }
   683 #ifdef SDL_INPUT_LINUXEV
   684     SDL_EVDEV_Quit();
   685 #endif
   686 }
   687 
   688 void
   689 KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
   690 {
   691     SDL_DisplayData *dispdata = display->driverdata;
   692     drmModeConnector *conn = dispdata->conn;
   693     SDL_DisplayMode mode;
   694 
   695     for (int i = 0; i < conn->count_modes; i++) {
   696         SDL_DisplayModeData *modedata = SDL_calloc(1, sizeof(SDL_DisplayModeData));
   697 
   698         if (modedata) {
   699           modedata->mode_index = i;
   700         }
   701 
   702         mode.w = conn->modes[i].hdisplay;
   703         mode.h = conn->modes[i].vdisplay;
   704         mode.refresh_rate = conn->modes[i].vrefresh;
   705         mode.format = SDL_PIXELFORMAT_ARGB8888;
   706         mode.driverdata = modedata;
   707 
   708         if (!SDL_AddDisplayMode(display, &mode)) {
   709             SDL_free(modedata);
   710         }
   711     }
   712 }
   713 
   714 int
   715 KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   716 {
   717     SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
   718     SDL_DisplayData *dispdata = (SDL_DisplayData *)display->driverdata;
   719     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   720     drmModeConnector *conn = dispdata->conn;
   721 
   722     if (!modedata) {
   723         return SDL_SetError("Mode doesn't have an associated index");
   724     }
   725 
   726     dispdata->mode = conn->modes[modedata->mode_index];
   727 
   728     for (int i = 0; i < viddata->num_windows; i++) {
   729         SDL_Window *window = viddata->windows[i];
   730         SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
   731 
   732 #if SDL_VIDEO_OPENGL_EGL
   733         /* Can't recreate EGL surfaces right now, need to wait until SwapWindow
   734            so the correct thread-local surface and context state are available */
   735         windata->egl_surface_dirty = 1;
   736 #else
   737         if (KMSDRM_CreateSurfaces(_this, window)) {
   738             return -1;
   739         }
   740 #endif
   741 
   742         /* Tell app about the resize */
   743         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode->w, mode->h);
   744     }
   745 
   746     return 0;
   747 }
   748 
   749 int
   750 KMSDRM_CreateWindow(_THIS, SDL_Window * window)
   751 {
   752     SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
   753     SDL_WindowData *windata;
   754     SDL_VideoDisplay *display;
   755 
   756 #if SDL_VIDEO_OPENGL_EGL
   757     if (!_this->egl_data) {
   758         if (SDL_GL_LoadLibrary(NULL) < 0) {
   759             goto error;
   760         }
   761     }
   762 #endif
   763 
   764     /* Allocate window internal data */
   765     windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
   766 
   767     if (!windata) {
   768         SDL_OutOfMemory();
   769         goto error;
   770     }
   771 
   772     /* Windows have one size for now */
   773     display = SDL_GetDisplayForWindow(window);
   774     window->w = display->desktop_mode.w;
   775     window->h = display->desktop_mode.h;
   776 
   777     /* Maybe you didn't ask for a fullscreen OpenGL window, but that's what you get */
   778     window->flags |= (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
   779 
   780     /* In case we want low-latency, double-buffer video, we take note here */
   781     windata->double_buffer = SDL_FALSE;
   782 
   783     if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
   784         windata->double_buffer = SDL_TRUE;
   785     }
   786 
   787     /* Setup driver data for this window */
   788     window->driverdata = windata;
   789 
   790     if (KMSDRM_CreateSurfaces(_this, window)) {
   791       goto error;
   792     }
   793 
   794     /* Add window to the internal list of tracked windows. Note, while it may
   795        seem odd to support multiple fullscreen windows, some apps create an
   796        extra window as a dummy surface when working with multiple contexts */
   797     windata->viddata = viddata;
   798 
   799     if (viddata->num_windows >= viddata->max_windows) {
   800         int new_max_windows = viddata->max_windows + 1;
   801         viddata->windows = (SDL_Window **)SDL_realloc(viddata->windows,
   802               new_max_windows * sizeof(SDL_Window *));
   803         viddata->max_windows = new_max_windows;
   804 
   805         if (!viddata->windows) {
   806             SDL_OutOfMemory();
   807             goto error;
   808         }
   809     }
   810 
   811     viddata->windows[viddata->num_windows++] = window;
   812 
   813     /* Focus on the newly created window */
   814     SDL_SetMouseFocus(window);
   815     SDL_SetKeyboardFocus(window);
   816 
   817     return 0;
   818 
   819 error:
   820     KMSDRM_DestroyWindow(_this, window);
   821 
   822     return -1;
   823 }
   824 
   825 void
   826 KMSDRM_DestroyWindow(_THIS, SDL_Window * window)
   827 {
   828     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
   829     SDL_VideoData *viddata;
   830     if (!windata) {
   831         return;
   832     }
   833 
   834     /* Remove from the internal window list */
   835     viddata = windata->viddata;
   836 
   837     for (int i = 0; i < viddata->num_windows; i++) {
   838         if (viddata->windows[i] == window) {
   839             viddata->num_windows--;
   840 
   841             for (int j = i; j < viddata->num_windows; j++) {
   842                 viddata->windows[j] = viddata->windows[j + 1];
   843             }
   844 
   845             break;
   846         }
   847     }
   848 
   849     KMSDRM_DestroySurfaces(_this, window);
   850 
   851     window->driverdata = NULL;
   852 
   853     SDL_free(windata);
   854 }
   855 
   856 int
   857 KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   858 {
   859     return -1;
   860 }
   861 
   862 void
   863 KMSDRM_SetWindowTitle(_THIS, SDL_Window * window)
   864 {
   865 }
   866 void
   867 KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   868 {
   869 }
   870 void
   871 KMSDRM_SetWindowPosition(_THIS, SDL_Window * window)
   872 {
   873 }
   874 void
   875 KMSDRM_SetWindowSize(_THIS, SDL_Window * window)
   876 {
   877 }
   878 void
   879 KMSDRM_ShowWindow(_THIS, SDL_Window * window)
   880 {
   881 }
   882 void
   883 KMSDRM_HideWindow(_THIS, SDL_Window * window)
   884 {
   885 }
   886 void
   887 KMSDRM_RaiseWindow(_THIS, SDL_Window * window)
   888 {
   889 }
   890 void
   891 KMSDRM_MaximizeWindow(_THIS, SDL_Window * window)
   892 {
   893 }
   894 void
   895 KMSDRM_MinimizeWindow(_THIS, SDL_Window * window)
   896 {
   897 }
   898 void
   899 KMSDRM_RestoreWindow(_THIS, SDL_Window * window)
   900 {
   901 }
   902 void
   903 KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   904 {
   905 
   906 }
   907 
   908 /*****************************************************************************/
   909 /* SDL Window Manager function                                               */
   910 /*****************************************************************************/
   911 SDL_bool
   912 KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
   913 {
   914     if (info->version.major <= SDL_MAJOR_VERSION) {
   915         return SDL_TRUE;
   916     } else {
   917         SDL_SetError("application not compiled with SDL %d.%d\n",
   918                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   919         return SDL_FALSE;
   920     }
   921 
   922     /* Failed to get window manager information */
   923     return SDL_FALSE;
   924 }
   925 
   926 #endif /* SDL_VIDEO_DRIVER_KMSDRM */
   927 
   928 /* vi: set ts=4 sw=4 expandtab: */