platform_wayland.c revision 11f64668a91259b876d6b6bccd902f875531502d
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_ARGB32 = 1, 45 HAS_PREMUL_ARGB32 = 2, 46 HAS_XRGB32 = 4 47}; 48 49static void 50wl_buffer_release(void *data, struct wl_buffer *buffer) 51{ 52 struct dri2_egl_surface *dri2_surf = data; 53 int i; 54 55 for (i = 0; i < WL_BUFFER_COUNT; ++i) 56 if (dri2_surf->wl_drm_buffer[i] == buffer) 57 break; 58 59 assert(i <= WL_BUFFER_COUNT); 60 61 /* not found? */ 62 if (i == WL_BUFFER_COUNT) 63 return; 64 65 dri2_surf->wl_buffer_lock[i] = 0; 66 67} 68 69static struct wl_buffer_listener wl_buffer_listener = { 70 wl_buffer_release 71}; 72 73/** 74 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 75 */ 76static _EGLSurface * 77dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, 78 _EGLConfig *conf, EGLNativeWindowType window, 79 const EGLint *attrib_list) 80{ 81 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 82 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 83 struct dri2_egl_surface *dri2_surf; 84 struct dri2_egl_buffer *dri2_buf; 85 int i; 86 87 (void) drv; 88 89 dri2_surf = malloc(sizeof *dri2_surf); 90 if (!dri2_surf) { 91 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 92 return NULL; 93 } 94 95 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) 96 goto cleanup_surf; 97 98 for (i = 0; i < WL_BUFFER_COUNT; ++i) { 99 dri2_surf->wl_drm_buffer[i] = NULL; 100 dri2_surf->wl_buffer_lock[i] = 0; 101 } 102 103 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) 104 dri2_surf->dri_buffers[i] = NULL; 105 106 dri2_surf->pending_buffer = NULL; 107 dri2_surf->third_buffer = NULL; 108 dri2_surf->block_swap_buffers = EGL_FALSE; 109 110 if (conf->AlphaSize == 0) 111 dri2_surf->format = WL_DRM_FORMAT_XRGB32; 112 else if (dri2_surf->base.VGAlphaFormat == EGL_VG_ALPHA_FORMAT_PRE) 113 dri2_surf->format = WL_DRM_FORMAT_PREMULTIPLIED_ARGB32; 114 else 115 dri2_surf->format = WL_DRM_FORMAT_ARGB32; 116 117 switch (type) { 118 case EGL_WINDOW_BIT: 119 dri2_surf->wl_win = (struct wl_egl_window *) window; 120 121 dri2_surf->base.Width = -1; 122 dri2_surf->base.Height = -1; 123 break; 124 case EGL_PIXMAP_BIT: 125 dri2_surf->wl_pix = (struct wl_egl_pixmap *) window; 126 127 dri2_surf->base.Width = dri2_surf->wl_pix->width; 128 dri2_surf->base.Height = dri2_surf->wl_pix->height; 129 130 if (dri2_surf->wl_pix->driver_private) { 131 dri2_buf = dri2_surf->wl_pix->driver_private; 132 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = dri2_buf->dri_buffer; 133 } 134 break; 135 default: 136 goto cleanup_surf; 137 } 138 139 dri2_surf->dri_drawable = 140 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, 141 type == EGL_WINDOW_BIT ? 142 dri2_conf->dri_double_config : 143 dri2_conf->dri_single_config, 144 dri2_surf); 145 if (dri2_surf->dri_drawable == NULL) { 146 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); 147 goto cleanup_dri_drawable; 148 } 149 150 return &dri2_surf->base; 151 152 cleanup_dri_drawable: 153 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 154 cleanup_surf: 155 free(dri2_surf); 156 157 return NULL; 158} 159 160/** 161 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 162 */ 163static _EGLSurface * 164dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, 165 _EGLConfig *conf, EGLNativeWindowType window, 166 const EGLint *attrib_list) 167{ 168 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf, 169 window, attrib_list); 170} 171 172static _EGLSurface * 173dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, 174 _EGLConfig *conf, EGLNativePixmapType pixmap, 175 const EGLint *attrib_list) 176{ 177 return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf, 178 pixmap, attrib_list); 179} 180 181/** 182 * Called via eglDestroySurface(), drv->API.DestroySurface(). 183 */ 184static EGLBoolean 185dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) 186{ 187 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 188 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 189 int i; 190 191 (void) drv; 192 193 if (!_eglPutSurface(surf)) 194 return EGL_TRUE; 195 196 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); 197 198 for (i = 0; i < WL_BUFFER_COUNT; ++i) 199 if (dri2_surf->wl_drm_buffer[i]) 200 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]); 201 202 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) 203 if (dri2_surf->dri_buffers[i] && !(i == __DRI_BUFFER_FRONT_LEFT && 204 dri2_surf->base.Type == EGL_PIXMAP_BIT)) 205 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 206 dri2_surf->dri_buffers[i]); 207 208 if (dri2_surf->third_buffer) { 209 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 210 dri2_surf->third_buffer); 211 } 212 213 free(surf); 214 215 return EGL_TRUE; 216} 217 218static void 219dri2_wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap) 220{ 221 struct dri2_egl_buffer *dri2_buf = egl_pixmap->driver_private; 222 223 assert(dri2_buf); 224 225 dri2_buf->dri2_dpy->dri2->releaseBuffer(dri2_buf->dri2_dpy->dri_screen, 226 dri2_buf->dri_buffer); 227 228 free(dri2_buf); 229 230 egl_pixmap->driver_private = NULL; 231 egl_pixmap->destroy = NULL; 232} 233 234static struct wl_buffer * 235wayland_create_buffer(struct dri2_egl_surface *dri2_surf, 236 __DRIbuffer *buffer) 237{ 238 struct dri2_egl_display *dri2_dpy = 239 dri2_egl_display(dri2_surf->base.Resource.Display); 240 struct wl_buffer *buf; 241 242 buf = wl_drm_create_buffer(dri2_dpy->wl_drm, buffer->name, 243 dri2_surf->base.Width, dri2_surf->base.Height, 244 buffer->pitch, dri2_surf->format); 245 wl_buffer_add_listener(buf, &wl_buffer_listener, dri2_surf); 246 247 return buf; 248} 249 250static void 251dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format) 252{ 253 struct dri2_egl_display *dri2_dpy = 254 dri2_egl_display(dri2_surf->base.Resource.Display); 255 256 (void) format; 257 258 switch (dri2_surf->base.Type) { 259 case EGL_WINDOW_BIT: 260 /* allocate a front buffer for our double-buffered window*/ 261 if (dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] != NULL) 262 break; 263 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = 264 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 265 __DRI_BUFFER_FRONT_LEFT, format, 266 dri2_surf->base.Width, dri2_surf->base.Height); 267 break; 268 default: 269 break; 270 } 271} 272 273static void 274dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format) 275{ 276 struct dri2_egl_display *dri2_dpy = 277 dri2_egl_display(dri2_surf->base.Resource.Display); 278 struct dri2_egl_buffer *dri2_buf; 279 280 switch (dri2_surf->base.Type) { 281 case EGL_PIXMAP_BIT: 282 dri2_buf = malloc(sizeof *dri2_buf); 283 if (!dri2_buf) 284 return; 285 286 dri2_buf->dri_buffer = dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]; 287 dri2_buf->dri2_dpy = dri2_dpy; 288 289 dri2_surf->wl_pix->driver_private = dri2_buf; 290 dri2_surf->wl_pix->destroy = dri2_wl_egl_pixmap_destroy; 291 break; 292 default: 293 break; 294 } 295} 296 297static void 298dri2_release_pending_buffer(void *data, 299 struct wl_callback *callback, uint32_t time) 300{ 301 struct dri2_egl_surface *dri2_surf = data; 302 struct dri2_egl_display *dri2_dpy = 303 dri2_egl_display(dri2_surf->base.Resource.Display); 304 305 /* FIXME: print internal error */ 306 if (!dri2_surf->pending_buffer) 307 return; 308 309 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 310 dri2_surf->pending_buffer); 311 dri2_surf->pending_buffer = NULL; 312 313 wl_callback_destroy(callback); 314} 315 316static const struct wl_callback_listener release_buffer_listener = { 317 dri2_release_pending_buffer 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 struct wl_callback *callback; 326 int i; 327 328 if (dri2_surf->third_buffer) { 329 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 330 dri2_surf->third_buffer); 331 dri2_surf->third_buffer = NULL; 332 } 333 334 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) { 335 if (dri2_surf->dri_buffers[i]) { 336 switch (i) { 337 case __DRI_BUFFER_FRONT_LEFT: 338 if (dri2_surf->pending_buffer) 339 wl_display_roundtrip(dri2_dpy->wl_dpy); 340 dri2_surf->pending_buffer = dri2_surf->dri_buffers[i]; 341 callback = wl_display_sync(dri2_dpy->wl_dpy); 342 wl_callback_add_listener(callback, 343 &release_buffer_listener, 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->base.Type == EGL_WINDOW_BIT && 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->base.Type == EGL_PIXMAP_BIT || 486 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); 487 488 if (dri2_surf->base.Type == EGL_PIXMAP_BIT && !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 493 *out_count = dri2_surf->buffer_count; 494 if (dri2_surf->buffer_count == 0) 495 return NULL; 496 497 *width = dri2_surf->base.Width; 498 *height = dri2_surf->base.Height; 499 500 return dri2_surf->buffers; 501} 502 503static __DRIbuffer * 504dri2_get_buffers(__DRIdrawable * driDrawable, 505 int *width, int *height, 506 unsigned int *attachments, int count, 507 int *out_count, void *loaderPrivate) 508{ 509 unsigned int *attachments_with_format; 510 __DRIbuffer *buffer; 511 const unsigned int format = 32; 512 int i; 513 514 attachments_with_format = calloc(count * 2, sizeof(unsigned int)); 515 if (!attachments_with_format) { 516 *out_count = 0; 517 return NULL; 518 } 519 520 for (i = 0; i < count; ++i) { 521 attachments_with_format[2*i] = attachments[i]; 522 attachments_with_format[2*i + 1] = format; 523 } 524 525 buffer = 526 dri2_get_buffers_with_format(driDrawable, 527 width, height, 528 attachments_with_format, count, 529 out_count, loaderPrivate); 530 531 free(attachments_with_format); 532 533 return buffer; 534} 535 536 537static void 538dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 539{ 540 (void) driDrawable; 541 542 /* FIXME: Does EGL support front buffer rendering at all? */ 543 544#if 0 545 struct dri2_egl_surface *dri2_surf = loaderPrivate; 546 547 dri2WaitGL(dri2_surf); 548#else 549 (void) loaderPrivate; 550#endif 551} 552 553static void 554wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time) 555{ 556 struct dri2_egl_surface *dri2_surf = data; 557 558 dri2_surf->block_swap_buffers = EGL_FALSE; 559 wl_callback_destroy(callback); 560} 561 562static const struct wl_callback_listener frame_listener = { 563 wayland_frame_callback 564}; 565 566/** 567 * Called via eglSwapBuffers(), drv->API.SwapBuffers(). 568 */ 569static EGLBoolean 570dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 571{ 572 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 573 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 574 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); 575 struct wl_callback *callback; 576 577 while (dri2_surf->block_swap_buffers) 578 wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE); 579 580 dri2_surf->block_swap_buffers = EGL_TRUE; 581 callback = wl_surface_frame(dri2_surf->wl_win->surface); 582 wl_callback_add_listener(callback, &frame_listener, dri2_surf); 583 584 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 585 pointer_swap( 586 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], 587 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); 588 589 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment = 590 __DRI_BUFFER_FRONT_LEFT; 591 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = 592 __DRI_BUFFER_BACK_LEFT; 593 594 swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK); 595 596 if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT]) 597 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] = 598 wayland_create_buffer(dri2_surf, 599 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]); 600 601 wl_buffer_damage(dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 0, 0, 602 dri2_surf->base.Width, dri2_surf->base.Height); 603 wl_surface_attach(dri2_surf->wl_win->surface, 604 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 605 dri2_surf->dx, dri2_surf->dy); 606 dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1; 607 608 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 609 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 610 /* reset resize growing parameters */ 611 dri2_surf->dx = 0; 612 dri2_surf->dy = 0; 613 614 wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, 615 dri2_surf->base.Width, dri2_surf->base.Height); 616 } 617 618 _EGLContext *ctx; 619 if (dri2_drv->glFlush) { 620 ctx = _eglGetCurrentContext(); 621 if (ctx && ctx->DrawSurface == &dri2_surf->base) 622 dri2_drv->glFlush(); 623 } 624 625 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); 626 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); 627 628 return EGL_TRUE; 629} 630 631/** 632 * Called via eglCreateImageKHR(), drv->API.CreateImageKHR(). 633 */ 634static _EGLImage * 635dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, 636 EGLClientBuffer buffer, const EGLint *attr_list) 637{ 638 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 639 struct wl_egl_pixmap *wl_egl_pixmap = (struct wl_egl_pixmap *) buffer; 640 struct dri2_egl_buffer *dri2_buf; 641 EGLint wl_attr_list[] = { 642 EGL_WIDTH, 0, 643 EGL_HEIGHT, 0, 644 EGL_DRM_BUFFER_STRIDE_MESA, 0, 645 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, 646 EGL_NONE 647 }; 648 649 dri2_buf = malloc(sizeof *dri2_buf); 650 if (!dri2_buf) 651 return NULL; 652 653 dri2_buf->dri2_dpy = dri2_dpy; 654 dri2_buf->dri_buffer = 655 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 656 __DRI_BUFFER_FRONT_LEFT, 32, 657 wl_egl_pixmap->width, 658 wl_egl_pixmap->height); 659 660 wl_egl_pixmap->destroy = dri2_wl_egl_pixmap_destroy; 661 wl_egl_pixmap->driver_private = dri2_buf; 662 663 /* FIXME: Get buffer format from attr_list somehow... or from the 664 wl_egl_piaxmap. */ 665 wl_egl_pixmap->buffer = 666 wl_drm_create_buffer(dri2_dpy->wl_drm, 667 dri2_buf->dri_buffer->name, 668 wl_egl_pixmap->width, 669 wl_egl_pixmap->height, 670 dri2_buf->dri_buffer->pitch, 671 WL_DRM_FORMAT_PREMULTIPLIED_ARGB32); 672 673 wl_attr_list[1] = wl_egl_pixmap->width; 674 wl_attr_list[3] = wl_egl_pixmap->height; 675 wl_attr_list[5] = dri2_buf->dri_buffer->pitch / 4; 676 677 return dri2_create_image_khr(disp->Driver, disp, ctx, EGL_DRM_BUFFER_MESA, 678 (EGLClientBuffer)(intptr_t) dri2_buf->dri_buffer->name, wl_attr_list); 679} 680 681static _EGLImage * 682dri2_wayland_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, 683 _EGLContext *ctx, EGLenum target, 684 EGLClientBuffer buffer, const EGLint *attr_list) 685{ 686 (void) drv; 687 688 switch (target) { 689 case EGL_NATIVE_PIXMAP_KHR: 690 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list); 691 default: 692 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); 693 } 694} 695 696static int 697dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id) 698{ 699 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 700 int ret = 0; 701 702 dri2_dpy->authenticated = 0; 703 704 wl_drm_authenticate(dri2_dpy->wl_drm, id); 705 wl_display_roundtrip(dri2_dpy->wl_dpy); 706 707 if (!dri2_dpy->authenticated) 708 ret = -1; 709 710 /* reset authenticated */ 711 dri2_dpy->authenticated = 1; 712 713 return ret; 714} 715 716/** 717 * Called via eglTerminate(), drv->API.Terminate(). 718 */ 719static EGLBoolean 720dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) 721{ 722 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 723 724 _eglReleaseDisplayResources(drv, disp); 725 _eglCleanupDisplay(disp); 726 727 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 728 close(dri2_dpy->fd); 729 dlclose(dri2_dpy->driver); 730 free(dri2_dpy->driver_name); 731 free(dri2_dpy); 732 disp->DriverData = NULL; 733 734 return EGL_TRUE; 735} 736 737static void 738drm_handle_device(void *data, struct wl_drm *drm, const char *device) 739{ 740 struct dri2_egl_display *dri2_dpy = data; 741 drm_magic_t magic; 742 743 dri2_dpy->device_name = strdup(device); 744 if (!dri2_dpy->device_name) 745 return; 746 747 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR); 748 if (dri2_dpy->fd == -1) { 749 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", 750 dri2_dpy->device_name, strerror(errno)); 751 return; 752 } 753 754 drmGetMagic(dri2_dpy->fd, &magic); 755 wl_drm_authenticate(dri2_dpy->wl_drm, magic); 756} 757 758static void 759drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 760{ 761 struct dri2_egl_display *dri2_dpy = data; 762 763 switch (format) { 764 case WL_DRM_FORMAT_ARGB32: 765 dri2_dpy->formats |= HAS_ARGB32; 766 break; 767 case WL_DRM_FORMAT_PREMULTIPLIED_ARGB32: 768 dri2_dpy->formats |= HAS_PREMUL_ARGB32; 769 break; 770 case WL_DRM_FORMAT_XRGB32: 771 dri2_dpy->formats |= HAS_XRGB32; 772 break; 773 } 774} 775 776static void 777drm_handle_authenticated(void *data, struct wl_drm *drm) 778{ 779 struct dri2_egl_display *dri2_dpy = data; 780 781 dri2_dpy->authenticated = 1; 782} 783 784static const struct wl_drm_listener drm_listener = { 785 drm_handle_device, 786 drm_handle_format, 787 drm_handle_authenticated 788}; 789 790EGLBoolean 791dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 792{ 793 struct dri2_egl_display *dri2_dpy; 794 const __DRIconfig *config; 795 uint32_t id, types; 796 int i; 797 static const unsigned int argb_masks[4] = 798 { 0xff0000, 0xff00, 0xff, 0xff000000 }; 799 static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 }; 800 801 drv->API.CreateWindowSurface = dri2_create_window_surface; 802 drv->API.CreatePixmapSurface = dri2_create_pixmap_surface; 803 drv->API.DestroySurface = dri2_destroy_surface; 804 drv->API.SwapBuffers = dri2_swap_buffers; 805 drv->API.CreateImageKHR = dri2_wayland_create_image_khr; 806 drv->API.Terminate = dri2_terminate; 807 808 dri2_dpy = malloc(sizeof *dri2_dpy); 809 if (!dri2_dpy) 810 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 811 812 memset(dri2_dpy, 0, sizeof *dri2_dpy); 813 814 disp->DriverData = (void *) dri2_dpy; 815 if (disp->PlatformDisplay == NULL) { 816 dri2_dpy->wl_dpy = wl_display_connect(NULL); 817 if (dri2_dpy->wl_dpy == NULL) 818 goto cleanup_dpy; 819 } else { 820 dri2_dpy->wl_dpy = disp->PlatformDisplay; 821 } 822 823 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1); 824 if (id == 0) 825 wl_display_roundtrip(dri2_dpy->wl_dpy); 826 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1); 827 if (id == 0) 828 goto cleanup_dpy; 829 dri2_dpy->wl_drm = wl_display_bind(dri2_dpy->wl_dpy, id, &wl_drm_interface); 830 if (!dri2_dpy->wl_drm) 831 goto cleanup_dpy; 832 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); 833 wl_display_roundtrip(dri2_dpy->wl_dpy); 834 if (dri2_dpy->fd == -1) 835 goto cleanup_drm; 836 837 wl_display_roundtrip(dri2_dpy->wl_dpy); 838 if (!dri2_dpy->authenticated) 839 goto cleanup_fd; 840 841 dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd); 842 if (dri2_dpy->driver_name == NULL) { 843 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); 844 goto cleanup_fd; 845 } 846 847 if (!dri2_load_driver(disp)) 848 goto cleanup_driver_name; 849 850 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; 851 dri2_dpy->dri2_loader_extension.base.version = 3; 852 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; 853 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; 854 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = 855 dri2_get_buffers_with_format; 856 857 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; 858 dri2_dpy->extensions[1] = &image_lookup_extension.base; 859 dri2_dpy->extensions[2] = &use_invalidate.base; 860 dri2_dpy->extensions[3] = NULL; 861 862 if (!dri2_create_screen(disp)) 863 goto cleanup_driver; 864 865 types = EGL_WINDOW_BIT | EGL_PIXMAP_BIT; 866 if (dri2_dpy->formats & HAS_PREMUL_ARGB32) 867 types |= EGL_VG_ALPHA_FORMAT_PRE_BIT; 868 869 for (i = 0; dri2_dpy->driver_configs[i]; i++) { 870 config = dri2_dpy->driver_configs[i]; 871 if (dri2_dpy->formats & HAS_XRGB32) 872 dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks); 873 if (dri2_dpy->formats & (HAS_ARGB32 | HAS_PREMUL_ARGB32)) 874 dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks); 875 } 876 877 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 878 879 disp->Extensions.WL_bind_wayland_display = EGL_TRUE; 880 dri2_dpy->authenticate = dri2_wayland_authenticate; 881 882 /* we're supporting EGL 1.4 */ 883 disp->VersionMajor = 1; 884 disp->VersionMinor = 4; 885 886 return EGL_TRUE; 887 888 cleanup_driver: 889 dlclose(dri2_dpy->driver); 890 cleanup_driver_name: 891 free(dri2_dpy->driver_name); 892 cleanup_fd: 893 close(dri2_dpy->fd); 894 cleanup_drm: 895 free(dri2_dpy->device_name); 896 wl_drm_destroy(dri2_dpy->wl_drm); 897 cleanup_dpy: 898 free(dri2_dpy); 899 900 return EGL_FALSE; 901} 902