1 /*
2 * Copyright (C) 2013 Samsung Electronics Co.Ltd
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 */
12
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <time.h>
22 #include <unistd.h>
23
24 #include <sys/mman.h>
25 #include <linux/stddef.h>
26
27 #include <xf86drm.h>
28 #include <xf86drmMode.h>
29 #include <libkms.h>
30 #include <drm_fourcc.h>
31
32 #include "exynos_drm.h"
33 #include "exynos_drmif.h"
34 #include "exynos_fimg2d.h"
35
36 #define DRM_MODULE_NAME "exynos"
37
38 static unsigned int screen_width, screen_height;
39
40 struct connector {
41 uint32_t id;
42 char mode_str[64];
43 drmModeModeInfo *mode;
44 drmModeEncoder *encoder;
45 int crtc;
46 };
47
connector_find_mode(int fd,struct connector * c,drmModeRes * resources)48 static void connector_find_mode(int fd, struct connector *c,
49 drmModeRes *resources)
50 {
51 drmModeConnector *connector;
52 int i, j;
53
54 /* First, find the connector & mode */
55 c->mode = NULL;
56 for (i = 0; i < resources->count_connectors; i++) {
57 connector = drmModeGetConnector(fd, resources->connectors[i]);
58
59 if (!connector) {
60 fprintf(stderr, "could not get connector %i: %s\n",
61 resources->connectors[i], strerror(errno));
62 drmModeFreeConnector(connector);
63 continue;
64 }
65
66 if (!connector->count_modes) {
67 drmModeFreeConnector(connector);
68 continue;
69 }
70
71 if (connector->connector_id != c->id) {
72 drmModeFreeConnector(connector);
73 continue;
74 }
75
76 for (j = 0; j < connector->count_modes; j++) {
77 c->mode = &connector->modes[j];
78 if (!strcmp(c->mode->name, c->mode_str))
79 break;
80 }
81
82 /* Found it, break out */
83 if (c->mode)
84 break;
85
86 drmModeFreeConnector(connector);
87 }
88
89 if (!c->mode) {
90 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
91 return;
92 }
93
94 /* Now get the encoder */
95 for (i = 0; i < resources->count_encoders; i++) {
96 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
97
98 if (!c->encoder) {
99 fprintf(stderr, "could not get encoder %i: %s\n",
100 resources->encoders[i], strerror(errno));
101 drmModeFreeEncoder(c->encoder);
102 continue;
103 }
104
105 if (c->encoder->encoder_id == connector->encoder_id)
106 break;
107
108 drmModeFreeEncoder(c->encoder);
109 }
110
111 if (c->crtc == -1)
112 c->crtc = c->encoder->crtc_id;
113 }
114
drm_set_crtc(struct exynos_device * dev,struct connector * c,unsigned int fb_id)115 static int drm_set_crtc(struct exynos_device *dev, struct connector *c,
116 unsigned int fb_id)
117 {
118 int ret;
119
120 ret = drmModeSetCrtc(dev->fd, c->crtc,
121 fb_id, 0, 0, &c->id, 1, c->mode);
122 if (ret)
123 drmMsg("failed to set mode: %s\n", strerror(errno));
124
125 return ret;
126 }
127
exynos_create_buffer(struct exynos_device * dev,unsigned long size,unsigned int flags)128 static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev,
129 unsigned long size,
130 unsigned int flags)
131 {
132 struct exynos_bo *bo;
133
134 bo = exynos_bo_create(dev, size, flags);
135 if (!bo)
136 return bo;
137
138 if (!exynos_bo_map(bo)) {
139 exynos_bo_destroy(bo);
140 return NULL;
141 }
142
143 return bo;
144 }
145
146 /* Allocate buffer and fill it with checkerboard pattern, where the tiles *
147 * have a random color. The caller has to free the buffer. */
create_checkerboard_pattern(unsigned int num_tiles_x,unsigned int num_tiles_y,unsigned int tile_size)148 static void *create_checkerboard_pattern(unsigned int num_tiles_x,
149 unsigned int num_tiles_y, unsigned int tile_size)
150 {
151 unsigned int *buf;
152 unsigned int x, y, i, j;
153 const unsigned int stride = num_tiles_x * tile_size;
154
155 if (posix_memalign((void*)&buf, 64, num_tiles_y * tile_size * stride * 4) != 0)
156 return NULL;
157
158 for (x = 0; x < num_tiles_x; ++x) {
159 for (y = 0; y < num_tiles_y; ++y) {
160 const unsigned int color = 0xff000000 + (random() & 0xffffff);
161
162 for (i = 0; i < tile_size; ++i) {
163 for (j = 0; j < tile_size; ++j) {
164 buf[x * tile_size + y * stride * tile_size + i + j * stride] = color;
165 }
166 }
167 }
168 }
169
170 return buf;
171 }
172
exynos_destroy_buffer(struct exynos_bo * bo)173 static void exynos_destroy_buffer(struct exynos_bo *bo)
174 {
175 exynos_bo_destroy(bo);
176 }
177
wait_for_user_input(int last)178 static void wait_for_user_input(int last)
179 {
180 printf("press <ENTER> to %s\n", last ? "exit test application" :
181 "skip to next test");
182
183 getchar();
184 }
185
g2d_solid_fill_test(struct exynos_device * dev,struct exynos_bo * dst)186 static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst)
187 {
188 struct g2d_context *ctx;
189 struct g2d_image img = {0};
190 unsigned int count, img_w, img_h;
191 int ret = 0;
192
193 ctx = g2d_init(dev->fd);
194 if (!ctx)
195 return -EFAULT;
196
197 img.bo[0] = dst->handle;
198
199 printf("solid fill test.\n");
200
201 srand(time(NULL));
202 img_w = screen_width;
203 img_h = screen_height;
204
205 for (count = 0; count < 2; count++) {
206 unsigned int x, y, w, h;
207
208 x = rand() % (img_w / 2);
209 y = rand() % (img_h / 2);
210 w = rand() % (img_w - x);
211 h = rand() % (img_h - y);
212
213 img.width = img_w;
214 img.height = img_h;
215 img.stride = img.width * 4;
216 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
217 img.color = 0xff000000 + (random() & 0xffffff);
218
219 ret = g2d_solid_fill(ctx, &img, x, y, w, h);
220 if (ret < 0)
221 goto err_fini;
222
223 ret = g2d_exec(ctx);
224 if (ret < 0)
225 break;
226 }
227
228 err_fini:
229 g2d_fini(ctx);
230
231 return ret;
232 }
233
g2d_copy_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)234 static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src,
235 struct exynos_bo *dst,
236 enum e_g2d_buf_type type)
237 {
238 struct g2d_context *ctx;
239 struct g2d_image src_img = {0}, dst_img = {0};
240 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
241 unsigned long userptr, size;
242 int ret;
243
244 ctx = g2d_init(dev->fd);
245 if (!ctx)
246 return -EFAULT;
247
248 dst_img.bo[0] = dst->handle;
249
250 src_x = 0;
251 src_y = 0;
252 dst_x = 0;
253 dst_y = 0;
254 img_w = screen_width;
255 img_h = screen_height;
256
257 switch (type) {
258 case G2D_IMGBUF_GEM:
259 src_img.bo[0] = src->handle;
260 break;
261 case G2D_IMGBUF_USERPTR:
262 size = img_w * img_h * 4;
263
264 userptr = (unsigned long)malloc(size);
265 if (!userptr) {
266 fprintf(stderr, "failed to allocate userptr.\n");
267 return -EFAULT;
268 }
269
270 src_img.user_ptr[0].userptr = userptr;
271 src_img.user_ptr[0].size = size;
272 break;
273 case G2D_IMGBUF_COLOR:
274 default:
275 ret = -EFAULT;
276 goto fail;
277 }
278
279 printf("copy test with %s.\n",
280 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
281
282 src_img.width = img_w;
283 src_img.height = img_h;
284 src_img.stride = src_img.width * 4;
285 src_img.buf_type = type;
286 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
287 src_img.color = 0xffff0000;
288 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
289 if (ret < 0)
290 goto err_free_userptr;
291
292 dst_img.width = img_w;
293 dst_img.height = img_h;
294 dst_img.stride = dst_img.width * 4;
295 dst_img.buf_type = G2D_IMGBUF_GEM;
296 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
297
298 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
299 img_w - 4, img_h - 4);
300 if (ret < 0)
301 goto err_free_userptr;
302
303 g2d_exec(ctx);
304
305 err_free_userptr:
306 if (type == G2D_IMGBUF_USERPTR)
307 if (userptr)
308 free((void *)userptr);
309
310 fail:
311 g2d_fini(ctx);
312
313 return ret;
314 }
315
g2d_move_test(struct exynos_device * dev,struct exynos_bo * tmp,struct exynos_bo * buf,enum e_g2d_buf_type type)316 static int g2d_move_test(struct exynos_device *dev,
317 struct exynos_bo *tmp,
318 struct exynos_bo *buf,
319 enum e_g2d_buf_type type)
320 {
321 struct g2d_context *ctx;
322 struct g2d_image img = {0}, tmp_img = {0};
323 unsigned int img_w, img_h, count;
324 int cur_x, cur_y;
325 void *checkerboard;
326 int ret;
327
328 static const struct g2d_step {
329 int x, y;
330 } steps[] = {
331 { 1, 0}, { 0, 1},
332 {-1, 0}, { 0, -1},
333 { 1, 1}, {-1, -1},
334 { 1, -1}, {-1, 1},
335 { 2, 1}, { 1, 2},
336 {-2, -1}, {-1, -2},
337 { 2, -1}, { 1, -2},
338 {-2, 1}, {-1, 2}
339 };
340 static const unsigned int num_steps =
341 sizeof(steps) / sizeof(struct g2d_step);
342
343 ctx = g2d_init(dev->fd);
344 if (!ctx)
345 return -EFAULT;
346
347 img.bo[0] = buf->handle;
348
349 /* create pattern of half the screen size */
350 checkerboard = create_checkerboard_pattern(screen_width / 64, screen_height / 64, 32);
351 if (!checkerboard) {
352 ret = -EFAULT;
353 goto fail;
354 }
355
356 img_w = (screen_width / 64) * 32;
357 img_h = (screen_height / 64) * 32;
358
359 switch (type) {
360 case G2D_IMGBUF_GEM:
361 memcpy(tmp->vaddr, checkerboard, img_w * img_h * 4);
362 tmp_img.bo[0] = tmp->handle;
363 break;
364 case G2D_IMGBUF_USERPTR:
365 tmp_img.user_ptr[0].userptr = (unsigned long)checkerboard;
366 tmp_img.user_ptr[0].size = img_w * img_h * 4;
367 break;
368 case G2D_IMGBUF_COLOR:
369 default:
370 ret = -EFAULT;
371 goto fail;
372 }
373
374 /* solid fill framebuffer with white color */
375 img.width = screen_width;
376 img.height = screen_height;
377 img.stride = screen_width * 4;
378 img.buf_type = G2D_IMGBUF_GEM;
379 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
380 img.color = 0xffffffff;
381
382 /* put checkerboard pattern in the center of the framebuffer */
383 cur_x = (screen_width - img_w) / 2;
384 cur_y = (screen_height - img_h) / 2;
385 tmp_img.width = img_w;
386 tmp_img.height = img_h;
387 tmp_img.stride = img_w * 4;
388 tmp_img.buf_type = type;
389 tmp_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
390
391 ret = g2d_solid_fill(ctx, &img, 0, 0, screen_width, screen_height) ||
392 g2d_copy(ctx, &tmp_img, &img, 0, 0, cur_x, cur_y, img_w, img_h);
393
394 if (!ret)
395 ret = g2d_exec(ctx);
396 if (ret < 0)
397 goto fail;
398
399 printf("move test with %s.\n",
400 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
401
402 srand(time(NULL));
403 for (count = 0; count < 256; ++count) {
404 const struct g2d_step *s;
405
406 /* select step and validate it */
407 while (1) {
408 s = &steps[random() % num_steps];
409
410 if (cur_x + s->x < 0 || cur_y + s->y < 0 ||
411 cur_x + img_w + s->x >= screen_width ||
412 cur_y + img_h + s->y >= screen_height)
413 continue;
414 else
415 break;
416 }
417
418 ret = g2d_move(ctx, &img, cur_x, cur_y, cur_x + s->x, cur_y + s->y,
419 img_w, img_h);
420 if (!ret)
421 ret = g2d_exec(ctx);
422
423 if (ret < 0)
424 goto fail;
425
426 cur_x += s->x;
427 cur_y += s->y;
428
429 usleep(100000);
430 }
431
432 fail:
433 g2d_fini(ctx);
434
435 free(checkerboard);
436
437 return ret;
438 }
439
g2d_copy_with_scale_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)440 static int g2d_copy_with_scale_test(struct exynos_device *dev,
441 struct exynos_bo *src,
442 struct exynos_bo *dst,
443 enum e_g2d_buf_type type)
444 {
445 struct g2d_context *ctx;
446 struct g2d_image src_img = {0}, dst_img = {0};
447 unsigned int src_x, src_y, img_w, img_h;
448 unsigned long userptr, size;
449 int ret;
450
451 ctx = g2d_init(dev->fd);
452 if (!ctx)
453 return -EFAULT;
454
455 dst_img.bo[0] = dst->handle;
456
457 src_x = 0;
458 src_y = 0;
459 img_w = screen_width;
460 img_h = screen_height;
461
462 switch (type) {
463 case G2D_IMGBUF_GEM:
464 src_img.bo[0] = src->handle;
465 break;
466 case G2D_IMGBUF_USERPTR:
467 size = img_w * img_h * 4;
468
469 userptr = (unsigned long)malloc(size);
470 if (!userptr) {
471 fprintf(stderr, "failed to allocate userptr.\n");
472 return -EFAULT;
473 }
474
475 src_img.user_ptr[0].userptr = userptr;
476 src_img.user_ptr[0].size = size;
477 break;
478 case G2D_IMGBUF_COLOR:
479 default:
480 ret = -EFAULT;
481 goto fail;
482 }
483
484 printf("copy and scale test with %s.\n",
485 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
486
487 src_img.width = img_w;
488 src_img.height = img_h;
489 src_img.stride = src_img.width * 4;
490 src_img.buf_type = type;
491 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
492 src_img.color = 0xffffffff;
493 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w , img_h);
494 if (ret < 0)
495 goto err_free_userptr;
496
497 src_img.color = 0xff00ff00;
498 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100);
499 if (ret < 0)
500 goto err_free_userptr;
501
502 dst_img.width = img_w;
503 dst_img.height = img_h;
504 dst_img.buf_type = G2D_IMGBUF_GEM;
505 dst_img.stride = dst_img.width * 4;
506 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
507
508 ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100,
509 100, 100, 200, 200, 0);
510 if (ret < 0)
511 goto err_free_userptr;
512
513 g2d_exec(ctx);
514
515 err_free_userptr:
516 if (type == G2D_IMGBUF_USERPTR)
517 if (userptr)
518 free((void *)userptr);
519
520 fail:
521 g2d_fini(ctx);
522
523 return 0;
524 }
525
g2d_blend_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)526 static int g2d_blend_test(struct exynos_device *dev,
527 struct exynos_bo *src,
528 struct exynos_bo *dst,
529 enum e_g2d_buf_type type)
530 {
531 struct g2d_context *ctx;
532 struct g2d_image src_img = {0}, dst_img = {0};
533 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
534 unsigned long userptr, size;
535 int ret;
536
537 ctx = g2d_init(dev->fd);
538 if (!ctx)
539 return -EFAULT;
540
541 dst_img.bo[0] = dst->handle;
542
543 src_x = 0;
544 src_y = 0;
545 dst_x = 0;
546 dst_y = 0;
547 img_w = screen_width;
548 img_h = screen_height;
549
550 switch (type) {
551 case G2D_IMGBUF_GEM:
552 src_img.bo[0] = src->handle;
553 break;
554 case G2D_IMGBUF_USERPTR:
555 size = img_w * img_h * 4;
556
557 userptr = (unsigned long)malloc(size);
558 if (!userptr) {
559 fprintf(stderr, "failed to allocate userptr.\n");
560 return -EFAULT;
561 }
562
563 src_img.user_ptr[0].userptr = userptr;
564 src_img.user_ptr[0].size = size;
565 break;
566 case G2D_IMGBUF_COLOR:
567 default:
568 ret = -EFAULT;
569 goto fail;
570 }
571
572 printf("blend test with %s.\n",
573 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
574
575 src_img.width = img_w;
576 src_img.height = img_h;
577 src_img.stride = src_img.width * 4;
578 src_img.buf_type = type;
579 src_img.select_mode = G2D_SELECT_MODE_NORMAL;
580 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
581 src_img.color = 0xffffffff;
582 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
583 if (ret < 0)
584 goto err_free_userptr;
585
586 src_img.color = 0x770000ff;
587 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200);
588 if (ret < 0)
589 goto err_free_userptr;
590
591 dst_img.width = img_w;
592 dst_img.height = img_h;
593 dst_img.stride = dst_img.width * 4;
594 dst_img.buf_type = G2D_IMGBUF_GEM;
595 dst_img.select_mode = G2D_SELECT_MODE_NORMAL;
596 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
597 dst_img.color = 0xffffffff;
598 ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h);
599 if (ret < 0)
600 goto err_free_userptr;
601
602 dst_img.color = 0x77ff0000;
603 ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200);
604 if (ret < 0)
605 goto err_free_userptr;
606
607 ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200,
608 G2D_OP_OVER);
609 if (ret < 0)
610 goto err_free_userptr;
611
612 g2d_exec(ctx);
613
614 err_free_userptr:
615 if (type == G2D_IMGBUF_USERPTR)
616 if (userptr)
617 free((void *)userptr);
618
619 fail:
620 g2d_fini(ctx);
621
622 return 0;
623 }
624
g2d_checkerboard_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)625 static int g2d_checkerboard_test(struct exynos_device *dev,
626 struct exynos_bo *src,
627 struct exynos_bo *dst,
628 enum e_g2d_buf_type type)
629 {
630 struct g2d_context *ctx;
631 struct g2d_image src_img = {0}, dst_img = {0};
632 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
633 void *checkerboard = NULL;
634 int ret;
635
636 ctx = g2d_init(dev->fd);
637 if (!ctx)
638 return -EFAULT;
639
640 dst_img.bo[0] = dst->handle;
641
642 src_x = 0;
643 src_y = 0;
644 dst_x = 0;
645 dst_y = 0;
646
647 checkerboard = create_checkerboard_pattern(screen_width / 32, screen_height / 32, 32);
648 if (checkerboard == NULL) {
649 ret = -1;
650 goto fail;
651 }
652
653 img_w = screen_width - (screen_width % 32);
654 img_h = screen_height - (screen_height % 32);
655
656 switch (type) {
657 case G2D_IMGBUF_GEM:
658 memcpy(src->vaddr, checkerboard, img_w * img_h * 4);
659 src_img.bo[0] = src->handle;
660 break;
661 case G2D_IMGBUF_USERPTR:
662 src_img.user_ptr[0].userptr = (unsigned long)checkerboard;
663 src_img.user_ptr[0].size = img_w * img_h * 4;
664 break;
665 case G2D_IMGBUF_COLOR:
666 default:
667 ret = -EFAULT;
668 goto fail;
669 }
670
671 printf("checkerboard test with %s.\n",
672 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
673
674 src_img.width = img_w;
675 src_img.height = img_h;
676 src_img.stride = src_img.width * 4;
677 src_img.buf_type = type;
678 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
679
680 dst_img.width = screen_width;
681 dst_img.height = screen_height;
682 dst_img.stride = dst_img.width * 4;
683 dst_img.buf_type = G2D_IMGBUF_GEM;
684 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
685 src_img.color = 0xff000000;
686 ret = g2d_solid_fill(ctx, &dst_img, src_x, src_y, screen_width, screen_height);
687 if (ret < 0)
688 goto fail;
689
690 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
691 img_w, img_h);
692 if (ret < 0)
693 goto fail;
694
695 g2d_exec(ctx);
696
697 fail:
698 free(checkerboard);
699 g2d_fini(ctx);
700
701 return ret;
702 }
703
usage(char * name)704 static void usage(char *name)
705 {
706 fprintf(stderr, "usage: %s [-s]\n", name);
707 fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n");
708 exit(0);
709 }
710
711 extern char *optarg;
712 static const char optstr[] = "s:";
713
main(int argc,char ** argv)714 int main(int argc, char **argv)
715 {
716 struct exynos_device *dev;
717 struct exynos_bo *bo, *src;
718 struct connector con;
719 unsigned int fb_id;
720 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
721 drmModeRes *resources;
722 int ret, fd, c;
723
724 memset(&con, 0, sizeof(struct connector));
725
726 if (argc != 3) {
727 usage(argv[0]);
728 return -EINVAL;
729 }
730
731 while ((c = getopt(argc, argv, optstr)) != -1) {
732 switch (c) {
733 case 's':
734 con.crtc = -1;
735 if (sscanf(optarg, "%d:0x%64s",
736 &con.id,
737 con.mode_str) != 2 &&
738 sscanf(optarg, "%d@%d:%64s",
739 &con.id,
740 &con.crtc,
741 con.mode_str) != 3)
742 usage(argv[0]);
743 break;
744 default:
745 usage(argv[0]);
746 break;
747 }
748 }
749
750 fd = drmOpen(DRM_MODULE_NAME, NULL);
751 if (fd < 0) {
752 fprintf(stderr, "failed to open.\n");
753 return fd;
754 }
755
756 dev = exynos_device_create(fd);
757 if (!dev) {
758 drmClose(dev->fd);
759 return -EFAULT;
760 }
761
762 resources = drmModeGetResources(dev->fd);
763 if (!resources) {
764 fprintf(stderr, "drmModeGetResources failed: %s\n",
765 strerror(errno));
766 ret = -EFAULT;
767 goto err_drm_close;
768 }
769
770 connector_find_mode(dev->fd, &con, resources);
771 drmModeFreeResources(resources);
772
773 if (!con.mode) {
774 fprintf(stderr, "failed to find usable connector\n");
775 ret = -EFAULT;
776 goto err_drm_close;
777 }
778
779 screen_width = con.mode->hdisplay;
780 screen_height = con.mode->vdisplay;
781
782 if (screen_width == 0 || screen_height == 0) {
783 fprintf(stderr, "failed to find sane resolution on connector\n");
784 ret = -EFAULT;
785 goto err_drm_close;
786 }
787
788 printf("screen width = %d, screen height = %d\n", screen_width,
789 screen_height);
790
791 bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
792 if (!bo) {
793 ret = -EFAULT;
794 goto err_drm_close;
795 }
796
797 handles[0] = bo->handle;
798 pitches[0] = screen_width * 4;
799 offsets[0] = 0;
800
801 ret = drmModeAddFB2(dev->fd, screen_width, screen_height,
802 DRM_FORMAT_XRGB8888, handles,
803 pitches, offsets, &fb_id, 0);
804 if (ret < 0)
805 goto err_destroy_buffer;
806
807 memset(bo->vaddr, 0xff, screen_width * screen_height * 4);
808
809 ret = drm_set_crtc(dev, &con, fb_id);
810 if (ret < 0)
811 goto err_rm_fb;
812
813 ret = g2d_solid_fill_test(dev, bo);
814 if (ret < 0) {
815 fprintf(stderr, "failed to solid fill operation.\n");
816 goto err_rm_fb;
817 }
818
819 wait_for_user_input(0);
820
821 src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
822 if (!src) {
823 ret = -EFAULT;
824 goto err_rm_fb;
825 }
826
827 ret = g2d_copy_test(dev, src, bo, G2D_IMGBUF_GEM);
828 if (ret < 0) {
829 fprintf(stderr, "failed to test copy operation.\n");
830 goto err_free_src;
831 }
832
833 wait_for_user_input(0);
834
835 ret = g2d_move_test(dev, src, bo, G2D_IMGBUF_GEM);
836 if (ret < 0) {
837 fprintf(stderr, "failed to test move operation.\n");
838 goto err_free_src;
839 }
840
841 wait_for_user_input(0);
842
843 ret = g2d_copy_with_scale_test(dev, src, bo, G2D_IMGBUF_GEM);
844 if (ret < 0) {
845 fprintf(stderr, "failed to test copy and scale operation.\n");
846 goto err_free_src;
847 }
848
849 wait_for_user_input(0);
850
851 ret = g2d_checkerboard_test(dev, src, bo, G2D_IMGBUF_GEM);
852 if (ret < 0) {
853 fprintf(stderr, "failed to issue checkerboard test.\n");
854 goto err_free_src;
855 }
856
857 wait_for_user_input(1);
858
859 /*
860 * The blend test uses the userptr functionality of exynos-drm, which
861 * is currently not safe to use. If the kernel hasn't been build with
862 * exynos-iommu support, then the blend test is going to produce (kernel)
863 * memory corruption, eventually leading to a system crash.
864 *
865 * Disable the test for now, until the kernel code has been sanitized.
866 */
867 #if 0
868 ret = g2d_blend_test(dev, src, bo, G2D_IMGBUF_USERPTR);
869 if (ret < 0)
870 fprintf(stderr, "failed to test blend operation.\n");
871
872 getchar();
873 #endif
874
875 err_free_src:
876 if (src)
877 exynos_destroy_buffer(src);
878
879 err_rm_fb:
880 drmModeRmFB(dev->fd, fb_id);
881
882 err_destroy_buffer:
883 exynos_destroy_buffer(bo);
884
885 err_drm_close:
886 drmClose(dev->fd);
887 exynos_device_destroy(dev);
888
889 return 0;
890 }
891