• 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    {VA_FOURCC('Y','8','0','0')},
53    {VA_FOURCC('4','4','4','P')},
54    {VA_FOURCC('R','G','B','P')},
55    {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
56     0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
57    {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
58     0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
59    {.fourcc = VA_FOURCC('A','R','G','B'), .byte_order = VA_LSB_FIRST, 32, 32,
60     0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
61    {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
62     0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
63    {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
64     0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
65 };
66 
67 static void
vlVaVideoSurfaceSize(vlVaSurface * p_surf,int component,unsigned * width,unsigned * height)68 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
69                      unsigned *width, unsigned *height)
70 {
71    *width = p_surf->templat.width;
72    *height = p_surf->templat.height;
73 
74    vl_video_buffer_adjust_size(width, height, component,
75                                pipe_format_to_chroma_format(p_surf->templat.buffer_format),
76                                p_surf->templat.interlaced);
77 }
78 
79 VAStatus
vlVaQueryImageFormats(VADriverContextP ctx,VAImageFormat * format_list,int * num_formats)80 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
81 {
82    struct pipe_screen *pscreen;
83    enum pipe_format format;
84    int i;
85 
86    STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
87 
88    if (!ctx)
89       return VA_STATUS_ERROR_INVALID_CONTEXT;
90 
91    if (!(format_list && num_formats))
92       return VA_STATUS_ERROR_INVALID_PARAMETER;
93 
94    *num_formats = 0;
95    pscreen = VL_VA_PSCREEN(ctx);
96    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
97       format = VaFourccToPipeFormat(formats[i].fourcc);
98       if (pscreen->is_video_format_supported(pscreen, format,
99           PIPE_VIDEO_PROFILE_UNKNOWN,
100           PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
101          format_list[(*num_formats)++] = formats[i];
102    }
103 
104    return VA_STATUS_SUCCESS;
105 }
106 
107 VAStatus
vlVaCreateImage(VADriverContextP ctx,VAImageFormat * format,int width,int height,VAImage * image)108 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
109 {
110    VAStatus status;
111    vlVaDriver *drv;
112    VAImage *img;
113    int w, h;
114 
115    if (!ctx)
116       return VA_STATUS_ERROR_INVALID_CONTEXT;
117 
118    if (!(format && image && width && height))
119       return VA_STATUS_ERROR_INVALID_PARAMETER;
120 
121    drv = VL_VA_DRIVER(ctx);
122 
123    img = CALLOC(1, sizeof(VAImage));
124    if (!img)
125       return VA_STATUS_ERROR_ALLOCATION_FAILED;
126    mtx_lock(&drv->mutex);
127    img->image_id = handle_table_add(drv->htab, img);
128    mtx_unlock(&drv->mutex);
129 
130    img->format = *format;
131    img->width = width;
132    img->height = height;
133    w = align(width, 2);
134    h = align(height, 2);
135 
136    switch (format->fourcc) {
137    case VA_FOURCC('N','V','1','2'):
138       img->num_planes = 2;
139       img->pitches[0] = w;
140       img->offsets[0] = 0;
141       img->pitches[1] = w;
142       img->offsets[1] = w * h;
143       img->data_size  = w * h * 3 / 2;
144       break;
145 
146    case VA_FOURCC('P','0','1','0'):
147    case VA_FOURCC('P','0','1','6'):
148       img->num_planes = 2;
149       img->pitches[0] = w * 2;
150       img->offsets[0] = 0;
151       img->pitches[1] = w * 2;
152       img->offsets[1] = w * h * 2;
153       img->data_size  = w * h * 3;
154       break;
155 
156    case VA_FOURCC('I','4','2','0'):
157    case VA_FOURCC('Y','V','1','2'):
158       img->num_planes = 3;
159       img->pitches[0] = w;
160       img->offsets[0] = 0;
161       img->pitches[1] = w / 2;
162       img->offsets[1] = w * h;
163       img->pitches[2] = w / 2;
164       img->offsets[2] = w * h * 5 / 4;
165       img->data_size  = w * h * 3 / 2;
166       break;
167 
168    case VA_FOURCC('U','Y','V','Y'):
169    case VA_FOURCC('Y','U','Y','V'):
170    case VA_FOURCC('Y','U','Y','2'):
171       img->num_planes = 1;
172       img->pitches[0] = w * 2;
173       img->offsets[0] = 0;
174       img->data_size  = w * h * 2;
175       break;
176 
177    case VA_FOURCC('B','G','R','A'):
178    case VA_FOURCC('R','G','B','A'):
179    case VA_FOURCC('A','R','G','B'):
180    case VA_FOURCC('B','G','R','X'):
181    case VA_FOURCC('R','G','B','X'):
182       img->num_planes = 1;
183       img->pitches[0] = w * 4;
184       img->offsets[0] = 0;
185       img->data_size  = w * h * 4;
186       break;
187 
188    case VA_FOURCC('Y','8','0','0'):
189       img->num_planes = 1;
190       img->pitches[0] = w;
191       img->offsets[0] = 0;
192       img->data_size  = w * h;
193       break;
194 
195    case VA_FOURCC('4','4','4', 'P'):
196    case VA_FOURCC('R','G','B', 'P'):
197       img->num_planes = 3;
198       img->offsets[0] = 0;
199       img->offsets[1] = w * h;
200       img->offsets[2] = w * h * 2;
201       img->pitches[0] = w;
202       img->pitches[1] = w;
203       img->pitches[2] = w;
204       img->data_size  = w * h * 3;
205       break;
206 
207    default:
208       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
209    }
210 
211    status =  vlVaCreateBuffer(ctx, 0, VAImageBufferType,
212                            align(img->data_size, 16),
213                            1, NULL, &img->buf);
214    if (status != VA_STATUS_SUCCESS)
215       return status;
216    *image = *img;
217 
218    return status;
219 }
220 
221 VAStatus
vlVaDeriveImage(VADriverContextP ctx,VASurfaceID surface,VAImage * image)222 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
223 {
224    vlVaDriver *drv;
225    vlVaSurface *surf;
226    vlVaBuffer *img_buf;
227    VAImage *img;
228    VAStatus status;
229    struct pipe_screen *screen;
230    struct pipe_surface **surfaces;
231    struct pipe_video_buffer *new_buffer = NULL;
232    int w;
233    int h;
234    int i;
235    unsigned stride = 0;
236    unsigned offset = 0;
237 
238    /* This function is used by some programs to test for hardware decoding, but on
239     * AMD devices, the buffers default to interlaced, which causes this function to fail.
240     * Some programs expect this function to fail, while others, assume this means
241     * hardware acceleration is not available and give up without trying the fall-back
242     * vaCreateImage + vaPutImage
243     */
244    const char *proc = util_get_process_name();
245    const char *derive_interlaced_allowlist[] = {
246          "vlc",
247          "h264encode",
248          "hevcencode"
249    };
250 
251    if (!ctx)
252       return VA_STATUS_ERROR_INVALID_CONTEXT;
253 
254    drv = VL_VA_DRIVER(ctx);
255 
256    if (!drv)
257       return VA_STATUS_ERROR_INVALID_CONTEXT;
258 
259    screen = VL_VA_PSCREEN(ctx);
260 
261    if (!screen)
262       return VA_STATUS_ERROR_INVALID_CONTEXT;
263 
264    surf = handle_table_get(drv->htab, surface);
265 
266    if (!surf || !surf->buffer)
267       return VA_STATUS_ERROR_INVALID_SURFACE;
268 
269    if (surf->buffer->interlaced) {
270       for (i = 0; i < ARRAY_SIZE(derive_interlaced_allowlist); i++)
271          if ((strcmp(derive_interlaced_allowlist[i], proc) == 0))
272             break;
273 
274       if (i >= ARRAY_SIZE(derive_interlaced_allowlist) ||
275           !screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
276                                    PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
277                                    PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE))
278          return VA_STATUS_ERROR_OPERATION_FAILED;
279    } else if (util_format_get_num_planes(surf->buffer->buffer_format) >= 2 &&
280               !screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
281                                        PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
282                                        PIPE_VIDEO_CAP_SUPPORTS_CONTIGUOUS_PLANES_MAP)) {
283       return VA_STATUS_ERROR_OPERATION_FAILED;
284    }
285 
286    surfaces = surf->buffer->get_surfaces(surf->buffer);
287    if (!surfaces || !surfaces[0]->texture)
288       return VA_STATUS_ERROR_ALLOCATION_FAILED;
289 
290    img = CALLOC(1, sizeof(VAImage));
291    if (!img)
292       return VA_STATUS_ERROR_ALLOCATION_FAILED;
293 
294    img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
295    img->buf = VA_INVALID_ID;
296    /* Use the visible dimensions. */
297    img->width = surf->templat.width;
298    img->height = surf->templat.height;
299    img->num_palette_entries = 0;
300    img->entry_bytes = 0;
301    /* Image data size is computed using internal dimensions. */
302    w = align(surf->buffer->width, 2);
303    h = align(surf->buffer->height, 2);
304 
305    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
306       if (img->format.fourcc == formats[i].fourcc) {
307          img->format = formats[i];
308          break;
309       }
310    }
311 
312    mtx_lock(&drv->mutex);
313    if (screen->resource_get_info) {
314       screen->resource_get_info(screen, surfaces[0]->texture, &stride,
315                                 &offset);
316       if (!stride)
317          offset = 0;
318    }
319 
320    img->num_planes = 1;
321    img->offsets[0] = offset;
322 
323    switch (img->format.fourcc) {
324    case VA_FOURCC('U','Y','V','Y'):
325    case VA_FOURCC('Y','U','Y','V'):
326       img->pitches[0] = stride > 0 ? stride : w * 2;
327       assert(img->pitches[0] >= (w * 2));
328       img->data_size  = img->pitches[0] * h;
329       break;
330 
331    case VA_FOURCC('B','G','R','A'):
332    case VA_FOURCC('R','G','B','A'):
333    case VA_FOURCC('B','G','R','X'):
334    case VA_FOURCC('R','G','B','X'):
335       img->pitches[0] = stride > 0 ? stride : w * 4;
336       assert(img->pitches[0] >= (w * 4));
337       img->data_size  = img->pitches[0] * h;
338       break;
339 
340    case VA_FOURCC('N','V','1','2'):
341    case VA_FOURCC('P','0','1','0'):
342    case VA_FOURCC('P','0','1','6'):
343    {
344       /* In some gallium platforms, the stride and offset are different*/
345       /* for the Y and UV planes, query them independently.*/
346       if (screen->resource_get_info) {
347          /* resource_get_info is called above for surfaces[0]->texture and */
348          /* saved results in stride, offset, reuse those values to avoid a new call to: */
349          /* screen->resource_get_info(screen, surfaces[0]->texture, &img->pitches[0],*/
350          /*                         &img->offsets[0]);*/
351          img->pitches[0] = stride;
352          img->offsets[0] = offset;
353 
354          screen->resource_get_info(screen, surfaces[1]->texture, &img->pitches[1],
355                                  &img->offsets[1]);
356          if (!img->pitches[1])
357                img->offsets[1] = 0;
358       }
359 
360       if (surf->buffer->interlaced) {
361          struct u_rect src_rect, dst_rect;
362          struct pipe_video_buffer new_template;
363 
364          new_template = surf->templat;
365          new_template.interlaced = false;
366          new_buffer = drv->pipe->create_video_buffer(drv->pipe, &new_template);
367 
368          /* not all devices support non-interlaced buffers */
369          if (!new_buffer) {
370             status = VA_STATUS_ERROR_OPERATION_FAILED;
371             goto exit_on_error;
372          }
373 
374          /* convert the interlaced to the progressive */
375          src_rect.x0 = dst_rect.x0 = 0;
376          src_rect.x1 = dst_rect.x1 = surf->templat.width;
377          src_rect.y0 = dst_rect.y0 = 0;
378          src_rect.y1 = dst_rect.y1 = surf->templat.height;
379 
380          vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
381                            surf->buffer, new_buffer,
382                            &src_rect, &dst_rect,
383                            VL_COMPOSITOR_WEAVE);
384 
385          /* recalculate the values now that we have a new surface */
386          surfaces = surf->buffer->get_surfaces(new_buffer);
387          if (screen->resource_get_info) {
388             screen->resource_get_info(screen, surfaces[0]->texture, &img->pitches[0],
389                                     &img->offsets[0]);
390             if (!img->pitches[0])
391                img->offsets[0] = 0;
392 
393             screen->resource_get_info(screen, surfaces[1]->texture, &img->pitches[1],
394                                     &img->offsets[1]);
395             if (!img->pitches[1])
396                img->offsets[1] = 0;
397          }
398 
399          w = align(new_buffer->width, 2);
400          h = align(new_buffer->height, 2);
401       }
402 
403       img->num_planes = 2;
404       if(screen->resource_get_info) {
405          /* Note this block might use h and w from the recalculated size if it entered
406             the interlaced branch above.*/
407          img->data_size  = (img->pitches[0] * h) + (img->pitches[1] * h / 2);
408       } else {
409          /* Use stride = w as default if screen->resource_get_info was not available */
410          img->pitches[0] = w;
411          img->pitches[1] = w;
412          img->offsets[1] = w * h;
413          img->data_size  = w * h * 3 / 2;
414       }
415    } break;
416    default:
417       /* VaDeriveImage only supports contiguous planes. But there is now a
418          more generic api vlVaExportSurfaceHandle. */
419       status = VA_STATUS_ERROR_OPERATION_FAILED;
420       goto exit_on_error;
421    }
422 
423    img_buf = CALLOC(1, sizeof(vlVaBuffer));
424    if (!img_buf) {
425       status = VA_STATUS_ERROR_ALLOCATION_FAILED;
426       goto exit_on_error;
427    }
428 
429    img->image_id = handle_table_add(drv->htab, img);
430 
431    img_buf->type = VAImageBufferType;
432    img_buf->size = img->data_size;
433    img_buf->num_elements = 1;
434 
435    pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
436    img_buf->derived_image_buffer = new_buffer;
437 
438    if (surf->ctx)
439       img_buf->derived_surface.entrypoint = surf->ctx->templat.entrypoint;
440 
441    img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
442    mtx_unlock(&drv->mutex);
443 
444    *image = *img;
445 
446    return VA_STATUS_SUCCESS;
447 
448 exit_on_error:
449    FREE(img);
450    mtx_unlock(&drv->mutex);
451    return status;
452 }
453 
454 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)455 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
456 {
457    vlVaDriver *drv;
458    VAImage  *vaimage;
459    VAStatus status;
460 
461    if (!ctx)
462       return VA_STATUS_ERROR_INVALID_CONTEXT;
463 
464    drv = VL_VA_DRIVER(ctx);
465    mtx_lock(&drv->mutex);
466    vaimage = handle_table_get(drv->htab, image);
467    if (!vaimage) {
468       mtx_unlock(&drv->mutex);
469       return VA_STATUS_ERROR_INVALID_IMAGE;
470    }
471 
472    handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
473    mtx_unlock(&drv->mutex);
474    status = vlVaDestroyBuffer(ctx, vaimage->buf);
475    FREE(vaimage);
476    return status;
477 }
478 
479 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)480 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
481 {
482    if (!ctx)
483       return VA_STATUS_ERROR_INVALID_CONTEXT;
484 
485    return VA_STATUS_ERROR_UNIMPLEMENTED;
486 }
487 
488 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)489 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
490              unsigned int width, unsigned int height, VAImageID image)
491 {
492    vlVaDriver *drv;
493    vlVaSurface *surf;
494    vlVaBuffer *img_buf;
495    VAImage *vaimage;
496    struct pipe_resource *view_resources[VL_NUM_COMPONENTS];
497    enum pipe_format format;
498    bool convert = false;
499    uint8_t *data[3];
500    unsigned pitches[3], i, j;
501 
502    if (!ctx)
503       return VA_STATUS_ERROR_INVALID_CONTEXT;
504 
505    drv = VL_VA_DRIVER(ctx);
506 
507    mtx_lock(&drv->mutex);
508    surf = handle_table_get(drv->htab, surface);
509    if (!surf || !surf->buffer) {
510       mtx_unlock(&drv->mutex);
511       return VA_STATUS_ERROR_INVALID_SURFACE;
512    }
513 
514    vaimage = handle_table_get(drv->htab, image);
515    if (!vaimage) {
516       mtx_unlock(&drv->mutex);
517       return VA_STATUS_ERROR_INVALID_IMAGE;
518    }
519 
520    if (x < 0 || y < 0) {
521       mtx_unlock(&drv->mutex);
522       return VA_STATUS_ERROR_INVALID_PARAMETER;
523    }
524 
525    if (x + width > surf->templat.width ||
526        y + height > surf->templat.height) {
527       mtx_unlock(&drv->mutex);
528       return VA_STATUS_ERROR_INVALID_PARAMETER;
529    }
530 
531    if (width > vaimage->width ||
532        height > vaimage->height) {
533       mtx_unlock(&drv->mutex);
534       return VA_STATUS_ERROR_INVALID_PARAMETER;
535    }
536 
537    img_buf = handle_table_get(drv->htab, vaimage->buf);
538    if (!img_buf) {
539       mtx_unlock(&drv->mutex);
540       return VA_STATUS_ERROR_INVALID_BUFFER;
541    }
542 
543    format = VaFourccToPipeFormat(vaimage->format.fourcc);
544    if (format == PIPE_FORMAT_NONE) {
545       mtx_unlock(&drv->mutex);
546       return VA_STATUS_ERROR_OPERATION_FAILED;
547    }
548 
549 
550    if (format != surf->buffer->buffer_format) {
551       /* support NV12 to YV12 and IYUV conversion now only */
552       if ((format == PIPE_FORMAT_YV12 &&
553          surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
554          (format == PIPE_FORMAT_IYUV &&
555          surf->buffer->buffer_format == PIPE_FORMAT_NV12))
556          convert = true;
557       else if (format == PIPE_FORMAT_NV12 &&
558          (surf->buffer->buffer_format == PIPE_FORMAT_P010 ||
559           surf->buffer->buffer_format == PIPE_FORMAT_P016)) {
560          mtx_unlock(&drv->mutex);
561          return VA_STATUS_ERROR_OPERATION_FAILED;
562       }
563       else {
564          mtx_unlock(&drv->mutex);
565          return VA_STATUS_ERROR_OPERATION_FAILED;
566       }
567    }
568 
569    memset(view_resources, 0, sizeof(view_resources));
570    surf->buffer->get_resources(surf->buffer, view_resources);
571 
572    for (i = 0; i < MIN2(vaimage->num_planes, 3); i++) {
573       data[i] = ((uint8_t*)img_buf->data) + vaimage->offsets[i];
574       pitches[i] = vaimage->pitches[i];
575    }
576    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
577       void *tmp_d;
578       unsigned tmp_p;
579       tmp_d  = data[1];
580       data[1] = data[2];
581       data[2] = tmp_d;
582       tmp_p = pitches[1];
583       pitches[1] = pitches[2];
584       pitches[2] = tmp_p;
585    }
586 
587    for (i = 0; i < vaimage->num_planes; i++) {
588       unsigned box_w = align(width, 2);
589       unsigned box_h = align(height, 2);
590       unsigned box_x = x & ~1;
591       unsigned box_y = y & ~1;
592       if (!view_resources[i]) continue;
593       vl_video_buffer_adjust_size(&box_w, &box_h, i,
594                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
595                                   surf->templat.interlaced);
596       vl_video_buffer_adjust_size(&box_x, &box_y, i,
597                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
598                                   surf->templat.interlaced);
599       for (j = 0; j < view_resources[i]->array_size; ++j) {
600          struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1};
601          struct pipe_transfer *transfer;
602          uint8_t *map;
603          map = drv->pipe->texture_map(drv->pipe, view_resources[i], 0,
604                   PIPE_MAP_READ, &box, &transfer);
605          if (!map) {
606             mtx_unlock(&drv->mutex);
607             return VA_STATUS_ERROR_OPERATION_FAILED;
608          }
609 
610          if (i == 1 && convert) {
611             u_copy_nv12_to_yv12((void *const *)data, pitches, i, j,
612                transfer->stride, view_resources[i]->array_size,
613                map, box.width, box.height);
614          } else {
615             util_copy_rect((uint8_t*)(data[i] + pitches[i] * j),
616                view_resources[i]->format,
617                pitches[i] * view_resources[i]->array_size, 0, 0,
618                box.width, box.height, map, transfer->stride, 0, 0);
619          }
620          pipe_texture_unmap(drv->pipe, transfer);
621       }
622    }
623    mtx_unlock(&drv->mutex);
624 
625    return VA_STATUS_SUCCESS;
626 }
627 
628 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)629 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
630              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
631              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
632 {
633    vlVaDriver *drv;
634    vlVaSurface *surf;
635    vlVaBuffer *img_buf;
636    VAImage *vaimage;
637    struct pipe_resource *view_resources[VL_NUM_COMPONENTS];
638    enum pipe_format format;
639    uint8_t *data[3];
640    unsigned pitches[3], i, j;
641 
642    if (!ctx)
643       return VA_STATUS_ERROR_INVALID_CONTEXT;
644 
645    drv = VL_VA_DRIVER(ctx);
646    mtx_lock(&drv->mutex);
647 
648    surf = handle_table_get(drv->htab, surface);
649    if (!surf || !surf->buffer) {
650       mtx_unlock(&drv->mutex);
651       return VA_STATUS_ERROR_INVALID_SURFACE;
652    }
653 
654    vaimage = handle_table_get(drv->htab, image);
655    if (!vaimage) {
656       mtx_unlock(&drv->mutex);
657       return VA_STATUS_ERROR_INVALID_IMAGE;
658    }
659 
660    img_buf = handle_table_get(drv->htab, vaimage->buf);
661    if (!img_buf) {
662       mtx_unlock(&drv->mutex);
663       return VA_STATUS_ERROR_INVALID_BUFFER;
664    }
665 
666    if (img_buf->derived_surface.resource) {
667       /* Attempting to transfer derived image to surface */
668       mtx_unlock(&drv->mutex);
669       return VA_STATUS_ERROR_UNIMPLEMENTED;
670    }
671 
672    format = VaFourccToPipeFormat(vaimage->format.fourcc);
673 
674    if (format == PIPE_FORMAT_NONE) {
675       mtx_unlock(&drv->mutex);
676       return VA_STATUS_ERROR_OPERATION_FAILED;
677    }
678 
679    if ((format != surf->buffer->buffer_format) &&
680          ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
681          ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
682       struct pipe_video_buffer *tmp_buf;
683 
684       surf->templat.buffer_format = format;
685       if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
686           format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
687           format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
688          surf->templat.interlaced = false;
689       tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
690 
691       if (!tmp_buf) {
692          mtx_unlock(&drv->mutex);
693          return VA_STATUS_ERROR_ALLOCATION_FAILED;
694       }
695 
696       surf->buffer->destroy(surf->buffer);
697       surf->buffer = tmp_buf;
698    }
699 
700    memset(view_resources, 0, sizeof(view_resources));
701    surf->buffer->get_resources(surf->buffer, view_resources);
702 
703    for (i = 0; i < MIN2(vaimage->num_planes, 3); i++) {
704       data[i] = ((uint8_t*)img_buf->data) + vaimage->offsets[i];
705       pitches[i] = vaimage->pitches[i];
706    }
707    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
708       void *tmp_d;
709       unsigned tmp_p;
710       tmp_d  = data[1];
711       data[1] = data[2];
712       data[2] = tmp_d;
713       tmp_p = pitches[1];
714       pitches[1] = pitches[2];
715       pitches[2] = tmp_p;
716    }
717 
718    for (i = 0; i < vaimage->num_planes; ++i) {
719       unsigned width, height;
720       struct pipe_resource *tex;
721 
722       if (!view_resources[i]) continue;
723       tex = view_resources[i];
724 
725       vlVaVideoSurfaceSize(surf, i, &width, &height);
726       for (j = 0; j < tex->array_size; ++j) {
727          struct pipe_box dst_box = {0, 0, j, width, height, 1};
728 
729          if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
730              && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
731              && i == 1) {
732             struct pipe_transfer *transfer = NULL;
733             uint8_t *map = NULL;
734 
735             map = drv->pipe->texture_map(drv->pipe,
736                                           tex,
737                                           0,
738                                           PIPE_MAP_WRITE |
739                                           PIPE_MAP_DISCARD_RANGE,
740                                           &dst_box, &transfer);
741             if (map == NULL) {
742                mtx_unlock(&drv->mutex);
743                return VA_STATUS_ERROR_OPERATION_FAILED;
744             }
745 
746             u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
747                                   transfer->stride, tex->array_size,
748                                   map, dst_box.width, dst_box.height);
749             pipe_texture_unmap(drv->pipe, transfer);
750          } else {
751             drv->pipe->texture_subdata(drv->pipe, tex, 0,
752                                        PIPE_MAP_WRITE, &dst_box,
753                                        data[i] + pitches[i] * j,
754                                        pitches[i] * view_resources[i]->array_size, 0);
755          }
756       }
757    }
758    drv->pipe->flush(drv->pipe, NULL, 0);
759    mtx_unlock(&drv->mutex);
760 
761    return VA_STATUS_SUCCESS;
762 }
763