diff options
author | Thomas Hellstrom <[email protected]> | 2016-03-03 09:25:44 +0100 |
---|---|---|
committer | Thomas Hellstrom <[email protected]> | 2017-02-24 16:44:33 +0100 |
commit | 3a418322ec6d540b1334f42688839aefb5d88d6d (patch) | |
tree | 803c0fe0488406a45ed151f0abee4cf6af5d7e8a /src/gallium/state_trackers/vdpau/surface.c | |
parent | 5398d006de3d2bd668e3fc4b80a3de0c101a3e43 (diff) |
st/vdpau: Provide YV12 to NV12 putBits conversion v2
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 <[email protected]>
Acked-by: Christian König <[email protected]>
Signed-off-by: Thomas Hellstrom <[email protected]>
Diffstat (limited to 'src/gallium/state_trackers/vdpau/surface.c')
-rw-r--r-- | src/gallium/state_trackers/vdpau/surface.c | 94 |
1 files changed, 75 insertions, 19 deletions
diff --git a/src/gallium/state_trackers/vdpau/surface.c b/src/gallium/state_trackers/vdpau/surface.c index 9a80605e24c..e0dff4e90cb 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); |