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 * Benjamin Franzke <benjaminfranzke@googlemail.com> 26 */ 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <stddef.h> 31#include <stdint.h> 32#include <string.h> 33#include <limits.h> 34 35#include <sys/types.h> 36#include <sys/mman.h> 37#include <unistd.h> 38#include <dlfcn.h> 39#include <xf86drm.h> 40 41#include <GL/gl.h> /* dri_interface needs GL types */ 42#include <GL/internal/dri_interface.h> 43 44#include "gbm_driint.h" 45 46#include "gbmint.h" 47 48/* For importing wl_buffer */ 49#if HAVE_WAYLAND_PLATFORM 50#include "../../../egl/wayland/wayland-drm/wayland-drm.h" 51#endif 52 53static __DRIimage * 54dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data) 55{ 56 struct gbm_dri_device *dri = data; 57 58 if (dri->lookup_image == NULL) 59 return NULL; 60 61 return dri->lookup_image(screen, image, dri->lookup_user_data); 62} 63 64static __DRIbuffer * 65dri_get_buffers(__DRIdrawable * driDrawable, 66 int *width, int *height, 67 unsigned int *attachments, int count, 68 int *out_count, void *data) 69{ 70 struct gbm_dri_surface *surf = data; 71 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 72 73 if (dri->get_buffers == NULL) 74 return NULL; 75 76 return dri->get_buffers(driDrawable, width, height, attachments, 77 count, out_count, surf->dri_private); 78} 79 80static void 81dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data) 82{ 83 struct gbm_dri_surface *surf = data; 84 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 85 86 if (dri->flush_front_buffer != NULL) 87 dri->flush_front_buffer(driDrawable, surf->dri_private); 88} 89 90static __DRIbuffer * 91dri_get_buffers_with_format(__DRIdrawable * driDrawable, 92 int *width, int *height, 93 unsigned int *attachments, int count, 94 int *out_count, void *data) 95{ 96 struct gbm_dri_surface *surf = data; 97 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 98 99 if (dri->get_buffers_with_format == NULL) 100 return NULL; 101 102 return 103 dri->get_buffers_with_format(driDrawable, width, height, attachments, 104 count, out_count, surf->dri_private); 105} 106 107static const __DRIuseInvalidateExtension use_invalidate = { 108 { __DRI_USE_INVALIDATE, 1 } 109}; 110 111static const __DRIimageLookupExtension image_lookup_extension = { 112 { __DRI_IMAGE_LOOKUP, 1 }, 113 dri_lookup_egl_image 114}; 115 116const __DRIdri2LoaderExtension dri2_loader_extension = { 117 { __DRI_DRI2_LOADER, 3 }, 118 dri_get_buffers, 119 dri_flush_front_buffer, 120 dri_get_buffers_with_format, 121}; 122 123struct dri_extension_match { 124 const char *name; 125 int version; 126 int offset; 127}; 128 129static struct dri_extension_match dri_core_extensions[] = { 130 { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) }, 131 { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) }, 132 { NULL, 0, 0 } 133}; 134 135static struct dri_extension_match gbm_dri_device_extensions[] = { 136 { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) }, 137 { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) }, 138 { NULL, 0, 0 } 139}; 140 141static int 142dri_bind_extensions(struct gbm_dri_device *dri, 143 struct dri_extension_match *matches, 144 const __DRIextension **extensions) 145{ 146 int i, j, ret = 0; 147 void *field; 148 149 for (i = 0; extensions[i]; i++) { 150 for (j = 0; matches[j].name; j++) { 151 if (strcmp(extensions[i]->name, matches[j].name) == 0 && 152 extensions[i]->version >= matches[j].version) { 153 field = ((char *) dri + matches[j].offset); 154 *(const __DRIextension **) field = extensions[i]; 155 } 156 } 157 } 158 159 for (j = 0; matches[j].name; j++) { 160 field = ((char *) dri + matches[j].offset); 161 if (*(const __DRIextension **) field == NULL) { 162 ret = -1; 163 } 164 } 165 166 return ret; 167} 168 169static int 170dri_load_driver(struct gbm_dri_device *dri) 171{ 172 const __DRIextension **extensions; 173 char path[PATH_MAX], *search_paths, *p, *next, *end; 174 175 search_paths = NULL; 176 if (geteuid() == getuid()) { 177 /* don't allow setuid apps to use GBM_DRIVERS_PATH */ 178 search_paths = getenv("GBM_DRIVERS_PATH"); 179 } 180 if (search_paths == NULL) 181 search_paths = DEFAULT_DRIVER_DIR; 182 183 dri->driver = NULL; 184 end = search_paths + strlen(search_paths); 185 for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) { 186 int len; 187 next = strchr(p, ':'); 188 if (next == NULL) 189 next = end; 190 191 len = next - p; 192#if GLX_USE_TLS 193 snprintf(path, sizeof path, 194 "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name); 195 dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 196#endif 197 if (dri->driver == NULL) { 198 snprintf(path, sizeof path, 199 "%.*s/%s_dri.so", len, p, dri->base.driver_name); 200 dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 201 if (dri->driver == NULL) 202 fprintf(stderr, "failed to open %s: %s\n", path, dlerror()); 203 } 204 } 205 206 if (dri->driver == NULL) { 207 fprintf(stderr, "gbm: failed to open any driver (search paths %s)", 208 search_paths); 209 return -1; 210 } 211 212 extensions = dlsym(dri->driver, __DRI_DRIVER_EXTENSIONS); 213 if (extensions == NULL) { 214 fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror()); 215 dlclose(dri->driver); 216 return -1; 217 } 218 219 220 if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) { 221 dlclose(dri->driver); 222 fprintf(stderr, "failed to bind extensions\n"); 223 return -1; 224 } 225 226 return 0; 227} 228 229static int 230dri_screen_create(struct gbm_dri_device *dri) 231{ 232 const __DRIextension **extensions; 233 int ret = 0; 234 235 dri->base.driver_name = dri_fd_get_driver_name(dri->base.base.fd); 236 if (dri->base.driver_name == NULL) 237 return -1; 238 239 ret = dri_load_driver(dri); 240 if (ret) { 241 fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name); 242 return ret; 243 }; 244 245 dri->extensions[0] = &image_lookup_extension.base; 246 dri->extensions[1] = &use_invalidate.base; 247 dri->extensions[2] = &dri2_loader_extension.base; 248 dri->extensions[3] = NULL; 249 250 if (dri->dri2 == NULL) 251 return -1; 252 253 dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd, 254 dri->extensions, 255 &dri->driver_configs, dri); 256 if (dri->screen == NULL) 257 return -1; 258 259 extensions = dri->core->getExtensions(dri->screen); 260 if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) { 261 ret = -1; 262 goto free_screen; 263 } 264 265 dri->lookup_image = NULL; 266 dri->lookup_user_data = NULL; 267 268 return 0; 269 270free_screen: 271 dri->core->destroyScreen(dri->screen); 272 273 return ret; 274} 275 276static int 277gbm_dri_is_format_supported(struct gbm_device *gbm, 278 uint32_t format, 279 uint32_t usage) 280{ 281 switch (format) { 282 case GBM_BO_FORMAT_XRGB8888: 283 case GBM_FORMAT_XRGB8888: 284 break; 285 case GBM_BO_FORMAT_ARGB8888: 286 case GBM_FORMAT_ARGB8888: 287 if (usage & GBM_BO_USE_SCANOUT) 288 return 0; 289 break; 290 default: 291 return 0; 292 } 293 294 if (usage & GBM_BO_USE_CURSOR_64X64 && 295 usage & GBM_BO_USE_RENDERING) 296 return 0; 297 298 return 1; 299} 300 301static int 302gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count) 303{ 304 struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 305 306 if (bo->image != NULL) 307 return -1; 308 309 memcpy(bo->map, buf, count); 310 311 return 0; 312} 313 314static void 315gbm_dri_bo_destroy(struct gbm_bo *_bo) 316{ 317 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 318 struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 319 struct drm_mode_destroy_dumb arg; 320 321 if (bo->image != NULL) { 322 dri->image->destroyImage(bo->image); 323 } else { 324 munmap(bo->map, bo->size); 325 memset(&arg, 0, sizeof(arg)); 326 arg.handle = bo->handle; 327 drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg); 328 } 329 330 free(bo); 331} 332 333static uint32_t 334gbm_dri_to_gbm_format(uint32_t dri_format) 335{ 336 uint32_t ret = 0; 337 338 switch (dri_format) { 339 case __DRI_IMAGE_FORMAT_RGB565: 340 ret = GBM_FORMAT_RGB565; 341 break; 342 case __DRI_IMAGE_FORMAT_XRGB8888: 343 ret = GBM_FORMAT_XRGB8888; 344 break; 345 case __DRI_IMAGE_FORMAT_ARGB8888: 346 ret = GBM_FORMAT_ARGB8888; 347 break; 348 case __DRI_IMAGE_FORMAT_ABGR8888: 349 ret = GBM_FORMAT_ABGR8888; 350 break; 351 default: 352 ret = 0; 353 break; 354 } 355 356 return ret; 357} 358 359static struct gbm_bo * 360gbm_dri_bo_import(struct gbm_device *gbm, 361 uint32_t type, void *buffer, uint32_t usage) 362{ 363 struct gbm_dri_device *dri = gbm_dri_device(gbm); 364 struct gbm_dri_bo *bo; 365 __DRIimage *image; 366 unsigned dri_use = 0; 367 int gbm_format; 368 369 /* Required for query image WIDTH & HEIGHT */ 370 if (dri->image->base.version < 4) 371 return NULL; 372 373 switch (type) { 374#if HAVE_WAYLAND_PLATFORM 375 case GBM_BO_IMPORT_WL_BUFFER: 376 { 377 struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer; 378 379 if (!wayland_buffer_is_drm(buffer)) 380 return NULL; 381 382 image = wb->driver_buffer; 383 384 switch (wb->format) { 385 case WL_DRM_FORMAT_XRGB8888: 386 gbm_format = GBM_FORMAT_XRGB8888; 387 break; 388 case WL_DRM_FORMAT_ARGB8888: 389 gbm_format = GBM_FORMAT_ARGB8888; 390 break; 391 case WL_DRM_FORMAT_YUYV: 392 gbm_format = GBM_FORMAT_YUYV; 393 break; 394 default: 395 return NULL; 396 } 397 break; 398 } 399#endif 400 401 case GBM_BO_IMPORT_EGL_IMAGE: 402 { 403 int dri_format; 404 if (dri->lookup_image == NULL) 405 return NULL; 406 407 image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data); 408 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format); 409 gbm_format = gbm_dri_to_gbm_format(dri_format); 410 if (gbm_format == 0) 411 return NULL; 412 break; 413 } 414 415 default: 416 return NULL; 417 } 418 419 420 bo = calloc(1, sizeof *bo); 421 if (bo == NULL) 422 return NULL; 423 424 bo->image = dri->image->dupImage(image, NULL); 425 426 if (usage & GBM_BO_USE_SCANOUT) 427 dri_use |= __DRI_IMAGE_USE_SCANOUT; 428 if (usage & GBM_BO_USE_CURSOR_64X64) 429 dri_use |= __DRI_IMAGE_USE_CURSOR; 430 if (dri->image->base.version >= 2 && 431 !dri->image->validateUsage(bo->image, dri_use)) { 432 free(bo); 433 return NULL; 434 } 435 436 bo->base.base.gbm = gbm; 437 bo->base.base.format = gbm_format; 438 439 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH, 440 (int*)&bo->base.base.width); 441 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT, 442 (int*)&bo->base.base.height); 443 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, 444 (int*)&bo->base.base.stride); 445 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, 446 &bo->base.base.handle.s32); 447 448 return &bo->base.base; 449} 450 451static struct gbm_bo * 452create_dumb(struct gbm_device *gbm, 453 uint32_t width, uint32_t height, 454 uint32_t format, uint32_t usage) 455{ 456 struct gbm_dri_device *dri = gbm_dri_device(gbm); 457 struct drm_mode_create_dumb create_arg; 458 struct drm_mode_map_dumb map_arg; 459 struct gbm_dri_bo *bo; 460 struct drm_mode_destroy_dumb destroy_arg; 461 int ret; 462 463 if (!(usage & GBM_BO_USE_CURSOR_64X64)) 464 return NULL; 465 if (format != GBM_FORMAT_ARGB8888) 466 return NULL; 467 468 bo = calloc(1, sizeof *bo); 469 if (bo == NULL) 470 return NULL; 471 472 create_arg.bpp = 32; 473 create_arg.width = width; 474 create_arg.height = height; 475 476 ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); 477 if (ret) 478 goto free_bo; 479 480 bo->base.base.gbm = gbm; 481 bo->base.base.width = width; 482 bo->base.base.height = height; 483 bo->base.base.stride = create_arg.pitch; 484 bo->base.base.handle.u32 = create_arg.handle; 485 bo->handle = create_arg.handle; 486 bo->size = create_arg.size; 487 488 memset(&map_arg, 0, sizeof(map_arg)); 489 map_arg.handle = bo->handle; 490 491 ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg); 492 if (ret) 493 goto destroy_dumb; 494 495 bo->map = mmap(0, bo->size, PROT_WRITE, 496 MAP_SHARED, dri->base.base.fd, map_arg.offset); 497 if (bo->map == MAP_FAILED) 498 goto destroy_dumb; 499 500 return &bo->base.base; 501 502destroy_dumb: 503 memset(&destroy_arg, 0, sizeof destroy_arg); 504 destroy_arg.handle = create_arg.handle; 505 drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); 506free_bo: 507 free(bo); 508 509 return NULL; 510} 511 512static struct gbm_bo * 513gbm_dri_bo_create(struct gbm_device *gbm, 514 uint32_t width, uint32_t height, 515 uint32_t format, uint32_t usage) 516{ 517 struct gbm_dri_device *dri = gbm_dri_device(gbm); 518 struct gbm_dri_bo *bo; 519 int dri_format; 520 unsigned dri_use = 0; 521 522 if (usage & GBM_BO_USE_WRITE) 523 return create_dumb(gbm, width, height, format, usage); 524 525 bo = calloc(1, sizeof *bo); 526 if (bo == NULL) 527 return NULL; 528 529 bo->base.base.gbm = gbm; 530 bo->base.base.width = width; 531 bo->base.base.height = height; 532 533 switch (format) { 534 case GBM_FORMAT_RGB565: 535 dri_format =__DRI_IMAGE_FORMAT_RGB565; 536 break; 537 case GBM_FORMAT_XRGB8888: 538 case GBM_BO_FORMAT_XRGB8888: 539 dri_format = __DRI_IMAGE_FORMAT_XRGB8888; 540 break; 541 case GBM_FORMAT_ARGB8888: 542 case GBM_BO_FORMAT_ARGB8888: 543 dri_format = __DRI_IMAGE_FORMAT_ARGB8888; 544 break; 545 case GBM_FORMAT_ABGR8888: 546 dri_format = __DRI_IMAGE_FORMAT_ABGR8888; 547 break; 548 default: 549 return NULL; 550 } 551 552 if (usage & GBM_BO_USE_SCANOUT) 553 dri_use |= __DRI_IMAGE_USE_SCANOUT; 554 if (usage & GBM_BO_USE_CURSOR_64X64) 555 dri_use |= __DRI_IMAGE_USE_CURSOR; 556 557 /* Gallium drivers requires shared in order to get the handle/stride */ 558 dri_use |= __DRI_IMAGE_USE_SHARE; 559 560 bo->image = 561 dri->image->createImage(dri->screen, 562 width, height, 563 dri_format, dri_use, 564 bo); 565 if (bo->image == NULL) 566 return NULL; 567 568 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, 569 &bo->base.base.handle.s32); 570 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, 571 (int *) &bo->base.base.stride); 572 573 return &bo->base.base; 574} 575 576static struct gbm_surface * 577gbm_dri_surface_create(struct gbm_device *gbm, 578 uint32_t width, uint32_t height, 579 uint32_t format, uint32_t flags) 580{ 581 struct gbm_dri_surface *surf; 582 583 surf = calloc(1, sizeof *surf); 584 if (surf == NULL) 585 return NULL; 586 587 surf->base.gbm = gbm; 588 surf->base.width = width; 589 surf->base.height = height; 590 surf->base.format = format; 591 surf->base.flags = flags; 592 593 return &surf->base; 594} 595 596static void 597gbm_dri_surface_destroy(struct gbm_surface *_surf) 598{ 599 struct gbm_dri_surface *surf = gbm_dri_surface(_surf); 600 601 free(surf); 602} 603 604static void 605dri_destroy(struct gbm_device *gbm) 606{ 607 struct gbm_dri_device *dri = gbm_dri_device(gbm); 608 609 dri->core->destroyScreen(dri->screen); 610 free(dri->driver_configs); 611 dlclose(dri->driver); 612 free(dri->base.driver_name); 613 614 free(dri); 615} 616 617static struct gbm_device * 618dri_device_create(int fd) 619{ 620 struct gbm_dri_device *dri; 621 int ret; 622 623 dri = calloc(1, sizeof *dri); 624 625 dri->base.base.fd = fd; 626 dri->base.base.bo_create = gbm_dri_bo_create; 627 dri->base.base.bo_import = gbm_dri_bo_import; 628 dri->base.base.is_format_supported = gbm_dri_is_format_supported; 629 dri->base.base.bo_write = gbm_dri_bo_write; 630 dri->base.base.bo_destroy = gbm_dri_bo_destroy; 631 dri->base.base.destroy = dri_destroy; 632 dri->base.base.surface_create = gbm_dri_surface_create; 633 dri->base.base.surface_destroy = gbm_dri_surface_destroy; 634 635 dri->base.type = GBM_DRM_DRIVER_TYPE_DRI; 636 dri->base.base.name = "drm"; 637 638 ret = dri_screen_create(dri); 639 if (ret) 640 goto err_dri; 641 642 return &dri->base.base; 643 644err_dri: 645 free(dri); 646 647 return NULL; 648} 649 650struct gbm_backend gbm_dri_backend = { 651 .backend_name = "dri", 652 .create_device = dri_device_create, 653}; 654