gbm_dri.c revision 93ebec87ed46978942464a6f08801ae06e86fa8b
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 /* Required for query image WIDTH & HEIGHT */ 369 if (dri->image->base.version < 4) 370 return NULL; 371 372 switch (type) { 373#if HAVE_WAYLAND_PLATFORM 374 case GBM_BO_IMPORT_WL_BUFFER: 375 { 376 struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer; 377 378 image = wb->driver_buffer; 379 stride = wb->stride[0]; 380 offset = wb->offset[0]; 381 cpp = 4; 382 switch (wb->format) { 383 case WL_DRM_FORMAT_XRGB8888: 384 dri_format = __DRI_IMAGE_FORMAT_XRGB8888; 385 gbm_format = GBM_FORMAT_XRGB8888; 386 break; 387 case WL_DRM_FORMAT_ARGB8888: 388 dri_format = __DRI_IMAGE_FORMAT_ARGB8888; 389 gbm_format = GBM_FORMAT_ARGB8888; 390 break; 391 case WL_DRM_FORMAT_YUYV: 392 dri_format = __DRI_IMAGE_FORMAT_ARGB8888; 393 gbm_format = GBM_FORMAT_YUYV; 394 break; 395 default: 396 return NULL; 397 } 398 break; 399 } 400#endif 401 402 case GBM_BO_IMPORT_EGL_IMAGE: 403 { 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 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); 411 offset = 0; 412 cpp = 4; 413 break; 414 } 415 416 default: 417 return NULL; 418 } 419 420 421 bo = calloc(1, sizeof *bo); 422 if (bo == NULL) 423 return NULL; 424 425 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width); 426 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height); 427 428 bo->image = dri->image->createSubImage(image, 429 width, height, dri_format, 430 offset, stride / cpp, NULL); 431 432 433 if (usage & GBM_BO_USE_SCANOUT) 434 dri_use |= __DRI_IMAGE_USE_SCANOUT; 435 if (usage & GBM_BO_USE_CURSOR_64X64) 436 dri_use |= __DRI_IMAGE_USE_CURSOR; 437 if (dri->image->base.version >= 2 && 438 !dri->image->validateUsage(bo->image, dri_use)) { 439 free(bo); 440 return NULL; 441 } 442 443 bo->base.base.gbm = gbm; 444 bo->base.base.width = width; 445 bo->base.base.height = height; 446 bo->base.base.stride = stride; 447 bo->base.base.format = gbm_format; 448 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, 449 &bo->base.base.handle.s32); 450 451 return &bo->base.base; 452} 453 454static struct gbm_bo * 455gbm_dri_bo_create(struct gbm_device *gbm, 456 uint32_t width, uint32_t height, 457 uint32_t format, uint32_t usage) 458{ 459 struct gbm_dri_device *dri = gbm_dri_device(gbm); 460 struct gbm_dri_bo *bo; 461 int dri_format; 462 unsigned dri_use = 0; 463 464 bo = calloc(1, sizeof *bo); 465 if (bo == NULL) 466 return NULL; 467 468 bo->base.base.gbm = gbm; 469 bo->base.base.width = width; 470 bo->base.base.height = height; 471 472 if (usage & GBM_BO_USE_WRITE) { 473 int ret; 474 unsigned attrs[7] = { 475 KMS_WIDTH, 64, 476 KMS_HEIGHT, 64, 477 KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8, 478 KMS_TERMINATE_PROP_LIST, 479 }; 480 481 if (!(usage & GBM_BO_USE_CURSOR_64X64)) 482 return NULL; 483 484 if (dri->kms == NULL) 485 return NULL; 486 487 ret = kms_bo_create(dri->kms, attrs, &bo->bo); 488 if (ret < 0) { 489 free(bo); 490 return NULL; 491 } 492 493 kms_bo_get_prop(bo->bo, KMS_PITCH, &bo->base.base.stride); 494 kms_bo_get_prop(bo->bo, KMS_HANDLE, (unsigned*)&bo->base.base.handle); 495 496 return &bo->base.base; 497 } 498 499 switch (format) { 500 case GBM_FORMAT_RGB565: 501 dri_format =__DRI_IMAGE_FORMAT_RGB565; 502 break; 503 case GBM_FORMAT_XRGB8888: 504 case GBM_BO_FORMAT_XRGB8888: 505 dri_format = __DRI_IMAGE_FORMAT_XRGB8888; 506 break; 507 case GBM_FORMAT_ARGB8888: 508 case GBM_BO_FORMAT_ARGB8888: 509 dri_format = __DRI_IMAGE_FORMAT_ARGB8888; 510 break; 511 case GBM_FORMAT_ABGR8888: 512 dri_format = __DRI_IMAGE_FORMAT_ABGR8888; 513 break; 514 default: 515 return NULL; 516 } 517 518 if (usage & GBM_BO_USE_SCANOUT) 519 dri_use |= __DRI_IMAGE_USE_SCANOUT; 520 if (usage & GBM_BO_USE_CURSOR_64X64) 521 dri_use |= __DRI_IMAGE_USE_CURSOR; 522 523 /* Gallium drivers requires shared in order to get the handle/stride */ 524 dri_use |= __DRI_IMAGE_USE_SHARE; 525 526 bo->image = 527 dri->image->createImage(dri->screen, 528 width, height, 529 dri_format, dri_use, 530 bo); 531 if (bo->image == NULL) 532 return NULL; 533 534 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, 535 &bo->base.base.handle.s32); 536 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, 537 (int *) &bo->base.base.stride); 538 539 return &bo->base.base; 540} 541 542static struct gbm_surface * 543gbm_dri_surface_create(struct gbm_device *gbm, 544 uint32_t width, uint32_t height, 545 uint32_t format, uint32_t flags) 546{ 547 struct gbm_dri_surface *surf; 548 549 surf = calloc(1, sizeof *surf); 550 if (surf == NULL) 551 return NULL; 552 553 surf->base.gbm = gbm; 554 surf->base.width = width; 555 surf->base.height = height; 556 surf->base.format = format; 557 surf->base.flags = flags; 558 559 return &surf->base; 560} 561 562static void 563gbm_dri_surface_destroy(struct gbm_surface *_surf) 564{ 565 struct gbm_dri_surface *surf = gbm_dri_surface(_surf); 566 567 free(surf); 568} 569 570static void 571dri_destroy(struct gbm_device *gbm) 572{ 573 struct gbm_dri_device *dri = gbm_dri_device(gbm); 574 575 dri->core->destroyScreen(dri->screen); 576 free(dri->driver_configs); 577 dlclose(dri->driver); 578 free(dri->base.driver_name); 579 580 free(dri); 581} 582 583static struct gbm_device * 584dri_device_create(int fd) 585{ 586 struct gbm_dri_device *dri; 587 int ret; 588 589 dri = calloc(1, sizeof *dri); 590 591 dri->base.base.fd = fd; 592 dri->base.base.bo_create = gbm_dri_bo_create; 593 dri->base.base.bo_import = gbm_dri_bo_import; 594 dri->base.base.is_format_supported = gbm_dri_is_format_supported; 595 dri->base.base.bo_write = gbm_dri_bo_write; 596 dri->base.base.bo_destroy = gbm_dri_bo_destroy; 597 dri->base.base.destroy = dri_destroy; 598 dri->base.base.surface_create = gbm_dri_surface_create; 599 dri->base.base.surface_destroy = gbm_dri_surface_destroy; 600 601 dri->base.type = GBM_DRM_DRIVER_TYPE_DRI; 602 dri->base.base.name = "drm"; 603 604 kms_create(fd, &dri->kms); 605 if (dri->kms == NULL) 606 goto err_kms; 607 608 ret = dri_screen_create(dri); 609 if (ret) 610 goto err_dri; 611 612 return &dri->base.base; 613 614err_dri: 615 kms_destroy(&dri->kms); 616err_kms: 617 free(dri); 618 return NULL; 619} 620 621struct gbm_backend gbm_dri_backend = { 622 .backend_name = "dri", 623 .create_device = dri_device_create, 624}; 625