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 Hgsberg <krh (at) bitplanet.net> 26 */ 27 28 #include <stdlib.h> 29 #include <string.h> 30 #include <stdio.h> 31 #include <limits.h> 32 #include <dlfcn.h> 33 #include <fcntl.h> 34 #include <errno.h> 35 #include <unistd.h> 36 #include <xf86drm.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 40 #include "egl_dri2.h" 41 42 static void 43 swrastCreateDrawable(struct dri2_egl_display * dri2_dpy, 44 struct dri2_egl_surface * dri2_surf, 45 int depth) 46 { 47 uint32_t mask; 48 const uint32_t function = GXcopy; 49 uint32_t valgc[2]; 50 51 /* create GC's */ 52 dri2_surf->gc = xcb_generate_id(dri2_dpy->conn); 53 mask = XCB_GC_FUNCTION; 54 xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function); 55 56 dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn); 57 mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES; 58 valgc[0] = function; 59 valgc[1] = False; 60 xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc); 61 dri2_surf->depth = depth; 62 switch (depth) { 63 case 32: 64 case 24: 65 dri2_surf->bytes_per_pixel = 4; 66 break; 67 case 16: 68 dri2_surf->bytes_per_pixel = 2; 69 break; 70 case 8: 71 dri2_surf->bytes_per_pixel = 1; 72 break; 73 case 0: 74 dri2_surf->bytes_per_pixel = 0; 75 break; 76 default: 77 _eglLog(_EGL_WARNING, "unsupported depth %d", depth); 78 } 79 } 80 81 static void 82 swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy, 83 struct dri2_egl_surface * dri2_surf) 84 { 85 xcb_free_gc(dri2_dpy->conn, dri2_surf->gc); 86 xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc); 87 } 88 89 static void 90 swrastGetDrawableInfo(__DRIdrawable * draw, 91 int *x, int *y, int *w, int *h, 92 void *loaderPrivate) 93 { 94 struct dri2_egl_surface *dri2_surf = loaderPrivate; 95 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 96 97 xcb_get_geometry_cookie_t cookie; 98 xcb_get_geometry_reply_t *reply; 99 xcb_generic_error_t *error; 100 101 *w = *h = 0; 102 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable); 103 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error); 104 if (reply == NULL) 105 return; 106 107 if (error != NULL) { 108 _eglLog(_EGL_WARNING, "error in xcb_get_geometry"); 109 free(error); 110 } else { 111 *w = reply->width; 112 *h = reply->height; 113 } 114 free(reply); 115 } 116 117 static void 118 swrastPutImage(__DRIdrawable * draw, int op, 119 int x, int y, int w, int h, 120 char *data, void *loaderPrivate) 121 { 122 struct dri2_egl_surface *dri2_surf = loaderPrivate; 123 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 124 125 xcb_gcontext_t gc; 126 127 switch (op) { 128 case __DRI_SWRAST_IMAGE_OP_DRAW: 129 gc = dri2_surf->gc; 130 break; 131 case __DRI_SWRAST_IMAGE_OP_SWAP: 132 gc = dri2_surf->swapgc; 133 break; 134 default: 135 return; 136 } 137 138 xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable, 139 gc, w, h, x, y, 0, dri2_surf->depth, 140 w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data); 141 } 142 143 static void 144 swrastGetImage(__DRIdrawable * read, 145 int x, int y, int w, int h, 146 char *data, void *loaderPrivate) 147 { 148 struct dri2_egl_surface *dri2_surf = loaderPrivate; 149 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 150 151 xcb_get_image_cookie_t cookie; 152 xcb_get_image_reply_t *reply; 153 xcb_generic_error_t *error; 154 155 cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, 156 dri2_surf->drawable, x, y, w, h, ~0); 157 reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error); 158 if (reply == NULL) 159 return; 160 161 if (error != NULL) { 162 _eglLog(_EGL_WARNING, "error in xcb_get_image"); 163 free(error); 164 } else { 165 uint32_t bytes = xcb_get_image_data_length(reply); 166 uint8_t *idata = xcb_get_image_data(reply); 167 memcpy(data, idata, bytes); 168 } 169 free(reply); 170 } 171 172 173 /** 174 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 175 */ 176 static _EGLSurface * 177 dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, 178 _EGLConfig *conf, EGLNativeWindowType window, 179 const EGLint *attrib_list) 180 { 181 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 182 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 183 struct dri2_egl_surface *dri2_surf; 184 xcb_get_geometry_cookie_t cookie; 185 xcb_get_geometry_reply_t *reply; 186 xcb_screen_iterator_t s; 187 xcb_generic_error_t *error; 188 189 (void) drv; 190 191 dri2_surf = malloc(sizeof *dri2_surf); 192 if (!dri2_surf) { 193 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 194 return NULL; 195 } 196 197 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) 198 goto cleanup_surf; 199 200 dri2_surf->region = XCB_NONE; 201 if (type == EGL_PBUFFER_BIT) { 202 dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn); 203 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); 204 xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize, 205 dri2_surf->drawable, s.data->root, 206 dri2_surf->base.Width, dri2_surf->base.Height); 207 } else { 208 dri2_surf->drawable = window; 209 } 210 211 if (dri2_dpy->dri2) { 212 dri2_surf->dri_drawable = 213 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, 214 type == EGL_WINDOW_BIT ? 215 dri2_conf->dri_double_config : 216 dri2_conf->dri_single_config, 217 dri2_surf); 218 } else { 219 assert(dri2_dpy->swrast); 220 dri2_surf->dri_drawable = 221 (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen, 222 dri2_conf->dri_double_config, 223 dri2_surf); 224 } 225 226 if (dri2_surf->dri_drawable == NULL) { 227 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); 228 goto cleanup_pixmap; 229 } 230 231 if (dri2_dpy->dri2) { 232 xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable); 233 } else { 234 swrastCreateDrawable(dri2_dpy, dri2_surf, _eglGetConfigKey(conf, EGL_BUFFER_SIZE)); 235 } 236 237 if (type != EGL_PBUFFER_BIT) { 238 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable); 239 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error); 240 if (reply == NULL || error != NULL) { 241 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry"); 242 free(error); 243 goto cleanup_dri_drawable; 244 } 245 246 dri2_surf->base.Width = reply->width; 247 dri2_surf->base.Height = reply->height; 248 free(reply); 249 } 250 251 /* we always copy the back buffer to front */ 252 dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE; 253 254 return &dri2_surf->base; 255 256 cleanup_dri_drawable: 257 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 258 cleanup_pixmap: 259 if (type == EGL_PBUFFER_BIT) 260 xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable); 261 cleanup_surf: 262 free(dri2_surf); 263 264 return NULL; 265 } 266 267 /** 268 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). 269 */ 270 static _EGLSurface * 271 dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, 272 _EGLConfig *conf, EGLNativeWindowType window, 273 const EGLint *attrib_list) 274 { 275 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf, 276 window, attrib_list); 277 } 278 279 static _EGLSurface * 280 dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, 281 _EGLConfig *conf, EGLNativePixmapType pixmap, 282 const EGLint *attrib_list) 283 { 284 return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf, 285 pixmap, attrib_list); 286 } 287 288 static _EGLSurface * 289 dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, 290 _EGLConfig *conf, const EGLint *attrib_list) 291 { 292 return dri2_create_surface(drv, disp, EGL_PBUFFER_BIT, conf, 293 XCB_WINDOW_NONE, attrib_list); 294 } 295 296 static EGLBoolean 297 dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) 298 { 299 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 300 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 301 302 (void) drv; 303 304 if (!_eglPutSurface(surf)) 305 return EGL_TRUE; 306 307 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); 308 309 if (dri2_dpy->dri2) { 310 xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable); 311 } else { 312 assert(dri2_dpy->swrast); 313 swrastDestroyDrawable(dri2_dpy, dri2_surf); 314 } 315 316 if (surf->Type == EGL_PBUFFER_BIT) 317 xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable); 318 319 free(surf); 320 321 return EGL_TRUE; 322 } 323 324 /** 325 * Process list of buffer received from the server 326 * 327 * Processes the list of buffers received in a reply from the server to either 328 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 329 */ 330 static void 331 dri2_process_buffers(struct dri2_egl_surface *dri2_surf, 332 xcb_dri2_dri2_buffer_t *buffers, unsigned count) 333 { 334 struct dri2_egl_display *dri2_dpy = 335 dri2_egl_display(dri2_surf->base.Resource.Display); 336 xcb_rectangle_t rectangle; 337 unsigned i; 338 339 dri2_surf->buffer_count = count; 340 dri2_surf->have_fake_front = 0; 341 342 /* This assumes the DRI2 buffer attachment tokens matches the 343 * __DRIbuffer tokens. */ 344 for (i = 0; i < count; i++) { 345 dri2_surf->buffers[i].attachment = buffers[i].attachment; 346 dri2_surf->buffers[i].name = buffers[i].name; 347 dri2_surf->buffers[i].pitch = buffers[i].pitch; 348 dri2_surf->buffers[i].cpp = buffers[i].cpp; 349 dri2_surf->buffers[i].flags = buffers[i].flags; 350 351 /* We only use the DRI drivers single buffer configs. This 352 * means that if we try to render to a window, DRI2 will give us 353 * the fake front buffer, which we'll use as a back buffer. 354 * Note that EGL doesn't require that several clients rendering 355 * to the same window must see the same aux buffers. */ 356 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 357 dri2_surf->have_fake_front = 1; 358 } 359 360 if (dri2_surf->region != XCB_NONE) 361 xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region); 362 363 rectangle.x = 0; 364 rectangle.y = 0; 365 rectangle.width = dri2_surf->base.Width; 366 rectangle.height = dri2_surf->base.Height; 367 dri2_surf->region = xcb_generate_id(dri2_dpy->conn); 368 xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle); 369 } 370 371 static __DRIbuffer * 372 dri2_get_buffers(__DRIdrawable * driDrawable, 373 int *width, int *height, 374 unsigned int *attachments, int count, 375 int *out_count, void *loaderPrivate) 376 { 377 struct dri2_egl_surface *dri2_surf = loaderPrivate; 378 struct dri2_egl_display *dri2_dpy = 379 dri2_egl_display(dri2_surf->base.Resource.Display); 380 xcb_dri2_dri2_buffer_t *buffers; 381 xcb_dri2_get_buffers_reply_t *reply; 382 xcb_dri2_get_buffers_cookie_t cookie; 383 384 (void) driDrawable; 385 386 cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn, 387 dri2_surf->drawable, 388 count, count, attachments); 389 reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL); 390 buffers = xcb_dri2_get_buffers_buffers (reply); 391 if (buffers == NULL) 392 return NULL; 393 394 *out_count = reply->count; 395 dri2_surf->base.Width = *width = reply->width; 396 dri2_surf->base.Height = *height = reply->height; 397 dri2_process_buffers(dri2_surf, buffers, *out_count); 398 399 free(reply); 400 401 return dri2_surf->buffers; 402 } 403 404 static __DRIbuffer * 405 dri2_get_buffers_with_format(__DRIdrawable * driDrawable, 406 int *width, int *height, 407 unsigned int *attachments, int count, 408 int *out_count, void *loaderPrivate) 409 { 410 struct dri2_egl_surface *dri2_surf = loaderPrivate; 411 struct dri2_egl_display *dri2_dpy = 412 dri2_egl_display(dri2_surf->base.Resource.Display); 413 xcb_dri2_dri2_buffer_t *buffers; 414 xcb_dri2_get_buffers_with_format_reply_t *reply; 415 xcb_dri2_get_buffers_with_format_cookie_t cookie; 416 xcb_dri2_attach_format_t *format_attachments; 417 418 (void) driDrawable; 419 420 format_attachments = (xcb_dri2_attach_format_t *) attachments; 421 cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn, 422 dri2_surf->drawable, 423 count, count, 424 format_attachments); 425 426 reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn, 427 cookie, NULL); 428 if (reply == NULL) 429 return NULL; 430 431 buffers = xcb_dri2_get_buffers_with_format_buffers (reply); 432 dri2_surf->base.Width = *width = reply->width; 433 dri2_surf->base.Height = *height = reply->height; 434 *out_count = reply->count; 435 dri2_process_buffers(dri2_surf, buffers, *out_count); 436 437 free(reply); 438 439 return dri2_surf->buffers; 440 } 441 442 static void 443 dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 444 { 445 (void) driDrawable; 446 447 /* FIXME: Does EGL support front buffer rendering at all? */ 448 449 #if 0 450 struct dri2_egl_surface *dri2_surf = loaderPrivate; 451 452 dri2WaitGL(dri2_surf); 453 #else 454 (void) loaderPrivate; 455 #endif 456 } 457 458 static char * 459 dri2_strndup(const char *s, int length) 460 { 461 char *d; 462 463 d = malloc(length + 1); 464 if (d == NULL) 465 return NULL; 466 467 memcpy(d, s, length); 468 d[length] = '\0'; 469 470 return d; 471 } 472 473 static EGLBoolean 474 dri2_connect(struct dri2_egl_display *dri2_dpy) 475 { 476 xcb_xfixes_query_version_reply_t *xfixes_query; 477 xcb_xfixes_query_version_cookie_t xfixes_query_cookie; 478 xcb_dri2_query_version_reply_t *dri2_query; 479 xcb_dri2_query_version_cookie_t dri2_query_cookie; 480 xcb_dri2_connect_reply_t *connect; 481 xcb_dri2_connect_cookie_t connect_cookie; 482 xcb_generic_error_t *error; 483 xcb_screen_iterator_t s; 484 char *driver_name, *device_name; 485 const xcb_query_extension_reply_t *extension; 486 487 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id); 488 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id); 489 490 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id); 491 if (!(extension && extension->present)) 492 return EGL_FALSE; 493 494 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id); 495 if (!(extension && extension->present)) 496 return EGL_FALSE; 497 498 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn, 499 XCB_XFIXES_MAJOR_VERSION, 500 XCB_XFIXES_MINOR_VERSION); 501 502 dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn, 503 XCB_DRI2_MAJOR_VERSION, 504 XCB_DRI2_MINOR_VERSION); 505 506 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); 507 connect_cookie = xcb_dri2_connect_unchecked (dri2_dpy->conn, 508 s.data->root, 509 XCB_DRI2_DRIVER_TYPE_DRI); 510 511 xfixes_query = 512 xcb_xfixes_query_version_reply (dri2_dpy->conn, 513 xfixes_query_cookie, &error); 514 if (xfixes_query == NULL || 515 error != NULL || xfixes_query->major_version < 2) { 516 _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version"); 517 free(error); 518 return EGL_FALSE; 519 } 520 free(xfixes_query); 521 522 dri2_query = 523 xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error); 524 if (dri2_query == NULL || error != NULL) { 525 _eglLog(_EGL_WARNING, "DRI2: failed to query version"); 526 free(error); 527 return EGL_FALSE; 528 } 529 dri2_dpy->dri2_major = dri2_query->major_version; 530 dri2_dpy->dri2_minor = dri2_query->minor_version; 531 free(dri2_query); 532 533 connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL); 534 if (connect == NULL || 535 connect->driver_name_length + connect->device_name_length == 0) { 536 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate"); 537 return EGL_FALSE; 538 } 539 540 driver_name = xcb_dri2_connect_driver_name (connect); 541 dri2_dpy->driver_name = 542 dri2_strndup(driver_name, 543 xcb_dri2_connect_driver_name_length (connect)); 544 545 #if XCB_DRI2_CONNECT_DEVICE_NAME_BROKEN 546 device_name = driver_name + ((connect->driver_name_length + 3) & ~3); 547 #else 548 device_name = xcb_dri2_connect_device_name (connect); 549 #endif 550 551 dri2_dpy->device_name = 552 dri2_strndup(device_name, 553 xcb_dri2_connect_device_name_length (connect)); 554 555 if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) { 556 free(dri2_dpy->device_name); 557 free(dri2_dpy->driver_name); 558 free(connect); 559 return EGL_FALSE; 560 } 561 free(connect); 562 563 return EGL_TRUE; 564 } 565 566 static int 567 dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id) 568 { 569 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 570 xcb_dri2_authenticate_reply_t *authenticate; 571 xcb_dri2_authenticate_cookie_t authenticate_cookie; 572 xcb_screen_iterator_t s; 573 int ret = 0; 574 575 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); 576 authenticate_cookie = 577 xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, id); 578 authenticate = 579 xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL); 580 581 if (authenticate == NULL || !authenticate->authenticated) 582 ret = -1; 583 584 if (authenticate) 585 free(authenticate); 586 587 return ret; 588 } 589 590 static EGLBoolean 591 dri2_authenticate(_EGLDisplay *disp) 592 { 593 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 594 drm_magic_t magic; 595 596 if (drmGetMagic(dri2_dpy->fd, &magic)) { 597 _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic"); 598 return EGL_FALSE; 599 } 600 601 if (dri2_x11_authenticate(disp, magic) < 0) { 602 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate"); 603 return EGL_FALSE; 604 } 605 606 return EGL_TRUE; 607 } 608 609 static EGLBoolean 610 dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, 611 _EGLDisplay *disp) 612 { 613 xcb_screen_iterator_t s; 614 xcb_depth_iterator_t d; 615 xcb_visualtype_t *visuals; 616 int i, j, id; 617 EGLint surface_type; 618 EGLint config_attrs[] = { 619 EGL_NATIVE_VISUAL_ID, 0, 620 EGL_NATIVE_VISUAL_TYPE, 0, 621 EGL_NONE 622 }; 623 624 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); 625 d = xcb_screen_allowed_depths_iterator(s.data); 626 id = 1; 627 628 surface_type = 629 EGL_WINDOW_BIT | 630 EGL_PIXMAP_BIT | 631 EGL_PBUFFER_BIT | 632 EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 633 634 while (d.rem > 0) { 635 EGLBoolean class_added[6] = { 0, }; 636 637 visuals = xcb_depth_visuals(d.data); 638 for (i = 0; i < xcb_depth_visuals_length(d.data); i++) { 639 if (class_added[visuals[i]._class]) 640 continue; 641 642 class_added[visuals[i]._class] = EGL_TRUE; 643 for (j = 0; dri2_dpy->driver_configs[j]; j++) { 644 config_attrs[1] = visuals[i].visual_id; 645 config_attrs[3] = visuals[i]._class; 646 647 dri2_add_config(disp, dri2_dpy->driver_configs[j], id++, 648 d.data->depth, surface_type, config_attrs, NULL); 649 } 650 } 651 652 xcb_depth_next(&d); 653 } 654 655 if (!_eglGetArraySize(disp->Configs)) { 656 _eglLog(_EGL_WARNING, "DRI2: failed to create any config"); 657 return EGL_FALSE; 658 } 659 660 return EGL_TRUE; 661 } 662 663 static EGLBoolean 664 dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp, 665 _EGLSurface *draw, xcb_xfixes_region_t region) 666 { 667 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 668 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 669 enum xcb_dri2_attachment_t render_attachment; 670 xcb_dri2_copy_region_cookie_t cookie; 671 672 /* No-op for a pixmap or pbuffer surface */ 673 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT) 674 return EGL_TRUE; 675 676 #ifdef __DRI2_FLUSH 677 if (dri2_dpy->flush) 678 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); 679 #endif 680 681 if (dri2_surf->have_fake_front) 682 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT; 683 else 684 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT; 685 686 cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn, 687 dri2_surf->drawable, 688 region, 689 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT, 690 render_attachment); 691 free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL)); 692 693 return EGL_TRUE; 694 } 695 696 static int64_t 697 dri2_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw, 698 int64_t msc, int64_t divisor, int64_t remainder) 699 { 700 #if XCB_DRI2_MINOR_VERSION >= 3 701 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 702 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 703 uint32_t msc_hi = msc >> 32; 704 uint32_t msc_lo = msc & 0xffffffff; 705 uint32_t divisor_hi = divisor >> 32; 706 uint32_t divisor_lo = divisor & 0xffffffff; 707 uint32_t remainder_hi = remainder >> 32; 708 uint32_t remainder_lo = remainder & 0xffffffff; 709 xcb_dri2_swap_buffers_cookie_t cookie; 710 xcb_dri2_swap_buffers_reply_t *reply; 711 int64_t swap_count = -1; 712 713 /* No-op for a pixmap or pbuffer surface */ 714 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT) 715 return 0; 716 717 if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available) 718 return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1; 719 720 #ifdef __DRI2_FLUSH 721 if (dri2_dpy->flush) 722 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); 723 #endif 724 725 cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable, 726 msc_hi, msc_lo, divisor_hi, divisor_lo, remainder_hi, remainder_lo); 727 728 reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL); 729 730 if (reply) { 731 swap_count = (((int64_t)reply->swap_hi) << 32) | reply->swap_lo; 732 free(reply); 733 } 734 735 #if __DRI2_FLUSH_VERSION >= 3 736 /* If the server doesn't send invalidate events */ 737 if (dri2_dpy->invalidate_available && dri2_dpy->flush && 738 dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate) 739 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); 740 #endif 741 742 return swap_count; 743 #else 744 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 745 746 return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1; 747 #endif /* XCB_DRI2_MINOR_VERSION >= 3 */ 748 749 } 750 751 static EGLBoolean 752 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 753 { 754 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 755 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 756 757 if (dri2_dpy->dri2) { 758 return dri2_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1; 759 } else { 760 assert(dri2_dpy->swrast); 761 762 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); 763 return EGL_TRUE; 764 } 765 } 766 767 static EGLBoolean 768 dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw, 769 EGLint numRects, const EGLint *rects) 770 { 771 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 772 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 773 EGLBoolean ret; 774 xcb_xfixes_region_t region; 775 xcb_rectangle_t rectangles[16]; 776 int i; 777 778 if (numRects > (int)ARRAY_SIZE(rectangles)) 779 return dri2_copy_region(drv, disp, draw, dri2_surf->region); 780 781 for (i = 0; i < numRects; i++) { 782 rectangles[i].x = rects[i * 4]; 783 rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3]; 784 rectangles[i].width = rects[i * 4 + 2]; 785 rectangles[i].height = rects[i * 4 + 3]; 786 } 787 788 region = xcb_generate_id(dri2_dpy->conn); 789 xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles); 790 ret = dri2_copy_region(drv, disp, draw, region); 791 xcb_xfixes_destroy_region(dri2_dpy->conn, region); 792 793 return ret; 794 } 795 796 static EGLBoolean 797 dri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw, 798 EGLint x, EGLint y, EGLint width, EGLint height) 799 { 800 const EGLint rect[4] = { x, y, width, height }; 801 802 if (x < 0 || y < 0 || width < 0 || height < 0) 803 _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV"); 804 805 return dri2_swap_buffers_region(drv, disp, draw, 1, rect); 806 } 807 808 static EGLBoolean 809 dri2_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint interval) 810 { 811 #if XCB_DRI2_MINOR_VERSION >= 3 812 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 813 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 814 #endif 815 816 /* XXX Check vblank_mode here? */ 817 818 if (interval > surf->Config->MaxSwapInterval) 819 interval = surf->Config->MaxSwapInterval; 820 else if (interval < surf->Config->MinSwapInterval) 821 interval = surf->Config->MinSwapInterval; 822 823 #if XCB_DRI2_MINOR_VERSION >= 3 824 if (interval != surf->SwapInterval && dri2_dpy->swap_available) 825 xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval); 826 #endif 827 828 surf->SwapInterval = interval; 829 830 return EGL_TRUE; 831 } 832 833 static EGLBoolean 834 dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, 835 EGLNativePixmapType target) 836 { 837 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 838 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 839 xcb_gcontext_t gc; 840 841 (void) drv; 842 843 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); 844 845 gc = xcb_generate_id(dri2_dpy->conn); 846 xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL); 847 xcb_copy_area(dri2_dpy->conn, 848 dri2_surf->drawable, 849 target, 850 gc, 851 0, 0, 852 0, 0, 853 dri2_surf->base.Width, 854 dri2_surf->base.Height); 855 xcb_free_gc(dri2_dpy->conn, gc); 856 857 return EGL_TRUE; 858 } 859 860 static _EGLImage * 861 dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, 862 EGLClientBuffer buffer, const EGLint *attr_list) 863 { 864 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 865 struct dri2_egl_image *dri2_img; 866 unsigned int attachments[1]; 867 xcb_drawable_t drawable; 868 xcb_dri2_get_buffers_cookie_t buffers_cookie; 869 xcb_dri2_get_buffers_reply_t *buffers_reply; 870 xcb_dri2_dri2_buffer_t *buffers; 871 xcb_get_geometry_cookie_t geometry_cookie; 872 xcb_get_geometry_reply_t *geometry_reply; 873 xcb_generic_error_t *error; 874 int stride, format; 875 876 (void) ctx; 877 878 drawable = (xcb_drawable_t) (uintptr_t) buffer; 879 xcb_dri2_create_drawable (dri2_dpy->conn, drawable); 880 attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT; 881 buffers_cookie = 882 xcb_dri2_get_buffers_unchecked (dri2_dpy->conn, 883 drawable, 1, 1, attachments); 884 geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable); 885 buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, 886 buffers_cookie, NULL); 887 buffers = xcb_dri2_get_buffers_buffers (buffers_reply); 888 if (buffers == NULL) { 889 return NULL; 890 } 891 892 geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn, 893 geometry_cookie, &error); 894 if (geometry_reply == NULL || error != NULL) { 895 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry"); 896 free(error); 897 free(buffers_reply); 898 return NULL; 899 } 900 901 switch (geometry_reply->depth) { 902 case 16: 903 format = __DRI_IMAGE_FORMAT_RGB565; 904 break; 905 case 24: 906 format = __DRI_IMAGE_FORMAT_XRGB8888; 907 break; 908 case 32: 909 format = __DRI_IMAGE_FORMAT_ARGB8888; 910 break; 911 default: 912 _eglError(EGL_BAD_PARAMETER, 913 "dri2_create_image_khr: unsupported pixmap depth"); 914 free(buffers_reply); 915 free(geometry_reply); 916 return NULL; 917 } 918 919 dri2_img = malloc(sizeof *dri2_img); 920 if (!dri2_img) { 921 free(buffers_reply); 922 free(geometry_reply); 923 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); 924 return EGL_NO_IMAGE_KHR; 925 } 926 927 if (!_eglInitImage(&dri2_img->base, disp)) { 928 free(buffers_reply); 929 free(geometry_reply); 930 free(dri2_img); 931 return EGL_NO_IMAGE_KHR; 932 } 933 934 stride = buffers[0].pitch / buffers[0].cpp; 935 dri2_img->dri_image = 936 dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, 937 buffers_reply->width, 938 buffers_reply->height, 939 format, 940 buffers[0].name, 941 stride, 942 dri2_img); 943 944 free(buffers_reply); 945 free(geometry_reply); 946 947 return &dri2_img->base; 948 } 949 950 static _EGLImage * 951 dri2_x11_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, 952 _EGLContext *ctx, EGLenum target, 953 EGLClientBuffer buffer, const EGLint *attr_list) 954 { 955 (void) drv; 956 957 switch (target) { 958 case EGL_NATIVE_PIXMAP_KHR: 959 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list); 960 default: 961 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); 962 } 963 } 964 965 static EGLBoolean 966 dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp) 967 { 968 struct dri2_egl_display *dri2_dpy; 969 970 drv->API.CreateWindowSurface = dri2_create_window_surface; 971 drv->API.CreatePixmapSurface = dri2_create_pixmap_surface; 972 drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface; 973 drv->API.DestroySurface = dri2_destroy_surface; 974 drv->API.SwapBuffers = dri2_swap_buffers; 975 drv->API.CopyBuffers = dri2_copy_buffers; 976 977 drv->API.SwapBuffersRegionNOK = NULL; 978 drv->API.CreateImageKHR = NULL; 979 drv->API.DestroyImageKHR = NULL; 980 drv->API.CreateDRMImageMESA = NULL; 981 drv->API.ExportDRMImageMESA = NULL; 982 983 dri2_dpy = malloc(sizeof *dri2_dpy); 984 if (!dri2_dpy) 985 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 986 987 memset(dri2_dpy, 0, sizeof *dri2_dpy); 988 989 disp->DriverData = (void *) dri2_dpy; 990 if (disp->PlatformDisplay == NULL) { 991 dri2_dpy->conn = xcb_connect(0, 0); 992 } else { 993 dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay); 994 } 995 996 if (xcb_connection_has_error(dri2_dpy->conn)) { 997 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed"); 998 goto cleanup_dpy; 999 } 1000 1001 if (!dri2_load_driver_swrast(disp)) 1002 goto cleanup_conn; 1003 1004 dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER; 1005 dri2_dpy->swrast_loader_extension.base.version = __DRI_SWRAST_LOADER_VERSION; 1006 dri2_dpy->swrast_loader_extension.getDrawableInfo = swrastGetDrawableInfo; 1007 dri2_dpy->swrast_loader_extension.putImage = swrastPutImage; 1008 dri2_dpy->swrast_loader_extension.getImage = swrastGetImage; 1009 1010 dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base; 1011 dri2_dpy->extensions[1] = NULL; 1012 dri2_dpy->extensions[2] = NULL; 1013 1014 if (!dri2_create_screen(disp)) 1015 goto cleanup_driver; 1016 1017 if (dri2_dpy->conn) { 1018 if (!dri2_add_configs_for_visuals(dri2_dpy, disp)) 1019 goto cleanup_configs; 1020 } 1021 1022 /* we're supporting EGL 1.4 */ 1023 disp->VersionMajor = 1; 1024 disp->VersionMinor = 4; 1025 1026 return EGL_TRUE; 1027 1028 cleanup_configs: 1029 _eglCleanupDisplay(disp); 1030 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 1031 cleanup_driver: 1032 dlclose(dri2_dpy->driver); 1033 cleanup_conn: 1034 if (disp->PlatformDisplay == NULL) 1035 xcb_disconnect(dri2_dpy->conn); 1036 cleanup_dpy: 1037 free(dri2_dpy); 1038 1039 return EGL_FALSE; 1040 } 1041 1042 1043 static EGLBoolean 1044 dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) 1045 { 1046 struct dri2_egl_display *dri2_dpy; 1047 1048 drv->API.CreateWindowSurface = dri2_create_window_surface; 1049 drv->API.CreatePixmapSurface = dri2_create_pixmap_surface; 1050 drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface; 1051 drv->API.DestroySurface = dri2_destroy_surface; 1052 drv->API.SwapBuffers = dri2_swap_buffers; 1053 drv->API.CopyBuffers = dri2_copy_buffers; 1054 drv->API.CreateImageKHR = dri2_x11_create_image_khr; 1055 drv->API.SwapBuffersRegionNOK = dri2_swap_buffers_region; 1056 drv->API.PostSubBufferNV = dri2_post_sub_buffer; 1057 drv->API.SwapInterval = dri2_swap_interval; 1058 1059 dri2_dpy = malloc(sizeof *dri2_dpy); 1060 if (!dri2_dpy) 1061 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 1062 1063 memset(dri2_dpy, 0, sizeof *dri2_dpy); 1064 1065 disp->DriverData = (void *) dri2_dpy; 1066 if (disp->PlatformDisplay == NULL) { 1067 dri2_dpy->conn = xcb_connect(0, 0); 1068 } else { 1069 dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay); 1070 } 1071 1072 if (xcb_connection_has_error(dri2_dpy->conn)) { 1073 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed"); 1074 goto cleanup_dpy; 1075 } 1076 1077 if (dri2_dpy->conn) { 1078 if (!dri2_connect(dri2_dpy)) 1079 goto cleanup_conn; 1080 } 1081 1082 if (!dri2_load_driver(disp)) 1083 goto cleanup_conn; 1084 1085 #ifdef O_CLOEXEC 1086 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC); 1087 if (dri2_dpy->fd == -1 && errno == EINVAL) 1088 #endif 1089 { 1090 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR); 1091 if (dri2_dpy->fd != -1) 1092 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) | 1093 FD_CLOEXEC); 1094 } 1095 if (dri2_dpy->fd == -1) { 1096 _eglLog(_EGL_WARNING, 1097 "DRI2: could not open %s (%s)", dri2_dpy->device_name, 1098 strerror(errno)); 1099 goto cleanup_driver; 1100 } 1101 1102 if (dri2_dpy->conn) { 1103 if (!dri2_authenticate(disp)) 1104 goto cleanup_fd; 1105 } 1106 1107 if (dri2_dpy->dri2_minor >= 1) { 1108 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; 1109 dri2_dpy->dri2_loader_extension.base.version = 3; 1110 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; 1111 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; 1112 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = 1113 dri2_get_buffers_with_format; 1114 } else { 1115 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; 1116 dri2_dpy->dri2_loader_extension.base.version = 2; 1117 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers; 1118 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer; 1119 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = NULL; 1120 } 1121 1122 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; 1123 dri2_dpy->extensions[1] = &image_lookup_extension.base; 1124 dri2_dpy->extensions[2] = NULL; 1125 1126 #if XCB_DRI2_MINOR_VERSION >= 3 1127 dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2); 1128 dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3); 1129 #endif 1130 1131 if (!dri2_create_screen(disp)) 1132 goto cleanup_fd; 1133 1134 if (dri2_dpy->conn) { 1135 if (!dri2_add_configs_for_visuals(dri2_dpy, disp)) 1136 goto cleanup_configs; 1137 } 1138 1139 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 1140 disp->Extensions.NOK_swap_region = EGL_TRUE; 1141 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE; 1142 disp->Extensions.NV_post_sub_buffer = EGL_TRUE; 1143 1144 #ifdef HAVE_WAYLAND_PLATFORM 1145 disp->Extensions.WL_bind_wayland_display = EGL_TRUE; 1146 #endif 1147 dri2_dpy->authenticate = dri2_x11_authenticate; 1148 1149 /* we're supporting EGL 1.4 */ 1150 disp->VersionMajor = 1; 1151 disp->VersionMinor = 4; 1152 1153 return EGL_TRUE; 1154 1155 cleanup_configs: 1156 _eglCleanupDisplay(disp); 1157 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); 1158 cleanup_fd: 1159 close(dri2_dpy->fd); 1160 cleanup_driver: 1161 dlclose(dri2_dpy->driver); 1162 cleanup_conn: 1163 if (disp->PlatformDisplay == NULL) 1164 xcb_disconnect(dri2_dpy->conn); 1165 cleanup_dpy: 1166 free(dri2_dpy); 1167 1168 return EGL_FALSE; 1169 } 1170 1171 EGLBoolean 1172 dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp) 1173 { 1174 EGLBoolean initialized = EGL_TRUE; 1175 1176 int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); 1177 1178 if (x11_dri2_accel) { 1179 if (!dri2_initialize_x11_dri2(drv, disp)) { 1180 initialized = dri2_initialize_x11_swrast(drv, disp); 1181 } 1182 } else { 1183 initialized = dri2_initialize_x11_swrast(drv, disp); 1184 } 1185 1186 return initialized; 1187 } 1188 1189