platform_wayland.c revision b1a91722773152ea96de79d2b446ae488561bb0c
1/* 2 * Copyright © 2011 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Kristian Høgsberg <krh@bitplanet.net> 26 * Benjamin Franzke <benjaminfranzke@googlemail.com> 27 */ 28 29#include <stdlib.h> 30#include <string.h> 31#include <limits.h> 32#include <dlfcn.h> 33#include <errno.h> 34#include <unistd.h> 35#include <fcntl.h> 36#include <xf86drm.h> 37 38#include "egl_dri2.h" 39 40#include <wayland-client.h> 41#include "wayland-drm-client-protocol.h" 42 43static void 44sync_callback(void *data) 45{ 46 int *done = data; 47 48 *done = 1; 49} 50 51static void 52force_roundtrip(struct wl_display *display) 53{ 54 int done = 0; 55 56 wl_display_sync_callback(display, sync_callback, &done); 57 wl_display_iterate(display, WL_DISPLAY_WRITABLE); 58 while (!done) 59 wl_display_iterate(display, WL_DISPLAY_READABLE); 60} 61 62 63/** 64 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 65 */ 66static _EGLSurface * 67dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, 68 _EGLConfig *conf, EGLNativeWindowType window, 69 const EGLint *attrib_list) 70{ 71 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 72 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 73 struct dri2_egl_surface *dri2_surf; 74 struct dri2_egl_buffer *dri2_buf; 75 int i; 76 77 (void) drv; 78 79 dri2_surf = malloc(sizeof *dri2_surf); 80 if (!dri2_surf) { 81 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 82 return NULL; 83 } 84 85 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) 86 goto cleanup_surf; 87 88 for (i = 0; i < WL_BUFFER_COUNT; ++i) 89 dri2_surf->wl_drm_buffer[i] = NULL; 90 91 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) 92 dri2_surf->dri_buffers[i] = NULL; 93 94 dri2_surf->pending_buffer = NULL; 95 dri2_surf->block_swap_buffers = EGL_FALSE; 96 97 switch (type) { 98 case EGL_WINDOW_BIT: 99 dri2_surf->wl_win = (struct wl_egl_window *) window; 100 dri2_surf->type = DRI2_WINDOW_SURFACE; 101 102 dri2_surf->base.Width = -1; 103 dri2_surf->base.Height = -1; 104 break; 105 case EGL_PIXMAP_BIT: 106 dri2_surf->wl_pix = (struct wl_egl_pixmap *) window; 107 dri2_surf->type = DRI2_PIXMAP_SURFACE; 108 109 dri2_surf->base.Width = dri2_surf->wl_pix->width; 110 dri2_surf->base.Height = dri2_surf->wl_pix->height; 111 112 if (dri2_surf->wl_pix->driver_private) { 113 dri2_buf = dri2_surf->wl_pix->driver_private; 114 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = dri2_buf->dri_buffer; 115 } 116 break; 117 default: 118 goto cleanup_surf; 119 } 120 121 dri2_surf->dri_drawable = 122 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, 123 type == EGL_WINDOW_BIT ? 124 dri2_conf->dri_double_config : 125 dri2_conf->dri_single_config, 126 dri2_surf); 127 if (dri2_surf->dri_drawable == NULL) { 128 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); 129 goto cleanup_dri_drawable; 130 } 131 132 return &dri2_surf->base; 133 134 cleanup_dri_drawable: 135 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 136 cleanup_surf: 137 free(dri2_surf); 138 139 return NULL; 140} 141 142/** 143 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 144 */ 145static _EGLSurface * 146dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, 147 _EGLConfig *conf, EGLNativeWindowType window, 148 const EGLint *attrib_list) 149{ 150 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf, 151 window, attrib_list); 152} 153 154static _EGLSurface * 155dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, 156 _EGLConfig *conf, EGLNativePixmapType pixmap, 157 const EGLint *attrib_list) 158{ 159 return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf, 160 pixmap, attrib_list); 161} 162 163/** 164 * Called via eglDestroySurface(), drv->API.DestroySurface(). 165 */ 166static EGLBoolean 167dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) 168{ 169 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 170 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 171 int i; 172 173 (void) drv; 174 175 if (!_eglPutSurface(surf)) 176 return EGL_TRUE; 177 178 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); 179 180 for (i = 0; i < WL_BUFFER_COUNT; ++i) 181 if (dri2_surf->wl_drm_buffer[i]) 182 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]); 183 184 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) 185 if (dri2_surf->dri_buffers[i] && !(i == __DRI_BUFFER_FRONT_LEFT && 186 dri2_surf->type == DRI2_PIXMAP_SURFACE)) 187 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 188 dri2_surf->dri_buffers[i]); 189 190 free(surf); 191 192 return EGL_TRUE; 193} 194 195static void 196dri2_wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap) 197{ 198 struct dri2_egl_buffer *dri2_buf = egl_pixmap->driver_private; 199 200 assert(dri2_buf); 201 202 dri2_buf->dri2_dpy->dri2->releaseBuffer(dri2_buf->dri2_dpy->dri_screen, 203 dri2_buf->dri_buffer); 204 205 free(dri2_buf); 206 207 egl_pixmap->driver_private = NULL; 208 egl_pixmap->destroy = NULL; 209} 210 211static struct wl_buffer * 212wayland_create_buffer(struct dri2_egl_surface *dri2_surf, 213 __DRIbuffer *buffer, 214 struct wl_visual *visual) 215{ 216 struct dri2_egl_display *dri2_dpy = 217 dri2_egl_display(dri2_surf->base.Resource.Display); 218 219 return wl_drm_create_buffer(dri2_dpy->wl_drm, buffer->name, 220 dri2_surf->base.Width, dri2_surf->base.Height, 221 buffer->pitch, visual); 222} 223 224static void 225dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format) 226{ 227 struct dri2_egl_display *dri2_dpy = 228 dri2_egl_display(dri2_surf->base.Resource.Display); 229 230 (void) format; 231 232 switch (dri2_surf->type) { 233 case DRI2_WINDOW_SURFACE: 234 /* allocate a front buffer for our double-buffered window*/ 235 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = 236 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 237 __DRI_BUFFER_FRONT_LEFT, format, 238 dri2_surf->base.Width, dri2_surf->base.Height); 239 break; 240 default: 241 break; 242 } 243} 244 245static void 246dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format) 247{ 248 struct dri2_egl_display *dri2_dpy = 249 dri2_egl_display(dri2_surf->base.Resource.Display); 250 struct dri2_egl_buffer *dri2_buf; 251 252 switch (dri2_surf->type) { 253 case DRI2_PIXMAP_SURFACE: 254 dri2_buf = malloc(sizeof *dri2_buf); 255 if (!dri2_buf) 256 return; 257 258 dri2_buf->dri_buffer = dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]; 259 dri2_buf->dri2_dpy = dri2_dpy; 260 261 dri2_surf->wl_pix->driver_private = dri2_buf; 262 dri2_surf->wl_pix->destroy = dri2_wl_egl_pixmap_destroy; 263 break; 264 default: 265 break; 266 } 267} 268 269static void 270dri2_release_pending_buffer(void *data) 271{ 272 struct dri2_egl_surface *dri2_surf = data; 273 struct dri2_egl_display *dri2_dpy = 274 dri2_egl_display(dri2_surf->base.Resource.Display); 275 276 /* FIXME: print internal error */ 277 if (!dri2_surf->pending_buffer) 278 return; 279 280 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 281 dri2_surf->pending_buffer); 282 dri2_surf->pending_buffer = NULL; 283} 284 285static void 286dri2_release_buffers(struct dri2_egl_surface *dri2_surf) 287{ 288 struct dri2_egl_display *dri2_dpy = 289 dri2_egl_display(dri2_surf->base.Resource.Display); 290 int i; 291 292 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) { 293 if (dri2_surf->dri_buffers[i]) { 294 switch (i) { 295 case __DRI_BUFFER_FRONT_LEFT: 296 if (dri2_surf->pending_buffer) 297 force_roundtrip(dri2_dpy->wl_dpy); 298 dri2_surf->pending_buffer = dri2_surf->dri_buffers[i]; 299 wl_display_sync_callback(dri2_dpy->wl_dpy, 300 dri2_release_pending_buffer, dri2_surf); 301 break; 302 default: 303 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 304 dri2_surf->dri_buffers[i]); 305 break; 306 } 307 dri2_surf->dri_buffers[i] = NULL; 308 } 309 } 310} 311 312static __DRIbuffer * 313dri2_get_buffers_with_format(__DRIdrawable * driDrawable, 314 int *width, int *height, 315 unsigned int *attachments, int count, 316 int *out_count, void *loaderPrivate) 317{ 318 struct dri2_egl_surface *dri2_surf = loaderPrivate; 319 struct dri2_egl_display *dri2_dpy = 320 dri2_egl_display(dri2_surf->base.Resource.Display); 321 int i; 322 323 if (dri2_surf->type == DRI2_WINDOW_SURFACE && 324 (dri2_surf->base.Width != dri2_surf->wl_win->width || 325 dri2_surf->base.Height != dri2_surf->wl_win->height)) { 326 327 dri2_release_buffers(dri2_surf); 328 329 dri2_surf->base.Width = dri2_surf->wl_win->width; 330 dri2_surf->base.Height = dri2_surf->wl_win->height; 331 dri2_surf->dx = dri2_surf->wl_win->dx; 332 dri2_surf->dy = dri2_surf->wl_win->dy; 333 334 for (i = 0; i < WL_BUFFER_COUNT; ++i) { 335 if (dri2_surf->wl_drm_buffer[i]) 336 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]); 337 dri2_surf->wl_drm_buffer[i] = NULL; 338 } 339 } 340 341 dri2_surf->buffer_count = 0; 342 for (i = 0; i < 2*count; i+=2) { 343 assert(attachments[i] < __DRI_BUFFER_COUNT); 344 assert(dri2_surf->buffer_count < 5); 345 346 if (dri2_surf->dri_buffers[attachments[i]] == NULL) { 347 348 dri2_surf->dri_buffers[attachments[i]] = 349 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 350 attachments[i], attachments[i+1], 351 dri2_surf->base.Width, dri2_surf->base.Height); 352 353 if (!dri2_surf->dri_buffers[attachments[i]]) 354 continue; 355 356 if (attachments[i] == __DRI_BUFFER_FRONT_LEFT) 357 dri2_process_front_buffer(dri2_surf, attachments[i+1]); 358 else if (attachments[i] == __DRI_BUFFER_BACK_LEFT) 359 dri2_process_back_buffer(dri2_surf, attachments[i+1]); 360 } 361 362 memcpy(&dri2_surf->buffers[dri2_surf->buffer_count], 363 dri2_surf->dri_buffers[attachments[i]], 364 sizeof(__DRIbuffer)); 365 366 dri2_surf->buffer_count++; 367 } 368 369 assert(dri2_surf->type == DRI2_PIXMAP_SURFACE || 370 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); 371 372 if (dri2_surf->type == DRI2_PIXMAP_SURFACE && !dri2_surf->wl_pix->buffer) 373 dri2_surf->wl_pix->buffer = 374 wayland_create_buffer(dri2_surf, 375 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], 376 dri2_surf->wl_pix->visual); 377 378 *out_count = dri2_surf->buffer_count; 379 if (dri2_surf->buffer_count == 0) 380 return NULL; 381 382 *width = dri2_surf->base.Width; 383 *height = dri2_surf->base.Height; 384 385 return dri2_surf->buffers; 386} 387 388static __DRIbuffer * 389dri2_get_buffers(__DRIdrawable * driDrawable, 390 int *width, int *height, 391 unsigned int *attachments, int count, 392 int *out_count, void *loaderPrivate) 393{ 394 unsigned int *attachments_with_format; 395 __DRIbuffer *buffer; 396 const unsigned int format = 32; 397 int i; 398 399 attachments_with_format = calloc(count * 2, sizeof(unsigned int)); 400 if (!attachments_with_format) { 401 *out_count = 0; 402 return NULL; 403 } 404 405 for (i = 0; i < count; ++i) { 406 attachments_with_format[2*i] = attachments[i]; 407 attachments_with_format[2*i + 1] = format; 408 } 409 410 buffer = 411 dri2_get_buffers_with_format(driDrawable, 412 width, height, 413 attachments_with_format, count, 414 out_count, loaderPrivate); 415 416 free(attachments_with_format); 417 418 return buffer; 419} 420 421 422static void 423dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 424{ 425 (void) driDrawable; 426 427 /* FIXME: Does EGL support front buffer rendering at all? */ 428 429#if 0 430 struct dri2_egl_surface *dri2_surf = loaderPrivate; 431 432 dri2WaitGL(dri2_surf); 433#else 434 (void) loaderPrivate; 435#endif 436} 437 438static void 439wayland_frame_callback(struct wl_surface *surface, void *data, uint32_t time) 440{ 441 struct dri2_egl_surface *dri2_surf = data; 442 443 dri2_surf->block_swap_buffers = EGL_FALSE; 444} 445 446static inline void 447pointer_swap(const void **p1, const void **p2) 448{ 449 const void *tmp = *p1; 450 *p1 = *p2; 451 *p2 = tmp; 452} 453 454/** 455 * Called via eglSwapBuffers(), drv->API.SwapBuffers(). 456 */ 457static EGLBoolean 458dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 459{ 460 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 461 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 462 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); 463 464 while (dri2_surf->block_swap_buffers) 465 wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE); 466 467 dri2_surf->block_swap_buffers = EGL_TRUE; 468 wl_display_frame_callback(dri2_dpy->wl_dpy, 469 dri2_surf->wl_win->surface, 470 wayland_frame_callback, dri2_surf); 471 472 if (dri2_surf->type == DRI2_WINDOW_SURFACE) { 473 pointer_swap( 474 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], 475 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); 476 477 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment = 478 __DRI_BUFFER_FRONT_LEFT; 479 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = 480 __DRI_BUFFER_BACK_LEFT; 481 482 pointer_swap((const void **) &dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 483 (const void **) &dri2_surf->wl_drm_buffer[WL_BUFFER_BACK]); 484 485 if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT]) 486 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] = 487 wayland_create_buffer(dri2_surf, 488 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], 489 dri2_surf->wl_win->visual); 490 491 wl_buffer_damage(dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 0, 0, 492 dri2_surf->base.Width, dri2_surf->base.Height); 493 wl_surface_attach(dri2_surf->wl_win->surface, 494 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 495 dri2_surf->dx, dri2_surf->dy); 496 497 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 498 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 499 /* reset resize growing parameters */ 500 dri2_surf->dx = 0; 501 dri2_surf->dy = 0; 502 503 wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, 504 dri2_surf->base.Width, dri2_surf->base.Height); 505 } 506 507 _EGLContext *ctx; 508 if (dri2_drv->glFlush) { 509 ctx = _eglGetCurrentContext(); 510 if (ctx && ctx->DrawSurface == &dri2_surf->base) 511 dri2_drv->glFlush(); 512 } 513 514 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); 515 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); 516 517 return EGL_TRUE; 518} 519 520/** 521 * Called via eglCreateImageKHR(), drv->API.CreateImageKHR(). 522 */ 523static _EGLImage * 524dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, 525 EGLClientBuffer buffer, const EGLint *attr_list) 526{ 527 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 528 struct wl_egl_pixmap *wl_egl_pixmap = (struct wl_egl_pixmap *) buffer; 529 struct dri2_egl_buffer *dri2_buf; 530 EGLint wl_attr_list[] = { 531 EGL_WIDTH, 0, 532 EGL_HEIGHT, 0, 533 EGL_DRM_BUFFER_STRIDE_MESA, 0, 534 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, 535 EGL_NONE 536 }; 537 538 dri2_buf = malloc(sizeof *dri2_buf); 539 if (!dri2_buf) 540 return NULL; 541 542 dri2_buf->dri2_dpy = dri2_dpy; 543 dri2_buf->dri_buffer = 544 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 545 __DRI_BUFFER_FRONT_LEFT, 32, 546 wl_egl_pixmap->width, 547 wl_egl_pixmap->height); 548 549 wl_egl_pixmap->destroy = dri2_wl_egl_pixmap_destroy; 550 wl_egl_pixmap->driver_private = dri2_buf; 551 552 wl_egl_pixmap->buffer = 553 wl_drm_create_buffer(dri2_dpy->wl_drm, 554 dri2_buf->dri_buffer->name, 555 wl_egl_pixmap->width, 556 wl_egl_pixmap->height, 557 dri2_buf->dri_buffer->pitch, 558 wl_egl_pixmap->visual); 559 560 wl_attr_list[1] = wl_egl_pixmap->width; 561 wl_attr_list[3] = wl_egl_pixmap->height; 562 wl_attr_list[5] = dri2_buf->dri_buffer->pitch / 4; 563 564 return dri2_create_image_khr(disp->Driver, disp, ctx, EGL_DRM_BUFFER_MESA, 565 (EGLClientBuffer)(intptr_t) dri2_buf->dri_buffer->name, wl_attr_list); 566} 567 568static _EGLImage * 569dri2_wayland_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, 570 _EGLContext *ctx, EGLenum target, 571 EGLClientBuffer buffer, const EGLint *attr_list) 572{ 573 (void) drv; 574 575 switch (target) { 576 case EGL_NATIVE_PIXMAP_KHR: 577 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list); 578 default: 579 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); 580 } 581} 582 583static int 584dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id) 585{ 586 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 587 int ret = 0; 588 589 dri2_dpy->authenticated = false; 590 591 wl_drm_authenticate(dri2_dpy->wl_drm, id); 592 force_roundtrip(dri2_dpy->wl_dpy); 593 594 if (!dri2_dpy->authenticated) 595 ret = -1; 596 597 /* reset authenticated */ 598 dri2_dpy->authenticated = true; 599 600 return ret; 601} 602 603/** 604 * Called via eglTerminate(), drv->API.Terminate(). 605 */ 606static EGLBoolean 607dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) 608{ 609 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 610 611 _eglReleaseDisplayResources(drv, disp); 612 _eglCleanupDisplay(disp); 613 614 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 615 close(dri2_dpy->fd); 616 dlclose(dri2_dpy->driver); 617 free(dri2_dpy->driver_name); 618 free(dri2_dpy); 619 disp->DriverData = NULL; 620 621 return EGL_TRUE; 622} 623 624static void 625drm_handle_device(void *data, struct wl_drm *drm, const char *device) 626{ 627 struct dri2_egl_display *dri2_dpy = data; 628 drm_magic_t magic; 629 630 dri2_dpy->device_name = strdup(device); 631 if (!dri2_dpy->device_name) 632 return; 633 634 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR); 635 if (dri2_dpy->fd == -1) { 636 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", 637 dri2_dpy->device_name, strerror(errno)); 638 return; 639 } 640 641 drmGetMagic(dri2_dpy->fd, &magic); 642 wl_drm_authenticate(dri2_dpy->wl_drm, magic); 643} 644 645static void 646drm_handle_authenticated(void *data, struct wl_drm *drm) 647{ 648 struct dri2_egl_display *dri2_dpy = data; 649 650 dri2_dpy->authenticated = true; 651} 652 653static const struct wl_drm_listener drm_listener = { 654 drm_handle_device, 655 drm_handle_authenticated 656}; 657 658EGLBoolean 659dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 660{ 661 struct dri2_egl_display *dri2_dpy; 662 uint32_t id; 663 int i; 664 665 drv->API.CreateWindowSurface = dri2_create_window_surface; 666 drv->API.CreatePixmapSurface = dri2_create_pixmap_surface; 667 drv->API.DestroySurface = dri2_destroy_surface; 668 drv->API.SwapBuffers = dri2_swap_buffers; 669 drv->API.CreateImageKHR = dri2_wayland_create_image_khr; 670 drv->API.Terminate = dri2_terminate; 671 672 dri2_dpy = malloc(sizeof *dri2_dpy); 673 if (!dri2_dpy) 674 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 675 676 memset(dri2_dpy, 0, sizeof *dri2_dpy); 677 678 disp->DriverData = (void *) dri2_dpy; 679 dri2_dpy->wl_dpy = disp->PlatformDisplay; 680 681 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1); 682 if (id == 0) 683 wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE); 684 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1); 685 if (id == 0) 686 goto cleanup_dpy; 687 dri2_dpy->wl_drm = wl_drm_create(dri2_dpy->wl_dpy, id, 1); 688 if (!dri2_dpy->wl_drm) 689 goto cleanup_dpy; 690 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); 691 force_roundtrip(dri2_dpy->wl_dpy); 692 if (dri2_dpy->fd == -1) 693 goto cleanup_drm; 694 695 force_roundtrip(dri2_dpy->wl_dpy); 696 if (!dri2_dpy->authenticated) 697 goto cleanup_fd; 698 699 dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd); 700 if (dri2_dpy->driver_name == NULL) { 701 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); 702 goto cleanup_fd; 703 } 704 705 if (!dri2_load_driver(disp)) 706 goto cleanup_driver_name; 707 708 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; 709 dri2_dpy->dri2_loader_extension.base.version = 3; 710 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; 711 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; 712 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = 713 dri2_get_buffers_with_format; 714 715 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; 716 dri2_dpy->extensions[1] = &image_lookup_extension.base; 717 dri2_dpy->extensions[2] = NULL; 718 719 if (!dri2_create_screen(disp)) 720 goto cleanup_driver; 721 722 for (i = 0; dri2_dpy->driver_configs[i]; i++) 723 dri2_add_config(disp, dri2_dpy->driver_configs[i], i + 1, 0, 724 EGL_WINDOW_BIT | EGL_PIXMAP_BIT, NULL); 725 726 727 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 728 729 disp->Extensions.WL_bind_wayland_display = EGL_TRUE; 730 dri2_dpy->authenticate = dri2_wayland_authenticate; 731 732 /* we're supporting EGL 1.4 */ 733 disp->VersionMajor = 1; 734 disp->VersionMinor = 4; 735 736 return EGL_TRUE; 737 738 cleanup_driver: 739 dlclose(dri2_dpy->driver); 740 cleanup_driver_name: 741 free(dri2_dpy->driver_name); 742 cleanup_fd: 743 close(dri2_dpy->fd); 744 cleanup_drm: 745 free(dri2_dpy->device_name); 746 wl_drm_destroy(dri2_dpy->wl_drm); 747 cleanup_dpy: 748 free(dri2_dpy); 749 750 return EGL_FALSE; 751} 752