xref: /aosp_15_r20/external/libdrm/tests/exynos/exynos_fimg2d_test.c (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1 /*
2  * Copyright (C) 2013 Samsung Electronics Co.Ltd
3  * Authors:
4  *	Inki Dae <[email protected]>
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 <libkms.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 
46 static unsigned int screen_width, screen_height;
47 
48 struct connector {
49 	uint32_t id;
50 	char mode_str[64];
51 	drmModeModeInfo *mode;
52 	drmModeEncoder *encoder;
53 	int crtc;
54 };
55 
connector_find_mode(int fd,struct connector * c,drmModeRes * resources)56 static 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 
drm_set_crtc(struct exynos_device * dev,struct connector * c,unsigned int fb_id)121 static 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 
exynos_create_buffer(struct exynos_device * dev,unsigned long size,unsigned int flags)134 static 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.                */
create_checkerboard_pattern(unsigned int num_tiles_x,unsigned int num_tiles_y,unsigned int tile_size)154 static 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 
exynos_destroy_buffer(struct exynos_bo * bo)179 static void exynos_destroy_buffer(struct exynos_bo *bo)
180 {
181 	exynos_bo_destroy(bo);
182 }
183 
wait_for_user_input(int last)184 static 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 
g2d_solid_fill_test(struct exynos_device * dev,struct exynos_bo * dst)192 static 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 
234 err_fini:
235 	g2d_fini(ctx);
236 
237 	return ret;
238 }
239 
g2d_copy_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)240 static 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 
312 err_free_userptr:
313 	if (type == G2D_IMGBUF_USERPTR)
314 		if (userptr)
315 			free((void *)userptr);
316 
317 fail:
318 	g2d_fini(ctx);
319 
320 	return ret;
321 }
322 
g2d_move_test(struct exynos_device * dev,struct exynos_bo * tmp,struct exynos_bo * buf,enum e_g2d_buf_type type)323 static 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 
439 fail:
440 	g2d_fini(ctx);
441 
442 	free(checkerboard);
443 
444 	return ret;
445 }
446 
g2d_copy_with_scale_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)447 static 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 
523 err_free_userptr:
524 	if (type == G2D_IMGBUF_USERPTR)
525 		if (userptr)
526 			free((void *)userptr);
527 
528 fail:
529 	g2d_fini(ctx);
530 
531 	return ret;
532 }
533 
534 #ifdef EXYNOS_G2D_USERPTR_TEST
g2d_blend_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)535 static 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 
624 err_free_userptr:
625 	if (type == G2D_IMGBUF_USERPTR)
626 		if (userptr)
627 			free((void *)userptr);
628 
629 fail:
630 	g2d_fini(ctx);
631 
632 	return ret;
633 }
634 #endif
635 
g2d_checkerboard_test(struct exynos_device * dev,struct exynos_bo * src,struct exynos_bo * dst,enum e_g2d_buf_type type)636 static 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 
708 fail:
709 	free(checkerboard);
710 	g2d_fini(ctx);
711 
712 	return ret;
713 }
714 
usage(char * name)715 static 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 
722 extern char *optarg;
723 static const char optstr[] = "s:";
724 
main(int argc,char ** argv)725 int 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 
886 err_free_src:
887 	if (src)
888 		exynos_destroy_buffer(src);
889 
890 err_rm_fb:
891 	drmModeRmFB(dev->fd, fb_id);
892 
893 err_destroy_buffer:
894 	exynos_destroy_buffer(bo);
895 
896 err_dev_destory:
897 	exynos_device_destroy(dev);
898 
899 err_drm_close:
900 	drmClose(fd);
901 
902 	return ret;
903 }
904