1 /*****************************************************************************
2 * vlc_vaapi.c: VAAPI helper for VLC
3 *****************************************************************************
4 * Copyright (C) 2017 VLC authors, VideoLAN and VideoLabs
6 * Authors: Thomas Guillem <thomas@gllm.fr>
7 * Petri Hintukainen <phintuka@gmail.com>
8 * Victorien Le Couviour--Tuffet <victorien.lecouviour.tuffet@gmail.com>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 #include "vlc_vaapi.h"
38 #include <vlc_common.h>
39 #include <vlc_atomic.h>
40 #include <vlc_fourcc.h>
41 #include <vlc_filter.h>
42 #include <vlc_picture_pool.h>
44 /* This macro is designed to wrap any VA call, and in case of failure,
45 display the VA error string then goto the 'error' label (which you must
47 #define VA_CALL(o, f, args...) \
50 VAStatus s = f(args); \
51 if (s != VA_STATUS_SUCCESS) \
53 msg_Err(o, "%s: %s", #f, vaErrorStr(s)); \
58 /**************************
59 * VA instance management *
60 **************************/
62 struct vlc_vaapi_instance
{
64 VANativeDisplay native
;
65 vlc_vaapi_native_destroy_cb native_destroy_cb
;
66 atomic_uint pic_refcount
;
69 struct vlc_vaapi_instance
*
70 vlc_vaapi_InitializeInstance(vlc_object_t
*o
, VADisplay dpy
,
71 VANativeDisplay native
,
72 vlc_vaapi_native_destroy_cb native_destroy_cb
)
74 int major
= 0, minor
= 0;
75 VA_CALL(o
, vaInitialize
, dpy
, &major
, &minor
);
76 struct vlc_vaapi_instance
*inst
= malloc(sizeof(*inst
));
78 if (unlikely(inst
== NULL
))
81 inst
->native
= native
;
82 inst
->native_destroy_cb
= native_destroy_cb
;
83 atomic_init(&inst
->pic_refcount
, 1);
88 if (native
!= NULL
&& native_destroy_cb
!= NULL
)
89 native_destroy_cb(native
);
94 vlc_vaapi_HoldInstance(struct vlc_vaapi_instance
*inst
)
96 atomic_fetch_add(&inst
->pic_refcount
, 1);
101 vlc_vaapi_ReleaseInstance(struct vlc_vaapi_instance
*inst
)
103 if (atomic_fetch_sub(&inst
->pic_refcount
, 1) == 1)
105 vaTerminate(inst
->dpy
);
106 if (inst
->native
!= NULL
&& inst
->native_destroy_cb
!= NULL
)
107 inst
->native_destroy_cb(inst
->native
);
112 /**************************
113 * VAAPI create & destroy *
114 **************************/
117 vlc_vaapi_CreateContext(vlc_object_t
*o
, VADisplay dpy
, VAConfigID conf
,
118 int pic_w
, int pic_h
, int flag
,
119 VASurfaceID
*render_targets
, int num_render_targets
)
122 VA_CALL(o
, vaCreateContext
, dpy
, conf
, pic_w
, pic_h
, flag
,
123 render_targets
, num_render_targets
, &ctx
);
125 error
: return VA_INVALID_ID
;
129 vlc_vaapi_CreateBuffer(vlc_object_t
*o
, VADisplay dpy
, VAContextID ctx
,
130 VABufferType type
, unsigned int size
,
131 unsigned int num_elements
, void *data
)
134 VA_CALL(o
, vaCreateBuffer
, dpy
, ctx
, type
,
135 size
, num_elements
, data
, &buf_id
);
137 error
: return VA_INVALID_ID
;
141 vlc_vaapi_DeriveImage(vlc_object_t
*o
,
142 VADisplay dpy
, VASurfaceID surface
, VAImage
*image
)
144 VA_CALL(o
, vaDeriveImage
, dpy
, surface
, image
);
146 error
: return VLC_EGENERIC
;
150 vlc_vaapi_CreateImage(vlc_object_t
*o
, VADisplay dpy
, VAImageFormat
*format
,
151 int width
, int height
, VAImage
*image
)
153 VA_CALL(o
, vaCreateImage
, dpy
, format
, width
, height
, image
);
155 error
: return VLC_EGENERIC
;
159 vlc_vaapi_DestroyConfig(vlc_object_t
*o
, VADisplay dpy
, VAConfigID conf
)
161 VA_CALL(o
, vaDestroyConfig
, dpy
, conf
);
163 error
: return VLC_EGENERIC
;
167 vlc_vaapi_DestroyContext(vlc_object_t
*o
, VADisplay dpy
, VAContextID ctx
)
169 VA_CALL(o
, vaDestroyContext
, dpy
, ctx
);
171 error
: return VLC_EGENERIC
;
175 vlc_vaapi_DestroyBuffer(vlc_object_t
*o
, VADisplay dpy
, VABufferID buf
)
177 VA_CALL(o
, vaDestroyBuffer
, dpy
, buf
);
179 error
: return VLC_EGENERIC
;
183 vlc_vaapi_DestroyImage(vlc_object_t
*o
, VADisplay dpy
, VAImageID image
)
185 VA_CALL(o
, vaDestroyImage
, dpy
, image
);
187 error
: return VLC_EGENERIC
;
190 /***********************
191 * VAAPI buffer access *
192 ***********************/
195 vlc_vaapi_MapBuffer(vlc_object_t
*o
, VADisplay dpy
,
196 VABufferID buf_id
, void **p_buf
)
198 VA_CALL(o
, vaMapBuffer
, dpy
, buf_id
, p_buf
);
200 error
: return VLC_EGENERIC
;
204 vlc_vaapi_UnmapBuffer(vlc_object_t
*o
, VADisplay dpy
, VABufferID buf_id
)
206 VA_CALL(o
, vaUnmapBuffer
, dpy
, buf_id
);
208 error
: return VLC_EGENERIC
;
212 vlc_vaapi_AcquireBufferHandle(vlc_object_t
*o
, VADisplay dpy
, VABufferID buf_id
,
213 VABufferInfo
*buf_info
)
215 VA_CALL(o
, vaAcquireBufferHandle
, dpy
, buf_id
, buf_info
);
217 error
: return VLC_EGENERIC
;
221 vlc_vaapi_ReleaseBufferHandle(vlc_object_t
*o
, VADisplay dpy
, VABufferID buf_id
)
223 VA_CALL(o
, vaReleaseBufferHandle
, dpy
, buf_id
);
225 error
: return VLC_EGENERIC
;
233 vlc_vaapi_IsVideoProcFilterAvailable(vlc_object_t
*o
, VADisplay dpy
,
234 VAContextID ctx
, VAProcFilterType filter
)
236 VAProcFilterType filters
[VAProcFilterCount
];
237 unsigned int num_filters
= VAProcFilterCount
;
239 VA_CALL(o
, vaQueryVideoProcFilters
, dpy
, ctx
, filters
, &num_filters
);
240 for (unsigned int i
= 0; i
< num_filters
; ++i
)
241 if (filter
== filters
[i
])
244 error
: return VLC_EGENERIC
;
248 vlc_vaapi_QueryVideoProcFilterCaps(vlc_object_t
*o
, VADisplay dpy
,
249 VAContextID ctx
, VAProcFilterType filter
,
250 void *caps
, unsigned int *p_num_caps
)
252 VA_CALL(o
, vaQueryVideoProcFilterCaps
, dpy
,
253 ctx
, filter
, caps
, p_num_caps
);
255 error
: return VLC_EGENERIC
;
259 vlc_vaapi_QueryVideoProcPipelineCaps(vlc_object_t
*o
, VADisplay dpy
,
260 VAContextID ctx
, VABufferID
*filters
,
261 unsigned int num_filters
,
262 VAProcPipelineCaps
*pipeline_caps
)
264 VA_CALL(o
, vaQueryVideoProcPipelineCaps
, dpy
,
265 ctx
, filters
, num_filters
, pipeline_caps
);
267 error
: return VLC_EGENERIC
;
275 vlc_vaapi_BeginPicture(vlc_object_t
*o
, VADisplay dpy
,
276 VAContextID ctx
, VASurfaceID surface
)
278 VA_CALL(o
, vaBeginPicture
, dpy
, ctx
, surface
);
280 error
: return VLC_EGENERIC
;
284 vlc_vaapi_RenderPicture(vlc_object_t
*o
, VADisplay dpy
, VAContextID ctx
,
285 VABufferID
*buffers
, int num_buffers
)
287 VA_CALL(o
, vaRenderPicture
, dpy
, ctx
, buffers
, num_buffers
);
289 error
: return VLC_EGENERIC
;
293 vlc_vaapi_EndPicture(vlc_object_t
*o
, VADisplay dpy
, VAContextID ctx
)
295 VA_CALL(o
, vaEndPicture
, dpy
, ctx
);
297 error
: return VLC_EGENERIC
;
305 IsVaProfileSupported(VADisplay dpy
, VAProfile i_profile
)
307 /* Check if the selected profile is supported */
308 if (i_profile
== VAProfileNone
)
310 int i_profiles_nb
= vaMaxNumProfiles(dpy
);
311 if (i_profiles_nb
< 0)
313 VAProfile
*p_profiles_list
= calloc(i_profiles_nb
, sizeof(VAProfile
));
314 if (!p_profiles_list
)
317 bool b_supported_profile
= false;
319 vaQueryConfigProfiles(dpy
, p_profiles_list
, &i_profiles_nb
);
320 if (status
!= VA_STATUS_SUCCESS
)
323 for (int i
= 0; i
< i_profiles_nb
; i
++)
325 if (p_profiles_list
[i
] == i_profile
)
327 b_supported_profile
= true;
333 free(p_profiles_list
);
334 return b_supported_profile
;
338 IsEntrypointAvailable(VADisplay dpy
, VAProfile i_profile
,
339 VAEntrypoint entrypoint
)
341 VAEntrypoint
* entrypoints
;
342 int num_entrypoints
= vaMaxNumEntrypoints(dpy
);
345 if (num_entrypoints
<= 0)
347 entrypoints
= malloc(num_entrypoints
* sizeof(VAEntrypoint
));
353 vaQueryConfigEntrypoints(dpy
, i_profile
, entrypoints
, &num_entrypoints
);
354 if (status
!= VA_STATUS_SUCCESS
)
357 for (int i
= 0; i
< num_entrypoints
; ++i
)
358 if (entrypoint
== entrypoints
[i
])
370 vlc_vaapi_CreateConfigChecked(vlc_object_t
*o
, VADisplay dpy
,
371 VAProfile i_profile
, VAEntrypoint entrypoint
,
374 if (!IsVaProfileSupported(dpy
, i_profile
))
376 msg_Err(o
, "profile(%d) is not supported", i_profile
);
377 return VA_INVALID_ID
;
379 if (!IsEntrypointAvailable(dpy
, i_profile
, entrypoint
))
381 msg_Err(o
, "entrypoint(%d) is not available", entrypoint
);
382 return VA_INVALID_ID
;
385 /* Create a VA configuration */
386 VAConfigAttrib attrib
= {
387 .type
= VAConfigAttribRTFormat
,
389 if (vaGetConfigAttributes(dpy
, i_profile
, entrypoint
, &attrib
, 1))
391 msg_Err(o
, "vaGetConfigAttributes failed");
392 return VA_INVALID_ID
;
395 /* Not sure what to do if not, I don't have a way to test */
396 if ((attrib
.value
& VA_RT_FORMAT_YUV420
) == 0)
398 msg_Err(o
, "config doesn't support VA_RT_FORMAT_YUV420");
399 return VA_INVALID_ID
;
402 unsigned int num_sattribs
;
403 VASurfaceAttrib
*sattribs
= NULL
;
404 VAConfigID va_config_id
= VA_INVALID_ID
;
405 VA_CALL(o
, vaCreateConfig
, dpy
, i_profile
, entrypoint
, &attrib
, 1,
408 if (va_force_fourcc
== 0)
411 /* Fetch VASurfaceAttrib list to make sure the decoder can output NV12 */
412 if (vaQuerySurfaceAttributes(dpy
, va_config_id
, NULL
, &num_sattribs
)
413 != VA_STATUS_SUCCESS
)
416 sattribs
= malloc(num_sattribs
* sizeof(*sattribs
));
417 if (sattribs
== NULL
)
419 if (vaQuerySurfaceAttributes(dpy
, va_config_id
, sattribs
, &num_sattribs
)
420 != VA_STATUS_SUCCESS
)
423 for (unsigned i
= 0; i
< num_sattribs
; ++i
)
425 VASurfaceAttrib
*sattrib
= &sattribs
[i
];
426 if (sattrib
->type
== VASurfaceAttribPixelFormat
427 && sattrib
->flags
& VA_SURFACE_ATTRIB_SETTABLE
428 && sattrib
->value
.value
.i
== va_force_fourcc
)
438 if (va_config_id
!= VA_INVALID_ID
)
440 msg_Err(o
, "config doesn't support forced fourcc");
441 vlc_vaapi_DestroyConfig(o
, dpy
, va_config_id
);
443 return VA_INVALID_ID
;
453 struct pic_sys_vaapi_instance
455 atomic_int pic_refcount
;
457 struct vlc_vaapi_instance
*va_inst
;
458 unsigned num_render_targets
;
459 VASurfaceID render_targets
[];
464 struct pic_sys_vaapi_instance
*instance
;
465 struct vaapi_pic_ctx ctx
;
469 pool_pic_destroy_cb(picture_t
*pic
)
471 picture_sys_t
*p_sys
= pic
->p_sys
;
472 struct pic_sys_vaapi_instance
*instance
= p_sys
->instance
;
474 if (atomic_fetch_sub(&instance
->pic_refcount
, 1) == 1)
476 vaDestroySurfaces(instance
->va_dpy
, instance
->render_targets
,
477 instance
->num_render_targets
);
478 vlc_vaapi_ReleaseInstance(instance
->va_inst
);
486 pic_ctx_destroy_cb(struct picture_context_t
*opaque
)
488 struct vaapi_pic_ctx
*ctx
= (struct vaapi_pic_ctx
*) opaque
;
489 picture_Release(ctx
->picref
);
493 static struct picture_context_t
*
494 pic_ctx_copy_cb(struct picture_context_t
*opaque
)
496 struct vaapi_pic_ctx
*src_ctx
= (struct vaapi_pic_ctx
*) opaque
;
497 struct vaapi_pic_ctx
*dst_ctx
= malloc(sizeof *dst_ctx
);
501 dst_ctx
->s
.destroy
= pic_ctx_destroy_cb
;
502 dst_ctx
->s
.copy
= pic_ctx_copy_cb
;
503 dst_ctx
->surface
= src_ctx
->surface
;
504 dst_ctx
->picref
= picture_Hold(src_ctx
->picref
);
509 pic_sys_ctx_destroy_cb(struct picture_context_t
*opaque
)
515 vlc_vaapi_PoolNew(vlc_object_t
*o
, struct vlc_vaapi_instance
*va_inst
,
516 VADisplay dpy
, unsigned count
, VASurfaceID
**render_targets
,
517 const video_format_t
*restrict fmt
,
518 unsigned va_rt_format
, int va_force_fourcc
)
520 struct pic_sys_vaapi_instance
*instance
=
521 malloc(sizeof(*instance
) + count
* sizeof(VASurfaceID
));
524 instance
->num_render_targets
= count
;
525 atomic_init(&instance
->pic_refcount
, 0);
527 VASurfaceAttrib
*attribs
= NULL
;
528 unsigned num_attribs
= 0;
529 VASurfaceAttrib fourcc_attribs
[1] = {
531 .type
= VASurfaceAttribPixelFormat
,
532 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
533 .value
.type
= VAGenericValueTypeInteger
,
534 .value
.value
.i
= va_force_fourcc
,
537 if (va_force_fourcc
!= 0)
539 attribs
= fourcc_attribs
;
543 picture_t
*pics
[count
];
545 VA_CALL(o
, vaCreateSurfaces
, dpy
, va_rt_format
,
546 fmt
->i_visible_width
, fmt
->i_visible_height
,
547 instance
->render_targets
, instance
->num_render_targets
,
548 attribs
, num_attribs
);
550 for (unsigned i
= 0; i
< count
; i
++)
552 picture_sys_t
*p_sys
= malloc(sizeof *p_sys
);
558 p_sys
->instance
= instance
;
559 p_sys
->ctx
.s
.destroy
= pic_sys_ctx_destroy_cb
;
560 p_sys
->ctx
.s
.copy
= pic_ctx_copy_cb
;
561 p_sys
->ctx
.surface
= instance
->render_targets
[i
];
562 p_sys
->ctx
.picref
= NULL
;
563 picture_resource_t rsc
= {
565 .pf_destroy
= pool_pic_destroy_cb
,
567 pics
[i
] = picture_NewFromResource(fmt
, &rsc
);
576 picture_pool_t
*pool
= picture_pool_New(count
, pics
);
580 atomic_store(&instance
->pic_refcount
, count
);
581 instance
->va_dpy
= vlc_vaapi_HoldInstance(va_inst
);
582 instance
->va_inst
= va_inst
;
584 *render_targets
= instance
->render_targets
;
589 picture_Release(pics
[--count
]);
591 VA_CALL(o
, vaDestroySurfaces
, instance
->va_dpy
, instance
->render_targets
,
592 instance
->num_render_targets
);
600 vlc_vaapi_PicSysGetRenderTargets(picture_sys_t
*sys
,
601 VASurfaceID
**render_targets
)
603 assert(sys
&& sys
->instance
);
604 *render_targets
= sys
->instance
->render_targets
;
605 return sys
->instance
->num_render_targets
;
608 struct vlc_vaapi_instance
*
609 vlc_vaapi_PicSysHoldInstance(picture_sys_t
*sys
, VADisplay
*dpy
)
611 assert(sys
->instance
!= NULL
);
612 *dpy
= vlc_vaapi_HoldInstance(sys
->instance
->va_inst
);
613 return sys
->instance
->va_inst
;
616 #define ASSERT_VAAPI_CHROMA(pic) do { \
617 assert(pic->format.i_chroma == VLC_CODEC_VAAPI_420); \
621 vlc_vaapi_PicAttachContext(picture_t
*pic
)
623 ASSERT_VAAPI_CHROMA(pic
);
624 assert(pic
->p_sys
!= NULL
);
625 assert(pic
->context
== NULL
);
627 pic
->p_sys
->ctx
.picref
= pic
;
628 pic
->context
= &pic
->p_sys
->ctx
.s
;
632 vlc_vaapi_PicGetSurface(picture_t
*pic
)
634 ASSERT_VAAPI_CHROMA(pic
);
635 assert(pic
->context
);
637 return ((struct vaapi_pic_ctx
*)pic
->context
)->surface
;
641 vlc_vaapi_PicGetDisplay(picture_t
*pic
)
643 ASSERT_VAAPI_CHROMA(pic
);
644 assert(pic
->context
);
646 return ((struct vaapi_pic_ctx
*)pic
->context
)->picref
->p_sys
->instance
->va_dpy
;