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 
check_bo(struct gbm_bo * bo)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 
find_first_connected_connector(int fd,drmModeRes * resources)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 
drm_open()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 
drm_open_vgem()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 
create_vgem_bo(int fd,size_t size,uint32_t * handle)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  */
test_init()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  */
test_reinit()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  */
test_alloc_free()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  */
test_alloc_free_sizes()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  */
test_alloc_free_formats()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  */
test_alloc_free_usage()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 
destroy_data1(struct gbm_bo * bo,void * data)362 void destroy_data1(struct gbm_bo *bo, void *data)
363 {
364 	been_there1 = 1;
365 }
366 
destroy_data2(struct gbm_bo * bo,void * data)367 void destroy_data2(struct gbm_bo *bo, void *data)
368 {
369 	been_there2 = 1;
370 }
371 
test_user_data()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  */
test_destroy()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  */
test_export()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  */
test_import()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 
main(int argc,char * argv[])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