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