gl: rename opengl_shaders_api_t to opengl_vtable_t
[vlc.git] / modules / hw / vaapi / vlc_vaapi.c
blob7dfe2aea45400ed07974cd0c8364891da661aae3
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 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include "vlc_vaapi.h"
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <inttypes.h>
34 #include <assert.h>
36 #include <va/va.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
46 define). */
47 #define VA_CALL(o, f, args...) \
48 do \
49 { \
50 VAStatus s = f(args); \
51 if (s != VA_STATUS_SUCCESS) \
52 { \
53 msg_Err(o, "%s: %s", #f, vaErrorStr(s)); \
54 goto error; \
55 } \
56 } while (0)
58 /**************************
59 * VA instance management *
60 **************************/
62 struct vlc_vaapi_instance {
63 VADisplay dpy;
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))
79 goto error;
80 inst->dpy = dpy;
81 inst->native = native;
82 inst->native_destroy_cb = native_destroy_cb;
83 atomic_init(&inst->pic_refcount, 1);
85 return inst;
86 error:
87 vaTerminate(dpy);
88 if (native != NULL && native_destroy_cb != NULL)
89 native_destroy_cb(native);
90 return NULL;
93 VADisplay
94 vlc_vaapi_HoldInstance(struct vlc_vaapi_instance *inst)
96 atomic_fetch_add(&inst->pic_refcount, 1);
97 return inst->dpy;
100 void
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);
108 free(inst);
112 /**************************
113 * VAAPI create & destroy *
114 **************************/
116 VAContextID
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)
121 VAContextID ctx;
122 VA_CALL(o, vaCreateContext, dpy, conf, pic_w, pic_h, flag,
123 render_targets, num_render_targets, &ctx);
124 return ctx;
125 error: return VA_INVALID_ID;
128 VABufferID
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)
133 VABufferID buf_id;
134 VA_CALL(o, vaCreateBuffer, dpy, ctx, type,
135 size, num_elements, data, &buf_id);
136 return 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);
145 return VLC_SUCCESS;
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);
154 return VLC_SUCCESS;
155 error: return VLC_EGENERIC;
159 vlc_vaapi_DestroyConfig(vlc_object_t *o, VADisplay dpy, VAConfigID conf)
161 VA_CALL(o, vaDestroyConfig, dpy, conf);
162 return VLC_SUCCESS;
163 error: return VLC_EGENERIC;
167 vlc_vaapi_DestroyContext(vlc_object_t *o, VADisplay dpy, VAContextID ctx)
169 VA_CALL(o, vaDestroyContext, dpy, ctx);
170 return VLC_SUCCESS;
171 error: return VLC_EGENERIC;
175 vlc_vaapi_DestroyBuffer(vlc_object_t *o, VADisplay dpy, VABufferID buf)
177 VA_CALL(o, vaDestroyBuffer, dpy, buf);
178 return VLC_SUCCESS;
179 error: return VLC_EGENERIC;
183 vlc_vaapi_DestroyImage(vlc_object_t *o, VADisplay dpy, VAImageID image)
185 VA_CALL(o, vaDestroyImage, dpy, image);
186 return VLC_SUCCESS;
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);
199 return VLC_SUCCESS;
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);
207 return VLC_SUCCESS;
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);
216 return VLC_SUCCESS;
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);
224 return VLC_SUCCESS;
225 error: return VLC_EGENERIC;
228 /*****************
229 * VAAPI queries *
230 *****************/
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])
242 return VLC_SUCCESS;
243 return VLC_EGENERIC;
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);
254 return VLC_SUCCESS;
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);
266 return VLC_SUCCESS;
267 error: return VLC_EGENERIC;
270 /*******************
271 * VAAPI rendering *
272 *******************/
275 vlc_vaapi_BeginPicture(vlc_object_t *o, VADisplay dpy,
276 VAContextID ctx, VASurfaceID surface)
278 VA_CALL(o, vaBeginPicture, dpy, ctx, surface);
279 return VLC_SUCCESS;
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);
288 return VLC_SUCCESS;
289 error: return VLC_EGENERIC;
293 vlc_vaapi_EndPicture(vlc_object_t *o, VADisplay dpy, VAContextID ctx)
295 VA_CALL(o, vaEndPicture, dpy, ctx);
296 return VLC_SUCCESS;
297 error: return VLC_EGENERIC;
300 /*****************
301 * VAAPI helpers *
302 *****************/
304 static bool
305 IsVaProfileSupported(VADisplay dpy, VAProfile i_profile)
307 /* Check if the selected profile is supported */
308 if (i_profile == VAProfileNone)
309 return true;
310 int i_profiles_nb = vaMaxNumProfiles(dpy);
311 if (i_profiles_nb < 0)
312 return false;
313 VAProfile *p_profiles_list = calloc(i_profiles_nb, sizeof(VAProfile));
314 if (!p_profiles_list)
315 return false;
317 bool b_supported_profile = false;
318 VAStatus status =
319 vaQueryConfigProfiles(dpy, p_profiles_list, &i_profiles_nb);
320 if (status != VA_STATUS_SUCCESS)
321 goto error;
323 for (int i = 0; i < i_profiles_nb; i++)
325 if (p_profiles_list[i] == i_profile)
327 b_supported_profile = true;
328 break;
332 error:
333 free(p_profiles_list);
334 return b_supported_profile;
337 static bool
338 IsEntrypointAvailable(VADisplay dpy, VAProfile i_profile,
339 VAEntrypoint entrypoint)
341 VAEntrypoint * entrypoints;
342 int num_entrypoints = vaMaxNumEntrypoints(dpy);
343 bool ret = false;
345 if (num_entrypoints <= 0)
346 return false;
347 entrypoints = malloc(num_entrypoints * sizeof(VAEntrypoint));
349 if (!entrypoints)
350 return false;
352 VAStatus status =
353 vaQueryConfigEntrypoints(dpy, i_profile, entrypoints, &num_entrypoints);
354 if (status != VA_STATUS_SUCCESS)
355 goto error;
357 for (int i = 0; i < num_entrypoints; ++i)
358 if (entrypoint == entrypoints[i])
360 ret = true;
361 break;
364 error:
365 free(entrypoints);
366 return ret;
369 VAConfigID
370 vlc_vaapi_CreateConfigChecked(vlc_object_t *o, VADisplay dpy,
371 VAProfile i_profile, VAEntrypoint entrypoint,
372 int va_force_fourcc)
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,
406 &va_config_id);
408 if (va_force_fourcc == 0)
409 return va_config_id;
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)
414 goto error;
416 sattribs = malloc(num_sattribs * sizeof(*sattribs));
417 if (sattribs == NULL)
418 goto error;
419 if (vaQuerySurfaceAttributes(dpy, va_config_id, sattribs, &num_sattribs)
420 != VA_STATUS_SUCCESS)
421 goto error;
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)
430 free(sattribs);
431 return va_config_id;
436 error:
437 free(sattribs);
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;
446 struct vaapi_pic_ctx
448 picture_context_t s;
449 VASurfaceID surface;
450 picture_t *picref;
453 struct pic_sys_vaapi_instance
455 atomic_int pic_refcount;
456 VADisplay va_dpy;
457 struct vlc_vaapi_instance *va_inst;
458 unsigned num_render_targets;
459 VASurfaceID render_targets[];
462 struct picture_sys_t
464 struct pic_sys_vaapi_instance *instance;
465 struct vaapi_pic_ctx ctx;
468 static void
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);
479 free(instance);
481 free(pic->p_sys);
482 free(pic);
485 static void
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);
490 free(opaque);
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);
498 if (dst_ctx == NULL)
499 return NULL;
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);
505 return &dst_ctx->s;
508 static void
509 pic_sys_ctx_destroy_cb(struct picture_context_t *opaque)
511 (void) opaque;
514 picture_pool_t *
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));
522 if (!instance)
523 return NULL;
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;
540 num_attribs = 1;
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);
553 if (p_sys == NULL)
555 count = i;
556 goto error_pic;
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 = {
564 .p_sys = p_sys,
565 .pf_destroy = pool_pic_destroy_cb,
567 pics[i] = picture_NewFromResource(fmt, &rsc);
568 if (pics[i] == NULL)
570 free(p_sys);
571 count = i;
572 goto error_pic;
576 picture_pool_t *pool = picture_pool_New(count, pics);
577 if (!pool)
578 goto error_pic;
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;
585 return pool;
587 error_pic:
588 while (count > 0)
589 picture_Release(pics[--count]);
591 VA_CALL(o, vaDestroySurfaces, instance->va_dpy, instance->render_targets,
592 instance->num_render_targets);
594 error:
595 free(instance);
596 return NULL;
599 unsigned
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); \
618 } while(0)
620 void
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;
631 VASurfaceID
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;
640 VADisplay
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;