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    VAStatus status;
204    struct pipe_screen *screen;
205    struct pipe_surface **surfaces;
206    struct pipe_video_buffer *new_buffer = NULL;
207    int w;
208    int h;
209    int i;
210    unsigned stride = 0;
211    unsigned offset = 0;
212 
213    /* This function is used by some programs to test for hardware decoding, but on
214     * AMD devices, the buffers default to interlaced, which causes this function to fail.
215     * Some programs expect this function to fail, while others, assume this means
216     * hardware acceleration is not available and give up without trying the fall-back
217     * vaCreateImage + vaPutImage
218     */
219    const char *proc = util_get_process_name();
220    const char *derive_interlaced_allowlist[] = {
221          "vlc",
222          "h264encode",
223          "hevcencode"
224    };
225 
226    if (!ctx)
227       return VA_STATUS_ERROR_INVALID_CONTEXT;
228 
229    drv = VL_VA_DRIVER(ctx);
230 
231    if (!drv)
232       return VA_STATUS_ERROR_INVALID_CONTEXT;
233 
234    screen = VL_VA_PSCREEN(ctx);
235 
236    if (!screen)
237       return VA_STATUS_ERROR_INVALID_CONTEXT;
238 
239    surf = handle_table_get(drv->htab, surface);
240 
241    if (!surf || !surf->buffer)
242       return VA_STATUS_ERROR_INVALID_SURFACE;
243 
244    if (surf->buffer->interlaced) {
245       for (i = 0; i < ARRAY_SIZE(derive_interlaced_allowlist); i++)
246          if ((strcmp(derive_interlaced_allowlist[i], proc) == 0))
247             break;
248 
249       if (i >= ARRAY_SIZE(derive_interlaced_allowlist) ||
250           !screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
251                                    PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
252                                    PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE))
253          return VA_STATUS_ERROR_OPERATION_FAILED;
254    }
255 
256    surfaces = surf->buffer->get_surfaces(surf->buffer);
257    if (!surfaces || !surfaces[0]->texture)
258       return VA_STATUS_ERROR_ALLOCATION_FAILED;
259 
260    img = CALLOC(1, sizeof(VAImage));
261    if (!img)
262       return VA_STATUS_ERROR_ALLOCATION_FAILED;
263 
264    img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
265    img->buf = VA_INVALID_ID;
266    /* Use the visible dimensions. */
267    img->width = surf->templat.width;
268    img->height = surf->templat.height;
269    img->num_palette_entries = 0;
270    img->entry_bytes = 0;
271    /* Image data size is computed using internal dimensions. */
272    w = align(surf->buffer->width, 2);
273    h = align(surf->buffer->height, 2);
274 
275    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
276       if (img->format.fourcc == formats[i].fourcc) {
277          img->format = formats[i];
278          break;
279       }
280    }
281 
282    mtx_lock(&drv->mutex);
283    if (screen->resource_get_info) {
284       screen->resource_get_info(screen, surfaces[0]->texture, &stride,
285                                 &offset);
286       if (!stride)
287          offset = 0;
288    }
289 
290    img->num_planes = 1;
291    img->offsets[0] = offset;
292 
293    switch (img->format.fourcc) {
294    case VA_FOURCC('U','Y','V','Y'):
295    case VA_FOURCC('Y','U','Y','V'):
296       img->pitches[0] = stride > 0 ? stride : w * 2;
297       assert(img->pitches[0] >= (w * 2));
298       img->data_size  = img->pitches[0] * h;
299       break;
300 
301    case VA_FOURCC('B','G','R','A'):
302    case VA_FOURCC('R','G','B','A'):
303    case VA_FOURCC('B','G','R','X'):
304    case VA_FOURCC('R','G','B','X'):
305       img->pitches[0] = stride > 0 ? stride : w * 4;
306       assert(img->pitches[0] >= (w * 4));
307       img->data_size  = img->pitches[0] * h;
308       break;
309 
310    case VA_FOURCC('N','V','1','2'):
311    case VA_FOURCC('P','0','1','0'):
312    case VA_FOURCC('P','0','1','6'):
313       if (surf->buffer->interlaced) {
314          struct u_rect src_rect, dst_rect;
315          struct pipe_video_buffer new_template;
316 
317          new_template = surf->templat;
318          new_template.interlaced = false;
319          new_buffer = drv->pipe->create_video_buffer(drv->pipe, &new_template);
320 
321          /* not all devices support non-interlaced buffers */
322          if (!new_buffer) {
323             status = VA_STATUS_ERROR_OPERATION_FAILED;
324             goto exit_on_error;
325          }
326 
327          /* convert the interlaced to the progressive */
328          src_rect.x0 = dst_rect.x0 = 0;
329          src_rect.x1 = dst_rect.x1 = surf->templat.width;
330          src_rect.y0 = dst_rect.y0 = 0;
331          src_rect.y1 = dst_rect.y1 = surf->templat.height;
332 
333          vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
334                            surf->buffer, new_buffer,
335                            &src_rect, &dst_rect,
336                            VL_COMPOSITOR_WEAVE);
337 
338          /* recalculate the values now that we have a new surface */
339          surfaces = surf->buffer->get_surfaces(new_buffer);
340          if (screen->resource_get_info) {
341             screen->resource_get_info(screen, surfaces[0]->texture, &stride,
342                                     &offset);
343             if (!stride)
344                offset = 0;
345          }
346 
347          w = align(new_buffer->width, 2);
348          h = align(new_buffer->height, 2);
349       }
350 
351       img->num_planes = 2;
352       img->pitches[0] = stride > 0 ? stride : w;
353       img->pitches[1] = stride > 0 ? stride : w;
354       img->offsets[1] = (stride > 0 ? stride : w) * h;
355       img->data_size  = (stride > 0 ? stride : w) * h * 3 / 2;
356       break;
357 
358    default:
359       /* VaDeriveImage only supports contiguous planes. But there is now a
360          more generic api vlVaExportSurfaceHandle. */
361       status = VA_STATUS_ERROR_OPERATION_FAILED;
362       goto exit_on_error;
363    }
364 
365    img_buf = CALLOC(1, sizeof(vlVaBuffer));
366    if (!img_buf) {
367       status = VA_STATUS_ERROR_ALLOCATION_FAILED;
368       goto exit_on_error;
369    }
370 
371    img->image_id = handle_table_add(drv->htab, img);
372 
373    img_buf->type = VAImageBufferType;
374    img_buf->size = img->data_size;
375    img_buf->num_elements = 1;
376 
377    pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
378    img_buf->derived_image_buffer = new_buffer;
379 
380    img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
381    mtx_unlock(&drv->mutex);
382 
383    *image = *img;
384 
385    return VA_STATUS_SUCCESS;
386 
387 exit_on_error:
388    FREE(img);
389    mtx_unlock(&drv->mutex);
390    return status;
391 }
392 
393 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)394 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
395 {
396    vlVaDriver *drv;
397    VAImage  *vaimage;
398    VAStatus status;
399 
400    if (!ctx)
401       return VA_STATUS_ERROR_INVALID_CONTEXT;
402 
403    drv = VL_VA_DRIVER(ctx);
404    mtx_lock(&drv->mutex);
405    vaimage = handle_table_get(drv->htab, image);
406    if (!vaimage) {
407       mtx_unlock(&drv->mutex);
408       return VA_STATUS_ERROR_INVALID_IMAGE;
409    }
410 
411    handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
412    mtx_unlock(&drv->mutex);
413    status = vlVaDestroyBuffer(ctx, vaimage->buf);
414    FREE(vaimage);
415    return status;
416 }
417 
418 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)419 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
420 {
421    if (!ctx)
422       return VA_STATUS_ERROR_INVALID_CONTEXT;
423 
424    return VA_STATUS_ERROR_UNIMPLEMENTED;
425 }
426 
427 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)428 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
429              unsigned int width, unsigned int height, VAImageID image)
430 {
431    vlVaDriver *drv;
432    vlVaSurface *surf;
433    vlVaBuffer *img_buf;
434    VAImage *vaimage;
435    struct pipe_sampler_view **views;
436    enum pipe_format format;
437    bool convert = false;
438    void *data[3];
439    unsigned pitches[3], i, j;
440 
441    if (!ctx)
442       return VA_STATUS_ERROR_INVALID_CONTEXT;
443 
444    drv = VL_VA_DRIVER(ctx);
445 
446    mtx_lock(&drv->mutex);
447    surf = handle_table_get(drv->htab, surface);
448    if (!surf || !surf->buffer) {
449       mtx_unlock(&drv->mutex);
450       return VA_STATUS_ERROR_INVALID_SURFACE;
451    }
452 
453    vaimage = handle_table_get(drv->htab, image);
454    if (!vaimage) {
455       mtx_unlock(&drv->mutex);
456       return VA_STATUS_ERROR_INVALID_IMAGE;
457    }
458 
459    if (x < 0 || y < 0) {
460       mtx_unlock(&drv->mutex);
461       return VA_STATUS_ERROR_INVALID_PARAMETER;
462    }
463 
464    if (x + width > surf->templat.width ||
465        y + height > surf->templat.height) {
466       mtx_unlock(&drv->mutex);
467       return VA_STATUS_ERROR_INVALID_PARAMETER;
468    }
469 
470    if (width > vaimage->width ||
471        height > vaimage->height) {
472       mtx_unlock(&drv->mutex);
473       return VA_STATUS_ERROR_INVALID_PARAMETER;
474    }
475 
476    img_buf = handle_table_get(drv->htab, vaimage->buf);
477    if (!img_buf) {
478       mtx_unlock(&drv->mutex);
479       return VA_STATUS_ERROR_INVALID_BUFFER;
480    }
481 
482    format = VaFourccToPipeFormat(vaimage->format.fourcc);
483    if (format == PIPE_FORMAT_NONE) {
484       mtx_unlock(&drv->mutex);
485       return VA_STATUS_ERROR_OPERATION_FAILED;
486    }
487 
488 
489    if (format != surf->buffer->buffer_format) {
490       /* support NV12 to YV12 and IYUV conversion now only */
491       if ((format == PIPE_FORMAT_YV12 &&
492          surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
493          (format == PIPE_FORMAT_IYUV &&
494          surf->buffer->buffer_format == PIPE_FORMAT_NV12))
495          convert = true;
496       else if (format == PIPE_FORMAT_NV12 &&
497          (surf->buffer->buffer_format == PIPE_FORMAT_P010 ||
498           surf->buffer->buffer_format == PIPE_FORMAT_P016)) {
499          mtx_unlock(&drv->mutex);
500          return VA_STATUS_ERROR_OPERATION_FAILED;
501       }
502       else {
503          mtx_unlock(&drv->mutex);
504          return VA_STATUS_ERROR_OPERATION_FAILED;
505       }
506    }
507 
508    views = surf->buffer->get_sampler_view_planes(surf->buffer);
509    if (!views) {
510       mtx_unlock(&drv->mutex);
511       return VA_STATUS_ERROR_OPERATION_FAILED;
512    }
513 
514    for (i = 0; i < vaimage->num_planes; i++) {
515       data[i] = img_buf->data + vaimage->offsets[i];
516       pitches[i] = vaimage->pitches[i];
517    }
518    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
519       void *tmp_d;
520       unsigned tmp_p;
521       tmp_d  = data[1];
522       data[1] = data[2];
523       data[2] = tmp_d;
524       tmp_p = pitches[1];
525       pitches[1] = pitches[2];
526       pitches[2] = tmp_p;
527    }
528 
529    for (i = 0; i < vaimage->num_planes; i++) {
530       unsigned box_w = align(width, 2);
531       unsigned box_h = align(height, 2);
532       unsigned box_x = x & ~1;
533       unsigned box_y = y & ~1;
534       if (!views[i]) continue;
535       vl_video_buffer_adjust_size(&box_w, &box_h, i,
536                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
537                                   surf->templat.interlaced);
538       vl_video_buffer_adjust_size(&box_x, &box_y, i,
539                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
540                                   surf->templat.interlaced);
541       for (j = 0; j < views[i]->texture->array_size; ++j) {
542          struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1};
543          struct pipe_transfer *transfer;
544          uint8_t *map;
545          map = drv->pipe->texture_map(drv->pipe, views[i]->texture, 0,
546                   PIPE_MAP_READ, &box, &transfer);
547          if (!map) {
548             mtx_unlock(&drv->mutex);
549             return VA_STATUS_ERROR_OPERATION_FAILED;
550          }
551 
552          if (i == 1 && convert) {
553             u_copy_nv12_to_yv12(data, pitches, i, j,
554                transfer->stride, views[i]->texture->array_size,
555                map, box.width, box.height);
556          } else {
557             util_copy_rect(data[i] + pitches[i] * j,
558                views[i]->texture->format,
559                pitches[i] * views[i]->texture->array_size, 0, 0,
560                box.width, box.height, map, transfer->stride, 0, 0);
561          }
562          pipe_texture_unmap(drv->pipe, transfer);
563       }
564    }
565    mtx_unlock(&drv->mutex);
566 
567    return VA_STATUS_SUCCESS;
568 }
569 
570 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)571 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
572              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
573              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
574 {
575    vlVaDriver *drv;
576    vlVaSurface *surf;
577    vlVaBuffer *img_buf;
578    VAImage *vaimage;
579    struct pipe_sampler_view **views;
580    enum pipe_format format;
581    void *data[3];
582    unsigned pitches[3], i, j;
583 
584    if (!ctx)
585       return VA_STATUS_ERROR_INVALID_CONTEXT;
586 
587    drv = VL_VA_DRIVER(ctx);
588    mtx_lock(&drv->mutex);
589 
590    surf = handle_table_get(drv->htab, surface);
591    if (!surf || !surf->buffer) {
592       mtx_unlock(&drv->mutex);
593       return VA_STATUS_ERROR_INVALID_SURFACE;
594    }
595 
596    vaimage = handle_table_get(drv->htab, image);
597    if (!vaimage) {
598       mtx_unlock(&drv->mutex);
599       return VA_STATUS_ERROR_INVALID_IMAGE;
600    }
601 
602    img_buf = handle_table_get(drv->htab, vaimage->buf);
603    if (!img_buf) {
604       mtx_unlock(&drv->mutex);
605       return VA_STATUS_ERROR_INVALID_BUFFER;
606    }
607 
608    if (img_buf->derived_surface.resource) {
609       /* Attempting to transfer derived image to surface */
610       mtx_unlock(&drv->mutex);
611       return VA_STATUS_ERROR_UNIMPLEMENTED;
612    }
613 
614    format = VaFourccToPipeFormat(vaimage->format.fourcc);
615 
616    if (format == PIPE_FORMAT_NONE) {
617       mtx_unlock(&drv->mutex);
618       return VA_STATUS_ERROR_OPERATION_FAILED;
619    }
620 
621    if ((format != surf->buffer->buffer_format) &&
622          ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
623          ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
624       struct pipe_video_buffer *tmp_buf;
625 
626       surf->templat.buffer_format = format;
627       if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
628           format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
629           format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
630          surf->templat.interlaced = false;
631       tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
632 
633       if (!tmp_buf) {
634          mtx_unlock(&drv->mutex);
635          return VA_STATUS_ERROR_ALLOCATION_FAILED;
636       }
637 
638       surf->buffer->destroy(surf->buffer);
639       surf->buffer = tmp_buf;
640    }
641 
642    views = surf->buffer->get_sampler_view_planes(surf->buffer);
643    if (!views) {
644       mtx_unlock(&drv->mutex);
645       return VA_STATUS_ERROR_OPERATION_FAILED;
646    }
647 
648    for (i = 0; i < vaimage->num_planes; i++) {
649       data[i] = img_buf->data + vaimage->offsets[i];
650       pitches[i] = vaimage->pitches[i];
651    }
652    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
653       void *tmp_d;
654       unsigned tmp_p;
655       tmp_d  = data[1];
656       data[1] = data[2];
657       data[2] = tmp_d;
658       tmp_p = pitches[1];
659       pitches[1] = pitches[2];
660       pitches[2] = tmp_p;
661    }
662 
663    for (i = 0; i < vaimage->num_planes; ++i) {
664       unsigned width, height;
665       struct pipe_resource *tex;
666 
667       if (!views[i]) continue;
668       tex = views[i]->texture;
669 
670       vlVaVideoSurfaceSize(surf, i, &width, &height);
671       for (j = 0; j < tex->array_size; ++j) {
672          struct pipe_box dst_box = {0, 0, j, width, height, 1};
673 
674          if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
675              && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
676              && i == 1) {
677             struct pipe_transfer *transfer = NULL;
678             uint8_t *map = NULL;
679 
680             map = drv->pipe->texture_map(drv->pipe,
681                                           tex,
682                                           0,
683                                           PIPE_MAP_WRITE |
684                                           PIPE_MAP_DISCARD_RANGE,
685                                           &dst_box, &transfer);
686             if (map == NULL) {
687                mtx_unlock(&drv->mutex);
688                return VA_STATUS_ERROR_OPERATION_FAILED;
689             }
690 
691             u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
692                                   transfer->stride, tex->array_size,
693                                   map, dst_box.width, dst_box.height);
694             pipe_texture_unmap(drv->pipe, transfer);
695          } else {
696             drv->pipe->texture_subdata(drv->pipe, tex, 0,
697                                        PIPE_MAP_WRITE, &dst_box,
698                                        data[i] + pitches[i] * j,
699                                        pitches[i] * views[i]->texture->array_size, 0);
700          }
701       }
702    }
703    drv->pipe->flush(drv->pipe, NULL, 0);
704    mtx_unlock(&drv->mutex);
705 
706    return VA_STATUS_SUCCESS;
707 }
708