From 1bf120025bf3eed2bc0042c3200ad55670bc6ccb Mon Sep 17 00:00:00 2001 From: Mateusz Krawczuk Date: Fri, 12 Jun 2015 20:21:04 +0200 Subject: v4l2-mfc-example: DRM IPP: Commit add ipp.c and basic initial setup for DRM Image Post-Proccesing Signed-off-by: Mateusz Krawczuk --- v4l2-mfc-example/Makefile | 2 +- v4l2-mfc-example/common.h | 41 +++++- v4l2-mfc-example/drm.c | 1 + v4l2-mfc-example/ipp.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++ v4l2-mfc-example/ipp.h | 44 ++++++ 5 files changed, 420 insertions(+), 4 deletions(-) create mode 100644 v4l2-mfc-example/ipp.c create mode 100644 v4l2-mfc-example/ipp.h diff --git a/v4l2-mfc-example/Makefile b/v4l2-mfc-example/Makefile index 64294a8..131ebaf 100644 --- a/v4l2-mfc-example/Makefile +++ b/v4l2-mfc-example/Makefile @@ -48,7 +48,7 @@ INCLUDES = $(KERNELHEADERS) $(DRMHEADERS) #-I$(TARGETROOT)/usr/include/linux -SOURCES = main.c fileops.c args.c parser.c fb.c fimc.c mfc.c queue.c drm.c gem.c +SOURCES = main.c fileops.c args.c parser.c fb.c fimc.c mfc.c queue.c drm.c gem.c ipp.c OBJECTS := $(SOURCES:.c=.o) EXEC = v4l2_decode CFLAGS = -Wall -g -DS5PC1XX_FIMC -lm diff --git a/v4l2-mfc-example/common.h b/v4l2-mfc-example/common.h index 5d9cd3d..330ad8e 100644 --- a/v4l2-mfc-example/common.h +++ b/v4l2-mfc-example/common.h @@ -42,7 +42,9 @@ #ifdef DRM #include #include -#include +#include +#include +#include #endif #ifdef ADD_DETAILS @@ -94,6 +96,27 @@ * to be processed by FIMC. */ #define BUF_FIMC 2 +#define INVALID_GEM_HANDLE ~0U + +#define DRM_IPP_MAX_BUF 3 +#define DRM_IPP_MAX_PLANES 3 + +struct drm_buff { + unsigned int index; + unsigned int handle[DRM_IPP_MAX_PLANES]; + int fd[DRM_IPP_MAX_PLANES]; + unsigned int fb_id; +}; + +struct shared_buffer { + unsigned int index; + unsigned int width; + unsigned int height; + unsigned int num_planes; + struct v4l2_plane planes[DRM_IPP_MAX_PLANES]; + unsigned int handle[DRM_IPP_MAX_PLANES]; +}; + struct instance { /* Input file related parameters */ struct { @@ -122,7 +145,10 @@ struct instance { unsigned int crtc_id; #ifdef DRM struct drm_exynos_gem_create gem[MAX_BUFS]; + struct drm_exynos_gem_create gem_src[MFC_MAX_CAP_BUF]; struct drm_mode_map_dumb mmap[MAX_BUFS]; + struct drm_prime_handle prime[MAX_BUFS]; + drmModeRes *resources; #endif char enabled; @@ -170,7 +196,17 @@ struct instance { int dmabuf; char ignore_format_change; } fimc; - + struct drm_ipp { + int enabled; + struct drm_exynos_ipp_queue_buf *queue_buf; + struct drm_exynos_ipp_property prop; + struct queue queue; + sem_t todo; + sem_t done; + int cur_buf; + struct drm_exynos_ipp_queue_buf *src_buff[DRM_IPP_MAX_BUF]; + struct drm_exynos_ipp_queue_buf *dst_buff[DRM_IPP_MAX_BUF]; + } ipp; /* MFC related parameters */ struct { char *name; @@ -182,7 +218,6 @@ struct instance { int out_buf_off[MFC_MAX_OUT_BUF]; char *out_buf_addr[MFC_MAX_OUT_BUF]; int out_buf_flag[MFC_MAX_OUT_BUF]; - /* Capture queue related */ int cap_w; int cap_h; diff --git a/v4l2-mfc-example/drm.c b/v4l2-mfc-example/drm.c index 1b408b5..c04595d 100644 --- a/v4l2-mfc-example/drm.c +++ b/v4l2-mfc-example/drm.c @@ -57,6 +57,7 @@ char * res##_str(int type) { \ #include #include #include "gem.h" +#include "ipp.h" struct type_name encoder_type_names[] = { { DRM_MODE_ENCODER_NONE, "none" }, diff --git a/v4l2-mfc-example/ipp.c b/v4l2-mfc-example/ipp.c new file mode 100644 index 0000000..3203f39 --- /dev/null +++ b/v4l2-mfc-example/ipp.c @@ -0,0 +1,336 @@ +/* + * V4L2 Codec decoding example application + * Kamil Debski + * Mateusz Krawczuk + * + * DRM IPP operations + * + * Copyright 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "fimc.h" +#include + +#include +#include +#include "drm.h" +#include "gem.h" + +#define MAX_BUF 3 + +#ifndef DRM_FORMAT_NV12MT +#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */ +#endif + +static drmEventContext event_ctx; + +/* + * exynos_drm_ipp_do_buffer is for enqueue or dequeue buffor of both types + * + */ +int exynos_drm_ipp_do_buffer(int index,int buf_type, int type,struct instance *inst) +{ + struct drm_exynos_ipp_queue_buf* qbuf ; + int d, ret; + for(d=0; d < DRM_IPP_MAX_BUF; d++) { + if (type == EXYNOS_DRM_OPS_SRC) { + qbuf = inst->ipp.src_buff[d]; + qbuf->handle[EXYNOS_DRM_PLANAR_Y] = inst->drm.gem_src[index*2].handle; + qbuf->handle[EXYNOS_DRM_PLANAR_CB] = inst->drm.gem_src[(index*2)+1].handle; + } + else + qbuf = inst->ipp.dst_buff[d]; + + qbuf->ops_id = type; + qbuf->buf_type = buf_type; + qbuf->prop_id = inst->ipp.prop.prop_id; + qbuf->user_data = 0; + qbuf->buf_id = 0; + ret = ioctl(inst->drm.fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, qbuf); + } + if (ret) { + err("Failed to do queue the buffer.\n"); + return -EINVAL; + } + return 0; +} + +/* + * exynos_drm_ipp_cmd_ctrl should be launched after all buffors are queued + * Command for controling ipp + * IPP_CTRL_PLAY + * IPP_CTRL_STOP + * IPP_CTRL_PAUSE + * IPP_CTRL_RESUME + */ +int exynos_drm_ipp_cmd_ctrl(enum drm_exynos_ipp_ctrl ctrl, struct instance *inst) +{ + struct drm_exynos_ipp_cmd_ctrl cmd_ctrl = {0,}; + + cmd_ctrl.prop_id = 1; + cmd_ctrl.ctrl = ctrl; + + if (ioctl(inst->drm.fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, &cmd_ctrl) < 0) { + err("Failed to set the control\n"); + return -EINVAL; + } + return 0; +} +/* + * + */ +int exynos_drm_ipp_display_flip(int index,struct instance *inst) +{ + struct timeval timeout = {.tv_sec = 3, .tv_usec = 0}; + fd_set fds; + int ret; + + ret = drmModePageFlip(inst->drm.fd, inst->drm.crtc[0], inst->drm.fb[0], + DRM_MODE_PAGE_FLIP_EVENT, (void*)(unsigned long)index); + if(ret) { + + err("Failed to page flip: %d\n",ret); + return -EINVAL; + } + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(inst->drm.fd, &fds); + + ret = select(inst->drm.fd +1, &fds, NULL, NULL, &timeout); + if (ret <= 0) { + err("Select timed out or error occured\n"); + return -EINVAL; + } else if (FD_ISSET(0, &fds)) { + err("Failed on select \n"); + return -EINVAL; + } + drmHandleEvent(inst->drm.fd, &event_ctx); + return 0; +} + +int exynos_drm_ipp_dequeue_buffors(struct instance *inst, int index) +{ + dbg("Dequeueing buffer %d\n", index); + if (exynos_drm_ipp_do_buffer(index, IPP_BUF_DEQUEUE,EXYNOS_DRM_OPS_SRC,inst)) + err("Failed to queue source buffer\n"); + if (exynos_drm_ipp_do_buffer(index, IPP_BUF_DEQUEUE,EXYNOS_DRM_OPS_DST,inst)) + err("Failed to queue destination buffer\n"); + return 0; +} +/* + * + */ +int exynos_drm_ipp_process_frame(struct instance *inst, int index) +{ + char buffer[1024]; + int len, i; + struct drm_event *event; + struct drm_exynos_ipp_event *ipp_event; + int count = 20; + int ret; + + dbg("Queueing buffer %d\n", index); + if (exynos_drm_ipp_do_buffer(index, IPP_BUF_ENQUEUE,EXYNOS_DRM_OPS_SRC,inst)) + err("Failed to queue source buffer\n"); + if (exynos_drm_ipp_do_buffer(index, IPP_BUF_ENQUEUE,EXYNOS_DRM_OPS_DST,inst)) + err("Failed to queue destination buffer\n"); + + dbg("IPP process frame\n"); + while (count) { + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0}; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(inst->drm.fd, &fds); + ret = select(inst->drm.fd + 1, &fds, NULL, NULL, &timeout); + if (ret <= 0) { + err("Failed on select - remainig attempts: %d\n", count); + --count; + continue; + } else if (FD_ISSET(0, &fds)) + break; + /* This is painfull ... */ + len = read(inst->drm.fd, buffer, sizeof(struct drm_exynos_ipp_event)); + if (len >= sizeof(*event)) { + int src_id, dest_id; + + i = 0; + while (i < len) { + event = (struct drm_event*) &buffer[i]; + + switch (event->type) { + case DRM_EXYNOS_IPP_EVENT: + dbg("Received event:\n"); + ipp_event = (struct drm_exynos_ipp_event*)event; + src_id = ipp_event->buf_id[EXYNOS_DRM_OPS_SRC]; + dest_id = ipp_event->buf_id[EXYNOS_DRM_OPS_DST]; + + exynos_drm_ipp_display_flip(dest_id, inst); + dbg("SRC ID: %d DEST ID: %d INDEX: %d\n", src_id, dest_id, index); + break; + default: + break; + } + i += event->length; + } + /* Done */ + return 0; + } + /* Handle event */ + --count; + } + // leave: + return -EINVAL; +} +/* + * Send command to stop ctrl and then clean up buffors and memory + */ +void exynos_drm_ipp_close(struct instance *inst) +{ + int i; + struct drm_gem_close gem_close; + + memset(&gem_close, 0, sizeof(gem_close)); + exynos_drm_ipp_cmd_ctrl( IPP_CTRL_STOP, inst); + for (i = 0; i < inst->mfc.cap_buf_cnt*2; ++i) { + gem_close.handle = inst->drm.gem_src[i].handle; + exynos_gem_close(inst->drm.fd, &gem_close); + } + for (i = 0; i < DRM_IPP_MAX_BUF; ++i) + exynos_drm_ipp_do_buffer(i, IPP_BUF_DEQUEUE, EXYNOS_DRM_OPS_DST,inst); + for (i = 0; i < MAX_BUFS; ++i) { + exynos_drm_ipp_do_buffer(i, IPP_BUF_DEQUEUE, EXYNOS_DRM_OPS_DST,inst); + gem_close.handle = inst->drm.gem[i].handle; + exynos_gem_close(inst->drm.fd, &gem_close); + } + drmModeRmFB(inst->drm.fd, (uint32_t)inst->drm.fb); + + close(inst->drm.fd); +} +/* + * Set ipp properties + */ +int exynos_drm_ipp_setup(struct instance *inst) +{ + int ret; + struct drm_exynos_sz input_size = {inst->mfc.cap_crop_w, inst->mfc.cap_crop_h}; + + dbg("Exynos DRM IPP init start\n"); + + struct drm_exynos_pos cpos = {inst->mfc.cap_crop_left, inst->mfc.cap_crop_top, input_size.hsize, input_size.vsize}; + struct drm_exynos_sz output_size = {inst->drm.width, inst->drm.height}; + + struct drm_exynos_pos spos = {0, 0, output_size.hsize, output_size.vsize}; + + if (inst->mfc.cap_pixfmt == V4L2_PIX_FMT_NV12MT) + inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_NV12MT; + else + inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_NV12; + + inst->ipp.prop.cmd = IPP_CMD_M2M; + inst->ipp.prop.prop_id = 0; + /* input */ + inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC; + inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE; + inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0; + // inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_NV12MT; + inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].pos = cpos; + inst->ipp.prop.config[EXYNOS_DRM_OPS_SRC].sz = input_size; + /* output */ + inst->ipp.prop.config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST; + inst->ipp.prop.config[EXYNOS_DRM_OPS_DST].flip = EXYNOS_DRM_FLIP_NONE; + inst->ipp.prop.config[EXYNOS_DRM_OPS_DST].degree = EXYNOS_DRM_DEGREE_0; + inst->ipp.prop.config[EXYNOS_DRM_OPS_DST].fmt = DRM_FORMAT_XRGB8888; + inst->ipp.prop.config[EXYNOS_DRM_OPS_DST].pos = spos; + inst->ipp.prop.config[EXYNOS_DRM_OPS_DST].sz = output_size; + + ret = ioctl(inst->drm.fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, &inst->ipp.prop); + if (ret) { + err("Failed to set properties [%d]\n", errno); + close(inst->drm.fd); + return -EINVAL; + } + + dbg("Exynos DRM IPP init done\n prop_id %d\n", inst->ipp.prop.prop_id); + return 0; +} +/* + * Allocate and setup ipp buffors + */ +int exynos_drm_ipp_allocate_ipp_buffers(struct instance *inst) { + int ret=0, d=0; + + for(d = 0; d < inst->mfc.cap_buf_cnt; d++) { + ret = drmPrimeFDToHandle(inst->drm.fd, inst->mfc.dbuf[d][0], &inst->drm.gem_src[d*2].handle); + ret = drmPrimeFDToHandle(inst->drm.fd, inst->mfc.dbuf[d][1], &inst->drm.gem_src[(d*2)+1].handle); + close(inst->mfc.dbuf[d][0]); + close(inst->mfc.dbuf[d][1]); + } + + for (d=0; dipp.src_buff[d]= (struct drm_exynos_ipp_queue_buf *) calloc (1,sizeof(struct drm_exynos_ipp_queue_buf)); + inst->ipp.src_buff[d]->ops_id = EXYNOS_DRM_OPS_SRC; + inst->ipp.src_buff[d]->buf_type = IPP_BUF_ENQUEUE; + inst->ipp.src_buff[d]->user_data = 0; + inst->ipp.src_buff[d]->prop_id = inst->ipp.prop.prop_id; + inst->ipp.src_buff[d]->buf_id = d; + + inst->ipp.src_buff[d]->handle[EXYNOS_DRM_PLANAR_Y] = inst->drm.gem_src[d*2].handle; + inst->ipp.src_buff[d]->handle[EXYNOS_DRM_PLANAR_CB] = inst->drm.gem_src[(d*2)+1].handle; + inst->ipp.src_buff[d]->handle[EXYNOS_DRM_PLANAR_CR] = 0; + ret = drmIoctl(inst->drm.fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, inst->ipp.src_buff[d]); + if (ret) { + fprintf(stderr, + "failed to SRC DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF[id:%d][buf addr:%p] : %s\n", + inst->ipp.src_buff[d]->buf_id, inst->ipp.src_buff[d], strerror(errno)); + + return ret; + } + + inst->ipp.dst_buff[d]= (struct drm_exynos_ipp_queue_buf *) calloc (1,sizeof(struct drm_exynos_ipp_queue_buf)); + inst->ipp.dst_buff[d]->ops_id = EXYNOS_DRM_OPS_DST; + inst->ipp.dst_buff[d]->buf_type = IPP_BUF_ENQUEUE; + inst->ipp.dst_buff[d]->user_data = 0; + inst->ipp.dst_buff[d]->prop_id = inst->ipp.prop.prop_id; + inst->ipp.dst_buff[d]->buf_id = d; + + inst->ipp.dst_buff[d]->handle[EXYNOS_DRM_PLANAR_Y] = inst->drm.gem[0].handle; + inst->ipp.dst_buff[d]->handle[EXYNOS_DRM_PLANAR_CB] = 0; + inst->ipp.dst_buff[d]->handle[EXYNOS_DRM_PLANAR_CR] = 0; + ret = drmIoctl(inst->drm.fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, inst->ipp.dst_buff[d]); + if (ret) { + fprintf(stderr, + "failed to DST DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF[id:%d][buf addr:%p] : %s\n", + inst->ipp.src_buff[d]->buf_id, inst->ipp.src_buff[d], strerror(errno)); + + return ret; + } + } + dbg("ipp_setup_output_from_mfc\n"); + return 0; +} diff --git a/v4l2-mfc-example/ipp.h b/v4l2-mfc-example/ipp.h new file mode 100644 index 0000000..a1f50bf --- /dev/null +++ b/v4l2-mfc-example/ipp.h @@ -0,0 +1,44 @@ +/* + * V4L2 Codec decoding example application + * Kamil Debski + * Mateusz Krawczuk + * + * DRM IPP operations header file + * + * Copyright 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef INCLUDE_IPP_H +#define INCLUDE_IPP_H + +#include "common.h" +/* Set ipp properties */ +int exynos_drm_ipp_setup(struct instance *i); +/**/ +int exynos_drm_ipp_allocate_ipp_buffers(struct instance *i); +/* exynos_drm_ipp_do_buffer is for enqueue or dequeue buffor of both types */ +int exynos_drm_ipp_do_buffer(int index,int buf_type, int type,struct instance *inst); +int exynos_drm_ipp_process_frame(struct instance *inst, int index); +/* Command for controling ipp */ +int exynos_drm_ipp_cmd_ctrl(enum drm_exynos_ipp_ctrl ctrl, struct instance *inst); +int exynos_drm_ipp_dequeue_buffors(struct instance *inst, int index); +/* Setup OUTPUT queue of IPP basing on the configuration of MFC */ +int exynos_drm_ipp_setup_output_from_mfc(struct instance *i); +/* Send command to stop ctrl and then clean up buffors and memory */ +int exynos_drm_ipp_dec_queue_buf_out_from_mfc(struct instance *inst, int n); +/* Send command to stop ctrl and then clean up buffors and memory */ +void exynos_drm_ipp_close(struct instance *inst) +#endif /* INCLUDE_IPP_H */ + -- cgit v1.2.3