src/video/kmsdrm/SDL_kmsdrmvideo.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 02 Aug 2017 10:22:48 -0700
changeset 11175 cbc6a8a5b701
child 11176 9397a2d41d6b
permissions -rw-r--r--
Fixed bug 3690 - SDL2 KMS/DRM render context support

Manuel

The attached patch adds support for KMS/DRM context graphics.

It builds with no problem on X86_64 GNU/Linux systems, provided the needed libraries are present, and on ARM GNU/Linux systems that have KMS/DRM support and a GLES2 implementation.
Tested on Raspberry Pi: KMS/DRM is what the Raspberry Pi will use as default in the near future, once the propietary DispmanX API by Broadcom is overtaken by open graphics stack, it's possible to boot current Raspbian system in KMS mode by adding "dtoverlay=vc4-kms-v3d" to config.txt on Raspbian's boot partition.
X86 systems use KMS right away in every current GNU/Linux system.

Simple build instructions:

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