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: */