Home | History | Annotate | Download | only in src
      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