1 /* 2 * Copyright 2011-2012 Intel Corporation 3 * Copyright 2012 Collabora, Ltd. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Kristian Hgsberg <krh (at) bitplanet.net> 27 * Benjamin Franzke <benjaminfranzke (at) googlemail.com> 28 */ 29 30 #include <stdint.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <limits.h> 34 #include <dlfcn.h> 35 #include <errno.h> 36 #include <unistd.h> 37 #include <fcntl.h> 38 #include <xf86drm.h> 39 #include <sys/mman.h> 40 41 #include "egl_dri2.h" 42 #include "egl_dri2_fallbacks.h" 43 #include "loader.h" 44 45 #include <wayland-client.h> 46 #include "wayland-drm-client-protocol.h" 47 48 enum wl_drm_format_flags { 49 HAS_ARGB8888 = 1, 50 HAS_XRGB8888 = 2, 51 HAS_RGB565 = 4, 52 }; 53 54 static EGLBoolean 55 dri2_wl_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, 56 EGLint interval); 57 58 static void 59 sync_callback(void *data, struct wl_callback *callback, uint32_t serial) 60 { 61 int *done = data; 62 63 *done = 1; 64 wl_callback_destroy(callback); 65 } 66 67 static const struct wl_callback_listener sync_listener = { 68 .done = sync_callback 69 }; 70 71 static int 72 roundtrip(struct dri2_egl_display *dri2_dpy) 73 { 74 struct wl_callback *callback; 75 int done = 0, ret = 0; 76 77 callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper); 78 wl_callback_add_listener(callback, &sync_listener, &done); 79 while (ret != -1 && !done) 80 ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); 81 82 if (!done) 83 wl_callback_destroy(callback); 84 85 return ret; 86 } 87 88 static void 89 wl_buffer_release(void *data, struct wl_buffer *buffer) 90 { 91 struct dri2_egl_surface *dri2_surf = data; 92 int i; 93 94 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i) 95 if (dri2_surf->color_buffers[i].wl_buffer == buffer) 96 break; 97 98 if (i == ARRAY_SIZE(dri2_surf->color_buffers)) { 99 wl_buffer_destroy(buffer); 100 return; 101 } 102 103 dri2_surf->color_buffers[i].locked = 0; 104 } 105 106 static const struct wl_buffer_listener wl_buffer_listener = { 107 .release = wl_buffer_release 108 }; 109 110 static void 111 resize_callback(struct wl_egl_window *wl_win, void *data) 112 { 113 struct dri2_egl_surface *dri2_surf = data; 114 struct dri2_egl_display *dri2_dpy = 115 dri2_egl_display(dri2_surf->base.Resource.Display); 116 117 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 118 } 119 120 static void 121 destroy_window_callback(void *data) 122 { 123 struct dri2_egl_surface *dri2_surf = data; 124 dri2_surf->wl_win = NULL; 125 } 126 127 /** 128 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 129 */ 130 static _EGLSurface * 131 dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, 132 _EGLConfig *conf, void *native_window, 133 const EGLint *attrib_list) 134 { 135 __DRIcreateNewDrawableFunc createNewDrawable; 136 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 137 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 138 struct wl_egl_window *window = native_window; 139 struct dri2_egl_surface *dri2_surf; 140 const __DRIconfig *config; 141 142 dri2_surf = calloc(1, sizeof *dri2_surf); 143 if (!dri2_surf) { 144 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 145 return NULL; 146 } 147 148 if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list)) 149 goto cleanup_surf; 150 151 if (dri2_dpy->dri2) { 152 if (conf->RedSize == 5) 153 dri2_surf->format = WL_DRM_FORMAT_RGB565; 154 else if (conf->AlphaSize == 0) 155 dri2_surf->format = WL_DRM_FORMAT_XRGB8888; 156 else 157 dri2_surf->format = WL_DRM_FORMAT_ARGB8888; 158 } else { 159 if (conf->RedSize == 5) 160 dri2_surf->format = WL_SHM_FORMAT_RGB565; 161 else if (conf->AlphaSize == 0) 162 dri2_surf->format = WL_SHM_FORMAT_XRGB8888; 163 else 164 dri2_surf->format = WL_SHM_FORMAT_ARGB8888; 165 } 166 167 if (!window) { 168 _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface"); 169 goto cleanup_surf; 170 } 171 172 dri2_surf->wl_win = window; 173 174 dri2_surf->wl_win->private = dri2_surf; 175 dri2_surf->wl_win->destroy_window_callback = destroy_window_callback; 176 177 dri2_surf->base.Width = -1; 178 dri2_surf->base.Height = -1; 179 180 config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, 181 dri2_surf->base.GLColorspace); 182 183 if (dri2_dpy->dri2) { 184 dri2_surf->wl_win->resize_callback = resize_callback; 185 186 createNewDrawable = dri2_dpy->dri2->createNewDrawable; 187 } else { 188 createNewDrawable = dri2_dpy->swrast->createNewDrawable; 189 } 190 191 dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config, 192 dri2_surf); 193 if (dri2_surf->dri_drawable == NULL) { 194 _eglError(EGL_BAD_ALLOC, "createNewDrawable"); 195 goto cleanup_surf; 196 } 197 198 dri2_wl_swap_interval(drv, disp, &dri2_surf->base, 199 dri2_dpy->default_swap_interval); 200 201 return &dri2_surf->base; 202 203 cleanup_surf: 204 free(dri2_surf); 205 206 return NULL; 207 } 208 209 static _EGLSurface * 210 dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, 211 _EGLConfig *conf, void *native_window, 212 const EGLint *attrib_list) 213 { 214 /* From the EGL_EXT_platform_wayland spec, version 3: 215 * 216 * It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy> 217 * that belongs to Wayland. Any such call fails and generates 218 * EGL_BAD_PARAMETER. 219 */ 220 _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on " 221 "Wayland"); 222 return NULL; 223 } 224 225 /** 226 * Called via eglDestroySurface(), drv->API.DestroySurface(). 227 */ 228 static EGLBoolean 229 dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) 230 { 231 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 232 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 233 int i; 234 235 (void) drv; 236 237 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 238 239 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 240 if (dri2_surf->color_buffers[i].wl_buffer) 241 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 242 if (dri2_surf->color_buffers[i].dri_image) 243 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); 244 if (dri2_surf->color_buffers[i].linear_copy) 245 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); 246 if (dri2_surf->color_buffers[i].data) 247 munmap(dri2_surf->color_buffers[i].data, 248 dri2_surf->color_buffers[i].data_size); 249 } 250 251 if (dri2_dpy->dri2) { 252 for (i = 0; i < __DRI_BUFFER_COUNT; i++) 253 if (dri2_surf->dri_buffers[i] && 254 dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT) 255 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 256 dri2_surf->dri_buffers[i]); 257 } 258 259 if (dri2_surf->throttle_callback) 260 wl_callback_destroy(dri2_surf->throttle_callback); 261 262 if (dri2_surf->wl_win) { 263 dri2_surf->wl_win->private = NULL; 264 dri2_surf->wl_win->resize_callback = NULL; 265 dri2_surf->wl_win->destroy_window_callback = NULL; 266 } 267 268 free(surf); 269 270 return EGL_TRUE; 271 } 272 273 static void 274 dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) 275 { 276 struct dri2_egl_display *dri2_dpy = 277 dri2_egl_display(dri2_surf->base.Resource.Display); 278 int i; 279 280 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 281 if (dri2_surf->color_buffers[i].wl_buffer && 282 !dri2_surf->color_buffers[i].locked) 283 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 284 if (dri2_surf->color_buffers[i].dri_image) 285 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); 286 if (dri2_surf->color_buffers[i].linear_copy) 287 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); 288 if (dri2_surf->color_buffers[i].data) 289 munmap(dri2_surf->color_buffers[i].data, 290 dri2_surf->color_buffers[i].data_size); 291 292 dri2_surf->color_buffers[i].wl_buffer = NULL; 293 dri2_surf->color_buffers[i].dri_image = NULL; 294 dri2_surf->color_buffers[i].linear_copy = NULL; 295 dri2_surf->color_buffers[i].data = NULL; 296 dri2_surf->color_buffers[i].locked = 0; 297 } 298 299 if (dri2_dpy->dri2) { 300 for (i = 0; i < __DRI_BUFFER_COUNT; i++) 301 if (dri2_surf->dri_buffers[i] && 302 dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT) 303 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, 304 dri2_surf->dri_buffers[i]); 305 } 306 } 307 308 static int 309 get_back_bo(struct dri2_egl_surface *dri2_surf) 310 { 311 struct dri2_egl_display *dri2_dpy = 312 dri2_egl_display(dri2_surf->base.Resource.Display); 313 int i, use_flags; 314 unsigned int dri_image_format; 315 316 /* currently supports three WL DRM formats, 317 * WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888, 318 * and WL_DRM_FORMAT_RGB565 319 */ 320 switch (dri2_surf->format) { 321 case WL_DRM_FORMAT_ARGB8888: 322 dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888; 323 break; 324 case WL_DRM_FORMAT_XRGB8888: 325 dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888; 326 break; 327 case WL_DRM_FORMAT_RGB565: 328 dri_image_format = __DRI_IMAGE_FORMAT_RGB565; 329 break; 330 default: 331 /* format is not supported */ 332 return -1; 333 } 334 335 /* There might be a buffer release already queued that wasn't processed */ 336 wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); 337 338 if (dri2_surf->back == NULL) { 339 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 340 /* Get an unlocked buffer, preferrably one with a dri_buffer 341 * already allocated. */ 342 if (dri2_surf->color_buffers[i].locked) 343 continue; 344 if (dri2_surf->back == NULL) 345 dri2_surf->back = &dri2_surf->color_buffers[i]; 346 else if (dri2_surf->back->dri_image == NULL) 347 dri2_surf->back = &dri2_surf->color_buffers[i]; 348 } 349 } 350 351 if (dri2_surf->back == NULL) 352 return -1; 353 354 use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER; 355 356 if (dri2_dpy->is_different_gpu && 357 dri2_surf->back->linear_copy == NULL) { 358 dri2_surf->back->linear_copy = 359 dri2_dpy->image->createImage(dri2_dpy->dri_screen, 360 dri2_surf->base.Width, 361 dri2_surf->base.Height, 362 dri_image_format, 363 use_flags | 364 __DRI_IMAGE_USE_LINEAR, 365 NULL); 366 if (dri2_surf->back->linear_copy == NULL) 367 return -1; 368 } 369 370 if (dri2_surf->back->dri_image == NULL) { 371 dri2_surf->back->dri_image = 372 dri2_dpy->image->createImage(dri2_dpy->dri_screen, 373 dri2_surf->base.Width, 374 dri2_surf->base.Height, 375 dri_image_format, 376 dri2_dpy->is_different_gpu ? 377 0 : use_flags, 378 NULL); 379 dri2_surf->back->age = 0; 380 } 381 if (dri2_surf->back->dri_image == NULL) 382 return -1; 383 384 dri2_surf->back->locked = 1; 385 386 return 0; 387 } 388 389 390 static void 391 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) 392 { 393 struct dri2_egl_display *dri2_dpy = 394 dri2_egl_display(dri2_surf->base.Resource.Display); 395 __DRIimage *image; 396 int name, pitch; 397 398 image = dri2_surf->back->dri_image; 399 400 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); 401 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); 402 403 buffer->attachment = __DRI_BUFFER_BACK_LEFT; 404 buffer->name = name; 405 buffer->pitch = pitch; 406 buffer->cpp = 4; 407 buffer->flags = 0; 408 } 409 410 static int 411 get_aux_bo(struct dri2_egl_surface *dri2_surf, 412 unsigned int attachment, unsigned int format, __DRIbuffer *buffer) 413 { 414 struct dri2_egl_display *dri2_dpy = 415 dri2_egl_display(dri2_surf->base.Resource.Display); 416 __DRIbuffer *b = dri2_surf->dri_buffers[attachment]; 417 418 if (b == NULL) { 419 b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, 420 attachment, format, 421 dri2_surf->base.Width, 422 dri2_surf->base.Height); 423 dri2_surf->dri_buffers[attachment] = b; 424 } 425 if (b == NULL) 426 return -1; 427 428 memcpy(buffer, b, sizeof *buffer); 429 430 return 0; 431 } 432 433 static int 434 update_buffers(struct dri2_egl_surface *dri2_surf) 435 { 436 struct dri2_egl_display *dri2_dpy = 437 dri2_egl_display(dri2_surf->base.Resource.Display); 438 int i; 439 440 if (dri2_surf->base.Width != dri2_surf->wl_win->width || 441 dri2_surf->base.Height != dri2_surf->wl_win->height) { 442 443 dri2_wl_release_buffers(dri2_surf); 444 445 dri2_surf->base.Width = dri2_surf->wl_win->width; 446 dri2_surf->base.Height = dri2_surf->wl_win->height; 447 dri2_surf->dx = dri2_surf->wl_win->dx; 448 dri2_surf->dy = dri2_surf->wl_win->dy; 449 } 450 451 if (get_back_bo(dri2_surf) < 0) { 452 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); 453 return -1; 454 } 455 456 /* If we have an extra unlocked buffer at this point, we had to do triple 457 * buffering for a while, but now can go back to just double buffering. 458 * That means we can free any unlocked buffer now. */ 459 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 460 if (!dri2_surf->color_buffers[i].locked && 461 dri2_surf->color_buffers[i].wl_buffer) { 462 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 463 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); 464 if (dri2_dpy->is_different_gpu) 465 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); 466 dri2_surf->color_buffers[i].wl_buffer = NULL; 467 dri2_surf->color_buffers[i].dri_image = NULL; 468 dri2_surf->color_buffers[i].linear_copy = NULL; 469 } 470 } 471 472 return 0; 473 } 474 475 static __DRIbuffer * 476 dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable, 477 int *width, int *height, 478 unsigned int *attachments, int count, 479 int *out_count, void *loaderPrivate) 480 { 481 struct dri2_egl_surface *dri2_surf = loaderPrivate; 482 int i, j; 483 484 if (update_buffers(dri2_surf) < 0) 485 return NULL; 486 487 for (i = 0, j = 0; i < 2 * count; i += 2, j++) { 488 switch (attachments[i]) { 489 case __DRI_BUFFER_BACK_LEFT: 490 back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]); 491 break; 492 default: 493 if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1], 494 &dri2_surf->buffers[j]) < 0) { 495 _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer"); 496 return NULL; 497 } 498 break; 499 } 500 } 501 502 *out_count = j; 503 if (j == 0) 504 return NULL; 505 506 *width = dri2_surf->base.Width; 507 *height = dri2_surf->base.Height; 508 509 return dri2_surf->buffers; 510 } 511 512 static __DRIbuffer * 513 dri2_wl_get_buffers(__DRIdrawable * driDrawable, 514 int *width, int *height, 515 unsigned int *attachments, int count, 516 int *out_count, void *loaderPrivate) 517 { 518 struct dri2_egl_surface *dri2_surf = loaderPrivate; 519 unsigned int *attachments_with_format; 520 __DRIbuffer *buffer; 521 unsigned int bpp; 522 523 int i; 524 525 switch (dri2_surf->format) { 526 case WL_DRM_FORMAT_ARGB8888: 527 case WL_DRM_FORMAT_XRGB8888: 528 bpp = 32; 529 break; 530 case WL_DRM_FORMAT_RGB565: 531 bpp = 16; 532 break; 533 default: 534 /* format is not supported */ 535 return NULL; 536 } 537 538 attachments_with_format = calloc(count, 2 * sizeof(unsigned int)); 539 if (!attachments_with_format) { 540 *out_count = 0; 541 return NULL; 542 } 543 544 for (i = 0; i < count; ++i) { 545 attachments_with_format[2*i] = attachments[i]; 546 attachments_with_format[2*i + 1] = bpp; 547 } 548 549 buffer = 550 dri2_wl_get_buffers_with_format(driDrawable, 551 width, height, 552 attachments_with_format, count, 553 out_count, loaderPrivate); 554 555 free(attachments_with_format); 556 557 return buffer; 558 } 559 560 static int 561 image_get_buffers(__DRIdrawable *driDrawable, 562 unsigned int format, 563 uint32_t *stamp, 564 void *loaderPrivate, 565 uint32_t buffer_mask, 566 struct __DRIimageList *buffers) 567 { 568 struct dri2_egl_surface *dri2_surf = loaderPrivate; 569 570 if (update_buffers(dri2_surf) < 0) 571 return 0; 572 573 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; 574 buffers->back = dri2_surf->back->dri_image; 575 576 return 1; 577 } 578 579 static void 580 dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 581 { 582 (void) driDrawable; 583 (void) loaderPrivate; 584 } 585 586 static const __DRIdri2LoaderExtension dri2_loader_extension = { 587 .base = { __DRI_DRI2_LOADER, 3 }, 588 589 .getBuffers = dri2_wl_get_buffers, 590 .flushFrontBuffer = dri2_wl_flush_front_buffer, 591 .getBuffersWithFormat = dri2_wl_get_buffers_with_format, 592 }; 593 594 static const __DRIimageLoaderExtension image_loader_extension = { 595 .base = { __DRI_IMAGE_LOADER, 1 }, 596 597 .getBuffers = image_get_buffers, 598 .flushFrontBuffer = dri2_wl_flush_front_buffer, 599 }; 600 601 static void 602 wayland_throttle_callback(void *data, 603 struct wl_callback *callback, 604 uint32_t time) 605 { 606 struct dri2_egl_surface *dri2_surf = data; 607 608 dri2_surf->throttle_callback = NULL; 609 wl_callback_destroy(callback); 610 } 611 612 static const struct wl_callback_listener throttle_listener = { 613 .done = wayland_throttle_callback 614 }; 615 616 static void 617 create_wl_buffer(struct dri2_egl_surface *dri2_surf) 618 { 619 struct dri2_egl_display *dri2_dpy = 620 dri2_egl_display(dri2_surf->base.Resource.Display); 621 __DRIimage *image; 622 int fd, stride, name; 623 624 if (dri2_surf->current->wl_buffer != NULL) 625 return; 626 627 if (dri2_dpy->is_different_gpu) { 628 image = dri2_surf->current->linear_copy; 629 } else { 630 image = dri2_surf->current->dri_image; 631 } 632 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) { 633 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd); 634 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); 635 636 dri2_surf->current->wl_buffer = 637 wl_drm_create_prime_buffer(dri2_dpy->wl_drm, 638 fd, 639 dri2_surf->base.Width, 640 dri2_surf->base.Height, 641 dri2_surf->format, 642 0, stride, 643 0, 0, 644 0, 0); 645 close(fd); 646 } else { 647 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); 648 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); 649 650 dri2_surf->current->wl_buffer = 651 wl_drm_create_buffer(dri2_dpy->wl_drm, 652 name, 653 dri2_surf->base.Width, 654 dri2_surf->base.Height, 655 stride, 656 dri2_surf->format); 657 } 658 659 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer, 660 dri2_dpy->wl_queue); 661 wl_buffer_add_listener(dri2_surf->current->wl_buffer, 662 &wl_buffer_listener, dri2_surf); 663 } 664 665 static EGLBoolean 666 try_damage_buffer(struct dri2_egl_surface *dri2_surf, 667 const EGLint *rects, 668 EGLint n_rects) 669 { 670 int i; 671 672 if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_win->surface) 673 < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) 674 return EGL_FALSE; 675 676 for (i = 0; i < n_rects; i++) { 677 const int *rect = &rects[i * 4]; 678 679 wl_surface_damage_buffer(dri2_surf->wl_win->surface, 680 rect[0], 681 dri2_surf->base.Height - rect[1] - rect[3], 682 rect[2], rect[3]); 683 } 684 return EGL_TRUE; 685 } 686 /** 687 * Called via eglSwapBuffers(), drv->API.SwapBuffers(). 688 */ 689 static EGLBoolean 690 dri2_wl_swap_buffers_with_damage(_EGLDriver *drv, 691 _EGLDisplay *disp, 692 _EGLSurface *draw, 693 const EGLint *rects, 694 EGLint n_rects) 695 { 696 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 697 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 698 int i; 699 700 while (dri2_surf->throttle_callback != NULL) 701 if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, 702 dri2_dpy->wl_queue) == -1) 703 return -1; 704 705 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) 706 if (dri2_surf->color_buffers[i].age > 0) 707 dri2_surf->color_buffers[i].age++; 708 709 /* Make sure we have a back buffer in case we're swapping without ever 710 * rendering. */ 711 if (get_back_bo(dri2_surf) < 0) { 712 _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); 713 return EGL_FALSE; 714 } 715 716 if (draw->SwapInterval > 0) { 717 dri2_surf->throttle_callback = 718 wl_surface_frame(dri2_surf->wl_win->surface); 719 wl_callback_add_listener(dri2_surf->throttle_callback, 720 &throttle_listener, dri2_surf); 721 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback, 722 dri2_dpy->wl_queue); 723 } 724 725 dri2_surf->back->age = 1; 726 dri2_surf->current = dri2_surf->back; 727 dri2_surf->back = NULL; 728 729 create_wl_buffer(dri2_surf); 730 731 wl_surface_attach(dri2_surf->wl_win->surface, 732 dri2_surf->current->wl_buffer, 733 dri2_surf->dx, dri2_surf->dy); 734 735 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 736 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 737 /* reset resize growing parameters */ 738 dri2_surf->dx = 0; 739 dri2_surf->dy = 0; 740 741 /* If the compositor doesn't support damage_buffer, we deliberately 742 * ignore the damage region and post maximum damage, due to 743 * https://bugs.freedesktop.org/78190 */ 744 if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects)) 745 wl_surface_damage(dri2_surf->wl_win->surface, 746 0, 0, INT32_MAX, INT32_MAX); 747 748 if (dri2_dpy->is_different_gpu) { 749 _EGLContext *ctx = _eglGetCurrentContext(); 750 struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); 751 dri2_dpy->image->blitImage(dri2_ctx->dri_context, 752 dri2_surf->current->linear_copy, 753 dri2_surf->current->dri_image, 754 0, 0, dri2_surf->base.Width, 755 dri2_surf->base.Height, 756 0, 0, dri2_surf->base.Width, 757 dri2_surf->base.Height, 0); 758 } 759 760 dri2_flush_drawable_for_swapbuffers(disp, draw); 761 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 762 763 wl_surface_commit(dri2_surf->wl_win->surface); 764 765 /* If we're not waiting for a frame callback then we'll at least throttle 766 * to a sync callback so that we always give a chance for the compositor to 767 * handle the commit and send a release event before checking for a free 768 * buffer */ 769 if (dri2_surf->throttle_callback == NULL) { 770 dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper); 771 wl_callback_add_listener(dri2_surf->throttle_callback, 772 &throttle_listener, dri2_surf); 773 } 774 775 wl_display_flush(dri2_dpy->wl_dpy); 776 777 return EGL_TRUE; 778 } 779 780 static EGLint 781 dri2_wl_query_buffer_age(_EGLDriver *drv, 782 _EGLDisplay *disp, _EGLSurface *surface) 783 { 784 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); 785 786 if (get_back_bo(dri2_surf) < 0) { 787 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); 788 return 0; 789 } 790 791 return dri2_surf->back->age; 792 } 793 794 static EGLBoolean 795 dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 796 { 797 return dri2_wl_swap_buffers_with_damage (drv, disp, draw, NULL, 0); 798 } 799 800 static struct wl_buffer * 801 dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv, 802 _EGLDisplay *disp, 803 _EGLImage *img) 804 { 805 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 806 struct dri2_egl_image *dri2_img = dri2_egl_image(img); 807 __DRIimage *image = dri2_img->dri_image; 808 struct wl_buffer *buffer; 809 int width, height, format, pitch; 810 enum wl_drm_format wl_format; 811 812 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format); 813 814 switch (format) { 815 case __DRI_IMAGE_FORMAT_ARGB8888: 816 if (!(dri2_dpy->formats & HAS_ARGB8888)) 817 goto bad_format; 818 wl_format = WL_DRM_FORMAT_ARGB8888; 819 break; 820 case __DRI_IMAGE_FORMAT_XRGB8888: 821 if (!(dri2_dpy->formats & HAS_XRGB8888)) 822 goto bad_format; 823 wl_format = WL_DRM_FORMAT_XRGB8888; 824 break; 825 default: 826 goto bad_format; 827 } 828 829 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width); 830 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height); 831 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); 832 833 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) { 834 int fd; 835 836 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd); 837 838 buffer = 839 wl_drm_create_prime_buffer(dri2_dpy->wl_drm, 840 fd, 841 width, height, 842 wl_format, 843 0, pitch, 844 0, 0, 845 0, 0); 846 847 close(fd); 848 } else { 849 int name; 850 851 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); 852 853 buffer = 854 wl_drm_create_buffer(dri2_dpy->wl_drm, 855 name, 856 width, height, 857 pitch, 858 wl_format); 859 } 860 861 /* The buffer object will have been created with our internal event queue 862 * because it is using the wl_drm object as a proxy factory. We want the 863 * buffer to be used by the application so we'll reset it to the display's 864 * default event queue */ 865 if (buffer) 866 wl_proxy_set_queue((struct wl_proxy *) buffer, NULL); 867 868 return buffer; 869 870 bad_format: 871 _eglError(EGL_BAD_MATCH, "unsupported image format"); 872 return NULL; 873 } 874 875 static int 876 dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id) 877 { 878 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 879 int ret = 0; 880 881 if (dri2_dpy->is_render_node) { 882 _eglLog(_EGL_WARNING, "wayland-egl: client asks server to " 883 "authenticate for render-nodes"); 884 return 0; 885 } 886 dri2_dpy->authenticated = 0; 887 888 wl_drm_authenticate(dri2_dpy->wl_drm, id); 889 if (roundtrip(dri2_dpy) < 0) 890 ret = -1; 891 892 if (!dri2_dpy->authenticated) 893 ret = -1; 894 895 /* reset authenticated */ 896 dri2_dpy->authenticated = 1; 897 898 return ret; 899 } 900 901 static void 902 drm_handle_device(void *data, struct wl_drm *drm, const char *device) 903 { 904 struct dri2_egl_display *dri2_dpy = data; 905 drm_magic_t magic; 906 907 dri2_dpy->device_name = strdup(device); 908 if (!dri2_dpy->device_name) 909 return; 910 911 dri2_dpy->fd = loader_open_device(dri2_dpy->device_name); 912 if (dri2_dpy->fd == -1) { 913 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", 914 dri2_dpy->device_name, strerror(errno)); 915 return; 916 } 917 918 if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) { 919 dri2_dpy->authenticated = 1; 920 } else { 921 drmGetMagic(dri2_dpy->fd, &magic); 922 wl_drm_authenticate(dri2_dpy->wl_drm, magic); 923 } 924 } 925 926 static void 927 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 928 { 929 struct dri2_egl_display *dri2_dpy = data; 930 931 switch (format) { 932 case WL_DRM_FORMAT_ARGB8888: 933 dri2_dpy->formats |= HAS_ARGB8888; 934 break; 935 case WL_DRM_FORMAT_XRGB8888: 936 dri2_dpy->formats |= HAS_XRGB8888; 937 break; 938 case WL_DRM_FORMAT_RGB565: 939 dri2_dpy->formats |= HAS_RGB565; 940 break; 941 } 942 } 943 944 static void 945 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value) 946 { 947 struct dri2_egl_display *dri2_dpy = data; 948 949 dri2_dpy->capabilities = value; 950 } 951 952 static void 953 drm_handle_authenticated(void *data, struct wl_drm *drm) 954 { 955 struct dri2_egl_display *dri2_dpy = data; 956 957 dri2_dpy->authenticated = 1; 958 } 959 960 static const struct wl_drm_listener drm_listener = { 961 .device = drm_handle_device, 962 .format = drm_handle_format, 963 .authenticated = drm_handle_authenticated, 964 .capabilities = drm_handle_capabilities 965 }; 966 967 static void 968 registry_handle_global_drm(void *data, struct wl_registry *registry, uint32_t name, 969 const char *interface, uint32_t version) 970 { 971 struct dri2_egl_display *dri2_dpy = data; 972 973 if (version > 1) 974 version = 2; 975 if (strcmp(interface, "wl_drm") == 0) { 976 dri2_dpy->wl_drm = 977 wl_registry_bind(registry, name, &wl_drm_interface, version); 978 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); 979 } 980 } 981 982 static void 983 registry_handle_global_remove(void *data, struct wl_registry *registry, 984 uint32_t name) 985 { 986 } 987 988 static const struct wl_registry_listener registry_listener_drm = { 989 .global = registry_handle_global_drm, 990 .global_remove = registry_handle_global_remove 991 }; 992 993 static EGLBoolean 994 dri2_wl_swap_interval(_EGLDriver *drv, 995 _EGLDisplay *disp, 996 _EGLSurface *surf, 997 EGLint interval) 998 { 999 if (interval > surf->Config->MaxSwapInterval) 1000 interval = surf->Config->MaxSwapInterval; 1001 else if (interval < surf->Config->MinSwapInterval) 1002 interval = surf->Config->MinSwapInterval; 1003 1004 surf->SwapInterval = interval; 1005 1006 return EGL_TRUE; 1007 } 1008 1009 static void 1010 dri2_wl_setup_swap_interval(struct dri2_egl_display *dri2_dpy) 1011 { 1012 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 1013 1014 /* We can't use values greater than 1 on Wayland because we are using the 1015 * frame callback to synchronise the frame and the only way we be sure to 1016 * get a frame callback is to attach a new buffer. Therefore we can't just 1017 * sit drawing nothing to wait until the next n frame callbacks */ 1018 1019 if (dri2_dpy->config) 1020 dri2_dpy->config->configQueryi(dri2_dpy->dri_screen, 1021 "vblank_mode", &vblank_mode); 1022 switch (vblank_mode) { 1023 case DRI_CONF_VBLANK_NEVER: 1024 dri2_dpy->min_swap_interval = 0; 1025 dri2_dpy->max_swap_interval = 0; 1026 dri2_dpy->default_swap_interval = 0; 1027 break; 1028 case DRI_CONF_VBLANK_ALWAYS_SYNC: 1029 dri2_dpy->min_swap_interval = 1; 1030 dri2_dpy->max_swap_interval = 1; 1031 dri2_dpy->default_swap_interval = 1; 1032 break; 1033 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 1034 dri2_dpy->min_swap_interval = 0; 1035 dri2_dpy->max_swap_interval = 1; 1036 dri2_dpy->default_swap_interval = 0; 1037 break; 1038 default: 1039 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 1040 dri2_dpy->min_swap_interval = 0; 1041 dri2_dpy->max_swap_interval = 1; 1042 dri2_dpy->default_swap_interval = 1; 1043 break; 1044 } 1045 } 1046 1047 static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { 1048 .authenticate = dri2_wl_authenticate, 1049 .create_window_surface = dri2_wl_create_window_surface, 1050 .create_pixmap_surface = dri2_wl_create_pixmap_surface, 1051 .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface, 1052 .destroy_surface = dri2_wl_destroy_surface, 1053 .create_image = dri2_create_image_khr, 1054 .swap_interval = dri2_wl_swap_interval, 1055 .swap_buffers = dri2_wl_swap_buffers, 1056 .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage, 1057 .swap_buffers_region = dri2_fallback_swap_buffers_region, 1058 .post_sub_buffer = dri2_fallback_post_sub_buffer, 1059 .copy_buffers = dri2_fallback_copy_buffers, 1060 .query_buffer_age = dri2_wl_query_buffer_age, 1061 .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image, 1062 .get_sync_values = dri2_fallback_get_sync_values, 1063 .get_dri_drawable = dri2_surface_get_dri_drawable, 1064 }; 1065 1066 static const __DRIextension *dri2_loader_extensions[] = { 1067 &dri2_loader_extension.base, 1068 &image_loader_extension.base, 1069 &image_lookup_extension.base, 1070 &use_invalidate.base, 1071 NULL, 1072 }; 1073 1074 static const __DRIextension *image_loader_extensions[] = { 1075 &image_loader_extension.base, 1076 &image_lookup_extension.base, 1077 &use_invalidate.base, 1078 NULL, 1079 }; 1080 1081 static EGLBoolean 1082 dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) 1083 { 1084 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1085 static const struct { 1086 const char *format_name; 1087 int has_format; 1088 unsigned int rgba_masks[4]; 1089 } visuals[] = { 1090 { "XRGB8888", HAS_XRGB8888, { 0xff0000, 0xff00, 0x00ff, 0xff000000 } }, 1091 { "ARGB8888", HAS_ARGB8888, { 0xff0000, 0xff00, 0x00ff, 0 } }, 1092 { "RGB565", HAS_RGB565, { 0x00f800, 0x07e0, 0x001f, 0 } }, 1093 }; 1094 unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 }; 1095 unsigned int count, i, j; 1096 1097 count = 0; 1098 for (i = 0; dri2_dpy->driver_configs[i]; i++) { 1099 for (j = 0; j < ARRAY_SIZE(visuals); j++) { 1100 struct dri2_egl_config *dri2_conf; 1101 1102 if (!(dri2_dpy->formats & visuals[j].has_format)) 1103 continue; 1104 1105 dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], 1106 count + 1, EGL_WINDOW_BIT, NULL, visuals[j].rgba_masks); 1107 if (dri2_conf) { 1108 count++; 1109 format_count[j]++; 1110 } 1111 } 1112 } 1113 1114 for (i = 0; i < ARRAY_SIZE(format_count); i++) { 1115 if (!format_count[i]) { 1116 _eglLog(_EGL_DEBUG, "No DRI config supports native format %s", 1117 visuals[i].format_name); 1118 } 1119 } 1120 1121 return (count != 0); 1122 } 1123 1124 static EGLBoolean 1125 dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) 1126 { 1127 struct dri2_egl_display *dri2_dpy; 1128 1129 loader_set_logger(_eglLog); 1130 1131 dri2_dpy = calloc(1, sizeof *dri2_dpy); 1132 if (!dri2_dpy) 1133 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 1134 1135 disp->DriverData = (void *) dri2_dpy; 1136 if (disp->PlatformDisplay == NULL) { 1137 dri2_dpy->wl_dpy = wl_display_connect(NULL); 1138 if (dri2_dpy->wl_dpy == NULL) 1139 goto cleanup_dpy; 1140 dri2_dpy->own_device = 1; 1141 } else { 1142 dri2_dpy->wl_dpy = disp->PlatformDisplay; 1143 } 1144 1145 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); 1146 1147 dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy); 1148 if (dri2_dpy->wl_dpy_wrapper == NULL) 1149 goto cleanup_dpy_wrapper; 1150 1151 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper, 1152 dri2_dpy->wl_queue); 1153 1154 if (dri2_dpy->own_device) 1155 wl_display_dispatch_pending(dri2_dpy->wl_dpy); 1156 1157 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper); 1158 wl_registry_add_listener(dri2_dpy->wl_registry, 1159 ®istry_listener_drm, dri2_dpy); 1160 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL) 1161 goto cleanup_registry; 1162 1163 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1) 1164 goto cleanup_drm; 1165 1166 if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated) 1167 goto cleanup_fd; 1168 1169 dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, 1170 &dri2_dpy->is_different_gpu); 1171 if (dri2_dpy->is_different_gpu) { 1172 free(dri2_dpy->device_name); 1173 dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd); 1174 if (!dri2_dpy->device_name) { 1175 _eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name " 1176 "for requested GPU"); 1177 goto cleanup_fd; 1178 } 1179 } 1180 1181 /* we have to do the check now, because loader_get_user_preferred_fd 1182 * will return a render-node when the requested gpu is different 1183 * to the server, but also if the client asks for the same gpu than 1184 * the server by requesting its pci-id */ 1185 dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER; 1186 1187 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); 1188 if (dri2_dpy->driver_name == NULL) { 1189 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); 1190 goto cleanup_fd; 1191 } 1192 1193 if (!dri2_load_driver(disp)) 1194 goto cleanup_driver_name; 1195 1196 /* render nodes cannot use Gem names, and thus do not support 1197 * the __DRI_DRI2_LOADER extension */ 1198 if (!dri2_dpy->is_render_node) 1199 dri2_dpy->loader_extensions = dri2_loader_extensions; 1200 else 1201 dri2_dpy->loader_extensions = image_loader_extensions; 1202 1203 if (!dri2_create_screen(disp)) 1204 goto cleanup_driver; 1205 1206 dri2_wl_setup_swap_interval(dri2_dpy); 1207 1208 /* To use Prime, we must have _DRI_IMAGE v7 at least. 1209 * createImageFromFds support indicates that Prime export/import 1210 * is supported by the driver. Fall back to 1211 * gem names if we don't have Prime support. */ 1212 1213 if (dri2_dpy->image->base.version < 7 || 1214 dri2_dpy->image->createImageFromFds == NULL) 1215 dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME; 1216 1217 /* We cannot use Gem names with render-nodes, only prime fds (dma-buf). 1218 * The server needs to accept them */ 1219 if (dri2_dpy->is_render_node && 1220 !(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) { 1221 _eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable"); 1222 goto cleanup_screen; 1223 } 1224 1225 if (dri2_dpy->is_different_gpu && 1226 (dri2_dpy->image->base.version < 9 || 1227 dri2_dpy->image->blitImage == NULL)) { 1228 _eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the " 1229 "Image extension in the driver is not " 1230 "compatible. Version 9 or later and blitImage() " 1231 "are required"); 1232 goto cleanup_screen; 1233 } 1234 1235 if (!dri2_wl_add_configs_for_visuals(drv, disp)) { 1236 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); 1237 goto cleanup_screen; 1238 } 1239 1240 dri2_set_WL_bind_wayland_display(drv, disp); 1241 /* When cannot convert EGLImage to wl_buffer when on a different gpu, 1242 * because the buffer of the EGLImage has likely a tiling mode the server 1243 * gpu won't support. These is no way to check for now. Thus do not support the 1244 * extension */ 1245 if (!dri2_dpy->is_different_gpu) { 1246 disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE; 1247 } else { 1248 dri2_wl_display_vtbl.create_wayland_buffer_from_image = 1249 dri2_fallback_create_wayland_buffer_from_image; 1250 } 1251 disp->Extensions.EXT_buffer_age = EGL_TRUE; 1252 1253 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; 1254 1255 /* Fill vtbl last to prevent accidentally calling virtual function during 1256 * initialization. 1257 */ 1258 dri2_dpy->vtbl = &dri2_wl_display_vtbl; 1259 1260 return EGL_TRUE; 1261 1262 cleanup_screen: 1263 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 1264 cleanup_driver: 1265 dlclose(dri2_dpy->driver); 1266 cleanup_driver_name: 1267 free(dri2_dpy->driver_name); 1268 cleanup_fd: 1269 close(dri2_dpy->fd); 1270 cleanup_drm: 1271 free(dri2_dpy->device_name); 1272 wl_drm_destroy(dri2_dpy->wl_drm); 1273 cleanup_registry: 1274 wl_registry_destroy(dri2_dpy->wl_registry); 1275 wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper); 1276 cleanup_dpy_wrapper: 1277 wl_event_queue_destroy(dri2_dpy->wl_queue); 1278 if (disp->PlatformDisplay == NULL) 1279 wl_display_disconnect(dri2_dpy->wl_dpy); 1280 cleanup_dpy: 1281 free(dri2_dpy); 1282 disp->DriverData = NULL; 1283 1284 return EGL_FALSE; 1285 } 1286 1287 static int 1288 dri2_wl_swrast_get_stride_for_format(int format, int w) 1289 { 1290 if (format == WL_SHM_FORMAT_RGB565) 1291 return 2 * w; 1292 else /* ARGB8888 || XRGB8888 */ 1293 return 4 * w; 1294 } 1295 1296 /* 1297 * Taken from weston shared/os-compatibility.c 1298 */ 1299 1300 #ifndef HAVE_MKOSTEMP 1301 1302 static int 1303 set_cloexec_or_close(int fd) 1304 { 1305 long flags; 1306 1307 if (fd == -1) 1308 return -1; 1309 1310 flags = fcntl(fd, F_GETFD); 1311 if (flags == -1) 1312 goto err; 1313 1314 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) 1315 goto err; 1316 1317 return fd; 1318 1319 err: 1320 close(fd); 1321 return -1; 1322 } 1323 1324 #endif 1325 1326 /* 1327 * Taken from weston shared/os-compatibility.c 1328 */ 1329 1330 static int 1331 create_tmpfile_cloexec(char *tmpname) 1332 { 1333 int fd; 1334 1335 #ifdef HAVE_MKOSTEMP 1336 fd = mkostemp(tmpname, O_CLOEXEC); 1337 if (fd >= 0) 1338 unlink(tmpname); 1339 #else 1340 fd = mkstemp(tmpname); 1341 if (fd >= 0) { 1342 fd = set_cloexec_or_close(fd); 1343 unlink(tmpname); 1344 } 1345 #endif 1346 1347 return fd; 1348 } 1349 1350 /* 1351 * Taken from weston shared/os-compatibility.c 1352 * 1353 * Create a new, unique, anonymous file of the given size, and 1354 * return the file descriptor for it. The file descriptor is set 1355 * CLOEXEC. The file is immediately suitable for mmap()'ing 1356 * the given size at offset zero. 1357 * 1358 * The file should not have a permanent backing store like a disk, 1359 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. 1360 * 1361 * The file name is deleted from the file system. 1362 * 1363 * The file is suitable for buffer sharing between processes by 1364 * transmitting the file descriptor over Unix sockets using the 1365 * SCM_RIGHTS methods. 1366 * 1367 * If the C library implements posix_fallocate(), it is used to 1368 * guarantee that disk space is available for the file at the 1369 * given size. If disk space is insufficent, errno is set to ENOSPC. 1370 * If posix_fallocate() is not supported, program may receive 1371 * SIGBUS on accessing mmap()'ed file contents instead. 1372 */ 1373 static int 1374 os_create_anonymous_file(off_t size) 1375 { 1376 static const char template[] = "/mesa-shared-XXXXXX"; 1377 const char *path; 1378 char *name; 1379 int fd; 1380 int ret; 1381 1382 path = getenv("XDG_RUNTIME_DIR"); 1383 if (!path) { 1384 errno = ENOENT; 1385 return -1; 1386 } 1387 1388 name = malloc(strlen(path) + sizeof(template)); 1389 if (!name) 1390 return -1; 1391 1392 strcpy(name, path); 1393 strcat(name, template); 1394 1395 fd = create_tmpfile_cloexec(name); 1396 1397 free(name); 1398 1399 if (fd < 0) 1400 return -1; 1401 1402 ret = ftruncate(fd, size); 1403 if (ret < 0) { 1404 close(fd); 1405 return -1; 1406 } 1407 1408 return fd; 1409 } 1410 1411 1412 static EGLBoolean 1413 dri2_wl_swrast_allocate_buffer(struct dri2_egl_display *dri2_dpy, 1414 int format, int w, int h, 1415 void **data, int *size, 1416 struct wl_buffer **buffer) 1417 { 1418 struct wl_shm_pool *pool; 1419 int fd, stride, size_map; 1420 void *data_map; 1421 1422 stride = dri2_wl_swrast_get_stride_for_format(format, w); 1423 size_map = h * stride; 1424 1425 /* Create a sharable buffer */ 1426 fd = os_create_anonymous_file(size_map); 1427 if (fd < 0) 1428 return EGL_FALSE; 1429 1430 data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 1431 if (data_map == MAP_FAILED) { 1432 close(fd); 1433 return EGL_FALSE; 1434 } 1435 1436 /* Share it in a wl_buffer */ 1437 pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map); 1438 *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format); 1439 wl_shm_pool_destroy(pool); 1440 close(fd); 1441 1442 *data = data_map; 1443 *size = size_map; 1444 return EGL_TRUE; 1445 } 1446 1447 static int 1448 swrast_update_buffers(struct dri2_egl_surface *dri2_surf) 1449 { 1450 struct dri2_egl_display *dri2_dpy = 1451 dri2_egl_display(dri2_surf->base.Resource.Display); 1452 int i; 1453 1454 /* we need to do the following operations only once per frame */ 1455 if (dri2_surf->back) 1456 return 0; 1457 1458 if (dri2_surf->base.Width != dri2_surf->wl_win->width || 1459 dri2_surf->base.Height != dri2_surf->wl_win->height) { 1460 1461 dri2_wl_release_buffers(dri2_surf); 1462 1463 dri2_surf->base.Width = dri2_surf->wl_win->width; 1464 dri2_surf->base.Height = dri2_surf->wl_win->height; 1465 dri2_surf->dx = dri2_surf->wl_win->dx; 1466 dri2_surf->dy = dri2_surf->wl_win->dy; 1467 dri2_surf->current = NULL; 1468 } 1469 1470 /* find back buffer */ 1471 1472 /* There might be a buffer release already queued that wasn't processed */ 1473 wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); 1474 1475 /* try get free buffer already created */ 1476 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 1477 if (!dri2_surf->color_buffers[i].locked && 1478 dri2_surf->color_buffers[i].wl_buffer) { 1479 dri2_surf->back = &dri2_surf->color_buffers[i]; 1480 break; 1481 } 1482 } 1483 1484 /* else choose any another free location */ 1485 if (!dri2_surf->back) { 1486 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 1487 if (!dri2_surf->color_buffers[i].locked) { 1488 dri2_surf->back = &dri2_surf->color_buffers[i]; 1489 if (!dri2_wl_swrast_allocate_buffer(dri2_dpy, 1490 dri2_surf->format, 1491 dri2_surf->base.Width, 1492 dri2_surf->base.Height, 1493 &dri2_surf->back->data, 1494 &dri2_surf->back->data_size, 1495 &dri2_surf->back->wl_buffer)) { 1496 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); 1497 return -1; 1498 } 1499 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->back->wl_buffer, 1500 dri2_dpy->wl_queue); 1501 wl_buffer_add_listener(dri2_surf->back->wl_buffer, 1502 &wl_buffer_listener, dri2_surf); 1503 break; 1504 } 1505 } 1506 } 1507 1508 if (!dri2_surf->back) { 1509 _eglError(EGL_BAD_ALLOC, "failed to find free buffer"); 1510 return -1; 1511 } 1512 1513 dri2_surf->back->locked = 1; 1514 1515 /* If we have an extra unlocked buffer at this point, we had to do triple 1516 * buffering for a while, but now can go back to just double buffering. 1517 * That means we can free any unlocked buffer now. */ 1518 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 1519 if (!dri2_surf->color_buffers[i].locked && 1520 dri2_surf->color_buffers[i].wl_buffer) { 1521 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 1522 munmap(dri2_surf->color_buffers[i].data, 1523 dri2_surf->color_buffers[i].data_size); 1524 dri2_surf->color_buffers[i].wl_buffer = NULL; 1525 dri2_surf->color_buffers[i].data = NULL; 1526 } 1527 } 1528 1529 return 0; 1530 } 1531 1532 static void* 1533 dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf) 1534 { 1535 /* if there has been a resize: */ 1536 if (!dri2_surf->current) 1537 return NULL; 1538 1539 return dri2_surf->current->data; 1540 } 1541 1542 static void* 1543 dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf) 1544 { 1545 assert(dri2_surf->back); 1546 return dri2_surf->back->data; 1547 } 1548 1549 static void 1550 dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf) 1551 { 1552 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 1553 1554 while (dri2_surf->throttle_callback != NULL) 1555 if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, 1556 dri2_dpy->wl_queue) == -1) 1557 return; 1558 1559 if (dri2_surf->base.SwapInterval > 0) { 1560 dri2_surf->throttle_callback = 1561 wl_surface_frame(dri2_surf->wl_win->surface); 1562 wl_callback_add_listener(dri2_surf->throttle_callback, 1563 &throttle_listener, dri2_surf); 1564 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback, 1565 dri2_dpy->wl_queue); 1566 } 1567 1568 dri2_surf->current = dri2_surf->back; 1569 dri2_surf->back = NULL; 1570 1571 wl_surface_attach(dri2_surf->wl_win->surface, 1572 dri2_surf->current->wl_buffer, 1573 dri2_surf->dx, dri2_surf->dy); 1574 1575 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 1576 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 1577 /* reset resize growing parameters */ 1578 dri2_surf->dx = 0; 1579 dri2_surf->dy = 0; 1580 1581 wl_surface_damage(dri2_surf->wl_win->surface, 1582 0, 0, INT32_MAX, INT32_MAX); 1583 wl_surface_commit(dri2_surf->wl_win->surface); 1584 1585 /* If we're not waiting for a frame callback then we'll at least throttle 1586 * to a sync callback so that we always give a chance for the compositor to 1587 * handle the commit and send a release event before checking for a free 1588 * buffer */ 1589 if (dri2_surf->throttle_callback == NULL) { 1590 dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper); 1591 wl_callback_add_listener(dri2_surf->throttle_callback, 1592 &throttle_listener, dri2_surf); 1593 } 1594 1595 wl_display_flush(dri2_dpy->wl_dpy); 1596 } 1597 1598 static void 1599 dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw, 1600 int *x, int *y, int *w, int *h, 1601 void *loaderPrivate) 1602 { 1603 struct dri2_egl_surface *dri2_surf = loaderPrivate; 1604 1605 (void) swrast_update_buffers(dri2_surf); 1606 *x = 0; 1607 *y = 0; 1608 *w = dri2_surf->base.Width; 1609 *h = dri2_surf->base.Height; 1610 } 1611 1612 static void 1613 dri2_wl_swrast_get_image(__DRIdrawable * read, 1614 int x, int y, int w, int h, 1615 char *data, void *loaderPrivate) 1616 { 1617 struct dri2_egl_surface *dri2_surf = loaderPrivate; 1618 int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); 1619 int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); 1620 int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width); 1621 int dst_stride = copy_width; 1622 char *src, *dst; 1623 1624 src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf); 1625 if (!src) { 1626 memset(data, 0, copy_width * h); 1627 return; 1628 } 1629 1630 assert(data != src); 1631 assert(copy_width <= src_stride); 1632 1633 src += x_offset; 1634 src += y * src_stride; 1635 dst = data; 1636 1637 if (copy_width > src_stride-x_offset) 1638 copy_width = src_stride-x_offset; 1639 if (h > dri2_surf->base.Height-y) 1640 h = dri2_surf->base.Height-y; 1641 1642 for (; h>0; h--) { 1643 memcpy(dst, src, copy_width); 1644 src += src_stride; 1645 dst += dst_stride; 1646 } 1647 } 1648 1649 static void 1650 dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op, 1651 int x, int y, int w, int h, int stride, 1652 char *data, void *loaderPrivate) 1653 { 1654 struct dri2_egl_surface *dri2_surf = loaderPrivate; 1655 int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); 1656 int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width); 1657 int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); 1658 char *src, *dst; 1659 1660 assert(copy_width <= stride); 1661 1662 (void) swrast_update_buffers(dri2_surf); 1663 dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf); 1664 1665 /* partial copy, copy old content */ 1666 if (copy_width < dst_stride) 1667 dri2_wl_swrast_get_image(draw, 0, 0, 1668 dri2_surf->base.Width, dri2_surf->base.Height, 1669 dst, loaderPrivate); 1670 1671 dst += x_offset; 1672 dst += y * dst_stride; 1673 1674 src = data; 1675 1676 /* drivers expect we do these checks (and some rely on it) */ 1677 if (copy_width > dst_stride-x_offset) 1678 copy_width = dst_stride-x_offset; 1679 if (h > dri2_surf->base.Height-y) 1680 h = dri2_surf->base.Height-y; 1681 1682 for (; h>0; h--) { 1683 memcpy(dst, src, copy_width); 1684 src += stride; 1685 dst += dst_stride; 1686 } 1687 dri2_wl_swrast_commit_backbuffer(dri2_surf); 1688 } 1689 1690 static void 1691 dri2_wl_swrast_put_image(__DRIdrawable * draw, int op, 1692 int x, int y, int w, int h, 1693 char *data, void *loaderPrivate) 1694 { 1695 struct dri2_egl_surface *dri2_surf = loaderPrivate; 1696 int stride; 1697 1698 stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); 1699 dri2_wl_swrast_put_image2(draw, op, x, y, w, h, 1700 stride, data, loaderPrivate); 1701 } 1702 1703 static EGLBoolean 1704 dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 1705 { 1706 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1707 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 1708 1709 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); 1710 return EGL_TRUE; 1711 } 1712 1713 static void 1714 shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) 1715 { 1716 struct dri2_egl_display *dri2_dpy = data; 1717 1718 switch (format) { 1719 case WL_SHM_FORMAT_ARGB8888: 1720 dri2_dpy->formats |= HAS_ARGB8888; 1721 break; 1722 case WL_SHM_FORMAT_XRGB8888: 1723 dri2_dpy->formats |= HAS_XRGB8888; 1724 break; 1725 case WL_SHM_FORMAT_RGB565: 1726 dri2_dpy->formats |= HAS_RGB565; 1727 break; 1728 } 1729 } 1730 1731 static const struct wl_shm_listener shm_listener = { 1732 .format = shm_handle_format 1733 }; 1734 1735 static void 1736 registry_handle_global_swrast(void *data, struct wl_registry *registry, uint32_t name, 1737 const char *interface, uint32_t version) 1738 { 1739 struct dri2_egl_display *dri2_dpy = data; 1740 1741 if (strcmp(interface, "wl_shm") == 0) { 1742 dri2_dpy->wl_shm = 1743 wl_registry_bind(registry, name, &wl_shm_interface, 1); 1744 wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy); 1745 } 1746 } 1747 1748 static const struct wl_registry_listener registry_listener_swrast = { 1749 .global = registry_handle_global_swrast, 1750 .global_remove = registry_handle_global_remove 1751 }; 1752 1753 static struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = { 1754 .authenticate = NULL, 1755 .create_window_surface = dri2_wl_create_window_surface, 1756 .create_pixmap_surface = dri2_wl_create_pixmap_surface, 1757 .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface, 1758 .destroy_surface = dri2_wl_destroy_surface, 1759 .create_image = dri2_fallback_create_image_khr, 1760 .swap_interval = dri2_wl_swap_interval, 1761 .swap_buffers = dri2_wl_swrast_swap_buffers, 1762 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage, 1763 .swap_buffers_region = dri2_fallback_swap_buffers_region, 1764 .post_sub_buffer = dri2_fallback_post_sub_buffer, 1765 .copy_buffers = dri2_fallback_copy_buffers, 1766 .query_buffer_age = dri2_fallback_query_buffer_age, 1767 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image, 1768 .get_sync_values = dri2_fallback_get_sync_values, 1769 .get_dri_drawable = dri2_surface_get_dri_drawable, 1770 }; 1771 1772 static const __DRIswrastLoaderExtension swrast_loader_extension = { 1773 .base = { __DRI_SWRAST_LOADER, 2 }, 1774 1775 .getDrawableInfo = dri2_wl_swrast_get_drawable_info, 1776 .putImage = dri2_wl_swrast_put_image, 1777 .getImage = dri2_wl_swrast_get_image, 1778 .putImage2 = dri2_wl_swrast_put_image2, 1779 }; 1780 1781 static const __DRIextension *swrast_loader_extensions[] = { 1782 &swrast_loader_extension.base, 1783 NULL, 1784 }; 1785 1786 static EGLBoolean 1787 dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) 1788 { 1789 struct dri2_egl_display *dri2_dpy; 1790 1791 loader_set_logger(_eglLog); 1792 1793 dri2_dpy = calloc(1, sizeof *dri2_dpy); 1794 if (!dri2_dpy) 1795 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 1796 1797 disp->DriverData = (void *) dri2_dpy; 1798 if (disp->PlatformDisplay == NULL) { 1799 dri2_dpy->wl_dpy = wl_display_connect(NULL); 1800 if (dri2_dpy->wl_dpy == NULL) 1801 goto cleanup_dpy; 1802 dri2_dpy->own_device = 1; 1803 } else { 1804 dri2_dpy->wl_dpy = disp->PlatformDisplay; 1805 } 1806 1807 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); 1808 1809 dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy); 1810 if (dri2_dpy->wl_dpy_wrapper == NULL) 1811 goto cleanup_dpy_wrapper; 1812 1813 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper, 1814 dri2_dpy->wl_queue); 1815 1816 if (dri2_dpy->own_device) 1817 wl_display_dispatch_pending(dri2_dpy->wl_dpy); 1818 1819 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper); 1820 wl_registry_add_listener(dri2_dpy->wl_registry, 1821 ®istry_listener_swrast, dri2_dpy); 1822 1823 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL) 1824 goto cleanup_registry; 1825 1826 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0) 1827 goto cleanup_shm; 1828 1829 dri2_dpy->fd = -1; 1830 dri2_dpy->driver_name = strdup("swrast"); 1831 if (!dri2_load_driver_swrast(disp)) 1832 goto cleanup_shm; 1833 1834 dri2_dpy->loader_extensions = swrast_loader_extensions; 1835 1836 if (!dri2_create_screen(disp)) 1837 goto cleanup_driver; 1838 1839 dri2_wl_setup_swap_interval(dri2_dpy); 1840 1841 if (!dri2_wl_add_configs_for_visuals(drv, disp)) { 1842 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); 1843 goto cleanup_screen; 1844 } 1845 1846 /* Fill vtbl last to prevent accidentally calling virtual function during 1847 * initialization. 1848 */ 1849 dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl; 1850 1851 return EGL_TRUE; 1852 1853 cleanup_screen: 1854 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 1855 cleanup_driver: 1856 dlclose(dri2_dpy->driver); 1857 cleanup_shm: 1858 wl_shm_destroy(dri2_dpy->wl_shm); 1859 cleanup_registry: 1860 wl_registry_destroy(dri2_dpy->wl_registry); 1861 wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper); 1862 cleanup_dpy_wrapper: 1863 wl_event_queue_destroy(dri2_dpy->wl_queue); 1864 if (disp->PlatformDisplay == NULL) 1865 wl_display_disconnect(dri2_dpy->wl_dpy); 1866 cleanup_dpy: 1867 free(dri2_dpy); 1868 disp->DriverData = NULL; 1869 1870 return EGL_FALSE; 1871 } 1872 1873 EGLBoolean 1874 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) 1875 { 1876 EGLBoolean initialized = EGL_TRUE; 1877 1878 int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); 1879 1880 if (hw_accel) { 1881 if (!dri2_initialize_wayland_drm(drv, disp)) { 1882 initialized = dri2_initialize_wayland_swrast(drv, disp); 1883 } 1884 } else { 1885 initialized = dri2_initialize_wayland_swrast(drv, disp); 1886 } 1887 1888 return initialized; 1889 1890 } 1891