platform_wayland.c revision 2332bc26d435e465a6f6571ab267db2a33ce05d2
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 43enum wl_drm_format_flags { 44 HAS_ARGB8888 = 1, 45 HAS_XRGB8888 = 2 46}; 47 48static void 49sync_callback(void *data, struct wl_callback *callback, uint32_t serial) 50{ 51 int *done = data; 52 53 *done = 1; 54 wl_callback_destroy(callback); 55} 56 57static const struct wl_callback_listener sync_listener = { 58 sync_callback 59}; 60 61static int 62roundtrip(struct dri2_egl_display *dri2_dpy) 63{ 64 struct wl_callback *callback; 65 int done = 0, ret = 0; 66 67 callback = wl_display_sync(dri2_dpy->wl_dpy); 68 wl_callback_add_listener(callback, &sync_listener, &done); 69 wl_proxy_set_queue((struct wl_proxy *) callback, dri2_dpy->wl_queue); 70 while (ret != -1 && !done) 71 ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); 72 73 return ret; 74} 75 76static void 77wl_buffer_release(void *data, struct wl_buffer *buffer) 78{ 79 struct dri2_egl_surface *dri2_surf = data; 80 int i; 81 82 for (i = 0; i < WL_BUFFER_COUNT; ++i) 83 if (dri2_surf->wl_drm_buffer[i] == buffer) 84 break; 85 86 assert(i <= WL_BUFFER_COUNT); 87 88 /* not found? */ 89 if (i == WL_BUFFER_COUNT) 90 return; 91 92 dri2_surf->wl_buffer_lock[i] = 0; 93 94} 95 96static struct wl_buffer_listener wl_buffer_listener = { 97 wl_buffer_release 98}; 99 100/** 101 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 102 */ 103static _EGLSurface * 104dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, 105 _EGLConfig *conf, EGLNativeWindowType window, 106 const EGLint *attrib_list) 107{ 108 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 109 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 110 struct dri2_egl_surface *dri2_surf; 111 int i; 112 113 (void) drv; 114 115 dri2_surf = malloc(sizeof *dri2_surf); 116 if (!dri2_surf) { 117 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 118 return NULL; 119 } 120 121 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) 122 goto cleanup_surf; 123 124 for (i = 0; i < WL_BUFFER_COUNT; ++i) { 125 dri2_surf->wl_drm_buffer[i] = NULL; 126 dri2_surf->wl_buffer_lock[i] = 0; 127 } 128 129 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) 130 dri2_surf->dri_buffers[i] = NULL; 131 132 dri2_surf->pending_buffer = NULL; 133 dri2_surf->third_buffer = NULL; 134 dri2_surf->frame_callback = NULL; 135 136 if (conf->AlphaSize == 0) 137 dri2_surf->format = WL_DRM_FORMAT_XRGB8888; 138 else 139 dri2_surf->format = WL_DRM_FORMAT_ARGB8888; 140 141 switch (type) { 142 case EGL_WINDOW_BIT: 143 dri2_surf->wl_win = (struct wl_egl_window *) window; 144 145 dri2_surf->base.Width = -1; 146 dri2_surf->base.Height = -1; 147 break; 148 default: 149 goto cleanup_surf; 150 } 151 152 dri2_surf->dri_drawable = 153 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, 154 type == EGL_WINDOW_BIT ? 155 dri2_conf->dri_double_config : 156 dri2_conf->dri_single_config, 157 dri2_surf); 158 if (dri2_surf->dri_drawable == NULL) { 159 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); 160 goto cleanup_dri_drawable; 161 } 162 163 return &dri2_surf->base; 164 165 cleanup_dri_drawable: 166 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 167 cleanup_surf: 168 free(dri2_surf); 169 170 return NULL; 171} 172 173/** 174 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 175 */ 176static _EGLSurface * 177dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, 178 _EGLConfig *conf, EGLNativeWindowType window, 179 const EGLint *attrib_list) 180{ 181 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf, 182 window, attrib_list); 183} 184 185/** 186 * Called via eglDestroySurface(), drv->API.DestroySurface(). 187 */ 188static EGLBoolean 189dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) 190{ 191 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 192 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 193 int i; 194 195 (void) drv; 196 197 if (!_eglPutSurface(surf)) 198 return EGL_TRUE; 199 200 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); 201 202 for (i = 0; i < WL_BUFFER_COUNT; ++i) 203 if (dri2_surf->wl_drm_buffer[i]) 204 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]); 205 206 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) 207 if (dri2_surf->dri_buffers[i]) 208 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 209 dri2_surf->dri_buffers[i]); 210 211 if (dri2_surf->third_buffer) { 212 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 213 dri2_surf->third_buffer); 214 } 215 216 if (dri2_surf->frame_callback) 217 wl_callback_destroy(dri2_surf->frame_callback); 218 219 free(surf); 220 221 return EGL_TRUE; 222} 223 224static struct wl_buffer * 225wayland_create_buffer(struct dri2_egl_surface *dri2_surf, 226 __DRIbuffer *buffer) 227{ 228 struct dri2_egl_display *dri2_dpy = 229 dri2_egl_display(dri2_surf->base.Resource.Display); 230 struct wl_buffer *buf; 231 232 buf = wl_drm_create_buffer(dri2_dpy->wl_drm, buffer->name, 233 dri2_surf->base.Width, dri2_surf->base.Height, 234 buffer->pitch, dri2_surf->format); 235 wl_buffer_add_listener(buf, &wl_buffer_listener, dri2_surf); 236 237 return buf; 238} 239 240static void 241dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format) 242{ 243 struct dri2_egl_display *dri2_dpy = 244 dri2_egl_display(dri2_surf->base.Resource.Display); 245 246 (void) format; 247 248 switch (dri2_surf->base.Type) { 249 case EGL_WINDOW_BIT: 250 /* allocate a front buffer for our double-buffered window*/ 251 if (dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] != NULL) 252 break; 253 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = 254 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 255 __DRI_BUFFER_FRONT_LEFT, format, 256 dri2_surf->base.Width, dri2_surf->base.Height); 257 break; 258 default: 259 break; 260 } 261} 262 263static void 264dri2_release_pending_buffer(void *data, 265 struct wl_callback *callback, uint32_t time) 266{ 267 struct dri2_egl_surface *dri2_surf = data; 268 struct dri2_egl_display *dri2_dpy = 269 dri2_egl_display(dri2_surf->base.Resource.Display); 270 271 /* FIXME: print internal error */ 272 if (!dri2_surf->pending_buffer) 273 return; 274 275 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 276 dri2_surf->pending_buffer); 277 dri2_surf->pending_buffer = NULL; 278 279 wl_callback_destroy(callback); 280} 281 282static const struct wl_callback_listener release_buffer_listener = { 283 dri2_release_pending_buffer 284}; 285 286static void 287dri2_release_buffers(struct dri2_egl_surface *dri2_surf) 288{ 289 struct dri2_egl_display *dri2_dpy = 290 dri2_egl_display(dri2_surf->base.Resource.Display); 291 struct wl_callback *callback; 292 int i; 293 294 if (dri2_surf->third_buffer) { 295 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 296 dri2_surf->third_buffer); 297 dri2_surf->third_buffer = NULL; 298 } 299 300 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) { 301 if (dri2_surf->dri_buffers[i]) { 302 switch (i) { 303 case __DRI_BUFFER_FRONT_LEFT: 304 if (dri2_surf->pending_buffer) 305 roundtrip(dri2_dpy); 306 dri2_surf->pending_buffer = dri2_surf->dri_buffers[i]; 307 callback = wl_display_sync(dri2_dpy->wl_dpy); 308 wl_callback_add_listener(callback, 309 &release_buffer_listener, dri2_surf); 310 wl_proxy_set_queue((struct wl_proxy *) callback, 311 dri2_dpy->wl_queue); 312 break; 313 default: 314 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 315 dri2_surf->dri_buffers[i]); 316 break; 317 } 318 dri2_surf->dri_buffers[i] = NULL; 319 } 320 } 321} 322 323static inline void 324pointer_swap(const void **p1, const void **p2) 325{ 326 const void *tmp = *p1; 327 *p1 = *p2; 328 *p2 = tmp; 329} 330 331static void 332destroy_third_buffer(struct dri2_egl_surface *dri2_surf) 333{ 334 struct dri2_egl_display *dri2_dpy = 335 dri2_egl_display(dri2_surf->base.Resource.Display); 336 337 if (dri2_surf->third_buffer == NULL) 338 return; 339 340 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 341 dri2_surf->third_buffer); 342 dri2_surf->third_buffer = NULL; 343 344 if (dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD]) 345 wl_buffer_destroy(dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD]); 346 dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD] = NULL; 347 dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD] = 0; 348} 349 350static void 351swap_wl_buffers(struct dri2_egl_surface *dri2_surf, 352 enum wayland_buffer_type a, enum wayland_buffer_type b) 353{ 354 int tmp; 355 356 tmp = dri2_surf->wl_buffer_lock[a]; 357 dri2_surf->wl_buffer_lock[a] = dri2_surf->wl_buffer_lock[b]; 358 dri2_surf->wl_buffer_lock[b] = tmp; 359 360 pointer_swap((const void **) &dri2_surf->wl_drm_buffer[a], 361 (const void **) &dri2_surf->wl_drm_buffer[b]); 362} 363 364static void 365swap_back_and_third(struct dri2_egl_surface *dri2_surf) 366{ 367 if (dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD]) 368 destroy_third_buffer(dri2_surf); 369 370 pointer_swap((const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT], 371 (const void **) &dri2_surf->third_buffer); 372 373 swap_wl_buffers(dri2_surf, WL_BUFFER_BACK, WL_BUFFER_THIRD); 374} 375 376static void 377dri2_prior_buffer_creation(struct dri2_egl_surface *dri2_surf, 378 unsigned int type) 379{ 380 switch (type) { 381 case __DRI_BUFFER_BACK_LEFT: 382 if (dri2_surf->wl_buffer_lock[WL_BUFFER_BACK]) 383 swap_back_and_third(dri2_surf); 384 else if (dri2_surf->third_buffer) 385 destroy_third_buffer(dri2_surf); 386 break; 387 default: 388 break; 389 390 } 391} 392 393static __DRIbuffer * 394dri2_get_buffers_with_format(__DRIdrawable * driDrawable, 395 int *width, int *height, 396 unsigned int *attachments, int count, 397 int *out_count, void *loaderPrivate) 398{ 399 struct dri2_egl_surface *dri2_surf = loaderPrivate; 400 struct dri2_egl_display *dri2_dpy = 401 dri2_egl_display(dri2_surf->base.Resource.Display); 402 int i; 403 404 if (dri2_surf->base.Type == EGL_WINDOW_BIT && 405 (dri2_surf->base.Width != dri2_surf->wl_win->width || 406 dri2_surf->base.Height != dri2_surf->wl_win->height)) { 407 408 dri2_release_buffers(dri2_surf); 409 410 dri2_surf->base.Width = dri2_surf->wl_win->width; 411 dri2_surf->base.Height = dri2_surf->wl_win->height; 412 dri2_surf->dx = dri2_surf->wl_win->dx; 413 dri2_surf->dy = dri2_surf->wl_win->dy; 414 415 for (i = 0; i < WL_BUFFER_COUNT; ++i) { 416 if (dri2_surf->wl_drm_buffer[i]) 417 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]); 418 dri2_surf->wl_drm_buffer[i] = NULL; 419 dri2_surf->wl_buffer_lock[i] = 0; 420 } 421 } 422 423 dri2_surf->buffer_count = 0; 424 for (i = 0; i < 2*count; i+=2) { 425 assert(attachments[i] < __DRI_BUFFER_COUNT); 426 assert(dri2_surf->buffer_count < 5); 427 428 dri2_prior_buffer_creation(dri2_surf, attachments[i]); 429 430 if (dri2_surf->dri_buffers[attachments[i]] == NULL) { 431 432 dri2_surf->dri_buffers[attachments[i]] = 433 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 434 attachments[i], attachments[i+1], 435 dri2_surf->base.Width, dri2_surf->base.Height); 436 437 if (!dri2_surf->dri_buffers[attachments[i]]) 438 continue; 439 440 if (attachments[i] == __DRI_BUFFER_BACK_LEFT) 441 dri2_process_back_buffer(dri2_surf, attachments[i+1]); 442 } 443 444 memcpy(&dri2_surf->buffers[dri2_surf->buffer_count], 445 dri2_surf->dri_buffers[attachments[i]], 446 sizeof(__DRIbuffer)); 447 448 dri2_surf->buffer_count++; 449 } 450 451 assert(dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); 452 453 *out_count = dri2_surf->buffer_count; 454 if (dri2_surf->buffer_count == 0) 455 return NULL; 456 457 *width = dri2_surf->base.Width; 458 *height = dri2_surf->base.Height; 459 460 return dri2_surf->buffers; 461} 462 463static __DRIbuffer * 464dri2_get_buffers(__DRIdrawable * driDrawable, 465 int *width, int *height, 466 unsigned int *attachments, int count, 467 int *out_count, void *loaderPrivate) 468{ 469 unsigned int *attachments_with_format; 470 __DRIbuffer *buffer; 471 const unsigned int format = 32; 472 int i; 473 474 attachments_with_format = calloc(count * 2, sizeof(unsigned int)); 475 if (!attachments_with_format) { 476 *out_count = 0; 477 return NULL; 478 } 479 480 for (i = 0; i < count; ++i) { 481 attachments_with_format[2*i] = attachments[i]; 482 attachments_with_format[2*i + 1] = format; 483 } 484 485 buffer = 486 dri2_get_buffers_with_format(driDrawable, 487 width, height, 488 attachments_with_format, count, 489 out_count, loaderPrivate); 490 491 free(attachments_with_format); 492 493 return buffer; 494} 495 496 497static void 498dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 499{ 500 (void) driDrawable; 501 502 /* FIXME: Does EGL support front buffer rendering at all? */ 503 504#if 0 505 struct dri2_egl_surface *dri2_surf = loaderPrivate; 506 507 dri2WaitGL(dri2_surf); 508#else 509 (void) loaderPrivate; 510#endif 511} 512 513static void 514wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time) 515{ 516 struct dri2_egl_surface *dri2_surf = data; 517 518 dri2_surf->frame_callback = NULL; 519 wl_callback_destroy(callback); 520} 521 522static const struct wl_callback_listener frame_listener = { 523 wayland_frame_callback 524}; 525 526/** 527 * Called via eglSwapBuffers(), drv->API.SwapBuffers(). 528 */ 529static EGLBoolean 530dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 531{ 532 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 533 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 534 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); 535 int ret = 0; 536 537 while (dri2_surf->frame_callback && ret != -1) 538 ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); 539 if (ret < 0) 540 return EGL_FALSE; 541 542 dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface); 543 wl_callback_add_listener(dri2_surf->frame_callback, 544 &frame_listener, dri2_surf); 545 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback, 546 dri2_dpy->wl_queue); 547 548 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 549 pointer_swap( 550 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], 551 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); 552 553 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment = 554 __DRI_BUFFER_FRONT_LEFT; 555 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = 556 __DRI_BUFFER_BACK_LEFT; 557 558 swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK); 559 560 if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT]) 561 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] = 562 wayland_create_buffer(dri2_surf, 563 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]); 564 565 wl_surface_attach(dri2_surf->wl_win->surface, 566 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 567 dri2_surf->dx, dri2_surf->dy); 568 dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1; 569 570 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 571 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 572 /* reset resize growing parameters */ 573 dri2_surf->dx = 0; 574 dri2_surf->dy = 0; 575 576 wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, 577 dri2_surf->base.Width, dri2_surf->base.Height); 578 579 wl_surface_commit(dri2_surf->wl_win->surface); 580 } 581 582 _EGLContext *ctx; 583 if (dri2_drv->glFlush) { 584 ctx = _eglGetCurrentContext(); 585 if (ctx && ctx->DrawSurface == &dri2_surf->base) 586 dri2_drv->glFlush(); 587 } 588 589 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); 590 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); 591 592 return EGL_TRUE; 593} 594 595static int 596dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id) 597{ 598 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 599 int ret = 0; 600 601 dri2_dpy->authenticated = 0; 602 603 wl_drm_authenticate(dri2_dpy->wl_drm, id); 604 if (roundtrip(dri2_dpy) < 0) 605 ret = -1; 606 607 if (!dri2_dpy->authenticated) 608 ret = -1; 609 610 /* reset authenticated */ 611 dri2_dpy->authenticated = 1; 612 613 return ret; 614} 615 616/** 617 * Called via eglTerminate(), drv->API.Terminate(). 618 */ 619static EGLBoolean 620dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) 621{ 622 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 623 624 _eglReleaseDisplayResources(drv, disp); 625 _eglCleanupDisplay(disp); 626 627 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 628 close(dri2_dpy->fd); 629 dlclose(dri2_dpy->driver); 630 free(dri2_dpy->driver_name); 631 free(dri2_dpy->device_name); 632 wl_drm_destroy(dri2_dpy->wl_drm); 633 if (dri2_dpy->own_device) 634 wl_display_disconnect(dri2_dpy->wl_dpy); 635 free(dri2_dpy); 636 disp->DriverData = NULL; 637 638 return EGL_TRUE; 639} 640 641static void 642drm_handle_device(void *data, struct wl_drm *drm, const char *device) 643{ 644 struct dri2_egl_display *dri2_dpy = data; 645 drm_magic_t magic; 646 647 dri2_dpy->device_name = strdup(device); 648 if (!dri2_dpy->device_name) 649 return; 650 651#ifdef O_CLOEXEC 652 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC); 653 if (dri2_dpy->fd == -1 && errno == EINVAL) 654#endif 655 { 656 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR); 657 if (dri2_dpy->fd != -1) 658 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) | 659 FD_CLOEXEC); 660 } 661 if (dri2_dpy->fd == -1) { 662 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", 663 dri2_dpy->device_name, strerror(errno)); 664 return; 665 } 666 667 drmGetMagic(dri2_dpy->fd, &magic); 668 wl_drm_authenticate(dri2_dpy->wl_drm, magic); 669} 670 671static void 672drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 673{ 674 struct dri2_egl_display *dri2_dpy = data; 675 676 switch (format) { 677 case WL_DRM_FORMAT_ARGB8888: 678 dri2_dpy->formats |= HAS_ARGB8888; 679 break; 680 case WL_DRM_FORMAT_XRGB8888: 681 dri2_dpy->formats |= HAS_XRGB8888; 682 break; 683 } 684} 685 686static void 687drm_handle_authenticated(void *data, struct wl_drm *drm) 688{ 689 struct dri2_egl_display *dri2_dpy = data; 690 691 dri2_dpy->authenticated = 1; 692} 693 694static const struct wl_drm_listener drm_listener = { 695 drm_handle_device, 696 drm_handle_format, 697 drm_handle_authenticated 698}; 699 700static void 701registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, 702 const char *interface, uint32_t version) 703{ 704 struct dri2_egl_display *dri2_dpy = data; 705 706 if (strcmp(interface, "wl_drm") == 0) { 707 dri2_dpy->wl_drm = 708 wl_registry_bind(registry, name, &wl_drm_interface, 1); 709 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); 710 } 711} 712 713static const struct wl_registry_listener registry_listener = { 714 registry_handle_global 715}; 716 717EGLBoolean 718dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 719{ 720 struct dri2_egl_display *dri2_dpy; 721 const __DRIconfig *config; 722 uint32_t types; 723 int i; 724 static const unsigned int argb_masks[4] = 725 { 0xff0000, 0xff00, 0xff, 0xff000000 }; 726 static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 }; 727 728 drv->API.CreateWindowSurface = dri2_create_window_surface; 729 drv->API.DestroySurface = dri2_destroy_surface; 730 drv->API.SwapBuffers = dri2_swap_buffers; 731 drv->API.Terminate = dri2_terminate; 732 733 dri2_dpy = malloc(sizeof *dri2_dpy); 734 if (!dri2_dpy) 735 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 736 737 memset(dri2_dpy, 0, sizeof *dri2_dpy); 738 739 disp->DriverData = (void *) dri2_dpy; 740 if (disp->PlatformDisplay == NULL) { 741 dri2_dpy->wl_dpy = wl_display_connect(NULL); 742 if (dri2_dpy->wl_dpy == NULL) 743 goto cleanup_dpy; 744 dri2_dpy->own_device = 1; 745 } else { 746 dri2_dpy->wl_dpy = disp->PlatformDisplay; 747 } 748 749 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); 750 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy); 751 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry, 752 dri2_dpy->wl_queue); 753 wl_registry_add_listener(dri2_dpy->wl_registry, 754 ®istry_listener, dri2_dpy); 755 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL) 756 goto cleanup_dpy; 757 758 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1) 759 goto cleanup_drm; 760 761 if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated) 762 goto cleanup_fd; 763 764 dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd); 765 if (dri2_dpy->driver_name == NULL) { 766 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); 767 goto cleanup_fd; 768 } 769 770 if (!dri2_load_driver(disp)) 771 goto cleanup_driver_name; 772 773 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; 774 dri2_dpy->dri2_loader_extension.base.version = 3; 775 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; 776 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; 777 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = 778 dri2_get_buffers_with_format; 779 780 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; 781 dri2_dpy->extensions[1] = &image_lookup_extension.base; 782 dri2_dpy->extensions[2] = &use_invalidate.base; 783 dri2_dpy->extensions[3] = NULL; 784 785 if (!dri2_create_screen(disp)) 786 goto cleanup_driver; 787 788 types = EGL_WINDOW_BIT; 789 for (i = 0; dri2_dpy->driver_configs[i]; i++) { 790 config = dri2_dpy->driver_configs[i]; 791 if (dri2_dpy->formats & HAS_XRGB8888) 792 dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks); 793 if (dri2_dpy->formats & HAS_ARGB8888) 794 dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks); 795 } 796 797 disp->Extensions.WL_bind_wayland_display = EGL_TRUE; 798 dri2_dpy->authenticate = dri2_wayland_authenticate; 799 800 /* we're supporting EGL 1.4 */ 801 disp->VersionMajor = 1; 802 disp->VersionMinor = 4; 803 804 return EGL_TRUE; 805 806 cleanup_driver: 807 dlclose(dri2_dpy->driver); 808 cleanup_driver_name: 809 free(dri2_dpy->driver_name); 810 cleanup_fd: 811 close(dri2_dpy->fd); 812 cleanup_drm: 813 free(dri2_dpy->device_name); 814 wl_drm_destroy(dri2_dpy->wl_drm); 815 cleanup_dpy: 816 free(dri2_dpy); 817 818 return EGL_FALSE; 819} 820