e80455a9bd3534682de2b4158bb7aae25743bd0b
[platform/upstream/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
22 #include <sys/mman.h>
23 #include <linux/stddef.h>
24
25 #include <xf86drm.h>
26 #include <xf86drmMode.h>
27 #include <libkms.h>
28 #include <drm_fourcc.h>
29
30 #include "exynos_drm.h"
31 #include "exynos_drmif.h"
32 #include "fimg2d.h"
33
34 #define DRM_MODULE_NAME         "exynos"
35 #define MAX_TEST_CASE           8
36
37 static unsigned int screen_width, screen_height;
38
39 /*
40  * A structure to test fimg2d hw.
41  *
42  * @solid_fild: fill given color data to source buffer.
43  * @copy: copy source to destination buffer.
44  * @copy_with_scale: copy source to destination buffer scaling up or
45  *      down properly.
46  * @blend: blend source to destination buffer.
47  */
48 struct fimg2d_test_case {
49         int (*solid_fill)(struct exynos_device *dev, struct exynos_bo *dst);
50         int (*copy)(struct exynos_device *dev, struct exynos_bo *src,
51                         struct exynos_bo *dst, enum e_g2d_buf_type);
52         int (*copy_with_scale)(struct exynos_device *dev,
53                                 struct exynos_bo *src, struct exynos_bo *dst,
54                                 enum e_g2d_buf_type);
55         int (*blend)(struct exynos_device *dev,
56                                 struct exynos_bo *src, struct exynos_bo *dst,
57                                 enum e_g2d_buf_type);
58 };
59
60 struct connector {
61         uint32_t id;
62         char mode_str[64];
63         char format_str[5];
64         unsigned int fourcc;
65         drmModeModeInfo *mode;
66         drmModeEncoder *encoder;
67         int crtc;
68         int pipe;
69         int plane_zpos;
70         unsigned int fb_id[2], current_fb_id;
71         struct timeval start;
72
73         int swap_count;
74 };
75
76 static void connector_find_mode(int fd, struct connector *c,
77                                 drmModeRes *resources)
78 {
79         drmModeConnector *connector;
80         int i, j;
81
82         /* First, find the connector & mode */
83         c->mode = NULL;
84         for (i = 0; i < resources->count_connectors; i++) {
85                 connector = drmModeGetConnector(fd, resources->connectors[i]);
86
87                 if (!connector) {
88                         fprintf(stderr, "could not get connector %i: %s\n",
89                                 resources->connectors[i], strerror(errno));
90                         drmModeFreeConnector(connector);
91                         continue;
92                 }
93
94                 if (!connector->count_modes) {
95                         drmModeFreeConnector(connector);
96                         continue;
97                 }
98
99                 if (connector->connector_id != c->id) {
100                         drmModeFreeConnector(connector);
101                         continue;
102                 }
103
104                 for (j = 0; j < connector->count_modes; j++) {
105                         c->mode = &connector->modes[j];
106                         if (!strcmp(c->mode->name, c->mode_str))
107                                 break;
108                 }
109
110                 /* Found it, break out */
111                 if (c->mode)
112                         break;
113
114                 drmModeFreeConnector(connector);
115         }
116
117         if (!c->mode) {
118                 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
119                 return;
120         }
121
122         /* Now get the encoder */
123         for (i = 0; i < resources->count_encoders; i++) {
124                 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
125
126                 if (!c->encoder) {
127                         fprintf(stderr, "could not get encoder %i: %s\n",
128                                 resources->encoders[i], strerror(errno));
129                         drmModeFreeEncoder(c->encoder);
130                         continue;
131                 }
132
133                 if (c->encoder->encoder_id  == connector->encoder_id)
134                         break;
135
136                 drmModeFreeEncoder(c->encoder);
137         }
138
139         if (c->crtc == -1)
140                 c->crtc = c->encoder->crtc_id;
141 }
142
143 static int connector_find_plane(int fd, unsigned int *plane_id)
144 {
145         drmModePlaneRes *plane_resources;
146         drmModePlane *ovr;
147         int i;
148
149         plane_resources = drmModeGetPlaneResources(fd);
150         if (!plane_resources) {
151                 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
152                         strerror(errno));
153                 return -1;
154         }
155
156         for (i = 0; i < plane_resources->count_planes; i++) {
157                 plane_id[i] = 0;
158
159                 ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
160                 if (!ovr) {
161                         fprintf(stderr, "drmModeGetPlane failed: %s\n",
162                                 strerror(errno));
163                         continue;
164                 }
165
166                 if (ovr->possible_crtcs & (1 << 0))
167                         plane_id[i] = ovr->plane_id;
168                 drmModeFreePlane(ovr);
169         }
170
171         return 0;
172 }
173
174 static int drm_set_crtc(struct exynos_device *dev, struct connector *c,
175                         unsigned int fb_id)
176 {
177         int ret;
178
179         ret = drmModeSetCrtc(dev->fd, c->crtc,
180                         fb_id, 0, 0, &c->id, 1, c->mode);
181         if (ret) {
182                 drmMsg("failed to set mode: %s\n", strerror(errno));
183                 goto err;
184         }
185
186         return 0;
187
188 err:
189         return ret;
190 }
191
192 static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev,
193                                                 unsigned long size,
194                                                 unsigned int flags)
195 {
196         struct exynos_bo *bo;
197
198         bo = exynos_bo_create(dev, size, flags);
199         if (!bo)
200                 return bo;
201
202         if (!exynos_bo_map(bo)) {
203                 exynos_bo_destroy(bo);
204                 return NULL;
205         }
206
207         return bo;
208 }
209
210 static void exynos_destroy_buffer(struct exynos_bo *bo)
211 {
212         exynos_bo_destroy(bo);
213 }
214
215 static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst)
216 {
217         struct g2d_context *ctx;
218         struct g2d_image img;
219         unsigned int count, img_w, img_h;
220         int ret = 0;
221
222         ctx = g2d_init(dev->fd);
223         if (!ctx)
224                 return -EFAULT;
225
226         memset(&img, 0, sizeof(struct g2d_image));
227         img.bo[0] = dst->handle;
228
229         printf("soild fill test.\n");
230
231         srand(time(NULL));
232         img_w = screen_width;
233         img_h = screen_height;
234
235         for (count = 0; count < 2; count++) {
236                 unsigned int x, y, w, h;
237
238                 x = rand() % (img_w / 2);
239                 y = rand() % (img_h / 2);
240                 w = rand() % (img_w - x);
241                 h = rand() % (img_h - y);
242
243                 img.width = img_w;
244                 img.height = img_h;
245                 img.stride = img.width * 4;
246                 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
247                 img.color = 0xff000000 + (random() & 0xffffff);
248
249                 ret = g2d_solid_fill(ctx, &img, x, y, w, h);
250                 if (ret < 0)
251                         goto err_fini;
252
253                 ret = g2d_exec(ctx);
254                 if (ret < 0)
255                         break;
256         }
257
258 err_fini:
259         g2d_fini(ctx);
260
261         return ret;
262 }
263
264 static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src,
265                                 struct exynos_bo *dst,
266                                 enum e_g2d_buf_type type)
267 {
268         struct g2d_context *ctx;
269         struct g2d_image src_img, dst_img;
270         unsigned int count;
271         unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
272         unsigned long userptr, size;
273         int ret;
274
275         ctx = g2d_init(dev->fd);
276         if (!ctx)
277                 return -EFAULT;
278
279         memset(&src_img, 0, sizeof(struct g2d_image));
280         memset(&dst_img, 0, sizeof(struct g2d_image));
281         dst_img.bo[0] = dst->handle;
282
283         src_x = 0;
284         src_y = 0;
285         dst_x = 0;
286         dst_y = 0;
287         img_w = screen_width;
288         img_h = screen_height;
289
290         switch (type) {
291         case G2D_IMGBUF_GEM:
292                 src_img.bo[0] = src->handle;
293                 break;
294         case G2D_IMGBUF_USERPTR:
295                 size = img_w * img_h * 4;
296
297                 userptr = (unsigned long)malloc(size);
298                 if (!userptr) {
299                         fprintf(stderr, "failed to allocate userptr.\n");
300                         return -EFAULT;
301                 }
302
303                 src_img.user_ptr[0].userptr = userptr;
304                 src_img.user_ptr[0].size = size;
305                 break;
306         default:
307                 type = G2D_IMGBUF_GEM;
308                 break;
309         }
310
311         printf("copy test with %s.\n",
312                         type == G2D_IMGBUF_GEM ? "gem" : "userptr");
313
314         src_img.width = img_w;
315         src_img.height = img_h;
316         src_img.stride = src_img.width * 4;
317         src_img.buf_type = type;
318         src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
319         src_img.color = 0xffff0000;
320         ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
321         if (ret < 0)
322                 goto err_free_userptr;
323
324         dst_img.width = img_w;
325         dst_img.height = img_h;
326         dst_img.stride = dst_img.width * 4;
327         dst_img.buf_type = G2D_IMGBUF_GEM;
328         dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
329
330         ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
331                         img_w - 4, img_h - 4);
332         if (ret < 0)
333                 goto err_free_userptr;
334
335         g2d_exec(ctx);
336
337 err_free_userptr:
338         if (type == G2D_IMGBUF_USERPTR)
339                 if (userptr)
340                         free((void *)userptr);
341
342         g2d_fini(ctx);
343
344         return ret;
345 }
346
347 static int g2d_copy_with_scale_test(struct exynos_device *dev,
348                                         struct exynos_bo *src,
349                                         struct exynos_bo *dst,
350                                         enum e_g2d_buf_type type)
351 {
352         struct g2d_context *ctx;
353         struct g2d_image src_img, dst_img;
354         unsigned int count;
355         unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
356         unsigned long userptr, size;
357         int ret;
358
359         ctx = g2d_init(dev->fd);
360         if (!ctx)
361                 return -EFAULT;
362
363         memset(&src_img, 0, sizeof(struct g2d_image));
364         memset(&dst_img, 0, sizeof(struct g2d_image));
365         dst_img.bo[0] = dst->handle;
366
367         src_x = 0;
368         src_y = 0;
369         dst_x = 0;
370         dst_y = 0;
371         img_w = screen_width;
372         img_h = screen_height;
373
374         switch (type) {
375         case G2D_IMGBUF_GEM:
376                 src_img.bo[0] = src->handle;
377                 break;
378         case G2D_IMGBUF_USERPTR:
379                 size = img_w * img_h * 4;
380
381                 userptr = (unsigned long)malloc(size);
382                 if (!userptr) {
383                         fprintf(stderr, "failed to allocate userptr.\n");
384                         return -EFAULT;
385                 }
386
387                 src_img.user_ptr[0].userptr = userptr;
388                 src_img.user_ptr[0].size = size;
389                 break;
390         default:
391                 type = G2D_IMGBUF_GEM;
392                 break;
393         }
394
395         printf("copy and scale test with %s.\n",
396                         type == G2D_IMGBUF_GEM ? "gem" : "userptr");
397
398         src_img.width = img_w;
399         src_img.height = img_h;
400         src_img.stride = src_img.width * 4;
401         src_img.buf_type = type;
402         src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
403         src_img.color = 0xffffffff;
404         ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w ,  img_h);
405         if (ret < 0)
406                 goto err_free_userptr;
407
408         src_img.color = 0xff00ff00;
409         ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100);
410         if (ret < 0)
411                 goto err_free_userptr;
412
413         dst_img.width = img_w;
414         dst_img.height = img_h;
415         dst_img.buf_type = G2D_IMGBUF_GEM;
416         dst_img.stride = dst_img.width * 4;
417         dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
418
419         ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100,
420                                         100, 100, 200, 200, 0);
421         if (ret < 0)
422                 goto err_free_userptr;
423
424         g2d_exec(ctx);
425
426 err_free_userptr:
427         if (type == G2D_IMGBUF_USERPTR)
428                 if (userptr)
429                         free((void *)userptr);
430
431         g2d_fini(ctx);
432
433         return 0;
434 }
435
436 static int g2d_blend_test(struct exynos_device *dev,
437                                         struct exynos_bo *src,
438                                         struct exynos_bo *dst,
439                                         enum e_g2d_buf_type type)
440 {
441         struct g2d_context *ctx;
442         struct g2d_image src_img, dst_img;
443         unsigned int count;
444         unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
445         unsigned long userptr, size;
446         int ret;
447
448         ctx = g2d_init(dev->fd);
449         if (!ctx)
450                 return -EFAULT;
451
452         memset(&src_img, 0, sizeof(struct g2d_image));
453         memset(&dst_img, 0, sizeof(struct g2d_image));
454         dst_img.bo[0] = dst->handle;
455
456         src_x = 0;
457         src_y = 0;
458         dst_x = 0;
459         dst_y = 0;
460         img_w = screen_width;
461         img_h = screen_height;
462
463         switch (type) {
464         case G2D_IMGBUF_GEM:
465                 src_img.bo[0] = src->handle;
466                 break;
467         case G2D_IMGBUF_USERPTR:
468                 size = img_w * img_h * 4;
469
470                 userptr = (unsigned long)malloc(size);
471                 if (!userptr) {
472                         fprintf(stderr, "failed to allocate userptr.\n");
473                         return -EFAULT;
474                 }
475
476                 src_img.user_ptr[0].userptr = userptr;
477                 src_img.user_ptr[0].size = size;
478                 break;
479         default:
480                 type = G2D_IMGBUF_GEM;
481                 break;
482         }
483
484         printf("blend 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.select_mode = G2D_SELECT_MODE_NORMAL;
492         src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
493         src_img.color = 0xffffffff;
494         ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
495         if (ret < 0)
496                 goto err_free_userptr;
497
498         src_img.color = 0x770000ff;
499         ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200);
500         if (ret < 0)
501                 goto err_free_userptr;
502
503         dst_img.width = img_w;
504         dst_img.height = img_h;
505         dst_img.stride = dst_img.width * 4;
506         dst_img.buf_type = G2D_IMGBUF_GEM;
507         dst_img.select_mode = G2D_SELECT_MODE_NORMAL;
508         dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
509         dst_img.color = 0xffffffff;
510         ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h);
511         if (ret < 0)
512                 goto err_free_userptr;
513
514         dst_img.color = 0x77ff0000;
515         ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200);
516         if (ret < 0)
517                 goto err_free_userptr;
518
519         ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200,
520                         G2D_OP_OVER);
521         if (ret < 0)
522                 goto err_free_userptr;
523
524         g2d_exec(ctx);
525
526 err_free_userptr:
527         if (type == G2D_IMGBUF_USERPTR)
528                 if (userptr)
529                         free((void *)userptr);
530
531         g2d_fini(ctx);
532
533         return 0;
534 }
535
536 static struct fimg2d_test_case test_case = {
537         .solid_fill = &g2d_solid_fill_test,
538         .copy = &g2d_copy_test,
539         .copy_with_scale = &g2d_copy_with_scale_test,
540         .blend = &g2d_blend_test,
541 };
542
543 static void usage(char *name)
544 {
545         fprintf(stderr, "usage: %s [-s]\n", name);
546         fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n");
547         exit(0);
548 }
549
550 extern char *optarg;
551 static const char optstr[] = "s:";
552
553 int main(int argc, char **argv)
554 {
555         struct exynos_device *dev;
556         struct exynos_bo *bo, *src;
557         struct connector con;
558         char *modeset = NULL;
559         unsigned int fb_id;
560         uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
561         drmModeRes *resources;
562         int ret, fd, c;
563
564         memset(&con, 0, sizeof(struct connector));
565
566         if (argc != 3) {
567                 usage(argv[0]);
568                 return -EINVAL;
569         }
570
571         while ((c = getopt(argc, argv, optstr)) != -1) {
572                 switch (c) {
573                 case 's':
574                         modeset = strdup(optarg);
575                         con.crtc = -1;
576                         if (sscanf(optarg, "%d:0x%64s",
577                                                 &con.id,
578                                                 con.mode_str) != 2 &&
579                                         sscanf(optarg, "%d@%d:%64s",
580                                                 &con.id,
581                                                 &con.crtc,
582                                                 con.mode_str) != 3)
583                                 usage(argv[0]);
584                         break;
585                 default:
586                         usage(argv[0]);
587                         return -EINVAL;
588                 }
589         }
590
591         fd = drmOpen(DRM_MODULE_NAME, NULL);
592         if (fd < 0) {
593                 fprintf(stderr, "failed to open.\n");
594                 return fd;
595         }
596
597         dev = exynos_device_create(fd);
598         if (!dev) {
599                 drmClose(dev->fd);
600                 return -EFAULT;
601         }
602
603         resources = drmModeGetResources(dev->fd);
604         if (!resources) {
605                 fprintf(stderr, "drmModeGetResources failed: %s\n",
606                                 strerror(errno));
607                 ret = -EFAULT;
608                 goto err_drm_close;
609         }
610
611         connector_find_mode(dev->fd, &con, resources);
612         drmModeFreeResources(resources);
613
614         screen_width = con.mode->hdisplay;
615         screen_height = con.mode->vdisplay;
616
617         printf("screen width  = %d, screen height = %d\n", screen_width,
618                         screen_height);
619
620         bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
621         if (!bo) {
622                 ret = -EFAULT;
623                 goto err_drm_close;
624         }
625
626         handles[0] = bo->handle;
627         pitches[0] = screen_width * 4;
628         offsets[0] = 0;
629
630         ret = drmModeAddFB2(dev->fd, screen_width, screen_height,
631                                 DRM_FORMAT_RGBA8888, handles,
632                                 pitches, offsets, &fb_id, 0);
633         if (ret < 0)
634                 goto err_destroy_buffer;
635
636         con.plane_zpos = -1;
637
638         memset(bo->vaddr, 0xff, screen_width * screen_height * 4);
639
640         ret = drm_set_crtc(dev, &con, fb_id);
641         if (ret < 0)
642                 goto err_rm_fb;
643
644         ret = test_case.solid_fill(dev, bo);
645         if (ret < 0) {
646                 fprintf(stderr, "failed to solid fill operation.\n");
647                 goto err_rm_fb;
648         }
649
650         getchar();
651
652         src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
653         if (!src) {
654                 ret = -EFAULT;
655                 goto err_rm_fb;
656         }
657
658         ret = test_case.copy(dev, src, bo, G2D_IMGBUF_GEM);
659         if (ret < 0) {
660                 fprintf(stderr, "failed to test copy operation.\n");
661                 goto err_free_src;
662         }
663
664         getchar();
665
666         ret = test_case.copy_with_scale(dev, src, bo, G2D_IMGBUF_GEM);
667         if (ret < 0) {
668                 fprintf(stderr, "failed to test copy and scale operation.\n");
669                 goto err_free_src;
670         }
671
672         getchar();
673
674         ret  = test_case.blend(dev, src, bo, G2D_IMGBUF_USERPTR);
675         if (ret < 0)
676                 fprintf(stderr, "failed to test blend operation.\n");
677
678         getchar();
679
680 err_free_src:
681         if (src)
682                 exynos_destroy_buffer(src);
683
684 err_rm_fb:
685         drmModeRmFB(fb_id, bo->handle);
686
687 err_destroy_buffer:
688         exynos_destroy_buffer(bo);
689
690 err_drm_close:
691         drmClose(dev->fd);
692         exynos_device_destroy(dev);
693
694         return 0;
695 }