summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/common_paths.h6
-rw-r--r--src/common/file_util.cpp68
-rw-r--r--src/common/file_util.h27
-rw-r--r--src/common/logging/backend.cpp25
-rw-r--r--src/common/logging/backend.h7
-rw-r--r--src/common/logging/filter.cpp75
-rw-r--r--src/common/logging/filter.h6
-rw-r--r--src/common/param_package.cpp19
-rw-r--r--src/common/param_package.h2
-rw-r--r--src/common/synchronized_wrapper.h85
-rw-r--r--src/core/arm/arm_interface.h7
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h2
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp14
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h2
-rw-r--r--src/core/file_sys/errors.h16
-rw-r--r--src/core/file_sys/partition_filesystem.cpp12
-rw-r--r--src/core/file_sys/vfs.cpp2
-rw-r--r--src/core/file_sys/vfs.h27
-rw-r--r--src/core/file_sys/vfs_offset.cpp5
-rw-r--r--src/core/file_sys/vfs_offset.h2
-rw-r--r--src/core/file_sys/vfs_real.cpp16
-rw-r--r--src/core/hle/ipc_helpers.h19
-rw-r--r--src/core/hle/kernel/scheduler.cpp3
-rw-r--r--src/core/hle/kernel/thread.cpp1
-rw-r--r--src/core/hle/kernel/thread.h9
-rw-r--r--src/core/hle/service/apm/interface.cpp17
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp4
-rw-r--r--src/core/hle/service/ns/pl_u.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp30
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h8
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp2
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp7
-rw-r--r--src/core/telemetry_session.cpp6
-rw-r--r--src/tests/core/arm/arm_test_common.cpp9
-rw-r--r--src/tests/core/arm/arm_test_common.h7
-rw-r--r--src/video_core/gpu.cpp6
-rw-r--r--src/video_core/gpu.h9
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h1
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp6
-rw-r--r--src/yuzu/main.cpp18
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp21
48 files changed, 338 insertions, 304 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index f49a31612..d5d4f6f82 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -63,7 +63,6 @@ add_library(common STATIC
string_util.cpp
string_util.h
swap.h
- synchronized_wrapper.h
telemetry.cpp
telemetry.h
thread.cpp
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 9bf3efaf2..6799a357a 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -26,7 +26,7 @@
#define USA_DIR "USA"
#define JAP_DIR "JAP"
-// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
+// Subdirs in the User dir returned by GetUserPath(UserPath::UserDir)
#define CONFIG_DIR "config"
#define CACHE_DIR "cache"
#define SDMC_DIR "sdmc"
@@ -35,11 +35,11 @@
#define LOG_DIR "log"
// Filenames
-// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
+// Files in the directory returned by GetUserPath(UserPath::ConfigDir)
#define EMU_CONFIG "emu.ini"
#define DEBUGGER_CONFIG "debugger.ini"
#define LOGGER_CONFIG "logger.ini"
-// Files in the directory returned by GetUserPath(D_LOGS_IDX)
+// Files in the directory returned by GetUserPath(UserPath::LogDir)
#define LOG_FILE "yuzu_log.txt"
// Sys files
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index c882ab39f..1e28f7cbb 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <sstream>
+#include <unordered_map>
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_paths.h"
@@ -681,67 +682,68 @@ std::string GetSysDirectory() {
// Returns a string with a yuzu data dir or file in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
-const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) {
- static std::string paths[NUM_PATH_INDICES];
+const std::string& GetUserPath(UserPath path, const std::string& new_path) {
+ static std::unordered_map<UserPath, std::string> paths;
+ auto& user_path = paths[UserPath::UserDir];
// Set up all paths and files on the first run
- if (paths[D_USER_IDX].empty()) {
+ if (user_path.empty()) {
#ifdef _WIN32
- paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
- if (!FileUtil::IsDirectory(paths[D_USER_IDX])) {
- paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
+ user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
+ if (!FileUtil::IsDirectory(user_path)) {
+ user_path = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
} else {
LOG_INFO(Common_Filesystem, "Using the local user directory");
}
- paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
- paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
+ paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
+ paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
#else
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
- paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
- paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
- paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
+ user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
+ paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
+ paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
} else {
std::string data_dir = GetUserDirectory("XDG_DATA_HOME");
std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME");
std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME");
- paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
- paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
- paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
+ user_path = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
+ paths.emplace(UserPath::ConfigDir, config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP);
+ paths.emplace(UserPath::CacheDir, cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP);
}
#endif
- paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
- paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
- paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
+ paths.emplace(UserPath::SDMCDir, user_path + SDMC_DIR DIR_SEP);
+ paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
+ paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
// TODO: Put the logs in a better location for each OS
- paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOG_DIR DIR_SEP;
+ paths.emplace(UserPath::LogDir, user_path + LOG_DIR DIR_SEP);
}
- if (!newPath.empty()) {
- if (!FileUtil::IsDirectory(newPath)) {
- LOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath);
- return paths[DirIDX];
+ if (!new_path.empty()) {
+ if (!FileUtil::IsDirectory(new_path)) {
+ LOG_ERROR(Common_Filesystem, "Invalid path specified {}", new_path);
+ return paths[path];
} else {
- paths[DirIDX] = newPath;
+ paths[path] = new_path;
}
- switch (DirIDX) {
- case D_ROOT_IDX:
- paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
+ switch (path) {
+ case UserPath::RootDir:
+ user_path = paths[UserPath::RootDir] + DIR_SEP;
break;
- case D_USER_IDX:
- paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
- paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
- paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
- paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
- paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
+ case UserPath::UserDir:
+ user_path = paths[UserPath::RootDir] + DIR_SEP;
+ paths[UserPath::ConfigDir] = user_path + CONFIG_DIR DIR_SEP;
+ paths[UserPath::CacheDir] = user_path + CACHE_DIR DIR_SEP;
+ paths[UserPath::SDMCDir] = user_path + SDMC_DIR DIR_SEP;
+ paths[UserPath::NANDDir] = user_path + NAND_DIR DIR_SEP;
break;
}
}
- return paths[DirIDX];
+ return paths[path];
}
size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 1f38b1560..ff01bf0ff 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -16,21 +16,20 @@
#include "common/string_util.h"
#endif
-// User directory indices for GetUserPath
-enum {
- D_USER_IDX,
- D_ROOT_IDX,
- D_CONFIG_IDX,
- D_CACHE_IDX,
- D_SDMC_IDX,
- D_NAND_IDX,
- D_SYSDATA_IDX,
- D_LOGS_IDX,
- NUM_PATH_INDICES
-};
-
namespace FileUtil {
+// User paths for GetUserPath
+enum class UserPath {
+ CacheDir,
+ ConfigDir,
+ LogDir,
+ NANDDir,
+ RootDir,
+ SDMCDir,
+ SysDataDir,
+ UserDir,
+};
+
// FileSystem tree node/
struct FSTEntry {
bool isDirectory;
@@ -123,7 +122,7 @@ bool SetCurrentDir(const std::string& directory);
// Returns a pointer to a string with a yuzu data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
-const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath = "");
+const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
// Returns the path to where the sys file are
std::string GetSysDirectory();
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index ed1e93cc2..59b999935 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -3,19 +3,20 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <array>
+#include <atomic>
#include <chrono>
#include <climits>
#include <condition_variable>
#include <memory>
+#include <mutex>
#include <thread>
+#include <vector>
#ifdef _WIN32
#include <share.h> // For _SH_DENYWR
#else
#define _SH_DENYWR 0
#endif
#include "common/assert.h"
-#include "common/common_funcs.h" // snprintf compatibility define
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
@@ -48,11 +49,11 @@ public:
backends.push_back(std::move(backend));
}
- void RemoveBackend(const std::string& backend_name) {
+ void RemoveBackend(std::string_view backend_name) {
std::lock_guard<std::mutex> lock(writing_mutex);
- auto it = std::remove_if(backends.begin(), backends.end(), [&backend_name](const auto& i) {
- return !strcmp(i->GetName(), backend_name.c_str());
- });
+ const auto it =
+ std::remove_if(backends.begin(), backends.end(),
+ [&backend_name](const auto& i) { return backend_name == i->GetName(); });
backends.erase(it, backends.end());
}
@@ -64,10 +65,10 @@ public:
filter = f;
}
- Backend* GetBackend(const std::string& backend_name) {
- auto it = std::find_if(backends.begin(), backends.end(), [&backend_name](const auto& i) {
- return !strcmp(i->GetName(), backend_name.c_str());
- });
+ Backend* GetBackend(std::string_view backend_name) {
+ const auto it =
+ std::find_if(backends.begin(), backends.end(),
+ [&backend_name](const auto& i) { return backend_name == i->GetName(); });
if (it == backends.end())
return nullptr;
return it->get();
@@ -265,11 +266,11 @@ void AddBackend(std::unique_ptr<Backend> backend) {
Impl::Instance().AddBackend(std::move(backend));
}
-void RemoveBackend(const std::string& backend_name) {
+void RemoveBackend(std::string_view backend_name) {
Impl::Instance().RemoveBackend(backend_name);
}
-Backend* GetBackend(const std::string& backend_name) {
+Backend* GetBackend(std::string_view backend_name) {
return Impl::Instance().GetBackend(backend_name);
}
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index 57cdf6b2d..b3f4b9cef 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -4,10 +4,9 @@
#pragma once
#include <chrono>
-#include <cstdarg>
#include <memory>
#include <string>
-#include <utility>
+#include <string_view>
#include "common/file_util.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
@@ -106,9 +105,9 @@ private:
void AddBackend(std::unique_ptr<Backend> backend);
-void RemoveBackend(const std::string& backend_name);
+void RemoveBackend(std::string_view backend_name);
-Backend* GetBackend(const std::string& backend_name);
+Backend* GetBackend(std::string_view backend_name);
/**
* Returns the name of the passed log class as a C-string. Subclasses are separated by periods
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 6ed087beb..2dd331152 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -8,39 +8,9 @@
#include "common/string_util.h"
namespace Log {
-
-Filter::Filter(Level default_level) {
- ResetAll(default_level);
-}
-
-void Filter::ResetAll(Level level) {
- class_levels.fill(level);
-}
-
-void Filter::SetClassLevel(Class log_class, Level level) {
- class_levels[static_cast<size_t>(log_class)] = level;
-}
-
-void Filter::ParseFilterString(const std::string& filter_str) {
- auto clause_begin = filter_str.cbegin();
- while (clause_begin != filter_str.cend()) {
- auto clause_end = std::find(clause_begin, filter_str.cend(), ' ');
-
- // If clause isn't empty
- if (clause_end != clause_begin) {
- ParseFilterRule(clause_begin, clause_end);
- }
-
- if (clause_end != filter_str.cend()) {
- // Skip over the whitespace
- ++clause_end;
- }
- clause_begin = clause_end;
- }
-}
-
+namespace {
template <typename It>
-static Level GetLevelByName(const It begin, const It end) {
+Level GetLevelByName(const It begin, const It end) {
for (u8 i = 0; i < static_cast<u8>(Level::Count); ++i) {
const char* level_name = GetLevelName(static_cast<Level>(i));
if (Common::ComparePartialString(begin, end, level_name)) {
@@ -51,7 +21,7 @@ static Level GetLevelByName(const It begin, const It end) {
}
template <typename It>
-static Class GetClassByName(const It begin, const It end) {
+Class GetClassByName(const It begin, const It end) {
for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) {
const char* level_name = GetLogClassName(static_cast<Class>(i));
if (Common::ComparePartialString(begin, end, level_name)) {
@@ -61,8 +31,8 @@ static Class GetClassByName(const It begin, const It end) {
return Class::Count;
}
-bool Filter::ParseFilterRule(const std::string::const_iterator begin,
- const std::string::const_iterator end) {
+template <typename Iterator>
+bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
auto level_separator = std::find(begin, end, ':');
if (level_separator == end) {
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}",
@@ -77,7 +47,7 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
}
if (Common::ComparePartialString(begin, level_separator, "*")) {
- ResetAll(level);
+ instance.ResetAll(level);
return true;
}
@@ -87,9 +57,40 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
return false;
}
- SetClassLevel(log_class, level);
+ instance.SetClassLevel(log_class, level);
return true;
}
+} // Anonymous namespace
+
+Filter::Filter(Level default_level) {
+ ResetAll(default_level);
+}
+
+void Filter::ResetAll(Level level) {
+ class_levels.fill(level);
+}
+
+void Filter::SetClassLevel(Class log_class, Level level) {
+ class_levels[static_cast<size_t>(log_class)] = level;
+}
+
+void Filter::ParseFilterString(std::string_view filter_view) {
+ auto clause_begin = filter_view.cbegin();
+ while (clause_begin != filter_view.cend()) {
+ auto clause_end = std::find(clause_begin, filter_view.cend(), ' ');
+
+ // If clause isn't empty
+ if (clause_end != clause_begin) {
+ ParseFilterRule(*this, clause_begin, clause_end);
+ }
+
+ if (clause_end != filter_view.cend()) {
+ // Skip over the whitespace
+ ++clause_end;
+ }
+ clause_begin = clause_end;
+ }
+}
bool Filter::CheckMessage(Class log_class, Level level) const {
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index 2a4f7c845..d5ffc5a58 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -6,7 +6,7 @@
#include <array>
#include <cstddef>
-#include <string>
+#include <string_view>
#include "common/logging/log.h"
namespace Log {
@@ -40,9 +40,7 @@ public:
* - `Service:Info` -- Sets the level of Service to Info.
* - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace.
*/
- void ParseFilterString(const std::string& filter_str);
- bool ParseFilterRule(const std::string::const_iterator start,
- const std::string::const_iterator end);
+ void ParseFilterString(std::string_view filter_view);
/// Matches class/level combination against the filter, returning true if it passed.
bool CheckMessage(Class log_class, Level level) const;
diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp
index e0df430ab..9526ca0c6 100644
--- a/src/common/param_package.cpp
+++ b/src/common/param_package.cpp
@@ -3,7 +3,9 @@
// Refer to the license.txt file included.
#include <array>
+#include <utility>
#include <vector>
+
#include "common/logging/log.h"
#include "common/param_package.h"
#include "common/string_util.h"
@@ -12,10 +14,11 @@ namespace Common {
constexpr char KEY_VALUE_SEPARATOR = ':';
constexpr char PARAM_SEPARATOR = ',';
+
constexpr char ESCAPE_CHARACTER = '$';
-const std::string KEY_VALUE_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '0'};
-const std::string PARAM_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '1'};
-const std::string ESCAPE_CHARACTER_ESCAPE{ESCAPE_CHARACTER, '2'};
+constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0";
+constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1";
+constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2";
ParamPackage::ParamPackage(const std::string& serialized) {
std::vector<std::string> pairs;
@@ -35,7 +38,7 @@ ParamPackage::ParamPackage(const std::string& serialized) {
part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER});
}
- Set(key_value[0], key_value[1]);
+ Set(key_value[0], std::move(key_value[1]));
}
}
@@ -101,16 +104,16 @@ float ParamPackage::Get(const std::string& key, float default_value) const {
}
}
-void ParamPackage::Set(const std::string& key, const std::string& value) {
- data[key] = value;
+void ParamPackage::Set(const std::string& key, std::string value) {
+ data.insert_or_assign(key, std::move(value));
}
void ParamPackage::Set(const std::string& key, int value) {
- data[key] = std::to_string(value);
+ data.insert_or_assign(key, std::to_string(value));
}
void ParamPackage::Set(const std::string& key, float value) {
- data[key] = std::to_string(value);
+ data.insert_or_assign(key, std::to_string(value));
}
bool ParamPackage::Has(const std::string& key) const {
diff --git a/src/common/param_package.h b/src/common/param_package.h
index c4c11b221..7842cd4ef 100644
--- a/src/common/param_package.h
+++ b/src/common/param_package.h
@@ -28,7 +28,7 @@ public:
std::string Get(const std::string& key, const std::string& default_value) const;
int Get(const std::string& key, int default_value) const;
float Get(const std::string& key, float default_value) const;
- void Set(const std::string& key, const std::string& value);
+ void Set(const std::string& key, std::string value);
void Set(const std::string& key, int value);
void Set(const std::string& key, float value);
bool Has(const std::string& key) const;
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h
deleted file mode 100644
index 4a1984c46..000000000
--- a/src/common/synchronized_wrapper.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <algorithm>
-#include <mutex>
-
-namespace Common {
-
-template <typename T>
-class SynchronizedWrapper;
-
-/**
- * Synchronized reference, that keeps a SynchronizedWrapper's mutex locked during its lifetime. This
- * greatly reduces the chance that someone will access the wrapped resource without locking the
- * mutex.
- */
-template <typename T>
-class SynchronizedRef {
-public:
- SynchronizedRef(SynchronizedWrapper<T>& wrapper) : wrapper(&wrapper) {
- wrapper.mutex.lock();
- }
-
- SynchronizedRef(SynchronizedRef&) = delete;
- SynchronizedRef(SynchronizedRef&& o) : wrapper(o.wrapper) {
- o.wrapper = nullptr;
- }
-
- ~SynchronizedRef() {
- if (wrapper)
- wrapper->mutex.unlock();
- }
-
- SynchronizedRef& operator=(SynchronizedRef&) = delete;
- SynchronizedRef& operator=(SynchronizedRef&& o) {
- std::swap(wrapper, o.wrapper);
- return *this;
- }
-
- T& operator*() {
- return wrapper->data;
- }
- const T& operator*() const {
- return wrapper->data;
- }
-
- T* operator->() {
- return &wrapper->data;
- }
- const T* operator->() const {
- return &wrapper->data;
- }
-
-private:
- SynchronizedWrapper<T>* wrapper;
-};
-
-/**
- * Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no
- * one forgets to lock a mutex before acessing an object. To access the wrapped object construct a
- * SyncronizedRef on this wrapper. Inspired by Rust's Mutex type
- * (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
- */
-template <typename T>
-class SynchronizedWrapper {
-public:
- template <typename... Args>
- SynchronizedWrapper(Args&&... args) : data(std::forward<Args>(args)...) {}
-
- SynchronizedRef<T> Lock() {
- return {*this};
- }
-
-private:
- template <typename U>
- friend class SynchronizedRef;
-
- std::mutex mutex;
- T data;
-};
-
-} // namespace Common
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 8416e73b0..b0d7ced7f 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -20,9 +20,6 @@ public:
u64 cpsr;
std::array<u128, 32> fpu_registers;
u64 fpscr;
-
- // TODO(bunnei): Fix once we have proper support for tpidrro_el0, etc. in the JIT
- VAddr tls_address;
};
/// Runs the CPU until an event happens
@@ -104,6 +101,10 @@ public:
virtual void SetTlsAddress(VAddr address) = 0;
+ virtual u64 GetTPIDR_EL0() const = 0;
+
+ virtual void SetTPIDR_EL0(u64 value) = 0;
+
/**
* Saves the current CPU context
* @param ctx Thread context to save
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 3572ee7b9..5d7efc9b6 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -196,6 +196,14 @@ void ARM_Dynarmic::SetTlsAddress(u64 address) {
cb->tpidrro_el0 = address;
}
+u64 ARM_Dynarmic::GetTPIDR_EL0() const {
+ return cb->tpidr_el0;
+}
+
+void ARM_Dynarmic::SetTPIDR_EL0(u64 value) {
+ cb->tpidr_el0 = value;
+}
+
void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
@@ -203,7 +211,6 @@ void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
ctx.cpsr = jit->GetPstate();
ctx.fpu_registers = jit->GetVectors();
ctx.fpscr = jit->GetFpcr();
- ctx.tls_address = cb->tpidrro_el0;
}
void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
@@ -213,7 +220,6 @@ void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
jit->SetPstate(static_cast<u32>(ctx.cpsr));
jit->SetVectors(ctx.fpu_registers);
jit->SetFpcr(static_cast<u32>(ctx.fpscr));
- cb->tpidrro_el0 = ctx.tls_address;
}
void ARM_Dynarmic::PrepareReschedule() {
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index ed724c3f1..a9891ac4f 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -34,6 +34,8 @@ public:
void SetCPSR(u32 cpsr) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
+ void SetTPIDR_EL0(u64 value) override;
+ u64 GetTPIDR_EL0() const override;
void SaveContext(ThreadContext& ctx) override;
void LoadContext(const ThreadContext& ctx) override;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index d2d699e9b..4c11f35a4 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -169,6 +169,16 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
}
+u64 ARM_Unicorn::GetTPIDR_EL0() const {
+ u64 value{};
+ CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
+ return value;
+}
+
+void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
+ CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
+}
+
void ARM_Unicorn::Run() {
if (GDBStub::IsServerEnabled()) {
ExecuteInstructions(std::max(4000000, 0));
@@ -220,8 +230,6 @@ void ARM_Unicorn::SaveContext(ARM_Interface::ThreadContext& ctx) {
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31));
- ctx.tls_address = GetTlsAddress();
-
for (int i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = &ctx.fpu_registers[i];
@@ -249,8 +257,6 @@ void ARM_Unicorn::LoadContext(const ARM_Interface::ThreadContext& ctx) {
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31));
- SetTlsAddress(ctx.tls_address);
-
for (auto i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = (void*)&ctx.fpu_registers[i];
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index a78a0acf2..af7943352 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -28,6 +28,8 @@ public:
void SetCPSR(u32 cpsr) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
+ void SetTPIDR_EL0(u64 value) override;
+ u64 GetTPIDR_EL0() const override;
void SaveContext(ThreadContext& ctx) override;
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index a152dbd33..fea0593c7 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -20,13 +20,13 @@ enum {
constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound);
// TODO(bunnei): Replace these with correct errors for Switch OS
-constexpr ResultCode ERROR_INVALID_PATH(ResultCode(-1));
-constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ResultCode(-1));
-constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ResultCode(-1));
-constexpr ResultCode ERROR_FILE_NOT_FOUND(ResultCode(-1));
-constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ResultCode(-1));
-constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ResultCode(-1));
-constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ResultCode(-1));
-constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(ResultCode(-1));
+constexpr ResultCode ERROR_INVALID_PATH(-1);
+constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1);
+constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1);
+constexpr ResultCode ERROR_FILE_NOT_FOUND(-1);
+constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1);
+constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1);
+constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1);
+constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1);
} // namespace FileSys
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 7ccca1089..8d2bd9f6b 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -2,7 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
#include <utility>
+
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/file_sys/partition_filesystem.h"
@@ -99,14 +104,15 @@ void PartitionFilesystem::PrintDebugInfo() const {
}
bool PartitionFilesystem::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
- auto iter = std::find(pfs_files.begin(), pfs_files.end(), file);
+ const auto iter = std::find(pfs_files.begin(), pfs_files.end(), file);
if (iter == pfs_files.end())
return false;
- pfs_files[iter - pfs_files.begin()] = pfs_files.back();
+ const std::ptrdiff_t offset = std::distance(pfs_files.begin(), iter);
+ pfs_files[offset] = pfs_files.back();
pfs_files.pop_back();
- pfs_dirs.emplace_back(dir);
+ pfs_dirs.emplace_back(std::move(dir));
return true;
}
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 16c8ad90b..3f690f12a 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -42,7 +42,7 @@ bool VfsFile::WriteByte(u8 data, size_t offset) {
return Write(&data, 1, offset) == 1;
}
-size_t VfsFile::WriteBytes(std::vector<u8> data, size_t offset) {
+size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) {
return Write(data.data(), data.size(), offset);
}
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index a5213e0cc..db3c77eac 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -59,8 +59,7 @@ struct VfsFile : NonCopyable {
// Returns the number of bytes (sizeof(T)*number_elements) read successfully.
template <typename T>
size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const {
- static_assert(std::is_trivially_copyable<T>::value,
- "Data type must be trivially copyable.");
+ static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset);
}
@@ -69,8 +68,7 @@ struct VfsFile : NonCopyable {
// Returns the number of bytes read successfully.
template <typename T>
size_t ReadBytes(T* data, size_t size, size_t offset = 0) const {
- static_assert(std::is_trivially_copyable<T>::value,
- "Data type must be trivially copyable.");
+ static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return Read(reinterpret_cast<u8*>(data), size, offset);
}
@@ -78,8 +76,7 @@ struct VfsFile : NonCopyable {
// Returns the number of bytes read successfully (sizeof(T)).
template <typename T>
size_t ReadObject(T* data, size_t offset = 0) const {
- static_assert(std::is_trivially_copyable<T>::value,
- "Data type must be trivially copyable.");
+ static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);
}
@@ -88,33 +85,29 @@ struct VfsFile : NonCopyable {
virtual bool WriteByte(u8 data, size_t offset = 0);
// Writes a vector of bytes to offset in file and returns the number of bytes successfully
// written.
- virtual size_t WriteBytes(std::vector<u8> data, size_t offset = 0);
+ virtual size_t WriteBytes(const std::vector<u8>& data, size_t offset = 0);
// Writes an array of type T, size number_elements to offset in file.
// Returns the number of bytes (sizeof(T)*number_elements) written successfully.
template <typename T>
- size_t WriteArray(T* data, size_t number_elements, size_t offset = 0) {
- static_assert(std::is_trivially_copyable<T>::value,
- "Data type must be trivially copyable.");
-
+ size_t WriteArray(const T* data, size_t number_elements, size_t offset = 0) {
+ static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return Write(data, number_elements * sizeof(T), offset);
}
// Writes size bytes starting at memory location data to offset in file.
// Returns the number of bytes written successfully.
template <typename T>
- size_t WriteBytes(T* data, size_t size, size_t offset = 0) {
- static_assert(std::is_trivially_copyable<T>::value,
- "Data type must be trivially copyable.");
- return Write(reinterpret_cast<u8*>(data), size, offset);
+ size_t WriteBytes(const T* data, size_t size, size_t offset = 0) {
+ static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
+ return Write(reinterpret_cast<const u8*>(data), size, offset);
}
// Writes one object of type T to offset in file.
// Returns the number of bytes written successfully (sizeof(T)).
template <typename T>
size_t WriteObject(const T& data, size_t offset = 0) {
- static_assert(std::is_trivially_copyable<T>::value,
- "Data type must be trivially copyable.");
+ static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return Write(&data, sizeof(T), offset);
}
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index 31fdd9aa1..217e02235 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <utility>
#include "core/file_sys/vfs_offset.h"
@@ -75,7 +76,7 @@ bool OffsetVfsFile::WriteByte(u8 data, size_t r_offset) {
return false;
}
-size_t OffsetVfsFile::WriteBytes(std::vector<u8> data, size_t r_offset) {
+size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, size_t r_offset) {
return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
}
@@ -88,7 +89,7 @@ size_t OffsetVfsFile::GetOffset() const {
}
size_t OffsetVfsFile::TrimToFit(size_t r_size, size_t r_offset) const {
- return std::max<size_t>(std::min<size_t>(size - r_offset, r_size), 0);
+ return std::clamp(r_size, size_t{0}, size - r_offset);
}
} // namespace FileSys
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index 2e16e47eb..ded4827f5 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -28,7 +28,7 @@ struct OffsetVfsFile : public VfsFile {
std::vector<u8> ReadBytes(size_t size, size_t offset) const override;
std::vector<u8> ReadAllBytes() const override;
bool WriteByte(u8 data, size_t offset) override;
- size_t WriteBytes(std::vector<u8> data, size_t offset) override;
+ size_t WriteBytes(const std::vector<u8>& data, size_t offset) override;
bool Rename(const std::string& name) override;
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 22c858e0d..f27fb1f2a 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -2,6 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <utility>
+
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "core/file_sys/vfs_real.h"
@@ -104,11 +109,11 @@ RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_)
}
std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
- return std::vector<std::shared_ptr<VfsFile>>(files);
+ return files;
}
std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
- return std::vector<std::shared_ptr<VfsDirectory>>(subdirectories);
+ return subdirectories;
}
bool RealVfsDirectory::IsWritable() const {
@@ -163,14 +168,15 @@ bool RealVfsDirectory::Rename(const std::string& name) {
}
bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
- auto iter = std::find(files.begin(), files.end(), file);
+ const auto iter = std::find(files.begin(), files.end(), file);
if (iter == files.end())
return false;
- files[iter - files.begin()] = files.back();
+ const std::ptrdiff_t offset = std::distance(files.begin(), iter);
+ files[offset] = files.back();
files.pop_back();
- subdirectories.emplace_back(dir);
+ subdirectories.emplace_back(std::move(dir));
return true;
}
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 24605a273..8b5b06f31 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -175,6 +175,25 @@ public:
void Push(const First& first_value, const Other&... other_values);
/**
+ * Helper function for pushing strongly-typed enumeration values.
+ *
+ * @tparam Enum The enumeration type to be pushed
+ *
+ * @param value The value to push.
+ *
+ * @note The underlying size of the enumeration type is the size of the
+ * data that gets pushed. e.g. "enum class SomeEnum : u16" will
+ * push a u16-sized amount of data.
+ */
+ template <typename Enum>
+ void PushEnum(Enum value) {
+ static_assert(std::is_enum_v<Enum>, "T must be an enum type within a PushEnum call.");
+ static_assert(!std::is_convertible_v<Enum, int>,
+ "enum type in PushEnum must be a strongly typed enum.");
+ Push(static_cast<std::underlying_type_t<Enum>>(value));
+ }
+
+ /**
* @brief Copies the content of the given trivially copyable class to the buffer as a normal
* param
* @note: The input class must be correctly packed/padded to fit hardware layout.
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index f7e25cbf5..e307eec98 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -56,6 +56,8 @@ void Scheduler::SwitchContext(Thread* new_thread) {
if (previous_thread) {
previous_thread->last_running_ticks = CoreTiming::GetTicks();
cpu_core->SaveContext(previous_thread->context);
+ // Save the TPIDR_EL0 system register in case it was modified.
+ previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0();
if (previous_thread->status == ThreadStatus::Running) {
// This is only the case when a reschedule is triggered without the current thread
@@ -87,6 +89,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
cpu_core->LoadContext(new_thread->context);
cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
+ cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
cpu_core->ClearExclusiveState();
} else {
current_thread = nullptr;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 53f2e861e..cd85c4b7c 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -312,6 +312,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->status = ThreadStatus::Dormant;
thread->entry_point = entry_point;
thread->stack_top = stack_top;
+ thread->tpidr_el0 = 0;
thread->nominal_priority = thread->current_priority = priority;
thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 47881ec20..6218960d2 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -183,6 +183,14 @@ public:
}
/*
+ * Returns the value of the TPIDR_EL0 Read/Write system register for this thread.
+ * @returns The value of the TPIDR_EL0 register.
+ */
+ u64 GetTPIDR_EL0() const {
+ return tpidr_el0;
+ }
+
+ /*
* Returns the address of the current thread's command buffer, located in the TLS.
* @returns VAddr of the thread's command buffer.
*/
@@ -213,6 +221,7 @@ public:
s32 processor_id;
VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
+ u64 tpidr_el0; ///< TPIDR_EL0 read/write system register.
SharedPtr<Process> owner_process; ///< Process that owns this thread
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index 751d73f8d..ce943d829 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -20,6 +20,21 @@ public:
}
private:
+ enum class PerformanceConfiguration : u32 {
+ Config1 = 0x00010000,
+ Config2 = 0x00010001,
+ Config3 = 0x00010002,
+ Config4 = 0x00020000,
+ Config5 = 0x00020001,
+ Config6 = 0x00020002,
+ Config7 = 0x00020003,
+ Config8 = 0x00020004,
+ Config9 = 0x00020005,
+ Config10 = 0x00020006,
+ Config11 = 0x92220007,
+ Config12 = 0x92220008,
+ };
+
void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -40,7 +55,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(0); // Performance configuration
+ rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
}
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index dffcdfbaf..671e0b8d0 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -272,9 +272,9 @@ void RegisterFileSystems() {
sdmc_factory = nullptr;
auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>(
- FileUtil::GetUserPath(D_NAND_IDX), FileSys::Mode::Write);
+ FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::Write);
auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>(
- FileUtil::GetUserPath(D_SDMC_IDX), FileSys::Mode::Write);
+ FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::Write);
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
save_data_factory = std::move(savedata);
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 691b1d106..bad27894a 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -42,7 +42,7 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
RegisterHandlers(functions);
// Attempt to load shared font data from disk
- const std::string filepath{FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT};
+ const std::string filepath{FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + SHARED_FONT};
FileUtil::CreateFullPath(filepath); // Create path if not already created
FileUtil::IOFile file(filepath, "rb");
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 8de870596..126782573 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -42,6 +42,9 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u
if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) {
return SubmitGPFIFO(input, output);
}
+ if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
+ return KickoffPB(input, output);
+ }
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
@@ -127,14 +130,37 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
- params.gpfifo, params.num_entries, params.flags);
+ params.address, params.num_entries, params.flags);
auto entries = std::vector<IoctlGpfifoEntry>();
entries.resize(params.num_entries);
std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(IoctlGpfifoEntry));
for (auto entry : entries) {
- VAddr va_addr = entry.Address();
+ Tegra::GPUVAddr va_addr = entry.Address();
+ Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz);
+ }
+ params.fence_out.id = 0;
+ params.fence_out.value = 0;
+ std::memcpy(output.data(), &params, output.size());
+ return 0;
+}
+
+u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) {
+ if (input.size() < sizeof(IoctlSubmitGpfifo)) {
+ UNIMPLEMENTED();
+ }
+ IoctlSubmitGpfifo params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
+ params.address, params.num_entries, params.flags);
+
+ std::vector<IoctlGpfifoEntry> entries(params.num_entries);
+ Memory::ReadBlock(params.address, entries.data(),
+ params.num_entries * sizeof(IoctlGpfifoEntry));
+
+ for (auto entry : entries) {
+ Tegra::GPUVAddr va_addr = entry.Address();
Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz);
}
params.fence_out.id = 0;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index c9f6b9b6a..aa8df2e6e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -15,6 +15,7 @@ namespace Service::Nvidia::Devices {
class nvmap;
constexpr u32 NVGPU_IOCTL_MAGIC('H');
constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
+constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
class nvhost_gpu final : public nvdevice {
public:
@@ -158,14 +159,14 @@ private:
BitField<31, 1, u32_le> unk2;
};
- VAddr Address() const {
- return (static_cast<VAddr>(gpu_va_hi) << 32) | entry0;
+ Tegra::GPUVAddr Address() const {
+ return (static_cast<Tegra::GPUVAddr>(gpu_va_hi) << 32) | entry0;
}
};
static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size");
struct IoctlSubmitGpfifo {
- u64_le gpfifo; // (ignored) pointer to gpfifo fence structs
+ u64_le address; // pointer to gpfifo entry structs
u32_le num_entries; // number of fence objects being submitted
u32_le flags;
IoctlFence fence_out; // returned new fence object for others to wait on
@@ -193,6 +194,7 @@ private:
u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index b10efd5c9..1b497b814 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -101,7 +101,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
{8, &NVDRV::SetClientPID, "SetClientPID"},
{9, nullptr, "DumpGraphicsMemoryInfo"},
{10, nullptr, "InitializeDevtools"},
- {11, nullptr, "Ioctl2"},
+ {11, &NVDRV::Ioctl, "Ioctl2"},
{12, nullptr, "Ioctl3"},
{13, &NVDRV::FinishInitialize, "FinishInitialize"},
};
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 19b8667ba..394963a69 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -83,16 +83,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
- const VAddr load_addr = next_load_addr;
const FileSys::VirtualFile module_file = dir->GetFile(module);
- if (module_file != nullptr)
+ if (module_file != nullptr) {
+ const VAddr load_addr = next_load_addr;
next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr);
- if (next_load_addr) {
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
// Register module with GDBStub
GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
- } else {
- next_load_addr = load_addr;
}
}
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index b9a603df3..69aa7a7be 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -37,7 +37,8 @@ static u64 GenerateTelemetryId() {
u64 GetTelemetryId() {
u64 telemetry_id{};
- static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"};
+ static const std::string& filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
+ "telemetry_id"};
if (FileUtil::Exists(filename)) {
FileUtil::IOFile file(filename, "rb");
@@ -61,7 +62,8 @@ u64 GetTelemetryId() {
u64 RegenerateTelemetryId() {
const u64 new_telemetry_id{GenerateTelemetryId()};
- static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"};
+ static const std::string& filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
+ "telemetry_id"};
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 7f9f27e19..539746246 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -10,8 +10,6 @@
namespace ArmTests {
-static Memory::PageTable* page_table = nullptr;
-
TestEnvironment::TestEnvironment(bool mutable_memory_)
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
@@ -67,10 +65,13 @@ boost::optional<bool> TestEnvironment::TestMemory::IsValidAddress(VAddr addr) {
}
boost::optional<u8> TestEnvironment::TestMemory::Read8(VAddr addr) {
- auto iter = data.find(addr);
+ const auto iter = data.find(addr);
+
if (iter == data.end()) {
- return addr; // Some arbitrary data
+ // Some arbitrary data
+ return static_cast<u8>(addr);
}
+
return iter->second;
}
diff --git a/src/tests/core/arm/arm_test_common.h b/src/tests/core/arm/arm_test_common.h
index b66922d61..7fdbda494 100644
--- a/src/tests/core/arm/arm_test_common.h
+++ b/src/tests/core/arm/arm_test_common.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <tuple>
#include <unordered_map>
#include <vector>
@@ -9,6 +11,10 @@
#include "common/common_types.h"
#include "core/memory_hook.h"
+namespace Memory {
+struct PageTable;
+}
+
namespace ArmTests {
struct WriteRecord {
@@ -79,6 +85,7 @@ private:
bool mutable_memory;
std::shared_ptr<TestMemory> test_memory;
std::vector<WriteRecord> write_records;
+ Memory::PageTable* page_table = nullptr;
};
} // namespace ArmTests
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index e36483145..a003bc9e3 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -20,7 +20,11 @@ GPU::GPU() {
GPU::~GPU() = default;
-const Tegra::Engines::Maxwell3D& GPU::Get3DEngine() const {
+const Engines::Maxwell3D& GPU::Maxwell3D() const {
+ return *maxwell_3d;
+}
+
+Engines::Maxwell3D& GPU::Maxwell3D() {
return *maxwell_3d;
}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 60930e997..a32148ecd 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -93,15 +93,14 @@ public:
/// Processes a command list stored at the specified address in GPU memory.
void ProcessCommandList(GPUVAddr address, u32 size);
+ /// Returns a const reference to the Maxwell3D GPU engine.
+ const Engines::Maxwell3D& Maxwell3D() const;
+
/// Returns a reference to the Maxwell3D GPU engine.
- const Engines::Maxwell3D& Get3DEngine() const;
+ Engines::Maxwell3D& Maxwell3D();
std::unique_ptr<MemoryManager> memory_manager;
- Engines::Maxwell3D& Maxwell3D() {
- return *maxwell_3d;
- }
-
private:
/// Writes a single register in the engine bound to the specified subchannel
void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index f75999557..65a2fd5e8 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -634,8 +634,8 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program,
u32 current_bindpoint,
const std::vector<GLShader::ConstBufferEntry>& entries) {
- auto& gpu = Core::System::GetInstance().GPU();
- auto& maxwell3d = gpu.Get3DEngine();
+ const auto& gpu = Core::System::GetInstance().GPU();
+ const auto& maxwell3d = gpu.Maxwell3D();
// Reset all buffer draw state for this stage.
for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) {
@@ -644,7 +644,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
}
// Upload only the enabled buffers from the 16 constbuffers of each shader stage
- auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
+ const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
const auto& used_buffer = entries[bindpoint];
@@ -700,8 +700,8 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit,
const std::vector<GLShader::SamplerEntry>& entries) {
- auto& gpu = Core::System::GetInstance().GPU();
- auto& maxwell3d = gpu.Get3DEngine();
+ const auto& gpu = Core::System::GetInstance().GPU();
+ const auto& maxwell3d = gpu.Maxwell3D();
ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units),
"Exceeded the number of active textures.");
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 1aa437f76..e81fcbbc4 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -10,8 +10,9 @@
namespace GLShader {
namespace Impl {
-void SetShaderUniformBlockBinding(GLuint shader, const char* name,
- Maxwell3D::Regs::ShaderStage binding, size_t expected_size) {
+static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
+ Maxwell3D::Regs::ShaderStage binding,
+ size_t expected_size) {
GLuint ub_index = glGetUniformBlockIndex(shader, name);
if (ub_index != GL_INVALID_INDEX) {
GLint ub_size = 0;
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 4295c20a6..e29d551e1 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -21,7 +21,6 @@ using Tegra::Engines::Maxwell3D;
namespace Impl {
void SetShaderUniformBlockBindings(GLuint shader);
-void SetShaderSamplerBindings(GLuint shader);
} // namespace Impl
/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 62754a1a9..98969fe10 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -10,7 +10,7 @@
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
- qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini";
+ qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini";
FileUtil::CreateFullPath(qt_config_loc);
qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 241db4ae3..5e66239ff 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -19,7 +19,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::Co
ui->setupUi(this);
this->setConfiguration();
connect(ui->open_log_button, &QPushButton::pressed, []() {
- QString path = QString::fromStdString(FileUtil::GetUserPath(D_LOGS_IDX));
+ QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
}
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 1fbca8ad0..c41ff693b 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -336,9 +336,9 @@ void GraphicsSurfaceWidget::OnUpdate() {
// TODO: Store a reference to the registers in the debug context instead of accessing them
// directly...
- auto& registers = gpu.Get3DEngine().regs;
- auto& rt = registers.rt[static_cast<size_t>(surface_source) -
- static_cast<size_t>(Source::RenderTarget0)];
+ const auto& registers = gpu.Maxwell3D().regs;
+ const auto& rt = registers.rt[static_cast<size_t>(surface_source) -
+ static_cast<size_t>(Source::RenderTarget0)];
surface_address = rt.Address();
surface_width = rt.width;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 16812e077..16a95bb19 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -909,6 +909,16 @@ void GMainWindow::UpdateUITheme() {
#undef main
#endif
+static void InitializeLogging() {
+ Log::Filter log_filter;
+ log_filter.ParseFilterString(Settings::values.log_filter);
+ Log::SetGlobalFilter(log_filter);
+
+ const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
+ FileUtil::CreateFullPath(log_dir);
+ Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
+}
+
int main(int argc, char* argv[]) {
MicroProfileOnThreadCreate("Frontend");
SCOPE_EXIT({ MicroProfileShutdown(); });
@@ -927,13 +937,7 @@ int main(int argc, char* argv[]) {
GMainWindow main_window;
// After settings have been loaded by GMainWindow, apply the filter
- Log::Filter log_filter;
- log_filter.ParseFilterString(Settings::values.log_filter);
- Log::SetGlobalFilter(log_filter);
- FileUtil::CreateFullPath(FileUtil::GetUserPath(D_LOGS_IDX));
- Log::AddBackend(
- std::make_unique<Log::FileBackend>(FileUtil::GetUserPath(D_LOGS_IDX) + LOG_FILE));
-
+ InitializeLogging();
main_window.show();
return app.exec();
}
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 723e8b4cc..cea1a5e62 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -15,7 +15,7 @@
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
- sdl2_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "sdl2-config.ini";
+ sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "sdl2-config.ini";
sdl2_config = std::make_unique<INIReader>(sdl2_config_loc);
Reload();
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 24db1065a..b5392c499 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -56,6 +56,18 @@ static void PrintVersion() {
std::cout << "yuzu " << Common::g_scm_branch << " " << Common::g_scm_desc << std::endl;
}
+static void InitializeLogging() {
+ Log::Filter log_filter(Log::Level::Debug);
+ log_filter.ParseFilterString(Settings::values.log_filter);
+ Log::SetGlobalFilter(log_filter);
+
+ Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
+
+ const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
+ FileUtil::CreateFullPath(log_dir);
+ Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
+}
+
/// Application entry point
int main(int argc, char** argv) {
Config config;
@@ -124,14 +136,7 @@ int main(int argc, char** argv) {
LocalFree(argv_w);
#endif
- Log::Filter log_filter(Log::Level::Debug);
- log_filter.ParseFilterString(Settings::values.log_filter);
- Log::SetGlobalFilter(log_filter);
-
- Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
- FileUtil::CreateFullPath(FileUtil::GetUserPath(D_LOGS_IDX));
- Log::AddBackend(
- std::make_unique<Log::FileBackend>(FileUtil::GetUserPath(D_LOGS_IDX) + LOG_FILE));
+ InitializeLogging();
MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); });