diff --git a/README.md b/README.md index d68fe0735..72c1b5c41 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2263. +This is the source code for early-access 2264. ## Legal Notice diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 28f834443..82ee2c8a1 100755 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -15,26 +15,26 @@ namespace Common { u64 EstimateRDTSCFrequency() { - const auto milli_10 = std::chrono::milliseconds{10}; - // get current time + // Discard the first result measuring the rdtsc. _mm_mfence(); - const u64 tscStart = __rdtsc(); - const auto startTime = std::chrono::steady_clock::now(); - // wait roughly 3 seconds - while (true) { - auto milli = std::chrono::duration_cast( - std::chrono::steady_clock::now() - startTime); - if (milli.count() >= 3000) - break; - std::this_thread::sleep_for(milli_10); - } - const auto endTime = std::chrono::steady_clock::now(); + __rdtsc(); + std::this_thread::sleep_for(std::chrono::milliseconds{1}); _mm_mfence(); - const u64 tscEnd = __rdtsc(); - // calculate difference - const u64 timer_diff = - std::chrono::duration_cast(endTime - startTime).count(); - const u64 tsc_diff = tscEnd - tscStart; + __rdtsc(); + + // Get the current time. + const auto start_time = std::chrono::steady_clock::now(); + _mm_mfence(); + const u64 tsc_start = __rdtsc(); + // Wait for 200 milliseconds. + std::this_thread::sleep_for(std::chrono::milliseconds{200}); + const auto end_time = std::chrono::steady_clock::now(); + _mm_mfence(); + const u64 tsc_end = __rdtsc(); + // Calculate differences. + const u64 timer_diff = static_cast( + std::chrono::duration_cast(end_time - start_time).count()); + const u64 tsc_diff = tsc_end - tsc_start; const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); return tsc_freq; } diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 91a30fef7..6a6325e38 100755 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(host_shaders) if(LIBVA_FOUND) set_source_files_properties(command_classes/codecs/codec.cpp PROPERTIES COMPILE_DEFINITIONS LIBVA_FOUND=1) + list(APPEND FFmpeg_LIBRARIES ${LIBVA_LIBRARIES}) endif() add_library(video_core STATIC diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 2c0d8da64..2a532b883 100755 --- 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 +#ifdef LIBVA_FOUND +// for querying VAAPI driver information +#include +#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 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 ListLinuxKernelModules() { - using FILEPtr = std::unique_ptr; - auto module_listing = FILEPtr{fopen("/proc/modules", "rt"), std::fclose}; - std::vector 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) - // - 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 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(static_cast(av_gpu_decoder->data)); + AVVAAPIDeviceContext* vactx = static_cast(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) {