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
connector_find_mode(int fd,struct connector * c,drmModeRes * resources)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
connector_find_plane(int fd,unsigned int * plane_id)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
drm_set_crtc(struct exynos_device * dev,struct connector * c,unsigned int fb_id)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
exynos_create_buffer(struct exynos_device * dev,unsigned long size,unsigned int flags)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
exynos_destroy_buffer(struct exynos_bo * bo)210 static void exynos_destroy_buffer(struct exynos_bo *bo)
211 {
212 exynos_bo_destroy(bo);
213 }
214
g2d_solid_fill_test(struct exynos_device * dev,struct exynos_bo * dst)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
g2d_copy_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)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
g2d_copy_with_scale_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)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
g2d_blend_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)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
usage(char * name)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
main(int argc,char ** argv)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(dev->fd, fb_id);
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 }
696