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