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