summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoegeun Kwon <hoegeun.kwon@samsung.com>2016-07-18 15:46:06 +0900
committerInki Dae <inki.dae@samsung.com>2016-08-07 16:44:17 -0700
commitad9ef04faed688ed214e45c4b96bb1feb0af6d47 (patch)
tree654c8cd78190e5ba704a997157ead5a7def93333
parent817a6e16e5dbd2a4753eb705fe468b713b85abe7 (diff)
downloadlibdrm-accepted/tizen_3.0.m2_mobile.tar.gz
libdrm-accepted/tizen_3.0.m2_mobile.tar.bz2
libdrm-accepted/tizen_3.0.m2_mobile.zip
This patch added for the function outputing the M2M to a screen. So, you can check for Image Post processing dirver to screen. Also you can select the degree about (0, 90, 180, 270). I will briefly explain the process of the function: - Memory(YUV422) ---> IPP ---> Memory(RGB888) ---> Screen - Create four DMA memory. - Draw the image of the YUV422 format on three DMA memories. - Rotate the relevant image by using IPP driver. - The rotated image is stored in one DMA memory as the RGB888 format. - The one DMA memory output screen. I referred to the modetest code. Change-Id: I2bf5738d98a457ced274dc8237df8ef108153e61 Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
-rw-r--r--exynos/exynos_drm.h7
-rw-r--r--tests/ipptest/fimc.c824
-rw-r--r--tests/ipptest/fimc.h7
-rw-r--r--tests/ipptest/fimctest.c65
-rw-r--r--tests/ipptest/fimctest.h79
-rw-r--r--tests/ipptest/gem.c34
-rw-r--r--tests/ipptest/gem.h5
-rw-r--r--tests/ipptest/util.c299
-rw-r--r--tests/ipptest/util.h26
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", &degree);
+ 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