src/video/kmsdrm/SDL_kmsdrmvideo.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 31 Oct 2018 15:16:51 -0700
changeset 12376 cfc65d4d49ae
parent 12310 18f3294b230e
child 12440 2b450a35f471
permissions -rw-r--r--
Fixed bug 4349 - SDL_CreateWindow fails with KMS/DRM after upgrading Mesa to 18.2.3

Rainer Sabelka

After I did an upgrade of my arch Linux installation (resulting in an update of Mesa to version 18.2.3), all my SDL2 applications which use the KMS/DRM driver stopped working.
Reason: Creating a Window with SDL_CreateWindow failed because the call to EGL
eglCreateWindowSurface() returns an error "EGL_BAD_MATCH".
After investigating with the debugger I figured, that the configuration, which has been selected from the output of eglChooseConfig(), has an "EGL_NATIVE_VISUAL_ID" which does not match the "format" of the underlying gbm surface.

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