| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| #include <alloca.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <va/va.h> |
| #include <va/va_drm.h> |
| |
| #include "label_detect.h" |
| |
| static bool is_blacklisted_driver(const char* vendor_string, |
| VAProfile profile, |
| VAEntrypoint entrypoint) { |
| // No blacklisted driver today. |
| return false; |
| } |
| |
| /* Returns true if given VA profile |va_profile| has |entrypoint| and the entry |
| * point supports given raw |format|. |
| */ |
| static bool has_vaapi_entrypoint(VADisplay va_display, |
| VAProfile va_profile, |
| VAEntrypoint entrypoint, |
| unsigned int format) { |
| VAStatus va_res; |
| VAConfigAttrib attrib = {VAConfigAttribRTFormat, 0}; |
| va_res = |
| vaGetConfigAttributes(va_display, va_profile, entrypoint, &attrib, 1); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaGetConfigAttributes failed (%d)\n", va_res); |
| return false; |
| } |
| |
| return attrib.value & format; |
| } |
| |
| /* Returns true if the current platform supports at least one of the |
| * |required_profiles| and |entrypoint| for that profile supports given raw |
| * |format|. |
| */ |
| static bool match_vaapi_capabilities(VADisplay va_display, |
| const VAProfile* required_profiles, |
| VAEntrypoint entrypoint, |
| unsigned int format) { |
| int i; |
| bool found = false; |
| int num_supported_profiles; |
| VAStatus va_res; |
| VAProfile* profiles; |
| int max_profiles = vaMaxNumProfiles(va_display); |
| /* If no profiles are supported do not proceed further */ |
| if (max_profiles <= 0) { |
| TRACE("vaMaxNumProfiles returns %d \n ", max_profiles); |
| return false; |
| } |
| |
| profiles = (VAProfile*)alloca(sizeof(VAProfile) * max_profiles); |
| if (!profiles) { |
| TRACE("alloca failed\n"); |
| return false; |
| } |
| va_res = vaQueryConfigProfiles(va_display, profiles, &num_supported_profiles); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaQueryConfigProfiles failed (%d)\n", va_res); |
| return false; |
| } |
| const char* vendor_string = vaQueryVendorString(va_display); |
| for (i = 0; i < num_supported_profiles; i++) { |
| int j; |
| VAProfile profile = profiles[i]; |
| TRACE("supported profile: %d\n", profile); |
| if (is_blacklisted_driver(vendor_string, profile, entrypoint)) { |
| continue; |
| } |
| for (j = 0; required_profiles[j] != VAProfileNone; j++) { |
| if (required_profiles[j] == profile && |
| has_vaapi_entrypoint(va_display, profile, entrypoint, format)) { |
| found = true; |
| /* continue the loop in order to output all supported profiles */ |
| } |
| } |
| } |
| return found; |
| } |
| |
| /* Returns true if libva supports any given profiles. And that profile has said |
| * entrypoint with format. |
| */ |
| bool is_vaapi_support_formats(int fd, |
| const VAProfile* profiles, |
| VAEntrypoint entrypoint, |
| unsigned int format) { |
| bool found = false; |
| VAStatus va_res; |
| VADisplay va_display; |
| int major_version, minor_version; |
| |
| va_display = vaGetDisplayDRM(fd); |
| if (!vaDisplayIsValid(va_display)) { |
| TRACE("vaGetDisplay returns invalid display\n"); |
| return false; |
| } |
| |
| va_res = vaInitialize(va_display, &major_version, &minor_version); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaInitialize failed\n"); |
| return false; |
| } |
| |
| if (match_vaapi_capabilities(va_display, profiles, entrypoint, format)) |
| found = true; |
| |
| vaTerminate(va_display); |
| |
| return found; |
| } |
| |
| /* Returns true if |entrypoint| is supported. */ |
| static bool is_entrypoint_supported(VADisplay va_display, |
| VAProfile va_profile, |
| VAEntrypoint entrypoint) { |
| bool result = false; |
| int max_entrypoints = vaMaxNumEntrypoints(va_display); |
| VAEntrypoint* supported_entrypoints = |
| malloc(max_entrypoints * sizeof(VAEntrypoint)); |
| int num_supported_entrypoints; |
| VAStatus va_res = |
| vaQueryConfigEntrypoints(va_display, va_profile, supported_entrypoints, |
| &num_supported_entrypoints); |
| |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaQueryConfigEntrypoints failed (%d)\n", va_res); |
| goto finish; |
| } |
| if (num_supported_entrypoints < 0 || |
| num_supported_entrypoints > max_entrypoints) { |
| TRACE("vaQueryConfigEntrypoints returned: %d\n", num_supported_entrypoints); |
| goto finish; |
| } |
| |
| for (int i = 0; i < num_supported_entrypoints; i++) { |
| if (supported_entrypoints[i] == entrypoint) { |
| result = true; |
| break; |
| } |
| } |
| |
| finish: |
| free(supported_entrypoints); |
| return result; |
| } |
| |
| /* Returns true if |required_attribs| are supported. */ |
| static bool are_attribs_supported(VADisplay va_display, |
| VAProfile va_profile, |
| VAEntrypoint entrypoint, |
| VAConfigAttrib* required_attribs, |
| int num_required_attribs) { |
| bool result = false; |
| VAConfigAttrib* attribs = |
| malloc(sizeof(VAConfigAttrib) * num_required_attribs); |
| memcpy(attribs, required_attribs, sizeof(*attribs) * num_required_attribs); |
| for (int i = 0; i < num_required_attribs; i++) { |
| attribs[i].value = 0; |
| } |
| |
| VAStatus va_res = vaGetConfigAttributes(va_display, va_profile, entrypoint, |
| attribs, num_required_attribs); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaGetConfigAttributes failed (%d)\n", va_res); |
| goto finish; |
| } |
| |
| for (int i = 0; i < num_required_attribs; i++) { |
| if (attribs[i].type != required_attribs[i].type || |
| (attribs[i].value & required_attribs[i].value) != |
| required_attribs[i].value) { |
| // Unsupported value. |
| goto finish; |
| } |
| } |
| result = true; |
| |
| finish: |
| free(attribs); |
| return result; |
| } |
| |
| /* Returns success or failure of getting resolution. The maximum resolution |
| * of a passed profile is returned through arguments. */ |
| static bool get_max_resolution(VADisplay va_display, |
| VAProfile va_profile, |
| VAEntrypoint entrypoint, |
| VAConfigAttrib* required_attribs, |
| int num_required_attribs, |
| int32_t* width, |
| int32_t* height) { |
| VAStatus va_res; |
| VAConfigID va_config_id; |
| VASurfaceAttrib* attrib_list; |
| unsigned int num_attribs = 0; |
| *width = 0; |
| *height = 0; |
| |
| va_res = vaCreateConfig(va_display, va_profile, entrypoint, required_attribs, |
| num_attribs, &va_config_id); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaQueryConfigProfiles failed (%d)\n", va_res); |
| return false; |
| } |
| // Calls vaQuerySurfaceAttributes twice. The first time is to get the number |
| // of attributes to prepare the space and the second time is to get all |
| // attributes. |
| va_res = |
| vaQuerySurfaceAttributes(va_display, va_config_id, NULL, &num_attribs); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaQuerySurfaceAttributes failed (%d)\n", va_res); |
| return false; |
| } |
| if (!num_attribs) { |
| return false; |
| } |
| |
| attrib_list = malloc(num_attribs * sizeof(VASurfaceAttrib)); |
| va_res = vaQuerySurfaceAttributes(va_display, va_config_id, attrib_list, |
| &num_attribs); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaQuerySurfaceAttributes failed (%d)\n", va_res); |
| free(attrib_list); |
| return false; |
| } |
| for (unsigned int j = 0; j < num_attribs; j++) { |
| VASurfaceAttrib attrib = attrib_list[j]; |
| if (attrib.type == VASurfaceAttribMaxWidth) { |
| *width = attrib.value.value.i; |
| } else if (attrib.type == VASurfaceAttribMaxHeight) { |
| *height = attrib.value.value.i; |
| } |
| } |
| free(attrib_list); |
| return *width > 0 && *height > 0; |
| } |
| |
| /* Returns success or failure of getting resolution. The maximum resolution |
| * among passed profiles is returned through arguments. */ |
| bool get_vaapi_max_resolution(int fd, |
| const VAProfile* profiles, |
| VAEntrypoint entrypoint, |
| int32_t* const resolution_width, |
| int32_t* const resolution_height) { |
| *resolution_width = 0; |
| *resolution_height = 0; |
| |
| VAConfigAttrib required_attribs = {VAConfigAttribRTFormat, |
| VA_RT_FORMAT_YUV420}; |
| VAStatus va_res; |
| VADisplay va_display = vaGetDisplayDRM(fd); |
| int major_version, minor_version; |
| if (!vaDisplayIsValid(va_display)) { |
| TRACE("vaGetDisplay returns invalid display\n"); |
| return false; |
| } |
| va_res = vaInitialize(va_display, &major_version, &minor_version); |
| if (va_res != VA_STATUS_SUCCESS) { |
| TRACE("vaInitialize failed\n"); |
| return false; |
| } |
| |
| for (size_t i = 0; profiles[i] != VAProfileNone; i++) { |
| VAProfile va_profile = profiles[i]; |
| int32_t width = 0; |
| int32_t height = 0; |
| if (!is_entrypoint_supported(va_display, va_profile, entrypoint)) { |
| continue; |
| } |
| |
| if (!are_attribs_supported(va_display, va_profile, entrypoint, |
| &required_attribs, 1)) { |
| continue; |
| } |
| |
| if (!get_max_resolution(va_display, va_profile, entrypoint, |
| &required_attribs, 1, &width, &height)) { |
| TRACE("GetMaxResolution failed for va_profile %d and entrypoint %u\n", |
| va_profile, entrypoint); |
| continue; |
| } |
| |
| if (*resolution_width <= width && *resolution_height <= height) { |
| *resolution_width = width; |
| *resolution_height = height; |
| } |
| } |
| vaTerminate(va_display); |
| return *resolution_width > 0 && *resolution_height > 0; |
| } |