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