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