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 
36 #include "vl/vl_winsys.h"
37 #include "vl/vl_video_buffer.h"
38 
39 #include "va_private.h"
40 
41 static const VAImageFormat formats[] =
42 {
43    {VA_FOURCC('N','V','1','2')},
44    {VA_FOURCC('P','0','1','0')},
45    {VA_FOURCC('P','0','1','6')},
46    {VA_FOURCC('I','4','2','0')},
47    {VA_FOURCC('Y','V','1','2')},
48    {VA_FOURCC('Y','U','Y','V')},
49    {VA_FOURCC('Y','U','Y','2')},
50    {VA_FOURCC('U','Y','V','Y')},
51    {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
52     0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
53    {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
54     0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
55    {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
56     0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
57    {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
58     0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
59 };
60 
61 static void
vlVaVideoSurfaceSize(vlVaSurface * p_surf,int component,unsigned * width,unsigned * height)62 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
63                      unsigned *width, unsigned *height)
64 {
65    *width = p_surf->templat.width;
66    *height = p_surf->templat.height;
67 
68    vl_video_buffer_adjust_size(width, height, component,
69                                pipe_format_to_chroma_format(p_surf->templat.buffer_format),
70                                p_surf->templat.interlaced);
71 }
72 
73 VAStatus
vlVaQueryImageFormats(VADriverContextP ctx,VAImageFormat * format_list,int * num_formats)74 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
75 {
76    struct pipe_screen *pscreen;
77    enum pipe_format format;
78    int i;
79 
80    STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
81 
82    if (!ctx)
83       return VA_STATUS_ERROR_INVALID_CONTEXT;
84 
85    if (!(format_list && num_formats))
86       return VA_STATUS_ERROR_INVALID_PARAMETER;
87 
88    *num_formats = 0;
89    pscreen = VL_VA_PSCREEN(ctx);
90    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
91       format = VaFourccToPipeFormat(formats[i].fourcc);
92       if (pscreen->is_video_format_supported(pscreen, format,
93           PIPE_VIDEO_PROFILE_UNKNOWN,
94           PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
95          format_list[(*num_formats)++] = formats[i];
96    }
97 
98    return VA_STATUS_SUCCESS;
99 }
100 
101 VAStatus
vlVaCreateImage(VADriverContextP ctx,VAImageFormat * format,int width,int height,VAImage * image)102 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
103 {
104    VAStatus status;
105    vlVaDriver *drv;
106    VAImage *img;
107    int w, h;
108 
109    if (!ctx)
110       return VA_STATUS_ERROR_INVALID_CONTEXT;
111 
112    if (!(format && image && width && height))
113       return VA_STATUS_ERROR_INVALID_PARAMETER;
114 
115    drv = VL_VA_DRIVER(ctx);
116 
117    img = CALLOC(1, sizeof(VAImage));
118    if (!img)
119       return VA_STATUS_ERROR_ALLOCATION_FAILED;
120    mtx_lock(&drv->mutex);
121    img->image_id = handle_table_add(drv->htab, img);
122    mtx_unlock(&drv->mutex);
123 
124    img->format = *format;
125    img->width = width;
126    img->height = height;
127    w = align(width, 2);
128    h = align(height, 2);
129 
130    switch (format->fourcc) {
131    case VA_FOURCC('N','V','1','2'):
132       img->num_planes = 2;
133       img->pitches[0] = w;
134       img->offsets[0] = 0;
135       img->pitches[1] = w;
136       img->offsets[1] = w * h;
137       img->data_size  = w * h * 3 / 2;
138       break;
139 
140    case VA_FOURCC('P','0','1','0'):
141    case VA_FOURCC('P','0','1','6'):
142       img->num_planes = 2;
143       img->pitches[0] = w * 2;
144       img->offsets[0] = 0;
145       img->pitches[1] = w * 2;
146       img->offsets[1] = w * h * 2;
147       img->data_size  = w * h * 3;
148       break;
149 
150    case VA_FOURCC('I','4','2','0'):
151    case VA_FOURCC('Y','V','1','2'):
152       img->num_planes = 3;
153       img->pitches[0] = w;
154       img->offsets[0] = 0;
155       img->pitches[1] = w / 2;
156       img->offsets[1] = w * h;
157       img->pitches[2] = w / 2;
158       img->offsets[2] = w * h * 5 / 4;
159       img->data_size  = w * h * 3 / 2;
160       break;
161 
162    case VA_FOURCC('U','Y','V','Y'):
163    case VA_FOURCC('Y','U','Y','V'):
164    case VA_FOURCC('Y','U','Y','2'):
165       img->num_planes = 1;
166       img->pitches[0] = w * 2;
167       img->offsets[0] = 0;
168       img->data_size  = w * h * 2;
169       break;
170 
171    case VA_FOURCC('B','G','R','A'):
172    case VA_FOURCC('R','G','B','A'):
173    case VA_FOURCC('B','G','R','X'):
174    case VA_FOURCC('R','G','B','X'):
175       img->num_planes = 1;
176       img->pitches[0] = w * 4;
177       img->offsets[0] = 0;
178       img->data_size  = w * h * 4;
179       break;
180 
181    default:
182       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
183    }
184 
185    status =  vlVaCreateBuffer(ctx, 0, VAImageBufferType,
186                            align(img->data_size, 16),
187                            1, NULL, &img->buf);
188    if (status != VA_STATUS_SUCCESS)
189       return status;
190    *image = *img;
191 
192    return status;
193 }
194 
195 VAStatus
vlVaDeriveImage(VADriverContextP ctx,VASurfaceID surface,VAImage * image)196 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
197 {
198    vlVaDriver *drv;
199    vlVaSurface *surf;
200    vlVaBuffer *img_buf;
201    VAImage *img;
202    struct pipe_screen *screen;
203    struct pipe_surface **surfaces;
204    int w;
205    int h;
206    int i;
207    unsigned stride = 0;
208    unsigned offset = 0;
209 
210    if (!ctx)
211       return VA_STATUS_ERROR_INVALID_CONTEXT;
212 
213    drv = VL_VA_DRIVER(ctx);
214 
215    if (!drv)
216       return VA_STATUS_ERROR_INVALID_CONTEXT;
217 
218    screen = VL_VA_PSCREEN(ctx);
219 
220    if (!screen)
221       return VA_STATUS_ERROR_INVALID_CONTEXT;
222 
223    surf = handle_table_get(drv->htab, surface);
224 
225    if (!surf || !surf->buffer)
226       return VA_STATUS_ERROR_INVALID_SURFACE;
227 
228    if (surf->buffer->interlaced)
229      return VA_STATUS_ERROR_OPERATION_FAILED;
230 
231    surfaces = surf->buffer->get_surfaces(surf->buffer);
232    if (!surfaces || !surfaces[0]->texture)
233       return VA_STATUS_ERROR_ALLOCATION_FAILED;
234 
235    img = CALLOC(1, sizeof(VAImage));
236    if (!img)
237       return VA_STATUS_ERROR_ALLOCATION_FAILED;
238 
239    img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
240    img->buf = VA_INVALID_ID;
241    /* Use the visible dimensions. */
242    img->width = surf->templat.width;
243    img->height = surf->templat.height;
244    img->num_palette_entries = 0;
245    img->entry_bytes = 0;
246    /* Image data size is computed using internal dimensions. */
247    w = align(surf->buffer->width, 2);
248    h = align(surf->buffer->height, 2);
249 
250    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
251       if (img->format.fourcc == formats[i].fourcc) {
252          img->format = formats[i];
253          break;
254       }
255    }
256 
257    mtx_lock(&drv->mutex);
258    if (screen->resource_get_info) {
259       screen->resource_get_info(screen, surfaces[0]->texture, &stride,
260                                 &offset);
261       if (!stride)
262          offset = 0;
263    }
264 
265    switch (img->format.fourcc) {
266    case VA_FOURCC('U','Y','V','Y'):
267    case VA_FOURCC('Y','U','Y','V'):
268       img->pitches[0] = stride > 0 ? stride : w * 2;
269       assert(img->pitches[0] >= (w * 2));
270       break;
271 
272    case VA_FOURCC('B','G','R','A'):
273    case VA_FOURCC('R','G','B','A'):
274    case VA_FOURCC('B','G','R','X'):
275    case VA_FOURCC('R','G','B','X'):
276       img->pitches[0] = stride > 0 ? stride : w * 4;
277       assert(img->pitches[0] >= (w * 4));
278       break;
279 
280    default:
281       /* VaDeriveImage only supports contiguous planes. But there is now a
282          more generic api vlVaExportSurfaceHandle. */
283       FREE(img);
284       mtx_unlock(&drv->mutex);
285       return VA_STATUS_ERROR_OPERATION_FAILED;
286    }
287 
288    img->num_planes = 1;
289    img->offsets[0] = offset;
290    img->data_size  = img->pitches[0] * h;
291 
292    img_buf = CALLOC(1, sizeof(vlVaBuffer));
293    if (!img_buf) {
294       FREE(img);
295       mtx_unlock(&drv->mutex);
296       return VA_STATUS_ERROR_ALLOCATION_FAILED;
297    }
298 
299    img->image_id = handle_table_add(drv->htab, img);
300 
301    img_buf->type = VAImageBufferType;
302    img_buf->size = img->data_size;
303    img_buf->num_elements = 1;
304 
305    pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
306 
307    img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
308    mtx_unlock(&drv->mutex);
309 
310    *image = *img;
311 
312    return VA_STATUS_SUCCESS;
313 }
314 
315 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)316 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
317 {
318    vlVaDriver *drv;
319    VAImage  *vaimage;
320    VAStatus status;
321 
322    if (!ctx)
323       return VA_STATUS_ERROR_INVALID_CONTEXT;
324 
325    drv = VL_VA_DRIVER(ctx);
326    mtx_lock(&drv->mutex);
327    vaimage = handle_table_get(drv->htab, image);
328    if (!vaimage) {
329       mtx_unlock(&drv->mutex);
330       return VA_STATUS_ERROR_INVALID_IMAGE;
331    }
332 
333    handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
334    mtx_unlock(&drv->mutex);
335    status = vlVaDestroyBuffer(ctx, vaimage->buf);
336    FREE(vaimage);
337    return status;
338 }
339 
340 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)341 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
342 {
343    if (!ctx)
344       return VA_STATUS_ERROR_INVALID_CONTEXT;
345 
346    return VA_STATUS_ERROR_UNIMPLEMENTED;
347 }
348 
349 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)350 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
351              unsigned int width, unsigned int height, VAImageID image)
352 {
353    vlVaDriver *drv;
354    vlVaSurface *surf;
355    vlVaBuffer *img_buf;
356    VAImage *vaimage;
357    struct pipe_sampler_view **views;
358    enum pipe_format format;
359    bool convert = false;
360    void *data[3];
361    unsigned pitches[3], i, j;
362 
363    if (!ctx)
364       return VA_STATUS_ERROR_INVALID_CONTEXT;
365 
366    drv = VL_VA_DRIVER(ctx);
367 
368    mtx_lock(&drv->mutex);
369    surf = handle_table_get(drv->htab, surface);
370    if (!surf || !surf->buffer) {
371       mtx_unlock(&drv->mutex);
372       return VA_STATUS_ERROR_INVALID_SURFACE;
373    }
374 
375    vaimage = handle_table_get(drv->htab, image);
376    if (!vaimage) {
377       mtx_unlock(&drv->mutex);
378       return VA_STATUS_ERROR_INVALID_IMAGE;
379    }
380 
381    if (x < 0 || y < 0) {
382       mtx_unlock(&drv->mutex);
383       return VA_STATUS_ERROR_INVALID_PARAMETER;
384    }
385 
386    if (x + width > surf->templat.width ||
387        y + height > surf->templat.height) {
388       mtx_unlock(&drv->mutex);
389       return VA_STATUS_ERROR_INVALID_PARAMETER;
390    }
391 
392    if (width > vaimage->width ||
393        height > vaimage->height) {
394       mtx_unlock(&drv->mutex);
395       return VA_STATUS_ERROR_INVALID_PARAMETER;
396    }
397 
398    img_buf = handle_table_get(drv->htab, vaimage->buf);
399    if (!img_buf) {
400       mtx_unlock(&drv->mutex);
401       return VA_STATUS_ERROR_INVALID_BUFFER;
402    }
403 
404    format = VaFourccToPipeFormat(vaimage->format.fourcc);
405    if (format == PIPE_FORMAT_NONE) {
406       mtx_unlock(&drv->mutex);
407       return VA_STATUS_ERROR_OPERATION_FAILED;
408    }
409 
410 
411    if (format != surf->buffer->buffer_format) {
412       /* support NV12 to YV12 and IYUV conversion now only */
413       if ((format == PIPE_FORMAT_YV12 &&
414          surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
415          (format == PIPE_FORMAT_IYUV &&
416          surf->buffer->buffer_format == PIPE_FORMAT_NV12))
417          convert = true;
418       else if (format == PIPE_FORMAT_NV12 &&
419          (surf->buffer->buffer_format == PIPE_FORMAT_P010 ||
420           surf->buffer->buffer_format == PIPE_FORMAT_P016)) {
421          mtx_unlock(&drv->mutex);
422          return VA_STATUS_ERROR_OPERATION_FAILED;
423       }
424       else {
425          mtx_unlock(&drv->mutex);
426          return VA_STATUS_ERROR_OPERATION_FAILED;
427       }
428    }
429 
430    views = surf->buffer->get_sampler_view_planes(surf->buffer);
431    if (!views) {
432       mtx_unlock(&drv->mutex);
433       return VA_STATUS_ERROR_OPERATION_FAILED;
434    }
435 
436    for (i = 0; i < vaimage->num_planes; i++) {
437       data[i] = img_buf->data + vaimage->offsets[i];
438       pitches[i] = vaimage->pitches[i];
439    }
440    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
441       void *tmp_d;
442       unsigned tmp_p;
443       tmp_d  = data[1];
444       data[1] = data[2];
445       data[2] = tmp_d;
446       tmp_p = pitches[1];
447       pitches[1] = pitches[2];
448       pitches[2] = tmp_p;
449    }
450 
451    for (i = 0; i < vaimage->num_planes; i++) {
452       unsigned box_w = align(width, 2);
453       unsigned box_h = align(height, 2);
454       unsigned box_x = x & ~1;
455       unsigned box_y = y & ~1;
456       if (!views[i]) continue;
457       vl_video_buffer_adjust_size(&box_w, &box_h, i,
458                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
459                                   surf->templat.interlaced);
460       vl_video_buffer_adjust_size(&box_x, &box_y, i,
461                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
462                                   surf->templat.interlaced);
463       for (j = 0; j < views[i]->texture->array_size; ++j) {
464          struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1};
465          struct pipe_transfer *transfer;
466          uint8_t *map;
467          map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
468                   PIPE_TRANSFER_READ, &box, &transfer);
469          if (!map) {
470             mtx_unlock(&drv->mutex);
471             return VA_STATUS_ERROR_OPERATION_FAILED;
472          }
473 
474          if (i == 1 && convert) {
475             u_copy_nv12_to_yv12(data, pitches, i, j,
476                transfer->stride, views[i]->texture->array_size,
477                map, box.width, box.height);
478          } else {
479             util_copy_rect(data[i] + pitches[i] * j,
480                views[i]->texture->format,
481                pitches[i] * views[i]->texture->array_size, 0, 0,
482                box.width, box.height, map, transfer->stride, 0, 0);
483          }
484          pipe_transfer_unmap(drv->pipe, transfer);
485       }
486    }
487    mtx_unlock(&drv->mutex);
488 
489    return VA_STATUS_SUCCESS;
490 }
491 
492 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)493 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
494              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
495              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
496 {
497    vlVaDriver *drv;
498    vlVaSurface *surf;
499    vlVaBuffer *img_buf;
500    VAImage *vaimage;
501    struct pipe_sampler_view **views;
502    enum pipe_format format;
503    void *data[3];
504    unsigned pitches[3], i, j;
505 
506    if (!ctx)
507       return VA_STATUS_ERROR_INVALID_CONTEXT;
508 
509    drv = VL_VA_DRIVER(ctx);
510    mtx_lock(&drv->mutex);
511 
512    surf = handle_table_get(drv->htab, surface);
513    if (!surf || !surf->buffer) {
514       mtx_unlock(&drv->mutex);
515       return VA_STATUS_ERROR_INVALID_SURFACE;
516    }
517 
518    vaimage = handle_table_get(drv->htab, image);
519    if (!vaimage) {
520       mtx_unlock(&drv->mutex);
521       return VA_STATUS_ERROR_INVALID_IMAGE;
522    }
523 
524    img_buf = handle_table_get(drv->htab, vaimage->buf);
525    if (!img_buf) {
526       mtx_unlock(&drv->mutex);
527       return VA_STATUS_ERROR_INVALID_BUFFER;
528    }
529 
530    if (img_buf->derived_surface.resource) {
531       /* Attempting to transfer derived image to surface */
532       mtx_unlock(&drv->mutex);
533       return VA_STATUS_ERROR_UNIMPLEMENTED;
534    }
535 
536    format = VaFourccToPipeFormat(vaimage->format.fourcc);
537 
538    if (format == PIPE_FORMAT_NONE) {
539       mtx_unlock(&drv->mutex);
540       return VA_STATUS_ERROR_OPERATION_FAILED;
541    }
542 
543    if ((format != surf->buffer->buffer_format) &&
544          ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
545          ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
546       struct pipe_video_buffer *tmp_buf;
547 
548       surf->templat.buffer_format = format;
549       if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
550           format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
551           format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
552          surf->templat.interlaced = false;
553       tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
554 
555       if (!tmp_buf) {
556          mtx_unlock(&drv->mutex);
557          return VA_STATUS_ERROR_ALLOCATION_FAILED;
558       }
559 
560       surf->buffer->destroy(surf->buffer);
561       surf->buffer = tmp_buf;
562    }
563 
564    views = surf->buffer->get_sampler_view_planes(surf->buffer);
565    if (!views) {
566       mtx_unlock(&drv->mutex);
567       return VA_STATUS_ERROR_OPERATION_FAILED;
568    }
569 
570    for (i = 0; i < vaimage->num_planes; i++) {
571       data[i] = img_buf->data + vaimage->offsets[i];
572       pitches[i] = vaimage->pitches[i];
573    }
574    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
575       void *tmp_d;
576       unsigned tmp_p;
577       tmp_d  = data[1];
578       data[1] = data[2];
579       data[2] = tmp_d;
580       tmp_p = pitches[1];
581       pitches[1] = pitches[2];
582       pitches[2] = tmp_p;
583    }
584 
585    for (i = 0; i < vaimage->num_planes; ++i) {
586       unsigned width, height;
587       struct pipe_resource *tex;
588 
589       if (!views[i]) continue;
590       tex = views[i]->texture;
591 
592       vlVaVideoSurfaceSize(surf, i, &width, &height);
593       for (j = 0; j < tex->array_size; ++j) {
594          struct pipe_box dst_box = {0, 0, j, width, height, 1};
595 
596          if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
597              && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
598              && i == 1) {
599             struct pipe_transfer *transfer = NULL;
600             uint8_t *map = NULL;
601 
602             map = drv->pipe->transfer_map(drv->pipe,
603                                           tex,
604                                           0,
605                                           PIPE_TRANSFER_WRITE |
606                                           PIPE_TRANSFER_DISCARD_RANGE,
607                                           &dst_box, &transfer);
608             if (map == NULL) {
609                mtx_unlock(&drv->mutex);
610                return VA_STATUS_ERROR_OPERATION_FAILED;
611             }
612 
613             u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
614                                   transfer->stride, tex->array_size,
615                                   map, dst_box.width, dst_box.height);
616             pipe_transfer_unmap(drv->pipe, transfer);
617          } else {
618             drv->pipe->texture_subdata(drv->pipe, tex, 0,
619                                        PIPE_TRANSFER_WRITE, &dst_box,
620                                        data[i] + pitches[i] * j,
621                                        pitches[i] * views[i]->texture->array_size, 0);
622          }
623       }
624    }
625    mtx_unlock(&drv->mutex);
626 
627    return VA_STATUS_SUCCESS;
628 }
629