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