summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt34
-rw-r--r--CMakeModules/CopyYuzuQt5Deps.cmake135
m---------externals/dynarmic0
-rw-r--r--src/common/fs/file.h11
-rw-r--r--src/core/arm/arm_interface.h5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp31
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp29
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h2
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.h2
-rw-r--r--src/core/hle/kernel/k_client_port.h6
-rw-r--r--src/core/hle/kernel/k_client_session.h4
-rw-r--r--src/core/hle/kernel/k_event.h14
-rw-r--r--src/core/hle/kernel/k_port.h3
-rw-r--r--src/core/hle/kernel/k_process.h8
-rw-r--r--src/core/hle/kernel/k_readable_event.h4
-rw-r--r--src/core/hle/kernel/k_resource_limit.h4
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp1
-rw-r--r--src/core/hle/kernel/k_server_port.h12
-rw-r--r--src/core/hle/kernel/k_server_session.h6
-rw-r--r--src/core/hle/kernel/k_session.h10
-rw-r--r--src/core/hle/kernel/k_shared_memory.h4
-rw-r--r--src/core/hle/kernel/k_slab_heap.h199
-rw-r--r--src/core/hle/kernel/k_synchronization_object.h4
-rw-r--r--src/core/hle/kernel/k_thread.cpp10
-rw-r--r--src/core/hle/kernel/k_thread.h10
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h10
-rw-r--r--src/core/hle/kernel/k_writable_event.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp5
-rw-r--r--src/core/hle/service/hid/hid.cpp11
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h4
-rw-r--r--src/video_core/rasterizer_accelerated.cpp6
-rw-r--r--src/video_core/rasterizer_accelerated.h12
-rw-r--r--src/yuzu/CMakeLists.txt13
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp14
-rw-r--r--src/yuzu/configuration/configure_dialog.h3
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp14
-rw-r--r--src/yuzu/configuration/configure_per_game.h2
-rw-r--r--src/yuzu/main.cpp40
-rw-r--r--src/yuzu/uisettings.h2
41 files changed, 518 insertions, 192 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e70f29636..10c5032dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,11 +13,11 @@ project(yuzu)
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
-CMAKE_DEPENDENT_OPTION(YUZU_ALLOW_SYSTEM_SDL2 "Try using system SDL2 before fallling back to one from externals" NOT UNIX "ENABLE_SDL2" OFF)
+option(YUZU_ALLOW_SYSTEM_SDL2 "Try using system SDL2 before fallling back to one from externals" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
-CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF)
+CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
@@ -240,6 +240,7 @@ yuzu_find_packages()
# Qt5 requires that we find components, so it doesn't fit our pretty little find package function
if(ENABLE_QT)
+ set(QT_VERSION 5.12)
# We want to load the generated conan qt config so that we get the QT_ROOT var so that we can use the official
# Qt5Config inside the root folder instead of the conan generated one.
if(EXISTS ${CMAKE_BINARY_DIR}/qtConfig.cmake)
@@ -247,22 +248,40 @@ if(ENABLE_QT)
list(APPEND CMAKE_MODULE_PATH "${CONAN_QT_ROOT_RELEASE}")
list(APPEND CMAKE_PREFIX_PATH "${CONAN_QT_ROOT_RELEASE}")
endif()
+
+ # Check for system Qt on Linux, fallback to bundled Qt
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ if (NOT YUZU_USE_BUNDLED_QT)
+ find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets QUIET)
+ if (NOT Qt5_FOUND)
+ set(YUZU_USE_BUNDLED_QT ON CACHE BOOL "Download bundled Qt" FORCE)
+ endif()
+ endif()
+ if (YUZU_USE_BUNDLED_QT)
+ # Binary package currently does not support Qt webengine, so make sure it's disabled
+ set(YUZU_USE_QT_WEB_ENGINE OFF CACHE BOOL "Use Qt Webengine" FORCE)
+ endif()
+ endif()
+
# Workaround for an issue where conan tries to build Qt from scratch instead of download prebuilt binaries
set(QT_PREFIX_HINT)
+
if(YUZU_USE_BUNDLED_QT)
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
- set(QT_VER qt-5.12.8-msvc2017_64)
+ set(QT_BUILD qt-5.12.8-msvc2017_64)
+ elseif ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND NOT MINGW AND ARCHITECTURE_x86_64)
+ set(QT_BUILD qt5_5_15_2)
else()
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
endif()
- if (DEFINED QT_VER)
- download_bundled_external("qt/" ${QT_VER} QT_PREFIX)
+ if (DEFINED QT_BUILD)
+ download_bundled_external("qt/" ${QT_BUILD} QT_PREFIX)
endif()
set(QT_PREFIX_HINT HINTS "${QT_PREFIX}")
endif()
- find_package(Qt5 5.9 COMPONENTS Widgets ${QT_PREFIX_HINT})
+ find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets ${QT_PREFIX_HINT} NO_CMAKE_SYSTEM_PATH)
if (YUZU_USE_QT_WEB_ENGINE)
find_package(Qt5 COMPONENTS WebEngineCore WebEngineWidgets)
endif()
@@ -271,6 +290,7 @@ if(ENABLE_QT)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
endif()
endif()
+
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the yuzu_find_package
if (ENABLE_SDL2)
if (YUZU_USE_BUNDLED_SDL2)
@@ -379,7 +399,7 @@ if (CONAN_REQUIRED_LIBS)
if(ENABLE_QT)
list(APPEND CMAKE_MODULE_PATH "${CONAN_QT_ROOT_RELEASE}")
list(APPEND CMAKE_PREFIX_PATH "${CONAN_QT_ROOT_RELEASE}")
- find_package(Qt5 5.9 REQUIRED COMPONENTS Widgets)
+ find_package(Qt5 5.12 REQUIRED COMPONENTS Widgets)
if (YUZU_USE_QT_WEB_ENGINE)
find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets)
endif()
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake
index 59343b1ca..4a6aeebbb 100644
--- a/CMakeModules/CopyYuzuQt5Deps.cmake
+++ b/CMakeModules/CopyYuzuQt5Deps.cmake
@@ -1,52 +1,111 @@
function(copy_yuzu_Qt5_deps target_dir)
include(WindowsCopyFiles)
- set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
- set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
+ if (MSVC)
+ set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
+ set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
+ else()
+ set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/")
+ set(Qt5_DLL_DIR "${Qt5_DIR}/../../../lib/")
+ endif()
set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
+ set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/")
+ set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/")
+ set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/")
set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/")
set(PLATFORMS ${DLL_DEST}plugins/platforms/)
set(STYLES ${DLL_DEST}plugins/styles/)
set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/)
- windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
- icudt*.dll
- icuin*.dll
- icuuc*.dll
- Qt5Core$<$<CONFIG:Debug>:d>.*
- Qt5Gui$<$<CONFIG:Debug>:d>.*
- Qt5Widgets$<$<CONFIG:Debug>:d>.*
- )
-
- if (YUZU_USE_QT_WEB_ENGINE)
- windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
- Qt5Network$<$<CONFIG:Debug>:d>.*
- Qt5Positioning$<$<CONFIG:Debug>:d>.*
- Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
- Qt5Qml$<$<CONFIG:Debug>:d>.*
- Qt5Quick$<$<CONFIG:Debug>:d>.*
- Qt5QuickWidgets$<$<CONFIG:Debug>:d>.*
- Qt5WebChannel$<$<CONFIG:Debug>:d>.*
- Qt5WebEngine$<$<CONFIG:Debug>:d>.*
- Qt5WebEngineCore$<$<CONFIG:Debug>:d>.*
- Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.*
- QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
+ if (MSVC)
+ windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
+ icudt*.dll
+ icuin*.dll
+ icuuc*.dll
+ Qt5Core$<$<CONFIG:Debug>:d>.*
+ Qt5Gui$<$<CONFIG:Debug>:d>.*
+ Qt5Widgets$<$<CONFIG:Debug>:d>.*
)
- windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST}
- qtwebengine_resources.pak
- qtwebengine_devtools_resources.pak
- qtwebengine_resources_100p.pak
- qtwebengine_resources_200p.pak
- icudtl.dat
- )
- endif ()
- windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
- windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
- windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
- qjpeg$<$<CONFIG:Debug>:d>.*
- qgif$<$<CONFIG:Debug>:d>.*
- )
+ if (YUZU_USE_QT_WEB_ENGINE)
+ windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
+ Qt5Network$<$<CONFIG:Debug>:d>.*
+ Qt5Positioning$<$<CONFIG:Debug>:d>.*
+ Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
+ Qt5Qml$<$<CONFIG:Debug>:d>.*
+ Qt5Quick$<$<CONFIG:Debug>:d>.*
+ Qt5QuickWidgets$<$<CONFIG:Debug>:d>.*
+ Qt5WebChannel$<$<CONFIG:Debug>:d>.*
+ Qt5WebEngine$<$<CONFIG:Debug>:d>.*
+ Qt5WebEngineCore$<$<CONFIG:Debug>:d>.*
+ Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.*
+ QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
+ )
+
+ windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST}
+ qtwebengine_resources.pak
+ qtwebengine_devtools_resources.pak
+ qtwebengine_resources_100p.pak
+ qtwebengine_resources_200p.pak
+ icudtl.dat
+ )
+ endif ()
+ windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
+ windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
+ windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
+ qjpeg$<$<CONFIG:Debug>:d>.*
+ qgif$<$<CONFIG:Debug>:d>.*
+ )
+ else()
+ set(Qt5_DLLS
+ "${Qt5_DLL_DIR}libQt5Core.so.5"
+ "${Qt5_DLL_DIR}libQt5DBus.so.5"
+ "${Qt5_DLL_DIR}libQt5Gui.so.5"
+ "${Qt5_DLL_DIR}libQt5Widgets.so.5"
+ "${Qt5_DLL_DIR}libQt5XcbQpa.so.5"
+ "${Qt5_DLL_DIR}libicudata.so.60"
+ "${Qt5_DLL_DIR}libicui18n.so.60"
+ "${Qt5_DLL_DIR}libicuuc.so.60"
+ )
+ set(Qt5_IMAGEFORMAT_DLLS
+ "${Qt5_IMAGEFORMATS_DIR}libqjpeg.so"
+ "${Qt5_IMAGEFORMATS_DIR}libqgif.so"
+ "${Qt5_IMAGEFORMATS_DIR}libqico.so"
+ )
+ set(Qt5_PLATFORMTHEME_DLLS
+ "${Qt5_PLATFORMTHEMES_DIR}libqgtk3.so"
+ "${Qt5_PLATFORMTHEMES_DIR}libqxdgdesktopportal.so"
+ )
+ set(Qt5_PLATFORM_DLLS
+ "${Qt5_PLATFORMS_DIR}libqxcb.so"
+ )
+ set(Qt5_PLATFORMINPUTCONTEXT_DLLS
+ "${Qt5_PLATFORMINPUTCONTEXTS_DIR}libcomposeplatforminputcontextplugin.so"
+ "${Qt5_PLATFORMINPUTCONTEXTS_DIR}libibusplatforminputcontextplugin.so"
+ )
+ set(Qt5_XCBGLINTEGRATION_DLLS
+ "${Qt5_XCBGLINTEGRATIONS_DIR}libqxcb-glx-integration.so"
+ )
+ foreach(LIB ${Qt5_DLLS})
+ file(COPY ${LIB} DESTINATION "${DLL_DEST}/lib" FOLLOW_SYMLINK_CHAIN)
+ endforeach()
+ foreach(LIB ${Qt5_IMAGEFORMAT_DLLS})
+ file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/imageformats/" FOLLOW_SYMLINK_CHAIN)
+ endforeach()
+ foreach(LIB ${Qt5_PLATFORMTHEME_DLLS})
+ file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/platformthemes/" FOLLOW_SYMLINK_CHAIN)
+ endforeach()
+ foreach(LIB ${Qt5_PLATFORM_DLLS})
+ file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/platforms/" FOLLOW_SYMLINK_CHAIN)
+ endforeach()
+ foreach(LIB ${Qt5_PLATFORMINPUTCONTEXT_DLLS})
+ file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/platforminputcontexts/" FOLLOW_SYMLINK_CHAIN)
+ endforeach()
+ foreach(LIB ${Qt5_XCBGLINTEGRATION_DLLS})
+ file(COPY ${LIB} DESTINATION "${DLL_DEST}plugins/xcbglintegrations/" FOLLOW_SYMLINK_CHAIN)
+ endforeach()
+
+ endif()
# Create an empty qt.conf file. Qt will detect that this file exists, and use the folder that its in as the root folder.
# This way it'll look for plugins in the root/plugins/ folder
add_custom_command(TARGET yuzu POST_BUILD
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject b2a4da5e65985e6b0a20ac8ac37d14425a2a39d
+Subproject 36c3b289a090aaf59a24346f57ebe1b13efb36c
diff --git a/src/common/fs/file.h b/src/common/fs/file.h
index 209f9664b..50e270c5b 100644
--- a/src/common/fs/file.h
+++ b/src/common/fs/file.h
@@ -117,7 +117,7 @@ template <typename Path>
}
#endif
-class IOFile final : NonCopyable {
+class IOFile final {
public:
IOFile();
@@ -142,7 +142,10 @@ public:
FileType type = FileType::BinaryFile,
FileShareFlag flag = FileShareFlag::ShareReadOnly);
- virtual ~IOFile();
+ ~IOFile();
+
+ IOFile(const IOFile&) = delete;
+ IOFile& operator=(const IOFile&) = delete;
IOFile(IOFile&& other) noexcept;
IOFile& operator=(IOFile&& other) noexcept;
@@ -441,8 +444,8 @@ public:
private:
std::filesystem::path file_path;
- FileAccessMode file_access_mode;
- FileType file_type;
+ FileAccessMode file_access_mode{};
+ FileType file_type{};
std::FILE* file = nullptr;
};
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 9a0151736..689e3ceb5 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -65,9 +65,6 @@ public:
/// Step CPU by one instruction
virtual void Step() = 0;
- /// Exits execution from a callback, the callback must rewind the stack
- virtual void ExceptionalExit() = 0;
-
/// Clear all instruction cache
virtual void ClearInstructionCache() = 0;
@@ -159,8 +156,6 @@ public:
*/
virtual void SetTPIDR_EL0(u64 value) = 0;
- virtual void ChangeProcessorID(std::size_t new_core_id) = 0;
-
virtual void SaveContext(ThreadContext32& ctx) = 0;
virtual void SaveContext(ThreadContext64& ctx) = 0;
virtual void LoadContext(const ThreadContext32& ctx) = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 93d43e22e..e5b78210a 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -4,9 +4,9 @@
#include <cinttypes>
#include <memory>
-#include <dynarmic/A32/a32.h>
-#include <dynarmic/A32/config.h>
-#include <dynarmic/A32/context.h>
+#include <dynarmic/interface/A32/a32.h>
+#include <dynarmic/interface/A32/config.h>
+#include <dynarmic/interface/A32/context.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
@@ -78,7 +78,9 @@ public:
}
void CallSVC(u32 swi) override {
- Kernel::Svc::Call(parent.system, swi);
+ parent.svc_called = true;
+ parent.svc_swi = swi;
+ parent.jit->HaltExecution();
}
void AddTicks(u64 ticks) override {
@@ -187,11 +189,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
}
void ARM_Dynarmic_32::Run() {
- jit->Run();
-}
-
-void ARM_Dynarmic_32::ExceptionalExit() {
- jit->ExceptionalExit();
+ while (true) {
+ jit->Run();
+ if (!svc_called) {
+ break;
+ }
+ svc_called = false;
+ Kernel::Svc::Call(system, svc_swi);
+ if (shutdown) {
+ break;
+ }
+ }
}
void ARM_Dynarmic_32::Step() {
@@ -255,10 +263,6 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
cp15->uprw = static_cast<u32>(value);
}
-void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
- jit->ChangeProcessorID(new_core_id);
-}
-
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
Dynarmic::A32::Context context;
jit->SaveContext(context);
@@ -279,6 +283,7 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
void ARM_Dynarmic_32::PrepareReschedule() {
jit->HaltExecution();
+ shutdown = true;
}
void ARM_Dynarmic_32::ClearInstructionCache() {
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 42778c02c..063605b46 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -7,9 +7,9 @@
#include <memory>
#include <unordered_map>
-#include <dynarmic/A32/a32.h>
-#include <dynarmic/A64/a64.h>
-#include <dynarmic/exclusive_monitor.h>
+#include <dynarmic/interface/A32/a32.h>
+#include <dynarmic/interface/A64/a64.h>
+#include <dynarmic/interface/exclusive_monitor.h>
#include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h"
@@ -42,13 +42,11 @@ public:
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
void Run() override;
- void ExceptionalExit() override;
void Step() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
- void ChangeProcessorID(std::size_t new_core_id) override;
bool IsInThumbMode() const {
return (GetPSTATE() & 0x20) != 0;
@@ -83,6 +81,12 @@ private:
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
std::shared_ptr<Dynarmic::A32::Jit> jit;
+
+ // SVC callback
+ u32 svc_swi{};
+ bool svc_called{};
+
+ bool shutdown{};
};
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 08fa85904..dd439f55e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -4,8 +4,8 @@
#include <cinttypes>
#include <memory>
-#include <dynarmic/A64/a64.h>
-#include <dynarmic/A64/config.h>
+#include <dynarmic/interface/A64/a64.h>
+#include <dynarmic/interface/A64/config.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
@@ -102,7 +102,9 @@ public:
}
void CallSVC(u32 swi) override {
- Kernel::Svc::Call(parent.system, swi);
+ parent.svc_called = true;
+ parent.svc_swi = swi;
+ parent.jit->HaltExecution();
}
void AddTicks(u64 ticks) override {
@@ -227,11 +229,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
}
void ARM_Dynarmic_64::Run() {
- jit->Run();
-}
-
-void ARM_Dynarmic_64::ExceptionalExit() {
- jit->ExceptionalExit();
+ while (true) {
+ jit->Run();
+ if (!svc_called) {
+ break;
+ }
+ svc_called = false;
+ Kernel::Svc::Call(system, svc_swi);
+ if (shutdown) {
+ break;
+ }
+ }
}
void ARM_Dynarmic_64::Step() {
@@ -296,10 +304,6 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) {
cb->tpidr_el0 = value;
}
-void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
- jit->ChangeProcessorID(new_core_id);
-}
-
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
@@ -324,6 +328,7 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
void ARM_Dynarmic_64::PrepareReschedule() {
jit->HaltExecution();
+ shutdown = true;
}
void ARM_Dynarmic_64::ClearInstructionCache() {
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index b81fbcc66..0c4e46c64 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -7,7 +7,7 @@
#include <memory>
#include <unordered_map>
-#include <dynarmic/A64/a64.h>
+#include <dynarmic/interface/A64/a64.h>
#include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h"
@@ -40,12 +40,10 @@ public:
void SetPSTATE(u32 pstate) override;
void Run() override;
void Step() override;
- void ExceptionalExit() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
- void ChangeProcessorID(std::size_t new_core_id) override;
void SaveContext(ThreadContext32& ctx) override {}
void SaveContext(ThreadContext64& ctx) override;
@@ -76,6 +74,12 @@ private:
DynarmicExclusiveMonitor& exclusive_monitor;
std::shared_ptr<Dynarmic::A64::Jit> jit;
+
+ // SVC callback
+ u32 svc_swi{};
+ bool svc_called{};
+
+ bool shutdown{};
};
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index 8597beddf..7c7ede79e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -7,7 +7,7 @@
#include <memory>
#include <optional>
-#include <dynarmic/A32/coprocessor.h>
+#include <dynarmic/interface/A32/coprocessor.h>
#include "common/common_types.h"
namespace Core {
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/arm_exclusive_monitor.h
index f9f056a59..73d41f223 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/arm_exclusive_monitor.h
@@ -7,7 +7,7 @@
#include <memory>
#include <unordered_map>
-#include <dynarmic/exclusive_monitor.h>
+#include <dynarmic/interface/exclusive_monitor.h>
#include "common/common_types.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
index 8501156e8..f2fff3b01 100644
--- a/src/core/hle/kernel/k_client_port.h
+++ b/src/core/hle/kernel/k_client_port.h
@@ -22,7 +22,7 @@ class KClientPort final : public KSynchronizationObject {
public:
explicit KClientPort(KernelCore& kernel_);
- virtual ~KClientPort() override;
+ ~KClientPort() override;
void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
void OnSessionFinalized();
@@ -49,8 +49,8 @@ public:
bool IsServerClosed() const;
// Overridden virtual functions.
- virtual void Destroy() override;
- virtual bool IsSignaled() const override;
+ void Destroy() override;
+ bool IsSignaled() const override;
ResultCode CreateSession(KClientSession** out);
diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h
index 720a8c243..b11d5b4e3 100644
--- a/src/core/hle/kernel/k_client_session.h
+++ b/src/core/hle/kernel/k_client_session.h
@@ -34,7 +34,7 @@ class KClientSession final
public:
explicit KClientSession(KernelCore& kernel_);
- virtual ~KClientSession();
+ ~KClientSession() override;
void Initialize(KSession* parent_, std::string&& name_) {
// Set member variables.
@@ -42,7 +42,7 @@ public:
name = std::move(name_);
}
- virtual void Destroy() override;
+ void Destroy() override;
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
KSession* GetParent() const {
diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h
index 9a59ffb70..3d3ec99e2 100644
--- a/src/core/hle/kernel/k_event.h
+++ b/src/core/hle/kernel/k_event.h
@@ -20,23 +20,21 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObj
public:
explicit KEvent(KernelCore& kernel_);
- virtual ~KEvent();
+ ~KEvent() override;
void Initialize(std::string&& name);
- virtual void Finalize() override;
+ void Finalize() override;
- virtual bool IsInitialized() const override {
+ bool IsInitialized() const override {
return initialized;
}
- virtual uintptr_t GetPostDestroyArgument() const override {
+ uintptr_t GetPostDestroyArgument() const override {
return reinterpret_cast<uintptr_t>(owner);
}
- static void PostDestroy(uintptr_t arg);
-
- virtual KProcess* GetOwner() const override {
+ KProcess* GetOwner() const override {
return owner;
}
@@ -48,6 +46,8 @@ public:
return writable_event;
}
+ static void PostDestroy(uintptr_t arg);
+
private:
KReadableEvent readable_event;
KWritableEvent writable_event;
diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h
index 960f1f3a3..4018ea2df 100644
--- a/src/core/hle/kernel/k_port.h
+++ b/src/core/hle/kernel/k_port.h
@@ -22,7 +22,7 @@ class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjec
public:
explicit KPort(KernelCore& kernel_);
- virtual ~KPort();
+ ~KPort() override;
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
@@ -59,7 +59,6 @@ private:
ServerClosed = 3,
};
-private:
KServerPort server;
KClientPort client;
State state{State::Invalid};
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 123d71cd3..c0656b9af 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -331,19 +331,19 @@ public:
void LoadModule(CodeSet code_set, VAddr base_addr);
- virtual bool IsInitialized() const override {
+ bool IsInitialized() const override {
return is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
- virtual void Finalize();
+ void Finalize() override;
- virtual u64 GetId() const override final {
+ u64 GetId() const override {
return GetProcessID();
}
- virtual bool IsSignaled() const override;
+ bool IsSignaled() const override;
void PinCurrentThread();
void UnpinCurrentThread();
diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h
index 33cd1dd3e..b2850ac7b 100644
--- a/src/core/hle/kernel/k_readable_event.h
+++ b/src/core/hle/kernel/k_readable_event.h
@@ -31,8 +31,8 @@ public:
return parent;
}
- virtual bool IsSignaled() const override;
- virtual void Destroy() override;
+ bool IsSignaled() const override;
+ void Destroy() override;
ResultCode Signal();
ResultCode Clear();
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
index 0debbbb51..fab6005ff 100644
--- a/src/core/hle/kernel/k_resource_limit.h
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -37,10 +37,10 @@ class KResourceLimit final
public:
explicit KResourceLimit(KernelCore& kernel_);
- virtual ~KResourceLimit();
+ ~KResourceLimit() override;
void Initialize(const Core::Timing::CoreTiming* core_timing_);
- virtual void Finalize() override;
+ void Finalize() override;
s64 GetLimitValue(LimitableResource which) const;
s64 GetCurrentValue(LimitableResource which) const;
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 2f82fbcd6..6a7d80d03 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -659,7 +659,6 @@ void KScheduler::Unload(KThread* thread) {
if (thread) {
if (thread->IsCallingSvc()) {
- system.ArmInterface(core_id).ExceptionalExit();
thread->ClearIsCallingSvc();
}
if (!thread->IsTerminationRequested()) {
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index d1a757ec3..55481d63f 100644
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -25,12 +25,9 @@ class SessionRequestHandler;
class KServerPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject);
-private:
- using SessionList = boost::intrusive::list<KServerSession>;
-
public:
explicit KServerPort(KernelCore& kernel_);
- virtual ~KServerPort() override;
+ ~KServerPort() override;
void Initialize(KPort* parent_, std::string&& name_);
@@ -63,13 +60,14 @@ public:
bool IsLight() const;
// Overridden virtual functions.
- virtual void Destroy() override;
- virtual bool IsSignaled() const override;
+ void Destroy() override;
+ bool IsSignaled() const override;
private:
+ using SessionList = boost::intrusive::list<KServerSession>;
+
void CleanupSessions();
-private:
SessionList session_list;
SessionRequestHandlerPtr session_handler;
KPort* parent{};
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index dd4de2904..27b757ad2 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -42,9 +42,9 @@ class KServerSession final : public KSynchronizationObject,
public:
explicit KServerSession(KernelCore& kernel_);
- virtual ~KServerSession() override;
+ ~KServerSession() override;
- virtual void Destroy() override;
+ void Destroy() override;
void Initialize(KSession* parent_, std::string&& name_);
@@ -56,7 +56,7 @@ public:
return parent;
}
- virtual bool IsSignaled() const override;
+ bool IsSignaled() const override;
void OnClientClosed();
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
index a981fd1f6..4ddd080d2 100644
--- a/src/core/hle/kernel/k_session.h
+++ b/src/core/hle/kernel/k_session.h
@@ -18,17 +18,17 @@ class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAut
public:
explicit KSession(KernelCore& kernel_);
- virtual ~KSession() override;
+ ~KSession() override;
void Initialize(KClientPort* port_, const std::string& name_);
- virtual void Finalize() override;
+ void Finalize() override;
- virtual bool IsInitialized() const override {
+ bool IsInitialized() const override {
return initialized;
}
- virtual uintptr_t GetPostDestroyArgument() const override {
+ uintptr_t GetPostDestroyArgument() const override {
return reinterpret_cast<uintptr_t>(process);
}
@@ -78,7 +78,6 @@ private:
ServerClosed = 3,
};
-private:
void SetState(State state) {
atomic_state = static_cast<u8>(state);
}
@@ -87,7 +86,6 @@ private:
return static_cast<State>(atomic_state.load(std::memory_order_relaxed));
}
-private:
KServerSession server;
KClientSession client;
std::atomic<std::underlying_type_t<State>> atomic_state{
diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h
index 553a56327..e9815f90b 100644
--- a/src/core/hle/kernel/k_shared_memory.h
+++ b/src/core/hle/kernel/k_shared_memory.h
@@ -68,9 +68,9 @@ public:
return device_memory->GetPointer(physical_address + offset);
}
- virtual void Finalize() override;
+ void Finalize() override;
- virtual bool IsInitialized() const override {
+ bool IsInitialized() const override {
return is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h
index 81d472a3e..0ad74b0a0 100644
--- a/src/core/hle/kernel/k_slab_heap.h
+++ b/src/core/hle/kernel/k_slab_heap.h
@@ -4,34 +4,213 @@
#pragma once
+#include <atomic>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+
namespace Kernel {
class KernelCore;
-/// This is a placeholder class to manage slab heaps for kernel objects. For now, we just allocate
-/// these with new/delete, but this can be re-implemented later to allocate these in emulated
-/// memory.
+namespace impl {
+
+class KSlabHeapImpl final : NonCopyable {
+public:
+ struct Node {
+ Node* next{};
+ };
+
+ constexpr KSlabHeapImpl() = default;
+
+ void Initialize(std::size_t size) {
+ ASSERT(head == nullptr);
+ obj_size = size;
+ }
+
+ constexpr std::size_t GetObjectSize() const {
+ return obj_size;
+ }
+
+ Node* GetHead() const {
+ return head;
+ }
+
+ void* Allocate() {
+ Node* ret = head.load();
+
+ do {
+ if (ret == nullptr) {
+ break;
+ }
+ } while (!head.compare_exchange_weak(ret, ret->next));
+
+ return ret;
+ }
+
+ void Free(void* obj) {
+ Node* node = static_cast<Node*>(obj);
+
+ Node* cur_head = head.load();
+ do {
+ node->next = cur_head;
+ } while (!head.compare_exchange_weak(cur_head, node));
+ }
+
+private:
+ std::atomic<Node*> head{};
+ std::size_t obj_size{};
+};
+
+} // namespace impl
+
+class KSlabHeapBase : NonCopyable {
+public:
+ constexpr KSlabHeapBase() = default;
+
+ constexpr bool Contains(uintptr_t addr) const {
+ return start <= addr && addr < end;
+ }
+
+ constexpr std::size_t GetSlabHeapSize() const {
+ return (end - start) / GetObjectSize();
+ }
+
+ constexpr std::size_t GetObjectSize() const {
+ return impl.GetObjectSize();
+ }
+
+ constexpr uintptr_t GetSlabHeapAddress() const {
+ return start;
+ }
+
+ std::size_t GetObjectIndexImpl(const void* obj) const {
+ return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize();
+ }
+
+ std::size_t GetPeakIndex() const {
+ return GetObjectIndexImpl(reinterpret_cast<const void*>(peak));
+ }
+
+ void* AllocateImpl() {
+ return impl.Allocate();
+ }
+
+ void FreeImpl(void* obj) {
+ // Don't allow freeing an object that wasn't allocated from this heap
+ ASSERT(Contains(reinterpret_cast<uintptr_t>(obj)));
+
+ impl.Free(obj);
+ }
+
+ void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) {
+ // Ensure we don't initialize a slab using null memory
+ ASSERT(memory != nullptr);
+
+ // Initialize the base allocator
+ impl.Initialize(obj_size);
+
+ // Set our tracking variables
+ const std::size_t num_obj = (memory_size / obj_size);
+ start = reinterpret_cast<uintptr_t>(memory);
+ end = start + num_obj * obj_size;
+ peak = start;
+
+ // Free the objects
+ u8* cur = reinterpret_cast<u8*>(end);
+
+ for (std::size_t i{}; i < num_obj; i++) {
+ cur -= obj_size;
+ impl.Free(cur);
+ }
+ }
+
+private:
+ using Impl = impl::KSlabHeapImpl;
+
+ Impl impl;
+ uintptr_t peak{};
+ uintptr_t start{};
+ uintptr_t end{};
+};
template <typename T>
-class KSlabHeap final : NonCopyable {
+class KSlabHeap final : public KSlabHeapBase {
public:
- KSlabHeap() = default;
+ enum class AllocationType {
+ Host,
+ Guest,
+ };
- void Initialize([[maybe_unused]] void* memory, [[maybe_unused]] std::size_t memory_size) {
- // Placeholder that should initialize the backing slab heap implementation.
+ explicit constexpr KSlabHeap(AllocationType allocation_type_ = AllocationType::Host)
+ : KSlabHeapBase(), allocation_type{allocation_type_} {}
+
+ void Initialize(void* memory, std::size_t memory_size) {
+ if (allocation_type == AllocationType::Guest) {
+ InitializeImpl(sizeof(T), memory, memory_size);
+ }
}
T* Allocate() {
- return new T();
+ switch (allocation_type) {
+ case AllocationType::Host:
+ // Fallback for cases where we do not yet support allocating guest memory from the slab
+ // heap, such as for kernel memory regions.
+ return new T;
+
+ case AllocationType::Guest:
+ T* obj = static_cast<T*>(AllocateImpl());
+ if (obj != nullptr) {
+ new (obj) T();
+ }
+ return obj;
+ }
+
+ UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type);
+ return nullptr;
}
T* AllocateWithKernel(KernelCore& kernel) {
- return new T(kernel);
+ switch (allocation_type) {
+ case AllocationType::Host:
+ // Fallback for cases where we do not yet support allocating guest memory from the slab
+ // heap, such as for kernel memory regions.
+ return new T(kernel);
+
+ case AllocationType::Guest:
+ T* obj = static_cast<T*>(AllocateImpl());
+ if (obj != nullptr) {
+ new (obj) T(kernel);
+ }
+ return obj;
+ }
+
+ UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type);
+ return nullptr;
}
void Free(T* obj) {
- delete obj;
+ switch (allocation_type) {
+ case AllocationType::Host:
+ // Fallback for cases where we do not yet support allocating guest memory from the slab
+ // heap, such as for kernel memory regions.
+ delete obj;
+ return;
+
+ case AllocationType::Guest:
+ FreeImpl(obj);
+ return;
+ }
+
+ UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type);
}
+
+ constexpr std::size_t GetObjectIndex(const T* obj) const {
+ return GetObjectIndexImpl(obj);
+ }
+
+private:
+ const AllocationType allocation_type;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h
index a41dd1220..3d4ce1fbc 100644
--- a/src/core/hle/kernel/k_synchronization_object.h
+++ b/src/core/hle/kernel/k_synchronization_object.h
@@ -29,7 +29,7 @@ public:
KSynchronizationObject** objects, const s32 num_objects,
s64 timeout);
- virtual void Finalize() override;
+ void Finalize() override;
[[nodiscard]] virtual bool IsSignaled() const = 0;
@@ -37,7 +37,7 @@ public:
protected:
explicit KSynchronizationObject(KernelCore& kernel);
- virtual ~KSynchronizationObject();
+ ~KSynchronizationObject() override;
virtual void OnFinalizeSynchronizationObject() {}
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index e3f08f256..3cf43d290 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -168,13 +168,13 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0,
sizeof(StackParameters));
- // Setup the TLS, if needed.
- if (type == ThreadType::User) {
- tls_address = owner->CreateTLSRegion();
- }
-
// Set parent, if relevant.
if (owner != nullptr) {
+ // Setup the TLS, if needed.
+ if (type == ThreadType::User) {
+ tls_address = owner->CreateTLSRegion();
+ }
+
parent = owner;
parent->Open();
parent->IncrementThreadCount();
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 4abfc2b49..01eebb165 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -358,21 +358,21 @@ public:
return termination_requested || GetRawState() == ThreadState::Terminated;
}
- [[nodiscard]] virtual u64 GetId() const override final {
+ [[nodiscard]] u64 GetId() const override {
return this->GetThreadID();
}
- [[nodiscard]] virtual bool IsInitialized() const override {
+ [[nodiscard]] bool IsInitialized() const override {
return initialized;
}
- [[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override {
+ [[nodiscard]] uintptr_t GetPostDestroyArgument() const override {
return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0);
}
- virtual void Finalize() override;
+ void Finalize() override;
- [[nodiscard]] virtual bool IsSignaled() const override;
+ [[nodiscard]] bool IsSignaled() const override;
static void PostDestroy(uintptr_t arg);
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h
index c2d0f1eaf..31029a5c2 100644
--- a/src/core/hle/kernel/k_transfer_memory.h
+++ b/src/core/hle/kernel/k_transfer_memory.h
@@ -27,23 +27,23 @@ class KTransferMemory final
public:
explicit KTransferMemory(KernelCore& kernel_);
- virtual ~KTransferMemory() override;
+ ~KTransferMemory() override;
ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
- virtual void Finalize() override;
+ void Finalize() override;
- virtual bool IsInitialized() const override {
+ bool IsInitialized() const override {
return is_initialized;
}
- virtual uintptr_t GetPostDestroyArgument() const override {
+ uintptr_t GetPostDestroyArgument() const override {
return reinterpret_cast<uintptr_t>(owner);
}
static void PostDestroy(uintptr_t arg);
- KProcess* GetOwner() const {
+ KProcess* GetOwner() const override {
return owner;
}
diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h
index 607b0eadb..858d982c4 100644
--- a/src/core/hle/kernel/k_writable_event.h
+++ b/src/core/hle/kernel/k_writable_event.h
@@ -21,7 +21,7 @@ public:
explicit KWritableEvent(KernelCore& kernel_);
~KWritableEvent() override;
- virtual void Destroy() override;
+ void Destroy() override;
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 8b55df82e..0ffb78d51 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -258,7 +258,7 @@ struct KernelCore::Impl {
KAutoObject::Create(thread.get());
ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess());
thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
- return std::move(thread);
+ return thread;
};
thread_local auto thread = make_thread();
@@ -620,7 +620,8 @@ struct KernelCore::Impl {
void InitializePageSlab() {
// Allocate slab heaps
- user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
+ user_slab_heap_pages =
+ std::make_unique<KSlabHeap<Page>>(KSlabHeap<Page>::AllocationType::Guest);
// TODO(ameerj): This should be derived, not hardcoded within the kernel
constexpr u64 user_slab_heap_size{0x3de000};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 49c17fd14..df0fe1c8e 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1770,7 +1770,7 @@ public:
{232, nullptr, "GetIrSensorState"},
{233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
{301, nullptr, "ActivateNpadSystem"},
- {303, nullptr, "ApplyNpadSystemCommonPolicy"},
+ {303, &HidSys::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
{304, nullptr, "EnableAssigningSingleOnSlSrPress"},
{305, nullptr, "DisableAssigningSingleOnSlSrPress"},
{306, nullptr, "GetLastActiveNpad"},
@@ -1949,6 +1949,15 @@ public:
RegisterHandlers(functions);
}
+
+private:
+ void ApplyNpadSystemCommonPolicy(Kernel::HLERequestContext& ctx) {
+ // We already do this for homebrew so we can just stub it out
+ LOG_WARNING(Service_HID, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
};
class HidTmp final : public ServiceFramework<HidTmp> {
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index de971041f..9e6b87960 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -596,7 +596,7 @@ void BufferCache<P>::PopAsyncFlushes() {
runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies);
}
runtime.Finish();
- for (const auto [copy, buffer_id] : downloads) {
+ for (const auto& [copy, buffer_id] : downloads) {
const Buffer& buffer = slot_buffers[buffer_id];
const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
// Undo the modified offset
@@ -606,7 +606,7 @@ void BufferCache<P>::PopAsyncFlushes() {
}
} else {
const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
- for (const auto [copy, buffer_id] : downloads) {
+ for (const auto& [copy, buffer_id] : downloads) {
Buffer& buffer = slot_buffers[buffer_id];
buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
index 62d84c0f8..6decd2546 100644
--- a/src/video_core/rasterizer_accelerated.cpp
+++ b/src/video_core/rasterizer_accelerated.cpp
@@ -18,10 +18,10 @@ RasterizerAccelerated::~RasterizerAccelerated() = default;
void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
const auto page_end = Common::DivCeil(addr + size, Core::Memory::PAGE_SIZE);
for (auto page = addr >> Core::Memory::PAGE_BITS; page != page_end; ++page) {
- auto& count = cached_pages.at(page >> 3).Count(page);
+ auto& count = cached_pages.at(page >> 2).Count(page);
if (delta > 0) {
- ASSERT_MSG(count < UINT8_MAX, "Count may overflow!");
+ ASSERT_MSG(count < UINT16_MAX, "Count may overflow!");
} else if (delta < 0) {
ASSERT_MSG(count > 0, "Count may underflow!");
} else {
@@ -29,7 +29,7 @@ void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int del
}
// Adds or subtracts 1, as count is a unsigned 8-bit value
- count += static_cast<u8>(delta);
+ count += static_cast<u16>(delta);
// Assume delta is either -1 or 1
if (count == 0) {
diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h
index 9227a4adc..ea879bfdd 100644
--- a/src/video_core/rasterizer_accelerated.h
+++ b/src/video_core/rasterizer_accelerated.h
@@ -29,20 +29,20 @@ private:
public:
CacheEntry() = default;
- std::atomic_uint8_t& Count(std::size_t page) {
- return values[page & 7];
+ std::atomic_uint16_t& Count(std::size_t page) {
+ return values[page & 3];
}
- const std::atomic_uint8_t& Count(std::size_t page) const {
- return values[page & 7];
+ const std::atomic_uint16_t& Count(std::size_t page) const {
+ return values[page & 3];
}
private:
- std::array<std::atomic_uint8_t, 8> values{};
+ std::array<std::atomic_uint16_t, 4> values{};
};
static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
- std::array<CacheEntry, 0x800000> cached_pages;
+ std::array<CacheEntry, 0x1000000> cached_pages;
Core::Memory::Memory& cpu_memory;
};
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index cc0790e07..634fe66a5 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -4,6 +4,12 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
+# Set the RPATH for Qt Libraries
+# This must be done before the `yuzu` target is created
+if (YUZU_USE_BUNDLED_QT AND (${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
+ set(CMAKE_BUILD_RPATH "${CMAKE_BINARY_DIR}/bin/lib/")
+endif()
+
add_executable(yuzu
Info.plist
about_dialog.cpp
@@ -278,11 +284,14 @@ if(UNIX AND NOT APPLE)
install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif()
-if (MSVC)
+if (YUZU_USE_BUNDLED_QT)
include(CopyYuzuQt5Deps)
+ copy_yuzu_Qt5_deps(yuzu)
+endif()
+
+if (MSVC)
include(CopyYuzuSDLDeps)
include(CopyYuzuFFmpegDeps)
- copy_yuzu_Qt5_deps(yuzu)
copy_yuzu_SDL_deps(yuzu)
copy_yuzu_FFmpeg_deps(yuzu)
endif()
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 3ad40d2b3..6028135c5 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <QAbstractButton>
+#include <QDialogButtonBox>
#include <QHash>
#include <QListWidgetItem>
+#include <QPushButton>
#include <QSignalBlocker>
#include "common/settings.h"
#include "core/core.h"
@@ -31,6 +34,12 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
&ConfigureDialog::UpdateVisibleTabs);
+ if (Core::System::GetInstance().IsPoweredOn()) {
+ QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply);
+ connect(apply_button, &QAbstractButton::clicked, this,
+ &ConfigureDialog::HandleApplyButtonClicked);
+ }
+
adjustSize();
ui->selectorList->setCurrentRow(0);
}
@@ -80,6 +89,11 @@ void ConfigureDialog::RetranslateUI() {
ui->tabWidget->setCurrentIndex(old_index);
}
+void ConfigureDialog::HandleApplyButtonClicked() {
+ UISettings::values.configuration_applied = true;
+ ApplyConfiguration();
+}
+
Q_DECLARE_METATYPE(QList<QWidget*>);
void ConfigureDialog::PopulateSelectionList() {
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 570c3b941..abe019635 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -35,9 +35,10 @@ signals:
private:
void changeEvent(QEvent* event) override;
-
void RetranslateUI();
+ void HandleApplyButtonClicked();
+
void SetConfiguration();
void UpdateVisibleTabs();
void PopulateSelectionList();
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index 3e13bd438..d89f1ad4b 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -6,9 +6,12 @@
#include <memory>
#include <utility>
+#include <QAbstractButton>
#include <QCheckBox>
+#include <QDialogButtonBox>
#include <QHeaderView>
#include <QMenu>
+#include <QPushButton>
#include <QStandardItemModel>
#include <QString>
#include <QTimer>
@@ -42,6 +45,12 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id)
scene = new QGraphicsScene;
ui->icon_view->setScene(scene);
+ if (Core::System::GetInstance().IsPoweredOn()) {
+ QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply);
+ connect(apply_button, &QAbstractButton::clicked, this,
+ &ConfigurePerGame::HandleApplyButtonClicked);
+ }
+
LoadConfiguration();
}
@@ -74,6 +83,11 @@ void ConfigurePerGame::RetranslateUI() {
ui->retranslateUi(this);
}
+void ConfigurePerGame::HandleApplyButtonClicked() {
+ UISettings::values.configuration_applied = true;
+ ApplyConfiguration();
+}
+
void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file) {
this->file = std::move(file);
LoadConfiguration();
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index 5f9a08cef..f6e6ab7c4 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -39,6 +39,8 @@ private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
+ void HandleApplyButtonClicked();
+
void LoadConfiguration();
std::unique_ptr<Ui::ConfigurePerGame> ui;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 37ef62967..0f0e228b0 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2587,12 +2587,12 @@ void GMainWindow::OnConfigure() {
&GMainWindow::OnLanguageChanged);
const auto result = configure_dialog.exec();
- if (result != QDialog::Accepted) {
+ if (result != QDialog::Accepted && !UISettings::values.configuration_applied) {
return;
+ } else if (result == QDialog::Accepted) {
+ configure_dialog.ApplyConfiguration();
+ controller_dialog->refreshConfiguration();
}
-
- configure_dialog.ApplyConfiguration();
- controller_dialog->refreshConfiguration();
InitializeHotkeys();
if (UISettings::values.theme != old_theme) {
UpdateUITheme();
@@ -2607,6 +2607,8 @@ void GMainWindow::OnConfigure() {
game_list->PopulateAsync(UISettings::values.game_dirs);
}
+ UISettings::values.configuration_applied = false;
+
config->Save();
if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
@@ -2636,23 +2638,27 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
ConfigurePerGame dialog(this, title_id);
dialog.LoadFromFile(v_file);
const auto result = dialog.exec();
- if (result == QDialog::Accepted) {
+
+ if (result != QDialog::Accepted && !UISettings::values.configuration_applied) {
+ Settings::RestoreGlobalState(system.IsPoweredOn());
+ return;
+ } else if (result == QDialog::Accepted) {
dialog.ApplyConfiguration();
+ }
- const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
- if (reload) {
- game_list->PopulateAsync(UISettings::values.game_dirs);
- }
+ const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
+ if (reload) {
+ game_list->PopulateAsync(UISettings::values.game_dirs);
+ }
- // Do not cause the global config to write local settings into the config file
- const bool is_powered_on = system.IsPoweredOn();
- Settings::RestoreGlobalState(is_powered_on);
+ // Do not cause the global config to write local settings into the config file
+ const bool is_powered_on = system.IsPoweredOn();
+ Settings::RestoreGlobalState(is_powered_on);
- if (!is_powered_on) {
- config->Save();
- }
- } else {
- Settings::RestoreGlobalState(system.IsPoweredOn());
+ UISettings::values.configuration_applied = false;
+
+ if (!is_powered_on) {
+ config->Save();
}
}
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 5ba00b8c8..49122ec32 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -95,6 +95,8 @@ struct Values {
uint8_t row_2_text_id;
std::atomic_bool is_game_list_reload_pending{false};
bool cache_game_list;
+
+ bool configuration_applied;
};
extern Values values;