• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
37 static int fd;
38 static struct gbm_device *gbm;
39 
40 static 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 
89 static 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 
check_bo(struct gbm_bo * bo)96 static 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 
find_first_connected_connector(int fd,drmModeRes * resources)144 static 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 
drm_open()163 static 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 
drm_open_vgem()207 static 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 
create_vgem_bo(int fd,size_t size,uint32_t * handle)241 static 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  */
test_init()265 static 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  */
test_reinit()286 static 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  */
test_alloc_free()309 static 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  */
test_alloc_free_sizes()324 static 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  */
test_alloc_free_formats()354 static 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  */
test_alloc_free_usage()373 static 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  */
398 static int been_there1;
399 static int been_there2;
400 
destroy_data1(struct gbm_bo * bo,void * data)401 void destroy_data1(struct gbm_bo *bo, void *data)
402 {
403 	been_there1 = 1;
404 }
405 
destroy_data2(struct gbm_bo * bo,void * data)406 void destroy_data2(struct gbm_bo *bo, void *data)
407 {
408 	been_there2 = 1;
409 }
410 
test_user_data()411 static 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  */
test_destroy()448 static int test_destroy()
449 {
450 	gbm_device_destroy(gbm);
451 	close(fd);
452 
453 	return 1;
454 }
455 
456 /*
457  * Tests prime export.
458  */
test_export()459 static 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  */
test_import_vgem()479 static 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  */
test_import_dmabuf()516 static 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  */
test_import_planar()554 static 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 
test_gem_map()610 static 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, GBM_BO_TRANSFER_READ_WRITE, &stride,
626 		          &map_data, 0);
627 
628 	CHECK(addr != MAP_FAILED);
629 	CHECK(map_data);
630 	CHECK(stride > 0);
631 
632 	pixel = (uint32_t *)addr;
633 	pixel_size = sizeof(*pixel);
634 
635 	pixel[(height / 2) * (stride / pixel_size) + width / 2] = 0xABBAABBA;
636 	gbm_bo_unmap(bo, map_data);
637 
638 	/* Re-map and verify written previously data. */
639 	stride = 0;
640 	addr = map_data = NULL;
641 
642 	addr = gbm_bo_map(bo, 0, 0, width, height, GBM_BO_TRANSFER_READ_WRITE, &stride,
643 		          &map_data, 0);
644 
645 	CHECK(addr != MAP_FAILED);
646 	CHECK(map_data);
647 	CHECK(stride > 0);
648 
649 	pixel = (uint32_t *)addr;
650 	CHECK(pixel[(height / 2) * (stride / pixel_size) + width / 2] == 0xABBAABBA);
651 
652 	gbm_bo_unmap(bo, map_data);
653 	gbm_bo_destroy(bo);
654 
655 	return 1;
656 }
657 
main(int argc,char * argv[])658 int main(int argc, char *argv[])
659 {
660 	int result;
661 
662 	result = test_init();
663 	if (result == ENODISPLAY) {
664 		printf("[  PASSED  ] graphics_Gbm test no connected display found\n");
665 		return EXIT_SUCCESS;
666 	} else if (!result) {
667 		printf("[  FAILED  ] graphics_Gbm test initialization failed\n");
668 		return EXIT_FAILURE;
669 	}
670 
671 	result &= test_reinit();
672 	result &= test_alloc_free();
673 	result &= test_alloc_free_sizes();
674 	result &= test_alloc_free_formats();
675 	result &= test_alloc_free_usage();
676 	result &= test_user_data();
677 	result &= test_export();
678 	result &= test_import_vgem();
679 	result &= test_import_dmabuf();
680 	result &= test_import_planar();
681 	result &= test_gem_map();
682 	result &= test_destroy();
683 
684 	if (!result) {
685 		printf("[  FAILED  ] graphics_Gbm test failed\n");
686 		return EXIT_FAILURE;
687 	} else {
688 		printf("[  PASSED  ] graphics_Gbm test success\n");
689 		return EXIT_SUCCESS;
690 	}
691 }
692 
693