2 * Copyright (C) 2013 Samsung Electronics Co.Ltd
4 * Inki Dae <inki.dae@samsung.com>
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.
25 #include <linux/stddef.h>
28 #include <xf86drmMode.h>
30 #include <drm_fourcc.h>
32 #include "exynos_drm.h"
33 #include "exynos_drmif.h"
34 #include "exynos_fimg2d.h"
36 #define DRM_MODULE_NAME "exynos"
38 static unsigned int screen_width, screen_height;
43 drmModeModeInfo *mode;
44 drmModeEncoder *encoder;
48 static void connector_find_mode(int fd, struct connector *c,
49 drmModeRes *resources)
51 drmModeConnector *connector;
54 /* First, find the connector & mode */
56 for (i = 0; i < resources->count_connectors; i++) {
57 connector = drmModeGetConnector(fd, resources->connectors[i]);
60 fprintf(stderr, "could not get connector %i: %s\n",
61 resources->connectors[i], strerror(errno));
62 drmModeFreeConnector(connector);
66 if (!connector->count_modes) {
67 drmModeFreeConnector(connector);
71 if (connector->connector_id != c->id) {
72 drmModeFreeConnector(connector);
76 for (j = 0; j < connector->count_modes; j++) {
77 c->mode = &connector->modes[j];
78 if (!strcmp(c->mode->name, c->mode_str))
82 /* Found it, break out */
86 drmModeFreeConnector(connector);
90 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
94 /* Now get the encoder */
95 for (i = 0; i < resources->count_encoders; i++) {
96 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
99 fprintf(stderr, "could not get encoder %i: %s\n",
100 resources->encoders[i], strerror(errno));
101 drmModeFreeEncoder(c->encoder);
105 if (c->encoder->encoder_id == connector->encoder_id)
108 drmModeFreeEncoder(c->encoder);
112 c->crtc = c->encoder->crtc_id;
115 static int drm_set_crtc(struct exynos_device *dev, struct connector *c,
120 ret = drmModeSetCrtc(dev->fd, c->crtc,
121 fb_id, 0, 0, &c->id, 1, c->mode);
123 drmMsg("failed to set mode: %s\n", strerror(errno));
128 static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev,
132 struct exynos_bo *bo;
134 bo = exynos_bo_create(dev, size, flags);
138 if (!exynos_bo_map(bo)) {
139 exynos_bo_destroy(bo);
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)
152 unsigned int x, y, i, j;
153 const unsigned int stride = num_tiles_x * tile_size;
155 if (posix_memalign((void*)&buf, 64, num_tiles_y * tile_size * stride * 4) != 0)
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);
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;
173 static void exynos_destroy_buffer(struct exynos_bo *bo)
175 exynos_bo_destroy(bo);
178 static void wait_for_user_input(int last)
180 printf("press <ENTER> to %s\n", last ? "exit test application" :
181 "skip to next test");
186 static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst)
188 struct g2d_context *ctx;
189 struct g2d_image img = {0};
190 unsigned int count, img_w, img_h;
193 ctx = g2d_init(dev->fd);
197 img.bo[0] = dst->handle;
199 printf("solid fill test.\n");
202 img_w = screen_width;
203 img_h = screen_height;
205 for (count = 0; count < 2; count++) {
206 unsigned int x, y, w, h;
208 x = rand() % (img_w / 2);
209 y = rand() % (img_h / 2);
210 w = rand() % (img_w - x);
211 h = rand() % (img_h - y);
215 img.stride = img.width * 4;
216 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
217 img.color = 0xff000000 + (random() & 0xffffff);
219 ret = g2d_solid_fill(ctx, &img, x, y, w, h);
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)
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;
244 ctx = g2d_init(dev->fd);
248 dst_img.bo[0] = dst->handle;
254 img_w = screen_width;
255 img_h = screen_height;
259 src_img.bo[0] = src->handle;
261 case G2D_IMGBUF_USERPTR:
262 size = img_w * img_h * 4;
264 userptr = (unsigned long)malloc(size);
266 fprintf(stderr, "failed to allocate userptr.\n");
270 src_img.user_ptr[0].userptr = userptr;
271 src_img.user_ptr[0].size = size;
273 case G2D_IMGBUF_COLOR:
279 printf("copy test with %s.\n",
280 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
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);
290 goto err_free_userptr;
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;
298 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
299 img_w - 4, img_h - 4);
301 goto err_free_userptr;
306 if (type == G2D_IMGBUF_USERPTR)
308 free((void *)userptr);
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)
321 struct g2d_context *ctx;
322 struct g2d_image img = {0}, tmp_img = {0};
323 unsigned int img_w, img_h, count;
328 static const struct g2d_step {
340 static const unsigned int num_steps =
341 sizeof(steps) / sizeof(struct g2d_step);
343 ctx = g2d_init(dev->fd);
347 img.bo[0] = buf->handle;
349 /* create pattern of half the screen size */
350 checkerboard = create_checkerboard_pattern(screen_width / 64, screen_height / 64, 32);
356 img_w = (screen_width / 64) * 32;
357 img_h = (screen_height / 64) * 32;
361 memcpy(tmp->vaddr, checkerboard, img_w * img_h * 4);
362 tmp_img.bo[0] = tmp->handle;
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;
368 case G2D_IMGBUF_COLOR:
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;
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;
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);
399 printf("move test with %s.\n",
400 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
403 for (count = 0; count < 256; ++count) {
404 const struct g2d_step *s;
406 /* select step and validate it */
408 s = &steps[random() % num_steps];
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)
418 ret = g2d_move(ctx, &img, cur_x, cur_y, cur_x + s->x, cur_y + s->y,
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)
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;
451 ctx = g2d_init(dev->fd);
455 dst_img.bo[0] = dst->handle;
459 img_w = screen_width;
460 img_h = screen_height;
464 src_img.bo[0] = src->handle;
466 case G2D_IMGBUF_USERPTR:
467 size = img_w * img_h * 4;
469 userptr = (unsigned long)malloc(size);
471 fprintf(stderr, "failed to allocate userptr.\n");
475 src_img.user_ptr[0].userptr = userptr;
476 src_img.user_ptr[0].size = size;
478 case G2D_IMGBUF_COLOR:
484 printf("copy and scale test with %s.\n",
485 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
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);
495 goto err_free_userptr;
497 src_img.color = 0xff00ff00;
498 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100);
500 goto err_free_userptr;
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;
508 ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100,
509 100, 100, 200, 200, 0);
511 goto err_free_userptr;
516 if (type == G2D_IMGBUF_USERPTR)
518 free((void *)userptr);
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)
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;
537 ctx = g2d_init(dev->fd);
541 dst_img.bo[0] = dst->handle;
547 img_w = screen_width;
548 img_h = screen_height;
552 src_img.bo[0] = src->handle;
554 case G2D_IMGBUF_USERPTR:
555 size = img_w * img_h * 4;
557 userptr = (unsigned long)malloc(size);
559 fprintf(stderr, "failed to allocate userptr.\n");
563 src_img.user_ptr[0].userptr = userptr;
564 src_img.user_ptr[0].size = size;
566 case G2D_IMGBUF_COLOR:
572 printf("blend test with %s.\n",
573 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
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);
584 goto err_free_userptr;
586 src_img.color = 0x770000ff;
587 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200);
589 goto err_free_userptr;
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);
600 goto err_free_userptr;
602 dst_img.color = 0x77ff0000;
603 ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200);
605 goto err_free_userptr;
607 ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200,
610 goto err_free_userptr;
615 if (type == G2D_IMGBUF_USERPTR)
617 free((void *)userptr);
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)
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;
636 ctx = g2d_init(dev->fd);
640 dst_img.bo[0] = dst->handle;
647 checkerboard = create_checkerboard_pattern(screen_width / 32, screen_height / 32, 32);
648 if (checkerboard == NULL) {
653 img_w = screen_width - (screen_width % 32);
654 img_h = screen_height - (screen_height % 32);
658 memcpy(src->vaddr, checkerboard, img_w * img_h * 4);
659 src_img.bo[0] = src->handle;
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;
665 case G2D_IMGBUF_COLOR:
671 printf("checkerboard test with %s.\n",
672 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
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;
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);
690 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
704 static void usage(char *name)
706 fprintf(stderr, "usage: %s [-s]\n", name);
707 fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n");
712 static const char optstr[] = "s:";
714 int main(int argc, char **argv)
716 struct exynos_device *dev;
717 struct exynos_bo *bo, *src;
718 struct connector con;
720 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
721 drmModeRes *resources;
724 memset(&con, 0, sizeof(struct connector));
731 while ((c = getopt(argc, argv, optstr)) != -1) {
735 if (sscanf(optarg, "%d:0x%64s",
737 con.mode_str) != 2 &&
738 sscanf(optarg, "%d@%d:%64s",
750 fd = drmOpen(DRM_MODULE_NAME, NULL);
752 fprintf(stderr, "failed to open.\n");
756 dev = exynos_device_create(fd);
762 resources = drmModeGetResources(dev->fd);
764 fprintf(stderr, "drmModeGetResources failed: %s\n",
770 connector_find_mode(dev->fd, &con, resources);
771 drmModeFreeResources(resources);
774 fprintf(stderr, "failed to find usable connector\n");
779 screen_width = con.mode->hdisplay;
780 screen_height = con.mode->vdisplay;
782 if (screen_width == 0 || screen_height == 0) {
783 fprintf(stderr, "failed to find sane resolution on connector\n");
788 printf("screen width = %d, screen height = %d\n", screen_width,
791 bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
797 handles[0] = bo->handle;
798 pitches[0] = screen_width * 4;
801 ret = drmModeAddFB2(dev->fd, screen_width, screen_height,
802 DRM_FORMAT_XRGB8888, handles,
803 pitches, offsets, &fb_id, 0);
805 goto err_destroy_buffer;
807 memset(bo->vaddr, 0xff, screen_width * screen_height * 4);
809 ret = drm_set_crtc(dev, &con, fb_id);
813 ret = g2d_solid_fill_test(dev, bo);
815 fprintf(stderr, "failed to solid fill operation.\n");
819 wait_for_user_input(0);
821 src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
827 ret = g2d_copy_test(dev, src, bo, G2D_IMGBUF_GEM);
829 fprintf(stderr, "failed to test copy operation.\n");
833 wait_for_user_input(0);
835 ret = g2d_move_test(dev, src, bo, G2D_IMGBUF_GEM);
837 fprintf(stderr, "failed to test move operation.\n");
841 wait_for_user_input(0);
843 ret = g2d_copy_with_scale_test(dev, src, bo, G2D_IMGBUF_GEM);
845 fprintf(stderr, "failed to test copy and scale operation.\n");
849 wait_for_user_input(0);
851 ret = g2d_checkerboard_test(dev, src, bo, G2D_IMGBUF_GEM);
853 fprintf(stderr, "failed to issue checkerboard test.\n");
857 wait_for_user_input(1);
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.
865 * Disable the test for now, until the kernel code has been sanitized.
868 ret = g2d_blend_test(dev, src, bo, G2D_IMGBUF_USERPTR);
870 fprintf(stderr, "failed to test blend operation.\n");
877 exynos_destroy_buffer(src);
880 drmModeRmFB(dev->fd, fb_id);
883 exynos_destroy_buffer(bo);
887 exynos_device_destroy(dev);