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