1/* 2 * Copyright © 2011 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Kristian Høgsberg <krh@bitplanet.net> 26 */ 27 28#include <stdbool.h> 29#include <stdint.h> 30#include <stdlib.h> 31#include <string.h> 32#include <stdio.h> 33#include <limits.h> 34#include <dlfcn.h> 35#include <fcntl.h> 36#include <errno.h> 37#include <unistd.h> 38#ifdef HAVE_LIBDRM 39#include <xf86drm.h> 40#endif 41#include <sys/types.h> 42#include <sys/stat.h> 43#include "util/debug.h" 44#include "util/macros.h" 45#include "util/bitscan.h" 46 47#include "egl_dri2.h" 48#include "loader.h" 49#include "kopper_interface.h" 50 51#ifdef HAVE_DRI3 52#include "platform_x11_dri3.h" 53#endif 54 55static EGLBoolean 56dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval); 57 58uint32_t 59dri2_format_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth); 60 61static void 62swrastCreateDrawable(struct dri2_egl_display * dri2_dpy, 63 struct dri2_egl_surface * dri2_surf) 64{ 65 uint32_t mask; 66 const uint32_t function = GXcopy; 67 uint32_t valgc[2]; 68 69 /* create GC's */ 70 dri2_surf->gc = xcb_generate_id(dri2_dpy->conn); 71 mask = XCB_GC_FUNCTION; 72 xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function); 73 74 dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn); 75 mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES; 76 valgc[0] = function; 77 valgc[1] = False; 78 xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc); 79 switch (dri2_surf->depth) { 80 case 32: 81 case 30: 82 case 24: 83 dri2_surf->bytes_per_pixel = 4; 84 break; 85 case 16: 86 dri2_surf->bytes_per_pixel = 2; 87 break; 88 case 8: 89 dri2_surf->bytes_per_pixel = 1; 90 break; 91 case 0: 92 dri2_surf->bytes_per_pixel = 0; 93 break; 94 default: 95 _eglLog(_EGL_WARNING, "unsupported depth %d", dri2_surf->depth); 96 } 97} 98 99static void 100swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy, 101 struct dri2_egl_surface * dri2_surf) 102{ 103 xcb_free_gc(dri2_dpy->conn, dri2_surf->gc); 104 xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc); 105} 106 107static bool 108x11_get_drawable_info(__DRIdrawable * draw, 109 int *x, int *y, int *w, int *h, 110 void *loaderPrivate) 111{ 112 struct dri2_egl_surface *dri2_surf = loaderPrivate; 113 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 114 115 xcb_get_geometry_cookie_t cookie; 116 xcb_get_geometry_reply_t *reply; 117 xcb_generic_error_t *error; 118 bool ret; 119 120 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable); 121 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error); 122 if (reply == NULL) 123 return false; 124 125 if (error != NULL) { 126 ret = false; 127 _eglLog(_EGL_WARNING, "error in xcb_get_geometry"); 128 free(error); 129 } else { 130 *x = reply->x; 131 *y = reply->y; 132 *w = reply->width; 133 *h = reply->height; 134 ret = true; 135 } 136 free(reply); 137 return ret; 138} 139 140static void 141swrastGetDrawableInfo(__DRIdrawable * draw, 142 int *x, int *y, int *w, int *h, 143 void *loaderPrivate) 144{ 145 *x = *y = *w = *h = 0; 146 x11_get_drawable_info(draw, x, y, w, h, loaderPrivate); 147} 148 149static void 150swrastPutImage(__DRIdrawable * draw, int op, 151 int x, int y, int w, int h, 152 char *data, void *loaderPrivate) 153{ 154 struct dri2_egl_surface *dri2_surf = loaderPrivate; 155 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 156 size_t hdr_len = sizeof(xcb_put_image_request_t); 157 int stride_b = dri2_surf->bytes_per_pixel * w; 158 size_t size = (hdr_len + stride_b * h) >> 2; 159 uint64_t max_req_len = xcb_get_maximum_request_length(dri2_dpy->conn); 160 161 xcb_gcontext_t gc; 162 xcb_void_cookie_t cookie; 163 switch (op) { 164 case __DRI_SWRAST_IMAGE_OP_DRAW: 165 gc = dri2_surf->gc; 166 break; 167 case __DRI_SWRAST_IMAGE_OP_SWAP: 168 gc = dri2_surf->swapgc; 169 break; 170 default: 171 return; 172 } 173 174 if (size < max_req_len) { 175 cookie = xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable, 176 gc, w, h, x, y, 0, dri2_surf->depth, 177 h * stride_b, (const uint8_t *)data); 178 xcb_discard_reply(dri2_dpy->conn, cookie.sequence); 179 } else { 180 int num_lines = ((max_req_len << 2) - hdr_len) / stride_b; 181 int y_start = 0; 182 int y_todo = h; 183 while (y_todo) { 184 int this_lines = MIN2(num_lines, y_todo); 185 cookie = xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable, 186 gc, w, this_lines, x, y_start, 0, dri2_surf->depth, 187 this_lines * stride_b, ((const uint8_t *)data + y_start * stride_b)); 188 xcb_discard_reply(dri2_dpy->conn, cookie.sequence); 189 y_start += this_lines; 190 y_todo -= this_lines; 191 } 192 } 193} 194 195static void 196swrastGetImage(__DRIdrawable * read, 197 int x, int y, int w, int h, 198 char *data, void *loaderPrivate) 199{ 200 struct dri2_egl_surface *dri2_surf = loaderPrivate; 201 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 202 203 xcb_get_image_cookie_t cookie; 204 xcb_get_image_reply_t *reply; 205 xcb_generic_error_t *error; 206 207 cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, 208 dri2_surf->drawable, x, y, w, h, ~0); 209 reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error); 210 if (reply == NULL) 211 return; 212 213 if (error != NULL) { 214 _eglLog(_EGL_WARNING, "error in xcb_get_image"); 215 free(error); 216 } else { 217 uint32_t bytes = xcb_get_image_data_length(reply); 218 uint8_t *idata = xcb_get_image_data(reply); 219 memcpy(data, idata, bytes); 220 } 221 free(reply); 222} 223 224 225static xcb_screen_t * 226get_xcb_screen(xcb_screen_iterator_t iter, int screen) 227{ 228 for (; iter.rem; --screen, xcb_screen_next(&iter)) 229 if (screen == 0) 230 return iter.data; 231 232 return NULL; 233} 234 235static xcb_visualtype_t * 236get_xcb_visualtype_for_depth(struct dri2_egl_display *dri2_dpy, int depth) 237{ 238 xcb_visualtype_iterator_t visual_iter; 239 xcb_screen_t *screen = dri2_dpy->screen; 240 xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen); 241 242 for (; depth_iter.rem; xcb_depth_next(&depth_iter)) { 243 if (depth_iter.data->depth != depth) 244 continue; 245 246 visual_iter = xcb_depth_visuals_iterator(depth_iter.data); 247 if (visual_iter.rem) 248 return visual_iter.data; 249 } 250 251 return NULL; 252} 253 254/* Get red channel mask for given depth. */ 255unsigned int 256dri2_x11_get_red_mask_for_depth(struct dri2_egl_display *dri2_dpy, int depth) 257{ 258 xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(dri2_dpy, depth); 259 260 if (visual) 261 return visual->red_mask; 262 263 return 0; 264} 265 266/** 267 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface(). 268 */ 269static _EGLSurface * 270dri2_x11_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf, 271 void *native_surface, const EGLint *attrib_list) 272{ 273 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 274 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 275 struct dri2_egl_surface *dri2_surf; 276 xcb_get_geometry_cookie_t cookie; 277 xcb_get_geometry_reply_t *reply; 278 xcb_generic_error_t *error; 279 const __DRIconfig *config; 280 281 dri2_surf = calloc(1, sizeof *dri2_surf); 282 if (!dri2_surf) { 283 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 284 return NULL; 285 } 286 287 if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list, 288 false, native_surface)) 289 goto cleanup_surf; 290 291 dri2_surf->region = XCB_NONE; 292 if (type == EGL_PBUFFER_BIT) { 293 dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn); 294 xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize, 295 dri2_surf->drawable, dri2_dpy->screen->root, 296 dri2_surf->base.Width, dri2_surf->base.Height); 297 } else { 298 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface)); 299 dri2_surf->drawable = (uintptr_t) native_surface; 300 } 301 302 config = dri2_get_dri_config(dri2_conf, type, 303 dri2_surf->base.GLColorspace); 304 305 if (!config) { 306 _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration"); 307 goto cleanup_pixmap; 308 } 309 310 if (type != EGL_PBUFFER_BIT) { 311 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable); 312 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error); 313 if (error != NULL) { 314 if (error->error_code == BadAlloc) 315 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry"); 316 else if (type == EGL_WINDOW_BIT) 317 _eglError(EGL_BAD_NATIVE_WINDOW, "xcb_get_geometry"); 318 else 319 _eglError(EGL_BAD_NATIVE_PIXMAP, "xcb_get_geometry"); 320 free(error); 321 free(reply); 322 goto cleanup_dri_drawable; 323 } else if (reply == NULL) { 324 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry"); 325 goto cleanup_dri_drawable; 326 } 327 328 dri2_surf->base.Width = reply->width; 329 dri2_surf->base.Height = reply->height; 330 dri2_surf->depth = reply->depth; 331 free(reply); 332 } 333 334 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf)) 335 goto cleanup_pixmap; 336 337 if (dri2_dpy->dri2) { 338 xcb_void_cookie_t cookie; 339 int conn_error; 340 341 cookie = xcb_dri2_create_drawable_checked(dri2_dpy->conn, 342 dri2_surf->drawable); 343 error = xcb_request_check(dri2_dpy->conn, cookie); 344 conn_error = xcb_connection_has_error(dri2_dpy->conn); 345 if (conn_error || error != NULL) { 346 if (type == EGL_PBUFFER_BIT || conn_error || error->error_code == BadAlloc) 347 _eglError(EGL_BAD_ALLOC, "xcb_dri2_create_drawable_checked"); 348 else if (type == EGL_WINDOW_BIT) 349 _eglError(EGL_BAD_NATIVE_WINDOW, 350 "xcb_dri2_create_drawable_checked"); 351 else 352 _eglError(EGL_BAD_NATIVE_PIXMAP, 353 "xcb_dri2_create_drawable_checked"); 354 free(error); 355 goto cleanup_dri_drawable; 356 } 357 } else { 358 if (type == EGL_PBUFFER_BIT) { 359 dri2_surf->depth = conf->BufferSize; 360 } 361 swrastCreateDrawable(dri2_dpy, dri2_surf); 362 } 363 364 /* we always copy the back buffer to front */ 365 dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE; 366 367 return &dri2_surf->base; 368 369 cleanup_dri_drawable: 370 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 371 cleanup_pixmap: 372 if (type == EGL_PBUFFER_BIT) 373 xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable); 374 cleanup_surf: 375 free(dri2_surf); 376 377 return NULL; 378} 379 380/** 381 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface(). 382 */ 383static _EGLSurface * 384dri2_x11_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, 385 void *native_window, const EGLint *attrib_list) 386{ 387 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 388 _EGLSurface *surf; 389 390 surf = dri2_x11_create_surface(disp, EGL_WINDOW_BIT, conf, 391 native_window, attrib_list); 392 if (surf != NULL) { 393 /* When we first create the DRI2 drawable, its swap interval on the 394 * server side is 1. 395 */ 396 surf->SwapInterval = 1; 397 398 /* Override that with a driconf-set value. */ 399 dri2_x11_swap_interval(disp, surf, dri2_dpy->default_swap_interval); 400 } 401 402 return surf; 403} 404 405static _EGLSurface * 406dri2_x11_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf, 407 void *native_pixmap, const EGLint *attrib_list) 408{ 409 return dri2_x11_create_surface(disp, EGL_PIXMAP_BIT, conf, 410 native_pixmap, attrib_list); 411} 412 413static _EGLSurface * 414dri2_x11_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf, 415 const EGLint *attrib_list) 416{ 417 return dri2_x11_create_surface(disp, EGL_PBUFFER_BIT, conf, 418 NULL, attrib_list); 419} 420 421static EGLBoolean 422dri2_x11_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) 423{ 424 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 425 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 426 427 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 428 429 if (dri2_dpy->dri2) { 430 xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable); 431 } else { 432 assert(dri2_dpy->swrast); 433 swrastDestroyDrawable(dri2_dpy, dri2_surf); 434 } 435 436 if (surf->Type == EGL_PBUFFER_BIT) 437 xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable); 438 439 dri2_fini_surface(surf); 440 free(surf); 441 442 return EGL_TRUE; 443} 444 445/** 446 * Function utilizes swrastGetDrawableInfo to get surface 447 * geometry from x server and calls default query surface 448 * implementation that returns the updated values. 449 * 450 * In case of errors we still return values that we currently 451 * have. 452 */ 453static EGLBoolean 454dri2_query_surface(_EGLDisplay *disp, _EGLSurface *surf, 455 EGLint attribute, EGLint *value) 456{ 457 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 458 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 459 int x, y, w, h; 460 461 __DRIdrawable *drawable = dri2_dpy->vtbl->get_dri_drawable(surf); 462 463 switch (attribute) { 464 case EGL_WIDTH: 465 case EGL_HEIGHT: 466 if (x11_get_drawable_info(drawable, &x, &y, &w, &h, dri2_surf)) { 467 surf->Width = w; 468 surf->Height = h; 469 } 470 break; 471 default: 472 break; 473 } 474 return _eglQuerySurface(disp, surf, attribute, value); 475} 476 477/** 478 * Process list of buffer received from the server 479 * 480 * Processes the list of buffers received in a reply from the server to either 481 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 482 */ 483static void 484dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf, 485 xcb_dri2_dri2_buffer_t *buffers, unsigned count) 486{ 487 struct dri2_egl_display *dri2_dpy = 488 dri2_egl_display(dri2_surf->base.Resource.Display); 489 xcb_rectangle_t rectangle; 490 491 dri2_surf->have_fake_front = false; 492 493 /* This assumes the DRI2 buffer attachment tokens matches the 494 * __DRIbuffer tokens. */ 495 for (unsigned i = 0; i < count; i++) { 496 dri2_surf->buffers[i].attachment = buffers[i].attachment; 497 dri2_surf->buffers[i].name = buffers[i].name; 498 dri2_surf->buffers[i].pitch = buffers[i].pitch; 499 dri2_surf->buffers[i].cpp = buffers[i].cpp; 500 dri2_surf->buffers[i].flags = buffers[i].flags; 501 502 /* We only use the DRI drivers single buffer configs. This 503 * means that if we try to render to a window, DRI2 will give us 504 * the fake front buffer, which we'll use as a back buffer. 505 * Note that EGL doesn't require that several clients rendering 506 * to the same window must see the same aux buffers. */ 507 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 508 dri2_surf->have_fake_front = true; 509 } 510 511 if (dri2_surf->region != XCB_NONE) 512 xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region); 513 514 rectangle.x = 0; 515 rectangle.y = 0; 516 rectangle.width = dri2_surf->base.Width; 517 rectangle.height = dri2_surf->base.Height; 518 dri2_surf->region = xcb_generate_id(dri2_dpy->conn); 519 xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle); 520} 521 522static __DRIbuffer * 523dri2_x11_get_buffers(__DRIdrawable * driDrawable, 524 int *width, int *height, 525 unsigned int *attachments, int count, 526 int *out_count, void *loaderPrivate) 527{ 528 struct dri2_egl_surface *dri2_surf = loaderPrivate; 529 struct dri2_egl_display *dri2_dpy = 530 dri2_egl_display(dri2_surf->base.Resource.Display); 531 xcb_dri2_dri2_buffer_t *buffers; 532 xcb_dri2_get_buffers_reply_t *reply; 533 xcb_dri2_get_buffers_cookie_t cookie; 534 535 (void) driDrawable; 536 537 cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn, 538 dri2_surf->drawable, 539 count, count, attachments); 540 reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL); 541 if (reply == NULL) 542 return NULL; 543 buffers = xcb_dri2_get_buffers_buffers (reply); 544 if (buffers == NULL) { 545 free(reply); 546 return NULL; 547 } 548 549 *out_count = reply->count; 550 dri2_surf->base.Width = *width = reply->width; 551 dri2_surf->base.Height = *height = reply->height; 552 dri2_x11_process_buffers(dri2_surf, buffers, *out_count); 553 554 free(reply); 555 556 return dri2_surf->buffers; 557} 558 559static __DRIbuffer * 560dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable, 561 int *width, int *height, 562 unsigned int *attachments, int count, 563 int *out_count, void *loaderPrivate) 564{ 565 struct dri2_egl_surface *dri2_surf = loaderPrivate; 566 struct dri2_egl_display *dri2_dpy = 567 dri2_egl_display(dri2_surf->base.Resource.Display); 568 xcb_dri2_dri2_buffer_t *buffers; 569 xcb_dri2_get_buffers_with_format_reply_t *reply; 570 xcb_dri2_get_buffers_with_format_cookie_t cookie; 571 xcb_dri2_attach_format_t *format_attachments; 572 573 (void) driDrawable; 574 575 format_attachments = (xcb_dri2_attach_format_t *) attachments; 576 cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn, 577 dri2_surf->drawable, 578 count, count, 579 format_attachments); 580 581 reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn, 582 cookie, NULL); 583 if (reply == NULL) 584 return NULL; 585 586 buffers = xcb_dri2_get_buffers_with_format_buffers (reply); 587 dri2_surf->base.Width = *width = reply->width; 588 dri2_surf->base.Height = *height = reply->height; 589 *out_count = reply->count; 590 dri2_x11_process_buffers(dri2_surf, buffers, *out_count); 591 592 free(reply); 593 594 return dri2_surf->buffers; 595} 596 597static void 598dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 599{ 600 (void) driDrawable; 601 602 /* FIXME: Does EGL support front buffer rendering at all? */ 603 604#if 0 605 struct dri2_egl_surface *dri2_surf = loaderPrivate; 606 607 dri2WaitGL(dri2_surf); 608#else 609 (void) loaderPrivate; 610#endif 611} 612 613static int 614dri2_x11_do_authenticate(struct dri2_egl_display *dri2_dpy, uint32_t id) 615{ 616 xcb_dri2_authenticate_reply_t *authenticate; 617 xcb_dri2_authenticate_cookie_t authenticate_cookie; 618 int ret = 0; 619 620 authenticate_cookie = 621 xcb_dri2_authenticate_unchecked(dri2_dpy->conn, dri2_dpy->screen->root, id); 622 authenticate = 623 xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL); 624 625 if (authenticate == NULL || !authenticate->authenticated) 626 ret = -1; 627 628 free(authenticate); 629 630 return ret; 631} 632 633static EGLBoolean 634dri2_x11_local_authenticate(struct dri2_egl_display *dri2_dpy) 635{ 636#ifdef HAVE_LIBDRM 637 drm_magic_t magic; 638 639 if (drmGetMagic(dri2_dpy->fd, &magic)) { 640 _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic"); 641 return EGL_FALSE; 642 } 643 644 if (dri2_x11_do_authenticate(dri2_dpy, magic) < 0) { 645 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate"); 646 return EGL_FALSE; 647 } 648#endif 649 return EGL_TRUE; 650} 651 652static EGLBoolean 653dri2_x11_connect(struct dri2_egl_display *dri2_dpy) 654{ 655 xcb_xfixes_query_version_reply_t *xfixes_query; 656 xcb_xfixes_query_version_cookie_t xfixes_query_cookie; 657 xcb_dri2_query_version_reply_t *dri2_query; 658 xcb_dri2_query_version_cookie_t dri2_query_cookie; 659 xcb_dri2_connect_reply_t *connect; 660 xcb_dri2_connect_cookie_t connect_cookie; 661 xcb_generic_error_t *error; 662 char *driver_name, *loader_driver_name, *device_name; 663 const xcb_query_extension_reply_t *extension; 664 665 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id); 666 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id); 667 668 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id); 669 if (!(extension && extension->present)) 670 return EGL_FALSE; 671 672 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id); 673 if (!(extension && extension->present)) 674 return EGL_FALSE; 675 676 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn, 677 XCB_XFIXES_MAJOR_VERSION, 678 XCB_XFIXES_MINOR_VERSION); 679 680 dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn, 681 XCB_DRI2_MAJOR_VERSION, 682 XCB_DRI2_MINOR_VERSION); 683 684 connect_cookie = xcb_dri2_connect_unchecked(dri2_dpy->conn, dri2_dpy->screen->root, 685 XCB_DRI2_DRIVER_TYPE_DRI); 686 687 xfixes_query = 688 xcb_xfixes_query_version_reply (dri2_dpy->conn, 689 xfixes_query_cookie, &error); 690 if (xfixes_query == NULL || 691 error != NULL || xfixes_query->major_version < 2) { 692 _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version"); 693 free(error); 694 free(xfixes_query); 695 return EGL_FALSE; 696 } 697 free(xfixes_query); 698 699 dri2_query = 700 xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error); 701 if (dri2_query == NULL || error != NULL) { 702 _eglLog(_EGL_WARNING, "DRI2: failed to query version"); 703 free(error); 704 free(dri2_query); 705 return EGL_FALSE; 706 } 707 dri2_dpy->dri2_major = dri2_query->major_version; 708 dri2_dpy->dri2_minor = dri2_query->minor_version; 709 free(dri2_query); 710 711 connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL); 712 if (connect == NULL || 713 connect->driver_name_length + connect->device_name_length == 0) { 714 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate"); 715 free(connect); 716 return EGL_FALSE; 717 } 718 719 device_name = xcb_dri2_connect_device_name (connect); 720 721 dri2_dpy->fd = loader_open_device(device_name); 722 if (dri2_dpy->fd == -1) { 723 _eglLog(_EGL_WARNING, 724 "DRI2: could not open %s (%s)", device_name, strerror(errno)); 725 free(connect); 726 return EGL_FALSE; 727 } 728 729 if (!dri2_x11_local_authenticate(dri2_dpy)) { 730 close(dri2_dpy->fd); 731 free(connect); 732 return EGL_FALSE; 733 } 734 735 driver_name = xcb_dri2_connect_driver_name (connect); 736 737 /* If Mesa knows about the appropriate driver for this fd, then trust it. 738 * Otherwise, default to the server's value. 739 */ 740 loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd); 741 if (loader_driver_name) { 742 dri2_dpy->driver_name = loader_driver_name; 743 } else { 744 dri2_dpy->driver_name = 745 strndup(driver_name, 746 xcb_dri2_connect_driver_name_length(connect)); 747 } 748 749 if (dri2_dpy->driver_name == NULL) { 750 close(dri2_dpy->fd); 751 free(connect); 752 return EGL_FALSE; 753 } 754 755#ifdef HAVE_WAYLAND_PLATFORM 756 dri2_dpy->device_name = 757 strndup(device_name, 758 xcb_dri2_connect_device_name_length(connect)); 759#endif 760 761 free(connect); 762 763 return EGL_TRUE; 764} 765 766static int 767dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id) 768{ 769 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 770 771 return dri2_x11_do_authenticate(dri2_dpy, id); 772} 773 774static EGLBoolean 775dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, 776 _EGLDisplay *disp, bool supports_preserved) 777{ 778 xcb_depth_iterator_t d; 779 xcb_visualtype_t *visuals; 780 int config_count = 0; 781 EGLint surface_type; 782 783 d = xcb_screen_allowed_depths_iterator(dri2_dpy->screen); 784 785 surface_type = 786 EGL_WINDOW_BIT | 787 EGL_PIXMAP_BIT | 788 EGL_PBUFFER_BIT; 789 790 if (supports_preserved) 791 surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 792 793 while (d.rem > 0) { 794 EGLBoolean class_added[6] = { 0, }; 795 796 visuals = xcb_depth_visuals(d.data); 797 798 for (int i = 0; i < xcb_depth_visuals_length(d.data); i++) { 799 if (class_added[visuals[i]._class]) 800 continue; 801 802 class_added[visuals[i]._class] = EGL_TRUE; 803 804 for (int j = 0; dri2_dpy->driver_configs[j]; j++) { 805 struct dri2_egl_config *dri2_conf; 806 const __DRIconfig *config = dri2_dpy->driver_configs[j]; 807 808 const EGLint config_attrs[] = { 809 EGL_NATIVE_VISUAL_ID, visuals[i].visual_id, 810 EGL_NATIVE_VISUAL_TYPE, visuals[i]._class, 811 EGL_NONE 812 }; 813 814 int rgba_shifts[4] = { 815 ffs(visuals[i].red_mask) - 1, 816 ffs(visuals[i].green_mask) - 1, 817 ffs(visuals[i].blue_mask) - 1, 818 -1, 819 }; 820 821 unsigned int rgba_sizes[4] = { 822 util_bitcount(visuals[i].red_mask), 823 util_bitcount(visuals[i].green_mask), 824 util_bitcount(visuals[i].blue_mask), 825 0, 826 }; 827 828 dri2_conf = dri2_add_config(disp, config, config_count + 1, 829 surface_type, config_attrs, 830 rgba_shifts, rgba_sizes); 831 if (dri2_conf) 832 if (dri2_conf->base.ConfigID == config_count + 1) 833 config_count++; 834 835 /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig. 836 * Ditto for 30-bit RGB visuals to match a 32-bit RGBA EGLConfig. 837 * Otherwise it will only match a 32-bit RGBA visual. On a 838 * composited window manager on X11, this will make all of the 839 * EGLConfigs with destination alpha get blended by the 840 * compositor. This is probably not what the application 841 * wants... especially on drivers that only have 32-bit RGBA 842 * EGLConfigs! */ 843 if (d.data->depth == 24 || d.data->depth == 30) { 844 unsigned int rgba_mask = ~(visuals[i].red_mask | 845 visuals[i].green_mask | 846 visuals[i].blue_mask); 847 rgba_shifts[3] = ffs(rgba_mask) - 1; 848 rgba_sizes[3] = util_bitcount(rgba_mask); 849 dri2_conf = dri2_add_config(disp, config, config_count + 1, 850 surface_type, config_attrs, 851 rgba_shifts, rgba_sizes); 852 if (dri2_conf) 853 if (dri2_conf->base.ConfigID == config_count + 1) 854 config_count++; 855 } 856 } 857 } 858 859 xcb_depth_next(&d); 860 } 861 862 if (!config_count) { 863 _eglLog(_EGL_WARNING, "DRI2: failed to create any config"); 864 return EGL_FALSE; 865 } 866 867 return EGL_TRUE; 868} 869 870static EGLBoolean 871dri2_copy_region(_EGLDisplay *disp, 872 _EGLSurface *draw, xcb_xfixes_region_t region) 873{ 874 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 875 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 876 enum xcb_dri2_attachment_t render_attachment; 877 xcb_dri2_copy_region_cookie_t cookie; 878 879 /* No-op for a pixmap or pbuffer surface */ 880 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT) 881 return EGL_TRUE; 882 883 if (dri2_dpy->flush) 884 dri2_dpy->flush->flush(dri2_surf->dri_drawable); 885 else 886 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); 887 888 if (dri2_surf->have_fake_front) 889 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT; 890 else 891 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT; 892 893 cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn, 894 dri2_surf->drawable, 895 region, 896 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT, 897 render_attachment); 898 free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL)); 899 900 return EGL_TRUE; 901} 902 903static int64_t 904dri2_x11_swap_buffers_msc(_EGLDisplay *disp, _EGLSurface *draw, 905 int64_t msc, int64_t divisor, int64_t remainder) 906{ 907 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 908 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 909 uint32_t msc_hi = msc >> 32; 910 uint32_t msc_lo = msc & 0xffffffff; 911 uint32_t divisor_hi = divisor >> 32; 912 uint32_t divisor_lo = divisor & 0xffffffff; 913 uint32_t remainder_hi = remainder >> 32; 914 uint32_t remainder_lo = remainder & 0xffffffff; 915 xcb_dri2_swap_buffers_cookie_t cookie; 916 xcb_dri2_swap_buffers_reply_t *reply; 917 int64_t swap_count = -1; 918 919 if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available) { 920 swap_count = dri2_copy_region(disp, draw, dri2_surf->region) ? 0 : -1; 921 } else { 922 dri2_flush_drawable_for_swapbuffers(disp, draw); 923 924 cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, 925 dri2_surf->drawable, msc_hi, 926 msc_lo, divisor_hi, divisor_lo, 927 remainder_hi, remainder_lo); 928 929 reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL); 930 931 if (reply) { 932 swap_count = combine_u32_into_u64(reply->swap_hi, reply->swap_lo); 933 free(reply); 934 } 935 } 936 937 /* Since we aren't watching for the server's invalidate events like we're 938 * supposed to (due to XCB providing no mechanism for filtering the events 939 * the way xlib does), and SwapBuffers is a common cause of invalidate 940 * events, just shove one down to the driver, even though we haven't told 941 * the driver that we're the kind of loader that provides reliable 942 * invalidate events. This causes the driver to request buffers again at 943 * its next draw, so that we get the correct buffers if a pageflip 944 * happened. The driver should still be using the viewport hack to catch 945 * window resizes. 946 */ 947 if (dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate) 948 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 949 950 return swap_count; 951} 952 953static EGLBoolean 954dri2_x11_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) 955{ 956 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 957 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 958 959 if (!dri2_dpy->flush) { 960 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); 961 return EGL_TRUE; 962 } 963 964 if (dri2_x11_swap_buffers_msc(disp, draw, 0, 0, 0) == -1) { 965 /* Swap failed with a window drawable. */ 966 return _eglError(EGL_BAD_NATIVE_WINDOW, __func__); 967 } 968 return EGL_TRUE; 969} 970 971static EGLBoolean 972dri2_x11_swap_buffers_region(_EGLDisplay *disp, _EGLSurface *draw, 973 EGLint numRects, const EGLint *rects) 974{ 975 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 976 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 977 EGLBoolean ret; 978 xcb_xfixes_region_t region; 979 xcb_rectangle_t rectangles[16]; 980 981 if (numRects > (int)ARRAY_SIZE(rectangles)) 982 return dri2_copy_region(disp, draw, dri2_surf->region); 983 984 for (int i = 0; i < numRects; i++) { 985 rectangles[i].x = rects[i * 4]; 986 rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3]; 987 rectangles[i].width = rects[i * 4 + 2]; 988 rectangles[i].height = rects[i * 4 + 3]; 989 } 990 991 region = xcb_generate_id(dri2_dpy->conn); 992 xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles); 993 ret = dri2_copy_region(disp, draw, region); 994 xcb_xfixes_destroy_region(dri2_dpy->conn, region); 995 996 return ret; 997} 998 999static EGLBoolean 1000dri2_x11_post_sub_buffer(_EGLDisplay *disp, _EGLSurface *draw, 1001 EGLint x, EGLint y, EGLint width, EGLint height) 1002{ 1003 const EGLint rect[4] = { x, y, width, height }; 1004 1005 if (x < 0 || y < 0 || width < 0 || height < 0) 1006 _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV"); 1007 1008 return dri2_x11_swap_buffers_region(disp, draw, 1, rect); 1009} 1010 1011static EGLBoolean 1012dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval) 1013{ 1014 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1015 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 1016 1017 if (dri2_dpy->kopper) { 1018 dri2_dpy->kopper->setSwapInterval(dri2_surf->dri_drawable, interval); 1019 return EGL_TRUE; 1020 } 1021 1022 if (dri2_dpy->swap_available) 1023 xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval); 1024 1025 return EGL_TRUE; 1026} 1027 1028static EGLBoolean 1029dri2_x11_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target) 1030{ 1031 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1032 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 1033 xcb_gcontext_t gc; 1034 xcb_pixmap_t target; 1035 1036 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target)); 1037 target = (uintptr_t) native_pixmap_target; 1038 1039 if (dri2_dpy->flush) 1040 dri2_dpy->flush->flush(dri2_surf->dri_drawable); 1041 else 1042 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); 1043 1044 gc = xcb_generate_id(dri2_dpy->conn); 1045 xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL); 1046 xcb_copy_area(dri2_dpy->conn, 1047 dri2_surf->drawable, 1048 target, 1049 gc, 1050 0, 0, 1051 0, 0, 1052 dri2_surf->base.Width, 1053 dri2_surf->base.Height); 1054 xcb_free_gc(dri2_dpy->conn, gc); 1055 1056 return EGL_TRUE; 1057} 1058 1059uint32_t 1060dri2_format_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth) 1061{ 1062 switch (depth) { 1063 case 16: 1064 return __DRI_IMAGE_FORMAT_RGB565; 1065 case 24: 1066 return __DRI_IMAGE_FORMAT_XRGB8888; 1067 case 30: 1068 /* Different preferred formats for different hw */ 1069 if (dri2_x11_get_red_mask_for_depth(dri2_dpy, 30) == 0x3ff) 1070 return __DRI_IMAGE_FORMAT_XBGR2101010; 1071 else 1072 return __DRI_IMAGE_FORMAT_XRGB2101010; 1073 case 32: 1074 return __DRI_IMAGE_FORMAT_ARGB8888; 1075 default: 1076 return __DRI_IMAGE_FORMAT_NONE; 1077 } 1078} 1079 1080static _EGLImage * 1081dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, 1082 EGLClientBuffer buffer, const EGLint *attr_list) 1083{ 1084 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1085 struct dri2_egl_image *dri2_img; 1086 unsigned int attachments[1]; 1087 xcb_drawable_t drawable; 1088 xcb_dri2_get_buffers_cookie_t buffers_cookie; 1089 xcb_dri2_get_buffers_reply_t *buffers_reply; 1090 xcb_dri2_dri2_buffer_t *buffers; 1091 xcb_get_geometry_cookie_t geometry_cookie; 1092 xcb_get_geometry_reply_t *geometry_reply; 1093 xcb_generic_error_t *error; 1094 int stride, format; 1095 1096 (void) ctx; 1097 1098 drawable = (xcb_drawable_t) (uintptr_t) buffer; 1099 xcb_dri2_create_drawable (dri2_dpy->conn, drawable); 1100 attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT; 1101 buffers_cookie = 1102 xcb_dri2_get_buffers_unchecked (dri2_dpy->conn, 1103 drawable, 1, 1, attachments); 1104 geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable); 1105 buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, 1106 buffers_cookie, NULL); 1107 if (buffers_reply == NULL) 1108 return NULL; 1109 1110 buffers = xcb_dri2_get_buffers_buffers (buffers_reply); 1111 if (buffers == NULL) { 1112 free(buffers_reply); 1113 return NULL; 1114 } 1115 1116 geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn, 1117 geometry_cookie, &error); 1118 if (geometry_reply == NULL || error != NULL) { 1119 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry"); 1120 free(error); 1121 free(buffers_reply); 1122 free(geometry_reply); 1123 return NULL; 1124 } 1125 1126 format = dri2_format_for_depth(dri2_dpy, geometry_reply->depth); 1127 if (format == __DRI_IMAGE_FORMAT_NONE) { 1128 _eglError(EGL_BAD_PARAMETER, 1129 "dri2_create_image_khr: unsupported pixmap depth"); 1130 free(buffers_reply); 1131 free(geometry_reply); 1132 return NULL; 1133 } 1134 1135 dri2_img = malloc(sizeof *dri2_img); 1136 if (!dri2_img) { 1137 free(buffers_reply); 1138 free(geometry_reply); 1139 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); 1140 return EGL_NO_IMAGE_KHR; 1141 } 1142 1143 _eglInitImage(&dri2_img->base, disp); 1144 1145 stride = buffers[0].pitch / buffers[0].cpp; 1146 dri2_img->dri_image = 1147 dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, 1148 buffers_reply->width, 1149 buffers_reply->height, 1150 format, 1151 buffers[0].name, 1152 stride, 1153 dri2_img); 1154 1155 free(buffers_reply); 1156 free(geometry_reply); 1157 1158 return &dri2_img->base; 1159} 1160 1161static _EGLImage * 1162dri2_x11_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target, 1163 EGLClientBuffer buffer, const EGLint *attr_list) 1164{ 1165 switch (target) { 1166 case EGL_NATIVE_PIXMAP_KHR: 1167 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list); 1168 default: 1169 return dri2_create_image_khr(disp, ctx, target, buffer, attr_list); 1170 } 1171} 1172 1173static EGLBoolean 1174dri2_x11_get_sync_values(_EGLDisplay *display, _EGLSurface *surface, 1175 EGLuint64KHR *ust, EGLuint64KHR *msc, 1176 EGLuint64KHR *sbc) 1177{ 1178 struct dri2_egl_display *dri2_dpy = dri2_egl_display(display); 1179 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); 1180 xcb_dri2_get_msc_cookie_t cookie; 1181 xcb_dri2_get_msc_reply_t *reply; 1182 1183 cookie = xcb_dri2_get_msc(dri2_dpy->conn, dri2_surf->drawable); 1184 reply = xcb_dri2_get_msc_reply(dri2_dpy->conn, cookie, NULL); 1185 1186 if (!reply) 1187 return _eglError(EGL_BAD_ACCESS, __func__); 1188 1189 *ust = ((EGLuint64KHR) reply->ust_hi << 32) | reply->ust_lo; 1190 *msc = ((EGLuint64KHR) reply->msc_hi << 32) | reply->msc_lo; 1191 *sbc = ((EGLuint64KHR) reply->sbc_hi << 32) | reply->sbc_lo; 1192 free(reply); 1193 1194 return EGL_TRUE; 1195} 1196 1197static EGLBoolean 1198dri2_kopper_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval) 1199{ 1200 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1201 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 1202 1203 /* This can legitimately be null for lavapipe */ 1204 if (dri2_dpy->kopper) 1205 dri2_dpy->kopper->setSwapInterval(dri2_surf->dri_drawable, interval); 1206 1207 return EGL_TRUE; 1208} 1209 1210static _EGLSurface * 1211dri2_kopper_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, 1212 void *native_window, 1213 const EGLint *attrib_list) 1214{ 1215 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1216 _EGLSurface *surf; 1217 1218 surf = dri2_x11_create_surface(disp, EGL_WINDOW_BIT, conf, 1219 native_window, attrib_list); 1220 if (surf != NULL) { 1221 /* When we first create the DRI2 drawable, its swap interval on the 1222 * server side is 1. 1223 */ 1224 surf->SwapInterval = 1; 1225 1226 /* Override that with a driconf-set value. */ 1227 dri2_kopper_swap_interval(disp, surf, dri2_dpy->default_swap_interval); 1228 } 1229 1230 return surf; 1231} 1232 1233static EGLint 1234dri2_kopper_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf) 1235{ 1236 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1237 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 1238 1239 /* This can legitimately be null for lavapipe */ 1240 if (dri2_dpy->kopper) 1241 return dri2_dpy->kopper->queryBufferAge(dri2_surf->dri_drawable); 1242 1243 return 0; 1244} 1245 1246static const struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = { 1247 .authenticate = NULL, 1248 .create_window_surface = dri2_x11_create_window_surface, 1249 .create_pixmap_surface = dri2_x11_create_pixmap_surface, 1250 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface, 1251 .destroy_surface = dri2_x11_destroy_surface, 1252 .create_image = dri2_create_image_khr, 1253 .swap_buffers = dri2_x11_swap_buffers, 1254 .swap_buffers_region = dri2_x11_swap_buffers_region, 1255 .post_sub_buffer = dri2_x11_post_sub_buffer, 1256 .copy_buffers = dri2_x11_copy_buffers, 1257 /* XXX: should really implement this since X11 has pixmaps */ 1258 .query_surface = dri2_query_surface, 1259 .get_dri_drawable = dri2_surface_get_dri_drawable, 1260}; 1261 1262static const struct dri2_egl_display_vtbl dri2_x11_kopper_display_vtbl = { 1263 .authenticate = NULL, 1264 .create_window_surface = dri2_kopper_create_window_surface, 1265 .create_pixmap_surface = dri2_x11_create_pixmap_surface, 1266 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface, 1267 .destroy_surface = dri2_x11_destroy_surface, 1268 .create_image = dri2_create_image_khr, 1269 .swap_interval = dri2_kopper_swap_interval, 1270 .swap_buffers = dri2_x11_swap_buffers, 1271 .swap_buffers_region = dri2_x11_swap_buffers_region, 1272 .post_sub_buffer = dri2_x11_post_sub_buffer, 1273 .copy_buffers = dri2_x11_copy_buffers, 1274 .query_buffer_age = dri2_kopper_query_buffer_age, 1275 /* XXX: should really implement this since X11 has pixmaps */ 1276 .query_surface = dri2_query_surface, 1277 .get_dri_drawable = dri2_surface_get_dri_drawable, 1278}; 1279 1280static const struct dri2_egl_display_vtbl dri2_x11_display_vtbl = { 1281 .authenticate = dri2_x11_authenticate, 1282 .create_window_surface = dri2_x11_create_window_surface, 1283 .create_pixmap_surface = dri2_x11_create_pixmap_surface, 1284 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface, 1285 .destroy_surface = dri2_x11_destroy_surface, 1286 .create_image = dri2_x11_create_image_khr, 1287 .swap_interval = dri2_x11_swap_interval, 1288 .swap_buffers = dri2_x11_swap_buffers, 1289 .swap_buffers_region = dri2_x11_swap_buffers_region, 1290 .post_sub_buffer = dri2_x11_post_sub_buffer, 1291 .copy_buffers = dri2_x11_copy_buffers, 1292 .query_surface = dri2_query_surface, 1293 .get_sync_values = dri2_x11_get_sync_values, 1294 .get_dri_drawable = dri2_surface_get_dri_drawable, 1295}; 1296 1297static const __DRIswrastLoaderExtension swrast_loader_extension = { 1298 .base = { __DRI_SWRAST_LOADER, 1 }, 1299 1300 .getDrawableInfo = swrastGetDrawableInfo, 1301 .putImage = swrastPutImage, 1302 .getImage = swrastGetImage, 1303}; 1304 1305static void 1306kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *ci) 1307{ 1308 struct dri2_egl_surface *dri2_surf = _draw; 1309 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 1310 1311 if (dri2_surf->base.Type != EGL_WINDOW_BIT) 1312 return; 1313 ci->xcb.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; 1314 ci->xcb.pNext = NULL; 1315 ci->xcb.flags = 0; 1316 ci->xcb.connection = dri2_dpy->conn; 1317 ci->xcb.window = dri2_surf->drawable; 1318 ci->has_alpha = dri2_surf->depth == 32; 1319} 1320 1321static const __DRIkopperLoaderExtension kopper_loader_extension = { 1322 .base = { __DRI_KOPPER_LOADER, 1 }, 1323 1324 .SetSurfaceCreateInfo = kopperSetSurfaceCreateInfo, 1325}; 1326 1327static const __DRIextension *swrast_loader_extensions[] = { 1328 &swrast_loader_extension.base, 1329 &image_lookup_extension.base, 1330 &kopper_loader_extension.base, 1331 NULL, 1332}; 1333 1334static int 1335dri2_find_screen_for_display(const _EGLDisplay *disp, int fallback_screen) 1336{ 1337 const EGLAttrib *attr; 1338 1339 if (!disp->Options.Attribs) 1340 return fallback_screen; 1341 1342 for (attr = disp->Options.Attribs; attr[0] != EGL_NONE; attr += 2) { 1343 if (attr[0] == EGL_PLATFORM_X11_SCREEN_EXT || 1344 attr[0] == EGL_PLATFORM_XCB_SCREEN_EXT) 1345 return attr[1]; 1346 } 1347 1348 return fallback_screen; 1349} 1350 1351static EGLBoolean 1352dri2_get_xcb_connection(_EGLDisplay *disp, 1353 struct dri2_egl_display *dri2_dpy) 1354{ 1355 xcb_screen_iterator_t s; 1356 int screen; 1357 const char *msg; 1358 1359 disp->DriverData = (void *) dri2_dpy; 1360 if (disp->PlatformDisplay == NULL) { 1361 dri2_dpy->conn = xcb_connect(NULL, &screen); 1362 dri2_dpy->own_device = true; 1363 screen = dri2_find_screen_for_display(disp, screen); 1364 } else if (disp->Platform == _EGL_PLATFORM_X11) { 1365 Display *dpy = disp->PlatformDisplay; 1366 dri2_dpy->conn = XGetXCBConnection(dpy); 1367 screen = DefaultScreen(dpy); 1368 } else { 1369 /* _EGL_PLATFORM_XCB */ 1370 dri2_dpy->conn = disp->PlatformDisplay; 1371 screen = dri2_find_screen_for_display(disp, 0); 1372 } 1373 1374 if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) { 1375 msg = "xcb_connect failed"; 1376 goto disconnect; 1377 } 1378 1379 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); 1380 dri2_dpy->screen = get_xcb_screen(s, screen); 1381 if (!dri2_dpy->screen) { 1382 msg = "failed to get xcb screen"; 1383 goto disconnect; 1384 } 1385 1386 return EGL_TRUE; 1387disconnect: 1388 if (disp->PlatformDisplay == NULL) 1389 xcb_disconnect(dri2_dpy->conn); 1390 1391 return _eglError(EGL_BAD_ALLOC, msg); 1392} 1393 1394static void 1395dri2_x11_setup_swap_interval(_EGLDisplay *disp) 1396{ 1397 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1398 int arbitrary_max_interval = 1000; 1399 1400 /* default behavior for no SwapBuffers support: no vblank syncing 1401 * either. 1402 */ 1403 dri2_dpy->min_swap_interval = 0; 1404 dri2_dpy->max_swap_interval = 0; 1405 dri2_dpy->default_swap_interval = 0; 1406 1407 if (!dri2_dpy->swap_available) 1408 return; 1409 1410 /* If we do have swapbuffers, then we can support pretty much any swap 1411 * interval. Unless we're kopper, for now. 1412 */ 1413 if (dri2_dpy->kopper) 1414 arbitrary_max_interval = 1; 1415 1416 dri2_setup_swap_interval(disp, arbitrary_max_interval); 1417} 1418 1419static EGLBoolean 1420dri2_initialize_x11_swrast(_EGLDisplay *disp) 1421{ 1422 _EGLDevice *dev; 1423 struct dri2_egl_display *dri2_dpy; 1424 1425 dri2_dpy = calloc(1, sizeof *dri2_dpy); 1426 if (!dri2_dpy) 1427 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 1428 1429 dri2_dpy->fd = -1; 1430 if (!dri2_get_xcb_connection(disp, dri2_dpy)) 1431 goto cleanup; 1432 1433 dev = _eglAddDevice(dri2_dpy->fd, true); 1434 if (!dev) { 1435 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); 1436 goto cleanup; 1437 } 1438 1439 disp->Device = dev; 1440 1441 /* 1442 * Every hardware driver_name is set using strdup. Doing the same in 1443 * here will allow is to simply free the memory at dri2_terminate(). 1444 */ 1445 dri2_dpy->driver_name = strdup(disp->Options.Zink ? "zink" : "swrast"); 1446 if (!dri2_load_driver_swrast(disp)) 1447 goto cleanup; 1448 1449 dri2_dpy->loader_extensions = swrast_loader_extensions; 1450 1451 if (!dri2_create_screen(disp)) 1452 goto cleanup; 1453 1454 if (!dri2_setup_extensions(disp)) 1455 goto cleanup; 1456 1457 dri2_setup_screen(disp); 1458 1459 if (disp->Options.Zink) { 1460#ifdef HAVE_WAYLAND_PLATFORM 1461 dri2_dpy->device_name = strdup("zink"); 1462#endif 1463 dri2_dpy->swap_available = EGL_TRUE; 1464 dri2_x11_setup_swap_interval(disp); 1465 if (!dri2_dpy->is_different_gpu) 1466 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 1467 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE; 1468 disp->Extensions.CHROMIUM_sync_control = EGL_TRUE; 1469 disp->Extensions.EXT_buffer_age = EGL_TRUE; 1470 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; 1471 1472 //dri2_set_WL_bind_wayland_display(disp); 1473 } 1474 1475 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true)) 1476 goto cleanup; 1477 1478 /* Fill vtbl last to prevent accidentally calling virtual function during 1479 * initialization. 1480 */ 1481 if (disp->Options.Zink) 1482 dri2_dpy->vtbl = &dri2_x11_kopper_display_vtbl; 1483 else 1484 dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl; 1485 1486 return EGL_TRUE; 1487 1488 cleanup: 1489 dri2_display_destroy(disp); 1490 return EGL_FALSE; 1491} 1492 1493#ifdef HAVE_DRI3 1494 1495static const __DRIextension *dri3_image_loader_extensions[] = { 1496 &dri3_image_loader_extension.base, 1497 &image_lookup_extension.base, 1498 &use_invalidate.base, 1499 &background_callable_extension.base, 1500 NULL, 1501}; 1502 1503static EGLBoolean 1504dri2_initialize_x11_dri3(_EGLDisplay *disp) 1505{ 1506 _EGLDevice *dev; 1507 struct dri2_egl_display *dri2_dpy; 1508 1509 dri2_dpy = calloc(1, sizeof *dri2_dpy); 1510 if (!dri2_dpy) 1511 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 1512 1513 dri2_dpy->fd = -1; 1514 if (!dri2_get_xcb_connection(disp, dri2_dpy)) 1515 goto cleanup; 1516 1517 if (!dri3_x11_connect(dri2_dpy)) 1518 goto cleanup; 1519 1520 dev = _eglAddDevice(dri2_dpy->fd, false); 1521 if (!dev) { 1522 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); 1523 goto cleanup; 1524 } 1525 1526 disp->Device = dev; 1527 1528 if (!dri2_load_driver_dri3(disp)) 1529 goto cleanup; 1530 1531 dri2_dpy->loader_extensions = dri3_image_loader_extensions; 1532 1533 dri2_dpy->swap_available = true; 1534 dri2_dpy->invalidate_available = true; 1535 1536 if (!dri2_create_screen(disp)) 1537 goto cleanup; 1538 1539 if (!dri2_setup_extensions(disp)) 1540 goto cleanup; 1541 1542 dri2_setup_screen(disp); 1543 1544 dri2_x11_setup_swap_interval(disp); 1545 1546 if (!dri2_dpy->is_different_gpu) 1547 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 1548 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE; 1549 disp->Extensions.CHROMIUM_sync_control = EGL_TRUE; 1550 disp->Extensions.EXT_buffer_age = EGL_TRUE; 1551 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; 1552 1553 dri2_set_WL_bind_wayland_display(disp); 1554 1555 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false)) 1556 goto cleanup; 1557 1558 dri2_dpy->loader_dri3_ext.core = dri2_dpy->core; 1559 dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver; 1560 dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush; 1561 dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer; 1562 dri2_dpy->loader_dri3_ext.image = dri2_dpy->image; 1563 dri2_dpy->loader_dri3_ext.config = dri2_dpy->config; 1564 1565 /* Fill vtbl last to prevent accidentally calling virtual function during 1566 * initialization. 1567 */ 1568 dri2_dpy->vtbl = &dri3_x11_display_vtbl; 1569 1570 _eglLog(_EGL_INFO, "Using DRI3"); 1571 1572 return EGL_TRUE; 1573 1574 cleanup: 1575 dri2_display_destroy(disp); 1576 return EGL_FALSE; 1577} 1578#endif 1579 1580static const __DRIdri2LoaderExtension dri2_loader_extension_old = { 1581 .base = { __DRI_DRI2_LOADER, 2 }, 1582 1583 .getBuffers = dri2_x11_get_buffers, 1584 .flushFrontBuffer = dri2_x11_flush_front_buffer, 1585 .getBuffersWithFormat = NULL, 1586}; 1587 1588static const __DRIdri2LoaderExtension dri2_loader_extension = { 1589 .base = { __DRI_DRI2_LOADER, 3 }, 1590 1591 .getBuffers = dri2_x11_get_buffers, 1592 .flushFrontBuffer = dri2_x11_flush_front_buffer, 1593 .getBuffersWithFormat = dri2_x11_get_buffers_with_format, 1594}; 1595 1596static const __DRIextension *dri2_loader_extensions_old[] = { 1597 &dri2_loader_extension_old.base, 1598 &image_lookup_extension.base, 1599 &background_callable_extension.base, 1600 NULL, 1601}; 1602 1603static const __DRIextension *dri2_loader_extensions[] = { 1604 &dri2_loader_extension.base, 1605 &image_lookup_extension.base, 1606 &use_invalidate.base, 1607 &background_callable_extension.base, 1608 NULL, 1609}; 1610 1611static EGLBoolean 1612dri2_initialize_x11_dri2(_EGLDisplay *disp) 1613{ 1614 _EGLDevice *dev; 1615 struct dri2_egl_display *dri2_dpy; 1616 1617 dri2_dpy = calloc(1, sizeof *dri2_dpy); 1618 if (!dri2_dpy) 1619 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 1620 1621 dri2_dpy->fd = -1; 1622 if (!dri2_get_xcb_connection(disp, dri2_dpy)) 1623 goto cleanup; 1624 1625 if (!dri2_x11_connect(dri2_dpy)) 1626 goto cleanup; 1627 1628 dev = _eglAddDevice(dri2_dpy->fd, false); 1629 if (!dev) { 1630 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); 1631 goto cleanup; 1632 } 1633 1634 disp->Device = dev; 1635 1636 if (!dri2_load_driver(disp)) 1637 goto cleanup; 1638 1639 if (dri2_dpy->dri2_minor >= 1) 1640 dri2_dpy->loader_extensions = dri2_loader_extensions; 1641 else 1642 dri2_dpy->loader_extensions = dri2_loader_extensions_old; 1643 1644 dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2); 1645 dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3); 1646 1647 if (!dri2_create_screen(disp)) 1648 goto cleanup; 1649 1650 if (!dri2_setup_extensions(disp)) 1651 goto cleanup; 1652 1653 dri2_setup_screen(disp); 1654 1655 dri2_x11_setup_swap_interval(disp); 1656 1657 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 1658 disp->Extensions.NOK_swap_region = EGL_TRUE; 1659 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE; 1660 disp->Extensions.NV_post_sub_buffer = EGL_TRUE; 1661 disp->Extensions.CHROMIUM_sync_control = EGL_TRUE; 1662 1663 dri2_set_WL_bind_wayland_display(disp); 1664 1665 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true)) 1666 goto cleanup; 1667 1668 /* Fill vtbl last to prevent accidentally calling virtual function during 1669 * initialization. 1670 */ 1671 dri2_dpy->vtbl = &dri2_x11_display_vtbl; 1672 1673 _eglLog(_EGL_INFO, "Using DRI2"); 1674 1675 return EGL_TRUE; 1676 1677 cleanup: 1678 dri2_display_destroy(disp); 1679 return EGL_FALSE; 1680} 1681 1682EGLBoolean 1683dri2_initialize_x11(_EGLDisplay *disp) 1684{ 1685 if (disp->Options.ForceSoftware) 1686 return dri2_initialize_x11_swrast(disp); 1687 1688#ifdef HAVE_DRI3 1689 if (!env_var_as_boolean("LIBGL_DRI3_DISABLE", false)) 1690 if (dri2_initialize_x11_dri3(disp)) 1691 return EGL_TRUE; 1692#endif 1693 1694 if (!env_var_as_boolean("LIBGL_DRI2_DISABLE", false)) 1695 if (dri2_initialize_x11_dri2(disp)) 1696 return EGL_TRUE; 1697 1698 return EGL_FALSE; 1699} 1700 1701void 1702dri2_teardown_x11(struct dri2_egl_display *dri2_dpy) 1703{ 1704 if (dri2_dpy->own_device) 1705 xcb_disconnect(dri2_dpy->conn); 1706} 1707