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('I','4','2','0')},
45 {VA_FOURCC('Y','V','1','2')},
46 {VA_FOURCC('Y','U','Y','V')},
47 {VA_FOURCC('U','Y','V','Y')},
48 {.fourcc
= VA_FOURCC('B','G','R','A'), .byte_order
= VA_LSB_FIRST
, 32, 32,
49 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
50 {.fourcc
= VA_FOURCC('R','G','B','A'), .byte_order
= VA_LSB_FIRST
, 32, 32,
51 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
52 {.fourcc
= VA_FOURCC('B','G','R','X'), .byte_order
= VA_LSB_FIRST
, 32, 24,
53 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
54 {.fourcc
= VA_FOURCC('R','G','B','X'), .byte_order
= VA_LSB_FIRST
, 32, 24,
55 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
59 vlVaVideoSurfaceSize(vlVaSurface
*p_surf
, int component
,
60 unsigned *width
, unsigned *height
)
62 *width
= p_surf
->templat
.width
;
63 *height
= p_surf
->templat
.height
;
65 vl_video_buffer_adjust_size(width
, height
, component
,
66 p_surf
->templat
.chroma_format
,
67 p_surf
->templat
.interlaced
);
71 vlVaQueryImageFormats(VADriverContextP ctx
, VAImageFormat
*format_list
, int *num_formats
)
73 struct pipe_screen
*pscreen
;
74 enum pipe_format format
;
77 STATIC_ASSERT(ARRAY_SIZE(formats
) == VL_VA_MAX_IMAGE_FORMATS
);
80 return VA_STATUS_ERROR_INVALID_CONTEXT
;
82 if (!(format_list
&& num_formats
))
83 return VA_STATUS_ERROR_INVALID_PARAMETER
;
86 pscreen
= VL_VA_PSCREEN(ctx
);
87 for (i
= 0; i
< ARRAY_SIZE(formats
); ++i
) {
88 format
= VaFourccToPipeFormat(formats
[i
].fourcc
);
89 if (pscreen
->is_video_format_supported(pscreen
, format
,
90 PIPE_VIDEO_PROFILE_UNKNOWN
,
91 PIPE_VIDEO_ENTRYPOINT_BITSTREAM
))
92 format_list
[(*num_formats
)++] = formats
[i
];
95 return VA_STATUS_SUCCESS
;
99 vlVaCreateImage(VADriverContextP ctx
, VAImageFormat
*format
, int width
, int height
, VAImage
*image
)
107 return VA_STATUS_ERROR_INVALID_CONTEXT
;
109 if (!(format
&& image
&& width
&& height
))
110 return VA_STATUS_ERROR_INVALID_PARAMETER
;
112 drv
= VL_VA_DRIVER(ctx
);
114 img
= CALLOC(1, sizeof(VAImage
));
116 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
117 pipe_mutex_lock(drv
->mutex
);
118 img
->image_id
= handle_table_add(drv
->htab
, img
);
119 pipe_mutex_unlock(drv
->mutex
);
121 img
->format
= *format
;
123 img
->height
= height
;
125 h
= align(height
, 2);
127 switch (format
->fourcc
) {
128 case VA_FOURCC('N','V','1','2'):
133 img
->offsets
[1] = w
* h
;
134 img
->data_size
= w
* h
* 3 / 2;
137 case VA_FOURCC('I','4','2','0'):
138 case VA_FOURCC('Y','V','1','2'):
142 img
->pitches
[1] = w
/ 2;
143 img
->offsets
[1] = w
* h
;
144 img
->pitches
[2] = w
/ 2;
145 img
->offsets
[2] = w
* h
* 5 / 4;
146 img
->data_size
= w
* h
* 3 / 2;
149 case VA_FOURCC('U','Y','V','Y'):
150 case VA_FOURCC('Y','U','Y','V'):
152 img
->pitches
[0] = w
* 2;
154 img
->data_size
= w
* h
* 2;
157 case VA_FOURCC('B','G','R','A'):
158 case VA_FOURCC('R','G','B','A'):
159 case VA_FOURCC('B','G','R','X'):
160 case VA_FOURCC('R','G','B','X'):
162 img
->pitches
[0] = w
* 4;
164 img
->data_size
= w
* h
* 4;
168 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT
;
171 status
= vlVaCreateBuffer(ctx
, 0, VAImageBufferType
,
172 align(img
->data_size
, 16),
174 if (status
!= VA_STATUS_SUCCESS
)
182 vlVaDeriveImage(VADriverContextP ctx
, VASurfaceID surface
, VAImage
*image
)
188 struct pipe_surface
**surfaces
;
194 return VA_STATUS_ERROR_INVALID_CONTEXT
;
196 drv
= VL_VA_DRIVER(ctx
);
199 return VA_STATUS_ERROR_INVALID_CONTEXT
;
201 surf
= handle_table_get(drv
->htab
, surface
);
203 if (!surf
|| !surf
->buffer
|| surf
->buffer
->interlaced
)
204 return VA_STATUS_ERROR_INVALID_SURFACE
;
206 surfaces
= surf
->buffer
->get_surfaces(surf
->buffer
);
207 if (!surfaces
|| !surfaces
[0]->texture
)
208 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
210 img
= CALLOC(1, sizeof(VAImage
));
212 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
214 img
->format
.fourcc
= PipeFormatToVaFourcc(surf
->buffer
->buffer_format
);
215 img
->buf
= VA_INVALID_ID
;
216 img
->width
= surf
->buffer
->width
;
217 img
->height
= surf
->buffer
->height
;
218 img
->num_palette_entries
= 0;
219 img
->entry_bytes
= 0;
220 w
= align(surf
->buffer
->width
, 2);
221 h
= align(surf
->buffer
->height
, 2);
223 for (i
= 0; i
< ARRAY_SIZE(formats
); ++i
) {
224 if (img
->format
.fourcc
== formats
[i
].fourcc
) {
225 img
->format
= formats
[i
];
230 switch (img
->format
.fourcc
) {
231 case VA_FOURCC('U','Y','V','Y'):
232 case VA_FOURCC('Y','U','Y','V'):
234 img
->pitches
[0] = w
* 2;
236 img
->data_size
= w
* h
* 2;
239 case VA_FOURCC('B','G','R','A'):
240 case VA_FOURCC('R','G','B','A'):
241 case VA_FOURCC('B','G','R','X'):
242 case VA_FOURCC('R','G','B','X'):
244 img
->pitches
[0] = w
* 4;
246 img
->data_size
= w
* h
* 4;
250 /* VaDeriveImage is designed for contiguous planes. */
252 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT
;
255 img_buf
= CALLOC(1, sizeof(vlVaBuffer
));
258 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
261 pipe_mutex_lock(drv
->mutex
);
262 img
->image_id
= handle_table_add(drv
->htab
, img
);
264 img_buf
->type
= VAImageBufferType
;
265 img_buf
->size
= img
->data_size
;
266 img_buf
->num_elements
= 1;
268 pipe_resource_reference(&img_buf
->derived_surface
.resource
, surfaces
[0]->texture
);
270 img
->buf
= handle_table_add(VL_VA_DRIVER(ctx
)->htab
, img_buf
);
271 pipe_mutex_unlock(drv
->mutex
);
275 return VA_STATUS_SUCCESS
;
279 vlVaDestroyImage(VADriverContextP ctx
, VAImageID image
)
286 return VA_STATUS_ERROR_INVALID_CONTEXT
;
288 drv
= VL_VA_DRIVER(ctx
);
289 pipe_mutex_lock(drv
->mutex
);
290 vaimage
= handle_table_get(drv
->htab
, image
);
292 pipe_mutex_unlock(drv
->mutex
);
293 return VA_STATUS_ERROR_INVALID_IMAGE
;
296 handle_table_remove(VL_VA_DRIVER(ctx
)->htab
, image
);
297 pipe_mutex_unlock(drv
->mutex
);
298 status
= vlVaDestroyBuffer(ctx
, vaimage
->buf
);
304 vlVaSetImagePalette(VADriverContextP ctx
, VAImageID image
, unsigned char *palette
)
307 return VA_STATUS_ERROR_INVALID_CONTEXT
;
309 return VA_STATUS_ERROR_UNIMPLEMENTED
;
313 vlVaGetImage(VADriverContextP ctx
, VASurfaceID surface
, int x
, int y
,
314 unsigned int width
, unsigned int height
, VAImageID image
)
320 struct pipe_sampler_view
**views
;
321 enum pipe_format format
;
322 bool convert
= false;
324 unsigned pitches
[3], i
, j
;
327 return VA_STATUS_ERROR_INVALID_CONTEXT
;
329 drv
= VL_VA_DRIVER(ctx
);
331 pipe_mutex_lock(drv
->mutex
);
332 surf
= handle_table_get(drv
->htab
, surface
);
333 if (!surf
|| !surf
->buffer
) {
334 pipe_mutex_unlock(drv
->mutex
);
335 return VA_STATUS_ERROR_INVALID_SURFACE
;
338 vaimage
= handle_table_get(drv
->htab
, image
);
340 pipe_mutex_unlock(drv
->mutex
);
341 return VA_STATUS_ERROR_INVALID_IMAGE
;
344 img_buf
= handle_table_get(drv
->htab
, vaimage
->buf
);
346 pipe_mutex_unlock(drv
->mutex
);
347 return VA_STATUS_ERROR_INVALID_BUFFER
;
350 format
= VaFourccToPipeFormat(vaimage
->format
.fourcc
);
351 if (format
== PIPE_FORMAT_NONE
) {
352 pipe_mutex_unlock(drv
->mutex
);
353 return VA_STATUS_ERROR_OPERATION_FAILED
;
356 if (format
!= surf
->buffer
->buffer_format
) {
357 /* support NV12 to YV12 and IYUV conversion now only */
358 if ((format
== PIPE_FORMAT_YV12
&&
359 surf
->buffer
->buffer_format
== PIPE_FORMAT_NV12
) ||
360 (format
== PIPE_FORMAT_IYUV
&&
361 surf
->buffer
->buffer_format
== PIPE_FORMAT_NV12
))
364 pipe_mutex_unlock(drv
->mutex
);
365 return VA_STATUS_ERROR_OPERATION_FAILED
;
369 views
= surf
->buffer
->get_sampler_view_planes(surf
->buffer
);
371 pipe_mutex_unlock(drv
->mutex
);
372 return VA_STATUS_ERROR_OPERATION_FAILED
;
375 for (i
= 0; i
< vaimage
->num_planes
; i
++) {
376 data
[i
] = img_buf
->data
+ vaimage
->offsets
[i
];
377 pitches
[i
] = vaimage
->pitches
[i
];
379 if (vaimage
->format
.fourcc
== VA_FOURCC('I','4','2','0')) {
386 pitches
[1] = pitches
[2];
390 for (i
= 0; i
< vaimage
->num_planes
; i
++) {
391 unsigned width
, height
;
392 if (!views
[i
]) continue;
393 vlVaVideoSurfaceSize(surf
, i
, &width
, &height
);
394 for (j
= 0; j
< views
[i
]->texture
->array_size
; ++j
) {
395 struct pipe_box box
= {0, 0, j
, width
, height
, 1};
396 struct pipe_transfer
*transfer
;
398 map
= drv
->pipe
->transfer_map(drv
->pipe
, views
[i
]->texture
, 0,
399 PIPE_TRANSFER_READ
, &box
, &transfer
);
401 pipe_mutex_unlock(drv
->mutex
);
402 return VA_STATUS_ERROR_OPERATION_FAILED
;
405 if (i
== 1 && convert
) {
406 u_copy_nv12_to_yv12(data
, pitches
, i
, j
,
407 transfer
->stride
, views
[i
]->texture
->array_size
,
408 map
, box
.width
, box
.height
);
410 util_copy_rect(data
[i
] + pitches
[i
] * j
,
411 views
[i
]->texture
->format
,
412 pitches
[i
] * views
[i
]->texture
->array_size
, 0, 0,
413 box
.width
, box
.height
, map
, transfer
->stride
, 0, 0);
415 pipe_transfer_unmap(drv
->pipe
, transfer
);
418 pipe_mutex_unlock(drv
->mutex
);
420 return VA_STATUS_SUCCESS
;
424 vlVaPutImage(VADriverContextP ctx
, VASurfaceID surface
, VAImageID image
,
425 int src_x
, int src_y
, unsigned int src_width
, unsigned int src_height
,
426 int dest_x
, int dest_y
, unsigned int dest_width
, unsigned int dest_height
)
432 struct pipe_sampler_view
**views
;
433 enum pipe_format format
;
435 unsigned pitches
[3], i
, j
;
438 return VA_STATUS_ERROR_INVALID_CONTEXT
;
440 drv
= VL_VA_DRIVER(ctx
);
441 pipe_mutex_lock(drv
->mutex
);
443 surf
= handle_table_get(drv
->htab
, surface
);
444 if (!surf
|| !surf
->buffer
) {
445 pipe_mutex_unlock(drv
->mutex
);
446 return VA_STATUS_ERROR_INVALID_SURFACE
;
449 vaimage
= handle_table_get(drv
->htab
, image
);
451 pipe_mutex_unlock(drv
->mutex
);
452 return VA_STATUS_ERROR_INVALID_IMAGE
;
455 img_buf
= handle_table_get(drv
->htab
, vaimage
->buf
);
457 pipe_mutex_unlock(drv
->mutex
);
458 return VA_STATUS_ERROR_INVALID_BUFFER
;
461 if (img_buf
->derived_surface
.resource
) {
462 /* Attempting to transfer derived image to surface */
463 pipe_mutex_unlock(drv
->mutex
);
464 return VA_STATUS_ERROR_UNIMPLEMENTED
;
467 format
= VaFourccToPipeFormat(vaimage
->format
.fourcc
);
469 if (format
== PIPE_FORMAT_NONE
) {
470 pipe_mutex_unlock(drv
->mutex
);
471 return VA_STATUS_ERROR_OPERATION_FAILED
;
474 if ((format
!= surf
->buffer
->buffer_format
) &&
475 ((format
!= PIPE_FORMAT_YV12
) || (surf
->buffer
->buffer_format
!= PIPE_FORMAT_NV12
)) &&
476 ((format
!= PIPE_FORMAT_IYUV
) || (surf
->buffer
->buffer_format
!= PIPE_FORMAT_NV12
))) {
477 struct pipe_video_buffer
*tmp_buf
;
478 struct pipe_video_buffer templat
= surf
->templat
;
480 templat
.buffer_format
= format
;
481 tmp_buf
= drv
->pipe
->create_video_buffer(drv
->pipe
, &templat
);
484 pipe_mutex_unlock(drv
->mutex
);
485 return VA_STATUS_ERROR_ALLOCATION_FAILED
;
488 surf
->buffer
->destroy(surf
->buffer
);
489 surf
->buffer
= tmp_buf
;
490 surf
->templat
.buffer_format
= format
;
493 views
= surf
->buffer
->get_sampler_view_planes(surf
->buffer
);
495 pipe_mutex_unlock(drv
->mutex
);
496 return VA_STATUS_ERROR_OPERATION_FAILED
;
499 for (i
= 0; i
< vaimage
->num_planes
; i
++) {
500 data
[i
] = img_buf
->data
+ vaimage
->offsets
[i
];
501 pitches
[i
] = vaimage
->pitches
[i
];
503 if (vaimage
->format
.fourcc
== VA_FOURCC('I','4','2','0')) {
510 pitches
[1] = pitches
[2];
514 for (i
= 0; i
< vaimage
->num_planes
; ++i
) {
515 unsigned width
, height
;
516 if (!views
[i
]) continue;
517 vlVaVideoSurfaceSize(surf
, i
, &width
, &height
);
518 if (((format
== PIPE_FORMAT_YV12
) || (format
== PIPE_FORMAT_IYUV
)) &&
519 (surf
->buffer
->buffer_format
== PIPE_FORMAT_NV12
)) {
520 struct pipe_transfer
*transfer
= NULL
;
522 struct pipe_box dst_box_1
= {0, 0, 0, width
, height
, 1};
523 map
= drv
->pipe
->transfer_map(drv
->pipe
,
526 PIPE_TRANSFER_DISCARD_RANGE
,
527 &dst_box_1
, &transfer
);
529 return VA_STATUS_ERROR_OPERATION_FAILED
;
531 u_copy_yv12_img_to_nv12_surf ((ubyte
* const*)data
, map
, width
, height
,
532 pitches
[i
], transfer
->stride
, i
);
533 pipe_transfer_unmap(drv
->pipe
, transfer
);
535 for (j
= 0; j
< views
[i
]->texture
->array_size
; ++j
) {
536 struct pipe_box dst_box
= {0, 0, j
, width
, height
, 1};
537 drv
->pipe
->texture_subdata(drv
->pipe
, views
[i
]->texture
, 0,
538 PIPE_TRANSFER_WRITE
, &dst_box
,
539 data
[i
] + pitches
[i
] * j
,
540 pitches
[i
] * views
[i
]->texture
->array_size
, 0);
544 pipe_mutex_unlock(drv
->mutex
);
546 return VA_STATUS_SUCCESS
;