• 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    struct pipe_video_buffer *new_buffer = NULL;
258    int w;
259    int h;
260    int i;
261    unsigned stride = 0;
262    unsigned offset = 0;
263 
264    if (!ctx)
265       return VA_STATUS_ERROR_INVALID_CONTEXT;
266 
267    drv = VL_VA_DRIVER(ctx);
268 
269    if (!drv)
270       return VA_STATUS_ERROR_INVALID_CONTEXT;
271 
272    screen = VL_VA_PSCREEN(ctx);
273 
274    if (!screen)
275       return VA_STATUS_ERROR_INVALID_CONTEXT;
276 
277    mtx_lock(&drv->mutex);
278    surf = handle_table_get(drv->htab, surface);
279    vlVaGetSurfaceBuffer(drv, surf);
280    if (!surf || !surf->buffer) {
281       status = VA_STATUS_ERROR_INVALID_SURFACE;
282       goto exit_on_error;
283    }
284 
285    if (surf->buffer->interlaced) {
286       status = VA_STATUS_ERROR_OPERATION_FAILED;
287       goto exit_on_error;
288    }
289 
290    if (util_format_get_num_planes(surf->buffer->buffer_format) >= 2 &&
291        (!screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
292                                          PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
293                                          PIPE_VIDEO_CAP_SUPPORTS_CONTIGUOUS_PLANES_MAP) ||
294         !surf->buffer->contiguous_planes)) {
295       status = VA_STATUS_ERROR_OPERATION_FAILED;
296       goto exit_on_error;
297    }
298 
299    memset(buf_resources, 0, sizeof(buf_resources));
300    surf->buffer->get_resources(surf->buffer, buf_resources);
301 
302    if (!buf_resources[0]) {
303       status = VA_STATUS_ERROR_ALLOCATION_FAILED;
304       goto exit_on_error;
305    }
306 
307    img = CALLOC(1, sizeof(VAImage));
308    if (!img) {
309       status = VA_STATUS_ERROR_ALLOCATION_FAILED;
310       goto exit_on_error;
311    }
312 
313    img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
314    img->buf = VA_INVALID_ID;
315    /* Use the visible dimensions. */
316    img->width = surf->templat.width;
317    img->height = surf->templat.height;
318    img->num_palette_entries = 0;
319    img->entry_bytes = 0;
320    /* Image data size is computed using internal dimensions. */
321    w = align(surf->buffer->width, 2);
322    h = align(surf->buffer->height, 2);
323 
324    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
325       if (img->format.fourcc == formats[i].fourcc) {
326          img->format = formats[i];
327          break;
328       }
329    }
330 
331    if (screen->resource_get_info) {
332       screen->resource_get_info(screen, buf_resources[0], &stride,
333                                 &offset);
334       if (!stride)
335          offset = 0;
336    }
337 
338    img->num_planes = 1;
339    img->offsets[0] = offset;
340 
341    switch (img->format.fourcc) {
342    case VA_FOURCC('U','Y','V','Y'):
343    case VA_FOURCC('Y','U','Y','V'):
344       img->pitches[0] = stride > 0 ? stride : w * 2;
345       assert(img->pitches[0] >= (w * 2));
346       img->data_size  = img->pitches[0] * h;
347       break;
348 
349    case VA_FOURCC('B','G','R','A'):
350    case VA_FOURCC('R','G','B','A'):
351    case VA_FOURCC('B','G','R','X'):
352    case VA_FOURCC('R','G','B','X'):
353    case VA_FOURCC('A','R','3','0'):
354    case VA_FOURCC('A','B','3','0'):
355    case VA_FOURCC('X','R','3','0'):
356    case VA_FOURCC('X','B','3','0'):
357       img->pitches[0] = stride > 0 ? stride : w * 4;
358       assert(img->pitches[0] >= (w * 4));
359       img->data_size  = img->pitches[0] * h;
360       break;
361 
362    case VA_FOURCC('N','V','1','2'):
363    case VA_FOURCC('P','0','1','0'):
364    case VA_FOURCC('P','0','1','2'):
365    case VA_FOURCC('P','0','1','6'):
366    {
367       /* In some gallium platforms, the stride and offset are different*/
368       /* for the Y and UV planes, query them independently.*/
369       if (screen->resource_get_info) {
370          /* resource_get_info is called above for buf_resources[0] and */
371          /* saved results in stride, offset, reuse those values to avoid a new call to: */
372          /* screen->resource_get_info(screen, buf_resources[0], &img->pitches[0],*/
373          /*                         &img->offsets[0]);*/
374          img->pitches[0] = stride;
375          img->offsets[0] = offset;
376 
377          screen->resource_get_info(screen, buf_resources[1], &img->pitches[1],
378                                  &img->offsets[1]);
379          if (!img->pitches[1])
380                img->offsets[1] = 0;
381       }
382 
383       img->num_planes = 2;
384       if(screen->resource_get_info) {
385          img->data_size  = (img->pitches[0] * h) + (img->pitches[1] * h / 2);
386       } else {
387          /* Use stride = w as default if screen->resource_get_info was not available */
388          img->pitches[0] = w;
389          img->pitches[1] = w;
390          img->offsets[1] = w * h;
391          img->data_size  = w * h * 3 / 2;
392       }
393    } break;
394    default:
395       /* VaDeriveImage only supports contiguous planes. But there is now a
396          more generic api vlVaExportSurfaceHandle. */
397       status = VA_STATUS_ERROR_OPERATION_FAILED;
398       goto exit_on_error;
399    }
400 
401    img_buf = CALLOC(1, sizeof(vlVaBuffer));
402    if (!img_buf) {
403       status = VA_STATUS_ERROR_ALLOCATION_FAILED;
404       goto exit_on_error;
405    }
406 
407    img->image_id = handle_table_add(drv->htab, img);
408 
409    img_buf->type = VAImageBufferType;
410    img_buf->size = img->data_size;
411    img_buf->num_elements = 1;
412 
413    pipe_resource_reference(&img_buf->derived_surface.resource, buf_resources[0]);
414    img_buf->derived_image_buffer = new_buffer;
415 
416    if (surf->ctx)
417       img_buf->derived_surface.entrypoint = surf->ctx->templat.entrypoint;
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_resource *view_resources[VL_NUM_COMPONENTS];
475    enum pipe_format format;
476    uint8_t *data[3];
477    unsigned pitches[3], i, j;
478 
479    if (!ctx)
480       return VA_STATUS_ERROR_INVALID_CONTEXT;
481 
482    drv = VL_VA_DRIVER(ctx);
483 
484    mtx_lock(&drv->mutex);
485    surf = handle_table_get(drv->htab, surface);
486    vlVaGetSurfaceBuffer(drv, surf);
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 != surf->buffer->buffer_format) {
523       mtx_unlock(&drv->mutex);
524       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
525    }
526 
527    memset(view_resources, 0, sizeof(view_resources));
528    surf->buffer->get_resources(surf->buffer, view_resources);
529 
530    for (i = 0; i < MIN2(vaimage->num_planes, 3); i++) {
531       data[i] = ((uint8_t*)img_buf->data) + vaimage->offsets[i];
532       pitches[i] = vaimage->pitches[i];
533    }
534 
535    for (i = 0; i < vaimage->num_planes; i++) {
536       unsigned box_w = align(width, 2);
537       unsigned box_h = align(height, 2);
538       unsigned box_x = x & ~1;
539       unsigned box_y = y & ~1;
540       if (!view_resources[i]) continue;
541       vl_video_buffer_adjust_size(&box_w, &box_h, i,
542                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
543                                   surf->templat.interlaced);
544       vl_video_buffer_adjust_size(&box_x, &box_y, i,
545                                   pipe_format_to_chroma_format(surf->templat.buffer_format),
546                                   surf->templat.interlaced);
547       for (j = 0; j < view_resources[i]->array_size; ++j) {
548          struct pipe_box box;
549          u_box_3d(box_x, box_y, j, box_w, box_h, 1, &box);
550          struct pipe_transfer *transfer;
551          uint8_t *map;
552          map = drv->pipe->texture_map(drv->pipe, view_resources[i], 0,
553                   PIPE_MAP_READ, &box, &transfer);
554          if (!map) {
555             mtx_unlock(&drv->mutex);
556             return VA_STATUS_ERROR_OPERATION_FAILED;
557          }
558          util_copy_rect((uint8_t*)(data[i] + pitches[i] * j),
559             view_resources[i]->format,
560             pitches[i] * view_resources[i]->array_size, 0, 0,
561             box.width, box.height, map, transfer->stride, 0, 0);
562          pipe_texture_unmap(drv->pipe, transfer);
563       }
564    }
565    mtx_unlock(&drv->mutex);
566 
567    return VA_STATUS_SUCCESS;
568 }
569 
570 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)571 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
572              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
573              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
574 {
575    vlVaDriver *drv;
576    vlVaSurface *surf;
577    vlVaBuffer *img_buf;
578    VAImage *vaimage;
579    struct pipe_resource *view_resources[VL_NUM_COMPONENTS];
580    enum pipe_format format;
581    uint8_t *data[3];
582    unsigned pitches[3], i, j;
583 
584    if (!ctx)
585       return VA_STATUS_ERROR_INVALID_CONTEXT;
586 
587    drv = VL_VA_DRIVER(ctx);
588    mtx_lock(&drv->mutex);
589 
590    surf = handle_table_get(drv->htab, surface);
591    vlVaGetSurfaceBuffer(drv, surf);
592    if (!surf || !surf->buffer) {
593       mtx_unlock(&drv->mutex);
594       return VA_STATUS_ERROR_INVALID_SURFACE;
595    }
596 
597    vaimage = handle_table_get(drv->htab, image);
598    if (!vaimage) {
599       mtx_unlock(&drv->mutex);
600       return VA_STATUS_ERROR_INVALID_IMAGE;
601    }
602 
603    img_buf = handle_table_get(drv->htab, vaimage->buf);
604    if (!img_buf) {
605       mtx_unlock(&drv->mutex);
606       return VA_STATUS_ERROR_INVALID_BUFFER;
607    }
608 
609    if (img_buf->derived_surface.resource) {
610       /* Attempting to transfer derived image to surface */
611       mtx_unlock(&drv->mutex);
612       return VA_STATUS_ERROR_UNIMPLEMENTED;
613    }
614 
615    format = VaFourccToPipeFormat(vaimage->format.fourcc);
616    if (format != surf->buffer->buffer_format) {
617       mtx_unlock(&drv->mutex);
618       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
619    }
620 
621    memset(view_resources, 0, sizeof(view_resources));
622    surf->buffer->get_resources(surf->buffer, view_resources);
623 
624    for (i = 0; i < MIN2(vaimage->num_planes, 3); i++) {
625       data[i] = ((uint8_t*)img_buf->data) + vaimage->offsets[i];
626       pitches[i] = vaimage->pitches[i];
627    }
628 
629    for (i = 0; i < vaimage->num_planes; ++i) {
630       unsigned width, height;
631       struct pipe_resource *tex;
632 
633       if (!view_resources[i]) continue;
634       tex = view_resources[i];
635 
636       vlVaVideoSurfaceSize(surf, i, &width, &height);
637       for (j = 0; j < tex->array_size; ++j) {
638          struct pipe_box dst_box;
639          u_box_3d(0, 0, j, width, height, 1, &dst_box);
640          drv->pipe->texture_subdata(drv->pipe, tex, 0,
641                                     PIPE_MAP_WRITE, &dst_box,
642                                     data[i] + pitches[i] * j,
643                                     pitches[i] * view_resources[i]->array_size, 0);
644       }
645    }
646    drv->pipe->flush(drv->pipe, NULL, 0);
647    mtx_unlock(&drv->mutex);
648 
649    return VA_STATUS_SUCCESS;
650 }
651