• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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