2 * Copyright (C) 2013 Samsung Electronics Co.Ltd
4 * Inki Dae <inki.dae@samsung.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
34 #include <linux/stddef.h>
37 #include <xf86drmMode.h>
38 #include <drm_fourcc.h>
40 #include "exynos_drm.h"
41 #include "exynos_drmif.h"
42 #include "exynos_fimg2d.h"
44 #define DRM_MODULE_NAME "exynos"
46 static unsigned int screen_width
, screen_height
;
51 drmModeModeInfo
*mode
;
52 drmModeEncoder
*encoder
;
56 static void connector_find_mode(int fd
, struct connector
*c
,
57 drmModeRes
*resources
)
59 drmModeConnector
*connector
;
62 /* First, find the connector & mode */
64 for (i
= 0; i
< resources
->count_connectors
; i
++) {
65 connector
= drmModeGetConnector(fd
, resources
->connectors
[i
]);
68 fprintf(stderr
, "could not get connector %i: %s\n",
69 resources
->connectors
[i
], strerror(errno
));
73 if (!connector
->count_modes
) {
74 drmModeFreeConnector(connector
);
78 if (connector
->connector_id
!= c
->id
) {
79 drmModeFreeConnector(connector
);
83 for (j
= 0; j
< connector
->count_modes
; j
++) {
84 c
->mode
= &connector
->modes
[j
];
85 if (!strcmp(c
->mode
->name
, c
->mode_str
))
89 /* Found it, break out */
93 drmModeFreeConnector(connector
);
97 fprintf(stderr
, "failed to find mode \"%s\"\n", c
->mode_str
);
101 /* Now get the encoder */
102 for (i
= 0; i
< resources
->count_encoders
; i
++) {
103 c
->encoder
= drmModeGetEncoder(fd
, resources
->encoders
[i
]);
106 fprintf(stderr
, "could not get encoder %i: %s\n",
107 resources
->encoders
[i
], strerror(errno
));
111 if (c
->encoder
->encoder_id
== connector
->encoder_id
)
114 drmModeFreeEncoder(c
->encoder
);
118 c
->crtc
= c
->encoder
->crtc_id
;
121 static int drm_set_crtc(struct exynos_device
*dev
, struct connector
*c
,
126 ret
= drmModeSetCrtc(dev
->fd
, c
->crtc
,
127 fb_id
, 0, 0, &c
->id
, 1, c
->mode
);
129 drmMsg("failed to set mode: %s\n", strerror(errno
));
134 static struct exynos_bo
*exynos_create_buffer(struct exynos_device
*dev
,
138 struct exynos_bo
*bo
;
140 bo
= exynos_bo_create(dev
, size
, flags
);
144 if (!exynos_bo_map(bo
)) {
145 exynos_bo_destroy(bo
);
152 /* Allocate buffer and fill it with checkerboard pattern, where the tiles *
153 * have a random color. The caller has to free the buffer. */
154 static void *create_checkerboard_pattern(unsigned int num_tiles_x
,
155 unsigned int num_tiles_y
, unsigned int tile_size
)
158 unsigned int x
, y
, i
, j
;
159 const unsigned int stride
= num_tiles_x
* tile_size
;
161 if (posix_memalign((void*)&buf
, 64, num_tiles_y
* tile_size
* stride
* 4) != 0)
164 for (x
= 0; x
< num_tiles_x
; ++x
) {
165 for (y
= 0; y
< num_tiles_y
; ++y
) {
166 const unsigned int color
= 0xff000000 + (random() & 0xffffff);
168 for (i
= 0; i
< tile_size
; ++i
) {
169 for (j
= 0; j
< tile_size
; ++j
) {
170 buf
[x
* tile_size
+ y
* stride
* tile_size
+ i
+ j
* stride
] = color
;
179 static void exynos_destroy_buffer(struct exynos_bo
*bo
)
181 exynos_bo_destroy(bo
);
184 static void wait_for_user_input(int last
)
186 printf("press <ENTER> to %s\n", last
? "exit test application" :
187 "skip to next test");
192 static int g2d_solid_fill_test(struct exynos_device
*dev
, struct exynos_bo
*dst
)
194 struct g2d_context
*ctx
;
195 struct g2d_image img
= {0};
196 unsigned int count
, img_w
, img_h
;
199 ctx
= g2d_init(dev
->fd
);
203 img
.bo
[0] = dst
->handle
;
205 printf("solid fill test.\n");
208 img_w
= screen_width
;
209 img_h
= screen_height
;
211 for (count
= 0; count
< 2; count
++) {
212 unsigned int x
, y
, w
, h
;
214 x
= rand() % (img_w
/ 2);
215 y
= rand() % (img_h
/ 2);
216 w
= rand() % (img_w
- x
);
217 h
= rand() % (img_h
- y
);
221 img
.stride
= img
.width
* 4;
222 img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
223 img
.color
= 0xff000000 + (random() & 0xffffff);
225 ret
= g2d_solid_fill(ctx
, &img
, x
, y
, w
, h
);
240 static int g2d_copy_test(struct exynos_device
*dev
, struct exynos_bo
*src
,
241 struct exynos_bo
*dst
,
242 enum e_g2d_buf_type type
)
244 struct g2d_context
*ctx
;
245 struct g2d_image src_img
= {0}, dst_img
= {0};
246 unsigned int src_x
, src_y
, dst_x
, dst_y
, img_w
, img_h
;
247 unsigned long userptr
, size
;
250 ctx
= g2d_init(dev
->fd
);
254 dst_img
.bo
[0] = dst
->handle
;
260 img_w
= screen_width
;
261 img_h
= screen_height
;
265 src_img
.bo
[0] = src
->handle
;
267 case G2D_IMGBUF_USERPTR
:
268 size
= img_w
* img_h
* 4;
270 userptr
= (unsigned long)malloc(size
);
272 fprintf(stderr
, "failed to allocate userptr.\n");
277 src_img
.user_ptr
[0].userptr
= userptr
;
278 src_img
.user_ptr
[0].size
= size
;
280 case G2D_IMGBUF_COLOR
:
286 printf("copy test with %s.\n",
287 type
== G2D_IMGBUF_GEM
? "gem" : "userptr");
289 src_img
.width
= img_w
;
290 src_img
.height
= img_h
;
291 src_img
.stride
= src_img
.width
* 4;
292 src_img
.buf_type
= type
;
293 src_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
294 src_img
.color
= 0xffff0000;
295 ret
= g2d_solid_fill(ctx
, &src_img
, src_x
, src_y
, img_w
, img_h
);
297 goto err_free_userptr
;
299 dst_img
.width
= img_w
;
300 dst_img
.height
= img_h
;
301 dst_img
.stride
= dst_img
.width
* 4;
302 dst_img
.buf_type
= G2D_IMGBUF_GEM
;
303 dst_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
305 ret
= g2d_copy(ctx
, &src_img
, &dst_img
, src_x
, src_y
, dst_x
, dst_y
,
306 img_w
- 4, img_h
- 4);
308 goto err_free_userptr
;
313 if (type
== G2D_IMGBUF_USERPTR
)
315 free((void *)userptr
);
323 static int g2d_move_test(struct exynos_device
*dev
,
324 struct exynos_bo
*tmp
,
325 struct exynos_bo
*buf
,
326 enum e_g2d_buf_type type
)
328 struct g2d_context
*ctx
;
329 struct g2d_image img
= {0}, tmp_img
= {0};
330 unsigned int img_w
, img_h
, count
;
335 static const struct g2d_step
{
347 static const unsigned int num_steps
=
348 sizeof(steps
) / sizeof(struct g2d_step
);
350 ctx
= g2d_init(dev
->fd
);
354 img
.bo
[0] = buf
->handle
;
356 /* create pattern of half the screen size */
357 checkerboard
= create_checkerboard_pattern(screen_width
/ 64, screen_height
/ 64, 32);
363 img_w
= (screen_width
/ 64) * 32;
364 img_h
= (screen_height
/ 64) * 32;
368 memcpy(tmp
->vaddr
, checkerboard
, img_w
* img_h
* 4);
369 tmp_img
.bo
[0] = tmp
->handle
;
371 case G2D_IMGBUF_USERPTR
:
372 tmp_img
.user_ptr
[0].userptr
= (unsigned long)checkerboard
;
373 tmp_img
.user_ptr
[0].size
= img_w
* img_h
* 4;
375 case G2D_IMGBUF_COLOR
:
381 /* solid fill framebuffer with white color */
382 img
.width
= screen_width
;
383 img
.height
= screen_height
;
384 img
.stride
= screen_width
* 4;
385 img
.buf_type
= G2D_IMGBUF_GEM
;
386 img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
387 img
.color
= 0xffffffff;
389 /* put checkerboard pattern in the center of the framebuffer */
390 cur_x
= (screen_width
- img_w
) / 2;
391 cur_y
= (screen_height
- img_h
) / 2;
392 tmp_img
.width
= img_w
;
393 tmp_img
.height
= img_h
;
394 tmp_img
.stride
= img_w
* 4;
395 tmp_img
.buf_type
= type
;
396 tmp_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
398 ret
= g2d_solid_fill(ctx
, &img
, 0, 0, screen_width
, screen_height
) ||
399 g2d_copy(ctx
, &tmp_img
, &img
, 0, 0, cur_x
, cur_y
, img_w
, img_h
);
406 printf("move test with %s.\n",
407 type
== G2D_IMGBUF_GEM
? "gem" : "userptr");
410 for (count
= 0; count
< 256; ++count
) {
411 const struct g2d_step
*s
;
413 /* select step and validate it */
415 s
= &steps
[random() % num_steps
];
417 if (cur_x
+ s
->x
< 0 || cur_y
+ s
->y
< 0 ||
418 cur_x
+ img_w
+ s
->x
>= screen_width
||
419 cur_y
+ img_h
+ s
->y
>= screen_height
)
425 ret
= g2d_move(ctx
, &img
, cur_x
, cur_y
, cur_x
+ s
->x
, cur_y
+ s
->y
,
447 static int g2d_copy_with_scale_test(struct exynos_device
*dev
,
448 struct exynos_bo
*src
,
449 struct exynos_bo
*dst
,
450 enum e_g2d_buf_type type
)
452 struct g2d_context
*ctx
;
453 struct g2d_image src_img
= {0}, dst_img
= {0};
454 unsigned int src_x
, src_y
, img_w
, img_h
;
455 unsigned long userptr
, size
;
458 ctx
= g2d_init(dev
->fd
);
462 dst_img
.bo
[0] = dst
->handle
;
466 img_w
= screen_width
;
467 img_h
= screen_height
;
471 src_img
.bo
[0] = src
->handle
;
473 case G2D_IMGBUF_USERPTR
:
474 size
= img_w
* img_h
* 4;
476 userptr
= (unsigned long)malloc(size
);
478 fprintf(stderr
, "failed to allocate userptr.\n");
483 src_img
.user_ptr
[0].userptr
= userptr
;
484 src_img
.user_ptr
[0].size
= size
;
486 case G2D_IMGBUF_COLOR
:
492 printf("copy and scale test with %s.\n",
493 type
== G2D_IMGBUF_GEM
? "gem" : "userptr");
495 src_img
.width
= img_w
;
496 src_img
.height
= img_h
;
497 src_img
.stride
= src_img
.width
* 4;
498 src_img
.buf_type
= type
;
499 src_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
500 src_img
.color
= 0xffffffff;
501 ret
= g2d_solid_fill(ctx
, &src_img
, src_x
, src_y
, img_w
, img_h
);
503 goto err_free_userptr
;
505 src_img
.color
= 0xff00ff00;
506 ret
= g2d_solid_fill(ctx
, &src_img
, 5, 5, 100, 100);
508 goto err_free_userptr
;
510 dst_img
.width
= img_w
;
511 dst_img
.height
= img_h
;
512 dst_img
.buf_type
= G2D_IMGBUF_GEM
;
513 dst_img
.stride
= dst_img
.width
* 4;
514 dst_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
516 ret
= g2d_copy_with_scale(ctx
, &src_img
, &dst_img
, 5, 5, 100, 100,
517 100, 100, 200, 200, 0);
519 goto err_free_userptr
;
524 if (type
== G2D_IMGBUF_USERPTR
)
526 free((void *)userptr
);
534 #ifdef EXYNOS_G2D_USERPTR_TEST
535 static int g2d_blend_test(struct exynos_device
*dev
,
536 struct exynos_bo
*src
,
537 struct exynos_bo
*dst
,
538 enum e_g2d_buf_type type
)
540 struct g2d_context
*ctx
;
541 struct g2d_image src_img
= {0}, dst_img
= {0};
542 unsigned int src_x
, src_y
, dst_x
, dst_y
, img_w
, img_h
;
543 unsigned long userptr
, size
;
546 ctx
= g2d_init(dev
->fd
);
550 dst_img
.bo
[0] = dst
->handle
;
556 img_w
= screen_width
;
557 img_h
= screen_height
;
561 src_img
.bo
[0] = src
->handle
;
563 case G2D_IMGBUF_USERPTR
:
564 size
= img_w
* img_h
* 4;
566 userptr
= (unsigned long)malloc(size
);
568 fprintf(stderr
, "failed to allocate userptr.\n");
573 src_img
.user_ptr
[0].userptr
= userptr
;
574 src_img
.user_ptr
[0].size
= size
;
576 case G2D_IMGBUF_COLOR
:
582 printf("blend test with %s.\n",
583 type
== G2D_IMGBUF_GEM
? "gem" : "userptr");
585 src_img
.width
= img_w
;
586 src_img
.height
= img_h
;
587 src_img
.stride
= src_img
.width
* 4;
588 src_img
.buf_type
= type
;
589 src_img
.select_mode
= G2D_SELECT_MODE_NORMAL
;
590 src_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
591 src_img
.color
= 0xffffffff;
592 ret
= g2d_solid_fill(ctx
, &src_img
, src_x
, src_y
, img_w
, img_h
);
594 goto err_free_userptr
;
596 src_img
.color
= 0x770000ff;
597 ret
= g2d_solid_fill(ctx
, &src_img
, 5, 5, 200, 200);
599 goto err_free_userptr
;
601 dst_img
.width
= img_w
;
602 dst_img
.height
= img_h
;
603 dst_img
.stride
= dst_img
.width
* 4;
604 dst_img
.buf_type
= G2D_IMGBUF_GEM
;
605 dst_img
.select_mode
= G2D_SELECT_MODE_NORMAL
;
606 dst_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
607 dst_img
.color
= 0xffffffff;
608 ret
= g2d_solid_fill(ctx
, &dst_img
, dst_x
, dst_y
, img_w
, img_h
);
610 goto err_free_userptr
;
612 dst_img
.color
= 0x77ff0000;
613 ret
= g2d_solid_fill(ctx
, &dst_img
, 105, 105, 200, 200);
615 goto err_free_userptr
;
617 ret
= g2d_blend(ctx
, &src_img
, &dst_img
, 5, 5, 105, 105, 200, 200,
620 goto err_free_userptr
;
625 if (type
== G2D_IMGBUF_USERPTR
)
627 free((void *)userptr
);
636 static int g2d_checkerboard_test(struct exynos_device
*dev
,
637 struct exynos_bo
*src
,
638 struct exynos_bo
*dst
,
639 enum e_g2d_buf_type type
)
641 struct g2d_context
*ctx
;
642 struct g2d_image src_img
= {0}, dst_img
= {0};
643 unsigned int src_x
, src_y
, dst_x
, dst_y
, img_w
, img_h
;
644 void *checkerboard
= NULL
;
647 ctx
= g2d_init(dev
->fd
);
651 dst_img
.bo
[0] = dst
->handle
;
658 checkerboard
= create_checkerboard_pattern(screen_width
/ 32, screen_height
/ 32, 32);
664 img_w
= screen_width
- (screen_width
% 32);
665 img_h
= screen_height
- (screen_height
% 32);
669 memcpy(src
->vaddr
, checkerboard
, img_w
* img_h
* 4);
670 src_img
.bo
[0] = src
->handle
;
672 case G2D_IMGBUF_USERPTR
:
673 src_img
.user_ptr
[0].userptr
= (unsigned long)checkerboard
;
674 src_img
.user_ptr
[0].size
= img_w
* img_h
* 4;
676 case G2D_IMGBUF_COLOR
:
682 printf("checkerboard test with %s.\n",
683 type
== G2D_IMGBUF_GEM
? "gem" : "userptr");
685 src_img
.width
= img_w
;
686 src_img
.height
= img_h
;
687 src_img
.stride
= src_img
.width
* 4;
688 src_img
.buf_type
= type
;
689 src_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
691 dst_img
.width
= screen_width
;
692 dst_img
.height
= screen_height
;
693 dst_img
.stride
= dst_img
.width
* 4;
694 dst_img
.buf_type
= G2D_IMGBUF_GEM
;
695 dst_img
.color_mode
= G2D_COLOR_FMT_ARGB8888
| G2D_ORDER_AXRGB
;
696 src_img
.color
= 0xff000000;
697 ret
= g2d_solid_fill(ctx
, &dst_img
, src_x
, src_y
, screen_width
, screen_height
);
701 ret
= g2d_copy(ctx
, &src_img
, &dst_img
, src_x
, src_y
, dst_x
, dst_y
,
715 static void usage(char *name
)
717 fprintf(stderr
, "usage: %s [-s]\n", name
);
718 fprintf(stderr
, "-s <connector_id>@<crtc_id>:<mode>\n");
723 static const char optstr
[] = "s:";
725 int main(int argc
, char **argv
)
727 struct exynos_device
*dev
;
728 struct exynos_bo
*bo
, *src
;
729 struct connector con
;
731 uint32_t handles
[4] = {0}, pitches
[4] = {0}, offsets
[4] = {0};
732 drmModeRes
*resources
;
735 memset(&con
, 0, sizeof(struct connector
));
742 while ((c
= getopt(argc
, argv
, optstr
)) != -1) {
746 if (sscanf(optarg
, "%d:0x%64s",
748 con
.mode_str
) != 2 &&
749 sscanf(optarg
, "%d@%d:%64s",
761 fd
= drmOpen(DRM_MODULE_NAME
, NULL
);
763 fprintf(stderr
, "failed to open.\n");
767 dev
= exynos_device_create(fd
);
773 resources
= drmModeGetResources(dev
->fd
);
775 fprintf(stderr
, "drmModeGetResources failed: %s\n",
778 goto err_dev_destory
;
781 connector_find_mode(dev
->fd
, &con
, resources
);
782 drmModeFreeResources(resources
);
785 fprintf(stderr
, "failed to find usable connector\n");
787 goto err_dev_destory
;
790 screen_width
= con
.mode
->hdisplay
;
791 screen_height
= con
.mode
->vdisplay
;
793 if (screen_width
== 0 || screen_height
== 0) {
794 fprintf(stderr
, "failed to find sane resolution on connector\n");
796 goto err_dev_destory
;
799 printf("screen width = %d, screen height = %d\n", screen_width
,
802 bo
= exynos_create_buffer(dev
, screen_width
* screen_height
* 4, 0);
805 goto err_dev_destory
;
808 handles
[0] = bo
->handle
;
809 pitches
[0] = screen_width
* 4;
812 ret
= drmModeAddFB2(dev
->fd
, screen_width
, screen_height
,
813 DRM_FORMAT_XRGB8888
, handles
,
814 pitches
, offsets
, &fb_id
, 0);
816 goto err_destroy_buffer
;
818 memset(bo
->vaddr
, 0xff, screen_width
* screen_height
* 4);
820 ret
= drm_set_crtc(dev
, &con
, fb_id
);
824 ret
= g2d_solid_fill_test(dev
, bo
);
826 fprintf(stderr
, "failed to solid fill operation.\n");
830 wait_for_user_input(0);
832 src
= exynos_create_buffer(dev
, screen_width
* screen_height
* 4, 0);
838 ret
= g2d_copy_test(dev
, src
, bo
, G2D_IMGBUF_GEM
);
840 fprintf(stderr
, "failed to test copy operation.\n");
844 wait_for_user_input(0);
846 ret
= g2d_move_test(dev
, src
, bo
, G2D_IMGBUF_GEM
);
848 fprintf(stderr
, "failed to test move operation.\n");
852 wait_for_user_input(0);
854 ret
= g2d_copy_with_scale_test(dev
, src
, bo
, G2D_IMGBUF_GEM
);
856 fprintf(stderr
, "failed to test copy and scale operation.\n");
860 wait_for_user_input(0);
862 ret
= g2d_checkerboard_test(dev
, src
, bo
, G2D_IMGBUF_GEM
);
864 fprintf(stderr
, "failed to issue checkerboard test.\n");
868 wait_for_user_input(1);
871 * The blend test uses the userptr functionality of exynos-drm, which
872 * is currently not safe to use. If the kernel hasn't been build with
873 * exynos-iommu support, then the blend test is going to produce (kernel)
874 * memory corruption, eventually leading to a system crash.
876 * Disable the test for now, until the kernel code has been sanitized.
878 #ifdef EXYNOS_G2D_USERPTR_TEST
879 ret
= g2d_blend_test(dev
, src
, bo
, G2D_IMGBUF_USERPTR
);
881 fprintf(stderr
, "failed to test blend operation.\n");
888 exynos_destroy_buffer(src
);
891 drmModeRmFB(dev
->fd
, fb_id
);
894 exynos_destroy_buffer(bo
);
897 exynos_device_destroy(dev
);