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