src/video/kmsdrm/SDL_kmsdrmvideo.c
author Ethan Lee <flibitijibibo@flibitijibibo.com>
Wed, 17 Jul 2019 23:20:57 -0400
changeset 12950 05dddfb66b85
parent 12892 d171cb5b389d
permissions -rw-r--r--
Copypaste SDL_NSLog to UIKit backend, document it as such
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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_mouse_c.h"
    32 #include "../../events/SDL_keyboard_c.h"
    33 
    34 #ifdef SDL_INPUT_LINUXEV
    35 #include "../../core/linux/SDL_evdev.h"
    36 #endif
    37 
    38 /* KMS/DRM declarations */
    39 #include "SDL_kmsdrmvideo.h"
    40 #include "SDL_kmsdrmevents.h"
    41 #include "SDL_kmsdrmopengles.h"
    42 #include "SDL_kmsdrmmouse.h"
    43 #include "SDL_kmsdrmdyn.h"
    44 #include <sys/stat.h>
    45 #include <dirent.h>
    46 #include <errno.h>
    47 
    48 #define KMSDRM_DRI_PATH "/dev/dri/"
    49 
    50 static int
    51 check_modestting(int devindex)
    52 {
    53     SDL_bool available = SDL_FALSE;
    54     char device[512];
    55     int drm_fd;
    56 
    57     SDL_snprintf(device, sizeof (device), "%scard%d", KMSDRM_DRI_PATH, devindex);
    58 
    59     drm_fd = open(device, O_RDWR | O_CLOEXEC);
    60     if (drm_fd >= 0) {
    61         if (SDL_KMSDRM_LoadSymbols()) {
    62             drmModeRes *resources = KMSDRM_drmModeGetResources(drm_fd);
    63             if (resources != NULL) {
    64                 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "%scard%d connector, encoder and CRTC counts are: %d %d %d",
    65                              KMSDRM_DRI_PATH, devindex,
    66                              resources->count_connectors, resources->count_encoders, resources->count_crtcs);
    67 
    68                 if (resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0) {
    69                     available = SDL_TRUE;
    70                 }
    71                 KMSDRM_drmModeFreeResources(resources);
    72             }
    73             SDL_KMSDRM_UnloadSymbols();
    74         }
    75         close(drm_fd);
    76     }
    77 
    78     return available;
    79 }
    80 
    81 static int get_dricount(void)
    82 {
    83     int devcount = 0;
    84     struct dirent *res;
    85     struct stat sb;
    86     DIR *folder;
    87 
    88     if (!(stat(KMSDRM_DRI_PATH, &sb) == 0
    89                 && S_ISDIR(sb.st_mode))) {
    90         printf("The path %s cannot be opened or is not available\n",
    91                KMSDRM_DRI_PATH);
    92         return 0;
    93     }
    94 
    95     if (access(KMSDRM_DRI_PATH, F_OK) == -1) {
    96         printf("The path %s cannot be opened\n",
    97                KMSDRM_DRI_PATH);
    98         return 0;
    99     }
   100 
   101     folder = opendir(KMSDRM_DRI_PATH);
   102     if (folder) {
   103         while ((res = readdir(folder))) {
   104             int len = SDL_strlen(res->d_name);
   105             if (len > 4 && SDL_strncmp(res->d_name, "card", 4) == 0) {
   106                 devcount++;
   107             }
   108         }
   109         closedir(folder);
   110     }
   111 
   112     return devcount;
   113 }
   114 
   115 static int
   116 get_driindex(void)
   117 {
   118     const int devcount = get_dricount();
   119     int i;
   120 
   121     for (i = 0; i < devcount; i++) {
   122         if (check_modestting(i)) {
   123             return i;
   124         }
   125     }
   126 
   127     return -ENOENT;
   128 }
   129 
   130 static int
   131 KMSDRM_Available(void)
   132 {
   133     int ret = -ENOENT;
   134 
   135     ret = get_driindex();
   136     if (ret >= 0)
   137         return 1;
   138 
   139     return ret;
   140 }
   141 
   142 static void
   143 KMSDRM_Destroy(SDL_VideoDevice * device)
   144 {
   145     if (device->driverdata != NULL) {
   146         SDL_free(device->driverdata);
   147         device->driverdata = NULL;
   148     }
   149 
   150     SDL_free(device);
   151     SDL_KMSDRM_UnloadSymbols();
   152 }
   153 
   154 static SDL_VideoDevice *
   155 KMSDRM_Create(int devindex)
   156 {
   157     SDL_VideoDevice *device;
   158     SDL_VideoData *vdata;
   159 
   160     if (!devindex || (devindex > 99)) {
   161         devindex = get_driindex();
   162     }
   163 
   164     if (devindex < 0) {
   165         SDL_SetError("devindex (%d) must be between 0 and 99.\n", devindex);
   166         return NULL;
   167     }
   168 
   169     if (!SDL_KMSDRM_LoadSymbols()) {
   170         return NULL;
   171     }
   172 
   173     /* Initialize SDL_VideoDevice structure */
   174     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
   175     if (device == NULL) {
   176         SDL_OutOfMemory();
   177         return NULL;
   178     }
   179 
   180     /* Initialize internal data */
   181     vdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
   182     if (vdata == NULL) {
   183         SDL_OutOfMemory();
   184         goto cleanup;
   185     }
   186     vdata->devindex = devindex;
   187     vdata->drm_fd = -1;
   188 
   189     device->driverdata = vdata;
   190 
   191     /* Setup amount of available displays and current display */
   192     device->num_displays = 0;
   193 
   194     /* Set device free function */
   195     device->free = KMSDRM_Destroy;
   196 
   197     /* Setup all functions which we can handle */
   198     device->VideoInit = KMSDRM_VideoInit;
   199     device->VideoQuit = KMSDRM_VideoQuit;
   200     device->GetDisplayModes = KMSDRM_GetDisplayModes;
   201     device->SetDisplayMode = KMSDRM_SetDisplayMode;
   202     device->CreateSDLWindow = KMSDRM_CreateWindow;
   203     device->CreateSDLWindowFrom = KMSDRM_CreateWindowFrom;
   204     device->SetWindowTitle = KMSDRM_SetWindowTitle;
   205     device->SetWindowIcon = KMSDRM_SetWindowIcon;
   206     device->SetWindowPosition = KMSDRM_SetWindowPosition;
   207     device->SetWindowSize = KMSDRM_SetWindowSize;
   208     device->ShowWindow = KMSDRM_ShowWindow;
   209     device->HideWindow = KMSDRM_HideWindow;
   210     device->RaiseWindow = KMSDRM_RaiseWindow;
   211     device->MaximizeWindow = KMSDRM_MaximizeWindow;
   212     device->MinimizeWindow = KMSDRM_MinimizeWindow;
   213     device->RestoreWindow = KMSDRM_RestoreWindow;
   214     device->SetWindowGrab = KMSDRM_SetWindowGrab;
   215     device->DestroyWindow = KMSDRM_DestroyWindow;
   216     device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo;
   217 #if SDL_VIDEO_OPENGL_EGL
   218     device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary;
   219     device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress;
   220     device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary;
   221     device->GL_CreateContext = KMSDRM_GLES_CreateContext;
   222     device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent;
   223     device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval;
   224     device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval;
   225     device->GL_SwapWindow = KMSDRM_GLES_SwapWindow;
   226     device->GL_DeleteContext = KMSDRM_GLES_DeleteContext;
   227 #endif
   228 
   229     device->PumpEvents = KMSDRM_PumpEvents;
   230 
   231     return device;
   232 
   233 cleanup:
   234     if (device != NULL)
   235         SDL_free(device);
   236     if (vdata != NULL)
   237         SDL_free(vdata);
   238     return NULL;
   239 }
   240 
   241 VideoBootStrap KMSDRM_bootstrap = {
   242     "KMSDRM",
   243     "KMS/DRM Video Driver",
   244     KMSDRM_Available,
   245     KMSDRM_Create
   246 };
   247 
   248 
   249 static void
   250 KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data)
   251 {
   252     KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data;
   253 
   254     if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) {
   255         KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
   256         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
   257     }
   258 
   259     SDL_free(fb_info);
   260 }
   261 
   262 KMSDRM_FBInfo *
   263 KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
   264 {
   265     uint32_t w, h, stride, handle;
   266     int ret;
   267     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   268     KMSDRM_FBInfo *fb_info;
   269 
   270     fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
   271     if (fb_info != NULL) {
   272         /* Have a previously used framebuffer, return it */
   273         return fb_info;
   274     }
   275 
   276     /* Here a new DRM FB must be created */
   277     fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo));
   278     if (fb_info == NULL) {
   279         SDL_OutOfMemory();
   280         return NULL;
   281     }
   282     fb_info->drm_fd = vdata->drm_fd;
   283 
   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 
   289     ret = KMSDRM_drmModeAddFB(vdata->drm_fd, w, h, 24, 32, stride, handle, &fb_info->fb_id);
   290     if (ret < 0) {
   291        SDL_free(fb_info);
   292        return NULL;
   293     }
   294     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "New DRM FB (%u): %ux%u, stride %u from BO %p", fb_info->fb_id, w, h, stride, (void *)bo);
   295 
   296     /* Associate our DRM framebuffer with this buffer object */
   297     KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);
   298     return fb_info;
   299 }
   300 
   301 SDL_bool
   302 KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *wdata, int timeout) {
   303     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   304 
   305     while (wdata->waiting_for_flip) {
   306         vdata->drm_pollfd.revents = 0;
   307         if (poll(&vdata->drm_pollfd, 1, timeout) < 0) {
   308             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
   309             return SDL_FALSE;
   310         }
   311 
   312         if (vdata->drm_pollfd.revents & (POLLHUP | POLLERR)) {
   313             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
   314             return SDL_FALSE;
   315         }
   316 
   317         if (vdata->drm_pollfd.revents & POLLIN) {
   318             /* Page flip? If so, drmHandleEvent will unset wdata->waiting_for_flip */
   319             KMSDRM_drmHandleEvent(vdata->drm_fd, &vdata->drm_evctx);
   320         } else {
   321             /* Timed out and page flip didn't happen */
   322             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
   323             return SDL_FALSE;
   324         }
   325     }
   326     return SDL_TRUE;
   327 }
   328 
   329 static void
   330 KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
   331 {
   332     *((SDL_bool *) data) = SDL_FALSE;
   333 }
   334 
   335 
   336 /*****************************************************************************/
   337 /* SDL Video and Display initialization/handling functions                   */
   338 /* _this is a SDL_VideoDevice *                                              */
   339 /*****************************************************************************/
   340 int
   341 KMSDRM_VideoInit(_THIS)
   342 {
   343     int i, j;
   344     SDL_bool found;
   345     int ret = 0;
   346     char *devname;
   347     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   348     drmModeRes *resources = NULL;
   349     drmModeConnector *connector = NULL;
   350     drmModeEncoder *encoder = NULL;
   351     SDL_DisplayMode current_mode;
   352     SDL_VideoDisplay display;
   353 
   354     /* Allocate display internal data */
   355     SDL_DisplayData *data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
   356     if (data == NULL) {
   357         return SDL_OutOfMemory();
   358     }
   359 
   360     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()");
   361 
   362     /* Open /dev/dri/cardNN */
   363     devname = (char *) SDL_calloc(1, 16);
   364     if (devname == NULL) {
   365         ret = SDL_OutOfMemory();
   366         goto cleanup;
   367     }
   368     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device /dev/dri/card%d", vdata->devindex);
   369     SDL_snprintf(devname, 16, "/dev/dri/card%d", vdata->devindex);
   370     vdata->drm_fd = open(devname, O_RDWR | O_CLOEXEC);
   371     SDL_free(devname);
   372 
   373     if (vdata->drm_fd < 0) {
   374         ret = SDL_SetError("Could not open /dev/dri/card%d.", vdata->devindex);
   375         goto cleanup;
   376     }
   377     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", vdata->drm_fd);
   378 
   379     vdata->gbm = KMSDRM_gbm_create_device(vdata->drm_fd);
   380     if (vdata->gbm == NULL) {
   381         ret = SDL_SetError("Couldn't create gbm device.");
   382         goto cleanup;
   383     }
   384 
   385     /* Find the first available connector with modes */
   386     resources = KMSDRM_drmModeGetResources(vdata->drm_fd);
   387     if (!resources) {
   388         ret = SDL_SetError("drmModeGetResources(%d) failed", vdata->drm_fd);
   389         goto cleanup;
   390     }
   391 
   392     for (i = 0; i < resources->count_connectors; i++) {
   393         connector = KMSDRM_drmModeGetConnector(vdata->drm_fd, resources->connectors[i]);
   394         if (connector == NULL)
   395             continue;
   396 
   397         if (connector->connection == DRM_MODE_CONNECTED &&
   398             connector->count_modes > 0) {
   399             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
   400                          connector->connector_id, connector->count_modes);
   401             vdata->saved_conn_id = connector->connector_id;
   402             break;
   403         }
   404 
   405         KMSDRM_drmModeFreeConnector(connector);
   406         connector = NULL;
   407     }
   408 
   409     if (i == resources->count_connectors) {
   410         ret = SDL_SetError("No currently active connector found.");
   411         goto cleanup;
   412     }
   413 
   414     found = SDL_FALSE;
   415 
   416     for (i = 0; i < resources->count_encoders; i++) {
   417         encoder = KMSDRM_drmModeGetEncoder(vdata->drm_fd, resources->encoders[i]);
   418 
   419         if (encoder == NULL)
   420             continue;
   421 
   422         if (encoder->encoder_id == connector->encoder_id) {
   423             data->encoder_id = encoder->encoder_id;
   424             found = SDL_TRUE;
   425         } else {
   426             for (j = 0; j < connector->count_encoders; j++) {
   427                 if (connector->encoders[j] == encoder->encoder_id) {
   428                     data->encoder_id = encoder->encoder_id;
   429                     found = SDL_TRUE;
   430                     break;
   431                 }
   432             }
   433         }
   434 
   435         if (found == SDL_TRUE) {
   436             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", data->encoder_id);
   437             break;
   438         }
   439 
   440         KMSDRM_drmModeFreeEncoder(encoder);
   441         encoder = NULL;
   442     }
   443 
   444     if (i == resources->count_encoders) {
   445         ret = SDL_SetError("No connected encoder found.");
   446         goto cleanup;
   447     }
   448 
   449     vdata->saved_crtc = KMSDRM_drmModeGetCrtc(vdata->drm_fd, encoder->crtc_id);
   450 
   451     if (vdata->saved_crtc == NULL) {
   452         for (i = 0; i < resources->count_crtcs; i++) {
   453             if (encoder->possible_crtcs & (1 << i)) {
   454                 encoder->crtc_id = resources->crtcs[i];
   455                 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Set encoder's CRTC to %d.", encoder->crtc_id);
   456                 vdata->saved_crtc = KMSDRM_drmModeGetCrtc(vdata->drm_fd, encoder->crtc_id);
   457                 break;
   458             }
   459         }
   460     }
   461 
   462     if (vdata->saved_crtc == NULL) {
   463         ret = SDL_SetError("No CRTC found.");
   464         goto cleanup;
   465     }
   466     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Saved crtc_id %u, fb_id %u, (%u,%u), %ux%u",
   467                  vdata->saved_crtc->crtc_id, vdata->saved_crtc->buffer_id, vdata->saved_crtc->x,
   468                  vdata->saved_crtc->y, vdata->saved_crtc->width, vdata->saved_crtc->height);
   469     data->crtc_id = encoder->crtc_id;
   470     data->cur_mode = vdata->saved_crtc->mode;
   471     vdata->crtc_id = encoder->crtc_id;
   472 
   473     // select default mode if this one is not valid
   474     if (vdata->saved_crtc->mode_valid == 0) {
   475         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO,
   476             "Current mode is invalid, selecting connector's mode #0.");
   477         data->cur_mode = connector->modes[0];
   478     }
   479 
   480     SDL_zero(current_mode);
   481 
   482     current_mode.w = data->cur_mode.hdisplay;
   483     current_mode.h = data->cur_mode.vdisplay;
   484     current_mode.refresh_rate = data->cur_mode.vrefresh;
   485 
   486     /* FIXME ?
   487     drmModeFB *fb = drmModeGetFB(vdata->drm_fd, vdata->saved_crtc->buffer_id);
   488     current_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
   489     drmModeFreeFB(fb);
   490     */
   491     current_mode.format = SDL_PIXELFORMAT_ARGB8888;
   492 
   493     current_mode.driverdata = NULL;
   494 
   495     SDL_zero(display);
   496     display.desktop_mode = current_mode;
   497     display.current_mode = current_mode;
   498 
   499     display.driverdata = data;
   500     /* SDL_VideoQuit will later SDL_free(display.driverdata) */
   501     SDL_AddVideoDisplay(&display);
   502 
   503     /* Setup page flip handler */
   504     vdata->drm_pollfd.fd = vdata->drm_fd;
   505     vdata->drm_pollfd.events = POLLIN;
   506     vdata->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
   507     vdata->drm_evctx.page_flip_handler = KMSDRM_FlipHandler;
   508 
   509 #ifdef SDL_INPUT_LINUXEV
   510     SDL_EVDEV_Init();
   511 #endif
   512 
   513     KMSDRM_InitMouse(_this);
   514 
   515     return ret;
   516 
   517 cleanup:
   518     if (encoder != NULL)
   519         KMSDRM_drmModeFreeEncoder(encoder);
   520     if (connector != NULL)
   521         KMSDRM_drmModeFreeConnector(connector);
   522     if (resources != NULL)
   523         KMSDRM_drmModeFreeResources(resources);
   524 
   525     if (ret != 0) {
   526         /* Error (complete) cleanup */
   527         SDL_free(data);
   528         if(vdata->saved_crtc != NULL) {
   529             KMSDRM_drmModeFreeCrtc(vdata->saved_crtc);
   530             vdata->saved_crtc = NULL;
   531         }
   532         if (vdata->gbm != NULL) {
   533             KMSDRM_gbm_device_destroy(vdata->gbm);
   534             vdata->gbm = NULL;
   535         }
   536         if (vdata->drm_fd >= 0) {
   537             close(vdata->drm_fd);
   538             vdata->drm_fd = -1;
   539         }
   540     }
   541     return ret;
   542 }
   543 
   544 void
   545 KMSDRM_VideoQuit(_THIS)
   546 {
   547     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   548 
   549     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()");
   550 
   551     if (_this->gl_config.driver_loaded) {
   552         SDL_GL_UnloadLibrary();
   553     }
   554 
   555     if(vdata->saved_crtc != NULL) {
   556         if(vdata->drm_fd >= 0 && vdata->saved_conn_id > 0) {
   557             /* Restore saved CRTC settings */
   558             drmModeCrtc *crtc = vdata->saved_crtc;
   559             if(KMSDRM_drmModeSetCrtc(vdata->drm_fd, crtc->crtc_id, crtc->buffer_id,
   560                                      crtc->x, crtc->y, &vdata->saved_conn_id, 1,
   561                                      &crtc->mode) != 0) {
   562                 SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original CRTC mode");
   563             }
   564         }
   565         KMSDRM_drmModeFreeCrtc(vdata->saved_crtc);
   566         vdata->saved_crtc = NULL;
   567     }
   568     if (vdata->gbm != NULL) {
   569         KMSDRM_gbm_device_destroy(vdata->gbm);
   570         vdata->gbm = NULL;
   571     }
   572     if (vdata->drm_fd >= 0) {
   573         close(vdata->drm_fd);
   574         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", vdata->drm_fd);
   575         vdata->drm_fd = -1;
   576     }
   577 #ifdef SDL_INPUT_LINUXEV
   578     SDL_EVDEV_Quit();
   579 #endif
   580 }
   581 
   582 void
   583 KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
   584 {
   585     /* Only one display mode available, the current one */
   586     SDL_AddDisplayMode(display, &display->current_mode);
   587 }
   588 
   589 int
   590 KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   591 {
   592     return 0;
   593 }
   594 
   595 int
   596 KMSDRM_CreateWindow(_THIS, SDL_Window * window)
   597 {
   598     SDL_WindowData *wdata;
   599     SDL_VideoDisplay *display;
   600     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   601     Uint32 surface_fmt, surface_flags;
   602 
   603     /* Allocate window internal data */
   604     wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
   605     if (wdata == NULL) {
   606         SDL_OutOfMemory();
   607         goto error;
   608     }
   609 
   610     wdata->waiting_for_flip = SDL_FALSE;
   611     display = SDL_GetDisplayForWindow(window);
   612 
   613     /* Windows have one size for now */
   614     window->w = display->desktop_mode.w;
   615     window->h = display->desktop_mode.h;
   616 
   617     /* Maybe you didn't ask for a fullscreen OpenGL window, but that's what you get */
   618     window->flags |= (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
   619 
   620     surface_fmt = GBM_FORMAT_XRGB8888;
   621     surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
   622 
   623     if (!KMSDRM_gbm_device_is_format_supported(vdata->gbm, surface_fmt, surface_flags)) {
   624         SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
   625     }
   626     wdata->gs = KMSDRM_gbm_surface_create(vdata->gbm, window->w, window->h, surface_fmt, surface_flags);
   627 
   628 #if SDL_VIDEO_OPENGL_EGL
   629     if (!_this->egl_data) {
   630         if (SDL_GL_LoadLibrary(NULL) < 0) {
   631             goto error;
   632         }
   633     }
   634     SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
   635     wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) wdata->gs);
   636 
   637     if (wdata->egl_surface == EGL_NO_SURFACE) {
   638         SDL_SetError("Could not create EGL window surface");
   639         goto error;
   640     }
   641 #endif /* SDL_VIDEO_OPENGL_EGL */
   642 
   643     /* In case we want low-latency, double-buffer video, we take note here */
   644     wdata->double_buffer = SDL_FALSE;
   645     if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
   646         wdata->double_buffer = SDL_TRUE;
   647     }
   648 
   649     /* Window is created, but we have yet to set up CRTC to one of the GBM buffers if we want
   650        drmModePageFlip to work, and we can't do it until EGL is completely setup, because we
   651        need to do eglSwapBuffers so we can get a valid GBM buffer object to call
   652        drmModeSetCrtc on it. */
   653     wdata->crtc_ready = SDL_FALSE;
   654 
   655     /* Setup driver data for this window */
   656     window->driverdata = wdata;
   657 
   658     /* One window, it always has focus */
   659     SDL_SetMouseFocus(window);
   660     SDL_SetKeyboardFocus(window);
   661 
   662     /* Window has been successfully created */
   663     return 0;
   664 
   665 error:
   666     if (wdata != NULL) {
   667 #if SDL_VIDEO_OPENGL_EGL
   668         if (wdata->egl_surface != EGL_NO_SURFACE)
   669             SDL_EGL_DestroySurface(_this, wdata->egl_surface);
   670 #endif /* SDL_VIDEO_OPENGL_EGL */
   671         if (wdata->gs != NULL)
   672             KMSDRM_gbm_surface_destroy(wdata->gs);
   673         SDL_free(wdata);
   674     }
   675     return -1;
   676 }
   677 
   678 void
   679 KMSDRM_DestroyWindow(_THIS, SDL_Window * window)
   680 {
   681     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   682     if(data) {
   683         /* Wait for any pending page flips and unlock buffer */
   684         KMSDRM_WaitPageFlip(_this, data, -1);
   685         if (data->crtc_bo != NULL) {
   686             KMSDRM_gbm_surface_release_buffer(data->gs, data->crtc_bo);
   687             data->crtc_bo = NULL;
   688         }
   689         if (data->next_bo != NULL) {
   690             KMSDRM_gbm_surface_release_buffer(data->gs, data->next_bo);
   691             data->next_bo = NULL;
   692         }
   693         if (data->current_bo != NULL) {
   694             KMSDRM_gbm_surface_release_buffer(data->gs, data->current_bo);
   695             data->current_bo = NULL;
   696         }
   697 #if SDL_VIDEO_OPENGL_EGL
   698         SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   699         if (data->egl_surface != EGL_NO_SURFACE) {
   700             SDL_EGL_DestroySurface(_this, data->egl_surface);
   701         }
   702 #endif /* SDL_VIDEO_OPENGL_EGL */
   703         if (data->gs != NULL) {
   704             KMSDRM_gbm_surface_destroy(data->gs);
   705             data->gs = NULL;
   706         }
   707         SDL_free(data);
   708         window->driverdata = NULL;
   709     }
   710 }
   711 
   712 int
   713 KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   714 {
   715     return -1;
   716 }
   717 
   718 void
   719 KMSDRM_SetWindowTitle(_THIS, SDL_Window * window)
   720 {
   721 }
   722 void
   723 KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   724 {
   725 }
   726 void
   727 KMSDRM_SetWindowPosition(_THIS, SDL_Window * window)
   728 {
   729 }
   730 void
   731 KMSDRM_SetWindowSize(_THIS, SDL_Window * window)
   732 {
   733 }
   734 void
   735 KMSDRM_ShowWindow(_THIS, SDL_Window * window)
   736 {
   737 }
   738 void
   739 KMSDRM_HideWindow(_THIS, SDL_Window * window)
   740 {
   741 }
   742 void
   743 KMSDRM_RaiseWindow(_THIS, SDL_Window * window)
   744 {
   745 }
   746 void
   747 KMSDRM_MaximizeWindow(_THIS, SDL_Window * window)
   748 {
   749 }
   750 void
   751 KMSDRM_MinimizeWindow(_THIS, SDL_Window * window)
   752 {
   753 }
   754 void
   755 KMSDRM_RestoreWindow(_THIS, SDL_Window * window)
   756 {
   757 }
   758 void
   759 KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   760 {
   761 
   762 }
   763 
   764 /*****************************************************************************/
   765 /* SDL Window Manager function                                               */
   766 /*****************************************************************************/
   767 SDL_bool
   768 KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
   769 {
   770     if (info->version.major <= SDL_MAJOR_VERSION) {
   771         return SDL_TRUE;
   772     } else {
   773         SDL_SetError("application not compiled with SDL %d.%d\n",
   774                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   775         return SDL_FALSE;
   776     }
   777 
   778     /* Failed to get window manager information */
   779     return SDL_FALSE;
   780 }
   781 
   782 #endif /* SDL_VIDEO_DRIVER_KMSDRM */
   783 
   784 /* vi: set ts=4 sw=4 expandtab: */