OSDN Git Service

freedreno: rework internal ring->emit_reloc_ring()
[android-x86/external-libdrm.git] / tests / exynos / exynos_fimg2d_test.c
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
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
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
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.                */
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
173 static void exynos_destroy_buffer(struct exynos_bo *bo)
174 {
175         exynos_bo_destroy(bo);
176 }
177
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
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
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
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
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
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
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
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
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 }