exynos_fimg2d_test.c revision baaff307
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
22#include <sys/mman.h>
23#include <linux/stddef.h>
24
25#include <xf86drm.h>
26#include <xf86drmMode.h>
27#include <libkms.h>
28#include <drm_fourcc.h>
29
30#include "exynos_drm.h"
31#include "exynos_drmif.h"
32#include "fimg2d.h"
33
34#define DRM_MODULE_NAME		"exynos"
35#define MAX_TEST_CASE		8
36
37static unsigned int screen_width, screen_height;
38
39/*
40 * A structure to test fimg2d hw.
41 *
42 * @solid_fild: fill given color data to source buffer.
43 * @copy: copy source to destination buffer.
44 * @copy_with_scale: copy source to destination buffer scaling up or
45 *	down properly.
46 * @blend: blend source to destination buffer.
47 */
48struct fimg2d_test_case {
49	int (*solid_fill)(struct exynos_device *dev, struct exynos_bo *dst);
50	int (*copy)(struct exynos_device *dev, struct exynos_bo *src,
51			struct exynos_bo *dst, enum e_g2d_buf_type);
52	int (*copy_with_scale)(struct exynos_device *dev,
53				struct exynos_bo *src, struct exynos_bo *dst,
54				enum e_g2d_buf_type);
55	int (*blend)(struct exynos_device *dev,
56				struct exynos_bo *src, struct exynos_bo *dst,
57				enum e_g2d_buf_type);
58};
59
60struct connector {
61	uint32_t id;
62	char mode_str[64];
63	char format_str[5];
64	unsigned int fourcc;
65	drmModeModeInfo *mode;
66	drmModeEncoder *encoder;
67	int crtc;
68	int pipe;
69	int plane_zpos;
70	unsigned int fb_id[2], current_fb_id;
71	struct timeval start;
72
73	int swap_count;
74};
75
76static void connector_find_mode(int fd, struct connector *c,
77				drmModeRes *resources)
78{
79	drmModeConnector *connector;
80	int i, j;
81
82	/* First, find the connector & mode */
83	c->mode = NULL;
84	for (i = 0; i < resources->count_connectors; i++) {
85		connector = drmModeGetConnector(fd, resources->connectors[i]);
86
87		if (!connector) {
88			fprintf(stderr, "could not get connector %i: %s\n",
89				resources->connectors[i], strerror(errno));
90			drmModeFreeConnector(connector);
91			continue;
92		}
93
94		if (!connector->count_modes) {
95			drmModeFreeConnector(connector);
96			continue;
97		}
98
99		if (connector->connector_id != c->id) {
100			drmModeFreeConnector(connector);
101			continue;
102		}
103
104		for (j = 0; j < connector->count_modes; j++) {
105			c->mode = &connector->modes[j];
106			if (!strcmp(c->mode->name, c->mode_str))
107				break;
108		}
109
110		/* Found it, break out */
111		if (c->mode)
112			break;
113
114		drmModeFreeConnector(connector);
115	}
116
117	if (!c->mode) {
118		fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
119		return;
120	}
121
122	/* Now get the encoder */
123	for (i = 0; i < resources->count_encoders; i++) {
124		c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
125
126		if (!c->encoder) {
127			fprintf(stderr, "could not get encoder %i: %s\n",
128				resources->encoders[i], strerror(errno));
129			drmModeFreeEncoder(c->encoder);
130			continue;
131		}
132
133		if (c->encoder->encoder_id  == connector->encoder_id)
134			break;
135
136		drmModeFreeEncoder(c->encoder);
137	}
138
139	if (c->crtc == -1)
140		c->crtc = c->encoder->crtc_id;
141}
142
143static int connector_find_plane(int fd, unsigned int *plane_id)
144{
145	drmModePlaneRes *plane_resources;
146	drmModePlane *ovr;
147	int i;
148
149	plane_resources = drmModeGetPlaneResources(fd);
150	if (!plane_resources) {
151		fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
152			strerror(errno));
153		return -1;
154	}
155
156	for (i = 0; i < plane_resources->count_planes; i++) {
157		plane_id[i] = 0;
158
159		ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
160		if (!ovr) {
161			fprintf(stderr, "drmModeGetPlane failed: %s\n",
162				strerror(errno));
163			continue;
164		}
165
166		if (ovr->possible_crtcs & (1 << 0))
167			plane_id[i] = ovr->plane_id;
168		drmModeFreePlane(ovr);
169	}
170
171	return 0;
172}
173
174static int drm_set_crtc(struct exynos_device *dev, struct connector *c,
175			unsigned int fb_id)
176{
177	int ret;
178
179	ret = drmModeSetCrtc(dev->fd, c->crtc,
180			fb_id, 0, 0, &c->id, 1, c->mode);
181	if (ret) {
182		drmMsg("failed to set mode: %s\n", strerror(errno));
183		goto err;
184	}
185
186	return 0;
187
188err:
189	return ret;
190}
191
192static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev,
193						unsigned long size,
194						unsigned int flags)
195{
196	struct exynos_bo *bo;
197
198	bo = exynos_bo_create(dev, size, flags);
199	if (!bo)
200		return bo;
201
202	if (!exynos_bo_map(bo)) {
203		exynos_bo_destroy(bo);
204		return NULL;
205	}
206
207	return bo;
208}
209
210static void exynos_destroy_buffer(struct exynos_bo *bo)
211{
212	exynos_bo_destroy(bo);
213}
214
215static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst)
216{
217	struct g2d_context *ctx;
218	struct g2d_image img;
219	unsigned int count, img_w, img_h;
220	int ret = 0;
221
222	ctx = g2d_init(dev->fd);
223	if (!ctx)
224		return -EFAULT;
225
226	memset(&img, 0, sizeof(struct g2d_image));
227	img.bo[0] = dst->handle;
228
229	printf("soild fill test.\n");
230
231	srand(time(NULL));
232	img_w = screen_width;
233	img_h = screen_height;
234
235	for (count = 0; count < 2; count++) {
236		unsigned int x, y, w, h;
237
238		x = rand() % (img_w / 2);
239		y = rand() % (img_h / 2);
240		w = rand() % (img_w - x);
241		h = rand() % (img_h - y);
242
243		img.width = img_w;
244		img.height = img_h;
245		img.stride = img.width * 4;
246		img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
247		img.color = 0xff000000 + (random() & 0xffffff);
248
249		ret = g2d_solid_fill(ctx, &img, x, y, w, h);
250		if (ret < 0)
251			goto err_fini;
252
253		ret = g2d_exec(ctx);
254		if (ret < 0)
255			break;
256	}
257
258err_fini:
259	g2d_fini(ctx);
260
261	return ret;
262}
263
264static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src,
265				struct exynos_bo *dst,
266				enum e_g2d_buf_type type)
267{
268	struct g2d_context *ctx;
269	struct g2d_image src_img, dst_img;
270	unsigned int count;
271	unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
272	unsigned long userptr, size;
273	int ret;
274
275	ctx = g2d_init(dev->fd);
276	if (!ctx)
277		return -EFAULT;
278
279	memset(&src_img, 0, sizeof(struct g2d_image));
280	memset(&dst_img, 0, sizeof(struct g2d_image));
281	dst_img.bo[0] = dst->handle;
282
283	src_x = 0;
284	src_y = 0;
285	dst_x = 0;
286	dst_y = 0;
287	img_w = screen_width;
288	img_h = screen_height;
289
290	switch (type) {
291	case G2D_IMGBUF_GEM:
292		src_img.bo[0] = src->handle;
293		break;
294	case G2D_IMGBUF_USERPTR:
295		size = img_w * img_h * 4;
296
297		userptr = (unsigned long)malloc(size);
298		if (!userptr) {
299			fprintf(stderr, "failed to allocate userptr.\n");
300			return -EFAULT;
301		}
302
303		src_img.user_ptr[0].userptr = userptr;
304		src_img.user_ptr[0].size = size;
305		break;
306	default:
307		type = G2D_IMGBUF_GEM;
308		break;
309	}
310
311	printf("copy test with %s.\n",
312			type == G2D_IMGBUF_GEM ? "gem" : "userptr");
313
314	src_img.width = img_w;
315	src_img.height = img_h;
316	src_img.stride = src_img.width * 4;
317	src_img.buf_type = type;
318	src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
319	src_img.color = 0xffff0000;
320	ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
321	if (ret < 0)
322		goto err_free_userptr;
323
324	dst_img.width = img_w;
325	dst_img.height = img_h;
326	dst_img.stride = dst_img.width * 4;
327	dst_img.buf_type = G2D_IMGBUF_GEM;
328	dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
329
330	ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y,
331			img_w - 4, img_h - 4);
332	if (ret < 0)
333		goto err_free_userptr;
334
335	g2d_exec(ctx);
336
337err_free_userptr:
338	if (type == G2D_IMGBUF_USERPTR)
339		if (userptr)
340			free((void *)userptr);
341
342	g2d_fini(ctx);
343
344	return ret;
345}
346
347static int g2d_copy_with_scale_test(struct exynos_device *dev,
348					struct exynos_bo *src,
349					struct exynos_bo *dst,
350					enum e_g2d_buf_type type)
351{
352	struct g2d_context *ctx;
353	struct g2d_image src_img, dst_img;
354	unsigned int count;
355	unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
356	unsigned long userptr, size;
357	int ret;
358
359	ctx = g2d_init(dev->fd);
360	if (!ctx)
361		return -EFAULT;
362
363	memset(&src_img, 0, sizeof(struct g2d_image));
364	memset(&dst_img, 0, sizeof(struct g2d_image));
365	dst_img.bo[0] = dst->handle;
366
367	src_x = 0;
368	src_y = 0;
369	dst_x = 0;
370	dst_y = 0;
371	img_w = screen_width;
372	img_h = screen_height;
373
374	switch (type) {
375	case G2D_IMGBUF_GEM:
376		src_img.bo[0] = src->handle;
377		break;
378	case G2D_IMGBUF_USERPTR:
379		size = img_w * img_h * 4;
380
381		userptr = (unsigned long)malloc(size);
382		if (!userptr) {
383			fprintf(stderr, "failed to allocate userptr.\n");
384			return -EFAULT;
385		}
386
387		src_img.user_ptr[0].userptr = userptr;
388		src_img.user_ptr[0].size = size;
389		break;
390	default:
391		type = G2D_IMGBUF_GEM;
392		break;
393	}
394
395	printf("copy and scale test with %s.\n",
396			type == G2D_IMGBUF_GEM ? "gem" : "userptr");
397
398	src_img.width = img_w;
399	src_img.height = img_h;
400	src_img.stride = src_img.width * 4;
401	src_img.buf_type = type;
402	src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
403	src_img.color = 0xffffffff;
404	ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w ,  img_h);
405	if (ret < 0)
406		goto err_free_userptr;
407
408	src_img.color = 0xff00ff00;
409	ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100);
410	if (ret < 0)
411		goto err_free_userptr;
412
413	dst_img.width = img_w;
414	dst_img.height = img_h;
415	dst_img.buf_type = G2D_IMGBUF_GEM;
416	dst_img.stride = dst_img.width * 4;
417	dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
418
419	ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100,
420					100, 100, 200, 200, 0);
421	if (ret < 0)
422		goto err_free_userptr;
423
424	g2d_exec(ctx);
425
426err_free_userptr:
427	if (type == G2D_IMGBUF_USERPTR)
428		if (userptr)
429			free((void *)userptr);
430
431	g2d_fini(ctx);
432
433	return 0;
434}
435
436static int g2d_blend_test(struct exynos_device *dev,
437					struct exynos_bo *src,
438					struct exynos_bo *dst,
439					enum e_g2d_buf_type type)
440{
441	struct g2d_context *ctx;
442	struct g2d_image src_img, dst_img;
443	unsigned int count;
444	unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h;
445	unsigned long userptr, size;
446	int ret;
447
448	ctx = g2d_init(dev->fd);
449	if (!ctx)
450		return -EFAULT;
451
452	memset(&src_img, 0, sizeof(struct g2d_image));
453	memset(&dst_img, 0, sizeof(struct g2d_image));
454	dst_img.bo[0] = dst->handle;
455
456	src_x = 0;
457	src_y = 0;
458	dst_x = 0;
459	dst_y = 0;
460	img_w = screen_width;
461	img_h = screen_height;
462
463	switch (type) {
464	case G2D_IMGBUF_GEM:
465		src_img.bo[0] = src->handle;
466		break;
467	case G2D_IMGBUF_USERPTR:
468		size = img_w * img_h * 4;
469
470		userptr = (unsigned long)malloc(size);
471		if (!userptr) {
472			fprintf(stderr, "failed to allocate userptr.\n");
473			return -EFAULT;
474		}
475
476		src_img.user_ptr[0].userptr = userptr;
477		src_img.user_ptr[0].size = size;
478		break;
479	default:
480		type = G2D_IMGBUF_GEM;
481		break;
482	}
483
484	printf("blend 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.select_mode = G2D_SELECT_MODE_NORMAL;
492	src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
493	src_img.color = 0xffffffff;
494	ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h);
495	if (ret < 0)
496		goto err_free_userptr;
497
498	src_img.color = 0x770000ff;
499	ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200);
500	if (ret < 0)
501		goto err_free_userptr;
502
503	dst_img.width = img_w;
504	dst_img.height = img_h;
505	dst_img.stride = dst_img.width * 4;
506	dst_img.buf_type = G2D_IMGBUF_GEM;
507	dst_img.select_mode = G2D_SELECT_MODE_NORMAL;
508	dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB;
509	dst_img.color = 0xffffffff;
510	ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h);
511	if (ret < 0)
512		goto err_free_userptr;
513
514	dst_img.color = 0x77ff0000;
515	ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200);
516	if (ret < 0)
517		goto err_free_userptr;
518
519	ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200,
520			G2D_OP_OVER);
521	if (ret < 0)
522		goto err_free_userptr;
523
524	g2d_exec(ctx);
525
526err_free_userptr:
527	if (type == G2D_IMGBUF_USERPTR)
528		if (userptr)
529			free((void *)userptr);
530
531	g2d_fini(ctx);
532
533	return 0;
534}
535
536static struct fimg2d_test_case test_case = {
537	.solid_fill = &g2d_solid_fill_test,
538	.copy = &g2d_copy_test,
539	.copy_with_scale = &g2d_copy_with_scale_test,
540	.blend = &g2d_blend_test,
541};
542
543static void usage(char *name)
544{
545	fprintf(stderr, "usage: %s [-s]\n", name);
546	fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n");
547	exit(0);
548}
549
550extern char *optarg;
551static const char optstr[] = "s:";
552
553int main(int argc, char **argv)
554{
555	struct exynos_device *dev;
556	struct exynos_bo *bo, *src;
557	struct connector con;
558	char *modeset = NULL;
559	unsigned int fb_id;
560	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
561	drmModeRes *resources;
562	int ret, fd, c;
563
564	memset(&con, 0, sizeof(struct connector));
565
566	if (argc != 3) {
567		usage(argv[0]);
568		return -EINVAL;
569	}
570
571	while ((c = getopt(argc, argv, optstr)) != -1) {
572		switch (c) {
573		case 's':
574			modeset = strdup(optarg);
575			con.crtc = -1;
576			if (sscanf(optarg, "%d:0x%64s",
577						&con.id,
578						con.mode_str) != 2 &&
579					sscanf(optarg, "%d@%d:%64s",
580						&con.id,
581						&con.crtc,
582						con.mode_str) != 3)
583				usage(argv[0]);
584			break;
585		default:
586			usage(argv[0]);
587			return -EINVAL;
588		}
589	}
590
591	fd = drmOpen(DRM_MODULE_NAME, NULL);
592	if (fd < 0) {
593		fprintf(stderr, "failed to open.\n");
594		return fd;
595	}
596
597	dev = exynos_device_create(fd);
598	if (!dev) {
599		drmClose(dev->fd);
600		return -EFAULT;
601	}
602
603	resources = drmModeGetResources(dev->fd);
604	if (!resources) {
605		fprintf(stderr, "drmModeGetResources failed: %s\n",
606				strerror(errno));
607		ret = -EFAULT;
608		goto err_drm_close;
609	}
610
611	connector_find_mode(dev->fd, &con, resources);
612	drmModeFreeResources(resources);
613
614	screen_width = con.mode->hdisplay;
615	screen_height = con.mode->vdisplay;
616
617	printf("screen width  = %d, screen height = %d\n", screen_width,
618			screen_height);
619
620	bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
621	if (!bo) {
622		ret = -EFAULT;
623		goto err_drm_close;
624	}
625
626	handles[0] = bo->handle;
627	pitches[0] = screen_width * 4;
628	offsets[0] = 0;
629
630	ret = drmModeAddFB2(dev->fd, screen_width, screen_height,
631				DRM_FORMAT_RGBA8888, handles,
632				pitches, offsets, &fb_id, 0);
633	if (ret < 0)
634		goto err_destroy_buffer;
635
636	con.plane_zpos = -1;
637
638	memset(bo->vaddr, 0xff, screen_width * screen_height * 4);
639
640	ret = drm_set_crtc(dev, &con, fb_id);
641	if (ret < 0)
642		goto err_rm_fb;
643
644	ret = test_case.solid_fill(dev, bo);
645	if (ret < 0) {
646		fprintf(stderr, "failed to solid fill operation.\n");
647		goto err_rm_fb;
648	}
649
650	getchar();
651
652	src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0);
653	if (!src) {
654		ret = -EFAULT;
655		goto err_rm_fb;
656	}
657
658	ret = test_case.copy(dev, src, bo, G2D_IMGBUF_GEM);
659	if (ret < 0) {
660		fprintf(stderr, "failed to test copy operation.\n");
661		goto err_free_src;
662	}
663
664	getchar();
665
666	ret = test_case.copy_with_scale(dev, src, bo, G2D_IMGBUF_GEM);
667	if (ret < 0) {
668		fprintf(stderr, "failed to test copy and scale operation.\n");
669		goto err_free_src;
670	}
671
672	getchar();
673
674	ret  = test_case.blend(dev, src, bo, G2D_IMGBUF_USERPTR);
675	if (ret < 0)
676		fprintf(stderr, "failed to test blend operation.\n");
677
678	getchar();
679
680err_free_src:
681	if (src)
682		exynos_destroy_buffer(src);
683
684err_rm_fb:
685	drmModeRmFB(dev->fd, fb_id);
686
687err_destroy_buffer:
688	exynos_destroy_buffer(bo);
689
690err_drm_close:
691	drmClose(dev->fd);
692	exynos_device_destroy(dev);
693
694	return 0;
695}
696