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