}
}
+/**
+ * \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,
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)
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);
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);