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