diff options
-rw-r--r-- | src/gallium/auxiliary/util/u_video.h | 42 | ||||
-rw-r--r-- | src/gallium/state_trackers/vdpau/query.c | 13 | ||||
-rw-r--r-- | 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 99a8fd6e4f3..7cd6268d1fc 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 e69c9b11f55..435cafd4041 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 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); |