1 /*
2 * Copyright (C) 2013 Samsung Electronics Co.Ltd
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 *
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:
12 *
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
15 * Software.
16 *
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.
24 */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #include <sys/mman.h>
34 #include <linux/stddef.h>
35
36 #include <xf86drm.h>
37 #include <xf86drmMode.h>
38 #include <libkms.h>
39 #include <drm_fourcc.h>
40
41 #include "exynos_drm.h"
42 #include "exynos_drmif.h"
43 #include "exynos_fimg2d.h"
44
45 #define DRM_MODULE_NAME "exynos"
46
47 static unsigned int screen_width, screen_height;
48
49 struct connector {
50 uint32_t id;
51 char mode_str[64];
52 drmModeModeInfo *mode;
53 drmModeEncoder *encoder;
54 int crtc;
55 };
56
connector_find_mode(int fd,struct connector * c,drmModeRes * resources)57 static void connector_find_mode(int fd, struct connector *c,
58 drmModeRes *resources)
59 {
60 drmModeConnector *connector;
61 int i, j;
62
63 /* First, find the connector & mode */
64 c->mode = NULL;
65 for (i = 0; i < resources->count_connectors; i++) {
66 connector = drmModeGetConnector(fd, resources->connectors[i]);
67
68 if (!connector) {
69 fprintf(stderr, "could not get connector %i: %s\n",
70 resources->connectors[i], strerror(errno));
71 continue;
72 }
73
74 if (!connector->count_modes) {
75 drmModeFreeConnector(connector);
76 continue;
77 }
78
79 if (connector->connector_id != c->id) {
80 drmModeFreeConnector(connector);
81 continue;
82 }
83
84 for (j = 0; j < connector->count_modes; j++) {
85 c->mode = &connector->modes[j];
86 if (!strcmp(c->mode->name, c->mode_str))
87 break;
88 }
89
90 /* Found it, break out */
91 if (c->mode)
92 break;
93
94 drmModeFreeConnector(connector);
95 }
96
97 if (!c->mode) {
98 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
99 return;
100 }
101
102 /* Now get the encoder */
103 for (i = 0; i < resources->count_encoders; i++) {
104 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
105
106 if (!c->encoder) {
107 fprintf(stderr, "could not get encoder %i: %s\n",
108 resources->encoders[i], strerror(errno));
109 continue;
110 }
111
112 if (c->encoder->encoder_id == connector->encoder_id)
113 break;
114
115 drmModeFreeEncoder(c->encoder);
116 }
117
118 if (c->crtc == -1)
119 c->crtc = c->encoder->crtc_id;
120 }
121
drm_set_crtc(struct exynos_device * dev,struct connector * c,unsigned int fb_id)122 static int drm_set_crtc(struct exynos_device *dev, struct connector *c,
123 unsigned int fb_id)
124 {
125 int ret;
126
127 ret = drmModeSetCrtc(dev->fd, c->crtc,
128 fb_id, 0, 0, &c->id, 1, c->mode);
129 if (ret)
130 drmMsg("failed to set mode: %s\n", strerror(errno));
131
132 return ret;
133 }
134
exynos_create_buffer(struct exynos_device * dev,unsigned long size,unsigned int flags)135 static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev,
136 unsigned long size,
137 unsigned int flags)
138 {
139 struct exynos_bo *bo;
140
141 bo = exynos_bo_create(dev, size, flags);
142 if (!bo)
143 return bo;
144
145 if (!exynos_bo_map(bo)) {
146 exynos_bo_destroy(bo);
147 return NULL;
148 }
149
150 return bo;
151 }
152
153 /* Allocate buffer and fill it with checkerboard pattern, where the tiles *
154 * have a random color. The caller has to free the buffer. */
create_checkerboard_pattern(unsigned int num_tiles_x,unsigned int num_tiles_y,unsigned int tile_size)155 static void *create_checkerboard_pattern(unsigned int num_tiles_x,
156 unsigned int num_tiles_y, unsigned int tile_size)
157 {
158 unsigned int *buf;
159 unsigned int x, y, i, j;
160 const unsigned int stride = num_tiles_x * tile_size;
161
162 if (posix_memalign((void*)&buf, 64, num_tiles_y * tile_size * stride * 4) != 0)
163 return NULL;
164
165 for (x = 0; x < num_tiles_x; ++x) {
166 for (y = 0; y < num_tiles_y; ++y) {
167 const unsigned int color = 0xff000000 + (random() & 0xffffff);
168
169 for (i = 0; i < tile_size; ++i) {
170 for (j = 0; j < tile_size; ++j) {
171 buf[x * tile_size + y * stride * tile_size + i + j * stride] = color;
172 }
173 }
174 }
175 }
176
177 return buf;
178 }
179
exynos_destroy_buffer(struct exynos_bo * bo)180 static void exynos_destroy_buffer(struct exynos_bo *bo)
181 {
182 exynos_bo_destroy(bo);
183 }
184
wait_for_user_input(int last)185 static void wait_for_user_input(int last)
186 {
187 printf("press <ENTER> to %s\n", last ? "exit test application" :
188 "skip to next test");
189
190 getchar();
191 }
192
g2d_solid_fill_test(struct exynos_device * dev,struct exynos_bo * dst)193 static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst)
194 {
195 struct g2d_context *ctx;
196 struct g2d_image img = {0};
197 unsigned int count, img_w, img_h;
198 int ret = 0;
199
200 ctx = g2d_init(dev->fd);
201 if (!ctx)
202 return -EFAULT;
203
204 img.bo[0] = dst->handle;
205
206 printf("solid fill test.\n");
207
208 srand(time(NULL));
209 img_w = screen_width;
210 img_h = screen_height;
211
212 for (count = 0; count < 2; count++) {
213 unsigned int x, y, w, h;
214
215 x = rand() % (img_w / 2);
216 y = rand() % (img_h / 2);
217 w = rand() % (img_w - x);
218 h = rand() % (img_h - y);
219
220 img.width = img_w;
221 img.height = img_h;
222 img.stride = img.width * 4;
223 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
224 img.color = 0xff000000 + (random() & 0xffffff);
225
226 ret = g2d_solid_fill(ctx, &img, x, y, w, h);
227 if (ret < 0)
228 goto err_fini;
229
230 ret = g2d_exec(ctx);
231 if (ret < 0)
232 break;
233 }
234
235 err_fini:
236 g2d_fini(ctx);
237
238 return ret;
239 }
240
g2d_copy_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)241 static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src,
242 struct exynos_bo *dst,
243 enum e_g2d_buf_type type)
244 {
245 struct g2d_context *ctx;
246 struct g2d_image src_img = {0}, dst_img = {0};
247 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
248 unsigned long userptr, size;
249 int ret;
250
251 ctx = g2d_init(dev->fd);
252 if (!ctx)
253 return -EFAULT;
254
255 dst_img.bo[0] = dst->handle;
256
257 src_x = 0;
258 src_y = 0;
259 dst_x = 0;
260 dst_y = 0;
261 img_w = screen_width;
262 img_h = screen_height;
263
264 switch (type) {
265 case G2D_IMGBUF_GEM:
266 src_img.bo[0] = src->handle;
267 break;
268 case G2D_IMGBUF_USERPTR:
269 size = img_w * img_h * 4;
270
271 userptr = (unsigned long)malloc(size);
272 if (!userptr) {
273 fprintf(stderr, "failed to allocate userptr.\n");
274 ret = -EFAULT;
275 goto fail;
276 }
277
278 src_img.user_ptr[0].userptr = userptr;
279 src_img.user_ptr[0].size = size;
280 break;
281 case G2D_IMGBUF_COLOR:
282 default:
283 ret = -EFAULT;
284 goto fail;
285 }
286
287 printf("copy test with %s.\n",
288 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
289
290 src_img.width = img_w;
291 src_img.height = img_h;
292 src_img.stride = src_img.width * 4;
293 src_img.buf_type = type;
294 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
295 src_img.color = 0xffff0000;
296 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
297 if (ret < 0)
298 goto err_free_userptr;
299
300 dst_img.width = img_w;
301 dst_img.height = img_h;
302 dst_img.stride = dst_img.width * 4;
303 dst_img.buf_type = G2D_IMGBUF_GEM;
304 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
305
306 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
307 img_w - 4, img_h - 4);
308 if (ret < 0)
309 goto err_free_userptr;
310
311 g2d_exec(ctx);
312
313 err_free_userptr:
314 if (type == G2D_IMGBUF_USERPTR)
315 if (userptr)
316 free((void *)userptr);
317
318 fail:
319 g2d_fini(ctx);
320
321 return ret;
322 }
323
g2d_move_test(struct exynos_device * dev,struct exynos_bo * tmp,struct exynos_bo * buf,enum e_g2d_buf_type type)324 static int g2d_move_test(struct exynos_device *dev,
325 struct exynos_bo *tmp,
326 struct exynos_bo *buf,
327 enum e_g2d_buf_type type)
328 {
329 struct g2d_context *ctx;
330 struct g2d_image img = {0}, tmp_img = {0};
331 unsigned int img_w, img_h, count;
332 int cur_x, cur_y;
333 void *checkerboard;
334 int ret;
335
336 static const struct g2d_step {
337 int x, y;
338 } steps[] = {
339 { 1, 0}, { 0, 1},
340 {-1, 0}, { 0, -1},
341 { 1, 1}, {-1, -1},
342 { 1, -1}, {-1, 1},
343 { 2, 1}, { 1, 2},
344 {-2, -1}, {-1, -2},
345 { 2, -1}, { 1, -2},
346 {-2, 1}, {-1, 2}
347 };
348 static const unsigned int num_steps =
349 sizeof(steps) / sizeof(struct g2d_step);
350
351 ctx = g2d_init(dev->fd);
352 if (!ctx)
353 return -EFAULT;
354
355 img.bo[0] = buf->handle;
356
357 /* create pattern of half the screen size */
358 checkerboard = create_checkerboard_pattern(screen_width / 64, screen_height / 64, 32);
359 if (!checkerboard) {
360 ret = -EFAULT;
361 goto fail;
362 }
363
364 img_w = (screen_width / 64) * 32;
365 img_h = (screen_height / 64) * 32;
366
367 switch (type) {
368 case G2D_IMGBUF_GEM:
369 memcpy(tmp->vaddr, checkerboard, img_w * img_h * 4);
370 tmp_img.bo[0] = tmp->handle;
371 break;
372 case G2D_IMGBUF_USERPTR:
373 tmp_img.user_ptr[0].userptr = (unsigned long)checkerboard;
374 tmp_img.user_ptr[0].size = img_w * img_h * 4;
375 break;
376 case G2D_IMGBUF_COLOR:
377 default:
378 ret = -EFAULT;
379 goto fail;
380 }
381
382 /* solid fill framebuffer with white color */
383 img.width = screen_width;
384 img.height = screen_height;
385 img.stride = screen_width * 4;
386 img.buf_type = G2D_IMGBUF_GEM;
387 img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
388 img.color = 0xffffffff;
389
390 /* put checkerboard pattern in the center of the framebuffer */
391 cur_x = (screen_width - img_w) / 2;
392 cur_y = (screen_height - img_h) / 2;
393 tmp_img.width = img_w;
394 tmp_img.height = img_h;
395 tmp_img.stride = img_w * 4;
396 tmp_img.buf_type = type;
397 tmp_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
398
399 ret = g2d_solid_fill(ctx, &img, 0, 0, screen_width, screen_height) ||
400 g2d_copy(ctx, &tmp_img, &img, 0, 0, cur_x, cur_y, img_w, img_h);
401
402 if (!ret)
403 ret = g2d_exec(ctx);
404 if (ret < 0)
405 goto fail;
406
407 printf("move test with %s.\n",
408 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
409
410 srand(time(NULL));
411 for (count = 0; count < 256; ++count) {
412 const struct g2d_step *s;
413
414 /* select step and validate it */
415 while (1) {
416 s = &steps[random() % num_steps];
417
418 if (cur_x + s->x < 0 || cur_y + s->y < 0 ||
419 cur_x + img_w + s->x >= screen_width ||
420 cur_y + img_h + s->y >= screen_height)
421 continue;
422 else
423 break;
424 }
425
426 ret = g2d_move(ctx, &img, cur_x, cur_y, cur_x + s->x, cur_y + s->y,
427 img_w, img_h);
428 if (!ret)
429 ret = g2d_exec(ctx);
430
431 if (ret < 0)
432 goto fail;
433
434 cur_x += s->x;
435 cur_y += s->y;
436
437 usleep(100000);
438 }
439
440 fail:
441 g2d_fini(ctx);
442
443 free(checkerboard);
444
445 return ret;
446 }
447
g2d_copy_with_scale_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)448 static int g2d_copy_with_scale_test(struct exynos_device *dev,
449 struct exynos_bo *src,
450 struct exynos_bo *dst,
451 enum e_g2d_buf_type type)
452 {
453 struct g2d_context *ctx;
454 struct g2d_image src_img = {0}, dst_img = {0};
455 unsigned int src_x, src_y, img_w, img_h;
456 unsigned long userptr, size;
457 int ret;
458
459 ctx = g2d_init(dev->fd);
460 if (!ctx)
461 return -EFAULT;
462
463 dst_img.bo[0] = dst->handle;
464
465 src_x = 0;
466 src_y = 0;
467 img_w = screen_width;
468 img_h = screen_height;
469
470 switch (type) {
471 case G2D_IMGBUF_GEM:
472 src_img.bo[0] = src->handle;
473 break;
474 case G2D_IMGBUF_USERPTR:
475 size = img_w * img_h * 4;
476
477 userptr = (unsigned long)malloc(size);
478 if (!userptr) {
479 fprintf(stderr, "failed to allocate userptr.\n");
480 ret = -EFAULT;
481 goto fail;
482 }
483
484 src_img.user_ptr[0].userptr = userptr;
485 src_img.user_ptr[0].size = size;
486 break;
487 case G2D_IMGBUF_COLOR:
488 default:
489 ret = -EFAULT;
490 goto fail;
491 }
492
493 printf("copy and scale test with %s.\n",
494 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
495
496 src_img.width = img_w;
497 src_img.height = img_h;
498 src_img.stride = src_img.width * 4;
499 src_img.buf_type = type;
500 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
501 src_img.color = 0xffffffff;
502 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w , img_h);
503 if (ret < 0)
504 goto err_free_userptr;
505
506 src_img.color = 0xff00ff00;
507 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100);
508 if (ret < 0)
509 goto err_free_userptr;
510
511 dst_img.width = img_w;
512 dst_img.height = img_h;
513 dst_img.buf_type = G2D_IMGBUF_GEM;
514 dst_img.stride = dst_img.width * 4;
515 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
516
517 ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100,
518 100, 100, 200, 200, 0);
519 if (ret < 0)
520 goto err_free_userptr;
521
522 g2d_exec(ctx);
523
524 err_free_userptr:
525 if (type == G2D_IMGBUF_USERPTR)
526 if (userptr)
527 free((void *)userptr);
528
529 fail:
530 g2d_fini(ctx);
531
532 return ret;
533 }
534
535 #ifdef EXYNOS_G2D_USERPTR_TEST
g2d_blend_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)536 static int g2d_blend_test(struct exynos_device *dev,
537 struct exynos_bo *src,
538 struct exynos_bo *dst,
539 enum e_g2d_buf_type type)
540 {
541 struct g2d_context *ctx;
542 struct g2d_image src_img = {0}, dst_img = {0};
543 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
544 unsigned long userptr, size;
545 int ret;
546
547 ctx = g2d_init(dev->fd);
548 if (!ctx)
549 return -EFAULT;
550
551 dst_img.bo[0] = dst->handle;
552
553 src_x = 0;
554 src_y = 0;
555 dst_x = 0;
556 dst_y = 0;
557 img_w = screen_width;
558 img_h = screen_height;
559
560 switch (type) {
561 case G2D_IMGBUF_GEM:
562 src_img.bo[0] = src->handle;
563 break;
564 case G2D_IMGBUF_USERPTR:
565 size = img_w * img_h * 4;
566
567 userptr = (unsigned long)malloc(size);
568 if (!userptr) {
569 fprintf(stderr, "failed to allocate userptr.\n");
570 ret = -EFAULT;
571 goto fail;
572 }
573
574 src_img.user_ptr[0].userptr = userptr;
575 src_img.user_ptr[0].size = size;
576 break;
577 case G2D_IMGBUF_COLOR:
578 default:
579 ret = -EFAULT;
580 goto fail;
581 }
582
583 printf("blend test with %s.\n",
584 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
585
586 src_img.width = img_w;
587 src_img.height = img_h;
588 src_img.stride = src_img.width * 4;
589 src_img.buf_type = type;
590 src_img.select_mode = G2D_SELECT_MODE_NORMAL;
591 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
592 src_img.color = 0xffffffff;
593 ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
594 if (ret < 0)
595 goto err_free_userptr;
596
597 src_img.color = 0x770000ff;
598 ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200);
599 if (ret < 0)
600 goto err_free_userptr;
601
602 dst_img.width = img_w;
603 dst_img.height = img_h;
604 dst_img.stride = dst_img.width * 4;
605 dst_img.buf_type = G2D_IMGBUF_GEM;
606 dst_img.select_mode = G2D_SELECT_MODE_NORMAL;
607 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
608 dst_img.color = 0xffffffff;
609 ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h);
610 if (ret < 0)
611 goto err_free_userptr;
612
613 dst_img.color = 0x77ff0000;
614 ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200);
615 if (ret < 0)
616 goto err_free_userptr;
617
618 ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200,
619 G2D_OP_OVER);
620 if (ret < 0)
621 goto err_free_userptr;
622
623 g2d_exec(ctx);
624
625 err_free_userptr:
626 if (type == G2D_IMGBUF_USERPTR)
627 if (userptr)
628 free((void *)userptr);
629
630 fail:
631 g2d_fini(ctx);
632
633 return ret;
634 }
635 #endif
636
g2d_checkerboard_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)637 static int g2d_checkerboard_test(struct exynos_device *dev,
638 struct exynos_bo *src,
639 struct exynos_bo *dst,
640 enum e_g2d_buf_type type)
641 {
642 struct g2d_context *ctx;
643 struct g2d_image src_img = {0}, dst_img = {0};
644 unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
645 void *checkerboard = NULL;
646 int ret;
647
648 ctx = g2d_init(dev->fd);
649 if (!ctx)
650 return -EFAULT;
651
652 dst_img.bo[0] = dst->handle;
653
654 src_x = 0;
655 src_y = 0;
656 dst_x = 0;
657 dst_y = 0;
658
659 checkerboard = create_checkerboard_pattern(screen_width / 32, screen_height / 32, 32);
660 if (!checkerboard) {
661 ret = -EFAULT;
662 goto fail;
663 }
664
665 img_w = screen_width - (screen_width % 32);
666 img_h = screen_height - (screen_height % 32);
667
668 switch (type) {
669 case G2D_IMGBUF_GEM:
670 memcpy(src->vaddr, checkerboard, img_w * img_h * 4);
671 src_img.bo[0] = src->handle;
672 break;
673 case G2D_IMGBUF_USERPTR:
674 src_img.user_ptr[0].userptr = (unsigned long)checkerboard;
675 src_img.user_ptr[0].size = img_w * img_h * 4;
676 break;
677 case G2D_IMGBUF_COLOR:
678 default:
679 ret = -EFAULT;
680 goto fail;
681 }
682
683 printf("checkerboard test with %s.\n",
684 type == G2D_IMGBUF_GEM ? "gem" : "userptr");
685
686 src_img.width = img_w;
687 src_img.height = img_h;
688 src_img.stride = src_img.width * 4;
689 src_img.buf_type = type;
690 src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
691
692 dst_img.width = screen_width;
693 dst_img.height = screen_height;
694 dst_img.stride = dst_img.width * 4;
695 dst_img.buf_type = G2D_IMGBUF_GEM;
696 dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
697 src_img.color = 0xff000000;
698 ret = g2d_solid_fill(ctx, &dst_img, src_x, src_y, screen_width, screen_height);
699 if (ret < 0)
700 goto fail;
701
702 ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
703 img_w, img_h);
704 if (ret < 0)
705 goto fail;
706
707 g2d_exec(ctx);
708
709 fail:
710 free(checkerboard);
711 g2d_fini(ctx);
712
713 return ret;
714 }
715
usage(char * name)716 static void usage(char *name)
717 {
718 fprintf(stderr, "usage: %s [-s]\n", name);
719 fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n");
720 exit(0);
721 }
722
723 extern char *optarg;
724 static const char optstr[] = "s:";
725
main(int argc,char ** argv)726 int main(int argc, char **argv)
727 {
728 struct exynos_device *dev;
729 struct exynos_bo *bo, *src;
730 struct connector con;
731 unsigned int fb_id;
732 uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
733 drmModeRes *resources;
734 int ret, fd, c;
735
736 memset(&con, 0, sizeof(struct connector));
737
738 if (argc != 3) {
739 usage(argv[0]);
740 return -EINVAL;
741 }
742
743 while ((c = getopt(argc, argv, optstr)) != -1) {
744 switch (c) {
745 case 's':
746 con.crtc = -1;
747 if (sscanf(optarg, "%d:0x%64s",
748 &con.id,
749 con.mode_str) != 2 &&
750 sscanf(optarg, "%d@%d:%64s",
751 &con.id,
752 &con.crtc,
753 con.mode_str) != 3)
754 usage(argv[0]);
755 break;
756 default:
757 usage(argv[0]);
758 break;
759 }
760 }
761
762 fd = drmOpen(DRM_MODULE_NAME, NULL);
763 if (fd < 0) {
764 fprintf(stderr, "failed to open.\n");
765 return fd;
766 }
767
768 dev = exynos_device_create(fd);
769 if (!dev) {
770 ret = -EFAULT;
771 goto err_drm_close;
772 }
773
774 resources = drmModeGetResources(dev->fd);
775 if (!resources) {
776 fprintf(stderr, "drmModeGetResources failed: %s\n",
777 strerror(errno));
778 ret = -EFAULT;
779 goto err_dev_destory;
780 }
781
782 connector_find_mode(dev->fd, &con, resources);
783 drmModeFreeResources(resources);
784
785 if (!con.mode) {
786 fprintf(stderr, "failed to find usable connector\n");
787 ret = -EFAULT;
788 goto err_dev_destory;
789 }
790
791 screen_width = con.mode->hdisplay;
792 screen_height = con.mode->vdisplay;
793
794 if (screen_width == 0 || screen_height == 0) {
795 fprintf(stderr, "failed to find sane resolution on connector\n");
796 ret = -EFAULT;
797 goto err_dev_destory;
798 }
799
800 printf("screen width = %d, screen height = %d\n", screen_width,
801 screen_height);
802
803 bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
804 if (!bo) {
805 ret = -EFAULT;
806 goto err_dev_destory;
807 }
808
809 handles[0] = bo->handle;
810 pitches[0] = screen_width * 4;
811 offsets[0] = 0;
812
813 ret = drmModeAddFB2(dev->fd, screen_width, screen_height,
814 DRM_FORMAT_XRGB8888, handles,
815 pitches, offsets, &fb_id, 0);
816 if (ret < 0)
817 goto err_destroy_buffer;
818
819 memset(bo->vaddr, 0xff, screen_width * screen_height * 4);
820
821 ret = drm_set_crtc(dev, &con, fb_id);
822 if (ret < 0)
823 goto err_rm_fb;
824
825 ret = g2d_solid_fill_test(dev, bo);
826 if (ret < 0) {
827 fprintf(stderr, "failed to solid fill operation.\n");
828 goto err_rm_fb;
829 }
830
831 wait_for_user_input(0);
832
833 src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
834 if (!src) {
835 ret = -EFAULT;
836 goto err_rm_fb;
837 }
838
839 ret = g2d_copy_test(dev, src, bo, G2D_IMGBUF_GEM);
840 if (ret < 0) {
841 fprintf(stderr, "failed to test copy operation.\n");
842 goto err_free_src;
843 }
844
845 wait_for_user_input(0);
846
847 ret = g2d_move_test(dev, src, bo, G2D_IMGBUF_GEM);
848 if (ret < 0) {
849 fprintf(stderr, "failed to test move operation.\n");
850 goto err_free_src;
851 }
852
853 wait_for_user_input(0);
854
855 ret = g2d_copy_with_scale_test(dev, src, bo, G2D_IMGBUF_GEM);
856 if (ret < 0) {
857 fprintf(stderr, "failed to test copy and scale operation.\n");
858 goto err_free_src;
859 }
860
861 wait_for_user_input(0);
862
863 ret = g2d_checkerboard_test(dev, src, bo, G2D_IMGBUF_GEM);
864 if (ret < 0) {
865 fprintf(stderr, "failed to issue checkerboard test.\n");
866 goto err_free_src;
867 }
868
869 wait_for_user_input(1);
870
871 /*
872 * The blend test uses the userptr functionality of exynos-drm, which
873 * is currently not safe to use. If the kernel hasn't been build with
874 * exynos-iommu support, then the blend test is going to produce (kernel)
875 * memory corruption, eventually leading to a system crash.
876 *
877 * Disable the test for now, until the kernel code has been sanitized.
878 */
879 #ifdef EXYNOS_G2D_USERPTR_TEST
880 ret = g2d_blend_test(dev, src, bo, G2D_IMGBUF_USERPTR);
881 if (ret < 0)
882 fprintf(stderr, "failed to test blend operation.\n");
883
884 getchar();
885 #endif
886
887 err_free_src:
888 if (src)
889 exynos_destroy_buffer(src);
890
891 err_rm_fb:
892 drmModeRmFB(dev->fd, fb_id);
893
894 err_destroy_buffer:
895 exynos_destroy_buffer(bo);
896
897 err_dev_destory:
898 exynos_device_destroy(dev);
899
900 err_drm_close:
901 drmClose(fd);
902
903 return ret;
904 }
905