SDL  2.0
SDL_kmsdrm_legacy_video.c
Go to the documentation of this file.
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 */
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) {
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  }
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 
155 }
156 
157 static SDL_VideoDevice *
158 KMSDRM_LEGACY_CreateDevice(int devindex)
159 {
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 
177  return NULL;
178  }
179 
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 
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 {
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 
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;
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
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
389 {
390  SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
391  SDL_WindowData *windata = (SDL_WindowData *)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
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) {
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
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 
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
641 {
642  SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
644 
645  SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_LEGACY_VideoQuit()");
646 
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
693 {
694  SDL_DisplayData *dispdata = display->driverdata;
695  drmModeConnector *conn = dispdata->conn;
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;
710  mode.driverdata = modedata;
711 
712  if (!SDL_AddDisplayMode(display, &mode)) {
713  SDL_free(modedata);
714  }
715  }
716 }
717 
718 int
720 {
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 
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
743  return -1;
744  }
745 #endif
746 
747  /* Tell app about the resize */
749  }
750 
751  return 0;
752 }
753 
754 int
756 {
758  SDL_WindowData *windata;
759  SDL_VideoDisplay *display;
760 
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 */
784 
785  /* In case we want low-latency, double-buffer video, we take note here */
786  windata->double_buffer = SDL_FALSE;
787 
789  windata->double_buffer = SDL_TRUE;
790  }
791 
792  /* Setup driver data for this window */
793  windata->viddata = viddata;
794  window->driverdata = windata;
795 
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 */
820 
821  return 0;
822 
823 error:
825 
826  return -1;
827 }
828 
829 void
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
864 {
865  return -1;
866 }
867 
868 void
870 {
871 }
872 void
874 {
875 }
876 void
878 {
879 }
880 void
882 {
883 }
884 void
886 {
887 }
888 void
890 {
891 }
892 void
894 {
895 }
896 void
898 {
899 }
900 void
902 {
903 }
904 void
906 {
907 }
908 void
910 {
911 
912 }
913 
914 /*****************************************************************************/
915 /* SDL Window Manager function */
916 /*****************************************************************************/
917 SDL_bool
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",
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: */
#define _THIS
#define SDL_SetError
#define SDL_strncmp
#define SDL_GL_LoadLibrary
#define SDL_strlen
#define SDL_realloc
#define SDL_LogError
#define SDL_free
#define SDL_GetHintBoolean
#define SDL_GL_UnloadLibrary
#define SDL_LogDebug
#define SDL_LogWarn
#define SDL_snprintf
#define SDL_calloc
#define SDL_GL_GetCurrentContext
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_HINT_VIDEO_DOUBLE_BUFFER
Tell the video driver that we only want a double buffer.
Definition: SDL_hints.h:1208
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:634
void SDL_KMSDRM_LEGACY_UnloadSymbols(void)
int SDL_KMSDRM_LEGACY_LoadSymbols(void)
void KMSDRM_LEGACY_PumpEvents(_THIS)
void KMSDRM_LEGACY_InitMouse(_THIS)
int KMSDRM_LEGACY_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context)
int KMSDRM_LEGACY_CreateWindowFrom(_THIS, SDL_Window *window, const void *data)
void KMSDRM_LEGACY_SetWindowPosition(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_GLES_DeleteContext(_THIS, SDL_GLContext context)
void KMSDRM_LEGACY_RestoreWindow(_THIS, SDL_Window *window)
void * KMSDRM_LEGACY_GLES_GetProcAddress(_THIS, const char *proc)
void KMSDRM_LEGACY_HideWindow(_THIS, SDL_Window *window)
int KMSDRM_LEGACY_CreateSurfaces(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_SetWindowTitle(_THIS, SDL_Window *window)
int KMSDRM_LEGACY_GLES_LoadLibrary(_THIS, const char *path)
SDL_GLContext KMSDRM_LEGACY_GLES_CreateContext(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_MaximizeWindow(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_ShowWindow(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_VideoQuit(_THIS)
void KMSDRM_LEGACY_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
int KMSDRM_LEGACY_GLES_SwapWindow(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_RaiseWindow(_THIS, SDL_Window *window)
int KMSDRM_LEGACY_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
int KMSDRM_LEGACY_VideoInit(_THIS)
SDL_bool KMSDRM_LEGACY_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
void KMSDRM_LEGACY_GLES_UnloadLibrary(_THIS)
void KMSDRM_LEGACY_DestroyWindow(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_MinimizeWindow(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_SetWindowSize(_THIS, SDL_Window *window)
void KMSDRM_LEGACY_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
SDL_bool KMSDRM_LEGACY_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout)
int KMSDRM_LEGACY_GLES_SetSwapInterval(_THIS, int interval)
int KMSDRM_LEGACY_CreateWindow(_THIS, SDL_Window *window)
KMSDRM_LEGACY_FBInfo * KMSDRM_LEGACY_FBFromBO(_THIS, struct gbm_bo *bo)
void KMSDRM_LEGACY_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
int KMSDRM_LEGACY_GLES_GetSwapInterval(_THIS)
@ SDL_LOG_CATEGORY_VIDEO
Definition: SDL_log.h:71
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:208
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
GLsizei stride
GLuint res
GLenum mode
GLbitfield GLuint64 timeout
GLenum GLsizei len
GLuint GLint GLboolean GLint GLenum access
GLfloat GLfloat GLfloat GLfloat h
GLubyte GLubyte GLubyte GLubyte w
@ SDL_PIXELFORMAT_ARGB8888
Definition: SDL_pixels.h:257
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
uint32_t Uint32
Definition: SDL_stdinc.h:209
void * SDL_GetDisplayDriverData(int displayIndex)
Definition: SDL_video.c:680
VideoBootStrap KMSDRM_LEGACY_bootstrap
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event)
Definition: SDL_video.c:607
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:792
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1130
#define SDL_MINOR_VERSION
Definition: SDL_version.h:61
#define SDL_MAJOR_VERSION
Definition: SDL_version.h:60
static SDL_VideoDevice * _this
Definition: SDL_video.c:126
@ SDL_WINDOW_OPENGL
Definition: SDL_video.h:100
@ SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:99
@ SDL_WINDOWEVENT_RESIZED
Definition: SDL_video.h:155
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
#define EGL_NO_CONTEXT
Definition: egl.h:98
void * EGLContext
Definition: egl.h:60
#define EGL_NO_SURFACE
Definition: egl.h:100
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
EGLNativeWindowType NativeWindowType
Definition: eglplatform.h:112
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
#define SDL_VIDEO_OPENGL_EGL
Definition: SDL_config.h:401
static SDL_AudioDeviceID device
Definition: loopwave.c:37
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld cleanup[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head if pixblock_size cache_preload_simple endif process_pixblock_tail pixinterleave dst_w_basereg irp if pixblock_size chunk_size tst beq if DST_W else pixst DST_W else mov ORIG_W endif add lsl if lsl endif if lsl endif lsl endif lsl endif lsl endif subs mov DST_W if regs_shortage str endif bge start_of_loop_label endm macro generate_composite_function
drmModeModeInfo mode
drmModeConnector * conn
The structure that defines a display mode.
Definition: SDL_video.h:54
Uint32 format
Definition: SDL_video.h:55
A collection of pixels used in software blitting.
Definition: SDL_surface.h:71
SDL_version version
Definition: SDL_syswm.h:218
unsigned int max_windows
SDL_Window ** windows
unsigned int num_windows
struct gbm_device * gbm
struct SDL_VideoDevice::@440 gl_config
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:132
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:133
EGLSurface egl_surface
struct gbm_bo * next_bo
struct gbm_bo * curr_bo
SDL_VideoData * viddata
struct gbm_surface * gs
The type used to identify a window.
Definition: SDL_sysvideo.h:75
Uint8 major
Definition: SDL_version.h:53
int frame
Definition: teststreaming.c:60