#include "config.h"
#endif
-#include <pixman.h>
+#include <linux/media-bus-format.h>
+#include <errno.h>
#include "tdm_nexell.h"
-#include "tdm_helper.h"
typedef struct _tdm_nexell_pp_buffer {
tbm_surface_h src;
struct list_head link;
} tdm_nexell_pp_data;
+#define MAX_PLANE_NUM 3
-static tbm_format pp_formats[] = {
- TBM_FORMAT_ARGB8888,
- TBM_FORMAT_XRGB8888,
- TBM_FORMAT_YUV420,
- TBM_FORMAT_YVU420
+struct rect {
+ int x;
+ int y;
+ int width;
+ int height;
};
-#define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0]))
-
-static int pp_list_init;
-static struct list_head pp_list;
-
-static pixman_format_code_t
-_tdm_nexell_pp_pixman_get_format(tbm_format tbmfmt)
-{
- switch (tbmfmt) {
- case TBM_FORMAT_ARGB8888:
- return PIXMAN_a8r8g8b8;
- case TBM_FORMAT_XRGB8888:
- return PIXMAN_x8r8g8b8;
- case TBM_FORMAT_YUV420:
- case TBM_FORMAT_YVU420:
- return PIXMAN_yv12;
- default:
- return 0;
- }
-}
-
-int
-_tdm_nexell_pp_pixman_convert(pixman_op_t op,
- unsigned char *srcbuf, unsigned char *dstbuf,
- pixman_format_code_t src_format, pixman_format_code_t dst_format,
- int sbw, int sbh, int sx, int sy, int sw, int sh,
- int dbw, int dbh, int dx, int dy, int dw, int dh,
- int rotate, int hflip, int vflip)
-{
- pixman_image_t *src_img;
- pixman_image_t *dst_img;
- struct pixman_f_transform ft;
- pixman_transform_t transform;
- int src_stride, dst_stride;
- int src_bpp;
- int dst_bpp;
- double scale_x, scale_y;
- int rotate_step;
- int ret = 0;
-
- RETURN_VAL_IF_FAIL(srcbuf != NULL, 0);
- RETURN_VAL_IF_FAIL(dstbuf != NULL, 0);
-
- TDM_DBG("src(%dx%d: %d,%d %dx%d) dst(%dx%d: %d,%d %dx%d) flip(%d,%d), rot(%d)",
- sbw, sbh, sx, sy, sw, sh, dbw, dbh, dx, dy, dw, dh, hflip, vflip, rotate);
+typedef struct _tdm_nexell_scaler_context {
+ int src_plane_num;
+ int src_fds[MAX_PLANE_NUM];
+ int src_stride[MAX_PLANE_NUM];
+ unsigned int src_width;
+ unsigned int src_height;
+ unsigned int src_code;
- src_bpp = PIXMAN_FORMAT_BPP(src_format) / 8;
- RETURN_VAL_IF_FAIL(src_bpp > 0, 0);
+ int dst_plane_num;
+ int dst_fds[MAX_PLANE_NUM];
+ int dst_stride[MAX_PLANE_NUM];
+ unsigned int dst_width;
+ unsigned int dst_height;
+ unsigned int dst_code;
- dst_bpp = PIXMAN_FORMAT_BPP(dst_format) / 8;
- RETURN_VAL_IF_FAIL(dst_bpp > 0, 0);
+ struct rect crop;
+} tdm_nexell_scaler_context;
- rotate_step = (rotate + 360) / 90 % 4;
-
- src_stride = sbw * src_bpp;
- dst_stride = dbw * dst_bpp;
-
- src_img = pixman_image_create_bits(src_format, sbw, sbh, (uint32_t *)srcbuf,
- src_stride);
- dst_img = pixman_image_create_bits(dst_format, dbw, dbh, (uint32_t *)dstbuf,
- dst_stride);
+static tbm_format pp_formats[] = {
+ TBM_FORMAT_YUV420
+};
- GOTO_IF_FAIL(src_img != NULL, CANT_CONVERT);
- GOTO_IF_FAIL(dst_img != NULL, CANT_CONVERT);
+#define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0]))
+#define IOC_NX_MAGIC 0x6e78 /* nx */
+enum {
+ IOCTL_SCALER_SET_AND_RUN = _IO(IOC_NX_MAGIC, 1),
+};
- pixman_f_transform_init_identity(&ft);
+#ifndef ALIGN
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#endif
- if (hflip) {
- pixman_f_transform_scale(&ft, NULL, -1, 1);
- pixman_f_transform_translate(&ft, NULL, dw, 0);
- }
+static int pp_list_init;
+static struct list_head pp_list;
- if (vflip) {
- pixman_f_transform_scale(&ft, NULL, 1, -1);
- pixman_f_transform_translate(&ft, NULL, 0, dh);
- }
+static int
+_tdm_drm_ioctl(int fd, unsigned long request, void *arg)
+{
+ int ret;
- if (rotate_step > 0) {
- int c = 0, s = 0, tx = 0, ty = 0;
+ do {
+ ret = ioctl(fd, request, arg);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
- if (rotate_step == 1) /* 90 degrees */
- s = -1, tx = -dw;
- else if (rotate_step == 2) /* 180 degrees */
- c = -1, tx = -dw, ty = -dh;
- else /* 270 degrees */
- s = 1, ty = -dh;
+ return ret;
+}
- pixman_f_transform_translate(&ft, NULL, tx, ty);
- pixman_f_transform_rotate(&ft, NULL, c, s);
- }
+static int
+_tdm_gem_to_dmafd(int drm_fd, int gem_fd)
+{
+ int ret;
+ struct drm_prime_handle arg = {0, };
- if (rotate_step % 2 == 0) {
- scale_x = (double)sw / dw;
- scale_y = (double)sh / dh;
- } else {
- scale_x = (double)sw / dh;
- scale_y = (double)sh / dw;
+ arg.handle = gem_fd;
+ ret = _tdm_drm_ioctl(drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg);
+ if (0 != ret) {
+ return -1;
}
-
- pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
- pixman_f_transform_translate(&ft, NULL, sx, sy);
-
- pixman_transform_from_pixman_f_transform(&transform, &ft);
- pixman_image_set_transform(src_img, &transform);
-
- pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, dx, dy, dw, dh);
-
- ret = 1;
-
-CANT_CONVERT:
- if (src_img)
- pixman_image_unref(src_img);
- if (dst_img)
- pixman_image_unref(dst_img);
-
- return ret;
+ return arg.fd;
}
static tdm_error
-_tdm_nexell_pp_convert(tdm_nexell_pp_buffer *buffer, tdm_info_pp *info)
+_tdm_nexell_pp_convert(tdm_nexell_pp_buffer *buffer, tdm_info_pp *info, int drm_fd, int scaler_fd)
{
- tbm_surface_info_s src_info, dst_info;
- pixman_format_code_t src_format, dst_format;
- int sbw, dbw;
- int rotate = 0, hflip = 0;
- tbm_bo bo = NULL;
- int bo_cnt = 0;
- int bo_size = 0;
-
- RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
- RETURN_VAL_IF_FAIL(buffer->src != NULL, TDM_ERROR_INVALID_PARAMETER);
- RETURN_VAL_IF_FAIL(buffer->dst != NULL, TDM_ERROR_INVALID_PARAMETER);
- RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
-
- bo_cnt = tbm_surface_internal_get_num_bos(buffer->src);
- RETURN_VAL_IF_FAIL(bo_cnt == 1, TDM_ERROR_INVALID_PARAMETER);
-
- bo_cnt = tbm_surface_internal_get_num_bos(buffer->dst);
- RETURN_VAL_IF_FAIL(bo_cnt == 1, TDM_ERROR_INVALID_PARAMETER);
-
- bo = tbm_surface_internal_get_bo(buffer->src, 0);
- RETURN_VAL_IF_FAIL(bo != NULL, TDM_ERROR_INVALID_PARAMETER);
-
- bo_size = tbm_bo_size(bo);
-
- /* not handle buffers which have 2 more gem handles */
-
- memset(&src_info, 0, sizeof(tbm_surface_info_s));
- tbm_surface_map(buffer->src, TBM_OPTION_READ, &src_info);
- GOTO_IF_FAIL(src_info.planes[0].ptr != NULL, fail_convert);
-
- memset(&dst_info, 0, sizeof(tbm_surface_info_s));
- tbm_surface_map(buffer->dst, TBM_OPTION_WRITE, &dst_info);
- GOTO_IF_FAIL(dst_info.planes[0].ptr != NULL, fail_convert);
-
- src_format = _tdm_nexell_pp_pixman_get_format(src_info.format);
- GOTO_IF_FAIL(src_format > 0, fail_convert);
- dst_format = _tdm_nexell_pp_pixman_get_format(dst_info.format);
- GOTO_IF_FAIL(dst_format > 0, fail_convert);
-
- if (src_info.format == TBM_FORMAT_YUV420) {
- if (dst_info.format == TBM_FORMAT_XRGB8888)
- dst_format = PIXMAN_x8b8g8r8;
- else if (dst_info.format == TBM_FORMAT_ARGB8888)
- dst_format = PIXMAN_a8b8g8r8;
- else if (dst_info.format == TBM_FORMAT_YVU420) {
- TDM_ERR("can't convert %c%c%c%c to %c%c%c%c",
- FOURCC_STR(src_info.format), FOURCC_STR(dst_info.format));
- goto fail_convert;
- }
- }
- /* need checking for other formats also? */
-
- if (IS_RGB(src_info.format))
- sbw = src_info.planes[0].stride >> 2;
- else
- sbw = src_info.planes[0].stride;
-
- if (IS_RGB(dst_info.format))
- dbw = dst_info.planes[0].stride >> 2;
- else
- dbw = dst_info.planes[0].stride;
-
- rotate = (info->transform % 4) * 90;
- if (info->transform >= TDM_TRANSFORM_FLIPPED)
- hflip = 1;
-
- if (bo_size < src_info.planes[0].stride * src_info.height) {
- TDM_WRN("bo size(%d) is smaller than the expected size(%d)",
- bo_size, src_info.planes[0].stride * src_info.height);
- goto fail_convert;
- }
-
- _tdm_nexell_pp_pixman_convert(PIXMAN_OP_SRC,
- src_info.planes[0].ptr, dst_info.planes[0].ptr,
- src_format, dst_format,
- sbw, src_info.height,
- info->src_config.pos.x, info->src_config.pos.y,
- info->src_config.pos.w, info->src_config.pos.h,
- dbw, dst_info.height,
- info->dst_config.pos.x, info->dst_config.pos.y,
- info->dst_config.pos.w, info->dst_config.pos.h,
- rotate, hflip, 0);
- tbm_surface_unmap(buffer->src);
- tbm_surface_unmap(buffer->dst);
+ tdm_nexell_scaler_context ctx;
+ unsigned int src_y_stride;
+ unsigned int src_c_stride;
+ unsigned int dst_y_stride;
+ unsigned int dst_c_stride;
+ tbm_bo bo_src = NULL;
+ tbm_bo bo_dst = NULL;
+ __u32 handle_src;
+ __u32 handle_dst;
+
+ bo_src = tbm_surface_internal_get_bo(buffer->src, 0);
+ RETURN_VAL_IF_FAIL(bo_src != NULL, TDM_ERROR_OPERATION_FAILED);
+ handle_src = (__u32)tbm_bo_get_handle(bo_src, TBM_DEVICE_DEFAULT).u32;
+ ctx.src_fds[0] = _tdm_gem_to_dmafd(drm_fd, handle_src);
+ ctx.src_fds[1] = ctx.src_fds[0];
+ ctx.src_fds[2] = ctx.src_fds[0];
+
+ bo_dst = tbm_surface_internal_get_bo(buffer->dst, 0);
+ RETURN_VAL_IF_FAIL(bo_dst != NULL, TDM_ERROR_OPERATION_FAILED);
+ handle_dst = (__u32)tbm_bo_get_handle(bo_dst, TBM_DEVICE_DEFAULT).u32;
+ ctx.dst_fds[0] = _tdm_gem_to_dmafd(drm_fd, handle_dst);
+ ctx.dst_fds[1] = ctx.dst_fds[0];
+ ctx.dst_fds[2] = ctx.dst_fds[0];
+
+ src_y_stride = ALIGN(info->src_config.size.h, 32);
+ src_c_stride = ALIGN(src_y_stride >> 1, 16);
+ dst_y_stride = ALIGN(info->dst_config.size.h, 8);
+ dst_c_stride = ALIGN(dst_y_stride >> 1, 4);
+
+ ctx.src_plane_num = 1;
+ ctx.src_width = info->src_config.size.h;
+ ctx.src_height = info->src_config.size.v;
+ ctx.src_code = MEDIA_BUS_FMT_YUYV8_2X8;
+ ctx.src_stride[0] = src_y_stride;
+ ctx.src_stride[1] = src_c_stride;
+ ctx.src_stride[2] = src_c_stride;
+
+ ctx.dst_plane_num = 1;
+ ctx.dst_width = info->dst_config.size.h;
+ ctx.dst_height = info->dst_config.size.v;
+ ctx.dst_code = MEDIA_BUS_FMT_YUYV8_2X8;
+ ctx.dst_stride[0] = dst_y_stride;
+ ctx.dst_stride[1] = dst_c_stride;
+ ctx.dst_stride[2] = dst_c_stride;
+
+ ctx.crop.x = info->src_config.pos.x;
+ ctx.crop.y = info->src_config.pos.y;
+ ctx.crop.width = info->src_config.pos.w;
+ ctx.crop.height = info->src_config.pos.h;
+
+ TDM_DBG("pp %p(%d, %d). src(%dx%d, (%d,%d,%d) (%d,%d,%d)) dst(%dx%d, (%d,%d,%d) (%d,%d,%d)) crop(%dx%d, %dx%d)", info, drm_fd, scaler_fd,
+ ctx.src_width, ctx.src_height, ctx.src_stride[0], ctx.src_stride[1], ctx.src_stride[2], ctx.src_fds[0], ctx.src_fds[1], ctx.src_fds[2],
+ ctx.dst_width, ctx.dst_height, ctx.dst_stride[0], ctx.dst_stride[1], ctx.dst_stride[2], ctx.dst_fds[0], ctx.dst_fds[1], ctx.dst_fds[2],
+ ctx.crop.x, ctx.crop.y, ctx.crop.width, ctx.crop.height);
+
+ ioctl(scaler_fd, IOCTL_SCALER_SET_AND_RUN, &ctx);
+
+ close(ctx.src_fds[0]);
+ close(ctx.dst_fds[0]);
return TDM_ERROR_NONE;
-fail_convert:
- tbm_surface_unmap(buffer->src);
- tbm_surface_unmap(buffer->dst);
- return TDM_ERROR_OPERATION_FAILED;
}
tdm_error
return TDM_ERROR_INVALID_PARAMETER;
}
- caps->capabilities = TDM_PP_CAPABILITY_SYNC;
+ if (nexell_data->scaler_fd < 0 ) {
+ TDM_ERR("no scaler_fd. not support pp.");
+ return TDM_ERROR_BAD_MODULE;
+ }
+
+ caps->capabilities = TDM_PP_CAPABILITY_SYNC | TDM_PP_CAPABILITY_SCANOUT;
caps->format_count = NUM_PP_FORMAT;
caps->min_h = 8;
caps->max_w = -1; /* not defined */
caps->max_h = -1;
- caps->preferred_align = 16;
+ caps->preferred_align = 32;
return TDM_ERROR_NONE;
}
tdm_pp *
tdm_nexell_pp_create(tdm_nexell_data *nexell_data, tdm_error *error)
{
- tdm_nexell_pp_data *pp_data = calloc(1, sizeof(tdm_nexell_pp_data));
+ tdm_nexell_pp_data *pp_data = NULL;
+
+ if (nexell_data->scaler_fd < 0 ) {
+ TDM_ERR("no scaler_fd.");
+ if (error)
+ *error = TDM_ERROR_BAD_MODULE;
+ return NULL;
+ }
+
+ pp_data = calloc(1, sizeof(tdm_nexell_pp_data));
if (!pp_data) {
TDM_ERR("alloc failed");
if (error)
RETURN_VAL_IF_FAIL(src, TDM_ERROR_INVALID_PARAMETER);
RETURN_VAL_IF_FAIL(dst, TDM_ERROR_INVALID_PARAMETER);
- if (tbm_surface_internal_get_num_bos(src) > 1 ||
- tbm_surface_internal_get_num_bos(dst) > 1) {
- TDM_ERR("can't handle multiple tbm bos");
- return TDM_ERROR_OPERATION_FAILED;
- }
-
buffer = calloc(1, sizeof(tdm_nexell_pp_buffer));
if (!buffer) {
TDM_ERR("alloc failed");
{
tdm_nexell_pp_data *pp_data = pp;
tdm_nexell_pp_buffer *b = NULL, *bb = NULL;
+ tdm_nexell_data *nexell_data;
RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
+ nexell_data = pp_data->nexell_data;
+
LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
LIST_DEL(&b->link);
- _tdm_nexell_pp_convert(b, &pp_data->info);
+ _tdm_nexell_pp_convert(b, &pp_data->info, nexell_data->drm_fd, nexell_data->scaler_fd);
if (pp_data->done_func)
pp_data->done_func(pp_data,