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/types.h> 17 #include <sys/stat.h> 18 #include <unistd.h> 19 #include <xf86drm.h> 20 #include <xf86drmMode.h> 21 22 #include <gbm.h> 23 24 #define CHECK(cond) do {\ 25 if (!(cond)) {\ 26 printf("CHECK failed in %s() %s:%d\n", __func__, __FILE__, __LINE__);\ 27 return 0;\ 28 }\ 29 } while(0) 30 31 #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A))) 32 33 #define ENODRM -1 34 #define ENODISPLAY -2 35 36 static int fd; 37 static struct gbm_device *gbm; 38 39 static const uint32_t format_list[] = { 40 GBM_BO_FORMAT_XRGB8888, 41 GBM_BO_FORMAT_ARGB8888, 42 GBM_FORMAT_C8, 43 GBM_FORMAT_RGB332, 44 GBM_FORMAT_BGR233, 45 GBM_FORMAT_XRGB4444, 46 GBM_FORMAT_XBGR4444, 47 GBM_FORMAT_RGBX4444, 48 GBM_FORMAT_BGRX4444, 49 GBM_FORMAT_ARGB4444, 50 GBM_FORMAT_ABGR4444, 51 GBM_FORMAT_RGBA4444, 52 GBM_FORMAT_BGRA4444, 53 GBM_FORMAT_XRGB1555, 54 GBM_FORMAT_XBGR1555, 55 GBM_FORMAT_RGBX5551, 56 GBM_FORMAT_BGRX5551, 57 GBM_FORMAT_ARGB1555, 58 GBM_FORMAT_ABGR1555, 59 GBM_FORMAT_RGBA5551, 60 GBM_FORMAT_BGRA5551, 61 GBM_FORMAT_RGB565, 62 GBM_FORMAT_BGR565, 63 GBM_FORMAT_RGB888, 64 GBM_FORMAT_BGR888, 65 GBM_FORMAT_XRGB8888, 66 GBM_FORMAT_XBGR8888, 67 GBM_FORMAT_RGBX8888, 68 GBM_FORMAT_BGRX8888, 69 GBM_FORMAT_ARGB8888, 70 GBM_FORMAT_ABGR8888, 71 GBM_FORMAT_RGBA8888, 72 GBM_FORMAT_BGRA8888, 73 GBM_FORMAT_XRGB2101010, 74 GBM_FORMAT_XBGR2101010, 75 GBM_FORMAT_RGBX1010102, 76 GBM_FORMAT_BGRX1010102, 77 GBM_FORMAT_ARGB2101010, 78 GBM_FORMAT_ABGR2101010, 79 GBM_FORMAT_RGBA1010102, 80 GBM_FORMAT_BGRA1010102, 81 GBM_FORMAT_YUYV, 82 GBM_FORMAT_YVYU, 83 GBM_FORMAT_UYVY, 84 GBM_FORMAT_VYUY, 85 GBM_FORMAT_AYUV, 86 }; 87 88 static const uint32_t usage_list[] = { 89 GBM_BO_USE_SCANOUT, 90 GBM_BO_USE_CURSOR_64X64, 91 GBM_BO_USE_RENDERING, 92 GBM_BO_USE_WRITE, 93 }; 94 95 static int check_bo(struct gbm_bo *bo) 96 { 97 CHECK(bo); 98 CHECK(gbm_bo_get_width(bo) >= 0); 99 CHECK(gbm_bo_get_height(bo) >= 0); 100 CHECK(gbm_bo_get_stride(bo) >= gbm_bo_get_width(bo)); 101 102 return 1; 103 } 104 105 static drmModeConnector *find_first_connected_connector(int fd, 106 drmModeRes *resources) 107 { 108 int i; 109 for (i = 0; i < resources->count_connectors; i++) { 110 drmModeConnector *connector; 111 112 connector = drmModeGetConnector(fd, resources->connectors[i]); 113 if (connector) { 114 if ((connector->count_modes > 0) && 115 (connector->connection == DRM_MODE_CONNECTED)) 116 return connector; 117 118 drmModeFreeConnector(connector); 119 } 120 } 121 return NULL; 122 } 123 124 static int drm_open() 125 { 126 int fd; 127 unsigned i; 128 bool has_drm_device = false; 129 130 for (i = 0; i < DRM_MAX_MINOR; i++) { 131 char* dev_name; 132 drmModeRes *res = NULL; 133 int ret; 134 135 ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i); 136 if (ret < 0) 137 continue; 138 139 fd = open(dev_name, O_RDWR, 0); 140 free(dev_name); 141 if (fd < 0) 142 continue; 143 144 res = drmModeGetResources(fd); 145 if (!res) { 146 drmClose(fd); 147 continue; 148 } 149 150 if (res->count_crtcs > 0 && res->count_connectors > 0) { 151 has_drm_device = true; 152 if (find_first_connected_connector(fd, res)) { 153 drmModeFreeResources(res); 154 return fd; 155 } 156 } 157 158 drmClose(fd); 159 drmModeFreeResources(res); 160 } 161 162 if (has_drm_device) 163 return ENODISPLAY; 164 else 165 return ENODRM; 166 } 167 168 static int drm_open_vgem() 169 { 170 const char g_sys_card_path_format[] = 171 "/sys/bus/platform/devices/vgem/drm/card%d"; 172 const char g_dev_card_path_format[] = 173 "/dev/dri/card%d"; 174 char *name; 175 int i, fd; 176 177 for (i = 0; i < 16; i++) { 178 struct stat _stat; 179 int ret; 180 ret = asprintf(&name, g_sys_card_path_format, i); 181 assert(ret != -1); 182 183 if (stat(name, &_stat) == -1) { 184 free(name); 185 continue; 186 } 187 188 free(name); 189 ret = asprintf(&name, g_dev_card_path_format, i); 190 assert(ret != -1); 191 192 fd = open(name, O_RDWR); 193 free(name); 194 if (fd == -1) { 195 return -1; 196 } 197 return fd; 198 } 199 return -1; 200 } 201 202 static int create_vgem_bo(int fd, size_t size, uint32_t * handle) 203 { 204 struct drm_mode_create_dumb create; 205 int ret; 206 207 memset(&create, 0, sizeof(create)); 208 create.height = size; 209 create.width = 1; 210 create.bpp = 8; 211 212 ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); 213 if (ret) 214 return ret; 215 216 assert(create.size >= size); 217 218 *handle = create.handle; 219 220 return 0; 221 } 222 223 /* 224 * Tests initialization. 225 */ 226 static int test_init() 227 { 228 fd = drm_open(); 229 if (fd == ENODISPLAY) 230 return ENODISPLAY; 231 CHECK(fd >= 0); 232 233 gbm = gbm_create_device(fd); 234 235 CHECK(gbm_device_get_fd(gbm) == fd); 236 237 const char* backend_name = gbm_device_get_backend_name(gbm); 238 239 CHECK(backend_name); 240 241 return 1; 242 } 243 244 /* 245 * Tests reinitialization. 246 */ 247 static int test_reinit() 248 { 249 gbm_device_destroy(gbm); 250 close(fd); 251 252 fd = drm_open(); 253 CHECK(fd >= 0); 254 255 gbm = gbm_create_device(fd); 256 257 CHECK(gbm_device_get_fd(gbm) == fd); 258 259 struct gbm_bo *bo; 260 bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 261 CHECK(check_bo(bo)); 262 gbm_bo_destroy(bo); 263 264 return 1; 265 } 266 267 /* 268 * Tests repeated alloc/free. 269 */ 270 static int test_alloc_free() 271 { 272 int i; 273 for(i = 0; i < 1000; i++) { 274 struct gbm_bo *bo; 275 bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 276 CHECK(check_bo(bo)); 277 gbm_bo_destroy(bo); 278 } 279 return 1; 280 } 281 282 /* 283 * Tests that we can allocate different buffer dimensions. 284 */ 285 static int test_alloc_free_sizes() 286 { 287 int i; 288 for(i = 1; i < 1920; i++) { 289 struct gbm_bo *bo; 290 bo = gbm_bo_create(gbm, i, i, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 291 CHECK(check_bo(bo)); 292 gbm_bo_destroy(bo); 293 } 294 295 for(i = 1; i < 1920; i++) { 296 struct gbm_bo *bo; 297 bo = gbm_bo_create(gbm, i, 1, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 298 CHECK(check_bo(bo)); 299 gbm_bo_destroy(bo); 300 } 301 302 for(i = 1; i < 1920; i++) { 303 struct gbm_bo *bo; 304 bo = gbm_bo_create(gbm, 1, i, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 305 CHECK(check_bo(bo)); 306 gbm_bo_destroy(bo); 307 } 308 309 return 1; 310 } 311 312 /* 313 * Tests that we can allocate different buffer formats. 314 */ 315 static int test_alloc_free_formats() 316 { 317 int i; 318 319 for(i = 0; i < ARRAY_SIZE(format_list); i++) { 320 uint32_t format = format_list[i]; 321 if (gbm_device_is_format_supported(gbm, format, GBM_BO_USE_RENDERING)) { 322 struct gbm_bo *bo; 323 bo = gbm_bo_create(gbm, 1024, 1024, format, GBM_BO_USE_RENDERING); 324 CHECK(check_bo(bo)); 325 } 326 } 327 328 return 1; 329 } 330 331 /* 332 * Tests that we find at least one working format for each usage. 333 */ 334 static int test_alloc_free_usage() 335 { 336 int i, j; 337 338 for(i = 0; i < ARRAY_SIZE(usage_list); i++) { 339 uint32_t usage = usage_list[i]; 340 int found = 0; 341 for(j = 0; j < ARRAY_SIZE(format_list); j++) { 342 uint32_t format = format_list[j]; 343 if (gbm_device_is_format_supported(gbm, format, usage)) { 344 struct gbm_bo *bo; 345 bo = gbm_bo_create(gbm, 1024, 1024, format, usage); 346 CHECK(check_bo(bo)); 347 found = 1; 348 } 349 } 350 CHECK(found); 351 } 352 353 return 1; 354 } 355 356 /* 357 * Tests user data. 358 */ 359 static int been_there1; 360 static int been_there2; 361 362 void destroy_data1(struct gbm_bo *bo, void *data) 363 { 364 been_there1 = 1; 365 } 366 367 void destroy_data2(struct gbm_bo *bo, void *data) 368 { 369 been_there2 = 1; 370 } 371 372 static int test_user_data() 373 { 374 struct gbm_bo *bo1, *bo2; 375 char *data1, *data2; 376 377 been_there1 = 0; 378 been_there2 = 0; 379 380 bo1 = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 381 bo2 = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 382 data1 = (char*)malloc(1); 383 data2 = (char*)malloc(1); 384 CHECK(data1); 385 CHECK(data2); 386 387 gbm_bo_set_user_data(bo1, data1, destroy_data1); 388 gbm_bo_set_user_data(bo2, data2, destroy_data2); 389 390 CHECK((char*)gbm_bo_get_user_data(bo1) == data1); 391 CHECK((char*)gbm_bo_get_user_data(bo2) == data2); 392 393 gbm_bo_destroy(bo1); 394 CHECK(been_there1 == 1); 395 396 gbm_bo_set_user_data(bo2, NULL, NULL); 397 gbm_bo_destroy(bo2); 398 CHECK(been_there2 == 0); 399 400 free(data1); 401 free(data2); 402 403 return 1; 404 } 405 406 /* 407 * Tests destruction. 408 */ 409 static int test_destroy() 410 { 411 gbm_device_destroy(gbm); 412 close(fd); 413 414 return 1; 415 } 416 417 /* 418 * Tests prime export. 419 */ 420 static int test_export() 421 { 422 struct gbm_bo *bo; 423 int prime_fd; 424 425 bo = gbm_bo_create(gbm, 1024, 1024, GBM_FORMAT_XRGB8888, GBM_BO_USE_RENDERING); 426 CHECK(check_bo(bo)); 427 428 prime_fd = gbm_bo_get_fd(bo); 429 CHECK(prime_fd > 0); 430 close(prime_fd); 431 432 gbm_bo_destroy(bo); 433 434 return 1; 435 } 436 437 /* 438 * Tests prime import. 439 */ 440 static int test_import() 441 { 442 struct gbm_import_fd_data fd_data; 443 int vgem_fd = drm_open_vgem(); 444 struct drm_prime_handle prime_handle; 445 struct gbm_bo *bo; 446 const int width = 123; 447 const int height = 456; 448 const int bytes_per_pixel = 4; 449 const int size = width * height * bytes_per_pixel; 450 451 if (vgem_fd <= 0) 452 return 1; 453 454 CHECK(create_vgem_bo(vgem_fd, size, &prime_handle.handle) == 0); 455 prime_handle.flags = DRM_CLOEXEC; 456 CHECK(drmIoctl(vgem_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle) == 0); 457 458 fd_data.fd = prime_handle.fd; 459 fd_data.width = width; 460 fd_data.height = height; 461 fd_data.stride = width * bytes_per_pixel; 462 fd_data.format = GBM_FORMAT_XRGB8888; 463 464 bo = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &fd_data, GBM_BO_USE_RENDERING); 465 CHECK(check_bo(bo)); 466 gbm_bo_destroy(bo); 467 468 close(vgem_fd); 469 470 return 1; 471 } 472 473 int main(int argc, char *argv[]) 474 { 475 int result; 476 477 result = test_init(); 478 if (result == ENODISPLAY) { 479 printf("[ PASSED ] graphics_Gbm test no connected display found\n"); 480 return EXIT_SUCCESS; 481 } else if (!result) { 482 printf("[ FAILED ] graphics_Gbm test initialization failed\n"); 483 return EXIT_FAILURE; 484 } 485 486 result &= test_reinit(); 487 result &= test_alloc_free(); 488 result &= test_alloc_free_sizes(); 489 result &= test_alloc_free_formats(); 490 result &= test_alloc_free_usage(); 491 result &= test_user_data(); 492 result &= test_export(); 493 result &= test_import(); 494 result &= test_destroy(); 495 496 if (!result) { 497 printf("[ FAILED ] graphics_Gbm test failed\n"); 498 return EXIT_FAILURE; 499 } else { 500 printf("[ PASSED ] graphics_Gbm test success\n"); 501 return EXIT_SUCCESS; 502 } 503 } 504 505