1 /**************************************************************************
3 * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4 * Copyright 2014 Advanced Micro Devices, Inc.
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:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
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.
27 **************************************************************************/
29 #include "pipe/p_screen.h"
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"
36 #include "vl/vl_winsys.h"
37 #include "vl/vl_video_buffer.h"
39 #include "va_private.h"
41 static const VAImageFormat formats
[] =
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}
61 vlVaVideoSurfaceSize(vlVaSurface
*p_surf
, int component
,
62 unsigned *width
, unsigned *height
)
64 *width
= p_surf
->templat
.width
;
65 *height
= p_surf
->templat
.height
;
67 vl_video_buffer_adjust_size(width
, height
, component
,
68 p_surf
->templat
.chroma_format
,
69 p_surf
->templat
.interlaced
);
73 vlVaQueryImageFormats(VADriverContextP ctx
, VAImageFormat
*format_list
, int *num_formats
)
75 struct pipe_screen
*pscreen
;
76 enum pipe_format format
;
79 STATIC_ASSERT(ARRAY_SIZE(formats
) == VL_VA_MAX_IMAGE_FORMATS
);
82 return VA_STATUS_ERROR_INVALID_CONTEXT
;
84 if (!(format_list
&& num_formats
))
85 return VA_STATUS_ERROR_INVALID_PARAMETER
;
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
];
97 return VA_STATUS_SUCCESS
;
101 vlVaCreateImage(VADriverContextP ctx
, VAImageFormat
*format
, int width
, int height
, VAImage
*image
)
109 return VA_STATUS_ERROR_INVALID_CONTEXT
;
111 if (!(format
&& image
&& width
&& height
))
112 return VA_STATUS_ERROR_INVALID_PARAMETER
;
114 drv
= VL_VA_DRIVER(ctx
);
116 img
= CALLOC(1, sizeof(VAImage
));
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
);
123 img
->format
= *format
;
125 img
->height
= height
;
127 h
= align(height
, 2);
129 switch (format
->fourcc
) {
130 case VA_FOURCC('N','V','1','2'):
135 img
->offsets
[1] = w
* h
;
136 img
->data_size
= w
* h
* 3 / 2;
139 case VA_FOURCC('P','0','1','0'):
140 case VA_FOURCC('P','0','1','6'):
142 img
->pitches
[0] = w
* 2;
144 img
->pitches
[1] = w
* 2;
145 img
->offsets
[1] = w
* h
* 2;
146 img
->data_size
= w
* h
* 3;
149 case VA_FOURCC('I','4','2','0'):
150 case VA_FOURCC('Y','V','1','2'):
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;
161 case VA_FOURCC('U','Y','V','Y'):
162 case VA_FOURCC('Y','U','Y','V'):
164 img
->pitches
[0] = w
* 2;
166 img
->data_size
= w
* h
* 2;
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'):
174 img
->pitches
[0] = w
* 4;
176 img
->data_size
= w
* h
* 4;
180 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT
;
183 status
= vlVaCreateBuffer(ctx
, 0, VAImageBufferType
,
184 align(img
->data_size
, 16),
186 if (status
!= VA_STATUS_SUCCESS
)
194 vlVaDeriveImage(VADriverContextP ctx
, VASurfaceID surface
, VAImage
*image
)
200 struct pipe_screen
*screen
;
201 struct pipe_surface
**surfaces
;
209 return VA_STATUS_ERROR_INVALID_CONTEXT
;
211 drv
= VL_VA_DRIVER(ctx
);
214 return VA_STATUS_ERROR_INVALID_CONTEXT
;
216 screen
= VL_VA_PSCREEN(ctx
);
219 return VA_STATUS_ERROR_INVALID_CONTEXT
;
221 surf
= handle_table_get(drv
->htab
, surface
);
223 if (!surf
|| !surf
->buffer
)
224 return VA_STATUS_ERROR_INVALID_SURFACE
;
226 if (surf
->buffer
->interlaced
)
227 return VA_STATUS_ERROR_OPERATION_FAILED
;
229 surfaces
= surf
->buffer
->get_surfaces(surf
->buffer
);
230 if (!surfaces
|| !surfaces
[0]->texture
)
231 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
233 img
= CALLOC(1, sizeof(VAImage
));
235 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
237 img
->format
.fourcc
= PipeFormatToVaFourcc(surf
->buffer
->buffer_format
);
238 img
->buf
= VA_INVALID_ID
;
239 /* Use the visible dimensions. */
240 img
->width
= surf
->templat
.width
;
241 img
->height
= surf
->templat
.height
;
242 img
->num_palette_entries
= 0;
243 img
->entry_bytes
= 0;
244 /* Image data size is computed using internal dimensions. */
245 w
= align(surf
->buffer
->width
, 2);
246 h
= align(surf
->buffer
->height
, 2);
248 for (i
= 0; i
< ARRAY_SIZE(formats
); ++i
) {
249 if (img
->format
.fourcc
== formats
[i
].fourcc
) {
250 img
->format
= formats
[i
];
255 mtx_lock(&drv
->mutex
);
256 if (screen
->resource_get_info
) {
257 screen
->resource_get_info(screen
, surfaces
[0]->texture
, &stride
,
263 switch (img
->format
.fourcc
) {
264 case VA_FOURCC('U','Y','V','Y'):
265 case VA_FOURCC('Y','U','Y','V'):
266 img
->pitches
[0] = stride
> 0 ? stride
: w
* 2;
267 assert(img
->pitches
[0] >= (w
* 2));
270 case VA_FOURCC('B','G','R','A'):
271 case VA_FOURCC('R','G','B','A'):
272 case VA_FOURCC('B','G','R','X'):
273 case VA_FOURCC('R','G','B','X'):
274 img
->pitches
[0] = stride
> 0 ? stride
: w
* 4;
275 assert(img
->pitches
[0] >= (w
* 4));
279 /* VaDeriveImage only supports contiguous planes. But there is now a
280 more generic api vlVaExportSurfaceHandle. */
282 mtx_unlock(&drv
->mutex
);
283 return VA_STATUS_ERROR_OPERATION_FAILED
;
287 img
->offsets
[0] = offset
;
288 img
->data_size
= img
->pitches
[0] * h
;
290 img_buf
= CALLOC(1, sizeof(vlVaBuffer
));
293 mtx_unlock(&drv
->mutex
);
294 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
297 img
->image_id
= handle_table_add(drv
->htab
, img
);
299 img_buf
->type
= VAImageBufferType
;
300 img_buf
->size
= img
->data_size
;
301 img_buf
->num_elements
= 1;
303 pipe_resource_reference(&img_buf
->derived_surface
.resource
, surfaces
[0]->texture
);
305 img
->buf
= handle_table_add(VL_VA_DRIVER(ctx
)->htab
, img_buf
);
306 mtx_unlock(&drv
->mutex
);
310 return VA_STATUS_SUCCESS
;
314 vlVaDestroyImage(VADriverContextP ctx
, VAImageID image
)
321 return VA_STATUS_ERROR_INVALID_CONTEXT
;
323 drv
= VL_VA_DRIVER(ctx
);
324 mtx_lock(&drv
->mutex
);
325 vaimage
= handle_table_get(drv
->htab
, image
);
327 mtx_unlock(&drv
->mutex
);
328 return VA_STATUS_ERROR_INVALID_IMAGE
;
331 handle_table_remove(VL_VA_DRIVER(ctx
)->htab
, image
);
332 mtx_unlock(&drv
->mutex
);
333 status
= vlVaDestroyBuffer(ctx
, vaimage
->buf
);
339 vlVaSetImagePalette(VADriverContextP ctx
, VAImageID image
, unsigned char *palette
)
342 return VA_STATUS_ERROR_INVALID_CONTEXT
;
344 return VA_STATUS_ERROR_UNIMPLEMENTED
;
348 vlVaGetImage(VADriverContextP ctx
, VASurfaceID surface
, int x
, int y
,
349 unsigned int width
, unsigned int height
, VAImageID image
)
355 struct pipe_sampler_view
**views
;
356 enum pipe_format format
;
357 bool convert
= false;
359 unsigned pitches
[3], i
, j
;
362 return VA_STATUS_ERROR_INVALID_CONTEXT
;
364 drv
= VL_VA_DRIVER(ctx
);
366 mtx_lock(&drv
->mutex
);
367 surf
= handle_table_get(drv
->htab
, surface
);
368 if (!surf
|| !surf
->buffer
) {
369 mtx_unlock(&drv
->mutex
);
370 return VA_STATUS_ERROR_INVALID_SURFACE
;
373 vaimage
= handle_table_get(drv
->htab
, image
);
375 mtx_unlock(&drv
->mutex
);
376 return VA_STATUS_ERROR_INVALID_IMAGE
;
379 if (x
< 0 || y
< 0) {
380 mtx_unlock(&drv
->mutex
);
381 return VA_STATUS_ERROR_INVALID_PARAMETER
;
384 if (x
+ width
> surf
->templat
.width
||
385 y
+ height
> surf
->templat
.height
) {
386 mtx_unlock(&drv
->mutex
);
387 return VA_STATUS_ERROR_INVALID_PARAMETER
;
390 if (width
> vaimage
->width
||
391 height
> vaimage
->height
) {
392 mtx_unlock(&drv
->mutex
);
393 return VA_STATUS_ERROR_INVALID_PARAMETER
;
396 img_buf
= handle_table_get(drv
->htab
, vaimage
->buf
);
398 mtx_unlock(&drv
->mutex
);
399 return VA_STATUS_ERROR_INVALID_BUFFER
;
402 format
= VaFourccToPipeFormat(vaimage
->format
.fourcc
);
403 if (format
== PIPE_FORMAT_NONE
) {
404 mtx_unlock(&drv
->mutex
);
405 return VA_STATUS_ERROR_OPERATION_FAILED
;
408 if (format
!= surf
->buffer
->buffer_format
) {
409 /* support NV12 to YV12 and IYUV conversion now only */
410 if ((format
== PIPE_FORMAT_YV12
&&
411 surf
->buffer
->buffer_format
== PIPE_FORMAT_NV12
) ||
412 (format
== PIPE_FORMAT_IYUV
&&
413 surf
->buffer
->buffer_format
== PIPE_FORMAT_NV12
))
416 mtx_unlock(&drv
->mutex
);
417 return VA_STATUS_ERROR_OPERATION_FAILED
;
421 views
= surf
->buffer
->get_sampler_view_planes(surf
->buffer
);
423 mtx_unlock(&drv
->mutex
);
424 return VA_STATUS_ERROR_OPERATION_FAILED
;
427 for (i
= 0; i
< vaimage
->num_planes
; i
++) {
428 data
[i
] = img_buf
->data
+ vaimage
->offsets
[i
];
429 pitches
[i
] = vaimage
->pitches
[i
];
431 if (vaimage
->format
.fourcc
== VA_FOURCC('I','4','2','0')) {
438 pitches
[1] = pitches
[2];
442 for (i
= 0; i
< vaimage
->num_planes
; i
++) {
443 unsigned box_w
= align(width
, 2);
444 unsigned box_h
= align(height
, 2);
445 unsigned box_x
= x
& ~1;
446 unsigned box_y
= y
& ~1;
447 if (!views
[i
]) continue;
448 vl_video_buffer_adjust_size(&box_w
, &box_h
, i
,
449 surf
->templat
.chroma_format
,
450 surf
->templat
.interlaced
);
451 vl_video_buffer_adjust_size(&box_x
, &box_y
, i
,
452 surf
->templat
.chroma_format
,
453 surf
->templat
.interlaced
);
454 for (j
= 0; j
< views
[i
]->texture
->array_size
; ++j
) {
455 struct pipe_box box
= {box_x
, box_y
, j
, box_w
, box_h
, 1};
456 struct pipe_transfer
*transfer
;
458 map
= drv
->pipe
->transfer_map(drv
->pipe
, views
[i
]->texture
, 0,
459 PIPE_TRANSFER_READ
, &box
, &transfer
);
461 mtx_unlock(&drv
->mutex
);
462 return VA_STATUS_ERROR_OPERATION_FAILED
;
465 if (i
== 1 && convert
) {
466 u_copy_nv12_to_yv12(data
, pitches
, i
, j
,
467 transfer
->stride
, views
[i
]->texture
->array_size
,
468 map
, box
.width
, box
.height
);
470 util_copy_rect(data
[i
] + pitches
[i
] * j
,
471 views
[i
]->texture
->format
,
472 pitches
[i
] * views
[i
]->texture
->array_size
, 0, 0,
473 box
.width
, box
.height
, map
, transfer
->stride
, 0, 0);
475 pipe_transfer_unmap(drv
->pipe
, transfer
);
478 mtx_unlock(&drv
->mutex
);
480 return VA_STATUS_SUCCESS
;
484 vlVaPutImage(VADriverContextP ctx
, VASurfaceID surface
, VAImageID image
,
485 int src_x
, int src_y
, unsigned int src_width
, unsigned int src_height
,
486 int dest_x
, int dest_y
, unsigned int dest_width
, unsigned int dest_height
)
492 struct pipe_sampler_view
**views
;
493 enum pipe_format format
;
495 unsigned pitches
[3], i
, j
;
498 return VA_STATUS_ERROR_INVALID_CONTEXT
;
500 drv
= VL_VA_DRIVER(ctx
);
501 mtx_lock(&drv
->mutex
);
503 surf
= handle_table_get(drv
->htab
, surface
);
504 if (!surf
|| !surf
->buffer
) {
505 mtx_unlock(&drv
->mutex
);
506 return VA_STATUS_ERROR_INVALID_SURFACE
;
509 vaimage
= handle_table_get(drv
->htab
, image
);
511 mtx_unlock(&drv
->mutex
);
512 return VA_STATUS_ERROR_INVALID_IMAGE
;
515 img_buf
= handle_table_get(drv
->htab
, vaimage
->buf
);
517 mtx_unlock(&drv
->mutex
);
518 return VA_STATUS_ERROR_INVALID_BUFFER
;
521 if (img_buf
->derived_surface
.resource
) {
522 /* Attempting to transfer derived image to surface */
523 mtx_unlock(&drv
->mutex
);
524 return VA_STATUS_ERROR_UNIMPLEMENTED
;
527 format
= VaFourccToPipeFormat(vaimage
->format
.fourcc
);
529 if (format
== PIPE_FORMAT_NONE
) {
530 mtx_unlock(&drv
->mutex
);
531 return VA_STATUS_ERROR_OPERATION_FAILED
;
534 if ((format
!= surf
->buffer
->buffer_format
) &&
535 ((format
!= PIPE_FORMAT_YV12
) || (surf
->buffer
->buffer_format
!= PIPE_FORMAT_NV12
)) &&
536 ((format
!= PIPE_FORMAT_IYUV
) || (surf
->buffer
->buffer_format
!= PIPE_FORMAT_NV12
))) {
537 struct pipe_video_buffer
*tmp_buf
;
539 surf
->templat
.buffer_format
= format
;
540 if (format
== PIPE_FORMAT_YUYV
|| format
== PIPE_FORMAT_UYVY
||
541 format
== PIPE_FORMAT_B8G8R8A8_UNORM
|| format
== PIPE_FORMAT_B8G8R8X8_UNORM
||
542 format
== PIPE_FORMAT_R8G8B8A8_UNORM
|| format
== PIPE_FORMAT_R8G8B8X8_UNORM
)
543 surf
->templat
.interlaced
= false;
544 tmp_buf
= drv
->pipe
->create_video_buffer(drv
->pipe
, &surf
->templat
);
547 mtx_unlock(&drv
->mutex
);
548 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
551 surf
->buffer
->destroy(surf
->buffer
);
552 surf
->buffer
= tmp_buf
;
555 views
= surf
->buffer
->get_sampler_view_planes(surf
->buffer
);
557 mtx_unlock(&drv
->mutex
);
558 return VA_STATUS_ERROR_OPERATION_FAILED
;
561 for (i
= 0; i
< vaimage
->num_planes
; i
++) {
562 data
[i
] = img_buf
->data
+ vaimage
->offsets
[i
];
563 pitches
[i
] = vaimage
->pitches
[i
];
565 if (vaimage
->format
.fourcc
== VA_FOURCC('I','4','2','0')) {
572 pitches
[1] = pitches
[2];
576 for (i
= 0; i
< vaimage
->num_planes
; ++i
) {
577 unsigned width
, height
;
578 struct pipe_resource
*tex
;
580 if (!views
[i
]) continue;
581 tex
= views
[i
]->texture
;
583 vlVaVideoSurfaceSize(surf
, i
, &width
, &height
);
584 for (j
= 0; j
< tex
->array_size
; ++j
) {
585 struct pipe_box dst_box
= {0, 0, j
, width
, height
, 1};
587 if (((format
== PIPE_FORMAT_YV12
) || (format
== PIPE_FORMAT_IYUV
))
588 && (surf
->buffer
->buffer_format
== PIPE_FORMAT_NV12
)
590 struct pipe_transfer
*transfer
= NULL
;
593 map
= drv
->pipe
->transfer_map(drv
->pipe
,
596 PIPE_TRANSFER_WRITE
|
597 PIPE_TRANSFER_DISCARD_RANGE
,
598 &dst_box
, &transfer
);
600 mtx_unlock(&drv
->mutex
);
601 return VA_STATUS_ERROR_OPERATION_FAILED
;
604 u_copy_nv12_from_yv12((const void * const*) data
, pitches
, i
, j
,
605 transfer
->stride
, tex
->array_size
,
606 map
, dst_box
.width
, dst_box
.height
);
607 pipe_transfer_unmap(drv
->pipe
, transfer
);
609 drv
->pipe
->texture_subdata(drv
->pipe
, tex
, 0,
610 PIPE_TRANSFER_WRITE
, &dst_box
,
611 data
[i
] + pitches
[i
] * j
,
612 pitches
[i
] * views
[i
]->texture
->array_size
, 0);
616 mtx_unlock(&drv
->mutex
);
618 return VA_STATUS_SUCCESS
;