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