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