Mesa (main): va: Add support for VPP rotation, flip, alpha blend, crop, scaling

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jul 21 23:05:21 UTC 2022


Module: Mesa
Branch: main
Commit: 345fd9209267ba5bd205cd87153c74c159d2e51d
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=345fd9209267ba5bd205cd87153c74c159d2e51d

Author: Sil Vilerino <sivileri at microsoft.com>
Date:   Fri Jul 15 08:01:41 2022 -0400

va: Add support for VPP rotation, flip, alpha blend, crop, scaling

Reviewed-by: Ruijing Dong <ruijing.dong at amd.com>
Reviewed-by: Jesse Natalie <jenatali at microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17557>

---

 src/gallium/frontends/va/context.c    |  5 +-
 src/gallium/frontends/va/picture.c    | 14 ++++++
 src/gallium/frontends/va/postproc.c   | 88 +++++++++++++++++++++++++++++++++++
 src/gallium/frontends/va/surface.c    | 67 +++++++++++++++++++++++++-
 src/gallium/frontends/va/va_private.h |  2 +
 5 files changed, 174 insertions(+), 2 deletions(-)

diff --git a/src/gallium/frontends/va/context.c b/src/gallium/frontends/va/context.c
index f59276e9c53..b205d173ba0 100644
--- a/src/gallium/frontends/va/context.c
+++ b/src/gallium/frontends/va/context.c
@@ -249,7 +249,10 @@ vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width,
    if (!context)
       return VA_STATUS_ERROR_ALLOCATION_FAILED;
 
-   if (is_vpp) {
+   if (is_vpp && !drv->vscreen->pscreen->get_video_param(drv->vscreen->pscreen,
+                                                         PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                         PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                         PIPE_VIDEO_CAP_SUPPORTED)) {
       context->decoder = NULL;
    } else {
       if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
diff --git a/src/gallium/frontends/va/picture.c b/src/gallium/frontends/va/picture.c
index 6c13217e285..bcd23b3ae8a 100644
--- a/src/gallium/frontends/va/picture.c
+++ b/src/gallium/frontends/va/picture.c
@@ -86,6 +86,14 @@ vlVaBeginPicture(VADriverContextP ctx, VAContextID context_id, VASurfaceID rende
           context->target->buffer_format != PIPE_FORMAT_P016)
          return VA_STATUS_ERROR_UNIMPLEMENTED;
 
+      if (drv->pipe->screen->get_video_param(drv->pipe->screen,
+                              PIPE_VIDEO_PROFILE_UNKNOWN,
+                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                              PIPE_VIDEO_CAP_SUPPORTED)) {
+         context->needs_begin_frame = true;
+         context->vpp_needs_flush_on_endpic = true;
+      }
+
       return VA_STATUS_SUCCESS;
    }
 
@@ -822,6 +830,12 @@ vlVaEndPicture(VADriverContextP ctx, VAContextID context_id)
    } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE &&
               u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_HEVC)
       context->desc.h265enc.frame_num++;
+   else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING &&
+            context->vpp_needs_flush_on_endpic) {
+      context->decoder->flush(context->decoder);
+      context->vpp_needs_flush_on_endpic = false;
+   }
+
    mtx_unlock(&drv->mutex);
    return VA_STATUS_SUCCESS;
 }
diff --git a/src/gallium/frontends/va/postproc.c b/src/gallium/frontends/va/postproc.c
index 44c35886f76..17513df4d2b 100644
--- a/src/gallium/frontends/va/postproc.c
+++ b/src/gallium/frontends/va/postproc.c
@@ -111,6 +111,74 @@ static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx,
    box->height = height;
 }
 
