platform_wayland.c revision 7b1d94e5d1f53ac5f59000176aea1d02fc9a1181
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 314static const struct wl_callback_listener release_buffer_listener = { 315 dri2_release_pending_buffer 316}; 317 318static void 319dri2_release_buffers(struct dri2_egl_surface *dri2_surf) 320{ 321 struct dri2_egl_display *dri2_dpy = 322 dri2_egl_display(dri2_surf->base.Resource.Display); 323 struct wl_callback *callback; 324 int i; 325 326 if (dri2_surf->third_buffer) { 327 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 328 dri2_surf->third_buffer); 329 dri2_surf->third_buffer = NULL; 330 } 331 332 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) { 333 if (dri2_surf->dri_buffers[i]) { 334 switch (i) { 335 case __DRI_BUFFER_FRONT_LEFT: 336 if (dri2_surf->pending_buffer) 337 wl_display_roundtrip(dri2_dpy->wl_dpy); 338 dri2_surf->pending_buffer = dri2_surf->dri_buffers[i]; 339 callback = wl_display_sync(dri2_dpy->wl_dpy); 340 wl_callback_add_listener(callback, 341 &release_buffer_listener, 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 491 *out_count = dri2_surf->buffer_count; 492 if (dri2_surf->buffer_count == 0) 493 return NULL; 494 495 *width = dri2_surf->base.Width; 496 *height = dri2_surf->base.Height; 497 498 return dri2_surf->buffers; 499} 500 501static __DRIbuffer * 502dri2_get_buffers(__DRIdrawable * driDrawable, 503 int *width, int *height, 504 unsigned int *attachments, int count, 505 int *out_count, void *loaderPrivate) 506{ 507 unsigned int *attachments_with_format; 508 __DRIbuffer *buffer; 509 const unsigned int format = 32; 510 int i; 511 512 attachments_with_format = calloc(count * 2, sizeof(unsigned int)); 513 if (!attachments_with_format) { 514 *out_count = 0; 515 return NULL; 516 } 517 518 for (i = 0; i < count; ++i) { 519 attachments_with_format[2*i] = attachments[i]; 520 attachments_with_format[2*i + 1] = format; 521 } 522 523 buffer = 524 dri2_get_buffers_with_format(driDrawable, 525 width, height, 526 attachments_with_format, count, 527 out_count, loaderPrivate); 528 529 free(attachments_with_format); 530 531 return buffer; 532} 533 534 535static void 536dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 537{ 538 (void) driDrawable; 539 540 /* FIXME: Does EGL support front buffer rendering at all? */ 541 542#if 0 543 struct dri2_egl_surface *dri2_surf = loaderPrivate; 544 545 dri2WaitGL(dri2_surf); 546#else 547 (void) loaderPrivate; 548#endif 549} 550 551static void 552wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time) 553{ 554 struct dri2_egl_surface *dri2_surf = data; 555 556 dri2_surf->block_swap_buffers = EGL_FALSE; 557 wl_callback_destroy(callback); 558} 559 560static const struct wl_callback_listener frame_listener = { 561 wayland_frame_callback 562}; 563 564/** 565 * Called via eglSwapBuffers(), drv->API.SwapBuffers(). 566 */ 567static EGLBoolean 568dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 569{ 570 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 571 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 572 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); 573 struct wl_callback *callback; 574 575 while (dri2_surf->block_swap_buffers) 576 wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE); 577 578 dri2_surf->block_swap_buffers = EGL_TRUE; 579 callback = wl_surface_frame(dri2_surf->wl_win->surface); 580 wl_callback_add_listener(callback, &frame_listener, dri2_surf); 581 582 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 583 pointer_swap( 584 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], 585 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); 586 587 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment = 588 __DRI_BUFFER_FRONT_LEFT; 589 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = 590 __DRI_BUFFER_BACK_LEFT; 591 592 swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK); 593 594 if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT]) 595 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] = 596 wayland_create_buffer(dri2_surf, 597 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]); 598 599 wl_buffer_damage(dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 0, 0, 600 dri2_surf->base.Width, dri2_surf->base.Height); 601 wl_surface_attach(dri2_surf->wl_win->surface, 602 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 603 dri2_surf->dx, dri2_surf->dy); 604 dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1; 605 606 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 607 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 608 /* reset resize growing parameters */ 609 dri2_surf->dx = 0; 610 dri2_surf->dy = 0; 611 612 wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, 613 dri2_surf->base.Width, dri2_surf->base.Height); 614 } 615 616 _EGLContext *ctx; 617 if (dri2_drv->glFlush) { 618 ctx = _eglGetCurrentContext(); 619 if (ctx && ctx->DrawSurface == &dri2_surf->base) 620 dri2_drv->glFlush(); 621 } 622 623 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); 624 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); 625 626 return EGL_TRUE; 627} 628 629/** 630 * Called via eglCreateImageKHR(), drv->API.CreateImageKHR(). 631 */ 632static _EGLImage * 633dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, 634 EGLClientBuffer buffer, const EGLint *attr_list) 635{ 636 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 637 struct wl_egl_pixmap *wl_egl_pixmap = (struct wl_egl_pixmap *) buffer; 638 struct dri2_egl_buffer *dri2_buf; 639 EGLint wl_attr_list[] = { 640 EGL_WIDTH, 0, 641 EGL_HEIGHT, 0, 642 EGL_DRM_BUFFER_STRIDE_MESA, 0, 643 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, 644 EGL_NONE 645 }; 646 647 dri2_buf = malloc(sizeof *dri2_buf); 648 if (!dri2_buf) 649 return NULL; 650 651 dri2_buf->dri2_dpy = dri2_dpy; 652 dri2_buf->dri_buffer = 653 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 654 __DRI_BUFFER_FRONT_LEFT, 32, 655 wl_egl_pixmap->width, 656 wl_egl_pixmap->height); 657 658 wl_egl_pixmap->destroy = dri2_wl_egl_pixmap_destroy; 659 wl_egl_pixmap->driver_private = dri2_buf; 660 661 /* FIXME: Get buffer format from attr_list somehow... or from the 662 wl_egl_piaxmap. */ 663 wl_egl_pixmap->buffer = 664 wl_drm_create_buffer(dri2_dpy->wl_drm, 665 dri2_buf->dri_buffer->name, 666 wl_egl_pixmap->width, 667 wl_egl_pixmap->height, 668 dri2_buf->dri_buffer->pitch, 669 WL_DRM_FORMAT_PREMULTIPLIED_ARGB32); 670 671 wl_attr_list[1] = wl_egl_pixmap->width; 672 wl_attr_list[3] = wl_egl_pixmap->height; 673 wl_attr_list[5] = dri2_buf->dri_buffer->pitch / 4; 674 675 return dri2_create_image_khr(disp->Driver, disp, ctx, EGL_DRM_BUFFER_MESA, 676 (EGLClientBuffer)(intptr_t) dri2_buf->dri_buffer->name, wl_attr_list); 677} 678 679static _EGLImage * 680dri2_wayland_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, 681 _EGLContext *ctx, EGLenum target, 682 EGLClientBuffer buffer, const EGLint *attr_list) 683{ 684 (void) drv; 685 686 switch (target) { 687 case EGL_NATIVE_PIXMAP_KHR: 688 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list); 689 default: 690 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); 691 } 692} 693 694static int 695dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id) 696{ 697 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 698 int ret = 0; 699 700 dri2_dpy->authenticated = 0; 701 702 wl_drm_authenticate(dri2_dpy->wl_drm, id); 703 wl_display_roundtrip(dri2_dpy->wl_dpy); 704 705 if (!dri2_dpy->authenticated) 706 ret = -1; 707 708 /* reset authenticated */ 709 dri2_dpy->authenticated = 1; 710 711 return ret; 712} 713 714/** 715 * Called via eglTerminate(), drv->API.Terminate(). 716 */ 717static EGLBoolean 718dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) 719{ 720 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 721 722 _eglReleaseDisplayResources(drv, disp); 723 _eglCleanupDisplay(disp); 724 725 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 726 close(dri2_dpy->fd); 727 dlclose(dri2_dpy->driver); 728 free(dri2_dpy->driver_name); 729 free(dri2_dpy); 730 disp->DriverData = NULL; 731 732 return EGL_TRUE; 733} 734 735static void 736drm_handle_device(void *data, struct wl_drm *drm, const char *device) 737{ 738 struct dri2_egl_display *dri2_dpy = data; 739 drm_magic_t magic; 740 741 dri2_dpy->device_name = strdup(device); 742 if (!dri2_dpy->device_name) 743 return; 744 745 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR); 746 if (dri2_dpy->fd == -1) { 747 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", 748 dri2_dpy->device_name, strerror(errno)); 749 return; 750 } 751 752 drmGetMagic(dri2_dpy->fd, &magic); 753 wl_drm_authenticate(dri2_dpy->wl_drm, magic); 754} 755 756static void 757drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 758{ 759 struct dri2_egl_display *dri2_dpy = data; 760 761 switch (format) { 762 case WL_DRM_FORMAT_ARGB32: 763 dri2_dpy->formats |= HAS_ARGB32; 764 break; 765 case WL_DRM_FORMAT_PREMULTIPLIED_ARGB32: 766 dri2_dpy->formats |= HAS_PREMUL_ARGB32; 767 break; 768 case WL_DRM_FORMAT_XRGB32: 769 dri2_dpy->formats |= HAS_XRGB32; 770 break; 771 } 772} 773 774static void 775drm_handle_authenticated(void *data, struct wl_drm *drm) 776{ 777 struct dri2_egl_display *dri2_dpy = data; 778 779 dri2_dpy->authenticated = 1; 780} 781 782static const struct wl_drm_listener drm_listener = { 783 drm_handle_device, 784 drm_handle_format, 785 drm_handle_authenticated 786}; 787 788EGLBoolean 789dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 790{ 791 struct dri2_egl_display *dri2_dpy; 792 const __DRIconfig *config; 793 uint32_t id, types; 794 int i; 795 static const unsigned int argb_masks[4] = 796 { 0xff0000, 0xff00, 0xff, 0xff000000 }; 797 static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 }; 798 799 drv->API.CreateWindowSurface = dri2_create_window_surface; 800 drv->API.CreatePixmapSurface = dri2_create_pixmap_surface; 801 drv->API.DestroySurface = dri2_destroy_surface; 802 drv->API.SwapBuffers = dri2_swap_buffers; 803 drv->API.CreateImageKHR = dri2_wayland_create_image_khr; 804 drv->API.Terminate = dri2_terminate; 805 806 dri2_dpy = malloc(sizeof *dri2_dpy); 807 if (!dri2_dpy) 808 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 809 810 memset(dri2_dpy, 0, sizeof *dri2_dpy); 811 812 disp->DriverData = (void *) dri2_dpy; 813 if (disp->PlatformDisplay == NULL) { 814 dri2_dpy->wl_dpy = wl_display_connect(NULL); 815 if (dri2_dpy->wl_dpy == NULL) 816 goto cleanup_dpy; 817 } else { 818 dri2_dpy->wl_dpy = disp->PlatformDisplay; 819 } 820 821 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1); 822 if (id == 0) 823 wl_display_roundtrip(dri2_dpy->wl_dpy); 824 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1); 825 if (id == 0) 826 goto cleanup_dpy; 827 dri2_dpy->wl_drm = wl_display_bind(dri2_dpy->wl_dpy, id, &wl_drm_interface); 828 if (!dri2_dpy->wl_drm) 829 goto cleanup_dpy; 830 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); 831 wl_display_roundtrip(dri2_dpy->wl_dpy); 832 if (dri2_dpy->fd == -1) 833 goto cleanup_drm; 834 835 wl_display_roundtrip(dri2_dpy->wl_dpy); 836 if (!dri2_dpy->authenticated) 837 goto cleanup_fd; 838 839 dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd); 840 if (dri2_dpy->driver_name == NULL) { 841 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); 842 goto cleanup_fd; 843 } 844 845 if (!dri2_load_driver(disp)) 846 goto cleanup_driver_name; 847 848 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; 849 dri2_dpy->dri2_loader_extension.base.version = 3; 850 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; 851 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; 852 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = 853 dri2_get_buffers_with_format; 854 855 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; 856 dri2_dpy->extensions[1] = &image_lookup_extension.base; 857 dri2_dpy->extensions[2] = &use_invalidate.base; 858 dri2_dpy->extensions[3] = NULL; 859 860 if (!dri2_create_screen(disp)) 861 goto cleanup_driver; 862 863 types = EGL_WINDOW_BIT | EGL_PIXMAP_BIT; 864 if (dri2_dpy->formats & HAS_PREMUL_ARGB32) 865 types |= EGL_VG_ALPHA_FORMAT_PRE_BIT; 866 867 for (i = 0; dri2_dpy->driver_configs[i]; i++) { 868 config = dri2_dpy->driver_configs[i]; 869 if (dri2_dpy->formats & HAS_XRGB32) 870 dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks); 871 if (dri2_dpy->formats & (HAS_ARGB32 | HAS_PREMUL_ARGB32)) 872 dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks); 873 } 874 875 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 876 877 disp->Extensions.WL_bind_wayland_display = EGL_TRUE; 878 dri2_dpy->authenticate = dri2_wayland_authenticate; 879 880 /* we're supporting EGL 1.4 */ 881 disp->VersionMajor = 1; 882 disp->VersionMinor = 4; 883 884 return EGL_TRUE; 885 886 cleanup_driver: 887 dlclose(dri2_dpy->driver); 888 cleanup_driver_name: 889 free(dri2_dpy->driver_name); 890 cleanup_fd: 891 close(dri2_dpy->fd); 892 cleanup_drm: 893 free(dri2_dpy->device_name); 894 wl_drm_destroy(dri2_dpy->wl_drm); 895 cleanup_dpy: 896 free(dri2_dpy); 897 898 return EGL_FALSE; 899} 900