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