From a091c00c00c1d5ae5e3da7ef31b98293c76d479f Mon Sep 17 00:00:00 2001 From: pants Date: Mon, 21 Sep 2026 14:16:59 -0700 Subject: init --- src/codec_query/vaapi.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 src/codec_query/vaapi.c (limited to 'src/codec_query/vaapi.c') diff --git a/src/codec_query/vaapi.c b/src/codec_query/vaapi.c new file mode 100644 index 0000000..0943450 --- /dev/null +++ b/src/codec_query/vaapi.c @@ -0,0 +1,236 @@ +#include "../../include/codec_query/vaapi.h" +#include "../../include/utils.h" + +#include +#include +#include +#include +#include + +#include +#include + +static bool profile_is_h264(VAProfile profile) { + switch(profile) { + case 5: // VAProfileH264Baseline + case VAProfileH264Main: + case VAProfileH264High: + case VAProfileH264ConstrainedBaseline: + return true; + default: + return false; + } +} + +static bool profile_is_hevc_8bit(VAProfile profile) { + switch(profile) { + case VAProfileHEVCMain: + return true; + default: + return false; + } +} + +static bool profile_is_hevc_10bit(VAProfile profile) { + switch(profile) { + case VAProfileHEVCMain10: + //case VAProfileHEVCMain12: + //case VAProfileHEVCMain422_10: + //case VAProfileHEVCMain422_12: + //case VAProfileHEVCMain444: + //case VAProfileHEVCMain444_10: + //case VAProfileHEVCMain444_12: + return true; + default: + return false; + } +} + +static bool profile_is_av1(VAProfile profile) { + switch(profile) { + case VAProfileAV1Profile0: + case VAProfileAV1Profile1: + return true; + default: + return false; + } +} + +static bool profile_is_vp8(VAProfile profile) { + switch(profile) { + case VAProfileVP8Version0_3: + return true; + default: + return false; + } +} + +static bool profile_is_vp9(VAProfile profile) { + switch(profile) { + case VAProfileVP9Profile0: + case VAProfileVP9Profile1: + case VAProfileVP9Profile2: + case VAProfileVP9Profile3: + return true; + default: + return false; + } +} + +/* Returns 0, 0 on error */ +static vec2i profile_entrypoint_get_max_resolution(VADisplay va_dpy, VAProfile profile, VAEntrypoint entrypoint) { + VAConfigAttrib attribs[2] = { + { + .type = VAConfigAttribMaxPictureWidth, + }, + { + .type = VAConfigAttribMaxPictureHeight, + } + }; + if(vaGetConfigAttributes(va_dpy, profile, entrypoint, attribs, 2) != VA_STATUS_SUCCESS || (attribs[0].value & VA_ATTRIB_NOT_SUPPORTED) || (attribs[1].value & VA_ATTRIB_NOT_SUPPORTED)) + return (vec2i){0, 0}; + + return (vec2i){ attribs[0].value, attribs[1].value }; +} + +/* Returns 0 on error or if none is supported */ +static VAEntrypoint profile_get_video_encoding_entrypoint(VADisplay va_dpy, VAProfile profile) { + int num_entrypoints = vaMaxNumEntrypoints(va_dpy); + if(num_entrypoints <= 0) + return 0; + + VAEntrypoint *entrypoint_list = calloc(num_entrypoints, sizeof(VAEntrypoint)); + if(!entrypoint_list) + return 0; + + int encoding_entrypoint_index = -1; + int lower_power_entrypoint_index = -1; + if(vaQueryConfigEntrypoints(va_dpy, profile, entrypoint_list, &num_entrypoints) == VA_STATUS_SUCCESS) { + for(int i = 0; i < num_entrypoints; ++i) { + if(entrypoint_list[i] == VAEntrypointEncSlice) + encoding_entrypoint_index = i; + else if(entrypoint_list[i] == VAEntrypointEncSliceLP) + lower_power_entrypoint_index = i; + } + } + + VAEntrypoint encoding_entrypoint = 0; + if(encoding_entrypoint_index != -1) + encoding_entrypoint = entrypoint_list[encoding_entrypoint_index]; + else if(lower_power_entrypoint_index != -1) + encoding_entrypoint = entrypoint_list[lower_power_entrypoint_index]; + + free(entrypoint_list); + return encoding_entrypoint; +} + +static bool get_supported_video_codecs(VADisplay va_dpy, gsr_supported_video_codecs *video_codecs, bool cleanup) { + *video_codecs = (gsr_supported_video_codecs){0}; + bool success = false; + VAProfile *profile_list = NULL; + + vaSetInfoCallback(va_dpy, NULL, NULL); + + int va_major = 0; + int va_minor = 0; + if(vaInitialize(va_dpy, &va_major, &va_minor) != VA_STATUS_SUCCESS) { + fprintf(stderr, "gsr error: gsr_get_supported_video_codecs_vaapi: vaInitialize failed\n"); + return false; + } + + int num_profiles = vaMaxNumProfiles(va_dpy); + if(num_profiles <= 0) + goto fail; + + profile_list = calloc(num_profiles, sizeof(VAProfile)); + if(!profile_list || vaQueryConfigProfiles(va_dpy, profile_list, &num_profiles) != VA_STATUS_SUCCESS) + goto fail; + + for(int i = 0; i < num_profiles; ++i) { + if(profile_is_h264(profile_list[i])) { + const VAEntrypoint encoding_entrypoint = profile_get_video_encoding_entrypoint(va_dpy, profile_list[i]); + if(encoding_entrypoint != 0) { + const vec2i max_resolution = profile_entrypoint_get_max_resolution(va_dpy, profile_list[i], encoding_entrypoint); + video_codecs->h264 = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + } + } else if(profile_is_hevc_8bit(profile_list[i])) { + const VAEntrypoint encoding_entrypoint = profile_get_video_encoding_entrypoint(va_dpy, profile_list[i]); + if(encoding_entrypoint != 0) { + const vec2i max_resolution = profile_entrypoint_get_max_resolution(va_dpy, profile_list[i], encoding_entrypoint); + video_codecs->hevc = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + } + } else if(profile_is_hevc_10bit(profile_list[i])) { + const VAEntrypoint encoding_entrypoint = profile_get_video_encoding_entrypoint(va_dpy, profile_list[i]); + if(encoding_entrypoint != 0) { + const vec2i max_resolution = profile_entrypoint_get_max_resolution(va_dpy, profile_list[i], encoding_entrypoint); + video_codecs->hevc_hdr = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + video_codecs->hevc_10bit = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + } + } else if(profile_is_av1(profile_list[i])) { + const VAEntrypoint encoding_entrypoint = profile_get_video_encoding_entrypoint(va_dpy, profile_list[i]); + if(encoding_entrypoint != 0) { + const vec2i max_resolution = profile_entrypoint_get_max_resolution(va_dpy, profile_list[i], encoding_entrypoint); + video_codecs->av1 = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + video_codecs->av1_hdr = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + video_codecs->av1_10bit = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + } + } else if(profile_is_vp8(profile_list[i])) { + const VAEntrypoint encoding_entrypoint = profile_get_video_encoding_entrypoint(va_dpy, profile_list[i]); + if(encoding_entrypoint != 0) { + const vec2i max_resolution = profile_entrypoint_get_max_resolution(va_dpy, profile_list[i], encoding_entrypoint); + video_codecs->vp8 = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + } + } else if(profile_is_vp9(profile_list[i])) { + const VAEntrypoint encoding_entrypoint = profile_get_video_encoding_entrypoint(va_dpy, profile_list[i]); + if(encoding_entrypoint != 0) { + const vec2i max_resolution = profile_entrypoint_get_max_resolution(va_dpy, profile_list[i], encoding_entrypoint); + video_codecs->vp9 = (gsr_supported_video_codec){ true, encoding_entrypoint == VAEntrypointEncSliceLP, max_resolution }; + } + } + } + + success = true; + fail: + if(profile_list) + free(profile_list); + + if(cleanup) + vaTerminate(va_dpy); + + return success; +} + +bool gsr_get_supported_video_codecs_vaapi(gsr_supported_video_codecs *video_codecs, const char *card_path, bool cleanup) { + memset(video_codecs, 0, sizeof(*video_codecs)); + bool success = false; + int drm_fd = -1; + + char render_path[128]; + if(!gsr_card_path_get_render_path(card_path, render_path)) { + fprintf(stderr, "gsr error: gsr_get_supported_video_codecs_vaapi: failed to get /dev/dri/renderDXXX file from %s\n", card_path); + goto done; + } + + drm_fd = open(render_path, O_RDWR); + if(drm_fd == -1) { + fprintf(stderr, "gsr error: gsr_get_supported_video_codecs_vaapi: failed to open device %s\n", render_path); + goto done; + } + + VADisplay va_dpy = vaGetDisplayDRM(drm_fd); + if(va_dpy) { + if(!get_supported_video_codecs(va_dpy, video_codecs, cleanup)) { + fprintf(stderr, "gsr error: gsr_get_supported_video_codecs_vaapi: failed to query supported video codecs for device %s\n", render_path); + goto done; + } + success = true; + } + + done: + if(cleanup) { + if(drm_fd > 0) + close(drm_fd); + } + + return success; +} -- cgit v1.2.3