• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4  * Copyright 2014 Advanced Micro Devices, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #include "pipe/p_screen.h"
30 
31 #include "util/u_memory.h"
32 #include "util/u_handle_table.h"
33 #include "util/u_surface.h"
34 #include "util/u_video.h"
35 #include "util/u_process.h"
36 
37 #include "vl/vl_winsys.h"
38 #include "vl/vl_video_buffer.h"
39 
40 #include "va_private.h"
41 
42 static const VAImageFormat formats[] =
43 {
44    {VA_FOURCC('N','V','1','2')},
45    {VA_FOURCC('P','0','1','0')},
46    {VA_FOURCC('P','0','1','6')},
47    {VA_FOURCC('I','4','2','0')},
48    {VA_FOURCC('Y','V','1','2')},
49    {VA_FOURCC('Y','U','Y','V')},
50    {VA_FOURCC('Y','U','Y','2')},
51    {VA_FOURCC('U','Y','V','Y')},
52    {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
53     0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
54    {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
55     0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
56    {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
57     0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
58    {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
59     0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
60 };
61 
62 static void
vlVaVideoSurfaceSize(vlVaSurface * p_surf,int component,unsigned * width,unsigned * height)63 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
64                      unsigned *width, unsigned *height)
65 {
66    *width = p_surf->templat.width;
67    *height = p_surf->templat.height;
68 
69    vl_video_buffer_adjust_size(width, height, component,
70                                pipe_format_to_chroma_format(p_surf->templat.buffer_format),
71                                p_surf->templat.interlaced);
72 }
73 
74 VAStatus
vlVaQueryImageFormats(VADriverContextP ctx,VAImageFormat * format_list,int * num_formats)75 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
76 {
77    struct pipe_screen *pscreen;
78    enum pipe_format format;
79    int i;
80 
81    STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
82 
83    if (!ctx)
84       return VA_STATUS_ERROR_INVALID_CONTEXT;
85 
86    if (!(format_list && num_formats))
87       return VA_STATUS_ERROR_INVALID_PARAMETER;
88 
89    *num_formats = 0;
90    pscreen = VL_VA_PSCREEN(ctx);
91    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
92       format = VaFourccToPipeFormat(formats[i].fourcc);
93       if (pscreen->is_video_format_supported(pscreen, format,
94           PIPE_VIDEO_PROFILE_UNKNOWN,
95           PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
96          format_list[(*num_formats)++] = formats[i];
97    }
98 
99    return VA_STATUS_SUCCESS;
100 }
101 
102 VAStatus
vlVaCreateImage(VADriverContextP ctx,VAImageFormat * format,int width,int height,VAImage * image)103 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
104 {
105    VAStatus status;
106    vlVaDriver *drv;
107    VAImage *img;
108    int w, h;
109 
110    if (!ctx)
111       return VA_STATUS_ERROR_INVALID_CONTEXT;
112 
113    if (!(format && image && width && height))
114       return VA_STATUS_ERROR_INVALID_PARAMETER;
115 
116    drv = VL_VA_DRIVER(ctx);
117 
118    img = CALLOC(1, sizeof(VAImage));
119    if (!img)
120       return VA_STATUS_ERROR_ALLOCATION_FAILED;
121    mtx_lock(&drv->mutex);
122    img->image_id = handle_table_add(drv->htab, img);
123    mtx_unlock(&drv->mutex);
124 
125    img->format = *format;
126    img->width = width;
127    img->height = height;
128    w = align(width, 2);
129    h = align(height, 2);
130 
131    switch (format->fourcc) {
132    case VA_FOURCC('N','V','1','2'):
133       img->num_planes = 2;
134       img->pitches[0] = w;
135       img->offsets[0] = 0;
136       img->pitches[1] = w;
137       img->offsets[1] = w * h;
138       img->data_size  = w * h * 3 / 2;
139       break;
140 
141    case VA_FOURCC('P','0','1','0'):
142    case VA_FOURCC('P','0','1','6'):
143       img->num_planes = 2;
144       img->pitches[0] = w * 2;
145       img->offsets[0] = 0;
146       img->pitches[1] = w * 2;
147       img->offsets[1] = w * h * 2;
148       img->data_size  = w * h * 3;
149       break;
150 
151    case VA_FOURCC('I','4','2','0'):
152    case VA_FOURCC('Y','V','1','2'):
153       img->num_planes = 3;
154       img->pitches[0] = w;
155       img->offsets[0] = 0;
156       img->pitches[1] = w / 2;
157       img->offsets[1] = w * h;
158       img->pitches[2] = w / 2;
159       img->offsets[2] = w * h * 5 / 4;
160       img->data_size  = w * h * 3 / 2;
161       break;
162 
163    case VA_FOURCC('U','Y','V','Y'):
164    case VA_FOURCC('Y','U','Y','V'):
165    case VA_FOURCC('Y','U','Y','2'):
166       img->num_planes = 1;
167       img->pitches[0] = w * 2;
168       img->offsets[0] = 0;
169       img->data_size  = w * h * 2;
170       break;
171 
172    case VA_FOURCC('B','G','R','A'):
173    case VA_FOURCC('R','G','B','A'):
174    case VA_FOURCC('B','G','R','X'):
175    case VA_FOURCC('R','G','B','X'):
176       img->num_planes = 1;
177       img->pitches[0] = w * 4;
178       img->offsets[0] = 0;
179       img->data_size  = w * h * 4;
180       break;
181 
182    default:
183       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
184    }
185 
186    status =  vlVaCreateBuffer(ctx, 0, VAImageBufferType,
187                            align(img->data_size, 16),
188                            1, NULL, &img->buf);
189    if (status != VA_STATUS_SUCCESS)
190       return status;
191    *image = *img;
192 
193    return status;
194 }
195 
196 VAStatus
vlVaDeriveImage(VADriverContextP ctx,VASurfaceID surface,VAImage * image)197 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
198 {
199    vlVaDriver *drv;
200    vlVaSurface *surf;
201    vlVaBuffer *img_buf;
202    VAImage *img;
203    struct pipe_screen *screen;
204    struct pipe_surface **surfaces;
205    struct pipe_video_buffer *new_buffer = NULL;
206    int w;
207    int h;
208    int i;
209    unsigned stride = 0;
210    unsigned offset = 0;
211 
212    /* This function is used by some programs to test for hardware decoding, but on
213     * AMD devices, the buffers default to interlaced, which causes this function to fail.
214     * Some programs expect this function to fail, while others, assume this means
215     * hardware acceleration is not available and give up without trying the fall-back
216     * vaCreateImage + vaPutImage
217     */
218    const char *proc = util_get_process_name();
219    const char *derive_interlaced_allowlist[] = {
220          "vlc",
221    };
222 
223    if (!ctx)
224       return VA_STATUS_ERROR_INVALID_CONTEXT;
225 
226    drv = VL_VA_DRIVER(ctx);
227 
228    if (!drv)
229       return VA_STATUS_ERROR_INVALID_CONTEXT;
230 
231    screen = VL_VA_PSCREEN(ctx);
232 
233    if (!screen)
234       return VA_STATUS_ERROR_INVALID_CONTEXT;
235 
236    surf = handle_table_get(drv->htab, surface);
237 
238    if (!surf || !surf->buffer)
239       return VA_STATUS_ERROR_INVALID_SURFACE;
240 
241    if (surf->buffer->interlaced) {
242       for (i = 0; i < ARRAY_SIZE(derive_interlaced_allowlist); i++)
243          if ((strcmp(derive_interlaced_allowlist[i], proc) == 0))
244             break;
245 
246       if (i >= ARRAY_SIZE(derive_interlaced_allowlist))
247          return VA_STATUS_ERROR_OPERATION_FAILED;
248 
249       if (!screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
250                                    PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE))
251          return VA_STATUS_ERROR_OPERATION_FAILED;
252    }
253 
254    surfaces = surf->buffer->get_surfaces(surf->buffer);
255    if (!surfaces || !surfaces[0]->texture)
256       return VA_STATUS_ERROR_ALLOCATION_FAILED;
257 
258    img = CALLOC(1, sizeof(VAImage));
259    if (!img)
260       return VA_STATUS_ERROR_ALLOCATION_FAILED;
261 
262    img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
263    img->buf = VA_INVALID_ID;
264    /* Use the visible dimensions. */
265    img->width = surf->templat.width;
266    img->height = surf->templat.height;
267    img->num_palette_entries = 0;
268    img->entry_bytes = 0;
269    /* Image data size is computed using internal dimensions. */
270    w = align(surf->buffer->width, 2);
271    h = align(surf->buffer->height, 2);
272 
273    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
274       if (img->format.fourcc == formats[i].fourcc) {
275          img->format = formats[i];
276          break;
277       }
278    }
279 
280    mtx_lock(&drv->mutex);
281    if (screen->resource_get_info) {
282       screen->resource_get_info(screen, surfaces[0]->texture, &stride,
283                                 &offset);
284       if (!stride)
285          offset = 0;
286    }
287 
288    img->num_planes = 1;
289    img->offsets[0] = offset;
290 
291    switch (img->format.fourcc) {
292    case VA_FOURCC('U','Y','V','Y'):
293    case VA_FOURCC('Y','U','Y','V'):
294       img->pitches[0] = stride > 0 ? stride : w * 2;
295       assert(img->pitches[0] >= (w * 2));
296       img->data_size  = img->pitches[0] * h;
297       break;
298 
299    case VA_FOURCC('B','G','R','A'):
300    case VA_FOURCC('R','G','B','A'):
301    case VA_FOURCC('B','G','R','X'):
302    case VA_FOURCC('R','G','B','X'):
303       img->pitches[0] = stride > 0 ? stride : w * 4;
304       assert(img->pitches[0] >= (w * 4));
305       img->data_size  = img->pitches[0] * h;
306       break;
307 
308    case VA_FOURCC('N','V','1','2'):
309    case VA_FOURCC('P','0','1','0'):
310    case VA_FOURCC('P','0','1','6'):
311       if (surf->buffer->interlaced) {
312          struct u_rect src_rect, dst_rect;
313          struct pipe_video_buffer new_template;
314 
315          new_template = surf->templat;
316          new_template.interlaced = false;
317          new_buffer = drv->pipe->create_video_buffer(drv->pipe, &new_template);
318 
319          /* not all devices support non-interlaced buffers */
320          if (!new_buffer) {
321             FREE(img);
322             mtx_unlock(&drv->mutex);
323             return VA_STATUS_ERROR_OPERATION_FAILED;
324          }
325 
326          /* convert the interlaced to the progressive */
327          src_rect.x0 = dst_rect.x0 = 0;
328          src_rect.x1 = dst_rect.x1 = surf->templat.width;
329          src_rect.y0 = dst_rect.y0 = 0;
330          src_rect.y1 = dst_rect.y1 = surf->templat.height;
331 
332          vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
333                            surf->buffer, new_buffer,
334                            &src_rect, &dst_rect,
335                            VL_COMPOSITOR_WEAVE);
336 
337          /* recalculate the values now that we have a new surface */
338          surfaces = surf->buffer->get_surfaces(new_buffer);
339          if (screen->resource_get_info) {
340             screen->resource_get_info(screen, surfaces[0]->texture, &stride,
341                                     &offset);
342             if (!stride)
343                offset = 0;
344          }
345 
346          w = align(new_buffer->width, 2);
347          h = align(new_buffer->height, 2);
348       }
349 
350       img->num_planes = 2;
351       img->pitches[0] = stride > 0 ? stride : w;
352       img->pitches[1] = stride > 0 ? stride : w;
353       img->offsets[1] = (stride > 0 ? stride : w) * h;
354       img->data_size  = (stride > 0 ? stride : w) * h * 3 / 2;
355       break;
356 
357    default:
358       /* VaDeriveImage only supports contiguous planes. But there is now a
359          more generic api vlVaExportSurfaceHandle. */
360       FREE(img);
361       mtx_unlock(&drv->mutex);
362       return VA_STATUS_ERROR_OPERATION_FAILED;
363    }
364 
365    img_buf = CALLOC(1, sizeof(vlVaBuffer));
366    if (!img_buf) {
367       FREE(img);
368       mtx_unlock(&drv->mutex);
369       return VA_STATUS_ERROR_ALLOCATION_FAILED;
370    }
371 
372    img->image_id = handle_table_add(drv->htab, img);
373 
374    img_buf->type = VAImageBufferType;
375    img_buf->size = img->data_size;
376    img_buf->num_elements = 1;
377 
378    pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
379    img_buf->derived_image_buffer = new_buffer;
380 
381    img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
382    mtx_unlock(&drv->mutex);
383 
384    *image = *img;
385 
386    return VA_STATUS_SUCCESS;
387 }
388 
389 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)390 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
391 {
392    vlVaDriver *drv;
393    VAImage  *vaimage;
394    VAStatus status;
395 
396    if (!ctx)
397       return VA_STATUS_ERROR_INVALID_CONTEXT;
398 
399    drv = VL_VA_DRIVER(ctx);
400    mtx_lock(&drv->mutex);
401    vaimage = handle_table_get(drv->htab, image);
402    if (!vaimage) {
403       mtx_unlock(&drv->mutex);
404       return VA_STATUS_ERROR_INVALID_IMAGE;
405    }
406 
407    handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
408    mtx_unlock(&drv->mutex);
409    status = vlVaDestroyBuffer(ctx, vaimage->buf);
410    FREE(vaimage);
411    return status;
412 }
413 
414 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)415 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
416 {
417    if (!ctx)
418       return VA_STATUS_ERROR_INVALID_CONTEXT;
419 
420    return VA_STATUS_ERROR_UNIMPLEMENTED;
421 }
422 
423 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)424 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
425              unsigned int width, unsigned int height, VAImageID image)
426 {
427    vlVaDriver *drv;
428    vlVaSurface *surf;
429    vlVaBuffer *img_buf;
430    VAImage *vaimage;
431    struct pipe_sampler_view **views;
432    enum pipe_format format;
433    bool convert = false;
434    void *data[3];
435    unsigned pitches[3], i, j;
436 
437    if (!ctx)
438       return VA_STATUS_ERROR_INVALID_CONTEXT;
439 
440    drv = VL_VA_DRIVER(ctx);
441 
442    mtx_lock(&drv->mutex);
443    surf = handle_table_get(drv->htab, surface);
444    if (!surf || !surf->buffer) {
445       mtx_unlock(&drv->mutex);
446       return VA_STATUS_ERROR_INVALID_SURFACE;
447    }
448 
449    vaimage = handle_table_get(drv->htab, image);
450    if (!vaimage) {
451       mtx_unlock(&drv->mutex);
452       return VA_STATUS_ERROR_INVALID_IMAGE;
453    }
454 
455    if (x < 0 || y < 0) {
456       mtx_unlock(&drv->mutex);
457       return VA_STATUS_ERROR_INVALID_PARAMETER;
458    }
459 
460    if (x + width > surf->templat.width ||
461        y + height > surf->templat.height) {
462       mtx_unlock(&drv->mutex);
463       return VA_STATUS_ERROR_INVALID_PARAMETER;
464    }
465 
466    if (width > vaimage->width ||
467        height > vaimage->height) {
468       mtx_unlock(&drv->mutex);
469       return VA_STATUS_ERROR_INVALID_PARAMETER;
470    }
471 
472    img_buf = handle_table_get(drv->htab, vaimage->buf);
473    if (!img_buf) {
474       mtx_unlock(&drv->mutex);
475       return VA_STATUS_ERROR_INVALID_BUFFER;
476    }
477 
478    format = VaFourccToPipeFormat(vaimage->format.fourcc);
479    if (format == PIPE_FORMAT_NONE) {
480       mtx_unlock(&drv->mutex);
481       return VA_STATUS_ERROR_OPERATION_FAILED;
482    }
483 
484 
485    if (format != surf->buffer->buffer_format) {
486       /* support NV12 to YV12 and IYUV conversion now only */
487       if ((format == PIPE_FORMAT_YV12 &&
488          surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
489          (format == PIPE_FORMAT_IYUV &&
490          surf->buffer->buffer_format == PIPE_FORMAT_NV12))
491          convert = true;
492       else if (format == PIPE_FORMAT_NV12 &&
493          (surf->buffer->buffer_format == PIPE_FORMAT_P010 ||
494           surf->buffer->buffer_format == PIPE_FORMAT_P016)) {
495          mtx_unlock(&drv->mutex);
496          return VA_STATUS_ERROR_OPERATION_FAILED;
497       }
498       else {
499          mtx_unlock(&drv->mutex);
500          return VA_STATUS_ERROR_OPERATION_FAILED;
501       }
502    }
503 
504    views = surf->buffer->get_sampler_view_planes(surf->buffer);
505    if (!views) {
506       mtx_unlock(&drv->mutex);
507       return VA_STATUS_ERROR_OPERATION_FAILED;
508    }
509 
510    for (i = 0; i < vaimage->num_planes; i++) {
511       data[i] = img_buf->data + vaimage->offsets[i];
512       pitches[i] = vaimage->pitches[i];
513    }
514    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
515       void *tmp_d;
516       unsigned tmp_p;
517       tmp_d  = data[1];
518       data[1] = data[2];
519       data[2] = tmp_d;
520       tmp_p = pitches[1];
521       pitches[1] = pitches[2];
522       pitches[2] = tmp_p;
523    }
524 
525    for (i = 0; i < vaimage->num_planes; i++) {
526       unsigned box_w = align(width, 2);
527       unsigned box_h = align(height, 2);
528       unsigned box_x = x & ~1;
529       unsigned box_y = y & ~1;
530       if (!views[i]) continue;
531       vl_video_buffer_adjust_size(&box_w, &box_h, i,
532                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
533                                   surf->templat.interlaced);
534       vl_video_buffer_adjust_size(&box_x, &box_y, i,
535                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
536                                   surf->templat.interlaced);
537       for (j = 0; j < views[i]->texture->array_size; ++j) {
538          struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1};
539          struct pipe_transfer *transfer;
540          uint8_t *map;
541          map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
542                   PIPE_MAP_READ, &box, &transfer);
543          if (!map) {
544             mtx_unlock(&drv->mutex);
545             return VA_STATUS_ERROR_OPERATION_FAILED;
546          }
547 
548          if (i == 1 && convert) {
549             u_copy_nv12_to_yv12(data, pitches, i, j,
550                transfer->stride, views[i]->texture->array_size,
551                map, box.width, box.height);
552          } else {
553             util_copy_rect(data[i] + pitches[i] * j,
554                views[i]->texture->format,
555                pitches[i] * views[i]->texture->array_size, 0, 0,
556                box.width, box.height, map, transfer->stride, 0, 0);
557          }
558          pipe_transfer_unmap(drv->pipe, transfer);
559       }
560    }
561    mtx_unlock(&drv->mutex);
562 
563    return VA_STATUS_SUCCESS;
564 }
565 
566 VAStatus
vlVaPutImage(VADriverContextP ctx,VASurfaceID surface,VAImageID image,int src_x,int src_y,unsigned int src_width,unsigned int src_height,int dest_x,int dest_y,unsigned int dest_width,unsigned int dest_height)567 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
568              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
569              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
570 {
571    vlVaDriver *drv;
572    vlVaSurface *surf;
573    vlVaBuffer *img_buf;
574    VAImage *vaimage;
575    struct pipe_sampler_view **views;
576    enum pipe_format format;
577    void *data[3];
578    unsigned pitches[3], i, j;
579 
580    if (!ctx)
581       return VA_STATUS_ERROR_INVALID_CONTEXT;
582 
583    drv = VL_VA_DRIVER(ctx);
584    mtx_lock(&drv->mutex);
585 
586    surf = handle_table_get(drv->htab, surface);
587    if (!surf || !surf->buffer) {
588       mtx_unlock(&drv->mutex);
589       return VA_STATUS_ERROR_INVALID_SURFACE;
590    }
591 
592    vaimage = handle_table_get(drv->htab, image);
593    if (!vaimage) {
594       mtx_unlock(&drv->mutex);
595       return VA_STATUS_ERROR_INVALID_IMAGE;
596    }
597 
598    img_buf = handle_table_get(drv->htab, vaimage->buf);
599    if (!img_buf) {
600       mtx_unlock(&drv->mutex);
601       return VA_STATUS_ERROR_INVALID_BUFFER;
602    }
603 
604    if (img_buf->derived_surface.resource) {
605       /* Attempting to transfer derived image to surface */
606       mtx_unlock(&drv->mutex);
607       return VA_STATUS_ERROR_UNIMPLEMENTED;
608    }
609 
610    format = VaFourccToPipeFormat(vaimage->format.fourcc);
611 
612    if (format == PIPE_FORMAT_NONE) {
613       mtx_unlock(&drv->mutex);
614       return VA_STATUS_ERROR_OPERATION_FAILED;
615    }
616 
617    if ((format != surf->buffer->buffer_format) &&
618          ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
619          ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
620       struct pipe_video_buffer *tmp_buf;
621 
622       surf->templat.buffer_format = format;
623       if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
624           format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
625           format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
626          surf->templat.interlaced = false;
627       tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
628 
629       if (!tmp_buf) {
630          mtx_unlock(&drv->mutex);
631          return VA_STATUS_ERROR_ALLOCATION_FAILED;
632       }
633 
634       surf->buffer->destroy(surf->buffer);
635       surf->buffer = tmp_buf;
636    }
637 
638    views = surf->buffer->get_sampler_view_planes(surf->buffer);
639    if (!views) {
640       mtx_unlock(&drv->mutex);
641       return VA_STATUS_ERROR_OPERATION_FAILED;
642    }
643 
644    for (i = 0; i < vaimage->num_planes; i++) {
645       data[i] = img_buf->data + vaimage->offsets[i];
646       pitches[i] = vaimage->pitches[i];
647    }
648    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
649       void *tmp_d;
650       unsigned tmp_p;
651       tmp_d  = data[1];
652       data[1] = data[2];
653       data[2] = tmp_d;
654       tmp_p = pitches[1];
655       pitches[1] = pitches[2];
656       pitches[2] = tmp_p;
657    }
658 
659    for (i = 0; i < vaimage->num_planes; ++i) {
660       unsigned width, height;
661       struct pipe_resource *tex;
662 
663       if (!views[i]) continue;
664       tex = views[i]->texture;
665 
666       vlVaVideoSurfaceSize(surf, i, &width, &height);
667       for (j = 0; j < tex->array_size; ++j) {
668          struct pipe_box dst_box = {0, 0, j, width, height, 1};
669 
670          if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
671              && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
672              && i == 1) {
673             struct pipe_transfer *transfer = NULL;
674             uint8_t *map = NULL;
675 
676             map = drv->pipe->transfer_map(drv->pipe,
677                                           tex,
678                                           0,
679                                           PIPE_MAP_WRITE |
680                                           PIPE_MAP_DISCARD_RANGE,
681                                           &dst_box, &transfer);
682             if (map == NULL) {
683                mtx_unlock(&drv->mutex);
684                return VA_STATUS_ERROR_OPERATION_FAILED;
685             }
686 
687             u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
688                                   transfer->stride, tex->array_size,
689                                   map, dst_box.width, dst_box.height);
690             pipe_transfer_unmap(drv->pipe, transfer);
691          } else {
692             drv->pipe->texture_subdata(drv->pipe, tex, 0,
693                                        PIPE_MAP_WRITE, &dst_box,
694                                        data[i] + pitches[i] * j,
695                                        pitches[i] * views[i]->texture->array_size, 0);
696          }
697       }
698    }
699    mtx_unlock(&drv->mutex);
700 
701    return VA_STATUS_SUCCESS;
702 }
703