1/* 2 * Copyright 2014 The Chromium OS Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 */ 6 7#define _GNU_SOURCE 8#include <assert.h> 9#include <fcntl.h> 10#include <stdbool.h> 11#include <stddef.h> 12#include <stdint.h> 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <sys/mman.h> 17#include <sys/types.h> 18#include <sys/stat.h> 19#include <unistd.h> 20#include <xf86drm.h> 21#include <xf86drmMode.h> 22 23#include <gbm.h> 24 25#define CHECK(cond) do {\ 26 if (!(cond)) {\ 27 printf("CHECK failed in %s() %s:%d\n", __func__, __FILE__, __LINE__);\ 28 return 0;\ 29 }\ 30} while(0) 31 32#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A))) 33 34#define ENODRM -1 35#define ENODISPLAY -2 36 37static int fd; 38static struct gbm_device *gbm; 39 40static const uint32_t format_list[] = { 41 GBM_FORMAT_C8, 42 GBM_FORMAT_RGB332, 43 GBM_FORMAT_BGR233, 44 GBM_FORMAT_XRGB4444, 45 GBM_FORMAT_XBGR4444, 46 GBM_FORMAT_RGBX4444, 47 GBM_FORMAT_BGRX4444, 48 GBM_FORMAT_ARGB4444, 49 GBM_FORMAT_ABGR4444, 50 GBM_FORMAT_RGBA4444, 51 GBM_FORMAT_BGRA4444, 52 GBM_FORMAT_XRGB1555, 53 GBM_FORMAT_XBGR1555, 54 GBM_FORMAT_RGBX5551, 55 GBM_FORMAT_BGRX5551, 56 GBM_FORMAT_ARGB1555, 57 GBM_FORMAT_ABGR1555, 58 GBM_FORMAT_RGBA5551, 59 GBM_FORMAT_BGRA5551, 60 GBM_FORMAT_RGB565, 61 GBM_FORMAT_BGR565, 62 GBM_FORMAT_RGB888, 63 GBM_FORMAT_BGR888, 64 GBM_FORMAT_XRGB8888, 65 GBM_FORMAT_XBGR8888, 66 GBM_FORMAT_RGBX8888, 67 GBM_FORMAT_BGRX8888, 68 GBM_FORMAT_ARGB8888, 69 GBM_FORMAT_ABGR8888, 70 GBM_FORMAT_RGBA8888, 71 GBM_FORMAT_BGRA8888, 72 GBM_FORMAT_XRGB2101010, 73 GBM_FORMAT_XBGR2101010, 74 GBM_FORMAT_RGBX1010102, 75 GBM_FORMAT_BGRX1010102, 76 GBM_FORMAT_ARGB2101010, 77 GBM_FORMAT_ABGR2101010, 78 GBM_FORMAT_RGBA1010102, 79 GBM_FORMAT_BGRA1010102, 80 GBM_FORMAT_YUYV, 81 GBM_FORMAT_YVYU, 82 GBM_FORMAT_UYVY, 83 GBM_FORMAT_VYUY, 84 GBM_FORMAT_AYUV, 85 GBM_FORMAT_NV12, 86 GBM_FORMAT_YVU420, 87}; 88 89static const uint32_t usage_list[] = { 90 GBM_BO_USE_SCANOUT, 91 GBM_BO_USE_CURSOR_64X64, 92 GBM_BO_USE_RENDERING, 93 GBM_BO_USE_LINEAR, 94}; 95 96static int check_bo(struct gbm_bo *bo) 97{ 98 uint32_t format; 99 size_t num_planes, plane; 100 int fd; 101 int i; 102 103 CHECK(bo); 104 CHECK(gbm_bo_get_width(bo) >= 0); 105 CHECK(gbm_bo_get_height(bo) >= 0); 106 CHECK(gbm_bo_get_stride(bo) >= gbm_bo_get_width(bo)); 107 108 format = gbm_bo_get_format(bo); 109 for (i = 0; i < ARRAY_SIZE(format_list); i++) 110 if (format_list[i] == format) 111 break; 112 CHECK(i < ARRAY_SIZE(format_list)); 113 114 num_planes = gbm_bo_get_num_planes(bo); 115 if (format == GBM_FORMAT_NV12) 116 CHECK(num_planes == 2); 117 else if (format == GBM_FORMAT_YVU420) 118 CHECK(num_planes == 3); 119 else 120 CHECK(num_planes == 1); 121 122 CHECK(gbm_bo_get_plane_handle(bo, 0).u32 == gbm_bo_get_handle(bo).u32); 123 124 CHECK(gbm_bo_get_plane_offset(bo, 0) == 0); 125 CHECK(gbm_bo_get_plane_size(bo, 0) >= 126 gbm_bo_get_width(bo) * gbm_bo_get_height(bo)); 127 CHECK(gbm_bo_get_plane_stride(bo, 0) == gbm_bo_get_stride(bo)); 128 129 for (plane = 0; plane < num_planes; plane++) { 130 CHECK(gbm_bo_get_plane_handle(bo, plane).u32); 131 132 fd = gbm_bo_get_plane_fd(bo, plane); 133 CHECK(fd > 0); 134 close(fd); 135 136 gbm_bo_get_plane_offset(bo, plane); 137 CHECK(gbm_bo_get_plane_size(bo, plane)); 138 CHECK(gbm_bo_get_plane_stride(bo, plane)); 139 } 140 141 return 1; 142} 143 144static drmModeConnector *find_first_connected_connector(int fd, 145 drmModeRes *resources) 146{ 147 int i; 148 for (i = 0; i < resources->count_connectors; i++) { 149 drmModeConnector *connector; 150 151 connector = drmModeGetConnector(fd, resources->connectors[i]); 152 if (connector) { 153 if ((connector->count_modes > 0) && 154 (connector->connection == DRM_MODE_CONNECTED)) 155 return connector; 156 157 drmModeFreeConnector(connector); 158 } 159 } 160 return NULL; 161} 162 163static int drm_open() 164{ 165 int fd; 166 unsigned i; 167 bool has_drm_device = false; 168 169 for (i = 0; i < DRM_MAX_MINOR; i++) { 170 char* dev_name; 171 drmModeRes *res = NULL; 172 int ret; 173 174 ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i); 175 if (ret < 0) 176 continue; 177 178 fd = open(dev_name, O_RDWR, 0); 179 free(dev_name); 180 if (fd < 0) 181 continue; 182 183 res = drmModeGetResources(fd); 184 if (!res) { 185 drmClose(fd); 186 continue; 187 } 188 189 if (res->count_crtcs > 0 && res->count_connectors > 0) { 190 has_drm_device = true; 191 if (find_first_connected_connector(fd, res)) { 192 drmModeFreeResources(res); 193 return fd; 194 } 195 } 196 197 drmClose(fd); 198 drmModeFreeResources(res); 199 } 200 201 if (has_drm_device) 202 return ENODISPLAY; 203 else 204 return ENODRM; 205} 206 207static int drm_open_vgem() 208{ 209 const char g_sys_card_path_format[] = 210 "/sys/bus/platform/devices/vgem/drm/card%d"; 211 const char g_dev_card_path_format[] = 212 "/dev/dri/card%d"; 213 char *name; 214 int i, fd; 215 216 for (i = 0; i < 16; i++) { 217 struct stat _stat; 218 int ret; 219 ret = asprintf(&name, g_sys_card_path_format, i); 220 assert(ret != -1); 221 222 if (stat(name, &_stat) == -1) { 223 free(name); 224 continue; 225 } 226 227 free(name); 228 ret = asprintf(&name, g_dev_card_path_format, i); 229 assert(ret != -1); 230 231 fd = open(name, O_RDWR); 232 free(name); 233 if (fd == -1) { 234 return -1; 235 } 236 return fd; 237 } 238 return -1; 239} 240 241static int create_vgem_bo(int fd, size_t size, uint32_t * handle) 242{ 243 struct drm_mode_create_dumb create; 244 int ret; 245 246 memset(&create, 0, sizeof(create)); 247 create.height = size; 248 create.width = 1; 249 create.bpp = 8; 250 251 ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); 252 if (ret) 253 return ret; 254 255 assert(create.size >= size); 256 257 *handle = create.handle; 258 259 return 0; 260} 261 262/* 263 * Tests initialization. 264 */ 265static int test_init() 266{ 267 fd = drm_open(); 268 if (fd == ENODISPLAY) 269 return ENODISPLAY; 270 CHECK(fd >= 0); 271 272 gbm = gbm_create_device(fd); 273 274 CHECK(gbm_device_get_fd(gbm) == fd); 275 276 const char* backend_name = gbm_device_get_backend_name(gbm); 277 278 CHECK(backend_name); 279 280 return 1; 281} 282 283/* 284 * Tests reinitialization. 285 */ 286static int test_reinit() 287{ 288 gbm_device_destroy(gbm); 289 close(fd); 290 291 fd = drm_open(); 292 CHECK(fd >= 0); 293 294 gbm = gbm_create_device(fd); 295 296 CHECK(gbm_device_get_fd(gbm) == fd); 297 298 struct gbm_bo *bo; 299 bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 300 CHECK(check_bo(bo)); 301 gbm_bo_destroy(bo); 302 303 return 1; 304} 305 306/* 307 * Tests repeated alloc/free. 308 */ 309static int test_alloc_free() 310{ 311 int i; 312 for(i = 0; i < 1000; i++) { 313 struct gbm_bo *bo; 314 bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 315 CHECK(check_bo(bo)); 316 gbm_bo_destroy(bo); 317 } 318 return 1; 319} 320 321/* 322 * Tests that we can allocate different buffer dimensions. 323 */ 324static int test_alloc_free_sizes() 325{ 326 int i; 327 for(i = 1; i < 1920; i++) { 328 struct gbm_bo *bo; 329 bo = gbm_bo_create(gbm, i, i, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 330 CHECK(check_bo(bo)); 331 gbm_bo_destroy(bo); 332 } 333 334 for(i = 1; i < 1920; i++) { 335 struct gbm_bo *bo; 336 bo = gbm_bo_create(gbm, i, 1, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 337 CHECK(check_bo(bo)); 338 gbm_bo_destroy(bo); 339 } 340 341 for(i = 1; i < 1920; i++) { 342 struct gbm_bo *bo; 343 bo = gbm_bo_create(gbm, 1, i, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 344 CHECK(check_bo(bo)); 345 gbm_bo_destroy(bo); 346 } 347 348 return 1; 349} 350 351/* 352 * Tests that we can allocate different buffer formats. 353 */ 354static int test_alloc_free_formats() 355{ 356 int i; 357 358 for(i = 0; i < ARRAY_SIZE(format_list); i++) { 359 uint32_t format = format_list[i]; 360 if (gbm_device_is_format_supported(gbm, format, GBM_BO_USE_RENDERING)) { 361 struct gbm_bo *bo; 362 bo = gbm_bo_create(gbm, 1024, 1024, format, GBM_BO_USE_RENDERING); 363 CHECK(check_bo(bo)); 364 } 365 } 366 367 return 1; 368} 369 370/* 371 * Tests that we find at least one working format for each usage. 372 */ 373static int test_alloc_free_usage() 374{ 375 int i, j; 376 377 for(i = 0; i < ARRAY_SIZE(usage_list); i++) { 378 uint32_t usage = usage_list[i]; 379 int found = 0; 380 for(j = 0; j < ARRAY_SIZE(format_list); j++) { 381 uint32_t format = format_list[j]; 382 if (gbm_device_is_format_supported(gbm, format, usage)) { 383 struct gbm_bo *bo; 384 bo = gbm_bo_create(gbm, 1024, 1024, format, usage); 385 CHECK(check_bo(bo)); 386 found = 1; 387 } 388 } 389 CHECK(found); 390 } 391 392 return 1; 393} 394 395/* 396 * Tests user data. 397 */ 398static int been_there1; 399static int been_there2; 400 401void destroy_data1(struct gbm_bo *bo, void *data) 402{ 403 been_there1 = 1; 404} 405 406void destroy_data2(struct gbm_bo *bo, void *data) 407{ 408 been_there2 = 1; 409} 410 411static int test_user_data() 412{ 413 struct gbm_bo *bo1, *bo2; 414 char *data1, *data2; 415 416 been_there1 = 0; 417 been_there2 = 0; 418 419 bo1 = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 420 bo2 = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 421 data1 = (char*)malloc(1); 422 data2 = (char*)malloc(1); 423 CHECK(data1); 424 CHECK(data2); 425 426 gbm_bo_set_user_data(bo1, data1, destroy_data1); 427 gbm_bo_set_user_data(bo2, data2, destroy_data2); 428 429 CHECK((char*)gbm_bo_get_user_data(bo1) == data1); 430 CHECK((char*)gbm_bo_get_user_data(bo2) == data2); 431 432 gbm_bo_destroy(bo1); 433 CHECK(been_there1 == 1); 434 435 gbm_bo_set_user_data(bo2, NULL, NULL); 436 gbm_bo_destroy(bo2); 437 CHECK(been_there2 == 0); 438 439 free(data1); 440 free(data2); 441 442 return 1; 443} 444 445/* 446 * Tests destruction. 447 */ 448static int test_destroy() 449{ 450 gbm_device_destroy(gbm); 451 close(fd); 452 453 return 1; 454} 455 456/* 457 * Tests prime export. 458 */ 459static int test_export() 460{ 461 struct gbm_bo *bo; 462 int prime_fd; 463 464 bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 465 CHECK(check_bo(bo)); 466 467 prime_fd = gbm_bo_get_fd(bo); 468 CHECK(prime_fd > 0); 469 close(prime_fd); 470 471 gbm_bo_destroy(bo); 472 473 return 1; 474} 475 476/* 477 * Tests prime import using VGEM sharing buffer. 478 */ 479static int test_import_vgem() 480{ 481 struct gbm_import_fd_data fd_data; 482 int vgem_fd = drm_open_vgem(); 483 struct drm_prime_handle prime_handle; 484 struct gbm_bo *bo; 485 const int width = 123; 486 const int height = 456; 487 const int bytes_per_pixel = 4; 488 const int size = width * height * bytes_per_pixel; 489 490 if (vgem_fd <= 0) 491 return 1; 492 493 CHECK(create_vgem_bo(vgem_fd, size, &prime_handle.handle) == 0); 494 prime_handle.flags = DRM_CLOEXEC; 495 CHECK(drmIoctl(vgem_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle) == 0); 496 497 fd_data.fd = prime_handle.fd; 498 fd_data.width = width; 499 fd_data.height = height; 500 fd_data.stride = width * bytes_per_pixel; 501 fd_data.format = GBM_FORMAT_XRGB8888; 502 503 bo = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &fd_data, GBM_BO_USE_RENDERING); 504 CHECK(check_bo(bo)); 505 gbm_bo_destroy(bo); 506 close(prime_handle.fd); 507 508 close(vgem_fd); 509 510 return 1; 511} 512 513/* 514 * Tests prime import using dma-buf API. 515 */ 516static int test_import_dmabuf() 517{ 518 struct gbm_import_fd_data fd_data; 519 struct gbm_bo *bo1, *bo2; 520 const int width = 123; 521 const int height = 456; 522 int prime_fd; 523 524 bo1 = gbm_bo_create(gbm, width, height, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 525 CHECK(check_bo(bo1)); 526 527 prime_fd = gbm_bo_get_fd(bo1); 528 CHECK(prime_fd >= 0); 529 530 fd_data.fd = prime_fd; 531 fd_data.width = width; 532 fd_data.height = height; 533 fd_data.stride = gbm_bo_get_stride(bo1); 534 fd_data.format = GBM_FORMAT_XRGB8888; 535 536 gbm_bo_destroy(bo1); 537 538 bo2 = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &fd_data, GBM_BO_USE_RENDERING); 539 CHECK(check_bo(bo2)); 540 CHECK(fd_data.width == gbm_bo_get_width(bo2)); 541 CHECK(fd_data.height == gbm_bo_get_height(bo2)); 542 CHECK(fd_data.stride == gbm_bo_get_stride(bo2)); 543 544 gbm_bo_destroy(bo2); 545 close(prime_fd); 546 547 return 1; 548} 549 550 551/* 552 * Tests GBM_BO_IMPORT_FD_PLANAR entry point. 553 */ 554static int test_import_planar() 555{ 556 struct gbm_import_fd_planar_data fd_data; 557 struct gbm_bo *bo1, *bo2; 558 const int width = 567; 559 const int height = 891; 560 size_t num_planes, p; 561 int i; 562 563 for (i = 0; i < ARRAY_SIZE(format_list); i++) { 564 uint32_t format = format_list[i]; 565 if (gbm_device_is_format_supported(gbm, format, GBM_BO_USE_RENDERING)) { 566 bo1 = gbm_bo_create(gbm, width, height, format, GBM_BO_USE_RENDERING); 567 CHECK(check_bo(bo1)); 568 569 num_planes = gbm_bo_get_num_planes(bo1); 570 for (p = 0; p < num_planes; p++) { 571 fd_data.fds[p] = gbm_bo_get_plane_fd(bo1, p); 572 CHECK(fd_data.fds[p] >= 0); 573 574 fd_data.strides[p] = gbm_bo_get_plane_stride(bo1, p); 575 fd_data.offsets[p] = gbm_bo_get_plane_offset(bo1, p); 576 fd_data.format_modifiers[p] = 577 gbm_bo_get_plane_format_modifier(bo1, p); 578 } 579 580 fd_data.width = width; 581 fd_data.height = height; 582 fd_data.format = format; 583 584 gbm_bo_destroy(bo1); 585 586 bo2 = gbm_bo_import(gbm, GBM_BO_IMPORT_FD_PLANAR, &fd_data, 587 GBM_BO_USE_RENDERING); 588 589 CHECK(check_bo(bo2)); 590 CHECK(fd_data.width == gbm_bo_get_width(bo2)); 591 CHECK(fd_data.height == gbm_bo_get_height(bo2)); 592 593 for (p = 0; p < num_planes; p++) { 594 CHECK(fd_data.strides[p] == gbm_bo_get_plane_stride(bo2, p)); 595 CHECK(fd_data.offsets[p] == gbm_bo_get_plane_offset(bo2, p)); 596 CHECK(fd_data.format_modifiers[p] == 597 gbm_bo_get_plane_format_modifier(bo2, p)); 598 } 599 600 gbm_bo_destroy(bo2); 601 602 for (p = 0; p < num_planes; p++) 603 close(fd_data.fds[p]); 604 } 605 } 606 607 return 1; 608} 609 610static int test_gem_map() 611{ 612 uint32_t *pixel, pixel_size; 613 struct gbm_bo *bo; 614 void *map_data, *addr; 615 616 uint32_t stride = 0; 617 const int width = 666; 618 const int height = 777; 619 620 addr = map_data = NULL; 621 622 bo = gbm_bo_create(gbm, width, height, GBM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR); 623 CHECK(check_bo(bo)); 624 625 addr = gbm_bo_map(bo, 0, 0, width, height, 0, &stride, &map_data, 0); 626 627 CHECK(addr != MAP_FAILED); 628 CHECK(map_data); 629 CHECK(stride > 0); 630 631 pixel = (uint32_t *)addr; 632 pixel_size = sizeof(*pixel); 633 634 pixel[(height / 2) * (stride / pixel_size) + width / 2] = 0xABBAABBA; 635 gbm_bo_unmap(bo, map_data); 636 637 /* Re-map and verify written previously data. */ 638 stride = 0; 639 addr = map_data = NULL; 640 641 addr = gbm_bo_map(bo, 0, 0, width, height, 0, &stride, &map_data, 0); 642 643 CHECK(addr != MAP_FAILED); 644 CHECK(map_data); 645 CHECK(stride > 0); 646 647 pixel = (uint32_t *)addr; 648 CHECK(pixel[(height / 2) * (stride / pixel_size) + width / 2] == 0xABBAABBA); 649 650 gbm_bo_unmap(bo, map_data); 651 gbm_bo_destroy(bo); 652 653 return 1; 654} 655 656int main(int argc, char *argv[]) 657{ 658 int result; 659 660 result = test_init(); 661 if (result == ENODISPLAY) { 662 printf("[ PASSED ] graphics_Gbm test no connected display found\n"); 663 return EXIT_SUCCESS; 664 } else if (!result) { 665 printf("[ FAILED ] graphics_Gbm test initialization failed\n"); 666 return EXIT_FAILURE; 667 } 668 669 result &= test_reinit(); 670 result &= test_alloc_free(); 671 result &= test_alloc_free_sizes(); 672 result &= test_alloc_free_formats(); 673 result &= test_alloc_free_usage(); 674 result &= test_user_data(); 675 result &= test_export(); 676 result &= test_import_vgem(); 677 result &= test_import_dmabuf(); 678 result &= test_import_planar(); 679 result &= test_gem_map(); 680 result &= test_destroy(); 681 682 if (!result) { 683 printf("[ FAILED ] graphics_Gbm test failed\n"); 684 return EXIT_FAILURE; 685 } else { 686 printf("[ PASSED ] graphics_Gbm test success\n"); 687 return EXIT_SUCCESS; 688 } 689} 690 691