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