// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include "common/literals.h" #include "common/memory_detect.h" #include "core/hle/service/filesystem/filesystem.h" #include "hid_core/hid_core.h" #include "network/network.h" #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" #include "common/scm_rev.h" #include "core/memory.h" #include "qt_common/util/content.h" #ifdef ARCHITECTURE_x86_64 #include "common/x64/cpu_detect.h" #endif #include #include #include "common/logging/log.h" #include "core/frontend/emu_window.h" #include "qt_common/util/meta.h" #include #include #include #include #if !defined(WIN32) && !defined(__APPLE__) #include #elif defined(__APPLE__) #include #endif #ifdef _WIN32 #include #include #include #include "core/core_timing.h" #include "common/windows/timer_resolution.h" #endif using namespace Common::Literals; namespace QtCommon { QObject* rootObject = nullptr; std::unique_ptr system = nullptr; std::shared_ptr vfs = nullptr; std::unique_ptr provider = nullptr; const QStringList supported_file_extensions = {QStringLiteral("nro"), QStringLiteral("nso"), QStringLiteral("nca"), QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; Core::Frontend::WindowSystemType GetWindowSystemType() { // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); if (platform_name == QStringLiteral("windows")) return Core::Frontend::WindowSystemType::Windows; else if (platform_name == QStringLiteral("xcb")) return Core::Frontend::WindowSystemType::X11; else if (platform_name == QStringLiteral("wayland")) return Core::Frontend::WindowSystemType::Wayland; else if (platform_name == QStringLiteral("wayland-egl")) return Core::Frontend::WindowSystemType::Wayland; else if (platform_name == QStringLiteral("cocoa")) return Core::Frontend::WindowSystemType::Cocoa; else if (platform_name == QStringLiteral("android")) return Core::Frontend::WindowSystemType::Android; else if (platform_name == QStringLiteral("haiku")) return Core::Frontend::WindowSystemType::Xcb; LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); return Core::Frontend::WindowSystemType::Windows; } // namespace Core::Frontend::WindowSystemType Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { Core::Frontend::EmuWindow::WindowSystemInfo wsi; wsi.type = GetWindowSystemType(); #if defined(WIN32) // Our Win32 Qt external doesn't have the private API. wsi.render_surface = reinterpret_cast(window->winId()); #elif defined(__APPLE__) wsi.render_surface = reinterpret_cast( objc_msgSend)(reinterpret_cast(window->winId()), sel_registerName("layer")); #else QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); wsi.display_connection = pni->nativeResourceForWindow("display", window); if (wsi.type == Core::Frontend::WindowSystemType::Wayland) wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr; else wsi.render_surface = window ? reinterpret_cast(window->winId()) : nullptr; #endif wsi.render_surface_scale = window ? static_cast(window->devicePixelRatio()) : 1.0f; return wsi; } const QString tr(const char* str) { return rootObject->tr(str); } const QString tr(const std::string& str) { return rootObject->tr(str.c_str()); } static void LogRuntimes() { #ifdef _MSC_VER // It is possible that the name of the dll will change. // vcruntime140.dll is for 2015 and onwards static constexpr char runtime_dll_name[] = "vcruntime140.dll"; UINT sz = GetFileVersionInfoSizeA(runtime_dll_name, nullptr); bool runtime_version_inspection_worked = false; if (sz > 0) { std::vector buf(sz); if (GetFileVersionInfoA(runtime_dll_name, 0, sz, buf.data())) { VS_FIXEDFILEINFO* pvi; sz = sizeof(VS_FIXEDFILEINFO); if (VerQueryValueA(buf.data(), "\\", reinterpret_cast(&pvi), &sz)) { if (pvi->dwSignature == VS_FFI_SIGNATURE) { runtime_version_inspection_worked = true; LOG_INFO(Frontend, "MSVC Compiler: {} Runtime: {}.{}.{}.{}", _MSC_VER, pvi->dwProductVersionMS >> 16, pvi->dwProductVersionMS & 0xFFFF, pvi->dwProductVersionLS >> 16, pvi->dwProductVersionLS & 0xFFFF); } } } } if (!runtime_version_inspection_worked) { LOG_INFO(Frontend, "Unable to inspect {}", runtime_dll_name); } #endif LOG_INFO(Frontend, "Qt Compile: {} Runtime: {}", QT_VERSION_STR, qVersion()); } static QString PrettyProductName() { #ifdef _WIN32 // After Windows 10 Version 2004, Microsoft decided to switch to a different notation: 20H2 // With that notation change they changed the registry key used to denote the current version QSettings windows_registry( QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), QSettings::NativeFormat); const QString release_id = windows_registry.value(QStringLiteral("ReleaseId")).toString(); if (release_id == QStringLiteral("2009")) { const u32 current_build = windows_registry.value(QStringLiteral("CurrentBuild")).toUInt(); const QString display_version = windows_registry.value(QStringLiteral("DisplayVersion")).toString(); const u32 ubr = windows_registry.value(QStringLiteral("UBR")).toUInt(); u32 version = 10; if (current_build >= 22000) { version = 11; } return QStringLiteral("Windows %1 Version %2 (Build %3.%4)") .arg(QString::number(version), display_version, QString::number(current_build), QString::number(ubr)); } #endif return QSysInfo::prettyProductName(); } static void RemoveCachedContents() { const auto cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir); const auto offline_fonts = cache_dir / "fonts"; const auto offline_manual = cache_dir / "offline_web_applet_manual"; const auto offline_legal_information = cache_dir / "offline_web_applet_legal_information"; const auto offline_system_data = cache_dir / "offline_web_applet_system_data"; Common::FS::RemoveDirRecursively(offline_fonts); Common::FS::RemoveDirRecursively(offline_manual); Common::FS::RemoveDirRecursively(offline_legal_information); Common::FS::RemoveDirRecursively(offline_system_data); } void Init(QObject* root) { system = std::make_unique(); rootObject = root; vfs = std::make_unique(); provider = std::make_unique(); // initialization stuff Common::FS::CreateEdenPaths(); system->Initialize(); Common::Log::Initialize(); Common::Log::Start(); Network::Init(); QtCommon::Meta::RegisterMetaTypes(); system->HIDCore().ReloadInputDevices(); // build version const auto branch_name = std::string(Common::g_scm_branch); const auto description = std::string(Common::g_scm_desc); const auto build_id = std::string(Common::g_build_id); const auto yuzu_build = fmt::format("Eden Development Build | {}-{}", branch_name, description); const auto override_build = fmt::format(fmt::runtime(std::string(Common::g_title_bar_format_idle)), build_id); const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; const auto processor_count = std::thread::hardware_concurrency(); // info logging LOG_INFO(Frontend, "Eden Version: {}", yuzu_build_version); LogRuntimes(); #ifdef ARCHITECTURE_x86_64 const auto& caps = Common::GetCPUCaps(); std::string cpu_string = caps.cpu_string; if (caps.avx || caps.avx2 || caps.avx512f) { cpu_string += " | AVX"; if (caps.avx512f) { cpu_string += "512"; } else if (caps.avx2) { cpu_string += '2'; } if (caps.fma || caps.fma4) { cpu_string += " | FMA"; } } LOG_INFO(Frontend, "Host CPU: {}", cpu_string); if (std::optional processor_core = Common::GetProcessorCount()) { LOG_INFO(Frontend, "Host CPU Cores: {}", *processor_core); } #endif LOG_INFO(Frontend, "Host CPU Threads: {}", processor_count); LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); #ifdef _WIN32 LOG_INFO(Frontend, "Host Timer Resolution: {:.4f} ms", std::chrono::duration_cast>( Common::Windows::SetCurrentTimerResolutionToMaximum()) .count()); QtCommon::system->CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution()); #endif // Remove cached contents generated during the previous session RemoveCachedContents(); } std::filesystem::path GetEdenCommand() { std::filesystem::path command; // TODO: flatpak? QString appimage = QString::fromLocal8Bit(getenv("APPIMAGE")); if (!appimage.isEmpty()) { command = std::filesystem::path{appimage.toStdString()}; } else { const QStringList args = QGuiApplication::arguments(); command = args[0].toStdString(); } // If relative path, make it an absolute path if (command.c_str()[0] == '.') { command = Common::FS::GetCurrentDir() / command; } return command; } void SetupContentProviders() { system->SetContentProvider(std::make_unique()); system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); system->GetFileSystemController().CreateFactories(*vfs); } } // namespace QtCommon