sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_kmsdrm_legacy_video.c (27698B)


      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_kmsdrm_legacy_video.h"
     41 #include "SDL_kmsdrm_legacy_events.h"
     42 #include "SDL_kmsdrm_legacy_opengles.h"
     43 #include "SDL_kmsdrm_legacy_mouse.h"
     44 #include "SDL_kmsdrm_legacy_dyn.h"
     45 #include <sys/stat.h>
     46 #include <dirent.h>
     47 #include <errno.h>
     48 #include <poll.h>
     49 
     50 #define KMSDRM_LEGACY_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_LEGACY_DRI_PATH, devindex);
     60 
     61     drm_fd = open(device, O_RDWR | O_CLOEXEC);
     62     if (drm_fd >= 0) {
     63         if (SDL_KMSDRM_LEGACY_LoadSymbols()) {
     64             drmModeRes *resources = KMSDRM_LEGACY_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_LEGACY_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_LEGACY_drmModeFreeResources(resources);
     74             }
     75             SDL_KMSDRM_LEGACY_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_LEGACY_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_LEGACY_DRI_PATH);
     94         return 0;
     95     }
     96 
     97     if (access(KMSDRM_LEGACY_DRI_PATH, F_OK) == -1) {
     98         printf("The path %s cannot be opened\n",
     99                KMSDRM_LEGACY_DRI_PATH);
    100         return 0;
    101     }
    102 
    103     folder = opendir(KMSDRM_LEGACY_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_LEGACY_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_LEGACY_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_LEGACY_UnloadSymbols();
    155 }
    156 
    157 static SDL_VideoDevice *
    158 KMSDRM_LEGACY_CreateDevice(int devindex)
    159 {
    160     SDL_VideoDevice *device;
    161     SDL_VideoData *viddata;
    162 
    163     if (!KMSDRM_LEGACY_Available()) {
    164         return NULL;
    165     }
    166 
    167     if (!devindex || (devindex > 99)) {
    168         devindex = get_driindex();
    169     }
    170 
    171     if (devindex < 0) {
    172         SDL_SetError("devindex (%d) must be between 0 and 99.\n", devindex);
    173         return NULL;
    174     }
    175 
    176     if (!SDL_KMSDRM_LEGACY_LoadSymbols()) {
    177         return NULL;
    178     }
    179 
    180     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    181     if (!device) {
    182         SDL_OutOfMemory();
    183         return NULL;
    184     }
    185 
    186     viddata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
    187     if (!viddata) {
    188         SDL_OutOfMemory();
    189         goto cleanup;
    190     }
    191     viddata->devindex = devindex;
    192     viddata->drm_fd = -1;
    193 
    194     device->driverdata = viddata;
    195 
    196     /* Setup all functions which we can handle */
    197     device->VideoInit = KMSDRM_LEGACY_VideoInit;
    198     device->VideoQuit = KMSDRM_LEGACY_VideoQuit;
    199     device->GetDisplayModes = KMSDRM_LEGACY_GetDisplayModes;
    200     device->SetDisplayMode = KMSDRM_LEGACY_SetDisplayMode;
    201     device->CreateSDLWindow = KMSDRM_LEGACY_CreateWindow;
    202     device->CreateSDLWindowFrom = KMSDRM_LEGACY_CreateWindowFrom;
    203     device->SetWindowTitle = KMSDRM_LEGACY_SetWindowTitle;
    204     device->SetWindowIcon = KMSDRM_LEGACY_SetWindowIcon;
    205     device->SetWindowPosition = KMSDRM_LEGACY_SetWindowPosition;
    206     device->SetWindowSize = KMSDRM_LEGACY_SetWindowSize;
    207     device->ShowWindow = KMSDRM_LEGACY_ShowWindow;
    208     device->HideWindow = KMSDRM_LEGACY_HideWindow;
    209     device->RaiseWindow = KMSDRM_LEGACY_RaiseWindow;
    210     device->MaximizeWindow = KMSDRM_LEGACY_MaximizeWindow;
    211     device->MinimizeWindow = KMSDRM_LEGACY_MinimizeWindow;
    212     device->RestoreWindow = KMSDRM_LEGACY_RestoreWindow;
    213     device->SetWindowGrab = KMSDRM_LEGACY_SetWindowGrab;
    214     device->DestroyWindow = KMSDRM_LEGACY_DestroyWindow;
    215     device->GetWindowWMInfo = KMSDRM_LEGACY_GetWindowWMInfo;
    216 #if SDL_VIDEO_OPENGL_EGL
    217     device->GL_LoadLibrary = KMSDRM_LEGACY_GLES_LoadLibrary;
    218     device->GL_GetProcAddress = KMSDRM_LEGACY_GLES_GetProcAddress;
    219     device->GL_UnloadLibrary = KMSDRM_LEGACY_GLES_UnloadLibrary;
    220     device->GL_CreateContext = KMSDRM_LEGACY_GLES_CreateContext;
    221     device->GL_MakeCurrent = KMSDRM_LEGACY_GLES_MakeCurrent;
    222     device->GL_SetSwapInterval = KMSDRM_LEGACY_GLES_SetSwapInterval;
    223     device->GL_GetSwapInterval = KMSDRM_LEGACY_GLES_GetSwapInterval;
    224     device->GL_SwapWindow = KMSDRM_LEGACY_GLES_SwapWindow;
    225     device->GL_DeleteContext = KMSDRM_LEGACY_GLES_DeleteContext;
    226 #endif
    227     device->PumpEvents = KMSDRM_LEGACY_PumpEvents;
    228     device->free = KMSDRM_LEGACY_DeleteDevice;
    229 
    230     return device;
    231 
    232 cleanup:
    233     if (device)
    234         SDL_free(device);
    235     if (viddata)
    236         SDL_free(viddata);
    237     return NULL;
    238 }
    239 
    240 VideoBootStrap KMSDRM_LEGACY_bootstrap = {
    241     "KMSDRM_LEGACY",
    242     "KMS/DRM Video Driver",
    243     KMSDRM_LEGACY_CreateDevice
    244 };
    245 
    246 
    247 static void
    248 KMSDRM_LEGACY_FBDestroyCallback(struct gbm_bo *bo, void *data)
    249 {
    250     KMSDRM_LEGACY_FBInfo *fb_info = (KMSDRM_LEGACY_FBInfo *)data;
    251 
    252     if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) {
    253         KMSDRM_LEGACY_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id);
    254         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id);
    255     }
    256 
    257     SDL_free(fb_info);
    258 }
    259 
    260 KMSDRM_LEGACY_FBInfo *
    261 KMSDRM_LEGACY_FBFromBO(_THIS, struct gbm_bo *bo)
    262 {
    263     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
    264     unsigned w,h;
    265     int ret;
    266     Uint32 stride, handle;
    267 
    268     /* Check for an existing framebuffer */
    269     KMSDRM_LEGACY_FBInfo *fb_info = (KMSDRM_LEGACY_FBInfo *)KMSDRM_LEGACY_gbm_bo_get_user_data(bo);
    270 
    271     if (fb_info) {
    272         return fb_info;
    273     }
    274 
    275     /* Create a structure that contains enough info to remove the framebuffer
    276        when the backing buffer is destroyed */
    277     fb_info = (KMSDRM_LEGACY_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_LEGACY_FBInfo));
    278 
    279     if (!fb_info) {
    280         SDL_OutOfMemory();
    281         return NULL;
    282     }
    283 
    284     fb_info->drm_fd = viddata->drm_fd;
    285 
    286     /* Create framebuffer object for the buffer */
    287     w = KMSDRM_LEGACY_gbm_bo_get_width(bo);
    288     h = KMSDRM_LEGACY_gbm_bo_get_height(bo);
    289     stride = KMSDRM_LEGACY_gbm_bo_get_stride(bo);
    290     handle = KMSDRM_LEGACY_gbm_bo_get_handle(bo).u32;
    291     ret = KMSDRM_LEGACY_drmModeAddFB(viddata->drm_fd, w, h, 24, 32, stride, handle,
    292                                   &fb_info->fb_id);
    293     if (ret) {
    294       SDL_free(fb_info);
    295       return NULL;
    296     }
    297 
    298     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "New DRM FB (%u): %ux%u, stride %u from BO %p",
    299                  fb_info->fb_id, w, h, stride, (void *)bo);
    300 
    301     /* Associate our DRM framebuffer with this buffer object */
    302     KMSDRM_LEGACY_gbm_bo_set_user_data(bo, fb_info, KMSDRM_LEGACY_FBDestroyCallback);
    303 
    304     return fb_info;
    305 }
    306 
    307 static void
    308 KMSDRM_LEGACY_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
    309 {
    310     *((SDL_bool *) data) = SDL_FALSE;
    311 }
    312 
    313 SDL_bool
    314 KMSDRM_LEGACY_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) {
    315     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
    316     drmEventContext ev = {0};
    317     struct pollfd pfd = {0};
    318 
    319     ev.version = DRM_EVENT_CONTEXT_VERSION;
    320     ev.page_flip_handler = KMSDRM_LEGACY_FlipHandler;
    321 
    322     pfd.fd = viddata->drm_fd;
    323     pfd.events = POLLIN;
    324 
    325     while (windata->waiting_for_flip) {
    326         pfd.revents = 0;
    327 
    328         if (poll(&pfd, 1, timeout) < 0) {
    329             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error");
    330             return SDL_FALSE;
    331         }
    332 
    333         if (pfd.revents & (POLLHUP | POLLERR)) {
    334             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error");
    335             return SDL_FALSE;
    336         }
    337 
    338         if (pfd.revents & POLLIN) {
    339             /* Page flip? If so, drmHandleEvent will unset windata->waiting_for_flip */
    340             KMSDRM_LEGACY_drmHandleEvent(viddata->drm_fd, &ev);
    341         } else {
    342             /* Timed out and page flip didn't happen */
    343             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip");
    344             return SDL_FALSE;
    345         }
    346     }
    347 
    348     return SDL_TRUE;
    349 }
    350 
    351 /*****************************************************************************/
    352 /* SDL Video and Display initialization/handling functions                   */
    353 /* _this is a SDL_VideoDevice *                                              */
    354 /*****************************************************************************/
    355 static void
    356 KMSDRM_LEGACY_DestroySurfaces(_THIS, SDL_Window * window)
    357 {
    358     SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
    359 
    360     KMSDRM_LEGACY_WaitPageFlip(_this, windata, -1);
    361 
    362     if (windata->curr_bo) {
    363         KMSDRM_LEGACY_gbm_surface_release_buffer(windata->gs, windata->curr_bo);
    364         windata->curr_bo = NULL;
    365     }
    366 
    367     if (windata->next_bo) {
    368         KMSDRM_LEGACY_gbm_surface_release_buffer(windata->gs, windata->next_bo);
    369         windata->next_bo = NULL;
    370     }
    371 
    372 #if SDL_VIDEO_OPENGL_EGL
    373     SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    374 
    375     if (windata->egl_surface != EGL_NO_SURFACE) {
    376         SDL_EGL_DestroySurface(_this, windata->egl_surface);
    377         windata->egl_surface = EGL_NO_SURFACE;
    378     }
    379 #endif
    380 
    381     if (windata->gs) {
    382         KMSDRM_LEGACY_gbm_surface_destroy(windata->gs);
    383         windata->gs = NULL;
    384     }
    385 }
    386 
    387 int
    388 KMSDRM_LEGACY_CreateSurfaces(_THIS, SDL_Window * window)
    389 {
    390     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
    391     SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
    392     SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
    393     Uint32 width = dispdata->mode.hdisplay;
    394     Uint32 height = dispdata->mode.vdisplay;
    395     Uint32 surface_fmt = GBM_FORMAT_XRGB8888;
    396     Uint32 surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
    397 #if SDL_VIDEO_OPENGL_EGL
    398     EGLContext egl_context;
    399 #endif
    400 
    401     if (!KMSDRM_LEGACY_gbm_device_is_format_supported(viddata->gbm, surface_fmt, surface_flags)) {
    402         SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway.");
    403     }
    404 
    405 #if SDL_VIDEO_OPENGL_EGL
    406     SDL_EGL_SetRequiredVisualId(_this, surface_fmt);
    407     egl_context = (EGLContext)SDL_GL_GetCurrentContext();
    408 #endif
    409 
    410     KMSDRM_LEGACY_DestroySurfaces(_this, window);
    411 
    412     windata->gs = KMSDRM_LEGACY_gbm_surface_create(viddata->gbm, width, height, surface_fmt, surface_flags);
    413 
    414     if (!windata->gs) {
    415         return SDL_SetError("Could not create GBM surface");
    416     }
    417 
    418 #if SDL_VIDEO_OPENGL_EGL
    419     windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs);
    420 
    421     if (windata->egl_surface == EGL_NO_SURFACE) {
    422         return SDL_SetError("Could not create EGL window surface");
    423     }
    424 
    425     SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context);
    426 
    427     windata->egl_surface_dirty = 0;
    428 #endif
    429 
    430     return 0;
    431 }
    432 
    433 int
    434 KMSDRM_LEGACY_VideoInit(_THIS)
    435 {
    436     int i, j, ret = 0;
    437     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
    438     SDL_DisplayData *dispdata = NULL;
    439     drmModeRes *resources = NULL;
    440     drmModeEncoder *encoder = NULL;
    441     char devname[32];
    442     SDL_VideoDisplay display = {0};
    443 
    444     dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
    445 
    446     if (!dispdata) {
    447         return SDL_OutOfMemory();
    448     }
    449 
    450     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_LEGACY_VideoInit()");
    451 
    452     /* Open /dev/dri/cardNN */
    453     SDL_snprintf(devname, sizeof(devname), "/dev/dri/card%d", viddata->devindex);
    454 
    455     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", devname);
    456     viddata->drm_fd = open(devname, O_RDWR | O_CLOEXEC);
    457 
    458     if (viddata->drm_fd < 0) {
    459         ret = SDL_SetError("Could not open %s", devname);
    460         goto cleanup;
    461     }
    462 
    463     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd);
    464 
    465     viddata->gbm = KMSDRM_LEGACY_gbm_create_device(viddata->drm_fd);
    466     if (!viddata->gbm) {
    467         ret = SDL_SetError("Couldn't create gbm device.");
    468         goto cleanup;
    469     }
    470 
    471     /* Get all of the available connectors / devices / crtcs */
    472     resources = KMSDRM_LEGACY_drmModeGetResources(viddata->drm_fd);
    473     if (!resources) {
    474         ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd);
    475         goto cleanup;
    476     }
    477 
    478     for (i = 0; i < resources->count_connectors; i++) {
    479         drmModeConnector *conn = KMSDRM_LEGACY_drmModeGetConnector(viddata->drm_fd, resources->connectors[i]);
    480 
    481         if (!conn) {
    482             continue;
    483         }
    484 
    485         if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) {
    486             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.",
    487                          conn->connector_id, conn->count_modes);
    488             dispdata->conn = conn;
    489             break;
    490         }
    491 
    492         KMSDRM_LEGACY_drmModeFreeConnector(conn);
    493     }
    494 
    495     if (!dispdata->conn) {
    496         ret = SDL_SetError("No currently active connector found.");
    497         goto cleanup;
    498     }
    499 
    500     /* Try to find the connector's current encoder */
    501     for (i = 0; i < resources->count_encoders; i++) {
    502         encoder = KMSDRM_LEGACY_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
    503 
    504         if (!encoder) {
    505           continue;
    506         }
    507 
    508         if (encoder->encoder_id == dispdata->conn->encoder_id) {
    509             SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
    510             break;
    511         }
    512 
    513         KMSDRM_LEGACY_drmModeFreeEncoder(encoder);
    514         encoder = NULL;
    515     }
    516 
    517     if (!encoder) {
    518         /* No encoder was connected, find the first supported one */
    519         for (i = 0; i < resources->count_encoders; i++) {
    520             encoder = KMSDRM_LEGACY_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]);
    521 
    522             if (!encoder) {
    523               continue;
    524             }
    525 
    526             for (j = 0; j < dispdata->conn->count_encoders; j++) {
    527                 if (dispdata->conn->encoders[j] == encoder->encoder_id) {
    528                     break;
    529                 }
    530             }
    531 
    532             if (j != dispdata->conn->count_encoders) {
    533               break;
    534             }
    535 
    536             KMSDRM_LEGACY_drmModeFreeEncoder(encoder);
    537             encoder = NULL;
    538         }
    539     }
    540 
    541     if (!encoder) {
    542         ret = SDL_SetError("No connected encoder found.");
    543         goto cleanup;
    544     }
    545 
    546     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id);
    547 
    548     /* Try to find a CRTC connected to this encoder */
    549     dispdata->saved_crtc = KMSDRM_LEGACY_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
    550 
    551     if (!dispdata->saved_crtc) {
    552         /* No CRTC was connected, find the first CRTC that can be connected */
    553         for (i = 0; i < resources->count_crtcs; i++) {
    554             if (encoder->possible_crtcs & (1 << i)) {
    555                 encoder->crtc_id = resources->crtcs[i];
    556                 dispdata->saved_crtc = KMSDRM_LEGACY_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id);
    557                 break;
    558             }
    559         }
    560     }
    561 
    562     if (!dispdata->saved_crtc) {
    563         ret = SDL_SetError("No CRTC found.");
    564         goto cleanup;
    565     }
    566 
    567     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Saved crtc_id %u, fb_id %u, (%u,%u), %ux%u",
    568                  dispdata->saved_crtc->crtc_id, dispdata->saved_crtc->buffer_id, dispdata->saved_crtc->x,
    569                  dispdata->saved_crtc->y, dispdata->saved_crtc->width, dispdata->saved_crtc->height);
    570 
    571     dispdata->crtc_id = encoder->crtc_id;
    572 
    573     /* Figure out the default mode to be set. If the current CRTC's mode isn't
    574        valid, select the first mode supported by the connector
    575 
    576        FIXME find first mode that specifies DRM_MODE_TYPE_PREFERRED */
    577     dispdata->mode = dispdata->saved_crtc->mode;
    578 
    579     if (dispdata->saved_crtc->mode_valid == 0) {
    580         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO,
    581             "Current mode is invalid, selecting connector's mode #0.");
    582         dispdata->mode = dispdata->conn->modes[0];
    583     }
    584 
    585     /* Setup the single display that's available */
    586 
    587     display.desktop_mode.w = dispdata->mode.hdisplay;
    588     display.desktop_mode.h = dispdata->mode.vdisplay;
    589     display.desktop_mode.refresh_rate = dispdata->mode.vrefresh;
    590 #if 1
    591     display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888;
    592 #else
    593     /* FIXME */
    594     drmModeFB *fb = drmModeGetFB(viddata->drm_fd, dispdata->saved_crtc->buffer_id);
    595     display.desktop_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth);
    596     drmModeFreeFB(fb);
    597 #endif
    598     display.current_mode = display.desktop_mode;
    599     display.driverdata = dispdata;
    600     SDL_AddVideoDisplay(&display, SDL_FALSE);
    601 
    602 #ifdef SDL_INPUT_LINUXEV
    603     SDL_EVDEV_Init();
    604 #endif
    605 
    606     KMSDRM_LEGACY_InitMouse(_this);
    607 
    608     return ret;
    609 
    610 cleanup:
    611     if (encoder)
    612         KMSDRM_LEGACY_drmModeFreeEncoder(encoder);
    613     if (resources)
    614         KMSDRM_LEGACY_drmModeFreeResources(resources);
    615 
    616     if (ret != 0) {
    617         /* Error (complete) cleanup */
    618         if (dispdata->conn) {
    619             KMSDRM_LEGACY_drmModeFreeConnector(dispdata->conn);
    620             dispdata->conn = NULL;
    621         }
    622         if (dispdata->saved_crtc) {
    623             KMSDRM_LEGACY_drmModeFreeCrtc(dispdata->saved_crtc);
    624             dispdata->saved_crtc = NULL;
    625         }
    626         if (viddata->gbm) {
    627             KMSDRM_LEGACY_gbm_device_destroy(viddata->gbm);
    628             viddata->gbm = NULL;
    629         }
    630         if (viddata->drm_fd >= 0) {
    631             close(viddata->drm_fd);
    632             viddata->drm_fd = -1;
    633         }
    634         SDL_free(dispdata);
    635     }
    636     return ret;
    637 }
    638 
    639 void
    640 KMSDRM_LEGACY_VideoQuit(_THIS)
    641 {
    642     SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
    643     SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
    644 
    645     SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_LEGACY_VideoQuit()");
    646 
    647     if (_this->gl_config.driver_loaded) {
    648         SDL_GL_UnloadLibrary();
    649     }
    650 
    651     /* Clear out the window list */
    652     SDL_free(viddata->windows);
    653     viddata->windows = NULL;
    654     viddata->max_windows = 0;
    655     viddata->num_windows = 0;
    656 
    657     /* Restore saved CRTC settings */
    658     if (viddata->drm_fd >= 0 && dispdata && dispdata->conn && dispdata->saved_crtc) {
    659         drmModeConnector *conn = dispdata->conn;
    660         drmModeCrtc *crtc = dispdata->saved_crtc;
    661 
    662         int ret = KMSDRM_LEGACY_drmModeSetCrtc(viddata->drm_fd, crtc->crtc_id, crtc->buffer_id,
    663                                         crtc->x, crtc->y, &conn->connector_id, 1, &crtc->mode);
    664 
    665         if (ret != 0) {
    666             SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original CRTC mode");
    667         }
    668     }
    669     if (dispdata && dispdata->conn) {
    670         KMSDRM_LEGACY_drmModeFreeConnector(dispdata->conn);
    671         dispdata->conn = NULL;
    672     }
    673     if (dispdata && dispdata->saved_crtc) {
    674         KMSDRM_LEGACY_drmModeFreeCrtc(dispdata->saved_crtc);
    675         dispdata->saved_crtc = NULL;
    676     }
    677     if (viddata->gbm) {
    678         KMSDRM_LEGACY_gbm_device_destroy(viddata->gbm);
    679         viddata->gbm = NULL;
    680     }
    681     if (viddata->drm_fd >= 0) {
    682         close(viddata->drm_fd);
    683         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", viddata->drm_fd);
    684         viddata->drm_fd = -1;
    685     }
    686 #ifdef SDL_INPUT_LINUXEV
    687     SDL_EVDEV_Quit();
    688 #endif
    689 }
    690 
    691 void
    692 KMSDRM_LEGACY_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
    693 {
    694     SDL_DisplayData *dispdata = display->driverdata;
    695     drmModeConnector *conn = dispdata->conn;
    696     SDL_DisplayMode mode;
    697     int i;
    698 
    699     for (i = 0; i < conn->count_modes; i++) {
    700         SDL_DisplayModeData *modedata = SDL_calloc(1, sizeof(SDL_DisplayModeData));
    701 
    702         if (modedata) {
    703           modedata->mode_index = i;
    704         }
    705 
    706         mode.w = conn->modes[i].hdisplay;
    707         mode.h = conn->modes[i].vdisplay;
    708         mode.refresh_rate = conn->modes[i].vrefresh;
    709         mode.format = SDL_PIXELFORMAT_ARGB8888;
    710         mode.driverdata = modedata;
    711 
    712         if (!SDL_AddDisplayMode(display, &mode)) {
    713             SDL_free(modedata);
    714         }
    715     }
    716 }
    717 
    718 int
    719 KMSDRM_LEGACY_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
    720 {
    721     SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
    722     SDL_DisplayData *dispdata = (SDL_DisplayData *)display->driverdata;
    723     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
    724     drmModeConnector *conn = dispdata->conn;
    725     int i;
    726 
    727     if (!modedata) {
    728         return SDL_SetError("Mode doesn't have an associated index");
    729     }
    730 
    731     dispdata->mode = conn->modes[modedata->mode_index];
    732 
    733     for (i = 0; i < viddata->num_windows; i++) {
    734         SDL_Window *window = viddata->windows[i];
    735         SDL_WindowData *windata = (SDL_WindowData *)window->driverdata;
    736 
    737 #if SDL_VIDEO_OPENGL_EGL
    738         /* Can't recreate EGL surfaces right now, need to wait until SwapWindow
    739            so the correct thread-local surface and context state are available */
    740         windata->egl_surface_dirty = 1;
    741 #else
    742         if (KMSDRM_LEGACY_CreateSurfaces(_this, window)) {
    743             return -1;
    744         }
    745 #endif
    746 
    747         /* Tell app about the resize */
    748         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode->w, mode->h);
    749     }
    750 
    751     return 0;
    752 }
    753 
    754 int
    755 KMSDRM_LEGACY_CreateWindow(_THIS, SDL_Window * window)
    756 {
    757     SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
    758     SDL_WindowData *windata;
    759     SDL_VideoDisplay *display;
    760 
    761 #if SDL_VIDEO_OPENGL_EGL
    762     if (!_this->egl_data) {
    763         if (SDL_GL_LoadLibrary(NULL) < 0) {
    764             goto error;
    765         }
    766     }
    767 #endif
    768 
    769     /* Allocate window internal data */
    770     windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
    771 
    772     if (!windata) {
    773         SDL_OutOfMemory();
    774         goto error;
    775     }
    776 
    777     /* Windows have one size for now */
    778     display = SDL_GetDisplayForWindow(window);
    779     window->w = display->desktop_mode.w;
    780     window->h = display->desktop_mode.h;
    781 
    782     /* Maybe you didn't ask for a fullscreen OpenGL window, but that's what you get */
    783     window->flags |= (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
    784 
    785     /* In case we want low-latency, double-buffer video, we take note here */
    786     windata->double_buffer = SDL_FALSE;
    787 
    788     if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) {
    789         windata->double_buffer = SDL_TRUE;
    790     }
    791 
    792     /* Setup driver data for this window */
    793     windata->viddata = viddata;
    794     window->driverdata = windata;
    795 
    796     if (KMSDRM_LEGACY_CreateSurfaces(_this, window)) {
    797       goto error;
    798     }
    799 
    800     /* Add window to the internal list of tracked windows. Note, while it may
    801        seem odd to support multiple fullscreen windows, some apps create an
    802        extra window as a dummy surface when working with multiple contexts */
    803     if (viddata->num_windows >= viddata->max_windows) {
    804         int new_max_windows = viddata->max_windows + 1;
    805         viddata->windows = (SDL_Window **)SDL_realloc(viddata->windows,
    806               new_max_windows * sizeof(SDL_Window *));
    807         viddata->max_windows = new_max_windows;
    808 
    809         if (!viddata->windows) {
    810             SDL_OutOfMemory();
    811             goto error;
    812         }
    813     }
    814 
    815     viddata->windows[viddata->num_windows++] = window;
    816 
    817     /* Focus on the newly created window */
    818     SDL_SetMouseFocus(window);
    819     SDL_SetKeyboardFocus(window);
    820 
    821     return 0;
    822 
    823 error:
    824     KMSDRM_LEGACY_DestroyWindow(_this, window);
    825 
    826     return -1;
    827 }
    828 
    829 void
    830 KMSDRM_LEGACY_DestroyWindow(_THIS, SDL_Window * window)
    831 {
    832     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
    833     SDL_VideoData *viddata;
    834     int i, j;
    835 
    836     if (!windata) {
    837         return;
    838     }
    839 
    840     /* Remove from the internal window list */
    841     viddata = windata->viddata;
    842 
    843     for (i = 0; i < viddata->num_windows; i++) {
    844         if (viddata->windows[i] == window) {
    845             viddata->num_windows--;
    846 
    847             for (j = i; j < viddata->num_windows; j++) {
    848                 viddata->windows[j] = viddata->windows[j + 1];
    849             }
    850 
    851             break;
    852         }
    853     }
    854 
    855     KMSDRM_LEGACY_DestroySurfaces(_this, window);
    856 
    857     window->driverdata = NULL;
    858 
    859     SDL_free(windata);
    860 }
    861 
    862 int
    863 KMSDRM_LEGACY_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
    864 {
    865     return -1;
    866 }
    867 
    868 void
    869 KMSDRM_LEGACY_SetWindowTitle(_THIS, SDL_Window * window)
    870 {
    871 }
    872 void
    873 KMSDRM_LEGACY_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
    874 {
    875 }
    876 void
    877 KMSDRM_LEGACY_SetWindowPosition(_THIS, SDL_Window * window)
    878 {
    879 }
    880 void
    881 KMSDRM_LEGACY_SetWindowSize(_THIS, SDL_Window * window)
    882 {
    883 }
    884 void
    885 KMSDRM_LEGACY_ShowWindow(_THIS, SDL_Window * window)
    886 {
    887 }
    888 void
    889 KMSDRM_LEGACY_HideWindow(_THIS, SDL_Window * window)
    890 {
    891 }
    892 void
    893 KMSDRM_LEGACY_RaiseWindow(_THIS, SDL_Window * window)
    894 {
    895 }
    896 void
    897 KMSDRM_LEGACY_MaximizeWindow(_THIS, SDL_Window * window)
    898 {
    899 }
    900 void
    901 KMSDRM_LEGACY_MinimizeWindow(_THIS, SDL_Window * window)
    902 {
    903 }
    904 void
    905 KMSDRM_LEGACY_RestoreWindow(_THIS, SDL_Window * window)
    906 {
    907 }
    908 void
    909 KMSDRM_LEGACY_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
    910 {
    911 
    912 }
    913 
    914 /*****************************************************************************/
    915 /* SDL Window Manager function                                               */
    916 /*****************************************************************************/
    917 SDL_bool
    918 KMSDRM_LEGACY_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
    919 {
    920     if (info->version.major <= SDL_MAJOR_VERSION) {
    921         return SDL_TRUE;
    922     } else {
    923         SDL_SetError("application not compiled with SDL %d.%d\n",
    924                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
    925         return SDL_FALSE;
    926     }
    927 
    928     /* Failed to get window manager information */
    929     return SDL_FALSE;
    930 }
    931 
    932 #endif /* SDL_VIDEO_DRIVER_KMSDRM */
    933 
    934 /* vi: set ts=4 sw=4 expandtab: */