media: venus: vdec: handle 10bit bitstreams
authorAniket Masule <amasule@codeaurora.org>
Wed, 4 Dec 2019 10:18:40 +0000 (11:18 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Thu, 27 Feb 2020 15:49:02 +0000 (16:49 +0100)
Handle 10bit video streams in the decoder by using dithering, i.e
the decoder output buffers will be in 8bit format.

The runtime handling is implemented by sending v4l2 event to
userspace application, then the application should stop the
streaming on capture queue and initiate format negotiation, and
start streaming again.

Signed-off-by: Aniket Masule <amasule@codeaurora.org>
Co-developed-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/platform/qcom/venus/core.h
drivers/media/platform/qcom/venus/helpers.c
drivers/media/platform/qcom/venus/hfi_helper.h
drivers/media/platform/qcom/venus/vdec.c

index bba29e4..ab7c360 100644 (file)
@@ -383,6 +383,7 @@ struct venus_inst {
        u32 session_type;
        union hfi_get_property hprop;
        unsigned int core_acquired: 1;
+       unsigned int bit_depth;
 };
 
 #define IS_V1(core)    ((core)->res->hfi_version == HFI_VERSION_1XX)
index 2b8c585..bcc6038 100644 (file)
@@ -626,6 +626,78 @@ static u32 get_framesize_raw_nv12_ubwc(u32 width, u32 height)
                     max(extradata, y_stride * 48), SZ_4K);
 }
 
+static u32 get_framesize_raw_p010(u32 width, u32 height)
+{
+       u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines;
+
+       y_stride = ALIGN(width * 2, 256);
+       uv_stride = ALIGN(width * 2, 256);
+       y_sclines = ALIGN(height, 32);
+       uv_sclines = ALIGN((height + 1) >> 1, 16);
+       y_plane = y_stride * y_sclines;
+       uv_plane = uv_stride * uv_sclines;
+
+       return ALIGN((y_plane + uv_plane), SZ_4K);
+}
+
+static u32 get_framesize_raw_p010_ubwc(u32 width, u32 height)
+{
+       u32 y_stride, uv_stride, y_sclines, uv_sclines;
+       u32 y_ubwc_plane, uv_ubwc_plane;
+       u32 y_meta_stride, y_meta_scanlines;
+       u32 uv_meta_stride, uv_meta_scanlines;
+       u32 y_meta_plane, uv_meta_plane;
+       u32 size;
+
+       y_stride = ALIGN(width * 2, 256);
+       uv_stride = ALIGN(width * 2, 256);
+       y_sclines = ALIGN(height, 16);
+       uv_sclines = ALIGN((height + 1) >> 1, 16);
+
+       y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
+       uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
+       y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
+       y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
+       y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
+       uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 16), 64);
+       uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
+       uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
+
+       size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
+
+       return ALIGN(size, SZ_4K);
+}
+
+static u32 get_framesize_raw_yuv420_tp10_ubwc(u32 width, u32 height)
+{
+       u32 y_stride, uv_stride, y_sclines, uv_sclines;
+       u32 y_ubwc_plane, uv_ubwc_plane;
+       u32 y_meta_stride, y_meta_scanlines;
+       u32 uv_meta_stride, uv_meta_scanlines;
+       u32 y_meta_plane, uv_meta_plane;
+       u32 extradata = SZ_16K;
+       u32 size;
+
+       y_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
+       uv_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
+       y_sclines = ALIGN(height, 16);
+       uv_sclines = ALIGN((height + 1) >> 1, 16);
+
+       y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
+       uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
+       y_meta_stride = ALIGN(DIV_ROUND_UP(width, 48), 64);
+       y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
+       y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
+       uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 24), 64);
+       uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
+       uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
+
+       size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
+       size += max(extradata + SZ_8K, y_stride * 48);
+
+       return ALIGN(size, SZ_4K);
+}
+
 u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height)
 {
        switch (hfi_fmt) {
@@ -634,6 +706,12 @@ u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height)
                return get_framesize_raw_nv12(width, height);
        case HFI_COLOR_FORMAT_NV12_UBWC:
                return get_framesize_raw_nv12_ubwc(width, height);
+       case HFI_COLOR_FORMAT_P010:
+               return get_framesize_raw_p010(width, height);
+       case HFI_COLOR_FORMAT_P010_UBWC:
+               return get_framesize_raw_p010_ubwc(width, height);
+       case HFI_COLOR_FORMAT_YUV420_TP10_UBWC:
+               return get_framesize_raw_yuv420_tp10_ubwc(width, height);
        default:
                return 0;
        }
@@ -1246,6 +1324,27 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
        if (!caps)
                return -EINVAL;
 
+       if (inst->bit_depth == VIDC_BITDEPTH_10 &&
+           inst->session_type == VIDC_SESSION_TYPE_DEC) {
+               found_ubwc =
+                       find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
+                                          HFI_COLOR_FORMAT_YUV420_TP10_UBWC);
+               found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2,
+                                          HFI_COLOR_FORMAT_NV12);
+               if (found_ubwc && found) {
+                       /*
+                        * Hard-code DPB buffers to be 10bit UBWC and decoder
+                        * output buffers in 8bit NV12 until V4L2 is able to
+                        * expose compressed/tiled formats to applications.
+                        */
+                       *out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC;
+                       *out2_fmt = HFI_COLOR_FORMAT_NV12;
+                       return 0;
+               }
+
+               return -EINVAL;
+       }
+
        if (ubwc) {
                ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE;
                found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
index 2a47f6c..f6613df 100644 (file)
@@ -793,6 +793,9 @@ struct hfi_h264_vui_timing_info {
        u32 time_scale;
 };
 
+#define VIDC_BITDEPTH_8                0x00000
+#define VIDC_BITDEPTH_10       0x20002
+
 struct hfi_bit_depth {
        u32 buffer_type;
        u32 bit_depth;
@@ -841,8 +844,10 @@ struct hfi_extradata_input_crop {
 #define HFI_COLOR_FORMAT_10_BIT_BASE           0x4000
 
 #define HFI_COLOR_FORMAT_YUV420_TP10           0x4002
+#define HFI_COLOR_FORMAT_P010                  0x4003
 #define HFI_COLOR_FORMAT_NV12_UBWC             0x8002
 #define HFI_COLOR_FORMAT_YUV420_TP10_UBWC      0xc002
+#define HFI_COLOR_FORMAT_P010_UBWC             0xc003
 #define HFI_COLOR_FORMAT_RGBA8888_UBWC         0x8010
 
 struct hfi_uncompressed_format_select {
index 5e0a912..f349201 100644 (file)
@@ -1193,6 +1193,9 @@ static void vdec_event_change(struct venus_inst *inst,
        inst->out_width = ev_data->width;
        inst->out_height = ev_data->height;
 
+       if (inst->bit_depth != ev_data->bit_depth)
+               inst->bit_depth = ev_data->bit_depth;
+
        dev_dbg(dev, "event %s sufficient resources (%ux%u)\n",
                sufficient ? "" : "not", ev_data->width, ev_data->height);
 
@@ -1340,6 +1343,7 @@ static int vdec_open(struct file *file)
        inst->buf_count = 0;
        inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
        inst->core_acquired = false;
+       inst->bit_depth = VIDC_BITDEPTH_8;
        init_waitqueue_head(&inst->reconf_wait);
        venus_helper_init_instance(inst);