[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