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 <stdint.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <xf86drm.h> 33 #include <dlfcn.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 39 #include "egl_dri2.h" 40 #include "egl_dri2_fallbacks.h" 41 #include "loader.h" 42 43 static struct gbm_bo * 44 lock_front_buffer(struct gbm_surface *_surf) 45 { 46 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf; 47 struct dri2_egl_surface *dri2_surf = surf->dri_private; 48 struct gbm_dri_device *device = (struct gbm_dri_device *) _surf->gbm; 49 struct gbm_bo *bo; 50 51 if (dri2_surf->current == NULL) { 52 _eglError(EGL_BAD_SURFACE, "no front buffer"); 53 return NULL; 54 } 55 56 bo = dri2_surf->current->bo; 57 58 if (device->dri2) { 59 dri2_surf->current->locked = true; 60 dri2_surf->current = NULL; 61 } 62 63 return bo; 64 } 65 66 static void 67 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo) 68 { 69 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf; 70 struct dri2_egl_surface *dri2_surf = surf->dri_private; 71 72 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 73 if (dri2_surf->color_buffers[i].bo == bo) { 74 dri2_surf->color_buffers[i].locked = false; 75 break; 76 } 77 } 78 } 79 80 static int 81 has_free_buffers(struct gbm_surface *_surf) 82 { 83 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf; 84 struct dri2_egl_surface *dri2_surf = surf->dri_private; 85 86 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) 87 if (!dri2_surf->color_buffers[i].locked) 88 return 1; 89 90 return 0; 91 } 92 93 static _EGLSurface * 94 dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, 95 _EGLConfig *conf, void *native_surface, 96 const EGLint *attrib_list) 97 { 98 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 99 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 100 struct dri2_egl_surface *dri2_surf; 101 struct gbm_surface *surface = native_surface; 102 struct gbm_dri_surface *surf; 103 const __DRIconfig *config; 104 105 (void) drv; 106 107 dri2_surf = calloc(1, sizeof *dri2_surf); 108 if (!dri2_surf) { 109 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 110 return NULL; 111 } 112 113 if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false)) 114 goto cleanup_surf; 115 116 surf = gbm_dri_surface(surface); 117 dri2_surf->gbm_surf = surf; 118 dri2_surf->base.Width = surf->base.width; 119 dri2_surf->base.Height = surf->base.height; 120 surf->dri_private = dri2_surf; 121 122 config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, 123 dri2_surf->base.GLColorspace); 124 125 if (dri2_dpy->dri2) { 126 dri2_surf->dri_drawable = 127 dri2_dpy->dri2->createNewDrawable(dri2_dpy->dri_screen, config, 128 dri2_surf->gbm_surf); 129 130 } else { 131 assert(dri2_dpy->swrast != NULL); 132 133 dri2_surf->dri_drawable = 134 dri2_dpy->swrast->createNewDrawable(dri2_dpy->dri_screen, config, 135 dri2_surf->gbm_surf); 136 137 } 138 if (dri2_surf->dri_drawable == NULL) { 139 _eglError(EGL_BAD_ALLOC, "createNewDrawable()"); 140 goto cleanup_surf; 141 } 142 143 return &dri2_surf->base; 144 145 cleanup_surf: 146 free(dri2_surf); 147 148 return NULL; 149 } 150 151 static _EGLSurface * 152 dri2_drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, 153 _EGLConfig *conf, void *native_window, 154 const EGLint *attrib_list) 155 { 156 /* From the EGL_MESA_platform_gbm spec, version 5: 157 * 158 * It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy> 159 * that belongs to the GBM platform. Any such call fails and generates 160 * EGL_BAD_PARAMETER. 161 */ 162 _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM"); 163 return NULL; 164 } 165 166 static EGLBoolean 167 dri2_drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) 168 { 169 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 170 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 171 172 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 173 174 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 175 if (dri2_surf->color_buffers[i].bo) 176 gbm_bo_destroy(dri2_surf->color_buffers[i].bo); 177 } 178 179 dri2_egl_surface_free_local_buffers(dri2_surf); 180 181 dri2_fini_surface(surf); 182 free(surf); 183 184 return EGL_TRUE; 185 } 186 187 static int 188 get_back_bo(struct dri2_egl_surface *dri2_surf) 189 { 190 struct dri2_egl_display *dri2_dpy = 191 dri2_egl_display(dri2_surf->base.Resource.Display); 192 struct gbm_dri_surface *surf = dri2_surf->gbm_surf; 193 int age = 0; 194 195 if (dri2_surf->back == NULL) { 196 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 197 if (!dri2_surf->color_buffers[i].locked && 198 dri2_surf->color_buffers[i].age >= age) { 199 dri2_surf->back = &dri2_surf->color_buffers[i]; 200 age = dri2_surf->color_buffers[i].age; 201 } 202 } 203 } 204 205 if (dri2_surf->back == NULL) 206 return -1; 207 if (dri2_surf->back->bo == NULL) { 208 if (surf->base.modifiers) 209 dri2_surf->back->bo = gbm_bo_create_with_modifiers(&dri2_dpy->gbm_dri->base, 210 surf->base.width, 211 surf->base.height, 212 surf->base.format, 213 surf->base.modifiers, 214 surf->base.count); 215 else 216 dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base, 217 surf->base.width, 218 surf->base.height, 219 surf->base.format, 220 surf->base.flags); 221 222 } 223 if (dri2_surf->back->bo == NULL) 224 return -1; 225 226 return 0; 227 } 228 229 static int 230 get_swrast_front_bo(struct dri2_egl_surface *dri2_surf) 231 { 232 struct dri2_egl_display *dri2_dpy = 233 dri2_egl_display(dri2_surf->base.Resource.Display); 234 struct gbm_dri_surface *surf = dri2_surf->gbm_surf; 235 236 if (dri2_surf->current == NULL) { 237 assert(!dri2_surf->color_buffers[0].locked); 238 dri2_surf->current = &dri2_surf->color_buffers[0]; 239 } 240 241 if (dri2_surf->current->bo == NULL) 242 dri2_surf->current->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base, 243 surf->base.width, surf->base.height, 244 surf->base.format, surf->base.flags); 245 if (dri2_surf->current->bo == NULL) 246 return -1; 247 248 return 0; 249 } 250 251 static void 252 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) 253 { 254 struct dri2_egl_display *dri2_dpy = 255 dri2_egl_display(dri2_surf->base.Resource.Display); 256 struct gbm_dri_bo *bo; 257 int name, pitch; 258 259 bo = (struct gbm_dri_bo *) dri2_surf->back->bo; 260 261 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_NAME, &name); 262 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); 263 264 buffer->attachment = __DRI_BUFFER_BACK_LEFT; 265 buffer->name = name; 266 buffer->pitch = pitch; 267 buffer->cpp = 4; 268 buffer->flags = 0; 269 } 270 271 static __DRIbuffer * 272 dri2_drm_get_buffers_with_format(__DRIdrawable *driDrawable, 273 int *width, int *height, 274 unsigned int *attachments, int count, 275 int *out_count, void *loaderPrivate) 276 { 277 struct dri2_egl_surface *dri2_surf = loaderPrivate; 278 int i, j; 279 280 for (i = 0, j = 0; i < 2 * count; i += 2, j++) { 281 __DRIbuffer *local; 282 283 assert(attachments[i] < __DRI_BUFFER_COUNT); 284 assert(j < ARRAY_SIZE(dri2_surf->buffers)); 285 286 switch (attachments[i]) { 287 case __DRI_BUFFER_BACK_LEFT: 288 if (get_back_bo(dri2_surf) < 0) { 289 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); 290 return NULL; 291 } 292 back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]); 293 break; 294 default: 295 local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i], 296 attachments[i + 1]); 297 298 if (!local) { 299 _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer"); 300 return NULL; 301 } 302 dri2_surf->buffers[j] = *local; 303 break; 304 } 305 } 306 307 *out_count = j; 308 if (j == 0) 309 return NULL; 310 311 *width = dri2_surf->base.Width; 312 *height = dri2_surf->base.Height; 313 314 return dri2_surf->buffers; 315 } 316 317 static __DRIbuffer * 318 dri2_drm_get_buffers(__DRIdrawable * driDrawable, 319 int *width, int *height, 320 unsigned int *attachments, int count, 321 int *out_count, void *loaderPrivate) 322 { 323 unsigned int *attachments_with_format; 324 __DRIbuffer *buffer; 325 const unsigned int format = 32; 326 327 attachments_with_format = calloc(count, 2 * sizeof(unsigned int)); 328 if (!attachments_with_format) { 329 *out_count = 0; 330 return NULL; 331 } 332 333 for (int i = 0; i < count; ++i) { 334 attachments_with_format[2*i] = attachments[i]; 335 attachments_with_format[2*i + 1] = format; 336 } 337 338 buffer = 339 dri2_drm_get_buffers_with_format(driDrawable, 340 width, height, 341 attachments_with_format, count, 342 out_count, loaderPrivate); 343 344 free(attachments_with_format); 345 346 return buffer; 347 } 348 349 static int 350 dri2_drm_image_get_buffers(__DRIdrawable *driDrawable, 351 unsigned int format, 352 uint32_t *stamp, 353 void *loaderPrivate, 354 uint32_t buffer_mask, 355 struct __DRIimageList *buffers) 356 { 357 struct dri2_egl_surface *dri2_surf = loaderPrivate; 358 struct gbm_dri_bo *bo; 359 360 if (get_back_bo(dri2_surf) < 0) 361 return 0; 362 363 bo = (struct gbm_dri_bo *) dri2_surf->back->bo; 364 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; 365 buffers->back = bo->image; 366 367 return 1; 368 } 369 370 static void 371 dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 372 { 373 (void) driDrawable; 374 (void) loaderPrivate; 375 } 376 377 static EGLBoolean 378 dri2_drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) 379 { 380 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 381 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 382 383 if (!dri2_dpy->flush) { 384 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); 385 return EGL_TRUE; 386 } 387 388 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 389 if (dri2_surf->current) 390 _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers"); 391 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) 392 if (dri2_surf->color_buffers[i].age > 0) 393 dri2_surf->color_buffers[i].age++; 394 395 /* Make sure we have a back buffer in case we're swapping without 396 * ever rendering. */ 397 if (get_back_bo(dri2_surf) < 0) 398 return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); 399 400 dri2_surf->current = dri2_surf->back; 401 dri2_surf->current->age = 1; 402 dri2_surf->back = NULL; 403 } 404 405 dri2_flush_drawable_for_swapbuffers(disp, draw); 406 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 407 408 return EGL_TRUE; 409 } 410 411 static EGLint 412 dri2_drm_query_buffer_age(_EGLDriver *drv, 413 _EGLDisplay *disp, _EGLSurface *surface) 414 { 415 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); 416 417 if (get_back_bo(dri2_surf) < 0) { 418 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); 419 return -1; 420 } 421 422 return dri2_surf->back->age; 423 } 424 425 static _EGLImage * 426 dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, 427 EGLClientBuffer buffer, const EGLint *attr_list) 428 { 429 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 430 struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *) buffer); 431 struct dri2_egl_image *dri2_img; 432 433 dri2_img = malloc(sizeof *dri2_img); 434 if (!dri2_img) { 435 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap"); 436 return NULL; 437 } 438 439 _eglInitImage(&dri2_img->base, disp); 440 441 dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img); 442 if (dri2_img->dri_image == NULL) { 443 free(dri2_img); 444 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap"); 445 return NULL; 446 } 447 448 return &dri2_img->base; 449 } 450 451 static _EGLImage * 452 dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, 453 _EGLContext *ctx, EGLenum target, 454 EGLClientBuffer buffer, const EGLint *attr_list) 455 { 456 (void) drv; 457 458 switch (target) { 459 case EGL_NATIVE_PIXMAP_KHR: 460 return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list); 461 default: 462 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); 463 } 464 } 465 466 static int 467 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id) 468 { 469 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 470 471 return drmAuthMagic(dri2_dpy->fd, id); 472 } 473 474 static void 475 swrast_put_image2(__DRIdrawable *driDrawable, 476 int op, 477 int x, 478 int y, 479 int width, 480 int height, 481 int stride, 482 char *data, 483 void *loaderPrivate) 484 { 485 struct dri2_egl_surface *dri2_surf = loaderPrivate; 486 int internal_stride; 487 struct gbm_dri_bo *bo; 488 uint32_t bpp; 489 int x_bytes, width_bytes; 490 char *src, *dst; 491 492 if (op != __DRI_SWRAST_IMAGE_OP_DRAW && 493 op != __DRI_SWRAST_IMAGE_OP_SWAP) 494 return; 495 496 if (get_swrast_front_bo(dri2_surf) < 0) 497 return; 498 499 bo = gbm_dri_bo(dri2_surf->current->bo); 500 501 bpp = gbm_bo_get_bpp(&bo->base); 502 if (bpp == 0) 503 return; 504 505 x_bytes = x * (bpp >> 3); 506 width_bytes = width * (bpp >> 3); 507 508 if (gbm_dri_bo_map_dumb(bo) == NULL) 509 return; 510 511 internal_stride = bo->base.stride; 512 513 dst = bo->map + x_bytes + (y * internal_stride); 514 src = data; 515 516 for (int i = 0; i < height; i++) { 517 memcpy(dst, src, width_bytes); 518 dst += internal_stride; 519 src += stride; 520 } 521 522 gbm_dri_bo_unmap_dumb(bo); 523 } 524 525 static void 526 swrast_get_image(__DRIdrawable *driDrawable, 527 int x, 528 int y, 529 int width, 530 int height, 531 char *data, 532 void *loaderPrivate) 533 { 534 struct dri2_egl_surface *dri2_surf = loaderPrivate; 535 int internal_stride, stride; 536 struct gbm_dri_bo *bo; 537 uint32_t bpp; 538 int x_bytes, width_bytes; 539 char *src, *dst; 540 541 if (get_swrast_front_bo(dri2_surf) < 0) 542 return; 543 544 bo = gbm_dri_bo(dri2_surf->current->bo); 545 546 bpp = gbm_bo_get_bpp(&bo->base); 547 if (bpp == 0) 548 return; 549 550 x_bytes = x * (bpp >> 3); 551 width_bytes = width * (bpp >> 3); 552 553 internal_stride = bo->base.stride; 554 stride = width_bytes; 555 556 if (gbm_dri_bo_map_dumb(bo) == NULL) 557 return; 558 559 dst = data; 560 src = bo->map + x_bytes + (y * internal_stride); 561 562 for (int i = 0; i < height; i++) { 563 memcpy(dst, src, width_bytes); 564 dst += stride; 565 src += internal_stride; 566 } 567 568 gbm_dri_bo_unmap_dumb(bo); 569 } 570 571 static EGLBoolean 572 drm_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) 573 { 574 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 575 static const struct { 576 int format; 577 unsigned int red_mask; 578 unsigned int alpha_mask; 579 } visuals[] = { 580 { GBM_FORMAT_XRGB2101010, 0x3ff00000, 0x00000000 }, 581 { GBM_FORMAT_ARGB2101010, 0x3ff00000, 0xc0000000 }, 582 { GBM_FORMAT_XRGB8888, 0x00ff0000, 0x00000000 }, 583 { GBM_FORMAT_ARGB8888, 0x00ff0000, 0xff000000 }, 584 { GBM_FORMAT_RGB565, 0x0000f800, 0x00000000 }, 585 }; 586 587 unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 }; 588 unsigned int config_count = 0; 589 590 for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { 591 unsigned int red, alpha; 592 593 dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], 594 __DRI_ATTRIB_RED_MASK, &red); 595 dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], 596 __DRI_ATTRIB_ALPHA_MASK, &alpha); 597 598 for (unsigned j = 0; j < ARRAY_SIZE(visuals); j++) { 599 struct dri2_egl_config *dri2_conf; 600 601 if (visuals[j].red_mask != red || visuals[j].alpha_mask != alpha) 602 continue; 603 604 const EGLint attr_list[] = { 605 EGL_NATIVE_VISUAL_ID, visuals[j].format, 606 EGL_NONE, 607 }; 608 609 dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], 610 config_count + 1, EGL_WINDOW_BIT, attr_list, NULL); 611 if (dri2_conf) { 612 if (dri2_conf->base.ConfigID == config_count + 1) 613 config_count++; 614 format_count[j]++; 615 } 616 } 617 } 618 619 for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) { 620 if (!format_count[i]) { 621 _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x", 622 visuals[i].format); 623 } 624 } 625 626 return (config_count != 0); 627 } 628 629 static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = { 630 .authenticate = dri2_drm_authenticate, 631 .create_window_surface = dri2_drm_create_window_surface, 632 .create_pixmap_surface = dri2_drm_create_pixmap_surface, 633 .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface, 634 .destroy_surface = dri2_drm_destroy_surface, 635 .create_image = dri2_drm_create_image_khr, 636 .swap_buffers = dri2_drm_swap_buffers, 637 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage, 638 .swap_buffers_region = dri2_fallback_swap_buffers_region, 639 .set_damage_region = dri2_fallback_set_damage_region, 640 .post_sub_buffer = dri2_fallback_post_sub_buffer, 641 .copy_buffers = dri2_fallback_copy_buffers, 642 .query_buffer_age = dri2_drm_query_buffer_age, 643 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image, 644 .get_sync_values = dri2_fallback_get_sync_values, 645 .get_dri_drawable = dri2_surface_get_dri_drawable, 646 }; 647 648 EGLBoolean 649 dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp) 650 { 651 struct dri2_egl_display *dri2_dpy; 652 struct gbm_device *gbm; 653 const char *err; 654 655 /* Not supported yet */ 656 if (disp->Options.ForceSoftware) 657 return EGL_FALSE; 658 659 loader_set_logger(_eglLog); 660 661 dri2_dpy = calloc(1, sizeof *dri2_dpy); 662 if (!dri2_dpy) 663 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 664 665 dri2_dpy->fd = -1; 666 disp->DriverData = (void *) dri2_dpy; 667 668 gbm = disp->PlatformDisplay; 669 if (gbm == NULL) { 670 char buf[64]; 671 int n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, 0); 672 if (n != -1 && n < sizeof(buf)) 673 dri2_dpy->fd = loader_open_device(buf); 674 gbm = gbm_create_device(dri2_dpy->fd); 675 if (gbm == NULL) { 676 err = "DRI2: failed to create gbm device"; 677 goto cleanup; 678 } 679 dri2_dpy->own_device = true; 680 } else { 681 dri2_dpy->fd = fcntl(gbm_device_get_fd(gbm), F_DUPFD_CLOEXEC, 3); 682 if (dri2_dpy->fd < 0) { 683 err = "DRI2: failed to fcntl() existing gbm device"; 684 goto cleanup; 685 } 686 } 687 688 if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) { 689 err = "DRI2: gbm device using incorrect/incompatible backend"; 690 goto cleanup; 691 } 692 693 dri2_dpy->gbm_dri = gbm_dri_device(gbm); 694 dri2_dpy->driver_name = strdup(dri2_dpy->gbm_dri->driver_name); 695 696 dri2_dpy->dri_screen = dri2_dpy->gbm_dri->screen; 697 dri2_dpy->core = dri2_dpy->gbm_dri->core; 698 dri2_dpy->dri2 = dri2_dpy->gbm_dri->dri2; 699 dri2_dpy->swrast = dri2_dpy->gbm_dri->swrast; 700 dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs; 701 702 dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image; 703 dri2_dpy->gbm_dri->lookup_user_data = disp; 704 705 dri2_dpy->gbm_dri->get_buffers = dri2_drm_get_buffers; 706 dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer; 707 dri2_dpy->gbm_dri->get_buffers_with_format = dri2_drm_get_buffers_with_format; 708 dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers; 709 dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2; 710 dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image; 711 712 dri2_dpy->gbm_dri->base.surface_lock_front_buffer = lock_front_buffer; 713 dri2_dpy->gbm_dri->base.surface_release_buffer = release_buffer; 714 dri2_dpy->gbm_dri->base.surface_has_free_buffers = has_free_buffers; 715 716 if (!dri2_setup_extensions(disp)) { 717 err = "DRI2: failed to find required DRI extensions"; 718 goto cleanup; 719 } 720 721 dri2_setup_screen(disp); 722 723 if (!drm_add_configs_for_visuals(drv, disp)) { 724 err = "DRI2: failed to add configs"; 725 goto cleanup; 726 } 727 728 disp->Extensions.KHR_image_pixmap = EGL_TRUE; 729 if (dri2_dpy->dri2) 730 disp->Extensions.EXT_buffer_age = EGL_TRUE; 731 732 #ifdef HAVE_WAYLAND_PLATFORM 733 dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd); 734 #endif 735 dri2_set_WL_bind_wayland_display(drv, disp); 736 737 /* Fill vtbl last to prevent accidentally calling virtual function during 738 * initialization. 739 */ 740 dri2_dpy->vtbl = &dri2_drm_display_vtbl; 741 742 return EGL_TRUE; 743 744 cleanup: 745 dri2_display_destroy(disp); 746 return _eglError(EGL_NOT_INITIALIZED, err); 747 } 748 749 void 750 dri2_teardown_drm(struct dri2_egl_display *dri2_dpy) 751 { 752 if (dri2_dpy->own_device) 753 gbm_device_destroy(&dri2_dpy->gbm_dri->base); 754 } 755