SDL_kmsdrmvideo.c (63394B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 Atomic KMSDRM backend by Manuel Alfayate Corchete <redwindwanderer@gmail.com> 5 6 This software is provided 'as-is', without any express or implied 7 warranty. In no event will the authors be held liable for any damages 8 arising from the use of this software. 9 10 Permission is granted to anyone to use this software for any purpose, 11 including commercial applications, and to alter it and redistribute it 12 freely, subject to the following restrictions: 13 14 1. The origin of this software must not be misrepresented; you must not 15 claim that you wrote the original software. If you use this software 16 in a product, an acknowledgment in the product documentation would be 17 appreciated but is not required. 18 2. Altered source versions must be plainly marked as such, and must not be 19 misrepresented as being the original software. 20 3. This notice may not be removed or altered from any source distribution. 21 */ 22 23 #include "../../SDL_internal.h" 24 25 #if SDL_VIDEO_DRIVER_KMSDRM 26 27 /* SDL internals */ 28 #include "../SDL_sysvideo.h" 29 #include "SDL_syswm.h" 30 #include "../../events/SDL_events_c.h" 31 #include "../../events/SDL_mouse_c.h" 32 #include "../../events/SDL_keyboard_c.h" 33 34 #ifdef SDL_INPUT_LINUXEV 35 #include "../../core/linux/SDL_evdev.h" 36 #endif 37 38 /* KMS/DRM declarations */ 39 #include "SDL_kmsdrmvideo.h" 40 #include "SDL_kmsdrmevents.h" 41 #include "SDL_kmsdrmopengles.h" 42 #include "SDL_kmsdrmmouse.h" 43 #include "SDL_kmsdrmdyn.h" 44 #include "SDL_kmsdrmvulkan.h" 45 #include <sys/stat.h> 46 #include <dirent.h> 47 #include <errno.h> 48 #include <poll.h> 49 50 /* for older KMSDRM headers... */ 51 #ifndef DRM_FORMAT_MOD_VENDOR_NONE 52 #define DRM_FORMAT_MOD_VENDOR_NONE 0 53 #endif 54 #ifndef DRM_FORMAT_MOD_LINEAR 55 #define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0) 56 #endif 57 58 #define KMSDRM_DRI_PATH "/dev/dri/" 59 60 static int set_client_caps (int fd) 61 { 62 if (KMSDRM_drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1)) { 63 return SDL_SetError("no atomic modesetting support."); 64 } 65 if (KMSDRM_drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { 66 return SDL_SetError("no universal planes support."); 67 } 68 return 0; 69 } 70 71 static int 72 check_modesetting(int devindex) 73 { 74 SDL_bool available = SDL_FALSE; 75 char device[512]; 76 unsigned int i; 77 int drm_fd; 78 79 SDL_snprintf(device, sizeof (device), "%scard%d", KMSDRM_DRI_PATH, devindex); 80 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "check_modesetting: probing \"%s\"", device); 81 82 drm_fd = open(device, O_RDWR | O_CLOEXEC); 83 if (drm_fd >= 0) { 84 if (SDL_KMSDRM_LoadSymbols()) { 85 drmModeRes *resources = (set_client_caps(drm_fd) < 0) ? NULL : KMSDRM_drmModeGetResources(drm_fd); 86 if (resources) { 87 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "%scard%d connector, encoder and CRTC counts are: %d %d %d", 88 KMSDRM_DRI_PATH, devindex, 89 resources->count_connectors, resources->count_encoders, resources->count_crtcs); 90 91 if (resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0) { 92 for (i = 0; i < resources->count_connectors; i++) { 93 drmModeConnector *conn = KMSDRM_drmModeGetConnector(drm_fd, resources->connectors[i]); 94 95 if (!conn) { 96 continue; 97 } 98 99 if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) { 100 available = SDL_TRUE; 101 } 102 103 KMSDRM_drmModeFreeConnector(conn); 104 if (available) { 105 break; 106 } 107 } 108 } 109 KMSDRM_drmModeFreeResources(resources); 110 } 111 SDL_KMSDRM_UnloadSymbols(); 112 } 113 close(drm_fd); 114 } 115 116 return available; 117 } 118 119 static unsigned int get_dricount(void) 120 { 121 unsigned int devcount = 0; 122 struct dirent *res; 123 struct stat sb; 124 DIR *folder; 125 126 if (!(stat(KMSDRM_DRI_PATH, &sb) == 0 && S_ISDIR(sb.st_mode))) { 127 SDL_SetError("The path %s cannot be opened or is not available", 128 KMSDRM_DRI_PATH); 129 return 0; 130 } 131 132 if (access(KMSDRM_DRI_PATH, F_OK) == -1) { 133 SDL_SetError("The path %s cannot be opened", 134 KMSDRM_DRI_PATH); 135 return 0; 136 } 137 138 folder = opendir(KMSDRM_DRI_PATH); 139 if (folder) { 140 while ((res = readdir(folder))) { 141 size_t len = SDL_strlen(res->d_name); 142 if (len > 4 && SDL_strncmp(res->d_name, "card", 4) == 0) { 143 devcount++; 144 } 145 } 146 closedir(folder); 147 } 148 149 return devcount; 150 } 151 152 static int 153 get_driindex(void) 154 { 155 const unsigned int devcount = get_dricount(); 156 unsigned int i; 157 158 for (i = 0; i < devcount; i++) { 159 if (check_modesetting(i)) { 160 return i; 161 } 162 } 163 164 return -ENOENT; 165 } 166 167 #if 0 168 169 /**********************/ 170 /* DUMB BUFFER Block. */ 171 /**********************/ 172 173 /* Create a dumb buffer, mmap the dumb buffer and fill it with pixels, */ 174 /* then create a KMS framebuffer wrapping the dumb buffer. */ 175 static dumb_buffer *KMSDRM_CreateDumbBuffer(_THIS) 176 { 177 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 178 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 179 180 struct drm_mode_create_dumb create; 181 struct drm_mode_map_dumb map; 182 struct drm_mode_destroy_dumb destroy; 183 184 dumb_buffer *ret = SDL_calloc(1, sizeof(*ret)); 185 if (!ret) { 186 SDL_OutOfMemory(); 187 return NULL; 188 } 189 190 /* 191 * The create ioctl uses the combination of depth and bpp to infer 192 * a format; 24/32 refers to DRM_FORMAT_XRGB8888 as defined in 193 * the drm_fourcc.h header. These arguments are the same as given 194 * to drmModeAddFB, which has since been superseded by 195 * drmModeAddFB2 as the latter takes an explicit format token. 196 * 197 * We only specify these arguments; the driver calculates the 198 * pitch (also known as stride or row length) and total buffer size 199 * for us, also returning us the GEM handle. 200 */ 201 create = (struct drm_mode_create_dumb) { 202 .width = dispdata->mode.hdisplay, 203 .height = dispdata->mode.vdisplay, 204 .bpp = 32, 205 }; 206 207 if (KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create)) { 208 SDL_SetError("failed to create dumb buffer\n"); 209 goto err; 210 } 211 212 ret->gem_handles[0] = create.handle; 213 ret->format = DRM_FORMAT_XRGB8888; 214 ret->modifier = DRM_FORMAT_MOD_LINEAR; 215 ret->width = create.width; 216 ret->height = create.height; 217 ret->pitches[0] = create.pitch; 218 219 /* 220 * In order to map the buffer, we call an ioctl specific to the buffer 221 * type, which returns us a fake offset to use with the mmap syscall. 222 * mmap itself then works as you expect. 223 * 224 * Note this means it is not possible to map arbitrary offsets of 225 * buffers without specifically requesting it from the kernel. 226 */ 227 map = (struct drm_mode_map_dumb) { 228 .handle = ret->gem_handles[0], 229 }; 230 231 if (KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map)) { 232 SDL_SetError("failed to get mmap offset for the dumb buffer."); 233 goto err_dumb; 234 } 235 236 ret->dumb.mem = mmap(NULL, create.size, PROT_WRITE, MAP_SHARED, 237 viddata->drm_fd, map.offset); 238 239 if (ret->dumb.mem == MAP_FAILED) { 240 SDL_SetError("failed to get mmap offset for the dumb buffer."); 241 goto err_dumb; 242 } 243 ret->dumb.size = create.size; 244 245 return ret; 246 247 err_dumb: 248 destroy = (struct drm_mode_destroy_dumb) { .handle = create.handle }; 249 KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy); 250 err: 251 SDL_free(ret); 252 return NULL; 253 } 254 255 static void 256 KMSDRM_DestroyDumbBuffer(_THIS, dumb_buffer **buffer) 257 { 258 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 259 260 struct drm_mode_destroy_dumb destroy = { 261 .handle = (*buffer)->gem_handles[0], 262 }; 263 264 KMSDRM_drmModeRmFB(viddata->drm_fd, (*buffer)->fb_id); 265 266 munmap((*buffer)->dumb.mem, (*buffer)->dumb.size); 267 KMSDRM_drmIoctl(viddata->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy); 268 free(*buffer); 269 *buffer = NULL; 270 } 271 272 /* Using the CPU mapping, fill the dumb buffer with black pixels. */ 273 static void 274 KMSDRM_FillDumbBuffer(dumb_buffer *buffer) 275 { 276 unsigned int x, y; 277 for (y = 0; y < buffer->height; y++) { 278 uint32_t *pix = (uint32_t *) ((uint8_t *) buffer->dumb.mem + (y * buffer->pitches[0])); 279 for (x = 0; x < buffer->width; x++) { 280 *pix++ = (0x00000000); 281 } 282 } 283 } 284 285 static dumb_buffer *KMSDRM_CreateBuffer(_THIS) 286 { 287 dumb_buffer *ret; 288 int err; 289 290 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 291 292 ret = KMSDRM_CreateDumbBuffer(_this); 293 294 if (!ret) 295 return NULL; 296 297 /* 298 * Wrap our GEM buffer in a KMS framebuffer, so we can then attach it 299 * to a plane. Here's where we get out fb_id! 300 */ 301 err = KMSDRM_drmModeAddFB2(viddata->drm_fd, ret->width, ret->height, 302 ret->format, ret->gem_handles, ret->pitches, 303 ret->offsets, &ret->fb_id, 0); 304 305 if (err != 0 || ret->fb_id == 0) { 306 SDL_SetError("Failed AddFB2 on dumb buffer\n"); 307 goto err; 308 } 309 return ret; 310 311 err: 312 KMSDRM_DestroyDumbBuffer(_this, &ret); 313 return NULL; 314 } 315 316 /***************************/ 317 /* DUMB BUFFER Block ends. */ 318 /***************************/ 319 320 #endif 321 322 /*********************************/ 323 /* Atomic helper functions block */ 324 /*********************************/ 325 326 #define VOID2U64(x) ((uint64_t)(unsigned long)(x)) 327 328 int add_connector_property(drmModeAtomicReq *req, struct connector *connector, 329 const char *name, uint64_t value) 330 { 331 unsigned int i; 332 int prop_id = 0; 333 334 for (i = 0 ; i < connector->props->count_props ; i++) { 335 if (strcmp(connector->props_info[i]->name, name) == 0) { 336 prop_id = connector->props_info[i]->prop_id; 337 break; 338 } 339 } 340 341 if (prop_id < 0) { 342 SDL_SetError("no connector property: %s", name); 343 return -EINVAL; 344 } 345 346 return KMSDRM_drmModeAtomicAddProperty(req, connector->connector->connector_id, prop_id, value); 347 } 348 349 int add_crtc_property(drmModeAtomicReq *req, struct crtc *crtc, 350 const char *name, uint64_t value) 351 { 352 unsigned int i; 353 int prop_id = -1; 354 355 for (i = 0 ; i < crtc->props->count_props ; i++) { 356 if (strcmp(crtc->props_info[i]->name, name) == 0) { 357 prop_id = crtc->props_info[i]->prop_id; 358 break; 359 } 360 } 361 362 if (prop_id < 0) { 363 SDL_SetError("no crtc property: %s", name); 364 return -EINVAL; 365 } 366 367 return KMSDRM_drmModeAtomicAddProperty(req, crtc->crtc->crtc_id, prop_id, value); 368 } 369 370 int add_plane_property(drmModeAtomicReq *req, struct plane *plane, 371 const char *name, uint64_t value) 372 { 373 unsigned int i; 374 int prop_id = -1; 375 376 for (i = 0 ; i < plane->props->count_props ; i++) { 377 if (strcmp(plane->props_info[i]->name, name) == 0) { 378 prop_id = plane->props_info[i]->prop_id; 379 break; 380 } 381 } 382 383 if (prop_id < 0) { 384 SDL_SetError("no plane property: %s", name); 385 return -EINVAL; 386 } 387 388 return KMSDRM_drmModeAtomicAddProperty(req, plane->plane->plane_id, prop_id, value); 389 } 390 391 #if 0 392 393 void print_plane_info(_THIS, drmModePlanePtr plane) 394 { 395 char *plane_type; 396 drmModeRes *resources; 397 uint32_t type = 0; 398 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 399 int i; 400 401 drmModeObjectPropertiesPtr props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd, 402 plane->plane_id, DRM_MODE_OBJECT_PLANE); 403 404 /* Search the plane props for the plane type. */ 405 for (i = 0; i < props->count_props; i++) { 406 drmModePropertyPtr p = KMSDRM_drmModeGetProperty(viddata->drm_fd, props->props[i]); 407 if ((strcmp(p->name, "type") == 0)) { 408 type = props->prop_values[i]; 409 } 410 411 KMSDRM_drmModeFreeProperty(p); 412 } 413 414 switch (type) { 415 case DRM_PLANE_TYPE_OVERLAY: 416 plane_type = "overlay"; 417 break; 418 419 case DRM_PLANE_TYPE_PRIMARY: 420 plane_type = "primary"; 421 break; 422 423 case DRM_PLANE_TYPE_CURSOR: 424 plane_type = "cursor"; 425 break; 426 } 427 428 429 /* Remember that to present a plane on screen, it has to be 430 connected to a CRTC so the CRTC scans it, 431 scales it, etc... and presents it on screen. */ 432 433 /* Now we look for the CRTCs supported by the plane. */ 434 resources = KMSDRM_drmModeGetResources(viddata->drm_fd); 435 if (!resources) 436 return; 437 438 printf("--PLANE ID: %d\nPLANE TYPE: %s\nCRTC READING THIS PLANE: %d\nCRTCS SUPPORTED BY THIS PLANE: ", plane->plane_id, plane_type, plane->crtc_id); 439 for (i = 0; i < resources->count_crtcs; i++) { 440 if (plane->possible_crtcs & (1 << i)) { 441 uint32_t crtc_id = resources->crtcs[i]; 442 printf ("%d", crtc_id); 443 break; 444 } 445 } 446 447 printf ("\n\n"); 448 } 449 450 void get_planes_info(_THIS) 451 { 452 drmModePlaneResPtr plane_resources; 453 uint32_t i; 454 455 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 456 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 457 458 plane_resources = KMSDRM_drmModeGetPlaneResources(viddata->drm_fd); 459 if (!plane_resources) { 460 printf("drmModeGetPlaneResources failed: %s\n", strerror(errno)); 461 return; 462 } 463 464 printf("--Number of planes found: %d-- \n", plane_resources->count_planes); 465 printf("--Usable CRTC that we have chosen: %d-- \n", dispdata->crtc->crtc->crtc_id); 466 467 /* Iterate on all the available planes. */ 468 for (i = 0; (i < plane_resources->count_planes); i++) { 469 470 uint32_t plane_id = plane_resources->planes[i]; 471 472 drmModePlanePtr plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id); 473 if (!plane) { 474 printf("drmModeGetPlane(%u) failed: %s\n", plane_id, strerror(errno)); 475 continue; 476 } 477 478 /* Print plane info. */ 479 print_plane_info(_this, plane); 480 KMSDRM_drmModeFreePlane(plane); 481 } 482 483 KMSDRM_drmModeFreePlaneResources(plane_resources); 484 } 485 486 #endif 487 488 /* Get the plane_id of a plane that is of the specified plane type (primary, 489 overlay, cursor...) and can use the CRTC we have chosen previously. */ 490 static int get_plane_id(_THIS, uint32_t plane_type) 491 { 492 drmModeRes *resources = NULL; 493 drmModePlaneResPtr plane_resources = NULL; 494 uint32_t i, j; 495 unsigned int crtc_index = 0; 496 int ret = -EINVAL; 497 int found = 0; 498 499 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 500 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 501 502 resources = KMSDRM_drmModeGetResources(viddata->drm_fd); 503 504 /* Get the crtc_index for the current CRTC. 505 It's needed to find out if a plane supports the CRTC. */ 506 for (i = 0; i < resources->count_crtcs; i++) { 507 if (resources->crtcs[i] == dispdata->crtc->crtc->crtc_id) { 508 crtc_index = i; 509 break; 510 } 511 } 512 513 plane_resources = KMSDRM_drmModeGetPlaneResources(viddata->drm_fd); 514 if (!plane_resources) { 515 return SDL_SetError("drmModeGetPlaneResources failed."); 516 } 517 518 /* Iterate on all the available planes. */ 519 for (i = 0; (i < plane_resources->count_planes) && !found; i++) { 520 521 uint32_t plane_id = plane_resources->planes[i]; 522 523 drmModePlanePtr plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id); 524 if (!plane) { 525 continue; 526 } 527 528 /* See if the current CRTC is available for this plane. */ 529 if (plane->possible_crtcs & (1 << crtc_index)) { 530 531 drmModeObjectPropertiesPtr props = KMSDRM_drmModeObjectGetProperties( 532 viddata->drm_fd, plane_id, DRM_MODE_OBJECT_PLANE); 533 ret = plane_id; 534 535 /* Iterate on the plane props to find the type of the plane, 536 to see if it's of the type we want. */ 537 for (j = 0; j < props->count_props; j++) { 538 539 drmModePropertyPtr p = KMSDRM_drmModeGetProperty(viddata->drm_fd, 540 props->props[j]); 541 542 if ((strcmp(p->name, "type") == 0) && (props->prop_values[j] == plane_type)) { 543 /* found our plane, use that: */ 544 found = 1; 545 } 546 547 KMSDRM_drmModeFreeProperty(p); 548 } 549 550 KMSDRM_drmModeFreeObjectProperties(props); 551 } 552 553 KMSDRM_drmModeFreePlane(plane); 554 } 555 556 KMSDRM_drmModeFreePlaneResources(plane_resources); 557 KMSDRM_drmModeFreeResources(resources); 558 559 return ret; 560 } 561 562 /* Setup a plane and it's props. */ 563 int 564 setup_plane(_THIS, struct plane **plane, uint32_t plane_type) 565 { 566 uint32_t plane_id; 567 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 568 int ret = 0; 569 570 *plane = SDL_calloc(1, sizeof(**plane)); 571 if (!(*plane)) { 572 ret = SDL_OutOfMemory(); 573 goto cleanup; 574 } 575 576 /* Get plane ID. */ 577 plane_id = get_plane_id(_this, plane_type); 578 579 if (!plane_id) { 580 ret = SDL_SetError("Invalid Plane ID"); 581 goto cleanup; 582 } 583 584 /* Get the DRM plane itself. */ 585 (*plane)->plane = KMSDRM_drmModeGetPlane(viddata->drm_fd, plane_id); 586 587 /* Get the DRM plane properties. */ 588 if ((*plane)->plane) { 589 unsigned int i; 590 (*plane)->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd, 591 (*plane)->plane->plane_id, DRM_MODE_OBJECT_PLANE); 592 (*plane)->props_info = SDL_calloc((*plane)->props->count_props, 593 sizeof(*(*plane)->props_info)); 594 595 if ( !((*plane)->props_info) ) { 596 ret = SDL_OutOfMemory(); 597 goto cleanup; 598 } 599 600 for (i = 0; i < (*plane)->props->count_props; i++) { 601 (*plane)->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd, 602 (*plane)->props->props[i]); 603 } 604 } 605 606 cleanup: 607 608 if (ret) { 609 if (*plane) { 610 SDL_free(*plane); 611 *plane = NULL; 612 } 613 } 614 return ret; 615 } 616 617 /* Free a plane and it's props. */ 618 void 619 free_plane(struct plane **plane) 620 { 621 if (*plane) { 622 if ((*plane)->plane) { 623 KMSDRM_drmModeFreePlane((*plane)->plane); 624 (*plane)->plane = NULL; 625 } 626 if ((*plane)->props_info) { 627 SDL_free((*plane)->props_info); 628 (*plane)->props_info = NULL; 629 } 630 SDL_free(*plane); 631 *plane = NULL; 632 } 633 } 634 635 /**********************************************************************************/ 636 /* The most important ATOMIC fn of the backend. */ 637 /* A PLANE reads a BUFFER, and a CRTC reads a PLANE and sends it's contents */ 638 /* over to a CONNECTOR->ENCODER system (several CONNECTORS can be connected */ 639 /* to the same PLANE). */ 640 /* Think of a plane as a "frame" sorrounding a picture, where the "picture" */ 641 /* is the buffer, and we move the "frame" from a picture to another, */ 642 /* and the one that has the "frame" is the one sent over to the screen */ 643 /* via the CONNECTOR->ENCODER system. */ 644 /* Think of a PLANE as being "in the middle", it's the CENTRAL part */ 645 /* bewteen the CRTC and the BUFFER that is shown on screen. */ 646 /* What we do here is connect a PLANE to a CRTC and a BUFFER. */ 647 /* -ALWAYS set the CRTC_ID and FB_ID attribs of a plane at the same time, */ 648 /* meaning IN THE SAME atomic request. */ 649 /* -And NEVER destroy a GBM surface whose buffers are being read by a plane: */ 650 /* first, move the plane away from those buffers and ONLY THEN destroy the */ 651 /* buffers and/or the GBM surface containig them. */ 652 /**********************************************************************************/ 653 void 654 drm_atomic_set_plane_props(struct KMSDRM_PlaneInfo *info) 655 { 656 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 657 658 /* Do we have a set of changes already in the making? If not, allocate a new one. */ 659 if (!dispdata->atomic_req) 660 dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc(); 661 662 add_plane_property(dispdata->atomic_req, info->plane, "FB_ID", info->fb_id); 663 add_plane_property(dispdata->atomic_req, info->plane, "CRTC_ID", info->crtc_id); 664 add_plane_property(dispdata->atomic_req, info->plane, "SRC_W", info->src_w << 16); 665 add_plane_property(dispdata->atomic_req, info->plane, "SRC_H", info->src_h << 16); 666 add_plane_property(dispdata->atomic_req, info->plane, "SRC_X", info->src_x); 667 add_plane_property(dispdata->atomic_req, info->plane, "SRC_Y", info->src_y); 668 add_plane_property(dispdata->atomic_req, info->plane, "CRTC_W", info->crtc_w); 669 add_plane_property(dispdata->atomic_req, info->plane, "CRTC_H", info->crtc_h); 670 add_plane_property(dispdata->atomic_req, info->plane, "CRTC_X", info->crtc_x); 671 add_plane_property(dispdata->atomic_req, info->plane, "CRTC_Y", info->crtc_y); 672 } 673 674 int drm_atomic_commit(_THIS, SDL_bool blocking) 675 { 676 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 677 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 678 int ret; 679 680 if (!blocking) 681 dispdata->atomic_flags |= DRM_MODE_ATOMIC_NONBLOCK; 682 683 /* Never issue a new atomic commit if previous has not yet completed, or it will error. */ 684 drm_atomic_waitpending(_this); 685 686 ret = KMSDRM_drmModeAtomicCommit(viddata->drm_fd, dispdata->atomic_req, dispdata->atomic_flags, NULL); 687 if (ret) { 688 SDL_SetError("Atomic commit failed, returned %d.", ret); 689 /* Uncomment this for fast-debugging */ 690 #if 0 691 printf("ATOMIC COMMIT FAILED: %s.\n", strerror(errno)); 692 #endif 693 goto out; 694 } 695 696 if (dispdata->kms_in_fence_fd != -1) { 697 close(dispdata->kms_in_fence_fd); 698 dispdata->kms_in_fence_fd = -1; 699 } 700 701 out: 702 KMSDRM_drmModeAtomicFree(dispdata->atomic_req); 703 dispdata->atomic_req = NULL; 704 dispdata->atomic_flags = 0; 705 706 return ret; 707 } 708 709 void 710 drm_atomic_waitpending(_THIS) 711 { 712 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 713 714 /* Will return immediately if we have already destroyed the fence, because we NULL-ify it just after. 715 Also, will return immediately in double-buffer mode, because kms_fence will alsawys be NULL. */ 716 if (dispdata->kms_fence) { 717 EGLint status; 718 719 do { 720 status = _this->egl_data->eglClientWaitSyncKHR(_this->egl_data->egl_display, 721 dispdata->kms_fence, 0, EGL_FOREVER_KHR); 722 } while (status != EGL_CONDITION_SATISFIED_KHR); 723 724 _this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->kms_fence); 725 dispdata->kms_fence = NULL; 726 } 727 } 728 729 /***************************************/ 730 /* End of Atomic helper functions block*/ 731 /***************************************/ 732 733 static int 734 KMSDRM_Available(void) 735 { 736 int ret = -ENOENT; 737 738 ret = get_driindex(); 739 if (ret >= 0) 740 return 1; 741 742 return ret; 743 } 744 745 static void 746 KMSDRM_DeleteDevice(SDL_VideoDevice * device) 747 { 748 if (device->driverdata) { 749 SDL_free(device->driverdata); 750 device->driverdata = NULL; 751 } 752 753 SDL_free(device); 754 755 SDL_KMSDRM_UnloadSymbols(); 756 } 757 758 static int 759 KMSDRM_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi) 760 { 761 int w, h; 762 763 uint32_t display_mm_width; 764 uint32_t display_mm_height; 765 766 SDL_DisplayData *dispdata; 767 768 dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); //viddata->devindex); 769 770 771 if (!dispdata) { 772 return SDL_SetError("No available displays"); 773 } 774 775 display_mm_width = dispdata->connector->connector->mmWidth; 776 display_mm_height = dispdata->connector->connector->mmHeight; 777 778 w = dispdata->mode.hdisplay; 779 h = dispdata->mode.vdisplay; 780 781 *hdpi = display_mm_width ? (((float) w) * 25.4f / display_mm_width) : 0.0f; 782 *vdpi = display_mm_height ? (((float) h) * 25.4f / display_mm_height) : 0.0f; 783 *ddpi = SDL_ComputeDiagonalDPI(w, h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f); 784 785 return 0; 786 } 787 788 static SDL_VideoDevice * 789 KMSDRM_CreateDevice(int devindex) 790 { 791 SDL_VideoDevice *device; 792 SDL_VideoData *viddata; 793 794 if (!KMSDRM_Available()) { 795 return NULL; 796 } 797 798 if (!devindex || (devindex > 99)) { 799 devindex = get_driindex(); 800 } 801 802 if (devindex < 0) { 803 SDL_SetError("devindex (%d) must be between 0 and 99.", devindex); 804 return NULL; 805 } 806 807 if (!SDL_KMSDRM_LoadSymbols()) { 808 return NULL; 809 } 810 811 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); 812 if (!device) { 813 SDL_OutOfMemory(); 814 return NULL; 815 } 816 817 viddata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); 818 if (!viddata) { 819 SDL_OutOfMemory(); 820 goto cleanup; 821 } 822 viddata->devindex = devindex; 823 viddata->drm_fd = -1; 824 825 device->driverdata = viddata; 826 827 /* Setup all functions that can be handled from this backend. */ 828 device->VideoInit = KMSDRM_VideoInit; 829 device->VideoQuit = KMSDRM_VideoQuit; 830 device->GetDisplayModes = KMSDRM_GetDisplayModes; 831 device->SetDisplayMode = KMSDRM_SetDisplayMode; 832 device->GetDisplayDPI = KMSDRM_GetDisplayDPI; 833 device->CreateSDLWindow = KMSDRM_CreateWindow; 834 device->CreateSDLWindowFrom = KMSDRM_CreateWindowFrom; 835 device->SetWindowTitle = KMSDRM_SetWindowTitle; 836 device->SetWindowIcon = KMSDRM_SetWindowIcon; 837 device->SetWindowPosition = KMSDRM_SetWindowPosition; 838 device->SetWindowSize = KMSDRM_SetWindowSize; 839 device->SetWindowFullscreen = KMSDRM_SetWindowFullscreen; 840 device->ShowWindow = KMSDRM_ShowWindow; 841 device->HideWindow = KMSDRM_HideWindow; 842 device->RaiseWindow = KMSDRM_RaiseWindow; 843 device->MaximizeWindow = KMSDRM_MaximizeWindow; 844 device->MinimizeWindow = KMSDRM_MinimizeWindow; 845 device->RestoreWindow = KMSDRM_RestoreWindow; 846 device->SetWindowGrab = KMSDRM_SetWindowGrab; 847 device->DestroyWindow = KMSDRM_DestroyWindow; 848 device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo; 849 #if SDL_VIDEO_OPENGL_EGL 850 device->GL_DefaultProfileConfig = KMSDRM_GLES_DefaultProfileConfig; 851 device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary; 852 device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress; 853 device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary; 854 device->GL_CreateContext = KMSDRM_GLES_CreateContext; 855 device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent; 856 device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval; 857 device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval; 858 device->GL_SwapWindow = KMSDRM_GLES_SwapWindow; 859 device->GL_DeleteContext = KMSDRM_GLES_DeleteContext; 860 #endif 861 device->PumpEvents = KMSDRM_PumpEvents; 862 device->free = KMSDRM_DeleteDevice; 863 #if SDL_VIDEO_VULKAN 864 device->Vulkan_LoadLibrary = KMSDRM_Vulkan_LoadLibrary; 865 device->Vulkan_UnloadLibrary = KMSDRM_Vulkan_UnloadLibrary; 866 device->Vulkan_GetInstanceExtensions = KMSDRM_Vulkan_GetInstanceExtensions; 867 device->Vulkan_CreateSurface = KMSDRM_Vulkan_CreateSurface; 868 device->Vulkan_GetDrawableSize = KMSDRM_Vulkan_GetDrawableSize; 869 #endif 870 return device; 871 872 cleanup: 873 if (device) 874 SDL_free(device); 875 if (viddata) 876 SDL_free(viddata); 877 return NULL; 878 } 879 880 VideoBootStrap KMSDRM_bootstrap = { 881 "KMSDRM", 882 "KMS/DRM Video Driver", 883 KMSDRM_CreateDevice 884 }; 885 886 887 static void 888 KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data) 889 { 890 KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data; 891 892 if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) { 893 KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id); 894 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id); 895 } 896 897 SDL_free(fb_info); 898 } 899 900 KMSDRM_FBInfo * 901 KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo) 902 { 903 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 904 unsigned width, height; 905 uint32_t format, strides[4] = {0}, handles[4] = {0}, offsets[4] = {0}; 906 const int num_planes = KMSDRM_gbm_bo_get_plane_count(bo); 907 unsigned int i; 908 int ret; 909 910 /* Check for an existing framebuffer */ 911 KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo); 912 913 if (fb_info) { 914 return fb_info; 915 } 916 917 /* Create a structure that contains the info about framebuffer 918 that we need to use it. */ 919 fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo)); 920 if (!fb_info) { 921 SDL_OutOfMemory(); 922 return NULL; 923 } 924 925 fb_info->drm_fd = viddata->drm_fd; 926 927 width = KMSDRM_gbm_bo_get_width(bo); 928 height = KMSDRM_gbm_bo_get_height(bo); 929 format = KMSDRM_gbm_bo_get_format(bo); 930 931 for (i = 0; i < num_planes; i++) { 932 strides[i] = KMSDRM_gbm_bo_get_stride_for_plane(bo, i); 933 handles[i] = KMSDRM_gbm_bo_get_handle(bo).u32; 934 offsets[i] = KMSDRM_gbm_bo_get_offset(bo, i); 935 } 936 937 /* Create framebuffer object for the buffer. 938 It's VERY important to note that fb_id is what we use to set the FB_ID prop 939 of a plane when using the ATOMIC interface, and we get the fb_id here. */ 940 ret = KMSDRM_drmModeAddFB2(viddata->drm_fd, width, height, format, 941 handles, strides, offsets, &fb_info->fb_id, 0); 942 943 if (ret) { 944 SDL_free(fb_info); 945 return NULL; 946 } 947 948 /* Set the userdata pointer. This pointer is used to store custom data that we need 949 to access in the future, so we store the fb_id here for later use, because fb_id is 950 what we need to set the FB_ID property of a plane when using the ATOMIC interface. */ 951 KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback); 952 953 return fb_info; 954 } 955 956 /*****************************************************************************/ 957 /* SDL Video and Display initialization/handling functions */ 958 /* _this is a SDL_VideoDevice * */ 959 /*****************************************************************************/ 960 961 /* Deinitializes the dispdata members needed for KMSDRM operation that are 962 inoffeensive for VK compatibility. */ 963 void KMSDRM_DisplayDataDeinit (_THIS, SDL_DisplayData *dispdata) { 964 /* Free connector */ 965 if (dispdata && dispdata->connector) { 966 if (dispdata->connector->connector) { 967 KMSDRM_drmModeFreeConnector(dispdata->connector->connector); 968 dispdata->connector->connector = NULL; 969 } 970 if (dispdata->connector->props_info) { 971 SDL_free(dispdata->connector->props_info); 972 dispdata->connector->props_info = NULL; 973 } 974 SDL_free(dispdata->connector); 975 dispdata->connector = NULL; 976 } 977 978 /* Free CRTC */ 979 if (dispdata && dispdata->crtc) { 980 if (dispdata->crtc->crtc) { 981 KMSDRM_drmModeFreeCrtc(dispdata->crtc->crtc); 982 dispdata->crtc->crtc = NULL; 983 } 984 if (dispdata->crtc->props_info) { 985 SDL_free(dispdata->crtc->props_info); 986 dispdata->crtc->props_info = NULL; 987 } 988 SDL_free(dispdata->crtc); 989 dispdata->crtc = NULL; 990 } 991 } 992 993 /* Initializes the dispdata members needed for KMSDRM operation that are 994 inoffeensive for VK compatibility, except we must leave the drm_fd 995 closed when we get to the end of this function. 996 This is to be called early, in VideoInit(), because it gets us 997 the videomode information, which SDL needs immediately after VideoInit(). */ 998 int KMSDRM_DisplayDataInit (_THIS, SDL_DisplayData *dispdata) { 999 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 1000 1001 drmModeRes *resources = NULL; 1002 drmModeEncoder *encoder = NULL; 1003 drmModeConnector *connector = NULL; 1004 drmModeCrtc *crtc = NULL; 1005 1006 char devname[32]; 1007 int ret = 0; 1008 unsigned i,j; 1009 1010 dispdata->atomic_flags = 0; 1011 dispdata->atomic_req = NULL; 1012 dispdata->kms_fence = NULL; 1013 dispdata->gpu_fence = NULL; 1014 dispdata->kms_out_fence_fd = -1; 1015 dispdata->modeset_pending = SDL_FALSE; 1016 dispdata->gbm_init = SDL_FALSE; 1017 1018 dispdata->display_plane = NULL; 1019 dispdata->cursor_plane = NULL; 1020 1021 dispdata->cursor_bo = NULL; 1022 1023 /* Open /dev/dri/cardNN */ 1024 SDL_snprintf(viddata->devpath, sizeof(viddata->devpath), "/dev/dri/card%d", viddata->devindex); 1025 1026 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", devname); 1027 viddata->drm_fd = open(viddata->devpath, O_RDWR | O_CLOEXEC); 1028 1029 if (viddata->drm_fd < 0) { 1030 ret = SDL_SetError("Could not open %s", devname); 1031 goto cleanup; 1032 } 1033 1034 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd); 1035 1036 /********************************************/ 1037 /* Block for enabling ATOMIC compatibility. */ 1038 /********************************************/ 1039 1040 /* Set ATOMIC & UNIVERSAL PLANES compatibility */ 1041 ret = set_client_caps(viddata->drm_fd); 1042 if (ret) { 1043 goto cleanup; 1044 } 1045 1046 /*******************************************/ 1047 /* Block for getting the ATOMIC resources. */ 1048 /*******************************************/ 1049 1050 /* Get all of the available connectors / devices / crtcs */ 1051 resources = KMSDRM_drmModeGetResources(viddata->drm_fd); 1052 if (!resources) { 1053 ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd); 1054 goto cleanup; 1055 } 1056 1057 /* Iterate on the available connectors to find a connected connector. */ 1058 for (i = 0; i < resources->count_connectors; i++) { 1059 drmModeConnector *conn = KMSDRM_drmModeGetConnector(viddata->drm_fd, 1060 resources->connectors[i]); 1061 1062 if (!conn) { 1063 continue; 1064 } 1065 1066 if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) { 1067 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.", 1068 conn->connector_id, conn->count_modes); 1069 connector = conn; 1070 1071 break; 1072 } 1073 1074 KMSDRM_drmModeFreeConnector(conn); 1075 } 1076 1077 if (!connector) { 1078 ret = SDL_SetError("No currently active connector found."); 1079 goto cleanup; 1080 } 1081 1082 /* Try to find the connector's current encoder */ 1083 for (i = 0; i < resources->count_encoders; i++) { 1084 encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]); 1085 1086 if (!encoder) { 1087 continue; 1088 } 1089 1090 if (encoder->encoder_id == connector->encoder_id) { 1091 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id); 1092 break; 1093 } 1094 1095 KMSDRM_drmModeFreeEncoder(encoder); 1096 encoder = NULL; 1097 } 1098 1099 if (!encoder) { 1100 /* No encoder was connected, find the first supported one */ 1101 for (i = 0; i < resources->count_encoders; i++) { 1102 encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]); 1103 1104 if (!encoder) { 1105 continue; 1106 } 1107 1108 for (j = 0; j < connector->count_encoders; j++) { 1109 if (connector->encoders[j] == encoder->encoder_id) { 1110 break; 1111 } 1112 } 1113 1114 if (j != connector->count_encoders) { 1115 break; 1116 } 1117 1118 KMSDRM_drmModeFreeEncoder(encoder); 1119 encoder = NULL; 1120 } 1121 } 1122 1123 if (!encoder) { 1124 ret = SDL_SetError("No connected encoder found."); 1125 goto cleanup; 1126 } 1127 1128 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id); 1129 1130 /* Try to find a CRTC connected to this encoder */ 1131 crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id); 1132 1133 /* If no CRTC was connected to the encoder, find the first CRTC 1134 that is supported by the encoder, and use that. */ 1135 if (!crtc) { 1136 for (i = 0; i < resources->count_crtcs; i++) { 1137 if (encoder->possible_crtcs & (1 << i)) { 1138 encoder->crtc_id = resources->crtcs[i]; 1139 crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id); 1140 break; 1141 } 1142 } 1143 } 1144 1145 if (!crtc) { 1146 ret = SDL_SetError("No CRTC found."); 1147 goto cleanup; 1148 } 1149 1150 /* Figure out the default mode to be set. */ 1151 dispdata->mode = crtc->mode; 1152 1153 /* Find the connector's preferred mode, to be used in case the current mode 1154 is not valid, or if restoring the current mode fails. 1155 We can always count on the preferred mode! */ 1156 for (i = 0; i < connector->count_modes; i++) { 1157 if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) { 1158 dispdata->preferred_mode = connector->modes[i]; 1159 } 1160 } 1161 1162 /* If the current CRTC's mode isn't valid, select the preferred 1163 mode of the connector. */ 1164 if (crtc->mode_valid == 0) { 1165 dispdata->mode = dispdata->preferred_mode; 1166 } 1167 1168 if (dispdata->mode.hdisplay == 0 || dispdata->mode.vdisplay == 0 ) { 1169 ret = SDL_SetError("Couldn't get a valid connector videomode."); 1170 goto cleanup; 1171 } 1172 1173 /* Get CRTC properties */ 1174 dispdata->crtc->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd, 1175 crtc->crtc_id, DRM_MODE_OBJECT_CRTC); 1176 1177 dispdata->crtc->props_info = SDL_calloc(dispdata->crtc->props->count_props, 1178 sizeof(*dispdata->crtc->props_info)); 1179 1180 if (!dispdata->crtc->props_info) { 1181 ret = SDL_OutOfMemory(); 1182 goto cleanup; 1183 } 1184 1185 for (i = 0; i < dispdata->crtc->props->count_props; i++) { 1186 dispdata->crtc->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd, 1187 dispdata->crtc->props->props[i]); 1188 } 1189 1190 /* Get connector properties */ 1191 dispdata->connector->props = KMSDRM_drmModeObjectGetProperties(viddata->drm_fd, 1192 connector->connector_id, DRM_MODE_OBJECT_CONNECTOR); 1193 1194 dispdata->connector->props_info = SDL_calloc(dispdata->connector->props->count_props, 1195 sizeof(*dispdata->connector->props_info)); 1196 1197 if (!dispdata->connector->props_info) { 1198 ret = SDL_OutOfMemory(); 1199 goto cleanup; 1200 } 1201 1202 for (i = 0; i < dispdata->connector->props->count_props; i++) { 1203 dispdata->connector->props_info[i] = KMSDRM_drmModeGetProperty(viddata->drm_fd, 1204 dispdata->connector->props->props[i]); 1205 } 1206 1207 /* Store the connector and crtc for future use. This is all we keep from this function, 1208 and these are just structs, inoffensive to VK. */ 1209 dispdata->connector->connector = connector; 1210 dispdata->crtc->crtc = crtc; 1211 1212 /***********************************/ 1213 /* Block fpr Vulkan compatibility. */ 1214 /***********************************/ 1215 1216 /* THIS IS FOR VULKAN! Leave the FD closed, so VK can work. 1217 Will reopen this in CreateWindow, but only if requested a non-VK window. */ 1218 KMSDRM_drmSetClientCap(viddata->drm_fd, DRM_CLIENT_CAP_ATOMIC, 0); 1219 KMSDRM_drmSetClientCap(viddata->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0); 1220 close (viddata->drm_fd); 1221 viddata->drm_fd = -1; 1222 1223 cleanup: 1224 if (encoder) 1225 KMSDRM_drmModeFreeEncoder(encoder); 1226 if (resources) 1227 KMSDRM_drmModeFreeResources(resources); 1228 if (ret) { 1229 /* Error (complete) cleanup */ 1230 if (dispdata->connector->connector) { 1231 KMSDRM_drmModeFreeConnector(dispdata->connector->connector); 1232 dispdata->connector->connector = NULL; 1233 } 1234 if (dispdata->crtc->props_info) { 1235 SDL_free(dispdata->crtc->props_info); 1236 dispdata->crtc->props_info = NULL; 1237 } 1238 if (dispdata->connector->props_info) { 1239 SDL_free(dispdata->connector->props_info); 1240 dispdata->connector->props_info = NULL; 1241 } 1242 if (dispdata->crtc->crtc) { 1243 KMSDRM_drmModeFreeCrtc(dispdata->crtc->crtc); 1244 dispdata->crtc->crtc = NULL; 1245 } 1246 if (viddata->drm_fd >= 0) { 1247 close(viddata->drm_fd); 1248 viddata->drm_fd = -1; 1249 } 1250 } 1251 1252 return ret; 1253 } 1254 1255 /* Init the Vulkan-INCOMPATIBLE stuff: 1256 Reopen FD, create gbm dev, create dumb buffer and setup display plane. 1257 This is to be called late, in WindowCreate(), and ONLY if this is not 1258 a Vulkan window. 1259 We are doing this so late to allow Vulkan to work if we build a VK window. 1260 These things are incompatible with Vulkan, which accesses the same resources 1261 internally so they must be free when trying to build a Vulkan surface. 1262 */ 1263 int 1264 KMSDRM_GBMInit (_THIS, SDL_DisplayData *dispdata) 1265 { 1266 SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata; 1267 int ret = 0; 1268 1269 /* Reopen the FD! */ 1270 viddata->drm_fd = open(viddata->devpath, O_RDWR | O_CLOEXEC); 1271 set_client_caps(viddata->drm_fd); 1272 1273 /* Create the GBM device. */ 1274 viddata->gbm_dev = KMSDRM_gbm_create_device(viddata->drm_fd); 1275 if (!viddata->gbm_dev) { 1276 ret = SDL_SetError("Couldn't create gbm device."); 1277 } 1278 1279 /* Setup the display plane. ONLY do this after dispdata has the right 1280 crtc and connector, because these are used in this function. */ 1281 ret = setup_plane(_this, &(dispdata->display_plane), DRM_PLANE_TYPE_PRIMARY); 1282 if (ret) { 1283 ret = SDL_SetError("can't find suitable display plane."); 1284 } 1285 1286 dispdata->gbm_init = SDL_TRUE; 1287 1288 return ret; 1289 } 1290 1291 /* Deinit the Vulkan-incompatible KMSDRM stuff. */ 1292 void 1293 KMSDRM_GBMDeinit (_THIS, SDL_DisplayData *dispdata) 1294 { 1295 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 1296 1297 /* Free display plane */ 1298 free_plane(&dispdata->display_plane); 1299 1300 /* Free cursor plane (if still not freed) */ 1301 free_plane(&dispdata->cursor_plane); 1302 1303 /* Destroy GBM device. GBM surface is destroyed by DestroySurfaces(), 1304 already called when we get here. */ 1305 if (viddata->gbm_dev) { 1306 KMSDRM_gbm_device_destroy(viddata->gbm_dev); 1307 viddata->gbm_dev = NULL; 1308 } 1309 1310 /* Finally close DRM FD. May be reopen on next non-vulkan window creation. */ 1311 if (viddata->drm_fd >= 0) { 1312 close(viddata->drm_fd); 1313 viddata->drm_fd = -1; 1314 } 1315 1316 dispdata->gbm_init = SDL_FALSE; 1317 } 1318 1319 /* Destroy the window surfaces and buffers. Have the PRIMARY PLANE 1320 disconnected from these buffers before doing so, or have the PRIMARY PLANE 1321 reading the original FB where the TTY lives, before doing this, or CRTC will 1322 be disconnected by the kernel. */ 1323 void 1324 KMSDRM_DestroySurfaces(_THIS, SDL_Window *window) 1325 { 1326 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; 1327 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 1328 KMSDRM_PlaneInfo plane_info = {0}; 1329 1330 #if SDL_VIDEO_OPENGL_EGL 1331 EGLContext egl_context; 1332 #endif 1333 1334 /********************************************************************/ 1335 /* BLOCK 1: protect the PRIMARY PLANE before destroying the buffers */ 1336 /* it's using, by making it point to the original CRTC buffer, */ 1337 /* where the TTY console should be. */ 1338 /********************************************************************/ 1339 1340 plane_info.plane = dispdata->display_plane; 1341 plane_info.crtc_id = dispdata->crtc->crtc->crtc_id; 1342 plane_info.fb_id = dispdata->crtc->crtc->buffer_id; 1343 plane_info.src_w = dispdata->mode.hdisplay; 1344 plane_info.src_h = dispdata->mode.vdisplay; 1345 plane_info.crtc_w = dispdata->mode.hdisplay; 1346 plane_info.crtc_h = dispdata->mode.vdisplay; 1347 1348 drm_atomic_set_plane_props(&plane_info); 1349 1350 /* Issue blocking atomic commit. */ 1351 if (drm_atomic_commit(_this, SDL_TRUE)) { 1352 SDL_SetError("Failed to issue atomic commit on surfaces destruction."); 1353 } 1354 1355 /****************************************************************************/ 1356 /* BLOCK 2: We can finally destroy the window GBM and EGL surfaces, and */ 1357 /* GBM buffers now that the buffers are not being used by the PRIMARY PLANE */ 1358 /* anymore. */ 1359 /****************************************************************************/ 1360 1361 /* Destroy the GBM surface and buffers. */ 1362 if (windata->bo) { 1363 KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo); 1364 windata->bo = NULL; 1365 } 1366 1367 if (windata->next_bo) { 1368 KMSDRM_gbm_surface_release_buffer(windata->gs, windata->next_bo); 1369 windata->next_bo = NULL; 1370 } 1371 1372 /***************************************************************************/ 1373 /* Destroy the EGL surface. */ 1374 /* In this eglMakeCurrent() call, we disable the current EGL surface */ 1375 /* because we're going to destroy it, but DON'T disable the EGL context, */ 1376 /* because it won't be enabled again until the programs ask for a pageflip */ 1377 /* so we get to SwapWindow(). */ 1378 /* If we disable the context until then and a program tries to retrieve */ 1379 /* the context version info before calling for a pageflip, the program */ 1380 /* will get wrong info and we will be in trouble. */ 1381 /***************************************************************************/ 1382 1383 #if SDL_VIDEO_OPENGL_EGL 1384 egl_context = (EGLContext)SDL_GL_GetCurrentContext(); 1385 SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, egl_context); 1386 1387 if (windata->egl_surface != EGL_NO_SURFACE) { 1388 SDL_EGL_DestroySurface(_this, windata->egl_surface); 1389 windata->egl_surface = EGL_NO_SURFACE; 1390 } 1391 #endif 1392 1393 if (windata->gs) { 1394 KMSDRM_gbm_surface_destroy(windata->gs); 1395 windata->gs = NULL; 1396 } 1397 1398 } 1399 1400 int 1401 KMSDRM_CreateSurfaces(_THIS, SDL_Window * window) 1402 { 1403 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 1404 SDL_WindowData *windata = (SDL_WindowData *)window->driverdata; 1405 SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; 1406 uint32_t surface_fmt = GBM_FORMAT_ARGB8888; 1407 uint32_t surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; 1408 uint32_t width, height; 1409 1410 EGLContext egl_context; 1411 1412 int ret = 0; 1413 1414 if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) || 1415 ((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) { 1416 1417 width = dispdata->mode.hdisplay; 1418 height = dispdata->mode.vdisplay; 1419 } else { 1420 width = window->w; 1421 height = window->h; 1422 } 1423 1424 if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, surface_fmt, surface_flags)) { 1425 SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway."); 1426 } 1427 1428 windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, width, height, surface_fmt, surface_flags); 1429 1430 if (!windata->gs) { 1431 return SDL_SetError("Could not create GBM surface"); 1432 } 1433 1434 #if SDL_VIDEO_OPENGL_EGL 1435 /* We can't get the EGL context yet because SDL_CreateRenderer has not been called, 1436 but we need an EGL surface NOW, or GL won't be able to render into any surface 1437 and we won't see the first frame. */ 1438 SDL_EGL_SetRequiredVisualId(_this, surface_fmt); 1439 windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs); 1440 1441 if (windata->egl_surface == EGL_NO_SURFACE) { 1442 ret = SDL_SetError("Could not create EGL window surface"); 1443 goto cleanup; 1444 } 1445 1446 /* Current context passing to EGL is now done here. If something fails, 1447 go back to delayed SDL_EGL_MakeCurrent() call in SwapWindow. */ 1448 egl_context = (EGLContext)SDL_GL_GetCurrentContext(); 1449 ret = SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context); 1450 1451 #endif 1452 1453 cleanup: 1454 1455 if (ret) { 1456 /* Error (complete) cleanup. */ 1457 if (windata->gs) { 1458 KMSDRM_gbm_surface_destroy(windata->gs); 1459 windata->gs = NULL; 1460 } 1461 } 1462 1463 return ret; 1464 } 1465 1466 void 1467 KMSDRM_DestroyWindow(_THIS, SDL_Window *window) 1468 { 1469 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; 1470 SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; 1471 SDL_VideoData *viddata = windata->viddata; 1472 SDL_bool is_vulkan = window->flags & SDL_WINDOW_VULKAN; /* Is this a VK window? */ 1473 unsigned int i, j; 1474 1475 if (!windata) { 1476 return; 1477 } 1478 1479 if (!is_vulkan) { 1480 KMSDRM_DestroySurfaces(_this, window); 1481 #if SDL_VIDEO_OPENGL_EGL 1482 if (_this->egl_data) { 1483 SDL_EGL_UnloadLibrary(_this); 1484 } 1485 #endif 1486 if (dispdata->gbm_init) { 1487 KMSDRM_DeinitMouse(_this); 1488 KMSDRM_GBMDeinit(_this, dispdata); 1489 } 1490 } 1491 1492 /********************************************/ 1493 /* Remove from the internal SDL window list */ 1494 /********************************************/ 1495 1496 for (i = 0; i < viddata->num_windows; i++) { 1497 if (viddata->windows[i] == window) { 1498 viddata->num_windows--; 1499 1500 for (j = i; j < viddata->num_windows; j++) { 1501 viddata->windows[j] = viddata->windows[j + 1]; 1502 } 1503 1504 break; 1505 } 1506 } 1507 1508 /*********************************************************************/ 1509 /* Free the window driverdata. Bye bye, surface and buffer pointers! */ 1510 /*********************************************************************/ 1511 window->driverdata = NULL; 1512 SDL_free(windata); 1513 } 1514 1515 /*****************************************************************************/ 1516 /* Reconfigure the window scaling parameters and re-construct it's surfaces, */ 1517 /* without destroying the window itself. */ 1518 /* To be used by SetWindowSize() and SetWindowFullscreen(). */ 1519 /*****************************************************************************/ 1520 static int 1521 KMSDRM_ReconfigureWindow( _THIS, SDL_Window * window) { 1522 SDL_WindowData *windata = window->driverdata; 1523 SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; 1524 SDL_bool is_vulkan = window->flags & SDL_WINDOW_VULKAN; /* Is this a VK window? */ 1525 float ratio; 1526 1527 if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) || 1528 ((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) { 1529 1530 windata->src_w = dispdata->mode.hdisplay; 1531 windata->src_h = dispdata->mode.vdisplay; 1532 windata->output_w = dispdata->mode.hdisplay; 1533 windata->output_h = dispdata->mode.vdisplay; 1534 windata->output_x = 0; 1535 1536 } else { 1537 1538 /* Normal non-fullscreen windows are scaled using the CRTC, 1539 so get output (CRTC) size and position, for AR correction. */ 1540 ratio = (float)window->w / (float)window->h; 1541 windata->src_w = window->w; 1542 windata->src_h = window->h; 1543 windata->output_w = dispdata->mode.vdisplay * ratio; 1544 windata->output_h = dispdata->mode.vdisplay; 1545 windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2; 1546 1547 } 1548 1549 if (!is_vulkan) { 1550 if (KMSDRM_CreateSurfaces(_this, window)) { 1551 return -1; 1552 } 1553 } 1554 return 0; 1555 } 1556 1557 int 1558 KMSDRM_VideoInit(_THIS) 1559 { 1560 int ret = 0; 1561 1562 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 1563 SDL_DisplayData *dispdata = NULL; 1564 SDL_VideoDisplay display = {0}; 1565 1566 SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()"); 1567 1568 viddata->video_init = SDL_FALSE; 1569 1570 dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData)); 1571 if (!dispdata) { 1572 return SDL_OutOfMemory(); 1573 } 1574 1575 /* Alloc memory for these. */ 1576 dispdata->display_plane = SDL_calloc(1, sizeof(*dispdata->display_plane)); 1577 dispdata->crtc = SDL_calloc(1, sizeof(*dispdata->crtc)); 1578 dispdata->connector = SDL_calloc(1, sizeof(*dispdata->connector)); 1579 if (!(dispdata->display_plane) || !(dispdata->crtc) || !(dispdata->connector)) { 1580 ret = SDL_OutOfMemory(); 1581 goto cleanup; 1582 } 1583 1584 /* Get KMSDRM resources info and store what we need. Getting and storing 1585 this info isn't a problem for VK compatibility. 1586 For VK-incompatible initializations we have KMSDRM_GBMInit(), which is 1587 called on window creation, and only when we know it's not a VK window. */ 1588 if (KMSDRM_DisplayDataInit(_this, dispdata)) { 1589 ret = SDL_SetError("error getting KMS/DRM information"); 1590 goto cleanup; 1591 } 1592 1593 /* Setup the single display that's available. 1594 There's no problem with it being still incomplete. */ 1595 display.driverdata = dispdata; 1596 display.desktop_mode.w = dispdata->mode.hdisplay; 1597 display.desktop_mode.h = dispdata->mode.vdisplay; 1598 display.desktop_mode.refresh_rate = dispdata->mode.vrefresh; 1599 display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888; 1600 display.current_mode = display.desktop_mode; 1601 1602 /* Add the display only when it's ready, */ 1603 SDL_AddVideoDisplay(&display, SDL_FALSE); 1604 1605 /* Use this if you ever need to see info on all available planes. */ 1606 #if 0 1607 get_planes_info(_this); 1608 #endif 1609 1610 #ifdef SDL_INPUT_LINUXEV 1611 SDL_EVDEV_Init(); 1612 #endif 1613 1614 viddata->video_init = SDL_TRUE; 1615 1616 cleanup: 1617 1618 if (ret) { 1619 /* Error (complete) cleanup */ 1620 if (dispdata->display_plane) { 1621 SDL_free(dispdata->display_plane); 1622 } 1623 if (dispdata->crtc) { 1624 SDL_free(dispdata->crtc); 1625 } 1626 if (dispdata->connector) { 1627 SDL_free(dispdata->connector); 1628 } 1629 1630 SDL_free(dispdata); 1631 } 1632 1633 return ret; 1634 } 1635 1636 /* The driverdata pointers, like dispdata, viddata, windata, etc... 1637 are freed by SDL internals, so not our job. */ 1638 void 1639 KMSDRM_VideoQuit(_THIS) 1640 { 1641 SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); 1642 SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); 1643 1644 KMSDRM_DisplayDataDeinit(_this, dispdata); 1645 1646 #ifdef SDL_INPUT_LINUXEV 1647 SDL_EVDEV_Quit(); 1648 #endif 1649 1650 /* Clear out the window list */ 1651 SDL_free(viddata->windows); 1652 viddata->windows = NULL; 1653 viddata->max_windows = 0; 1654 viddata->num_windows = 0; 1655 viddata->video_init = SDL_FALSE; 1656 } 1657 1658 #if 0 1659 void 1660 KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display) 1661 { 1662 /* Only one display mode available: the current one */ 1663 SDL_AddDisplayMode(display, &display->current_mode); 1664 } 1665 #endif 1666 1667 /* We only change the video mode for FULLSCREEN windows 1668 that are not FULLSCREEN_DESKTOP. 1669 Normal non-fullscreen windows are scaled using the CRTC. */ 1670 void 1671 KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display) 1672 { 1673 SDL_DisplayData *dispdata = display->driverdata; 1674 drmModeConnector *conn = dispdata->connector->connector; 1675 SDL_DisplayMode mode; 1676 int i; 1677 1678 for (i = 0; i < conn->count_modes; i++) { 1679 SDL_DisplayModeData *modedata = SDL_calloc(1, sizeof(SDL_DisplayModeData)); 1680 1681 if (!modedata) { 1682 SDL_OutOfMemory(); 1683 return; 1684 } 1685 1686 modedata->mode_index = i; 1687 1688 mode.w = conn->modes[i].hdisplay; 1689 mode.h = conn->modes[i].vdisplay; 1690 mode.refresh_rate = conn->modes[i].vrefresh; 1691 mode.format = SDL_PIXELFORMAT_ARGB8888; 1692 mode.driverdata = modedata; 1693 1694 if (!SDL_AddDisplayMode(display, &mode)) { 1695 SDL_free(modedata); 1696 } 1697 } 1698 } 1699 1700 int 1701 KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) 1702 { 1703 /* Set the dispdata->mode to the new mode and leave actual modesetting 1704 pending to be done on SwapWindow(), to be included on next atomic 1705 commit changeset. */ 1706 1707 SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata; 1708 SDL_DisplayData *dispdata = (SDL_DisplayData *)display->driverdata; 1709 SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; 1710 drmModeConnector *conn = dispdata->connector->connector; 1711 int i; 1712 1713 if (!modedata) { 1714 return SDL_SetError("Mode doesn't have an associated index"); 1715 } 1716 1717 /* Take note of the new mode. It will be used in SwapWindow to 1718 set the props needed for mode setting. */ 1719 dispdata->mode = conn->modes[modedata->mode_index]; 1720 1721 dispdata->modeset_pending = SDL_TRUE; 1722 1723 for (i = 0; i < viddata->num_windows; i++) { 1724 SDL_Window *window = viddata->windows[i]; 1725 1726 if (KMSDRM_CreateSurfaces(_this, window)) { 1727 return -1; 1728 } 1729 1730 /* Tell app about the window resize */ 1731 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode->w, mode->h); 1732 } 1733 1734 return 0; 1735 } 1736 1737 int 1738 KMSDRM_CreateWindow(_THIS, SDL_Window * window) 1739 { 1740 SDL_WindowData *windata = NULL; 1741 SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata; 1742 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); 1743 SDL_DisplayData *dispdata = display->driverdata; 1744 SDL_bool is_vulkan = window->flags & SDL_WINDOW_VULKAN; /* Is this a VK window? */ 1745 NativeDisplayType egl_display; 1746 float ratio; 1747 int ret = 0; 1748 1749 if ( !(dispdata->gbm_init) && (!is_vulkan)) { 1750 /* Reopen FD, create gbm dev, setup display plane, etc,. 1751 but only when we come here for the first time, 1752 and only if it's not a VK window. */ 1753 if ((ret = KMSDRM_GBMInit(_this, dispdata))) { 1754 goto cleanup; 1755 } 1756 1757 #if SDL_VIDEO_OPENGL_EGL 1758 /* Manually load the EGL library. KMSDRM_EGL_LoadLibrary() has already 1759 been called by SDL_CreateWindow() but we don't do anything there, 1760 precisely to be able to load it here. 1761 If we let SDL_CreateWindow() load the lib, it will be loaded 1762 before we call KMSDRM_GBMInit(), causing GLES programs to fail. */ 1763 if (!_this->egl_data) { 1764 egl_display = (NativeDisplayType)((SDL_VideoData *)_this->driverdata)->gbm_dev; 1765 if ((ret = SDL_EGL_LoadLibrary(_this, NULL, egl_display, EGL_PLATFORM_GBM_MESA))) { 1766 goto cleanup; 1767 } 1768 } 1769 #endif 1770 1771 /* Can't init mouse stuff sooner because cursor plane is not ready. */ 1772 KMSDRM_InitMouse(_this); 1773 1774 /* Since we take cursor buffer way from the cursor plane and 1775 destroy the cursor GBM BO when we destroy a window, we must 1776 also manually re-show the cursor on screen, if necessary, 1777 when we create a window. */ 1778 KMSDRM_InitCursor(); 1779 } 1780 1781 /* Allocate window internal data */ 1782 windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); 1783 if (!windata) { 1784 ret = SDL_OutOfMemory(); 1785 goto cleanup; 1786 } 1787 1788 if (((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) || 1789 ((window->flags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)) 1790 { 1791 windata->src_w = dispdata->mode.hdisplay; 1792 windata->src_h = dispdata->mode.vdisplay; 1793 windata->output_w = dispdata->mode.hdisplay; 1794 windata->output_h = dispdata->mode.vdisplay; 1795 windata->output_x = 0; 1796 } else { 1797 /* Normal non-fullscreen windows are scaled using the CRTC, 1798 so get output (CRTC) size and position, for AR correction. */ 1799 ratio = (float)window->w / (float)window->h; 1800 windata->src_w = window->w; 1801 windata->src_h = window->h; 1802 windata->output_w = dispdata->mode.vdisplay * ratio; 1803 windata->output_h = dispdata->mode.vdisplay; 1804 windata->output_x = (dispdata->mode.hdisplay - windata->output_w) / 2; 1805 } 1806 1807 /* Don't force fullscreen on all windows: it confuses programs that try 1808 to set a window fullscreen after creating it as non-fullscreen (sm64ex) */ 1809 // window->flags |= SDL_WINDOW_FULLSCREEN; 1810 1811 /* Setup driver data for this window */ 1812 windata->viddata = viddata; 1813 window->driverdata = windata; 1814 1815 if (!is_vulkan) { 1816 if ((ret = KMSDRM_CreateSurfaces(_this, window))) { 1817 goto cleanup; 1818 } 1819 } 1820 1821 /* Add window to the internal list of tracked windows. Note, while it may 1822 seem odd to support multiple fullscreen windows, some apps create an 1823 extra window as a dummy surface when working with multiple contexts */ 1824 if (viddata->num_windows >= viddata->max_windows) { 1825 unsigned int new_max_windows = viddata->max_windows + 1; 1826 viddata->windows = (SDL_Window **)SDL_realloc(viddata->windows, 1827 new_max_windows * sizeof(SDL_Window *)); 1828 viddata->max_windows = new_max_windows; 1829 1830 if (!viddata->windows) { 1831 ret = SDL_OutOfMemory(); 1832 goto cleanup; 1833 } 1834 } 1835 1836 viddata->windows[viddata->num_windows++] = window; 1837 1838 /* Focus on the newly created window */ 1839 SDL_SetMouseFocus(window); 1840 SDL_SetKeyboardFocus(window); 1841 1842 /***********************************************************/ 1843 /* Tell SDL that the mouse has entered the window using an */ 1844 /* artificial event: we have no windowing system to tell */ 1845 /* SDL that it has happened. This makes SDL set the */ 1846 /* SDL_WINDOW_MOUSE_FOCUS on this window, thus fixing */ 1847 /* Scummvm sticky-on-sides software cursor. */ 1848 /***********************************************************/ 1849 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_ENTER, 0, 0); 1850 1851 cleanup: 1852 1853 if (ret) { 1854 /* Allocated windata will be freed in KMSDRM_DestroyWindow */ 1855 KMSDRM_DestroyWindow(_this, window); 1856 } 1857 return ret; 1858 } 1859 1860 int 1861 KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) 1862 { 1863 return -1; 1864 } 1865 1866 void 1867 KMSDRM_SetWindowTitle(_THIS, SDL_Window * window) 1868 { 1869 } 1870 void 1871 KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) 1872 { 1873 } 1874 void 1875 KMSDRM_SetWindowPosition(_THIS, SDL_Window * window) 1876 { 1877 } 1878 1879 void 1880 KMSDRM_SetWindowSize(_THIS, SDL_Window * window) 1881 { 1882 if (KMSDRM_ReconfigureWindow(_this, window)) { 1883 SDL_SetError("Can't reconfigure window on SetWindowSize."); 1884 } 1885 } 1886 1887 void 1888 KMSDRM_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) 1889 { 1890 if (KMSDRM_ReconfigureWindow(_this, window)) { 1891 SDL_SetError("Can't reconfigure window on SetWindowFullscreen."); 1892 } 1893 } 1894 1895 void 1896 KMSDRM_ShowWindow(_THIS, SDL_Window * window) 1897 { 1898 } 1899 void 1900 KMSDRM_HideWindow(_THIS, SDL_Window * window) 1901 { 1902 } 1903 void 1904 KMSDRM_RaiseWindow(_THIS, SDL_Window * window) 1905 { 1906 } 1907 void 1908 KMSDRM_MaximizeWindow(_THIS, SDL_Window * window) 1909 { 1910 } 1911 void 1912 KMSDRM_MinimizeWindow(_THIS, SDL_Window * window) 1913 { 1914 } 1915 void 1916 KMSDRM_RestoreWindow(_THIS, SDL_Window * window) 1917 { 1918 } 1919 void 1920 KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) 1921 { 1922 1923 } 1924 1925 /*****************************************************************************/ 1926 /* SDL Window Manager function */ 1927 /*****************************************************************************/ 1928 SDL_bool 1929 KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info) 1930 { 1931 if (info->version.major <= SDL_MAJOR_VERSION) { 1932 return SDL_TRUE; 1933 } else { 1934 SDL_SetError("application not compiled with SDL %d.%d\n", 1935 SDL_MAJOR_VERSION, SDL_MINOR_VERSION); 1936 return SDL_FALSE; 1937 } 1938 1939 /* Failed to get window manager information */ 1940 return SDL_FALSE; 1941 } 1942 1943 #endif /* SDL_VIDEO_DRIVER_KMSDRM */ 1944 1945 /* vi: set ts=4 sw=4 expandtab: */