• 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 
36 #include "vl/vl_winsys.h"
37 #include "vl/vl_video_buffer.h"
38 
39 #include "va_private.h"
40 
41 static const VAImageFormat formats[] =
42 {
43    {VA_FOURCC('N','V','1','2')},
44    {VA_FOURCC('P','0','1','0')},
45    {VA_FOURCC('P','0','1','6')},
46    {VA_FOURCC('I','4','2','0')},
47    {VA_FOURCC('Y','V','1','2')},
48    {VA_FOURCC('Y','U','Y','V')},
49    {VA_FOURCC('U','Y','V','Y')},
50    {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
51     0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
52    {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
53     0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
54    {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
55     0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
56    {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
57     0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
58 };
59 
60 static void
vlVaVideoSurfaceSize(vlVaSurface * p_surf,int component,unsigned * width,unsigned * height)61 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
62                      unsigned *width, unsigned *height)
63 {
64    *width = p_surf->templat.width;
65    *height = p_surf->templat.height;
66 
67    vl_video_buffer_adjust_size(width, height, component,
68                                p_surf->templat.chroma_format,
69                                p_surf->templat.interlaced);
70 }
71 
72 VAStatus
vlVaQueryImageFormats(VADriverContextP ctx,VAImageFormat * format_list,int * num_formats)73 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
74 {
75    struct pipe_screen *pscreen;
76    enum pipe_format format;
77    int i;
78 
79    STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
80 
81    if (!ctx)
82       return VA_STATUS_ERROR_INVALID_CONTEXT;
83 
84    if (!(format_list && num_formats))
85       return VA_STATUS_ERROR_INVALID_PARAMETER;
86 
87    *num_formats = 0;
88    pscreen = VL_VA_PSCREEN(ctx);
89    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
90       format = VaFourccToPipeFormat(formats[i].fourcc);
91       if (pscreen->is_video_format_supported(pscreen, format,
92           PIPE_VIDEO_PROFILE_UNKNOWN,
93           PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
94          format_list[(*num_formats)++] = formats[i];
95    }
96 
97    return VA_STATUS_SUCCESS;
98 }
99 
100 VAStatus
vlVaCreateImage(VADriverContextP ctx,VAImageFormat * format,int width,int height,VAImage * image)101 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
102 {
103    VAStatus status;
104    vlVaDriver *drv;
105    VAImage *img;
106    int w, h;
107 
108    if (!ctx)
109       return VA_STATUS_ERROR_INVALID_CONTEXT;
110 
111    if (!(format && image && width && height))
112       return VA_STATUS_ERROR_INVALID_PARAMETER;
113 
114    drv = VL_VA_DRIVER(ctx);
115 
116    img = CALLOC(1, sizeof(VAImage));
117    if (!img)
118       return VA_STATUS_ERROR_ALLOCATION_FAILED;
119    mtx_lock(&drv->mutex);
120    img->image_id = handle_table_add(drv->htab, img);
121    mtx_unlock(&drv->mutex);
122 
123    img->format = *format;
124    img->width = width;
125    img->height = height;
126    w = align(width, 2);
127    h = align(height, 2);
128 
129    switch (format->fourcc) {
130    case VA_FOURCC('N','V','1','2'):
131       img->num_planes = 2;
132       img->pitches[0] = w;
133       img->offsets[0] = 0;
134       img->pitches[1] = w;
135       img->offsets[1] = w * h;
136       img->data_size  = w * h * 3 / 2;
137       break;
138 
139    case VA_FOURCC('P','0','1','0'):
140    case VA_FOURCC('P','0','1','6'):
141       img->num_planes = 2;
142       img->pitches[0] = w * 2;
143       img->offsets[0] = 0;
144       img->pitches[1] = w * 2;
145       img->offsets[1] = w * h * 2;
146       img->data_size  = w * h * 3;
147       break;
148 
149    case VA_FOURCC('I','4','2','0'):
150    case VA_FOURCC('Y','V','1','2'):
151       img->num_planes = 3;
152       img->pitches[0] = w;
153       img->offsets[0] = 0;
154       img->pitches[1] = w / 2;
155       img->offsets[1] = w * h;
156       img->pitches[2] = w / 2;
157       img->offsets[2] = w * h * 5 / 4;
158       img->data_size  = w * h * 3 / 2;
159       break;
160 
161    case VA_FOURCC('U','Y','V','Y'):
162    case VA_FOURCC('Y','U','Y','V'):
163       img->num_planes = 1;
164       img->pitches[0] = w * 2;
165       img->offsets[0] = 0;
166       img->data_size  = w * h * 2;
167       break;
168 
169    case VA_FOURCC('B','G','R','A'):
170    case VA_FOURCC('R','G','B','A'):
171    case VA_FOURCC('B','G','R','X'):
172    case VA_FOURCC('R','G','B','X'):
173       img->num_planes = 1;
174       img->pitches[0] = w * 4;
175       img->offsets[0] = 0;
176       img->data_size  = w * h * 4;
177       break;
178 
179    default:
180       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
181    }
182 
183    status =  vlVaCreateBuffer(ctx, 0, VAImageBufferType,
184                            align(img->data_size, 16),
185                            1, NULL, &img->buf);
186    if (status != VA_STATUS_SUCCESS)
187       return status;
188    *image = *img;
189 
190    return status;
191 }
192 
193 VAStatus
vlVaDeriveImage(VADriverContextP ctx,VASurfaceID surface,VAImage * image)194 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
195 {
196    vlVaDriver *drv;
197    vlVaSurface *surf;
198    vlVaBuffer *img_buf;
199    VAImage *img;
200    struct pipe_surface **surfaces;
201    int w;
202    int h;
203    int i;
204 
205    if (!ctx)
206       return VA_STATUS_ERROR_INVALID_CONTEXT;
207 
208    drv = VL_VA_DRIVER(ctx);
209 
210    if (!drv)
211       return VA_STATUS_ERROR_INVALID_CONTEXT;
212 
213    surf = handle_table_get(drv->htab, surface);
214 
215    if (!surf || !surf->buffer || surf->buffer->interlaced)
216       return VA_STATUS_ERROR_INVALID_SURFACE;
217 
218    surfaces = surf->buffer->get_surfaces(surf->buffer);
219    if (!surfaces || !surfaces[0]->texture)
220       return VA_STATUS_ERROR_ALLOCATION_FAILED;
221 
222    img = CALLOC(1, sizeof(VAImage));
223    if (!img)
224       return VA_STATUS_ERROR_ALLOCATION_FAILED;
225 
226    img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
227    img->buf = VA_INVALID_ID;
228    img->width = surf->buffer->width;
229    img->height = surf->buffer->height;
230    img->num_palette_entries = 0;
231    img->entry_bytes = 0;
232    w = align(surf->buffer->width, 2);
233    h = align(surf->buffer->height, 2);
234 
235    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
236       if (img->format.fourcc == formats[i].fourcc) {
237          img->format = formats[i];
238          break;
239       }
240    }
241 
242    switch (img->format.fourcc) {
243    case VA_FOURCC('U','Y','V','Y'):
244    case VA_FOURCC('Y','U','Y','V'):
245       img->num_planes = 1;
246       img->pitches[0] = w * 2;
247       img->offsets[0] = 0;
248       img->data_size  = w * h * 2;
249       break;
250 
251    case VA_FOURCC('B','G','R','A'):
252    case VA_FOURCC('R','G','B','A'):
253    case VA_FOURCC('B','G','R','X'):
254    case VA_FOURCC('R','G','B','X'):
255       img->num_planes = 1;
256       img->pitches[0] = w * 4;
257       img->offsets[0] = 0;
258       img->data_size  = w * h * 4;
259       break;
260 
261    default:
262       /* VaDeriveImage is designed for contiguous planes. */
263       FREE(img);
264       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
265    }
266 
267    img_buf = CALLOC(1, sizeof(vlVaBuffer));
268    if (!img_buf) {
269       FREE(img);
270       return VA_STATUS_ERROR_ALLOCATION_FAILED;
271    }
272 
273    mtx_lock(&drv->mutex);
274    img->image_id = handle_table_add(drv->htab, img);
275 
276    img_buf->type = VAImageBufferType;
277    img_buf->size = img->data_size;
278    img_buf->num_elements = 1;
279 
280    pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
281 
282    img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
283    mtx_unlock(&drv->mutex);
284 
285    *image = *img;
286 
287    return VA_STATUS_SUCCESS;
288 }
289 
290 VAStatus
vlVaDestroyImage(VADriverContextP ctx,VAImageID image)291 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
292 {
293    vlVaDriver *drv;
294    VAImage  *vaimage;
295    VAStatus status;
296 
297    if (!ctx)
298       return VA_STATUS_ERROR_INVALID_CONTEXT;
299 
300    drv = VL_VA_DRIVER(ctx);
301    mtx_lock(&drv->mutex);
302    vaimage = handle_table_get(drv->htab, image);
303    if (!vaimage) {
304       mtx_unlock(&drv->mutex);
305       return VA_STATUS_ERROR_INVALID_IMAGE;
306    }
307 
308    handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
309    mtx_unlock(&drv->mutex);
310    status = vlVaDestroyBuffer(ctx, vaimage->buf);
311    FREE(vaimage);
312    return status;
313 }
314 
315 VAStatus
vlVaSetImagePalette(VADriverContextP ctx,VAImageID image,unsigned char * palette)316 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
317 {
318    if (!ctx)
319       return VA_STATUS_ERROR_INVALID_CONTEXT;
320 
321    return VA_STATUS_ERROR_UNIMPLEMENTED;
322 }
323 
324 VAStatus
vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image)325 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
326              unsigned int width, unsigned int height, VAImageID image)
327 {
328    vlVaDriver *drv;
329    vlVaSurface *surf;
330    vlVaBuffer *img_buf;
331    VAImage *vaimage;
332    struct pipe_sampler_view **views;
333    enum pipe_format format;
334    bool convert = false;
335    void *data[3];
336    unsigned pitches[3], i, j;
337 
338    if (!ctx)
339       return VA_STATUS_ERROR_INVALID_CONTEXT;
340 
341    drv = VL_VA_DRIVER(ctx);
342 
343    mtx_lock(&drv->mutex);
344    surf = handle_table_get(drv->htab, surface);
345    if (!surf || !surf->buffer) {
346       mtx_unlock(&drv->mutex);
347       return VA_STATUS_ERROR_INVALID_SURFACE;
348    }
349 
350    vaimage = handle_table_get(drv->htab, image);
351    if (!vaimage) {
352       mtx_unlock(&drv->mutex);
353       return VA_STATUS_ERROR_INVALID_IMAGE;
354    }
355 
356    img_buf = handle_table_get(drv->htab, vaimage->buf);
357    if (!img_buf) {
358       mtx_unlock(&drv->mutex);
359       return VA_STATUS_ERROR_INVALID_BUFFER;
360    }
361 
362    format = VaFourccToPipeFormat(vaimage->format.fourcc);
363    if (format == PIPE_FORMAT_NONE) {
364       mtx_unlock(&drv->mutex);
365       return VA_STATUS_ERROR_OPERATION_FAILED;
366    }
367 
368    if (format != surf->buffer->buffer_format) {
369       /* support NV12 to YV12 and IYUV conversion now only */
370       if ((format == PIPE_FORMAT_YV12 &&
371           surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
372           (format == PIPE_FORMAT_IYUV &&
373           surf->buffer->buffer_format == PIPE_FORMAT_NV12))
374          convert = true;
375       else {
376          mtx_unlock(&drv->mutex);
377          return VA_STATUS_ERROR_OPERATION_FAILED;
378       }
379    }
380 
381    views = surf->buffer->get_sampler_view_planes(surf->buffer);
382    if (!views) {
383       mtx_unlock(&drv->mutex);
384       return VA_STATUS_ERROR_OPERATION_FAILED;
385    }
386 
387    for (i = 0; i < vaimage->num_planes; i++) {
388       data[i] = img_buf->data + vaimage->offsets[i];
389       pitches[i] = vaimage->pitches[i];
390    }
391    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
392       void *tmp_d;
393       unsigned tmp_p;
394       tmp_d  = data[1];
395       data[1] = data[2];
396       data[2] = tmp_d;
397       tmp_p = pitches[1];
398       pitches[1] = pitches[2];
399       pitches[2] = tmp_p;
400    }
401 
402    for (i = 0; i < vaimage->num_planes; i++) {
403       unsigned width, height;
404       if (!views[i]) continue;
405       vlVaVideoSurfaceSize(surf, i, &width, &height);
406       for (j = 0; j < views[i]->texture->array_size; ++j) {
407          struct pipe_box box = {0, 0, j, width, height, 1};
408          struct pipe_transfer *transfer;
409          uint8_t *map;
410          map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
411                   PIPE_TRANSFER_READ, &box, &transfer);
412          if (!map) {
413             mtx_unlock(&drv->mutex);
414             return VA_STATUS_ERROR_OPERATION_FAILED;
415          }
416 
417          if (i == 1 && convert) {
418             u_copy_nv12_to_yv12(data, pitches, i, j,
419                transfer->stride, views[i]->texture->array_size,
420                map, box.width, box.height);
421          } else {
422             util_copy_rect(data[i] + pitches[i] * j,
423                views[i]->texture->format,
424                pitches[i] * views[i]->texture->array_size, 0, 0,
425                box.width, box.height, map, transfer->stride, 0, 0);
426          }
427          pipe_transfer_unmap(drv->pipe, transfer);
428       }
429    }
430    mtx_unlock(&drv->mutex);
431 
432    return VA_STATUS_SUCCESS;
433 }
434 
435 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)436 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
437              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
438              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
439 {
440    vlVaDriver *drv;
441    vlVaSurface *surf;
442    vlVaBuffer *img_buf;
443    VAImage *vaimage;
444    struct pipe_sampler_view **views;
445    enum pipe_format format;
446    void *data[3];
447    unsigned pitches[3], i, j;
448 
449    if (!ctx)
450       return VA_STATUS_ERROR_INVALID_CONTEXT;
451 
452    drv = VL_VA_DRIVER(ctx);
453    mtx_lock(&drv->mutex);
454 
455    surf = handle_table_get(drv->htab, surface);
456    if (!surf || !surf->buffer) {
457       mtx_unlock(&drv->mutex);
458       return VA_STATUS_ERROR_INVALID_SURFACE;
459    }
460 
461    vaimage = handle_table_get(drv->htab, image);
462    if (!vaimage) {
463       mtx_unlock(&drv->mutex);
464       return VA_STATUS_ERROR_INVALID_IMAGE;
465    }
466 
467    img_buf = handle_table_get(drv->htab, vaimage->buf);
468    if (!img_buf) {
469       mtx_unlock(&drv->mutex);
470       return VA_STATUS_ERROR_INVALID_BUFFER;
471    }
472 
473    if (img_buf->derived_surface.resource) {
474       /* Attempting to transfer derived image to surface */
475       mtx_unlock(&drv->mutex);
476       return VA_STATUS_ERROR_UNIMPLEMENTED;
477    }
478 
479    format = VaFourccToPipeFormat(vaimage->format.fourcc);
480 
481    if (format == PIPE_FORMAT_NONE) {
482       mtx_unlock(&drv->mutex);
483       return VA_STATUS_ERROR_OPERATION_FAILED;
484    }
485 
486    if ((format != surf->buffer->buffer_format) &&
487          ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
488          ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
489       struct pipe_video_buffer *tmp_buf;
490 
491       surf->templat.buffer_format = format;
492       if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
493           format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
494           format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
495          surf->templat.interlaced = false;
496       tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
497 
498       if (!tmp_buf) {
499          mtx_unlock(&drv->mutex);
500          return VA_STATUS_ERROR_ALLOCATION_FAILED;
501       }
502 
503       surf->buffer->destroy(surf->buffer);
504       surf->buffer = tmp_buf;
505    }
506 
507    views = surf->buffer->get_sampler_view_planes(surf->buffer);
508    if (!views) {
509       mtx_unlock(&drv->mutex);
510       return VA_STATUS_ERROR_OPERATION_FAILED;
511    }
512 
513    for (i = 0; i < vaimage->num_planes; i++) {
514       data[i] = img_buf->data + vaimage->offsets[i];
515       pitches[i] = vaimage->pitches[i];
516    }
517    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
518       void *tmp_d;
519       unsigned tmp_p;
520       tmp_d  = data[1];
521       data[1] = data[2];
522       data[2] = tmp_d;
523       tmp_p = pitches[1];
524       pitches[1] = pitches[2];
525       pitches[2] = tmp_p;
526    }
527 
528    for (i = 0; i < vaimage->num_planes; ++i) {
529       unsigned width, height;
530       struct pipe_resource *tex;
531 
532       if (!views[i]) continue;
533       tex = views[i]->texture;
534 
535       vlVaVideoSurfaceSize(surf, i, &width, &height);
536       for (j = 0; j < tex->array_size; ++j) {
537          struct pipe_box dst_box = {0, 0, j, width, height, 1};
538 
539          if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
540              && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
541              && i == 1) {
542             struct pipe_transfer *transfer = NULL;
543             uint8_t *map = NULL;
544 
545             map = drv->pipe->transfer_map(drv->pipe,
546                                           tex,
547                                           0,
548                                           PIPE_TRANSFER_WRITE |
549                                           PIPE_TRANSFER_DISCARD_RANGE,
550                                           &dst_box, &transfer);
551             if (map == NULL) {
552                mtx_unlock(&drv->mutex);
553                return VA_STATUS_ERROR_OPERATION_FAILED;
554             }
555 
556             u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
557                                   transfer->stride, tex->array_size,
558                                   map, dst_box.width, dst_box.height);
559             pipe_transfer_unmap(drv->pipe, transfer);
560          } else {
561             drv->pipe->texture_subdata(drv->pipe, tex, 0,
562                                        PIPE_TRANSFER_WRITE, &dst_box,
563                                        data[i] + pitches[i] * j,
564                                        pitches[i] * views[i]->texture->array_size, 0);
565          }
566       }
567    }
568    mtx_unlock(&drv->mutex);
569 
570    return VA_STATUS_SUCCESS;
571 }
572