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