exynos_fimg2d_test.c revision 7cdc0497
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
47static unsigned int screen_width, screen_height;
48
49struct connector {
50	uint32_t id;
51	char mode_str[64];
52	drmModeModeInfo *mode;
53	drmModeEncoder *encoder;
54	int crtc;
55};
56
57static 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
122static 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
135static 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.                */
155static 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
180static void exynos_destroy_buffer(struct exynos_bo *bo)
181{
182	exynos_bo_destroy(bo);
183}
184
185static 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
193static 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
235err_fini:
236	g2d_fini(ctx);
237
238	return ret;
239}
240
241static 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
313err_free_userptr:
314	if (type == G2D_IMGBUF_USERPTR)
315		if (userptr)
316			free((void *)userptr);
317
318fail:
319	g2d_fini(ctx);
320
321	return ret;
322}
323
324static 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
440fail:
441	g2d_fini(ctx);
442
443	free(checkerboard);
444
445	return ret;
446}
447
448static 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
524err_free_userptr:
525	if (type == G2D_IMGBUF_USERPTR)
526		if (userptr)
527			free((void *)userptr);
528
529fail:
530	g2d_fini(ctx);
531
532	return ret;
533}
534
535#ifdef EXYNOS_G2D_USERPTR_TEST
536static 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
625err_free_userptr:
626	if (type == G2D_IMGBUF_USERPTR)
627		if (userptr)
628			free((void *)userptr);
629
630fail:
631	g2d_fini(ctx);
632
633	return ret;
634}
635#endif
636
637static 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
709fail:
710	free(checkerboard);
711	g2d_fini(ctx);
712
713	return ret;
714}
715
716static 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
723extern char *optarg;
724static const char optstr[] = "s:";
725
726int 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
887err_free_src:
888	if (src)
889		exynos_destroy_buffer(src);
890
891err_rm_fb:
892	drmModeRmFB(dev->fd, fb_id);
893
894err_destroy_buffer:
895	exynos_destroy_buffer(bo);
896
897err_dev_destory:
898	exynos_device_destroy(dev);
899
900err_drm_close:
901	drmClose(fd);
902
903	return ret;
904}
905