diff options
Diffstat (limited to 'tests/exynos')
-rw-r--r-- | tests/exynos/Makefile.am | 19 | ||||
-rw-r--r-- | tests/exynos/exynos_fimg2d_test.c | 695 |
2 files changed, 714 insertions, 0 deletions
diff --git a/tests/exynos/Makefile.am b/tests/exynos/Makefile.am new file mode 100644 index 00000000..bf9ad820 --- /dev/null +++ b/tests/exynos/Makefile.am @@ -0,0 +1,19 @@ +AM_CFLAGS = \ + -I $(top_srcdir)/include/drm \ + -I $(top_srcdir)/libkms/ \ + -I $(top_srcdir)/exynos \ + -I $(top_srcdir) + +noinst_PROGRAMS = \ + exynos_fimg2d_test + +exynos_fimg2d_test_LDADD = \ + $(top_builddir)/libdrm.la \ + $(top_builddir)/libkms/libkms.la \ + $(top_builddir)/exynos/libdrm_exynos.la + +exynos_fimg2d_test_SOURCES = \ + exynos_fimg2d_test.c + +run: exynos_fimg2d_test + ./exynos_fimg2d_test diff --git a/tests/exynos/exynos_fimg2d_test.c b/tests/exynos/exynos_fimg2d_test.c new file mode 100644 index 00000000..e80455a9 --- /dev/null +++ b/tests/exynos/exynos_fimg2d_test.c @@ -0,0 +1,695 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * Authors: + * Inki Dae <inki.dae@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <sys/mman.h> +#include <linux/stddef.h> + +#include <xf86drm.h> +#include <xf86drmMode.h> +#include <libkms.h> +#include <drm_fourcc.h> + +#include "exynos_drm.h" +#include "exynos_drmif.h" +#include "fimg2d.h" + +#define DRM_MODULE_NAME "exynos" +#define MAX_TEST_CASE 8 + +static unsigned int screen_width, screen_height; + +/* + * A structure to test fimg2d hw. + * + * @solid_fild: fill given color data to source buffer. + * @copy: copy source to destination buffer. + * @copy_with_scale: copy source to destination buffer scaling up or + * down properly. + * @blend: blend source to destination buffer. + */ +struct fimg2d_test_case { + int (*solid_fill)(struct exynos_device *dev, struct exynos_bo *dst); + int (*copy)(struct exynos_device *dev, struct exynos_bo *src, + struct exynos_bo *dst, enum e_g2d_buf_type); + int (*copy_with_scale)(struct exynos_device *dev, + struct exynos_bo *src, struct exynos_bo *dst, + enum e_g2d_buf_type); + int (*blend)(struct exynos_device *dev, + struct exynos_bo *src, struct exynos_bo *dst, + enum e_g2d_buf_type); +}; + +struct connector { + uint32_t id; + char mode_str[64]; + char format_str[5]; + unsigned int fourcc; + drmModeModeInfo *mode; + drmModeEncoder *encoder; + int crtc; + int pipe; + int plane_zpos; + unsigned int fb_id[2], current_fb_id; + struct timeval start; + + int swap_count; +}; + +static void connector_find_mode(int fd, struct connector *c, + drmModeRes *resources) +{ + drmModeConnector *connector; + int i, j; + + /* First, find the connector & mode */ + c->mode = NULL; + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + drmModeFreeConnector(connector); + continue; + } + + if (!connector->count_modes) { + drmModeFreeConnector(connector); + continue; + } + + if (connector->connector_id != c->id) { + drmModeFreeConnector(connector); + continue; + } + + for (j = 0; j < connector->count_modes; j++) { + c->mode = &connector->modes[j]; + if (!strcmp(c->mode->name, c->mode_str)) + break; + } + + /* Found it, break out */ + if (c->mode) + break; + + drmModeFreeConnector(connector); + } + + if (!c->mode) { + fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); + return; + } + + /* Now get the encoder */ + for (i = 0; i < resources->count_encoders; i++) { + c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!c->encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + drmModeFreeEncoder(c->encoder); + continue; + } + + if (c->encoder->encoder_id == connector->encoder_id) + break; + + drmModeFreeEncoder(c->encoder); + } + + if (c->crtc == -1) + c->crtc = c->encoder->crtc_id; +} + +static int connector_find_plane(int fd, unsigned int *plane_id) +{ + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + int i; + + plane_resources = drmModeGetPlaneResources(fd); + if (!plane_resources) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return -1; + } + + for (i = 0; i < plane_resources->count_planes; i++) { + plane_id[i] = 0; + + ovr = drmModeGetPlane(fd, plane_resources->planes[i]); + if (!ovr) { + fprintf(stderr, "drmModeGetPlane failed: %s\n", + strerror(errno)); + continue; + } + + if (ovr->possible_crtcs & (1 << 0)) + plane_id[i] = ovr->plane_id; + drmModeFreePlane(ovr); + } + + return 0; +} + +static int drm_set_crtc(struct exynos_device *dev, struct connector *c, + unsigned int fb_id) +{ + int ret; + + ret = drmModeSetCrtc(dev->fd, c->crtc, + fb_id, 0, 0, &c->id, 1, c->mode); + if (ret) { + drmMsg("failed to set mode: %s\n", strerror(errno)); + goto err; + } + + return 0; + +err: + return ret; +} + +static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev, + unsigned long size, + unsigned int flags) +{ + struct exynos_bo *bo; + + bo = exynos_bo_create(dev, size, flags); + if (!bo) + return bo; + + if (!exynos_bo_map(bo)) { + exynos_bo_destroy(bo); + return NULL; + } + + return bo; +} + +static void exynos_destroy_buffer(struct exynos_bo *bo) +{ + exynos_bo_destroy(bo); +} + +static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst) +{ + struct g2d_context *ctx; + struct g2d_image img; + unsigned int count, img_w, img_h; + int ret = 0; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + memset(&img, 0, sizeof(struct g2d_image)); + img.bo[0] = dst->handle; + + printf("soild fill test.\n"); + + srand(time(NULL)); + img_w = screen_width; + img_h = screen_height; + + for (count = 0; count < 2; count++) { + unsigned int x, y, w, h; + + x = rand() % (img_w / 2); + y = rand() % (img_h / 2); + w = rand() % (img_w - x); + h = rand() % (img_h - y); + + img.width = img_w; + img.height = img_h; + img.stride = img.width * 4; + img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + img.color = 0xff000000 + (random() & 0xffffff); + + ret = g2d_solid_fill(ctx, &img, x, y, w, h); + if (ret < 0) + goto err_fini; + + ret = g2d_exec(ctx); + if (ret < 0) + break; + } + +err_fini: + g2d_fini(ctx); + + return ret; +} + +static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src, + struct exynos_bo *dst, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image src_img, dst_img; + unsigned int count; + unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; + unsigned long userptr, size; + int ret; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + memset(&src_img, 0, sizeof(struct g2d_image)); + memset(&dst_img, 0, sizeof(struct g2d_image)); + dst_img.bo[0] = dst->handle; + + src_x = 0; + src_y = 0; + dst_x = 0; + dst_y = 0; + img_w = screen_width; + img_h = screen_height; + + switch (type) { + case G2D_IMGBUF_GEM: + src_img.bo[0] = src->handle; + break; + case G2D_IMGBUF_USERPTR: + size = img_w * img_h * 4; + + userptr = (unsigned long)malloc(size); + if (!userptr) { + fprintf(stderr, "failed to allocate userptr.\n"); + return -EFAULT; + } + + src_img.user_ptr[0].userptr = userptr; + src_img.user_ptr[0].size = size; + break; + default: + type = G2D_IMGBUF_GEM; + break; + } + + printf("copy test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + src_img.width = img_w; + src_img.height = img_h; + src_img.stride = src_img.width * 4; + src_img.buf_type = type; + src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_img.color = 0xffff0000; + ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); + if (ret < 0) + goto err_free_userptr; + + dst_img.width = img_w; + dst_img.height = img_h; + dst_img.stride = dst_img.width * 4; + dst_img.buf_type = G2D_IMGBUF_GEM; + dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + + ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, + img_w - 4, img_h - 4); + if (ret < 0) + goto err_free_userptr; + + g2d_exec(ctx); + +err_free_userptr: + if (type == G2D_IMGBUF_USERPTR) + if (userptr) + free((void *)userptr); + + g2d_fini(ctx); + + return ret; +} + +static int g2d_copy_with_scale_test(struct exynos_device *dev, + struct exynos_bo *src, + struct exynos_bo *dst, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image src_img, dst_img; + unsigned int count; + unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; + unsigned long userptr, size; + int ret; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + memset(&src_img, 0, sizeof(struct g2d_image)); + memset(&dst_img, 0, sizeof(struct g2d_image)); + dst_img.bo[0] = dst->handle; + + src_x = 0; + src_y = 0; + dst_x = 0; + dst_y = 0; + img_w = screen_width; + img_h = screen_height; + + switch (type) { + case G2D_IMGBUF_GEM: + src_img.bo[0] = src->handle; + break; + case G2D_IMGBUF_USERPTR: + size = img_w * img_h * 4; + + userptr = (unsigned long)malloc(size); + if (!userptr) { + fprintf(stderr, "failed to allocate userptr.\n"); + return -EFAULT; + } + + src_img.user_ptr[0].userptr = userptr; + src_img.user_ptr[0].size = size; + break; + default: + type = G2D_IMGBUF_GEM; + break; + } + + printf("copy and scale test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + src_img.width = img_w; + src_img.height = img_h; + src_img.stride = src_img.width * 4; + src_img.buf_type = type; + src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_img.color = 0xffffffff; + ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w , img_h); + if (ret < 0) + goto err_free_userptr; + + src_img.color = 0xff00ff00; + ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100); + if (ret < 0) + goto err_free_userptr; + + dst_img.width = img_w; + dst_img.height = img_h; + dst_img.buf_type = G2D_IMGBUF_GEM; + dst_img.stride = dst_img.width * 4; + dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + + ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100, + 100, 100, 200, 200, 0); + if (ret < 0) + goto err_free_userptr; + + g2d_exec(ctx); + +err_free_userptr: + if (type == G2D_IMGBUF_USERPTR) + if (userptr) + free((void *)userptr); + + g2d_fini(ctx); + + return 0; +} + +static int g2d_blend_test(struct exynos_device *dev, + struct exynos_bo *src, + struct exynos_bo *dst, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image src_img, dst_img; + unsigned int count; + unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; + unsigned long userptr, size; + int ret; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + memset(&src_img, 0, sizeof(struct g2d_image)); + memset(&dst_img, 0, sizeof(struct g2d_image)); + dst_img.bo[0] = dst->handle; + + src_x = 0; + src_y = 0; + dst_x = 0; + dst_y = 0; + img_w = screen_width; + img_h = screen_height; + + switch (type) { + case G2D_IMGBUF_GEM: + src_img.bo[0] = src->handle; + break; + case G2D_IMGBUF_USERPTR: + size = img_w * img_h * 4; + + userptr = (unsigned long)malloc(size); + if (!userptr) { + fprintf(stderr, "failed to allocate userptr.\n"); + return -EFAULT; + } + + src_img.user_ptr[0].userptr = userptr; + src_img.user_ptr[0].size = size; + break; + default: + type = G2D_IMGBUF_GEM; + break; + } + + printf("blend test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + src_img.width = img_w; + src_img.height = img_h; + src_img.stride = src_img.width * 4; + src_img.buf_type = type; + src_img.select_mode = G2D_SELECT_MODE_NORMAL; + src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_img.color = 0xffffffff; + ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); + if (ret < 0) + goto err_free_userptr; + + src_img.color = 0x770000ff; + ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200); + if (ret < 0) + goto err_free_userptr; + + dst_img.width = img_w; + dst_img.height = img_h; + dst_img.stride = dst_img.width * 4; + dst_img.buf_type = G2D_IMGBUF_GEM; + dst_img.select_mode = G2D_SELECT_MODE_NORMAL; + dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + dst_img.color = 0xffffffff; + ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h); + if (ret < 0) + goto err_free_userptr; + + dst_img.color = 0x77ff0000; + ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200); + if (ret < 0) + goto err_free_userptr; + + ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200, + G2D_OP_OVER); + if (ret < 0) + goto err_free_userptr; + + g2d_exec(ctx); + +err_free_userptr: + if (type == G2D_IMGBUF_USERPTR) + if (userptr) + free((void *)userptr); + + g2d_fini(ctx); + + return 0; +} + +static struct fimg2d_test_case test_case = { + .solid_fill = &g2d_solid_fill_test, + .copy = &g2d_copy_test, + .copy_with_scale = &g2d_copy_with_scale_test, + .blend = &g2d_blend_test, +}; + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-s]\n", name); + fprintf(stderr, "-s <connector_id>@<crtc_id>:<mode>\n"); + exit(0); +} + +extern char *optarg; +static const char optstr[] = "s:"; + +int main(int argc, char **argv) +{ + struct exynos_device *dev; + struct exynos_bo *bo, *src; + struct connector con; + char *modeset = NULL; + unsigned int fb_id; + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + drmModeRes *resources; + int ret, fd, c; + + memset(&con, 0, sizeof(struct connector)); + + if (argc != 3) { + usage(argv[0]); + return -EINVAL; + } + + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 's': + modeset = strdup(optarg); + con.crtc = -1; + if (sscanf(optarg, "%d:0x%64s", + &con.id, + con.mode_str) != 2 && + sscanf(optarg, "%d@%d:%64s", + &con.id, + &con.crtc, + con.mode_str) != 3) + usage(argv[0]); + break; + default: + usage(argv[0]); + return -EINVAL; + } + } + + fd = drmOpen(DRM_MODULE_NAME, NULL); + if (fd < 0) { + fprintf(stderr, "failed to open.\n"); + return fd; + } + + dev = exynos_device_create(fd); + if (!dev) { + drmClose(dev->fd); + return -EFAULT; + } + + resources = drmModeGetResources(dev->fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + ret = -EFAULT; + goto err_drm_close; + } + + connector_find_mode(dev->fd, &con, resources); + drmModeFreeResources(resources); + + screen_width = con.mode->hdisplay; + screen_height = con.mode->vdisplay; + + printf("screen width = %d, screen height = %d\n", screen_width, + screen_height); + + bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); + if (!bo) { + ret = -EFAULT; + goto err_drm_close; + } + + handles[0] = bo->handle; + pitches[0] = screen_width * 4; + offsets[0] = 0; + + ret = drmModeAddFB2(dev->fd, screen_width, screen_height, + DRM_FORMAT_RGBA8888, handles, + pitches, offsets, &fb_id, 0); + if (ret < 0) + goto err_destroy_buffer; + + con.plane_zpos = -1; + + memset(bo->vaddr, 0xff, screen_width * screen_height * 4); + + ret = drm_set_crtc(dev, &con, fb_id); + if (ret < 0) + goto err_rm_fb; + + ret = test_case.solid_fill(dev, bo); + if (ret < 0) { + fprintf(stderr, "failed to solid fill operation.\n"); + goto err_rm_fb; + } + + getchar(); + + src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); + if (!src) { + ret = -EFAULT; + goto err_rm_fb; + } + + ret = test_case.copy(dev, src, bo, G2D_IMGBUF_GEM); + if (ret < 0) { + fprintf(stderr, "failed to test copy operation.\n"); + goto err_free_src; + } + + getchar(); + + ret = test_case.copy_with_scale(dev, src, bo, G2D_IMGBUF_GEM); + if (ret < 0) { + fprintf(stderr, "failed to test copy and scale operation.\n"); + goto err_free_src; + } + + getchar(); + + ret = test_case.blend(dev, src, bo, G2D_IMGBUF_USERPTR); + if (ret < 0) + fprintf(stderr, "failed to test blend operation.\n"); + + getchar(); + +err_free_src: + if (src) + exynos_destroy_buffer(src); + +err_rm_fb: + drmModeRmFB(fb_id, bo->handle); + +err_destroy_buffer: + exynos_destroy_buffer(bo); + +err_drm_close: + drmClose(dev->fd); + exynos_device_destroy(dev); + + return 0; +} |