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