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