+static VAStatus vlVaVidEngineBlit(vlVaDriver *drv, vlVaContext *context,
+                                 const VARectangle *src_region,
+                                 const VARectangle *dst_region,
+                                 struct pipe_video_buffer *src,
+                                 struct pipe_video_buffer *dst,
+                                 enum vl_compositor_deinterlace deinterlace,
+                                 VAProcPipelineParameterBuffer* param)
+{
+   if (deinterlace != VL_COMPOSITOR_NONE)
+      return VA_STATUS_ERROR_UNIMPLEMENTED;
+
+   if (src->buffer_format != PIPE_FORMAT_NV12 ||
+       dst->buffer_format != PIPE_FORMAT_NV12)
+      return VA_STATUS_ERROR_UNIMPLEMENTED;
+
+   struct u_rect src_rect;
+   struct u_rect dst_rect;
+
+   src_rect.x0 = src_region->x;
+   src_rect.y0 = src_region->y;
+   src_rect.x1 = src_region->x + src_region->width;
+   src_rect.y1 = src_region->y + src_region->height;
+
+   dst_rect.x0 = dst_region->x;
+   dst_rect.y0 = dst_region->y;
+   dst_rect.x1 = dst_region->x + dst_region->width;
+   dst_rect.y1 = dst_region->y + dst_region->height;
+
+   context->desc.vidproc.base.input_format = src->buffer_format;
+   context->desc.vidproc.base.output_format = dst->buffer_format;
+
+   context->desc.vidproc.src_region = src_rect;
+   context->desc.vidproc.dst_region = dst_rect;
+
+   if (param->rotation_state == VA_ROTATION_NONE)
+      context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ORIENTATION_DEFAULT;
+   else if (param->rotation_state == VA_ROTATION_90)
+      context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_90;
+   else if (param->rotation_state == VA_ROTATION_180)
+      context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_180;
+   else if (param->rotation_state == VA_ROTATION_270)
+      context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_270;
+
+   if (param->mirror_state == VA_MIRROR_HORIZONTAL)
+      context->desc.vidproc.orientation |= PIPE_VIDEO_VPP_FLIP_HORIZONTAL;
+   if (param->mirror_state == VA_MIRROR_VERTICAL)
+      context->desc.vidproc.orientation |= PIPE_VIDEO_VPP_FLIP_VERTICAL;
+
+   memset(&context->desc.vidproc.blend, 0, sizeof(context->desc.vidproc.blend));
+   context->desc.vidproc.blend.mode = PIPE_VIDEO_VPP_BLEND_MODE_NONE;
+   if (param->blend_state != NULL) {
+      if (param->blend_state->flags & VA_BLEND_GLOBAL_ALPHA) {
+         context->desc.vidproc.blend.mode = PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA;
+         context->desc.vidproc.blend.global_alpha = param->blend_state->global_alpha;
+      }
+   }
+
+   if (context->needs_begin_frame) {
+      context->decoder->begin_frame(context->decoder, dst,
+                                    &context->desc.base);
+      context->needs_begin_frame = false;
+   }
+   context->decoder->process_frame(context->decoder, src, &context->desc.vidproc);
+   context->vpp_needs_flush_on_endpic = true;
+
+   return VA_STATUS_SUCCESS;
+}
+
 static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,
                                  const VARectangle *src_region,
                                  const VARectangle *dst_region,
@@ -402,6 +470,26 @@ vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *contex
    src_region = vlVaRegionDefault(param->surface_region, src_surface, &def_src_region);
    dst_region = vlVaRegionDefault(param->output_region, dst_surface, &def_dst_region);
 
+   /* If the driver supports video engine post proc, attempt to do that
+    * if it fails, fallback to the other existing implementations below
+    */
+   if (pscreen->get_video_param(pscreen,
+                                PIPE_VIDEO_PROFILE_UNKNOWN,
+                                PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                PIPE_VIDEO_CAP_SUPPORTED)) {
+      if (!context->decoder) {
+         context->decoder = drv->pipe->create_video_codec(drv->pipe, &context->templat);
+         if (!context->decoder)
+            return VA_STATUS_ERROR_ALLOCATION_FAILED;
+      }
+
+      /* Perform VPBlit, if fail, fallback to other implementations below */
+      if (VA_STATUS_SUCCESS == vlVaVidEngineBlit(drv, context, src_region, dst_region,
+                                                 src, context->target, deinterlace, param))
+         return VA_STATUS_SUCCESS;
+   }
+
+   /* Try other post proc implementations */
    if (context->target->buffer_format != PIPE_FORMAT_NV12 &&
        context->target->buffer_format != PIPE_FORMAT_P010 &&
        context->target->buffer_format != PIPE_FORMAT_P016)
