src/video/kmsdrm/SDL_kmsdrmvideo.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sat, 05 Aug 2017 22:10:36 +0200
changeset 11190 478630f6b756
parent 11186 a01f9b70ff97
child 11217 d9c3f934bd0e
permissions -rw-r--r--
kmsdrm: Fixed crashes if allocating memory failed.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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_version.h"
    29 #include "SDL_syswm.h"
    30 #include "SDL_loadso.h"
    31 #include "SDL_events.h"
    32 #include "SDL_log.h"
    33 #include "../../events/SDL_mouse_c.h"
    34 #include "../../events/SDL_keyboard_c.h"
    35 
    36 #ifdef SDL_INPUT_LINUXEV
    37 #include "../../core/linux/SDL_evdev.h"
    38 #endif
    39 
    40 /* KMS/DRM declarations */
    41 #include "SDL_kmsdrmvideo.h"
    42 #include "SDL_kmsdrmevents_c.h"
    43 #include "SDL_kmsdrmopengles.h"
    44 #include "SDL_kmsdrmmouse.h"
    45 #include "SDL_kmsdrmdyn.h"
    46 
    47 #define KMSDRM_DRI_CARD_0 "/dev/dri/card0"
    48 
    49 static int
    50 KMSDRM_Available(void)
    51 {
    52     int available = 0;
    53 
    54     int drm_fd = open(KMSDRM_DRI_CARD_0, O_RDWR | O_CLOEXEC);
    55     if (drm_fd >= 0) {
    56         if (SDL_KMSDRM_LoadSymbols()) {
    57             drmModeRes *resources = KMSDRM_drmModeGetResources(drm_fd);
    58             if (resources != NULL) {
    59                 available = 1;
    60                 KMSDRM_drmModeFreeResources(resources);
    61             }
    62             SDL_KMSDRM_UnloadSymbols();
    63         }
    64         close(drm_fd);
    65     }
    66 
    67     return available;
    68 }
    69 
    70 static void
    71 KMSDRM_Destroy(SDL_VideoDevice * device)
    72 {
    73     if (device->driverdata != NULL) {
    74         SDL_free(device->driverdata);
    75         device->driverdata = NULL;
    76     }
    77 
    78     SDL_free(device);
    79     SDL_KMSDRM_UnloadSymbols();
    80 }
    81 
    82 static SDL_VideoDevice *
    83 KMSDRM_Create(int devindex)
    84 {
    85     SDL_VideoDevice *device;
    86     SDL_VideoData *vdata;
    87 
    88     if (devindex < 0 || devindex > 99) {
    89         SDL_SetError("devindex (%d) must be between 0 and 99.\n", devindex);
    90         return NULL;
    91     }
    92 
    93     if (!SDL_KMSDRM_LoadSymbols()) {
    94         return NULL;
    95     }
    96 
    97     /* Initialize SDL_VideoDevice structure */
    98     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    99     if (device == NULL) {
   100         SDL_OutOfMemory();
   101         return NULL;
   102     }
   103 
   104     /* Initialize internal data */
   105     vdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
   106     if (vdata == NULL) {
   107         SDL_OutOfMemory();
   108         goto cleanup;
   109     }
   110     vdata->devindex = devindex;
   111     vdata->drm_fd = -1;
   112 
   113     device->driverdata = vdata;
   114 
   115     /* Setup amount of available displays and current display */
   116     device->num_displays = 0;
   117 
   118     /* Set device free function */
   119     device->free = KMSDRM_Destroy;
   120 
   121     /* Setup all functions which we can handle */
   122     device->VideoInit = KMSDRM_VideoInit;
   123     device->VideoQuit = KMSDRM_VideoQuit;
   124     device->GetDisplayModes = KMSDRM_GetDisplayModes;
   125     device->SetDisplayMode = KMSDRM_SetDisplayMode;
   126     device->CreateWindow = KMSDRM_CreateWindow;
   127     device->CreateWindowFrom = KMSDRM_CreateWindowFrom;
   128     device->SetWindowTitle = KMSDRM_SetWindowTitle;
   129     device->SetWindowIcon = KMSDRM_SetWindowIcon;
   130     device->SetWindowPosition = KMSDRM_SetWindowPosition;
   131     device->SetWindowSize = KMSDRM_SetWindowSize;
   132     device->ShowWindow = KMSDRM_ShowWindow;
   133     device->HideWindow = KMSDRM_HideWindow;
   134     device->RaiseWindow = KMSDRM_RaiseWindow;
   135     device->MaximizeWindow = KMSDRM_MaximizeWindow;
   136     device->MinimizeWindow = KMSDRM_MinimizeWindow;
   137     device->RestoreWindow = KMSDRM_RestoreWindow;
   138     device->SetWindowGrab = KMSDRM_SetWindowGrab;
   139     device->DestroyWindow = KMSDRM_DestroyWindow;
   140     device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo;
   141 #if SDL_VIDEO_OPENGL_EGL
   142     device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary;
   143     device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress;
   144     device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary;
   145     device->GL_CreateContext = KMSDRM_GLES_CreateContext;
   146     device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent;
   147     device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval;
   148     device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval;
   149     device->GL_SwapWindow = KMSDRM_GLES_SwapWindow;
   150     device->GL_DeleteContext = KMSDRM_GLES_DeleteContext;
   151 #endif
   152 
   153     device->PumpEvents = KMSDRM_PumpEvents;
   154 
   155     return device;
   156 
   157 cleanup:
   158     if (device != NULL)
   159         SDL_free(device);
   160     if (vdata != NULL)
   161         SDL_free(vdata);
   162     return NULL;
   163 }
   164 
   165 VideoBootStrap KMSDRM_bootstrap = {
   166     "KMSDRM",
   167     "KMS/DRM Video Driver",
   168     KMSDRM_Available,
   169     KMSDRM_Create
   170 };
   171 
   172 
   173 static void
   174 KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data)
   175 {
   176     KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data;
   177 
   178     if (fb_info && fb_info->drm_fd > 0 && fb_info->fb_id != 0) {
   179         KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
   180         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
   181     }
   182 
   183     free(fb_info);
   184 }
   185 
   186 KMSDRM_FBInfo *
   187 KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo)
   188 {
   189     uint32_t w, h, stride, handle;
   190     int ret;
   191     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   192     KMSDRM_FBInfo *fb_info;
   193 
   194     fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo);
   195     if (fb_info != NULL) {
   196         /* Have a previously used framebuffer, return it */
   197         return fb_info;
   198     }
   199 
   200     /* Here a new DRM FB must be created */
   201     fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo));
   202     if (fb_info == NULL) {
   203         SDL_OutOfMemory();
   204         return NULL;
   205     }
   206     fb_info->drm_fd = vdata->drm_fd;
   207 
   208     w  = KMSDRM_gbm_bo_get_width(bo);
   209     h = KMSDRM_gbm_bo_get_height(bo);
   210     stride = KMSDRM_gbm_bo_get_stride(bo);
   211     handle = KMSDRM_gbm_bo_get_handle(bo).u32;
   212 
   213     ret = KMSDRM_drmModeAddFB(vdata->drm_fd, w, h, 24, 32, stride, handle, &fb_info->fb_id);
   214     if (ret < 0) {
   215        free(fb_info);
   216        return NULL;
   217     }
   218     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);
   219 
   220     /* Associate our DRM framebuffer with this buffer object */
   221     KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback);
   222     return fb_info;
   223 }
   224 
   225 SDL_bool
   226 KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *wdata, int timeout) {
   227     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   228 
   229     while (wdata->waiting_for_flip) {
   230         vdata->drm_pollfd.revents = 0;
   231         if (poll(&vdata->drm_pollfd, 1, timeout) < 0) {
   232             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
   233             return SDL_FALSE;
   234         }
   235 
   236         if (vdata->drm_pollfd.revents & (POLLHUP | POLLERR)) {
   237             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
   238             return SDL_FALSE;
   239         }
   240 
   241         if (vdata->drm_pollfd.revents & POLLIN) {
   242             /* Page flip? If so, drmHandleEvent will unset wdata->waiting_for_flip */
   243             KMSDRM_drmHandleEvent(vdata->drm_fd, &vdata->drm_evctx);
   244         } else {
   245             /* Timed out and page flip didn't happen */
   246             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
   247             return SDL_FALSE;
   248         }
   249     }
   250     return SDL_TRUE;
   251 }
   252 
   253 static void
   254 KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
   255 {
   256     *((SDL_bool *) data) = SDL_FALSE;
   257 }
   258 
   259 
   260 /*****************************************************************************/
   261 /* SDL Video and Display initialization/handling functions                   */
   262 /* _this is a SDL_VideoDevice *                                              */
   263 /*****************************************************************************/
   264 int
   265 KMSDRM_VideoInit(_THIS)
   266 {
   267     int i;
   268     int ret = 0;
   269     char *devname;
   270     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   271     drmModeRes *resources = NULL;
   272     drmModeConnector *connector = NULL;
   273     drmModeEncoder *encoder = NULL;
   274     SDL_DisplayMode current_mode;
   275     SDL_VideoDisplay display;
   276 
   277     /* Allocate display internal data */
   278     SDL_DisplayData *data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
   279     if (data == NULL) {
   280         return SDL_OutOfMemory();
   281     }
   282 
   283     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()");
   284 
   285     /* Open /dev/dri/cardNN */
   286     devname = (char *) SDL_calloc(1, 16);
   287     if (devname == NULL) {
   288         ret = SDL_OutOfMemory();
   289         goto cleanup;
   290     }
   291     SDL_snprintf(devname, 16, "/dev/dri/card%d", vdata->devindex);
   292     vdata->drm_fd = open(devname, O_RDWR | O_CLOEXEC);
   293     SDL_free(devname);
   294 
   295     if (vdata->drm_fd < 0) {
   296         ret = SDL_SetError("Could not open /dev/dri/card%d.", vdata->devindex);
   297         goto cleanup;
   298     }
   299     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", vdata->drm_fd);
   300 
   301     vdata->gbm = KMSDRM_gbm_create_device(vdata->drm_fd);
   302     if (vdata->gbm == NULL) {
   303         ret = SDL_SetError("Couldn't create gbm device.");
   304         goto cleanup;
   305     }
   306 
   307     /* Find the first available connector with modes */
   308     resources = KMSDRM_drmModeGetResources(vdata->drm_fd);
   309     if (!resources) {
   310         ret = SDL_SetError("drmModeGetResources(%d) failed", vdata->drm_fd);
   311         goto cleanup;
   312     }
   313 
   314     for (i = 0; i < resources->count_connectors; i++) {
   315         connector = KMSDRM_drmModeGetConnector(vdata->drm_fd, resources->connectors[i]);
   316         if (connector == NULL)
   317             continue;
   318 
   319         if (connector->connection == DRM_MODE_CONNECTED &&
   320             connector->count_modes > 0) {
   321             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
   322                          connector->connector_id, connector->count_modes);
   323             vdata->saved_conn_id = connector->connector_id;
   324             break;
   325         }
   326 
   327         KMSDRM_drmModeFreeConnector(connector);
   328     }
   329 
   330     if (i == resources->count_connectors) {
   331         ret = SDL_SetError("No currently active connector found.");
   332         goto cleanup;
   333     }
   334 
   335     for (i = 0; i < resources->count_encoders; i++) {
   336         encoder = KMSDRM_drmModeGetEncoder(vdata->drm_fd, resources->encoders[i]);
   337 
   338         if (encoder == NULL)
   339             continue;
   340 
   341         if (encoder->encoder_id == connector->encoder_id) {
   342             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
   343             data->encoder_id = encoder->encoder_id;
   344             break;
   345         }
   346 
   347         KMSDRM_drmModeFreeEncoder(encoder);
   348     }
   349 
   350     if (i == resources->count_encoders) {
   351         ret = SDL_SetError("No connected encoder found.");
   352         goto cleanup;
   353     }
   354 
   355     vdata->saved_crtc = KMSDRM_drmModeGetCrtc(vdata->drm_fd, encoder->crtc_id);
   356     if (vdata->saved_crtc == NULL) {
   357         ret = SDL_SetError("No CRTC found.");
   358         goto cleanup;
   359     }
   360     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Saved crtc_id %u, fb_id %u, (%u,%u), %ux%u",
   361                  vdata->saved_crtc->crtc_id, vdata->saved_crtc->buffer_id, vdata->saved_crtc->x,
   362                  vdata->saved_crtc->y, vdata->saved_crtc->width, vdata->saved_crtc->height);
   363     data->crtc_id = encoder->crtc_id;
   364     data->cur_mode = vdata->saved_crtc->mode;
   365 
   366     SDL_zero(current_mode);
   367 
   368     current_mode.w = vdata->saved_crtc->mode.hdisplay;
   369     current_mode.h = vdata->saved_crtc->mode.vdisplay;
   370     current_mode.refresh_rate = vdata->saved_crtc->mode.vrefresh;
   371 
   372     /* FIXME ?
   373     drmModeFB *fb = drmModeGetFB(vdata->drm_fd, vdata->saved_crtc->buffer_id);
   374     current_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
   375     drmModeFreeFB(fb);
   376     */
   377     current_mode.format = SDL_PIXELFORMAT_ARGB8888;
   378 
   379     current_mode.driverdata = NULL;
   380 
   381     SDL_zero(display);
   382     display.desktop_mode = current_mode;
   383     display.current_mode = current_mode;
   384 
   385     display.driverdata = data;
   386     /* SDL_VideoQuit will later SDL_free(display.driverdata) */
   387     SDL_AddVideoDisplay(&display);
   388 
   389     /* Setup page flip handler */
   390     vdata->drm_pollfd.fd = vdata->drm_fd;
   391     vdata->drm_pollfd.events = POLLIN;
   392     vdata->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
   393     vdata->drm_evctx.page_flip_handler = KMSDRM_FlipHandler;
   394 
   395 #ifdef SDL_INPUT_LINUXEV
   396     SDL_EVDEV_Init();
   397 #endif
   398 
   399     KMSDRM_InitMouse(_this);
   400 
   401 cleanup:
   402     if (encoder != NULL)
   403         KMSDRM_drmModeFreeEncoder(encoder);
   404     if (connector != NULL)
   405         KMSDRM_drmModeFreeConnector(connector);
   406     if (resources != NULL)
   407         KMSDRM_drmModeFreeResources(resources);
   408 
   409     if (ret != 0) {
   410         /* Error (complete) cleanup */
   411         SDL_free(data);
   412         if(vdata->saved_crtc != NULL) {
   413             KMSDRM_drmModeFreeCrtc(vdata->saved_crtc);
   414             vdata->saved_crtc = NULL;
   415         }
   416         if (vdata->gbm != NULL) {
   417             KMSDRM_gbm_device_destroy(vdata->gbm);
   418             vdata->gbm = NULL;
   419         }
   420         if (vdata->drm_fd >= 0) {
   421             close(vdata->drm_fd);
   422             vdata->drm_fd = -1;
   423         }
   424     }
   425     return ret;
   426 }
   427 
   428 void
   429 KMSDRM_VideoQuit(_THIS)
   430 {
   431     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   432 
   433     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()");
   434 
   435     if (_this->gl_config.driver_loaded) {
   436         SDL_GL_UnloadLibrary();
   437     }
   438 
   439     if(vdata->saved_crtc != NULL) {
   440         if(vdata->drm_fd > 0 && vdata->saved_conn_id > 0) {
   441             /* Restore saved CRTC settings */
   442             drmModeCrtc *crtc = vdata->saved_crtc;
   443             if(KMSDRM_drmModeSetCrtc(vdata->drm_fd, crtc->crtc_id, crtc->buffer_id,
   444                                      crtc->x, crtc->y, &vdata->saved_conn_id, 1,
   445                                      &crtc->mode) != 0) {
   446                 SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original CRTC mode");
   447             }
   448         }
   449         KMSDRM_drmModeFreeCrtc(vdata->saved_crtc);
   450         vdata->saved_crtc = NULL;
   451     }
   452     if (vdata->gbm != NULL) {
   453         KMSDRM_gbm_device_destroy(vdata->gbm);
   454         vdata->gbm = NULL;
   455     }
   456     if (vdata->drm_fd >= 0) {
   457         close(vdata->drm_fd);
   458         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", vdata->drm_fd);
   459         vdata->drm_fd = -1;
   460     }
   461 #ifdef SDL_INPUT_LINUXEV
   462     SDL_EVDEV_Quit();
   463 #endif
   464 }
   465 
   466 void
   467 KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
   468 {
   469     /* Only one display mode available, the current one */
   470     SDL_AddDisplayMode(display, &display->current_mode);
   471 }
   472 
   473 int
   474 KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   475 {
   476     return 0;
   477 }
   478 
   479 int
   480 KMSDRM_CreateWindow(_THIS, SDL_Window * window)
   481 {
   482     SDL_WindowData *wdata;
   483     SDL_VideoDisplay *display;
   484     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
   485     Uint32 surface_fmt, surface_flags;
   486 
   487     /* Allocate window internal data */
   488     wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
   489     if (wdata == NULL) {
   490         SDL_OutOfMemory();
   491         goto error;
   492     }
   493 
   494     wdata->waiting_for_flip = SDL_FALSE;
   495     display = SDL_GetDisplayForWindow(window);
   496 
   497     /* Windows have one size for now */
   498     window->w = display->desktop_mode.w;
   499     window->h = display->desktop_mode.h;
   500 
   501     /* Maybe you didn't ask for a fullscreen OpenGL window, but that's what you get */
   502     window->flags |= (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
   503 
   504     surface_fmt = GBM_BO_FORMAT_XRGB8888;
   505     surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
   506 
   507     if (!KMSDRM_gbm_device_is_format_supported(vdata->gbm, surface_fmt, surface_flags)) {
   508         SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
   509     }
   510     wdata->gs = KMSDRM_gbm_surface_create(vdata->gbm, window->w, window->h, surface_fmt, surface_flags);
   511 
   512 #if SDL_VIDEO_OPENGL_EGL
   513     if (!_this->egl_data) {
   514         if (SDL_GL_LoadLibrary(NULL) < 0) {
   515             goto error;
   516         }
   517     }
   518     wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) wdata->gs);
   519 
   520     if (wdata->egl_surface == EGL_NO_SURFACE) {
   521         SDL_SetError("Could not create EGL window surface");
   522         goto error;
   523     }
   524 #endif /* SDL_VIDEO_OPENGL_EGL */
   525 
   526     /* Setup driver data for this window */
   527     window->driverdata = wdata;
   528 
   529     /* One window, it always has focus */
   530     SDL_SetMouseFocus(window);
   531     SDL_SetKeyboardFocus(window);
   532 
   533     /* Window has been successfully created */
   534     return 0;
   535 
   536 error:
   537     if (wdata != NULL) {
   538 #if SDL_VIDEO_OPENGL_EGL
   539         if (wdata->egl_surface != EGL_NO_SURFACE)
   540             SDL_EGL_DestroySurface(_this, wdata->egl_surface);
   541 #endif /* SDL_VIDEO_OPENGL_EGL */
   542         if (wdata->gs != NULL)
   543             KMSDRM_gbm_surface_destroy(wdata->gs);
   544         SDL_free(wdata);
   545     }
   546     return -1;
   547 }
   548 
   549 void
   550 KMSDRM_DestroyWindow(_THIS, SDL_Window * window)
   551 {
   552     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   553     if(data) {
   554         /* Wait for any pending page flips and unlock buffer */
   555         KMSDRM_WaitPageFlip(_this, data, -1);
   556         if (data->next_bo != NULL) {
   557             KMSDRM_gbm_surface_release_buffer(data->gs, data->next_bo);
   558             data->next_bo = NULL;
   559         }
   560         if (data->current_bo != NULL) {
   561             KMSDRM_gbm_surface_release_buffer(data->gs, data->current_bo);
   562             data->current_bo = NULL;
   563         }
   564 #if SDL_VIDEO_OPENGL_EGL
   565         SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   566         if (data->egl_surface != EGL_NO_SURFACE) {
   567             SDL_EGL_DestroySurface(_this, data->egl_surface);
   568         }
   569 #endif /* SDL_VIDEO_OPENGL_EGL */
   570         if (data->gs != NULL) {
   571             KMSDRM_gbm_surface_destroy(data->gs);
   572             data->gs = NULL;
   573         }
   574         SDL_free(data);
   575         window->driverdata = NULL;
   576     }
   577 }
   578 
   579 int
   580 KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   581 {
   582     return -1;
   583 }
   584 
   585 void
   586 KMSDRM_SetWindowTitle(_THIS, SDL_Window * window)
   587 {
   588 }
   589 void
   590 KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   591 {
   592 }
   593 void
   594 KMSDRM_SetWindowPosition(_THIS, SDL_Window * window)
   595 {
   596 }
   597 void
   598 KMSDRM_SetWindowSize(_THIS, SDL_Window * window)
   599 {
   600 }
   601 void
   602 KMSDRM_ShowWindow(_THIS, SDL_Window * window)
   603 {
   604 }
   605 void
   606 KMSDRM_HideWindow(_THIS, SDL_Window * window)
   607 {
   608 }
   609 void
   610 KMSDRM_RaiseWindow(_THIS, SDL_Window * window)
   611 {
   612 }
   613 void
   614 KMSDRM_MaximizeWindow(_THIS, SDL_Window * window)
   615 {
   616 }
   617 void
   618 KMSDRM_MinimizeWindow(_THIS, SDL_Window * window)
   619 {
   620 }
   621 void
   622 KMSDRM_RestoreWindow(_THIS, SDL_Window * window)
   623 {
   624 }
   625 void
   626 KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   627 {
   628 
   629 }
   630 
   631 /*****************************************************************************/
   632 /* SDL Window Manager function                                               */
   633 /*****************************************************************************/
   634 SDL_bool
   635 KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
   636 {
   637     if (info->version.major <= SDL_MAJOR_VERSION) {
   638         return SDL_TRUE;
   639     } else {
   640         SDL_SetError("application not compiled with SDL %d.%d\n",
   641                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   642         return SDL_FALSE;
   643     }
   644 
   645     /* Failed to get window manager information */
   646     return SDL_FALSE;
   647 }
   648 
   649 #endif /* SDL_VIDEO_DRIVER_KMSDRM */
   650 
   651 /* vi: set ts=4 sw=4 expandtab: */