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