diff --git a/src/gallium/frontends/va/surface.c b/src/gallium/frontends/va/surface.c
index 47e916652ca..4441c0b1908 100755
--- a/src/gallium/frontends/va/surface.c
+++ b/src/gallium/frontends/va/surface.c
@@ -523,7 +523,12 @@ vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id,
    }
 #endif
 
-   if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
+   /* If VPP supported entry, use the max dimensions cap values, if not fallback to this below */
+   if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_PROCESSING ||
+       pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                PIPE_VIDEO_CAP_SUPPORTED))
+   {
       attribs[i].type = VASurfaceAttribMaxWidth;
       attribs[i].value.type = VAGenericValueTypeInteger;
       attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
@@ -1146,6 +1151,66 @@ vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
    pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards);
    pipeline_cap->output_color_standards = vpp_output_color_standards;
 
+   struct pipe_screen *pscreen = VL_VA_PSCREEN(ctx);
+   uint32_t pipe_orientation_flags = pscreen->get_video_param(pscreen,
+                                                              PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                              PIPE_VIDEO_CAP_VPP_ORIENTATION_MODES);
+
+   pipeline_cap->rotation_flags = VA_ROTATION_NONE;
+   if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_90)
+      pipeline_cap->rotation_flags |= (1 << VA_ROTATION_90);
+   if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_180)
+      pipeline_cap->rotation_flags |= (1 << VA_ROTATION_180);
+   if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_270)
+      pipeline_cap->rotation_flags |= (1 << VA_ROTATION_270);
+
+   pipeline_cap->mirror_flags = VA_MIRROR_NONE;
+   if(pipe_orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL)
+      pipeline_cap->mirror_flags |= VA_MIRROR_HORIZONTAL;
+   if(pipe_orientation_flags & PIPE_VIDEO_VPP_FLIP_VERTICAL)
+      pipeline_cap->mirror_flags |= VA_MIRROR_VERTICAL;
+
+   pipeline_cap->max_input_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                            PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                            PIPE_VIDEO_CAP_VPP_MAX_INPUT_WIDTH);
+
+   pipeline_cap->max_input_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                             PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                             PIPE_VIDEO_CAP_VPP_MAX_INPUT_HEIGHT);
+
+   pipeline_cap->min_input_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                            PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                            PIPE_VIDEO_CAP_VPP_MIN_INPUT_WIDTH);
+
+   pipeline_cap->min_input_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                             PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                             PIPE_VIDEO_CAP_VPP_MIN_INPUT_HEIGHT);
+
+   pipeline_cap->max_output_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                             PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                             PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_WIDTH);
+
+   pipeline_cap->max_output_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                              PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_HEIGHT);
+
+   pipeline_cap->min_output_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                             PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                             PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_WIDTH);
+
+   pipeline_cap->min_output_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                              PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_HEIGHT);
+
+   uint32_t pipe_blend_modes = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
+                                                        PIPE_VIDEO_ENTRYPOINT_PROCESSING,
+                                                        PIPE_VIDEO_CAP_VPP_BLEND_MODES);
+
+   pipeline_cap->blend_flags = 0;
+   if (pipe_blend_modes & PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA)
+      pipeline_cap->blend_flags |= VA_BLEND_GLOBAL_ALPHA;
+
    for (i = 0; i < num_filters; i++) {
       vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]);
       VAProcFilterParameterBufferBase *filter;
diff --git a/src/gallium/frontends/va/va_private.h b/src/gallium/frontends/va/va_private.h
index 149cfa2d961..15222ac4d73 100755
--- a/src/gallium/frontends/va/va_private.h
+++ b/src/gallium/frontends/va/va_private.h
@@ -293,6 +293,7 @@ typedef struct {
       struct pipe_av1_picture_desc av1;
       struct pipe_h264_enc_picture_desc h264enc;
       struct pipe_h265_enc_picture_desc h265enc;
+      struct pipe_vpp_desc vidproc;
    } desc;
 
    struct {
@@ -317,6 +318,7 @@ typedef struct {
    bool first_single_submitted;
    int gop_coeff;
    bool needs_begin_frame;
+   bool vpp_needs_flush_on_endpic;
    void *blit_cs;
    int packed_header_type;
 } vlVaContext;



More information about the mesa-commit mailing list