[Mesa-dev] [PATCH 1/2] st/vdpau: Provide YV12 to NV12 putBits conversion v2

Christian König deathsimple at vodafone.de
Fri Feb 24 14:45:01 UTC 2017


Am 22.02.2017 um 16:25 schrieb Thomas Hellstrom:
> mplayer likes putting YV12 data, and if there is a buffer format mismatch,
> the vdpau state tracker would try to reallocate the video surface as an
> YV12 surface. A virtual driver doesn't like reallocating and doesn't like YV12
> surfaces, so if we can't support YV12, try an YV12 to NV12 conversion
> instead.
>
> Also advertize that we actually can do the getBits and putBits conversion.
>
> v2: A previous version of this patch prioritized conversion before
> reallocating. This has been changed to prioritize reallocating in this version.
>
> Cc: Christian König <cthristian.koenig at amd.com>
> Signed-off-by: Thomas Hellstrom <thellstrom at vmware.com>

Acked-by: Christian König <christian.koenig at amd.com> for both patches.

> ---
>   src/gallium/auxiliary/util/u_video.h       | 42 +++++++++++++
>   src/gallium/state_trackers/vdpau/query.c   | 13 +++++
>   src/gallium/state_trackers/vdpau/surface.c | 94 ++++++++++++++++++++++++------
>   3 files changed, 130 insertions(+), 19 deletions(-)
>
> diff --git a/src/gallium/auxiliary/util/u_video.h b/src/gallium/auxiliary/util/u_video.h
> index 99a8fd6..7cd6268 100644
> --- a/src/gallium/auxiliary/util/u_video.h
> +++ b/src/gallium/auxiliary/util/u_video.h
> @@ -107,6 +107,48 @@ u_copy_nv12_to_yv12(void *const *destination_data,
>      }
>   }
>   
> +/**
> + * \brief  Copy YV12 chroma data while converting it NV12
> + *
> + * Given a set of YV12 source pointers and -pitches, copy the data to a
> + * layout typical for NV12 video buffers.
> + *
> + * \param source data[in]  The plane data pointers. Array of 3.
> + * \param source_pitches[in]  The plane pitches. Array of 3.
> + * \param dst_plane[in]  The destination plane to copy to. For NV12 always 1.
> + * \param dst_field[in]  The destination field if interlaced.
> + * \param dst_stride[in]  The destination stride for this plane.
> + * \param num_fields[in]  The number of fields in the video buffer.
> + * \param dst[in]  The destination plane pointer.
> + * \param width[in]  The source plane width.
> + * \param height[in]  The source plane height.
> + */
> +static inline void
> +u_copy_nv12_from_yv12(const void *const *source_data,
> +                      uint32_t const *source_pitches,
> +                      int dst_plane, int dst_field,
> +                      int dst_stride, int num_fields,
> +                      uint8_t *dst,
> +                      int width, int height)
> +{
> +   int x, y;
> +   unsigned u_stride = source_pitches[2] * num_fields;
> +   unsigned v_stride = source_pitches[1] * num_fields;
> +   uint8_t *u_src = (uint8_t *)source_data[2] + source_pitches[2] * dst_field;
> +   uint8_t *v_src = (uint8_t *)source_data[1] + source_pitches[1] * dst_field;
> +
> +   /* TODO: SIMD */
> +   for (y = 0; y < height; y++) {
> +      for (x = 0; x < width; x++) {
> +         dst[2*x] = u_src[x];
> +         dst[2*x+1] = v_src[x];
> +      }
> +      u_src += u_stride;
> +      v_src += v_stride;
> +      dst += dst_stride;
> +   }
> +}
> +
>   static inline void
>   u_copy_yv12_to_nv12(void *const *destination_data,
>                       uint32_t const *destination_pitches,
> diff --git a/src/gallium/state_trackers/vdpau/query.c b/src/gallium/state_trackers/vdpau/query.c
> index e69c9b1..435cafd 100644
> --- a/src/gallium/state_trackers/vdpau/query.c
> +++ b/src/gallium/state_trackers/vdpau/query.c
> @@ -123,8 +123,21 @@ vlVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities(VdpDevice device, VdpChromaTyp
>   
>      switch(bits_ycbcr_format) {
>      case VDP_YCBCR_FORMAT_NV12:
> +      *is_supported = surface_chroma_type == VDP_CHROMA_TYPE_420;
> +      break;
> +
>      case VDP_YCBCR_FORMAT_YV12:
>         *is_supported = surface_chroma_type == VDP_CHROMA_TYPE_420;
> +
> +      /* We can convert YV12 to NV12 on the fly! */
> +      if (*is_supported &&
> +          pscreen->is_video_format_supported(pscreen,
> +                                             PIPE_FORMAT_NV12,
> +                                             PIPE_VIDEO_PROFILE_UNKNOWN,
> +                                             PIPE_VIDEO_ENTRYPOINT_BITSTREAM)) {
> +         pipe_mutex_unlock(dev->mutex);
> +         return VDP_STATUS_OK;
> +      }
>         break;
>   
>      case VDP_YCBCR_FORMAT_UYVY:
> diff --git a/src/gallium/state_trackers/vdpau/surface.c b/src/gallium/state_trackers/vdpau/surface.c
> index 9a80605..e0dff4e 100644
> --- a/src/gallium/state_trackers/vdpau/surface.c
> +++ b/src/gallium/state_trackers/vdpau/surface.c
> @@ -304,9 +304,11 @@ vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,
>                                 uint32_t const *source_pitches)
>   {
>      enum pipe_format pformat = FormatYCBCRToPipe(source_ycbcr_format);
> +   enum getbits_conversion conversion = CONVERSION_NONE;
>      struct pipe_context *pipe;
>      struct pipe_sampler_view **sampler_views;
>      unsigned i, j;
> +   unsigned usage = PIPE_TRANSFER_WRITE;
>   
>      vlVdpSurface *p_surf = vlGetDataHTAB(surface);
>      if (!p_surf)
> @@ -320,24 +322,53 @@ vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,
>          return VDP_STATUS_INVALID_POINTER;
>   
>      pipe_mutex_lock(p_surf->device->mutex);
> -   if (p_surf->video_buffer == NULL || pformat != p_surf->video_buffer->buffer_format) {
>   
> -      /* destroy the old one */
> -      if (p_surf->video_buffer)
> -         p_surf->video_buffer->destroy(p_surf->video_buffer);
> +   if (p_surf->video_buffer == NULL ||
> +       ((pformat != p_surf->video_buffer->buffer_format))) {
> +      enum pipe_format nformat = pformat;
> +      struct pipe_screen *screen = pipe->screen;
> +
> +      /* Determine the most suitable format for the new surface */
> +      if (!screen->is_video_format_supported(screen, nformat,
> +                                             PIPE_VIDEO_PROFILE_UNKNOWN,
> +                                             PIPE_VIDEO_ENTRYPOINT_BITSTREAM)) {
> +         nformat = screen->get_video_param(screen,
> +                                           PIPE_VIDEO_PROFILE_UNKNOWN,
> +                                           PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
> +                                           PIPE_VIDEO_CAP_PREFERED_FORMAT);
> +         if (nformat == PIPE_FORMAT_NONE) {
> +            pipe_mutex_unlock(p_surf->device->mutex);
> +            return VDP_STATUS_NO_IMPLEMENTATION;
> +         }
> +      }
>   
> -      /* adjust the template parameters */
> -      p_surf->templat.buffer_format = pformat;
> +      if (p_surf->video_buffer == NULL  ||
> +          nformat != p_surf->video_buffer->buffer_format) {
> +         /* destroy the old one */
> +         if (p_surf->video_buffer)
> +            p_surf->video_buffer->destroy(p_surf->video_buffer);
>   
> -      /* and try to create the video buffer with the new format */
> -      p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
> +         /* adjust the template parameters */
> +         p_surf->templat.buffer_format = nformat;
>   
> -      /* stil no luck? ok forget it we don't support it */
> -      if (!p_surf->video_buffer) {
> -         pipe_mutex_unlock(p_surf->device->mutex);
> -         return VDP_STATUS_NO_IMPLEMENTATION;
> +         /* and try to create the video buffer with the new format */
> +         p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
> +
> +         /* stil no luck? ok forget it we don't support it */
> +         if (!p_surf->video_buffer) {
> +            pipe_mutex_unlock(p_surf->device->mutex);
> +            return VDP_STATUS_NO_IMPLEMENTATION;
> +         }
> +         vlVdpVideoSurfaceClear(p_surf);
>         }
> -      vlVdpVideoSurfaceClear(p_surf);
> +   }
> +
> +   if (pformat != p_surf->video_buffer->buffer_format) {
> +      if (pformat == PIPE_FORMAT_YV12 &&
> +          p_surf->video_buffer->buffer_format == PIPE_FORMAT_NV12)
> +         conversion = CONVERSION_YV12_TO_NV12;
> +      else
> +         return VDP_STATUS_NO_IMPLEMENTATION;
>      }
>   
>      sampler_views = p_surf->video_buffer->get_sampler_view_planes(p_surf->video_buffer);
> @@ -349,21 +380,46 @@ vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,
>      for (i = 0; i < 3; ++i) {
>         unsigned width, height;
>         struct pipe_sampler_view *sv = sampler_views[i];
> +      struct pipe_resource *tex;
>         if (!sv || !source_pitches[i]) continue;
>   
> +      tex = sv->texture;
>         vlVdpVideoSurfaceSize(p_surf, i, &width, &height);
>   
> -      for (j = 0; j < sv->texture->array_size; ++j) {
> +      for (j = 0; j < tex->array_size; ++j) {
>            struct pipe_box dst_box = {
>               0, 0, j,
>               width, height, 1
>            };
>   
> -         pipe->texture_subdata(pipe, sv->texture, 0,
> -                               PIPE_TRANSFER_WRITE, &dst_box,
> -                               source_data[i] + source_pitches[i] * j,
> -                               source_pitches[i] * sv->texture->array_size,
> -                               0);
> +         if (conversion == CONVERSION_YV12_TO_NV12 && i == 1) {
> +            struct pipe_transfer *transfer;
> +            uint8_t *map;
> +
> +            map = pipe->transfer_map(pipe, tex, 0, usage,
> +                                     &dst_box, &transfer);
> +            if (!map) {
> +               pipe_mutex_unlock(p_surf->device->mutex);
> +               return VDP_STATUS_RESOURCES;
> +            }
> +
> +            u_copy_nv12_from_yv12(source_data, source_pitches,
> +                                  i, j, transfer->stride, tex->array_size,
> +                                  map, dst_box.width, dst_box.height);
> +
> +            pipe_transfer_unmap(pipe, transfer);
> +         } else {
> +            pipe->texture_subdata(pipe, tex, 0,
> +                                  PIPE_TRANSFER_WRITE, &dst_box,
> +                                  source_data[i] + source_pitches[i] * j,
> +                                  source_pitches[i] * tex->array_size,
> +                                  0);
> +         }
> +         /*
> +          * This surface has already been synced
> +          * by the first map.
> +          */
> +         usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
>         }
>      }
>      pipe_mutex_unlock(p_surf->device->mutex);




More information about the mesa-dev mailing list