aboutsummaryrefslogtreecommitdiff
path: root/src/qt_common/qt_common.cpp
diff options
context:
space:
mode:
authorcrueter <crueter@eden-emu.dev>2026-05-20 04:49:16 +0200
committercrueter <crueter@eden-emu.dev>2026-05-20 04:49:16 +0200
commitfeb8c5f88eae046c1b76f46e4fa103a844fb0f23 (patch)
tree70f71937a8930c1a5b562f69047e35491d6156b4 /src/qt_common/qt_common.cpp
parent300a646a34b6729879e3fb71d53e625a09683bb2 (diff)
[desktop] More qt_common reorganization (#3916)
Ported from QML branch. Main "big" change is that EmuThread is now a shared state in QtCommon, not individually managed/passed around by GRenderWindow and MainWindow. Signed-off-by: crueter <crueter@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3916 Reviewed-by: Lizzie <lizzie@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Diffstat (limited to 'src/qt_common/qt_common.cpp')
-rw-r--r--src/qt_common/qt_common.cpp216
1 files changed, 180 insertions, 36 deletions
diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp
index 3091171df8..0a134d5047 100644
--- a/src/qt_common/qt_common.cpp
+++ b/src/qt_common/qt_common.cpp
@@ -1,25 +1,52 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
-#include "common/fs/fs.h"
+#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.h"
+#include "common/scm_rev.h"
+#include "core/memory.h"
+
+#ifdef ARCHITECTURE_x86_64
+#include "common/x64/cpu_detect.h"
+#endif
+
#include <QGuiApplication>
#include <QStringLiteral>
-#include "common/logging.h"
#include "core/frontend/emu_window.h"
+#include "qt_common/util/meta.h"
#include <QFile>
+#include <QMessageBox>
+
+#include <thread>
#include <JlCompress.h>
#if !defined(WIN32) && !defined(__APPLE__)
#include <qpa/qplatformnativeinterface.h>
#elif defined(__APPLE__)
#include <objc/message.h>
-#include <objc/runtime.h>
#endif
+#ifdef _WIN32
+#include <QApplication>
+#include <QSettings>
+#include <windows.h>
+#include "common/windows/timer_resolution.h"
+#include "core/core_timing.h"
+#endif
+
+using namespace Common::Literals;
+
namespace QtCommon {
QWidget* rootObject = nullptr;
@@ -27,6 +54,11 @@ QWidget* rootObject = nullptr;
std::unique_ptr<Core::System> system = nullptr;
std::shared_ptr<FileSys::RealVfsFilesystem> vfs = nullptr;
std::unique_ptr<FileSys::ManualContentProvider> provider = nullptr;
+std::unique_ptr<EmuThread> emu_thread = 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.
@@ -58,37 +90,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
// Our Win32 Qt external doesn't have the private API.
wsi.render_surface = reinterpret_cast<void*>(window->winId());
#elif defined(__APPLE__)
- id layer = reinterpret_cast<id (*)(id, SEL)>(objc_msgSend)(
+ wsi.render_surface = reinterpret_cast<void* (*)(id, SEL)>(objc_msgSend)(
reinterpret_cast<id>(window->winId()), sel_registerName("layer"));
-
- // In Qt 6, the layer of the NSView might be a QContainerLayer.
- // MoltenVK needs a CAMetalLayer. We search for it in sublayers.
- Class metal_layer_class = objc_getClass("CAMetalLayer");
- id metal_layer = nullptr;
-
- if (layer) {
- if (reinterpret_cast<bool (*)(id, SEL, Class)>(objc_msgSend)(
- layer, sel_registerName("isKindOfClass:"), metal_layer_class)) {
- metal_layer = layer;
- } else {
- id sublayers = reinterpret_cast<id (*)(id, SEL)>(objc_msgSend)(
- layer, sel_registerName("sublayers"));
- if (sublayers) {
- unsigned long count = reinterpret_cast<unsigned long (*)(id, SEL)>(objc_msgSend)(
- sublayers, sel_registerName("count"));
- for (unsigned long i = 0; i < count; ++i) {
- id sublayer = reinterpret_cast<id (*)(id, SEL, unsigned long)>(objc_msgSend)(
- sublayers, sel_registerName("objectAtIndex:"), i);
- if (reinterpret_cast<bool (*)(id, SEL, Class)>(objc_msgSend)(
- sublayer, sel_registerName("isKindOfClass:"), metal_layer_class)) {
- metal_layer = sublayer;
- break;
- }
- }
- }
- }
- }
- wsi.render_surface = reinterpret_cast<void*>(metal_layer ? metal_layer : layer);
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
@@ -103,18 +106,148 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
}
const QString tr(const char* str) {
- return QGuiApplication::tr(str);
+ return rootObject->tr(str);
}
const QString tr(const std::string& str) {
- return QGuiApplication::tr(str.c_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<u8> buf(sz);
+ if (GetFileVersionInfoA(runtime_dll_name, 0, sz, buf.data())) {
+ VS_FIXEDFILEINFO* pvi;
+ sz = sizeof(VS_FIXEDFILEINFO);
+ if (VerQueryValueA(buf.data(), "\\", reinterpret_cast<LPVOID*>(&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(QWidget* root) {
- system = std::make_unique<Core::System>();
rootObject = root;
+
+ system = std::make_unique<Core::System>();
vfs = std::make_unique<FileSys::RealVfsFilesystem>();
provider = std::make_unique<FileSys::ManualContentProvider>();
+
+ // initialization stuff
+ Common::FS::CreateEdenPaths();
+
+ system->Initialize();
+
+ Common::Log::Initialize();
+ Common::Log::Start();
+
+ Network::Init();
+
+ QtCommon::Meta::RegisterMetaTypes();
+
+ // 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<int> 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<std::chrono::duration<f64, std::milli>>(
+ 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() {
@@ -137,4 +270,15 @@ std::filesystem::path GetEdenCommand() {
return command;
}
+void SetupContentProviders() {
+ system->SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
+ system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
+ provider.get());
+ system->GetFileSystemController().CreateFactories(*vfs);
+}
+
+void SetupHID() {
+ system->HIDCore().ReloadInputDevices();
+}
+
} // namespace QtCommon