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