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