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