diff options
-rw-r--r-- | exynos/exynos_drm.h | 7 | ||||
-rw-r--r-- | tests/ipptest/fimc.c | 824 | ||||
-rw-r--r-- | tests/ipptest/fimc.h | 7 | ||||
-rw-r--r-- | tests/ipptest/fimctest.c | 65 | ||||
-rw-r--r-- | tests/ipptest/fimctest.h | 79 | ||||
-rw-r--r-- | tests/ipptest/gem.c | 34 | ||||
-rw-r--r-- | tests/ipptest/gem.h | 5 | ||||
-rw-r--r-- | tests/ipptest/util.c | 299 | ||||
-rw-r--r-- | tests/ipptest/util.h | 26 |
9 files changed, 1176 insertions, 170 deletions
diff --git a/exynos/exynos_drm.h b/exynos/exynos_drm.h index f403a672..d21a8324 100644 --- a/exynos/exynos_drm.h +++ b/exynos/exynos_drm.h @@ -312,6 +312,13 @@ enum drm_exynos_ipp_cmd { IPP_CMD_MAX, }; +/* define of M2M command */ +enum drm_exynos_ipp_cmd_m2m { + IPP_CMD_M2M_FILE, + IPP_CMD_M2M_DISPLAY, + IPP_CMD_M2M_NONE, +}; + /* define of color range */ enum drm_exynos_color_range { COLOR_RANGE_LIMITED, /* Narrow: Y(16 to 235), Cb/Cr(16 to 240) */ diff --git a/tests/ipptest/fimc.c b/tests/ipptest/fimc.c index 2eac01f6..9e809280 100644 --- a/tests/ipptest/fimc.c +++ b/tests/ipptest/fimc.c @@ -41,11 +41,384 @@ #include "util.h" #include "drm_fourcc.h" +#include "drm_mode.h" +#include "libkms.h" +#include "internal.h" + +void free_resources(struct resources *res) +{ + if (!res) + return; + +#define free_resource(_res, __res, type, Type) \ + do { \ + int i; \ + if (!(_res)->type##s) \ + break; \ + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ + if (!(_res)->type##s[i].type) \ + break; \ + drmModeFree##Type((_res)->type##s[i].type); \ + } \ + free((_res)->type##s); \ + } while (0) + +#define free_properties(_res, __res, type) \ + do { \ + int i; \ + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ + drmModeFreeObjectProperties(res->type##s[i].props); \ + free(res->type##s[i].props_info); \ + } \ + } while (0) + + if (res->res) { + free_properties(res, res, crtc); + + free_resource(res, res, crtc, Crtc); + free_resource(res, res, encoder, Encoder); + free_resource(res, res, connector, Connector); + free_resource(res, res, fb, FB); + + drmModeFreeResources(res->res); + } + + if (res->plane_res) { + free_properties(res, plane_res, plane); + + free_resource(res, plane_res, plane, Plane); + + drmModeFreePlaneResources(res->plane_res); + } + + free(res); +} + +struct resources *get_resources(struct device *dev) +{ + struct resources *res; + int i; + + res = malloc(sizeof *res); + if (res == 0) + return NULL; + + memset(res, 0, sizeof *res); + + res->res = drmModeGetResources(dev->fd); + if (!res->res) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + goto error; + } + + res->crtcs = malloc(res->res->count_crtcs * sizeof *res->crtcs); + res->encoders = malloc(res->res->count_encoders * sizeof *res->encoders); + res->connectors = malloc(res->res->count_connectors * sizeof *res->connectors); + res->fbs = malloc(res->res->count_fbs * sizeof *res->fbs); + + if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) + goto error; + + memset(res->crtcs , 0, res->res->count_crtcs * sizeof *res->crtcs); + memset(res->encoders, 0, res->res->count_encoders * sizeof *res->encoders); + memset(res->connectors, 0, res->res->count_connectors * sizeof *res->connectors); + memset(res->fbs, 0, res->res->count_fbs * sizeof *res->fbs); + +#define get_resource(_res, __res, type, Type) \ + do { \ + int i; \ + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ + (_res)->type##s[i].type = \ + drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \ + if (!(_res)->type##s[i].type) \ + fprintf(stderr, "could not get %s %i: %s\n", \ + #type, (_res)->__res->type##s[i], \ + strerror(errno)); \ + } \ + } while (0) + + get_resource(res, res, crtc, Crtc); + get_resource(res, res, encoder, Encoder); + get_resource(res, res, connector, Connector); + get_resource(res, res, fb, FB); + +#define get_properties(_res, __res, type, Type) \ + do { \ + int i; \ + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ + struct type *obj = &res->type##s[i]; \ + unsigned int j; \ + obj->props = \ + drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ + DRM_MODE_OBJECT_##Type); \ + if (!obj->props) { \ + fprintf(stderr, \ + "could not get %s %i properties: %s\n", \ + #type, obj->type->type##_id, \ + strerror(errno)); \ + continue; \ + } \ + obj->props_info = malloc(obj->props->count_props * \ + sizeof *obj->props_info); \ + if (!obj->props_info) \ + continue; \ + for (j = 0; j < obj->props->count_props; ++j) \ + obj->props_info[j] = \ + drmModeGetProperty(dev->fd, obj->props->props[j]); \ + } \ + } while (0) + + get_properties(res, res, crtc, CRTC); + + /** + * This code is needed because drm_connector function. + * It's replace below code. + * get_properties(res, res, drm_connector, CONNECTOR); + */ + for (i = 0; i < (int)res->res->count_connectors; ++i) { + struct drm_connector *obj = &res->connectors[i]; + unsigned int j; + obj->props = drmModeObjectGetProperties(dev->fd, + obj->connector->connector_id, + DRM_MODE_OBJECT_CONNECTOR); + + if (!obj->props) { + fprintf(stderr, "could not get %s %u properties: %s\n", + "drm_connector", obj->connector->connector_id, + strerror(errno)); + continue; + } + printf("could not get %s %u properties: %s\n", + "drm_connector", obj->connector->connector_id, + strerror(errno)); + + obj->props_info = malloc(obj->props->count_props * + sizeof(*obj->props_info)); + if (!obj->props_info) + continue; + + for (j = 0; j < obj->props->count_props; ++j) + obj->props_info[j] = + drmModeGetProperty(dev->fd, obj->props->props[j]); + } + + for (i = 0; i < res->res->count_crtcs; ++i) + res->crtcs[i].mode = &res->crtcs[i].crtc->mode; + + res->plane_res = drmModeGetPlaneResources(dev->fd); + if (!res->plane_res) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return res; + } + + res->planes = malloc(res->plane_res->count_planes * sizeof *res->planes); + if (!res->planes) + goto error; + + memset(res->planes, 0, res->plane_res->count_planes * sizeof *res->planes); + + get_resource(res, plane_res, plane, Plane); + get_properties(res, plane_res, plane, PLANE); + + return res; + +error: + free_resources(res); + return NULL; +} + +static int get_crtc_index(struct device *dev, uint32_t id) +{ + int i; + + for (i = 0; i < dev->resources->res->count_crtcs; ++i) { + drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; + if (crtc && crtc->crtc_id == id) + return i; + } + + return -1; +} + +static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) +{ + drmModeConnector *connector; + int i; + + for (i = 0; i < dev->resources->res->count_connectors; i++) { + connector = dev->resources->connectors[i].connector; + if (connector && connector->connector_id == id) + return connector; + } + + return NULL; +} + +static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) +{ + drmModeEncoder *encoder; + int i; + + for (i = 0; i < dev->resources->res->count_encoders; i++) { + encoder = dev->resources->encoders[i].encoder; + if (encoder && encoder->encoder_id == id) + return encoder; + } + + return NULL; +} + +static drmModeModeInfo * +connector_find_mode_output(struct device *dev, uint32_t con_id, + const char *mode_str, const unsigned int vrefresh) +{ + drmModeConnector *connector; + drmModeModeInfo *mode; + int i; + + connector = get_connector_by_id(dev, con_id); + if (!connector || !connector->count_modes) + return NULL; + + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + if (!strcmp(mode->name, mode_str)) { + /* If the vertical refresh frequency is not specified + * then return the first mode that match with the name. + * Else, return the mode that match the name and + * the specified vertical refresh frequency. + */ + if (vrefresh == 0) + return mode; + else if (mode->vrefresh == vrefresh) + return mode; + } + } + + return NULL; +} + +struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) +{ + uint32_t possible_crtcs = ~0; + uint32_t active_crtcs = 0; + unsigned int crtc_idx; + unsigned int i; + int j; + + for (i = 0; i < pipe->num_cons; ++i) { + uint32_t crtcs_for_connector = 0; + drmModeConnector *connector; + drmModeEncoder *encoder; + int idx; + + connector = get_connector_by_id(dev, pipe->con_ids[i]); + if (!connector) + return NULL; + + for (j = 0; j < connector->count_encoders; ++j) { + encoder = get_encoder_by_id(dev, connector->encoders[j]); + if (!encoder) + continue; + + crtcs_for_connector |= encoder->possible_crtcs; + + idx = get_crtc_index(dev, encoder->crtc_id); + if (idx >= 0) + active_crtcs |= 1 << idx; + } + + possible_crtcs &= crtcs_for_connector; + } + + if (!possible_crtcs) + return NULL; + + /* Return the first possible and active CRTC if one exists, or the first + * possible CRTC otherwise. + */ + if (possible_crtcs & active_crtcs) + crtc_idx = ffs(possible_crtcs & active_crtcs); + else + crtc_idx = ffs(possible_crtcs); + + return &dev->resources->crtcs[crtc_idx - 1]; +} + +static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe, + struct connector *c) +{ + drmModeModeInfo *mode = NULL; + int i; + + /* init pipe_arg and parse connector by khg */ + pipe->vrefresh = 0; + pipe->crtc_id = (uint32_t)-1; + strcpy(pipe->format_str, "XR24"); + + /* Count the number of connectors and allocate them. */ + pipe->num_cons = 1; + pipe->con_ids = malloc(pipe->num_cons * sizeof(*pipe->con_ids)); + if (!pipe->con_ids) + return -1; + + pipe->con_ids[0] = c->id; + pipe->crtc_id = c->crtc; + + strcpy(pipe->mode_str, c->mode_str); + pipe->fourcc = format_fourcc(pipe->format_str); + if (!pipe->fourcc) { + fprintf(stderr, "unknown format %s\n", pipe->format_str); + return -1; + } + + pipe->mode = NULL; + + for (i = 0; i < (int)pipe->num_cons; i++) { + mode = connector_find_mode_output(dev, pipe->con_ids[i], + pipe->mode_str, pipe->vrefresh); + if (mode == NULL) { + fprintf(stderr, + "failed to find mode \"%s\" for connector %u\n", + pipe->mode_str, pipe->con_ids[i]); + return -EINVAL; + } + } + + /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise + * locate a CRTC that can be attached to all the connectors. + */ + if (pipe->crtc_id != (uint32_t)-1) { + for (i = 0; i < dev->resources->res->count_crtcs; i++) { + struct crtc *crtc = &dev->resources->crtcs[i]; + + if (pipe->crtc_id == crtc->crtc->crtc_id) { + pipe->crtc = crtc; + break; + } + } + } else { + pipe->crtc = pipe_find_crtc(dev, pipe); + } + + if (!pipe->crtc) { + fprintf(stderr, "failed to find CRTC for pipe\n"); + return -EINVAL; + } + + pipe->mode = mode; + pipe->crtc->mode = mode; + + return 0; +} static int exynos_drm_ipp_set_property(int fd, struct drm_exynos_ipp_property *property, struct drm_exynos_sz *def_sz, enum drm_exynos_ipp_cmd cmd, + enum drm_exynos_ipp_cmd_m2m cmd_m2m, enum drm_exynos_degree degree) { struct drm_exynos_pos crop_pos = {0, 0, def_sz->hsize, def_sz->vsize}; @@ -62,7 +435,12 @@ static int exynos_drm_ipp_set_property(int fd, property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC; property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE; property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0; - property->config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_XRGB8888; + if (cmd_m2m == IPP_CMD_M2M_FILE) + property->config[EXYNOS_DRM_OPS_SRC].fmt = + DRM_FORMAT_XRGB8888; + else + property->config[EXYNOS_DRM_OPS_SRC].fmt = + DRM_FORMAT_YUV422; property->config[EXYNOS_DRM_OPS_SRC].pos = crop_pos; property->config[EXYNOS_DRM_OPS_SRC].sz = src_sz; @@ -134,7 +512,9 @@ static int exynos_drm_ipp_queue_buf(int fd, struct drm_exynos_ipp_queue_buf *qbu enum drm_exynos_ipp_buf_type buf_type, int prop_id, int buf_id, - unsigned int gem_handle) + unsigned int gem_handle_y, + unsigned int gem_handle_u, + unsigned int gem_handle_v) { int ret = 0; @@ -145,16 +525,16 @@ static int exynos_drm_ipp_queue_buf(int fd, struct drm_exynos_ipp_queue_buf *qbu qbuf->user_data = 0; qbuf->prop_id = prop_id; qbuf->buf_id = buf_id; - qbuf->handle[EXYNOS_DRM_PLANAR_Y] = gem_handle; - qbuf->handle[EXYNOS_DRM_PLANAR_CB] = 0; - qbuf->handle[EXYNOS_DRM_PLANAR_CR] = 0; + qbuf->handle[EXYNOS_DRM_PLANAR_Y] = gem_handle_y; + qbuf->handle[EXYNOS_DRM_PLANAR_CB] = gem_handle_u; + qbuf->handle[EXYNOS_DRM_PLANAR_CR] = gem_handle_v; ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, qbuf); if (ret) fprintf(stderr, "failed to DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF[id:%d][buf_type:%d] : %s\n", ops_id, buf_type, strerror(errno)); - + return ret; } @@ -178,10 +558,13 @@ static int exynos_drm_ipp_cmd_ctrl(int fd, struct drm_exynos_ipp_cmd_ctrl *cmd_c return ret; } -int fimc_event_handler(struct drm_exynos_ipp_queue_buf *src_qbuf, struct drm_exynos_gem_create *src_gem, - struct drm_exynos_ipp_queue_buf *dst_qbuf, struct drm_exynos_gem_create *dst_gem, +int fimc_event_handler(struct drm_exynos_ipp_queue_buf *src_qbuf, + struct drm_exynos_gem_create *src_gem, + struct drm_exynos_ipp_queue_buf *dst_qbuf, + struct drm_exynos_gem_create *dst_gem, struct drm_exynos_ipp_property *property, void **usr_addr, - unsigned int width, unsigned int height, enum drm_exynos_ipp_cmd cmd) + unsigned int width, unsigned int height, enum drm_exynos_ipp_cmd cmd, + enum drm_exynos_ipp_cmd_m2m cmd_m2m) { char buffer[1024]; int len, i; @@ -209,14 +592,25 @@ int fimc_event_handler(struct drm_exynos_ipp_queue_buf *src_qbuf, struct drm_exy printf("%s:src_buf_id[%d]dst_buf_id[%d]bmp_idx[%d]\n", __func__, src_buf_id, dst_buf_id, bmp_idx++); if (cmd == IPP_CMD_M2M) { - sprintf(filename, RESULT_PATH "fimc_m2m_dst%d.bmp", bmp_idx); - - util_write_bmp(filename, usr_addr[dst_buf_id], width, height); - - /* For source buffer queue to IPP */ - ret = exynos_drm_ipp_queue_buf(fd, &src_qbuf[src_buf_id], EXYNOS_DRM_OPS_SRC, + if (cmd_m2m == IPP_CMD_M2M_DISPLAY) { + ret = exynos_drm_ipp_queue_buf( + fd, &src_qbuf[src_buf_id], + EXYNOS_DRM_OPS_SRC, + IPP_BUF_ENQUEUE, + property->prop_id, + src_buf_id, + src_gem[src_buf_id].handle, + src_gem[src_buf_id + 1].handle, + src_gem[src_buf_id + 2].handle); + } else { + sprintf(filename, RESULT_PATH "fimc_m2m_dst%d.bmp", bmp_idx); + util_write_bmp(filename, usr_addr[dst_buf_id], width, height); + + /* For source buffer queue to IPP */ + ret = exynos_drm_ipp_queue_buf(fd, &src_qbuf[src_buf_id], EXYNOS_DRM_OPS_SRC, IPP_BUF_ENQUEUE, property->prop_id, - src_buf_id, src_gem[src_buf_id].handle); + src_buf_id, src_gem[src_buf_id].handle, 0, 0); + } if (ret) { fprintf(stderr, "failed to ipp buf src queue\n"); goto err_ipp_ctrl_close; @@ -225,20 +619,19 @@ int fimc_event_handler(struct drm_exynos_ipp_queue_buf *src_qbuf, struct drm_exy /* For destination buffer queue to IPP */ ret = exynos_drm_ipp_queue_buf(fd, &dst_qbuf[dst_buf_id], EXYNOS_DRM_OPS_DST, IPP_BUF_ENQUEUE, property->prop_id, - dst_buf_id, dst_gem[dst_buf_id].handle); + dst_buf_id, dst_gem[dst_buf_id].handle, 0, 0); if (ret) { fprintf(stderr, "failed to ipp buf dst queue\n"); goto err_ipp_ctrl_close; } } else if (cmd == IPP_CMD_WB) { sprintf(filename, RESULT_PATH "fimc_wb_%d.bmp", bmp_idx); - util_write_bmp(filename, usr_addr[dst_buf_id], width, height); /* For destination buffer queue to IPP */ ret = exynos_drm_ipp_queue_buf(fd, &dst_qbuf[dst_buf_id], EXYNOS_DRM_OPS_DST, IPP_BUF_ENQUEUE, property->prop_id, - dst_buf_id, dst_gem[dst_buf_id].handle); + dst_buf_id, dst_gem[dst_buf_id].handle, 0, 0); if (ret) { fprintf(stderr, "failed to ipp buf dst queue\n"); goto err_ipp_ctrl_close; @@ -255,179 +648,299 @@ err_ipp_ctrl_close: return ret; } -void fimc_m2m_set_mode(struct connector *c, int count, int page_flip, - long int *usec) +void fimc_m2m_set_mode(struct device *dev, struct connector *c, int count, + enum drm_exynos_degree degree, enum drm_exynos_ipp_cmd_m2m display, + long int *usec) { struct drm_exynos_ipp_property property; struct drm_exynos_ipp_cmd_ctrl cmd_ctrl; - struct drm_exynos_sz def_sz = {720, 1280}; + struct drm_exynos_sz def_sz; struct drm_exynos_ipp_queue_buf qbuf1[MAX_BUF], qbuf2[MAX_BUF]; - unsigned int width=720, height=1280, stride; - int ret, i, j, x; struct drm_exynos_gem_create gem1[MAX_BUF], gem2[MAX_BUF]; struct exynos_gem_mmap_data mmap1[MAX_BUF], mmap2[MAX_BUF]; void *usr_addr1[MAX_BUF], *usr_addr2[MAX_BUF]; - struct timeval begin, end; struct drm_gem_close args; - char filename[100]; + uint32_t handles[4], pitches[4], offsets[4] = {0}; + unsigned int fb_id_dst; + struct kms_bo *bo_src[MAX_BUF], *bo_dst; + struct pipe_arg pipe; + int ret, i, j; - /* For mode */ - width = height = 0; + struct timeval begin, end; + char filename[80]; + + dev->mode.width = 0; + dev->mode.height = 0; + + /* For crtc and mode */ for (i = 0; i < count; i++) { - connector_find_mode(&c[i]); - if (c[i].mode == NULL) continue; - width += c[i].mode->hdisplay; - if (height < c[i].mode->vdisplay) height = c[i].mode->vdisplay; + ret = pipe_find_crtc_and_mode(dev, &pipe, &c[i]); + if (ret < 0) + continue; + + dev->mode.width += pipe.mode->hdisplay; + if (dev->mode.height < pipe.mode->vdisplay) + dev->mode.height = pipe.mode->vdisplay; } - stride = width * 4; - i =0; - def_sz.hsize = width; - def_sz.vsize = height; + /* For source buffer */ + for (i = 0; i < MAX_BUF; i++) { + bo_src[i] = util_kms_gem_create_mmap(dev->kms, pipe.fourcc, + dev->mode.width, dev->mode.height, + handles, pitches, offsets); + if (!bo_src[i]) + goto err_ipp_src_buff_close; + + mmap1[i].size = gem1[i].size = bo_src[i]->size; + mmap1[i].offset = gem1[i].flags = 0; + mmap1[i].handle = gem1[i].handle = bo_src[i]->handle; + usr_addr1[i] = mmap1[i].addr = bo_src[i]->ptr; + } + + /* Create test Image + * Display is YUV422 format, file is RGB888 format + */ + if (display == IPP_CMD_M2M_DISPLAY) + util_draw_buffer_yuv(usr_addr1, + dev->mode.width, dev->mode.height); + else + util_draw_buffer(usr_addr1[0], 1, dev->mode.width, + dev->mode.height, dev->mode.width * 4, 0); + + /*For destination buffer */ + bo_dst = util_kms_gem_create_mmap(dev->kms, pipe.fourcc, + dev->mode.width, dev->mode.height, + handles, pitches, offsets); + if (!bo_dst) + goto err_ipp_src_buff_close; + + mmap2[0].size = gem2[0].size = bo_dst->size; + mmap2[0].offset = gem2[0].flags = 0; + mmap2[0].handle = gem2[0].handle = bo_dst->handle; + usr_addr2[0] = mmap2[0].addr = bo_dst->ptr; + + def_sz.hsize = dev->mode.width; + def_sz.vsize = dev->mode.height; /* For property */ - ret = exynos_drm_ipp_set_property(fd, &property, &def_sz, IPP_CMD_M2M, EXYNOS_DRM_DEGREE_90); + if (display == IPP_CMD_M2M_DISPLAY) + ret = exynos_drm_ipp_set_property(dev->fd, &property, + &def_sz, IPP_CMD_M2M, IPP_CMD_M2M_DISPLAY, + EXYNOS_DRM_DEGREE_0); + else + ret = exynos_drm_ipp_set_property(dev->fd, &property, + &def_sz, IPP_CMD_M2M, IPP_CMD_M2M_FILE, degree); if (ret) { fprintf(stderr, "failed to ipp property\n"); - return; + goto err_ipp_dst_buff_close; } - for (i = 0; i < MAX_BUF; i++) { - /* For source buffer */ - ret = util_gem_create_mmap(fd, &gem1[i], &mmap1[i], stride * height); - if (ret) { - fprintf(stderr, "failed to gem create mmap: %s\n", - strerror(errno)); - - if (ret == -1) - return; - else if (ret == -2) - goto err_ipp_ctrl_close; - } - usr_addr1[i] = mmap1[i].addr; - - /* For source buffer map to IPP */ - ret = exynos_drm_ipp_queue_buf(fd, &qbuf1[i], EXYNOS_DRM_OPS_SRC, - IPP_BUF_ENQUEUE, property.prop_id, i, gem1[i].handle); - if (ret) { - fprintf(stderr, "failed to ipp buf src map\n"); - goto err_ipp_ctrl_close; - } - - util_draw_buffer(usr_addr1[i], 1, width, height, stride, 0); - sprintf(filename, RESULT_PATH "fimc_m2m_org_src%d.bmp", j); - util_write_bmp(filename, usr_addr1[i], width, height); + /* For source buffer map to IPP */ + if (display == IPP_CMD_M2M_DISPLAY) + ret = exynos_drm_ipp_queue_buf(dev->fd, &qbuf1[0], + EXYNOS_DRM_OPS_SRC, IPP_BUF_ENQUEUE, + property.prop_id, 0, gem1[0].handle, + gem1[1].handle, gem1[2].handle); + else + ret = exynos_drm_ipp_queue_buf(dev->fd, &qbuf1[0], + EXYNOS_DRM_OPS_SRC, IPP_BUF_ENQUEUE, + property.prop_id, 0, gem1[0].handle, 0, 0); + if (ret) { + fprintf(stderr, "failed to ipp buf src map\n"); + goto err_ipp_quque_close; } - for (i = 0; i < MAX_BUF; i++) { - /* For destination buffer */ - ret = util_gem_create_mmap(fd, &gem2[i], &mmap2[i], stride * height); - if (ret) { - fprintf(stderr, "failed to gem create mmap: %s\n", - strerror(errno)); - if (ret == -1) - goto err_ipp_ctrl_close; - else if (ret == -2) - goto err_ipp_ctrl_close; - } - usr_addr2[i] = mmap2[i].addr; - - /* For destination buffer map to IPP */ - ret = exynos_drm_ipp_queue_buf(fd, &qbuf2[i], EXYNOS_DRM_OPS_DST, - IPP_BUF_ENQUEUE, property.prop_id, i, gem2[i].handle); - if (ret) { - fprintf(stderr, "failed to ipp buf dst map\n"); - goto err_ipp_ctrl_close; - } - - util_draw_buffer(usr_addr2[i], 0, 0, 0, 0, mmap2[i].size); - sprintf(filename, RESULT_PATH "fimc_m2m_org_dst%d.bmp", j); - util_write_bmp(filename, usr_addr2[i], height, width); + /* For destination buffer map to IPP */ + ret = exynos_drm_ipp_queue_buf(dev->fd, &qbuf2[0], + EXYNOS_DRM_OPS_DST, IPP_BUF_ENQUEUE, + property.prop_id, 0, gem2[0].handle, 0, 0); + if (ret) { + fprintf(stderr, "failed to ipp buf dst map\n"); + goto err_ipp_quque_close; } /* Start */ - gettimeofday(&begin, NULL); - ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_PLAY); + ret = exynos_drm_ipp_cmd_ctrl(dev->fd, &cmd_ctrl, + property.prop_id, IPP_CTRL_PLAY); if (ret) { fprintf(stderr, - "failed to ipp ctrl IPP_CMD_M2M start\n"); - goto err_ipp_ctrl_close; + "failed to ipp ctrl IPP_CMD_M2M start\n"); + goto err_ipp_quque_close; } - - j=0; - while (1) { - struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; - fd_set fds; + gettimeofday(&begin, NULL); - FD_ZERO(&fds); - FD_SET(0, &fds); - FD_SET(fd, &fds); - ret = select(fd + 1, &fds, NULL, NULL, &timeout); - if (ret <= 0) { - fprintf(stderr, "select timed out or error.\n"); - continue; - } else if (FD_ISSET(0, &fds)) { - break; + /* Display OR File */ + switch (display) { + case IPP_CMD_M2M_FILE: + /* For src image write file */ + sprintf(filename, RESULT_PATH "fimc_m2m_org_src.bmp"); + util_write_bmp(filename, usr_addr1[0], + dev->mode.width, dev->mode.height); + + j = 0; + while (1) { + struct timeval timeout = {.tv_sec = 3, .tv_usec = 0}; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(dev->fd, &fds); + ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); + if (ret <= 0) { + fprintf(stderr, "select timed out or error.\n"); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } + + gettimeofday(&end, NULL); + usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 + + (end.tv_usec - begin.tv_usec); + + if (property.config[EXYNOS_DRM_OPS_DST].degree == + EXYNOS_DRM_DEGREE_90 || + property.config[EXYNOS_DRM_OPS_DST].degree == + EXYNOS_DRM_DEGREE_270) { + if(fimc_event_handler(qbuf1, gem1, qbuf2, gem2, + &property, usr_addr2, dev->mode.height, + dev->mode.width, IPP_CMD_M2M, + IPP_CMD_M2M_FILE) < 0) + break; + } else { + if(fimc_event_handler(qbuf1, gem1, qbuf2, gem2, + &property, usr_addr2, dev->mode.width, + dev->mode.height, IPP_CMD_M2M, + IPP_CMD_M2M_FILE) < 0) + break; + } + + if (++j > MAX_LOOP) + break; + + gettimeofday(&begin, NULL); + } + break; + case IPP_CMD_M2M_DISPLAY: + /* Add fb2 dst */ + ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, + pipe.fourcc, handles, pitches, + offsets, &fb_id_dst, 0); + if (ret) { + fprintf(stderr, "failed to add fb (%ux%u):%s\n", + dev->mode.width, dev->mode.height, + strerror(errno)); + goto err_ipp_quque_close; } - gettimeofday(&end, NULL); - usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 + - (end.tv_usec - begin.tv_usec); + j = 0; + while (1) { + struct timeval timeout = {.tv_sec = 3, .tv_usec = 0}; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(dev->fd, &fds); + ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); + if (ret <= 0) { + fprintf(stderr, "select timed out or error.\n"); + continue; + } else if (FD_ISSET(0, &fds)) { + goto err_ipp_quque_close; + } - if (property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90 || - property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_270) { - if(fimc_event_handler(qbuf1, gem1, qbuf2, gem2, &property, usr_addr2, height, width, IPP_CMD_M2M) < 0) + /* Set Flip */ + ret = drmModePageFlip(dev->fd, pipe.crtc->crtc->crtc_id, + fb_id_dst, DRM_MODE_PAGE_FLIP_EVENT, + &pipe); + if (ret) { + fprintf(stderr, "failed to page flip: %s\n", + strerror(errno)); + goto err_ipp_quque_close; + } + + gettimeofday(&end, NULL); + usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 + + (end.tv_usec - begin.tv_usec); + + getchar(); + + /* For property */ + if (j == 0) { + ret = exynos_drm_ipp_set_property(dev->fd, &property, + &def_sz, IPP_CMD_M2M, IPP_CMD_M2M_DISPLAY, + degree); + } else { + ret = exynos_drm_ipp_set_property(dev->fd, &property, + &def_sz, IPP_CMD_M2M, IPP_CMD_M2M_DISPLAY, + EXYNOS_DRM_DEGREE_0); + } + if (ret) { + fprintf(stderr, "failed to ipp property\n"); break; - } else { - if(fimc_event_handler(qbuf1, gem1, qbuf2, gem2, &property, usr_addr2, width, height, IPP_CMD_M2M) < 0) + } + + if(fimc_event_handler(qbuf1, gem1, qbuf2, gem2, + &property, usr_addr2, dev->mode.width, + dev->mode.height, IPP_CMD_M2M, + IPP_CMD_M2M_DISPLAY) < 0) break; - } - if (++j > MAX_LOOP) - break; + /* Start */ + ret = exynos_drm_ipp_cmd_ctrl(dev->fd, &cmd_ctrl, + property.prop_id, IPP_CTRL_PLAY); + if (ret) { + fprintf(stderr, + "failed to ipp ctrl IPP_CMD_M2M start\n"); + break; + } - gettimeofday(&begin, NULL); + if (++j > 1) + break; + + gettimeofday(&begin, NULL); + } + break; } -err_ipp_ctrl_close: - /* For source buffer dequeue to IPP */ - for (i = 0; i < MAX_BUF; i++) { - ret = exynos_drm_ipp_queue_buf(fd, &qbuf1[i], EXYNOS_DRM_OPS_SRC, - IPP_BUF_DEQUEUE, property.prop_id, i, gem1[i].handle); +err_ipp_quque_close: + for (i = 1; i <= property.prop_id; i++) { + /* For destination buffer dequeue to IPP */ + ret = exynos_drm_ipp_queue_buf(dev->fd, &qbuf2[0], + EXYNOS_DRM_OPS_DST, IPP_BUF_DEQUEUE, + i, 0, gem2[0].handle, 0, 0); if (ret < 0) fprintf(stderr, "failed to ipp buf dst dequeue\n"); - } - /* For destination buffer dequeue to IPP */ - for (i = 0; i < MAX_BUF; i++) { - ret = exynos_drm_ipp_queue_buf(fd, &qbuf2[i], EXYNOS_DRM_OPS_DST, - IPP_BUF_DEQUEUE, property.prop_id, i, gem2[i].handle); + /* For source buffer dequeue to IPP */ + ret = exynos_drm_ipp_queue_buf(dev->fd, &qbuf1[0], + EXYNOS_DRM_OPS_SRC, IPP_BUF_DEQUEUE, i, 0, + gem1[0].handle, gem1[1].handle, gem1[2].handle); if (ret < 0) fprintf(stderr, "failed to ipp buf dst dequeue\n"); - } - - /* Stop */ - ret = exynos_drm_ipp_cmd_ctrl(fd, &cmd_ctrl, property.prop_id, IPP_CTRL_STOP); - if (ret) - fprintf(stderr, "failed to ipp ctrl IPP_CMD_WB stop\n"); + /* Stop */ + ret = exynos_drm_ipp_cmd_ctrl(dev->fd, &cmd_ctrl, + i, IPP_CTRL_STOP); + if (ret) + fprintf(stderr, + "failed to ipp ctrl IPP_CMD_M2M stop\n"); + } +err_ipp_dst_buff_close: + /* Close destination buffer */ + munmap(usr_addr2[0], mmap2[0].size); + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem2[0].handle; + exynos_gem_close(dev->fd, &args); + kms_bo_destroy(&bo_dst); +err_ipp_src_buff_close: /* Close source buffer */ for (i = 0; i < MAX_BUF; i++) { munmap(usr_addr1[i], mmap1[i].size); - memset(&args, 0x00, sizeof(struct drm_gem_close)); + memset(&args, 0, sizeof(struct drm_gem_close)); args.handle = gem1[i].handle; - exynos_gem_close(fd, &args); - } - - /* Close destination buffer */ - for (i = 0; i < MAX_BUF; i++) { - munmap(usr_addr2[i], mmap2[i].size); - memset(&args, 0x00, sizeof(struct drm_gem_close)); - args.handle = gem2[i].handle; - exynos_gem_close(fd, &args); + exynos_gem_close(dev->fd, &args); + kms_bo_destroy(&bo_src[i]); } - - return; } void fimc_wb_set_mode(struct connector *c, int count, int page_flip, @@ -460,7 +973,9 @@ void fimc_wb_set_mode(struct connector *c, int count, int page_flip, def_sz.vsize = height; /* For property */ - ret = exynos_drm_ipp_set_property(fd, &property, &def_sz, IPP_CMD_WB, EXYNOS_DRM_DEGREE_0); + ret = exynos_drm_ipp_set_property(fd, &property, &def_sz, + IPP_CMD_WB, IPP_CMD_M2M_NONE, EXYNOS_DRM_DEGREE_0); + printf("property: %d\n", ret); if (ret) { fprintf(stderr, "failed to ipp property\n"); return; @@ -478,7 +993,8 @@ void fimc_wb_set_mode(struct connector *c, int count, int page_flip, usr_addr[i] = mmap[i].addr; /* For destination buffer map to IPP */ ret = exynos_drm_ipp_queue_buf(fd, &qbuf[i], EXYNOS_DRM_OPS_DST, - IPP_BUF_ENQUEUE, property.prop_id, i, gem[i].handle); + IPP_BUF_ENQUEUE, property.prop_id, i, + gem[i].handle, 0, 0); if (ret) { fprintf(stderr, "failed to ipp buf dst map\n"); goto err_ipp_ctrl_close; @@ -519,10 +1035,10 @@ void fimc_wb_set_mode(struct connector *c, int count, int page_flip, property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_270 || property.config[EXYNOS_DRM_OPS_SRC].degree == EXYNOS_DRM_DEGREE_90 || property.config[EXYNOS_DRM_OPS_SRC].degree == EXYNOS_DRM_DEGREE_270) { - if(fimc_event_handler(NULL, NULL, qbuf, gem, &property, usr_addr, height, width, IPP_CMD_WB) < 0) + if(fimc_event_handler(NULL, NULL, qbuf, gem, &property, usr_addr, height, width, IPP_CMD_WB, IPP_CMD_M2M_NONE) < 0) break; } else { - if(fimc_event_handler(NULL, NULL, qbuf, gem, &property, usr_addr, width, height, IPP_CMD_WB) < 0) + if(fimc_event_handler(NULL, NULL, qbuf, gem, &property, usr_addr, width, height, IPP_CMD_WB, IPP_CMD_M2M_NONE) < 0) break; } @@ -538,7 +1054,8 @@ void fimc_wb_set_mode(struct connector *c, int count, int page_flip, } /* For property */ - ret = exynos_drm_ipp_set_property(fd, &property, &def_sz, IPP_CMD_WB, EXYNOS_DRM_DEGREE_90); + ret = exynos_drm_ipp_set_property(fd, &property, + &def_sz, IPP_CMD_WB, IPP_CMD_M2M_NONE, EXYNOS_DRM_DEGREE_90); if (ret) { fprintf(stderr, "failed to ipp property\n"); goto err_ipp_ctrl_close; @@ -548,7 +1065,8 @@ void fimc_wb_set_mode(struct connector *c, int count, int page_flip, for (i = 0; i < MAX_BUF; i++) { /* For destination buffer map to IPP */ ret = exynos_drm_ipp_queue_buf(fd, &qbuf[i], EXYNOS_DRM_OPS_DST, - IPP_BUF_ENQUEUE, property.prop_id, i, gem[i].handle); + IPP_BUF_ENQUEUE, property.prop_id, i, + gem[i].handle, 0, 0); if (ret) { fprintf(stderr, "failed to ipp buf dst map\n"); goto err_ipp_ctrl_close; @@ -571,7 +1089,8 @@ err_ipp_ctrl_close: /* For destination buffer dequeue to IPP */ for (i = 0; i < MAX_BUF; i++) { ret = exynos_drm_ipp_queue_buf(fd, &qbuf[i], EXYNOS_DRM_OPS_DST, - IPP_BUF_DEQUEUE, property.prop_id, i, gem[i].handle); + IPP_BUF_DEQUEUE, property.prop_id, i, + gem[i].handle, 0, 0); if (ret < 0) fprintf(stderr, "failed to ipp buf dst dequeue\n"); } @@ -596,4 +1115,3 @@ void fimc_output_set_mode(struct connector *c, int count, int page_flip, { fprintf(stderr, "not supported. please wait v2\n"); } - diff --git a/tests/ipptest/fimc.h b/tests/ipptest/fimc.h index 81e0e008..85261958 100644 --- a/tests/ipptest/fimc.h +++ b/tests/ipptest/fimc.h @@ -1,11 +1,14 @@ #ifndef __FIMC_H__ #define __FIMC_H__ -void fimc_m2m_set_mode(struct connector *c, int count, int page_flip, - long int *usec); +void fimc_m2m_set_mode(struct device *dev, struct connector *c, int count, + enum drm_exynos_degree degree, enum drm_exynos_ipp_cmd_m2m display, + long int *usec); void fimc_wb_set_mode(struct connector *c, int count, int page_flip, long int *usec); void fimc_output_set_mode(struct connector *c, int count, int page_flip, long int *usec); +struct resources *get_resources(struct device *dev); +void free_resources(struct resources *res); #endif diff --git a/tests/ipptest/fimctest.c b/tests/ipptest/fimctest.c index 8fec6412..a01c6740 100644 --- a/tests/ipptest/fimctest.c +++ b/tests/ipptest/fimctest.c @@ -339,7 +339,7 @@ void connector_find_mode(struct connector *c) extern char *optarg; extern int optind, opterr, optopt; -static char optstr[] = "ecpmfo:s:v"; +static char optstr[] = "ecpmfvDo:s:d:"; static void usage(char *name) { @@ -351,6 +351,8 @@ static void usage(char *name) fprintf(stderr, "\t-f\tlist framebuffers\n"); fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); fprintf(stderr, "\t-o\tlist of operation id : 0: M2M, 1: Writeback, 2: Output\n"); + fprintf(stderr, "\t-D\ttest M2M Display Mode\n"); + fprintf(stderr, "\t-d\tlist of degree operation : 0: 0, 1: 90, 2, 180, 3, 270\n"); fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); fprintf(stderr, "\n\tDefault is to dump all info.\n"); @@ -361,14 +363,19 @@ static void usage(char *name) int main(int argc, char **argv) { + struct device dev; int c; int operations = 0, encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; + int degree = EXYNOS_DRM_DEGREE_180; + int display = IPP_CMD_M2M_FILE; int test_vsync = 0; char *modules[] = {"exynos", "i915", "radeon", "nouveau", "vmwgfx"}; char *modeset = NULL; int i, count = 0; struct connector con_args[2]; - + + memset(&dev, 0, sizeof(dev)); + opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { @@ -407,6 +414,13 @@ int main(int argc, char **argv) usage(argv[0]); count++; break; + case 'd': + if (optarg) + sscanf(optarg, "%d", °ree); + break; + case 'D': + display = 1; + break; default: usage(argv[0]); break; @@ -423,6 +437,7 @@ int main(int argc, char **argv) printf("failed.\n"); } else { printf("success.\n"); + dev.fd = fd; break; } } @@ -432,13 +447,14 @@ int main(int argc, char **argv) return -1; } - resources = drmModeGetResources(fd); - if (!resources) { - fprintf(stderr, "drmModeGetResources failed: %s\n", - strerror(errno)); - drmClose(fd); + dev.resources = get_resources(&dev); + if (!dev.resources) { + fprintf(stderr, "get_resources failed: %s\n", + strerror(errno)); + drmClose(dev.fd); return 1; } + resources = dev.resources->res; dump_resource(encoders); dump_resource(connectors); @@ -446,11 +462,28 @@ int main(int argc, char **argv) dump_resource(framebuffers); if (count > 0) { - long int sum = 0, usec[MAX_LOOP]; + long int sum = 0, usec[MAX_LOOP] = {0, }; + int ret; switch(operations) { case 0: - fimc_m2m_set_mode(con_args, count, test_vsync, usec); + if (degree < EXYNOS_DRM_DEGREE_0 || + degree > EXYNOS_DRM_DEGREE_270) { + fprintf(stderr, "not support degree\n"); + break; + } + + ret = kms_create(dev.fd, &dev.kms); + if (ret) { + fprintf(stderr, + "failed to create kms driver: %s\n", + strerror(-ret)); + break; + } + + fimc_m2m_set_mode(&dev, con_args, count, + degree, display, usec); + kms_destroy(&dev.kms); break; case 1: fimc_wb_set_mode(con_args, count, test_vsync, usec); @@ -462,16 +495,18 @@ int main(int argc, char **argv) break; } - for (i = 0; i < MAX_LOOP; i++) { - printf("[%d] : %d\n", i + 1, usec[i]); - sum += usec[i]; + if (display == IPP_CMD_M2M_FILE) { + for (i = 0; i < MAX_LOOP && usec[i] != 0; i++) { + printf("[%d] : %d\n", i + 1, usec[i]); + sum += usec[i]; + } + printf("fimc : result files are in %s\n", RESULT_PATH); + printf("avg : [%d]\n", sum / i); } - printf("fimc : result files are in %s\n", RESULT_PATH); - printf("avg : [%d]\n", sum / MAX_LOOP); getchar(); } - drmModeFreeResources(resources); + free_resources(dev.resources); return 0; } diff --git a/tests/ipptest/fimctest.h b/tests/ipptest/fimctest.h index dd0afa83..40259f0a 100644 --- a/tests/ipptest/fimctest.h +++ b/tests/ipptest/fimctest.h @@ -1,8 +1,10 @@ #ifndef __FIMCTEST_H__ #define __FIMCTEST_H__ +#include <stdbool.h> #include "xf86drm.h" #include "xf86drmMode.h" +#include "libkms.h" #define MAX_LOOP 20 #define HALF_LOOP 10 @@ -22,6 +24,83 @@ struct connector { int swap_count; }; +struct crtc { + drmModeCrtc *crtc; + drmModeObjectProperties *props; + drmModePropertyRes **props_info; + drmModeModeInfo *mode; +}; + +struct encoder { + drmModeEncoder *encoder; +}; + +struct drm_connector { + drmModeConnector *connector; + drmModeObjectProperties *props; + drmModePropertyRes **props_info; +}; + +struct fb { + drmModeFB *fb; +}; + +struct plane { + drmModePlane *plane; + drmModeObjectProperties *props; + drmModePropertyRes **props_info; +}; + +struct resources { + drmModeRes *res; + drmModePlaneRes *plane_res; + + struct crtc *crtcs; + struct encoder *encoders; + struct drm_connector *connectors; + struct fb *fbs; + struct plane *planes; +}; + +struct device { + int fd; + + struct resources *resources; + struct kms_driver *kms; + + struct { + unsigned int width; + unsigned int height; + + unsigned int fb_id; + struct kms_bo *bo; + } mode; +}; + +struct pipe_arg { + uint32_t *con_ids; + unsigned int num_cons; + uint32_t crtc_id; + char mode_str[64]; + char format_str[5]; + unsigned int vrefresh; + unsigned int fourcc; + drmModeModeInfo *mode; + struct crtc *crtc; + struct timeval start; +}; + +struct plane_arg { + uint32_t crtc_id; /* the id of CRTC to bind to */ + bool has_position; + int32_t x, y; + uint32_t w, h; + double scale; + unsigned int fb_id; + char format_str[5]; /* need to leave room for terminating \0 */ + unsigned int fourcc; +}; + extern int fd; extern void connector_find_mode(struct connector *c); diff --git a/tests/ipptest/gem.c b/tests/ipptest/gem.c index 69f2168c..a60bc250 100644 --- a/tests/ipptest/gem.c +++ b/tests/ipptest/gem.c @@ -41,6 +41,7 @@ #include "libkms.h" #include "exynos_drm.h" +#include "internal.h" #include "gem.h" int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem) @@ -98,3 +99,36 @@ int exynos_gem_close(int fd, struct drm_gem_close *gem_close) fprintf(stderr, "failed to close: %s\n", strerror(-ret)); return ret; } + +struct kms_bo* exynos_kms_gem_create(struct kms_driver *kms, + unsigned int width, unsigned int height, unsigned int *stride) +{ + struct kms_bo *bo; + unsigned bo_attribs[] = { + KMS_WIDTH, 0, + KMS_HEIGHT, 0, + KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8, + KMS_TERMINATE_PROP_LIST + }; + int ret; + + bo_attribs[1] = width; + bo_attribs[3] = height; + + ret = kms_bo_create(kms, bo_attribs, &bo); + if (ret) { + fprintf(stderr, "failed to alloc buffer: %s\n", + strerror(-ret)); + return NULL; + } + + ret = kms_bo_get_prop(bo, KMS_PITCH, stride); + if (ret) { + fprintf(stderr, "failed to retreive buffer stride: %s\n", + strerror(-ret)); + kms_bo_destroy(&bo); + return NULL; + } + + return bo; +} diff --git a/tests/ipptest/gem.h b/tests/ipptest/gem.h index 0f59782e..5e28c775 100644 --- a/tests/ipptest/gem.h +++ b/tests/ipptest/gem.h @@ -8,8 +8,13 @@ struct exynos_gem_mmap_data { void *addr; }; +struct kms_bo; +struct kms_driver; + extern int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem); extern int exynos_gem_mmap(int fd, struct exynos_gem_mmap_data *in_mmap); extern int exynos_gem_close(int fd, struct drm_gem_close *gem_close); +extern struct kms_bo* exynos_kms_gem_create(struct kms_driver *kms, + unsigned int width, unsigned int height, unsigned int *stride); #endif diff --git a/tests/ipptest/util.c b/tests/ipptest/util.c index cde93dc0..f49ad1d8 100644 --- a/tests/ipptest/util.c +++ b/tests/ipptest/util.c @@ -34,7 +34,121 @@ #include <errno.h> #include "exynos_drm.h" +#include "drm_fourcc.h" +#include "libkms.h" +#include "internal.h" #include "gem.h" +#include "util.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +/* + * Formats + */ +struct color_component { + unsigned int length; + unsigned int offset; +}; + +struct rgb_info { + struct color_component red; + struct color_component green; + struct color_component blue; + struct color_component alpha; +}; + +enum yuv_order { + YUV_YCbCr = 1, + YUV_YCrCb = 2, + YUV_YC = 4, + YUV_CY = 8, +}; + +struct yuv_info { + enum yuv_order order; + unsigned int xsub; + unsigned int ysub; + unsigned int chroma_stride; +}; + +struct format_info { + unsigned int format; + const char *name; + const struct rgb_info rgb; + const struct yuv_info yuv; +}; + +#define MAKE_RGB_INFO(rl, ro, bl, bo, gl, go, al, ao) \ + .rgb = { { (rl), (ro) }, { (bl), (bo) }, { (gl), (go) }, { (al), (ao) } } + +#define MAKE_YUV_INFO(order, xsub, ysub, chroma_stride) \ + .yuv = { (order), (xsub), (ysub), (chroma_stride) } + +static const struct format_info format_info[] = { + /* YUV packed */ + { DRM_FORMAT_UYVY, "UYVY", MAKE_YUV_INFO(YUV_YCbCr | YUV_CY, 2, 2, 2) }, + { DRM_FORMAT_VYUY, "VYUY", MAKE_YUV_INFO(YUV_YCrCb | YUV_CY, 2, 2, 2) }, + { DRM_FORMAT_YUYV, "YUYV", MAKE_YUV_INFO(YUV_YCbCr | YUV_YC, 2, 2, 2) }, + { DRM_FORMAT_YVYU, "YVYU", MAKE_YUV_INFO(YUV_YCrCb | YUV_YC, 2, 2, 2) }, + /* YUV semi-planar */ + { DRM_FORMAT_NV12, "NV12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) }, + { DRM_FORMAT_NV21, "NV21", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 2) }, + { DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) }, + { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) }, + /* YUV planar */ + { DRM_FORMAT_YUV420, "YU12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 1) }, + { DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) }, + /* RGB16 */ + { DRM_FORMAT_ARGB4444, "AR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) }, + { DRM_FORMAT_XRGB4444, "XR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 0, 0) }, + { DRM_FORMAT_ABGR4444, "AB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 4, 12) }, + { DRM_FORMAT_XBGR4444, "XB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 0, 0) }, + { DRM_FORMAT_RGBA4444, "RA12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 4, 0) }, + { DRM_FORMAT_RGBX4444, "RX12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 0, 0) }, + { DRM_FORMAT_BGRA4444, "BA12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 4, 0) }, + { DRM_FORMAT_BGRX4444, "BX12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 0, 0) }, + { DRM_FORMAT_ARGB1555, "AR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) }, + { DRM_FORMAT_XRGB1555, "XR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) }, + { DRM_FORMAT_ABGR1555, "AB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 1, 15) }, + { DRM_FORMAT_XBGR1555, "XB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 0, 0) }, + { DRM_FORMAT_RGBA5551, "RA15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 1, 0) }, + { DRM_FORMAT_RGBX5551, "RX15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 0, 0) }, + { DRM_FORMAT_BGRA5551, "BA15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 1, 0) }, + { DRM_FORMAT_BGRX5551, "BX15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 0, 0) }, + { DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) }, + { DRM_FORMAT_BGR565, "BG16", MAKE_RGB_INFO(5, 0, 6, 5, 5, 11, 0, 0) }, + /* RGB24 */ + { DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) }, + { DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) }, + /* RGB32 */ + { DRM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) }, + { DRM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) }, + { DRM_FORMAT_ABGR8888, "AB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 8, 24) }, + { DRM_FORMAT_XBGR8888, "XB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) }, + { DRM_FORMAT_RGBA8888, "RA24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 8, 0) }, + { DRM_FORMAT_RGBX8888, "RX24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 0, 0) }, + { DRM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) }, + { DRM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) }, + { DRM_FORMAT_ARGB2101010, "AR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 2, 30) }, + { DRM_FORMAT_XRGB2101010, "XR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 0, 0) }, + { DRM_FORMAT_ABGR2101010, "AB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 2, 30) }, + { DRM_FORMAT_XBGR2101010, "XB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 0, 0) }, + { DRM_FORMAT_RGBA1010102, "RA30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 2, 0) }, + { DRM_FORMAT_RGBX1010102, "RX30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 0, 0) }, + { DRM_FORMAT_BGRA1010102, "BA30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 2, 0) }, + { DRM_FORMAT_BGRX1010102, "BX30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 0, 0) }, +}; + +unsigned int format_fourcc(const char *name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(format_info); i++) { + if (!strcmp(format_info[i].name, name)) + return format_info[i].format; + } + return 0; +} int util_gem_create_mmap(int fd, struct drm_exynos_gem_create *gem, struct exynos_gem_mmap_data *mmap, @@ -62,6 +176,141 @@ int util_gem_create_mmap(int fd, struct drm_exynos_gem_create *gem, return 0; } +struct kms_bo *util_kms_gem_create_mmap(struct kms_driver *kms, + unsigned int format, unsigned int width, + unsigned int height, unsigned int handles[4], + unsigned int pitches[4], unsigned int offsets[4]) +{ + unsigned int virtual_height; + void *planes[3] = { 0, }; + void *virtual; + struct kms_bo *bo; + int ret; + + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + virtual_height = height * 3 / 2; + break; + + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + virtual_height = height * 2; + break; + + default: + virtual_height = height; + break; + } + + bo = exynos_kms_gem_create(kms, width, virtual_height, &pitches[0]); + if (!bo) + return NULL; + + ret = kms_bo_map(bo, &virtual); + if (ret) { + fprintf(stderr, "failed to map buffer: %s\n", + strerror(-ret)); + kms_bo_destroy(&bo); + return NULL; + } + + /* just testing a limited # of formats to test single + * and multi-planar path.. would be nice to add more.. + */ + switch (format) { + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + offsets[0] = 0; + kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); + kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]); + + planes[0] = virtual; + break; + + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + offsets[0] = 0; + kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); + kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]); + pitches[1] = pitches[0]; + offsets[1] = pitches[0] * height; + kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]); + + planes[0] = virtual; + planes[1] = virtual + offsets[1]; + break; + + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + offsets[0] = 0; + kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); + kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]); + pitches[1] = pitches[0] / 2; + offsets[1] = pitches[0] * height; + kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]); + pitches[2] = pitches[1]; + offsets[2] = offsets[1] + pitches[1] * height / 2; + kms_bo_get_prop(bo, KMS_HANDLE, &handles[2]); + + planes[0] = virtual; + planes[1] = virtual + offsets[1]; + planes[2] = virtual + offsets[2]; + break; + + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_BGRX1010102: + offsets[0] = 0; + kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); + kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]); + + planes[0] = virtual; + break; + } + + kms_bo_unmap(bo); + + return bo; +} + void util_draw_buffer(void *addr, unsigned int stripe, unsigned int width, unsigned int height, unsigned int stride, unsigned int size) @@ -83,6 +332,56 @@ void util_draw_buffer(void *addr, unsigned int stripe, memset(addr, 0x77, size); } +void util_draw_buffer_yuv(void **addr, unsigned int width, unsigned int height) +{ + int i, j; + unsigned char *img_ptr; + unsigned char *y, *u, *v, *u422, *v422; + + img_ptr = malloc(width * height * 4); + y = malloc(width * height); + u = malloc(width * height); + v = malloc(width * height); + + u422 = malloc(width * (height / 2)); + v422 = malloc(width * (height / 2)); + + /* Get RGB fmt Image */ + util_draw_buffer(img_ptr, 1, width, height, width * 4, 0); + + /* RGB888 to YUV422 Conversion */ + i = 0; + for (j = 0; j < width * height * 4; j += 4) { + y[j / 4] = (unsigned char)( + FMT_Y_R_VALUE * img_ptr[width * height * 4 - j - 1] + + FMT_Y_G_VALUE * img_ptr[width * height * 4 - j - 2] + + FMT_Y_B_VALUE * img_ptr[width * height * 4 - j - 3] + ) + 16; + u[j / 4] = (unsigned char)(-1 * + FMT_U_R_VALUE * img_ptr[width * height * 4 - j - 1] - + FMT_U_G_VALUE * img_ptr[width * height * 4 - j - 2] + + FMT_U_B_VALUE * img_ptr[width * height * 4 - j - 3] + ) + 128; + v[j / 4] = (unsigned char)( + FMT_V_R_VALUE * img_ptr[width * height * 4 - j - 1] - + FMT_V_G_VALUE * img_ptr[width * height * 4 - j - 2] - + FMT_V_B_VALUE * img_ptr[width * height * 4 - j - 3] + ) + 128; + + if ((j / 4) % 2 == 0) { + u422[i] = u[j / 4]; + v422[i] = v[j / 4]; + i++; + } + } + + memcpy(addr[EXYNOS_DRM_PLANAR_Y], y, width * height); + memcpy(addr[EXYNOS_DRM_PLANAR_CB], u422, width * (height / 2)); + memcpy(addr[EXYNOS_DRM_PLANAR_CR], v422, width * (height / 2)); + + free(img_ptr); free(y); free(u); free(v); free(u422); free(v422); +} + int util_write_bmp(const char *file, const void *data, unsigned int width, unsigned int height) { diff --git a/tests/ipptest/util.h b/tests/ipptest/util.h index 0bbeac66..1e71d44d 100644 --- a/tests/ipptest/util.h +++ b/tests/ipptest/util.h @@ -1,12 +1,38 @@ #ifndef __UTIL_H__ #define __UTIL_H__ +/* + * RGB value of YUV format + */ +#define FMT_Y_R_VALUE 0.257 +#define FMT_Y_G_VALUE 0.504 +#define FMT_Y_B_VALUE 0.098 + +#define FMT_U_R_VALUE 0.148 +#define FMT_U_G_VALUE 0.291 +#define FMT_U_B_VALUE 0.439 + +#define FMT_V_R_VALUE 0.439 +#define FMT_V_G_VALUE 0.368 +#define FMT_V_B_VALUE 0.071 + +struct kms_bo; +struct kms_driver; + +unsigned int format_fourcc(const char *name); extern int util_gem_create_mmap(int fd, struct drm_exynos_gem_create *gem, struct exynos_gem_mmap_data *mmap, unsigned int size); +extern struct kms_bo *util_kms_gem_create_mmap(struct kms_driver *kms, + unsigned int format, unsigned int width, + unsigned int height, unsigned int handles[4], + unsigned int pitches[4], unsigned int offsets[4]); extern void util_draw_buffer(void *addr, unsigned int stripe, unsigned int width, unsigned int height, unsigned int stride, unsigned int size); +extern void util_draw_buffer_yuv(void **addr, unsigned int width, + unsigned int height); extern int util_write_bmp(const char *file, const void *data, unsigned int width, unsigned int height); + #endif |