diff options
Diffstat (limited to 'src/video_core')
-rw-r--r-- | src/video_core/command_classes/codecs/codec.cpp | 88 |
1 files changed, 25 insertions, 63 deletions
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 2c0d8da64..2a532b883 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -17,6 +17,10 @@ extern "C" { #include <libavutil/opt.h> +#ifdef LIBVA_FOUND +// for querying VAAPI driver information +#include <libavutil/hwcontext_vaapi.h> +#endif } namespace Tegra { @@ -29,6 +33,7 @@ constexpr std::array PREFERRED_GPU_DECODERS = { AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2, #elif defined(__linux__) + AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VDPAU, #endif // last resort for Linux Flatpak (w/ NVIDIA) @@ -78,79 +83,18 @@ static std::vector<AVHWDeviceType> ListSupportedContexts() { AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; do { current_device_type = av_hwdevice_iterate_types(current_device_type); - // filter out VA-API since we will try that first if supported - if (current_device_type != AV_HWDEVICE_TYPE_VAAPI) { - contexts.push_back(current_device_type); - } + contexts.push_back(current_device_type); } while (current_device_type != AV_HWDEVICE_TYPE_NONE); return contexts; } -#ifdef LIBVA_FOUND -// List all the currently loaded Linux modules -static std::vector<std::string> ListLinuxKernelModules() { - using FILEPtr = std::unique_ptr<FILE, decltype(&std::fclose)>; - auto module_listing = FILEPtr{fopen("/proc/modules", "rt"), std::fclose}; - std::vector<std::string> modules{}; - if (!module_listing) { - LOG_WARNING(Service_NVDRV, "Could not open /proc/modules to collect available modules"); - return modules; - } - char* buffer = nullptr; - size_t buf_len = 0; - while (getline(&buffer, &buf_len, module_listing.get()) != -1) { - // format for the module listing file (sysfs) - // <name> <module_size> <depended_by_count> <depended_by_names> <status> <load_address> - auto line = std::string(buffer); - // we are only interested in module names - auto name_pos = line.find_first_of(" "); - if (name_pos == std::string::npos) { - continue; - } - modules.push_back(line.erase(name_pos)); - } - free(buffer); - return modules; -} -#endif - bool Codec::CreateGpuAvDevice() { -#if defined(LIBVA_FOUND) - static constexpr std::array<const char*, 3> VAAPI_DRIVERS = { - "i915", - "iHD", - "amdgpu", - }; - AVDictionary* hwdevice_options = nullptr; - const auto loaded_modules = ListLinuxKernelModules(); - av_dict_set(&hwdevice_options, "connection_type", "drm", 0); - for (const auto& driver : VAAPI_DRIVERS) { - // first check if the target driver is loaded in the kernel - bool found = std::any_of(loaded_modules.begin(), loaded_modules.end(), - [&driver](const auto& module) { return module == driver; }); - if (!found) { - LOG_DEBUG(Service_NVDRV, "Kernel driver {} is not loaded, trying the next one", driver); - continue; - } - av_dict_set(&hwdevice_options, "kernel_driver", driver, 0); - const int hwdevice_error = av_hwdevice_ctx_create(&av_gpu_decoder, AV_HWDEVICE_TYPE_VAAPI, - nullptr, hwdevice_options, 0); - if (hwdevice_error >= 0) { - LOG_INFO(Service_NVDRV, "Using VA-API with {}", driver); - av_dict_free(&hwdevice_options); - av_codec_ctx->pix_fmt = AV_PIX_FMT_VAAPI; - return true; - } - LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed {}", hwdevice_error); - } - LOG_DEBUG(Service_NVDRV, "VA-API av_hwdevice_ctx_create failed for all drivers"); - av_dict_free(&hwdevice_options); -#endif static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX; static const auto supported_contexts = ListSupportedContexts(); for (const auto& type : PREFERRED_GPU_DECODERS) { if (std::none_of(supported_contexts.begin(), supported_contexts.end(), [&type](const auto& context) { return context == type; })) { + LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); continue; } const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0); @@ -159,6 +103,24 @@ bool Codec::CreateGpuAvDevice() { av_hwdevice_get_type_name(type), hwdevice_res); continue; } +#ifdef LIBVA_FOUND + if (type == AV_HWDEVICE_TYPE_VAAPI) { + // we need to determine if this is an impersonated VAAPI driver + AVHWDeviceContext* hwctx = + static_cast<AVHWDeviceContext*>(static_cast<void*>(av_gpu_decoder->data)); + AVVAAPIDeviceContext* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx); + const char* vendor_name = vaQueryVendorString(vactx->display); + if (strstr(vendor_name, "VDPAU backend")) { + // VDPAU impersonated VAAPI impl's are super buggy, we need to skip them + LOG_DEBUG(Service_NVDRV, "Skipping vdapu impersonated VAAPI driver"); + continue; + } else { + // according to some user testing, certain vaapi driver (Intel?) could be buggy + // so let's log the driver name which may help the developers/supporters + LOG_DEBUG(Service_NVDRV, "Using VAAPI driver: {}", vendor_name); + } + } +#endif for (int i = 0;; i++) { const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i); if (!config) { |