Compare commits
110 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bab07c367 | ||
|
|
d84d9a64b3 | ||
|
|
07d080ecc8 | ||
|
|
f0125b2be8 | ||
|
|
51546ce57e | ||
|
|
201514cb50 | ||
|
|
a89dfc9183 | ||
|
|
2781201bfb | ||
|
|
9121d35e70 | ||
|
|
0648e023ea | ||
|
|
815f30dc10 | ||
|
|
f66e3181dc | ||
|
|
f26f53f35b | ||
|
|
73bb87c06b | ||
|
|
52e83f0d5c | ||
|
|
4ad69ca96e | ||
|
|
0ca7b8269a | ||
|
|
1bbc61f5f1 | ||
|
|
8794e623d9 | ||
|
|
a82fdea1ac | ||
|
|
263200f982 | ||
|
|
9f027b1af2 | ||
|
|
666b37ad56 | ||
|
|
a683e42516 | ||
|
|
6d1477f214 | ||
|
|
93fe982a0c | ||
|
|
e2730372b8 | ||
|
|
450cbcfee6 | ||
|
|
bf9c010be5 | ||
|
|
ab65de2f96 | ||
|
|
393cdb15f5 | ||
|
|
edb291b3be | ||
|
|
6989fd65f3 | ||
|
|
8160e142e1 | ||
|
|
e02687ff47 | ||
|
|
edb2caaae5 | ||
|
|
b284c43385 | ||
|
|
883fab2fff | ||
|
|
f2f876e3ff | ||
|
|
f1d8c83e1c | ||
|
|
07632ad825 | ||
|
|
b2305dcee0 | ||
|
|
b971b82275 | ||
|
|
84b5804834 | ||
|
|
539675b21a | ||
|
|
8df93132cd | ||
|
|
a1dddca4ab | ||
|
|
839c91cd14 | ||
|
|
a8ba6dc3c9 | ||
|
|
32b6fc4062 | ||
|
|
9ce6ea648f | ||
|
|
a67d00ef31 | ||
|
|
739d90ee66 | ||
|
|
ed89bcc767 | ||
|
|
f1aabc21ee | ||
|
|
80a0f2a118 | ||
|
|
6001538139 | ||
|
|
63cc4e417f | ||
|
|
e60733aad3 | ||
|
|
5fb27f83cf | ||
|
|
f16a94fb39 | ||
|
|
e5abf11186 | ||
|
|
1074c87f18 | ||
|
|
7a051c4973 | ||
|
|
a4306b9e56 | ||
|
|
da11a27f42 | ||
|
|
505aa3a4c1 | ||
|
|
a59ad9246b | ||
|
|
6744e7ea4a | ||
|
|
0193202964 | ||
|
|
fb0fefc75c | ||
|
|
a0ee597b19 | ||
|
|
a45a57641f | ||
|
|
fca26980a2 | ||
|
|
995067538d | ||
|
|
01a1adfb0c | ||
|
|
042c6602a0 | ||
|
|
798c1b457d | ||
|
|
c574ab5aa1 | ||
|
|
d7a2dc4cea | ||
|
|
d39b457566 | ||
|
|
755506d404 | ||
|
|
7351ca8c75 | ||
|
|
75a01475d1 | ||
|
|
6d8d7ebc66 | ||
|
|
7f4d96d873 | ||
|
|
4c269e5ced | ||
|
|
b24b463c87 | ||
|
|
17242a8865 | ||
|
|
0373ead96e | ||
|
|
47e26d7bc7 | ||
|
|
0974533c96 | ||
|
|
df27813e76 | ||
|
|
48aa076049 | ||
|
|
48ff15602e | ||
|
|
4489ea6f53 | ||
|
|
cf76769026 | ||
|
|
2a9d17b7e7 | ||
|
|
b57475887b | ||
|
|
e3253b5f18 | ||
|
|
86abff48e1 | ||
|
|
7ad423923d | ||
|
|
3f910efb40 | ||
|
|
38b585a309 | ||
|
|
b1b1ed7597 | ||
|
|
86946ea13c | ||
|
|
f3630a0713 | ||
|
|
a0c499aef7 | ||
|
|
f2eead3b5b | ||
|
|
6a0010d0c6 |
@@ -118,8 +118,17 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
|
||||
# Configure C++ standard
|
||||
# ===========================
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
# boost asio's concept usage doesn't play nicely with some compilers yet.
|
||||
add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)
|
||||
if (MSVC)
|
||||
add_compile_options(/std:c++latest)
|
||||
|
||||
# cubeb and boost still make use of deprecated result_of.
|
||||
add_definitions(-D_HAS_DEPRECATED_RESULT_OF)
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
# Output binaries to bin/
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
@@ -151,7 +160,7 @@ macro(yuzu_find_packages)
|
||||
# Cmake Pkg Prefix Version Conan Pkg
|
||||
"Boost 1.71 boost/1.72.0"
|
||||
"Catch2 2.11 catch2/2.11.0"
|
||||
"fmt 6.2 fmt/6.2.0"
|
||||
"fmt 7.0 fmt/7.0.1"
|
||||
# can't use until https://github.com/bincrafters/community/issues/1173
|
||||
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
|
||||
"lz4 1.8 lz4/1.9.2"
|
||||
@@ -211,7 +220,7 @@ if(ENABLE_QT)
|
||||
|
||||
set(QT_PREFIX_HINT HINTS "${QT_PREFIX}")
|
||||
endif()
|
||||
find_package(Qt5 5.9 COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
|
||||
find_package(Qt5 5.9 COMPONENTS Widgets ${QT_PREFIX_HINT})
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
find_package(Qt5 COMPONENTS WebEngineCore WebEngineWidgets)
|
||||
endif()
|
||||
@@ -287,7 +296,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 OpenGL)
|
||||
find_package(Qt5 5.9 REQUIRED COMPONENTS Widgets)
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets)
|
||||
endif()
|
||||
@@ -330,13 +339,16 @@ elseif(SDL2_FOUND)
|
||||
endif()
|
||||
|
||||
# Ensure libusb is properly configured (based on dolphin libusb include)
|
||||
find_package(LibUSB)
|
||||
if(NOT APPLE)
|
||||
include(FindPkgConfig)
|
||||
find_package(LibUSB)
|
||||
endif()
|
||||
if (NOT LIBUSB_FOUND)
|
||||
add_subdirectory(externals/libusb)
|
||||
set(LIBUSB_INCLUDE_DIR "")
|
||||
set(LIBUSB_LIBRARIES usb)
|
||||
endif()
|
||||
|
||||
|
||||
# Prefer the -pthread flag on Linux.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
@@ -15,7 +15,6 @@ function(copy_yuzu_Qt5_deps target_dir)
|
||||
icuuc*.dll
|
||||
Qt5Core$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Gui$<$<CONFIG:Debug>:d>.*
|
||||
Qt5OpenGL$<$<CONFIG:Debug>:d>.*
|
||||
Qt5Widgets$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ yuzu emulator
|
||||
=============
|
||||
[](https://travis-ci.com/yuzu-emu/yuzu)
|
||||
[](https://dev.azure.com/yuzu-emu/yuzu/)
|
||||
[](https://discord.gg/XQV6dn9)
|
||||
[](https://discord.com/invite/u77vRWY)
|
||||
|
||||
yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/).
|
||||
|
||||
@@ -16,7 +16,7 @@ yuzu is licensed under the GPLv2 (or any later version). Refer to the license.tx
|
||||
|
||||
Check out our [website](https://yuzu-emu.org/)!
|
||||
|
||||
For development discussion, please join us on [Discord](https://discord.gg/XQV6dn9).
|
||||
For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY).
|
||||
|
||||
### Development
|
||||
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 4f967387c0...82417da780
@@ -11,7 +11,9 @@ namespace Common {
|
||||
template <typename T>
|
||||
constexpr T AlignUp(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return static_cast<T>(value + (size - value % size) % size);
|
||||
auto mod{static_cast<T>(value % size)};
|
||||
value -= mod;
|
||||
return static_cast<T>(mod == T{0} ? value : value + size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -17,43 +17,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
#include <bit>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include "common/common_types.h"
|
||||
|
||||
// GCC
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN)
|
||||
#define COMMON_LITTLE_ENDIAN 1
|
||||
#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN)
|
||||
#define COMMON_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
// LLVM/clang
|
||||
#elif defined(__clang__)
|
||||
|
||||
#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN)
|
||||
#define COMMON_LITTLE_ENDIAN 1
|
||||
#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN)
|
||||
#define COMMON_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
// MSVC
|
||||
#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN)
|
||||
|
||||
#define COMMON_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
// Worst case, default to little endian.
|
||||
#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN
|
||||
#define COMMON_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -675,17 +646,8 @@ struct AddEndian<T, SwapTag> {
|
||||
};
|
||||
|
||||
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
|
||||
#if COMMON_LITTLE_ENDIAN
|
||||
|
||||
using LETag = KeepTag;
|
||||
using BETag = SwapTag;
|
||||
|
||||
#else
|
||||
|
||||
using BETag = KeepTag;
|
||||
using LETag = SwapTag;
|
||||
|
||||
#endif
|
||||
using LETag = std::conditional_t<std::endian::native == std::endian::little, KeepTag, SwapTag>;
|
||||
using BETag = std::conditional_t<std::endian::native == std::endian::big, KeepTag, SwapTag>;
|
||||
|
||||
// Aliases for LE types
|
||||
using u16_le = AddEndian<u16, LETag>::type;
|
||||
|
||||
@@ -142,10 +142,32 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
|
||||
// Timing
|
||||
config.wall_clock_cntpct = uses_wall_clock;
|
||||
|
||||
// Optimizations
|
||||
if (Settings::values.disable_cpu_opt) {
|
||||
config.enable_optimizations = false;
|
||||
config.enable_fast_dispatch = false;
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
if (!Settings::values.cpuopt_block_linking) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
|
||||
}
|
||||
if (!Settings::values.cpuopt_return_stack_buffer) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer;
|
||||
}
|
||||
if (!Settings::values.cpuopt_fast_dispatcher) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch;
|
||||
}
|
||||
if (!Settings::values.cpuopt_context_elimination) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination;
|
||||
}
|
||||
if (!Settings::values.cpuopt_const_prop) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp;
|
||||
}
|
||||
if (!Settings::values.cpuopt_misc_ir) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt;
|
||||
}
|
||||
if (!Settings::values.cpuopt_reduce_misalign_checks) {
|
||||
config.only_detect_misalignment_via_page_table_on_page_boundary = false;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||
|
||||
@@ -191,15 +191,37 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
|
||||
// Unpredictable instructions
|
||||
config.define_unpredictable_behaviour = true;
|
||||
|
||||
// Optimizations
|
||||
if (Settings::values.disable_cpu_opt) {
|
||||
config.enable_optimizations = false;
|
||||
config.enable_fast_dispatch = false;
|
||||
}
|
||||
|
||||
// Timing
|
||||
config.wall_clock_cntpct = uses_wall_clock;
|
||||
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
if (!Settings::values.cpuopt_block_linking) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
|
||||
}
|
||||
if (!Settings::values.cpuopt_return_stack_buffer) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer;
|
||||
}
|
||||
if (!Settings::values.cpuopt_fast_dispatcher) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch;
|
||||
}
|
||||
if (!Settings::values.cpuopt_context_elimination) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination;
|
||||
}
|
||||
if (!Settings::values.cpuopt_const_prop) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp;
|
||||
}
|
||||
if (!Settings::values.cpuopt_misc_ir) {
|
||||
config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt;
|
||||
}
|
||||
if (!Settings::values.cpuopt_reduce_misalign_checks) {
|
||||
config.only_detect_misalignment_via_page_table_on_page_boundary = false;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<Dynarmic::A64::Jit>(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include "common/fiber.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Common {
|
||||
@@ -46,9 +49,9 @@ public:
|
||||
|
||||
void Pause(bool paused);
|
||||
|
||||
std::function<void(void*)> GetGuestThreadStartFunc();
|
||||
std::function<void(void*)> GetIdleThreadStartFunc();
|
||||
std::function<void(void*)> GetSuspendThreadStartFunc();
|
||||
static std::function<void(void*)> GetGuestThreadStartFunc();
|
||||
static std::function<void(void*)> GetIdleThreadStartFunc();
|
||||
static std::function<void(void*)> GetSuspendThreadStartFunc();
|
||||
void* GetStartFuncParamater();
|
||||
|
||||
void PreemptSingleCore(bool from_running_enviroment = true);
|
||||
@@ -97,7 +100,6 @@ private:
|
||||
bool is_async_gpu{};
|
||||
bool is_multicore{};
|
||||
std::atomic<std::size_t> current_core{};
|
||||
std::size_t preemption_count{};
|
||||
std::size_t idle_count{};
|
||||
static constexpr std::size_t max_cycle_runs = 5;
|
||||
|
||||
|
||||
@@ -695,8 +695,9 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
|
||||
}
|
||||
|
||||
void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
if (s128_keys.find({id, field1, field2}) != s128_keys.end())
|
||||
if (s128_keys.find({id, field1, field2}) != s128_keys.end() || key == Key128{}) {
|
||||
return;
|
||||
}
|
||||
if (id == S128KeyType::Titlekey) {
|
||||
Key128 rights_id;
|
||||
std::memcpy(rights_id.data(), &field2, sizeof(u64));
|
||||
@@ -716,8 +717,9 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
|
||||
std::tie(id, field1, field2);
|
||||
});
|
||||
if (iter2 != s128_file_id.end())
|
||||
if (iter2 != s128_file_id.end()) {
|
||||
WriteKeyToFile(category, iter2->first, key);
|
||||
}
|
||||
|
||||
// Variable cases
|
||||
if (id == S128KeyType::KeyArea) {
|
||||
@@ -745,16 +747,18 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
}
|
||||
|
||||
void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
|
||||
if (s256_keys.find({id, field1, field2}) != s256_keys.end())
|
||||
if (s256_keys.find({id, field1, field2}) != s256_keys.end() || key == Key256{}) {
|
||||
return;
|
||||
}
|
||||
const auto iter = std::find_if(
|
||||
s256_file_id.begin(), s256_file_id.end(),
|
||||
[&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) {
|
||||
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
|
||||
std::tie(id, field1, field2);
|
||||
});
|
||||
if (iter != s256_file_id.end())
|
||||
if (iter != s256_file_id.end()) {
|
||||
WriteKeyToFile(KeyCategory::Standard, iter->first, key);
|
||||
}
|
||||
s256_keys[{id, field1, field2}] = key;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB
|
||||
constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB
|
||||
constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB
|
||||
|
||||
BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
|
||||
: nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
|
||||
dump_root(std::move(dump_root_)),
|
||||
@@ -110,30 +114,29 @@ VirtualDir BISFactory::GetImageDirectory() const {
|
||||
|
||||
u64 BISFactory::GetSystemNANDFreeSpace() const {
|
||||
const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
|
||||
if (sys_dir == nullptr)
|
||||
return 0;
|
||||
if (sys_dir == nullptr) {
|
||||
return GetSystemNANDTotalSpace();
|
||||
}
|
||||
|
||||
return GetSystemNANDTotalSpace() - sys_dir->GetSize();
|
||||
}
|
||||
|
||||
u64 BISFactory::GetSystemNANDTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.nand_system_size);
|
||||
return NAND_SYSTEM_SIZE;
|
||||
}
|
||||
|
||||
u64 BISFactory::GetUserNANDFreeSpace() const {
|
||||
const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user");
|
||||
if (usr_dir == nullptr)
|
||||
return 0;
|
||||
|
||||
return GetUserNANDTotalSpace() - usr_dir->GetSize();
|
||||
// For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes.
|
||||
// Set the free space to be 1 MiB less than the total as a workaround to this issue.
|
||||
return GetUserNANDTotalSpace() - 0x100000;
|
||||
}
|
||||
|
||||
u64 BISFactory::GetUserNANDTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.nand_user_size);
|
||||
return NAND_USER_SIZE;
|
||||
}
|
||||
|
||||
u64 BISFactory::GetFullNANDTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.nand_total_size);
|
||||
return NAND_TOTAL_SIZE;
|
||||
}
|
||||
|
||||
VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const {
|
||||
|
||||
@@ -547,6 +547,56 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex
|
||||
return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
|
||||
}
|
||||
|
||||
bool RegisteredCache::RemoveExistingEntry(u64 title_id) {
|
||||
const auto delete_nca = [this](const NcaID& id) {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
|
||||
if (dir->GetFileRelative(path) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
|
||||
const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
// If an entry exists in the registered cache, remove it
|
||||
if (HasEntry(title_id, ContentRecordType::Meta)) {
|
||||
LOG_INFO(Loader,
|
||||
"Previously installed entry (v{}) for title_id={:016X} detected! "
|
||||
"Attempting to remove...",
|
||||
GetEntryVersion(title_id).value_or(0), title_id);
|
||||
// Get all the ncas associated with the current CNMT and delete them
|
||||
const auto meta_old_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
|
||||
const auto program_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
|
||||
const auto data_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
|
||||
const auto control_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
|
||||
const auto html_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
|
||||
const auto legal_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
|
||||
|
||||
delete_nca(meta_old_id);
|
||||
delete_nca(program_id);
|
||||
delete_nca(data_id);
|
||||
delete_nca(control_id);
|
||||
delete_nca(html_id);
|
||||
delete_nca(legal_id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
|
||||
const VfsCopyFunction& copy) {
|
||||
const auto ncas = nsp.GetNCAsCollapsed();
|
||||
@@ -560,31 +610,57 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
|
||||
return InstallResult::ErrorMetaFailed;
|
||||
}
|
||||
|
||||
// Install Metadata File
|
||||
const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
|
||||
const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
|
||||
|
||||
const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
|
||||
if (res != InstallResult::Success)
|
||||
return res;
|
||||
if ((*meta_iter)->GetSubdirectories().empty()) {
|
||||
LOG_ERROR(Loader,
|
||||
"The file you are attempting to install does not contain a section0 within the "
|
||||
"metadata NCA and is therefore malformed. Verify that the file is valid.");
|
||||
return InstallResult::ErrorMetaFailed;
|
||||
}
|
||||
|
||||
// Install all the other NCAs
|
||||
const auto section0 = (*meta_iter)->GetSubdirectories()[0];
|
||||
|
||||
if (section0->GetFiles().empty()) {
|
||||
LOG_ERROR(Loader,
|
||||
"The file you are attempting to install does not contain a CNMT within the "
|
||||
"metadata NCA and is therefore malformed. Verify that the file is valid.");
|
||||
return InstallResult::ErrorMetaFailed;
|
||||
}
|
||||
|
||||
const auto cnmt_file = section0->GetFiles()[0];
|
||||
const CNMT cnmt(cnmt_file);
|
||||
|
||||
const auto title_id = cnmt.GetTitleID();
|
||||
const auto result = RemoveExistingEntry(title_id);
|
||||
|
||||
// Install Metadata File
|
||||
const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
|
||||
if (res != InstallResult::Success) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Install all the other NCAs
|
||||
for (const auto& record : cnmt.GetContentRecords()) {
|
||||
// Ignore DeltaFragments, they are not useful to us
|
||||
if (record.type == ContentRecordType::DeltaFragment)
|
||||
if (record.type == ContentRecordType::DeltaFragment) {
|
||||
continue;
|
||||
}
|
||||
const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);
|
||||
if (nca == nullptr)
|
||||
if (nca == nullptr) {
|
||||
return InstallResult::ErrorCopyFailed;
|
||||
}
|
||||
const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
|
||||
if (res2 != InstallResult::Success)
|
||||
if (res2 != InstallResult::Success) {
|
||||
return res2;
|
||||
}
|
||||
}
|
||||
|
||||
Refresh();
|
||||
if (result) {
|
||||
return InstallResult::OverwriteExisting;
|
||||
}
|
||||
return InstallResult::Success;
|
||||
}
|
||||
|
||||
@@ -610,8 +686,9 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
|
||||
mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0);
|
||||
memcpy(&c_rec.nca_id, &c_rec.hash, 16);
|
||||
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
|
||||
if (!RawInstallYuzuMeta(new_cnmt))
|
||||
if (!RawInstallYuzuMeta(new_cnmt)) {
|
||||
return InstallResult::ErrorMetaFailed;
|
||||
}
|
||||
return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
|
||||
}
|
||||
|
||||
@@ -649,8 +726,9 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
|
||||
}
|
||||
|
||||
auto out = dir->CreateFileRelative(path);
|
||||
if (out == nullptr)
|
||||
if (out == nullptr) {
|
||||
return InstallResult::ErrorCopyFailed;
|
||||
}
|
||||
return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success
|
||||
: InstallResult::ErrorCopyFailed;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile
|
||||
|
||||
enum class InstallResult {
|
||||
Success,
|
||||
OverwriteExisting,
|
||||
ErrorAlreadyExists,
|
||||
ErrorCopyFailed,
|
||||
ErrorMetaFailed,
|
||||
@@ -154,6 +155,9 @@ public:
|
||||
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
|
||||
std::optional<u64> title_id = {}) const override;
|
||||
|
||||
// Removes an existing entry based on title id
|
||||
bool RemoveExistingEntry(u64 title_id);
|
||||
|
||||
// Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
|
||||
// there is a meta NCA and all of them are accessible.
|
||||
InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB
|
||||
|
||||
SDMCFactory::SDMCFactory(VirtualDir dir_)
|
||||
: dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>(
|
||||
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
|
||||
@@ -46,7 +48,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const {
|
||||
}
|
||||
|
||||
u64 SDMCFactory::GetSDMCTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.sdmc_size);
|
||||
return SDMC_TOTAL_SIZE;
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -112,19 +112,26 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
|
||||
return nullptr;
|
||||
|
||||
if (cache.find(old_path) != cache.end()) {
|
||||
auto cached = cache[old_path];
|
||||
if (!cached.expired()) {
|
||||
auto file = cached.lock();
|
||||
file->Open(new_path, "r+b");
|
||||
cache.erase(old_path);
|
||||
cache[new_path] = file;
|
||||
auto file = cache[old_path].lock();
|
||||
|
||||
if (!cache[old_path].expired()) {
|
||||
file->Close();
|
||||
}
|
||||
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cache.erase(old_path);
|
||||
file->Open(new_path, "r+b");
|
||||
cache[new_path] = file;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return OpenFile(new_path, Mode::ReadWrite);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace Kernel {
|
||||
// Wake up num_to_wake (or all) threads in a vector.
|
||||
void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads,
|
||||
s32 num_to_wake) {
|
||||
auto& time_manager = system.Kernel().TimeManager();
|
||||
// Only process up to 'target' threads, unless 'target' is <= 0, in which case process
|
||||
// them all.
|
||||
std::size_t last = waiting_threads.size();
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/scheduler.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
@@ -22,7 +24,7 @@ constexpr u16 GetGeneration(Handle handle) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
HandleTable::HandleTable() {
|
||||
HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} {
|
||||
Clear();
|
||||
}
|
||||
|
||||
@@ -103,9 +105,9 @@ bool HandleTable::IsValid(Handle handle) const {
|
||||
|
||||
std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
|
||||
if (handle == CurrentThread) {
|
||||
return SharedFrom(GetCurrentThread());
|
||||
return SharedFrom(kernel.CurrentScheduler().GetCurrentThread());
|
||||
} else if (handle == CurrentProcess) {
|
||||
return SharedFrom(Core::System::GetInstance().CurrentProcess());
|
||||
return SharedFrom(kernel.CurrentProcess());
|
||||
}
|
||||
|
||||
if (!IsValid(handle)) {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KernelCore;
|
||||
|
||||
enum KernelHandle : Handle {
|
||||
InvalidHandle = 0,
|
||||
CurrentThread = 0xFFFF8000,
|
||||
@@ -48,7 +50,7 @@ public:
|
||||
/// This is the maximum limit of handles allowed per process in Horizon
|
||||
static constexpr std::size_t MAX_COUNT = 1024;
|
||||
|
||||
HandleTable();
|
||||
explicit HandleTable(KernelCore& kernel);
|
||||
~HandleTable();
|
||||
|
||||
/**
|
||||
@@ -134,6 +136,9 @@ private:
|
||||
|
||||
/// Head of the free slots linked list.
|
||||
u16 next_free_slot = 0;
|
||||
|
||||
/// Underlying kernel instance that this handle table operates under.
|
||||
KernelCore& kernel;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -50,7 +50,8 @@ namespace Kernel {
|
||||
|
||||
struct KernelCore::Impl {
|
||||
explicit Impl(Core::System& system, KernelCore& kernel)
|
||||
: global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {}
|
||||
: global_scheduler{kernel}, synchronization{system}, time_manager{system},
|
||||
global_handle_table{kernel}, system{system} {}
|
||||
|
||||
void SetMulticore(bool is_multicore) {
|
||||
this->is_multicore = is_multicore;
|
||||
@@ -160,13 +161,14 @@ struct KernelCore::Impl {
|
||||
void InitializeSuspendThreads() {
|
||||
for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
std::string name = "Suspend Thread Id:" + std::to_string(i);
|
||||
std::function<void(void*)> init_func =
|
||||
system.GetCpuManager().GetSuspendThreadStartFunc();
|
||||
std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
|
||||
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
|
||||
ThreadType type =
|
||||
const auto type =
|
||||
static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND);
|
||||
auto thread_res = Thread::Create(system, type, name, 0, 0, 0, static_cast<u32>(i), 0,
|
||||
nullptr, std::move(init_func), init_func_parameter);
|
||||
auto thread_res =
|
||||
Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
|
||||
nullptr, std::move(init_func), init_func_parameter);
|
||||
|
||||
suspend_threads[i] = std::move(thread_res).Unwrap();
|
||||
}
|
||||
}
|
||||
@@ -307,7 +309,7 @@ struct KernelCore::Impl {
|
||||
|
||||
// This is the kernel's handle table or supervisor handle table which
|
||||
// stores all the objects in place.
|
||||
Kernel::HandleTable global_handle_table;
|
||||
HandleTable global_handle_table;
|
||||
|
||||
/// Map of named ports managed by the kernel, which can be retrieved using
|
||||
/// the ConnectToPort SVC.
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "core/arm/cpu_interrupt_handler.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/memory/memory_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
@@ -66,8 +66,6 @@ private:
|
||||
const MemoryRegion application;
|
||||
const MemoryRegion applet;
|
||||
const MemoryRegion system;
|
||||
|
||||
const PAddr start_address{};
|
||||
};
|
||||
|
||||
} // namespace Kernel::Memory
|
||||
|
||||
@@ -408,7 +408,7 @@ void Process::LoadModule(CodeSet code_set, VAddr base_addr) {
|
||||
Process::Process(Core::System& system)
|
||||
: SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>(
|
||||
system)},
|
||||
address_arbiter{system}, mutex{system}, system{system} {}
|
||||
handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {}
|
||||
|
||||
Process::~Process() = default;
|
||||
|
||||
|
||||
@@ -382,12 +382,6 @@ private:
|
||||
/// List of threads waiting for a condition variable
|
||||
std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads;
|
||||
|
||||
/// System context
|
||||
Core::System& system;
|
||||
|
||||
/// Name of this process
|
||||
std::string name;
|
||||
|
||||
/// Address of the top of the main thread's stack
|
||||
VAddr main_thread_stack_top{};
|
||||
|
||||
@@ -399,6 +393,12 @@ private:
|
||||
|
||||
/// Process total image size
|
||||
std::size_t image_size{};
|
||||
|
||||
/// Name of this process
|
||||
std::string name;
|
||||
|
||||
/// System context
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -802,7 +802,7 @@ void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
|
||||
|
||||
void Scheduler::Initialize() {
|
||||
std::string name = "Idle Thread Id:" + std::to_string(core_id);
|
||||
std::function<void(void*)> init_func = system.GetCpuManager().GetIdleThreadStartFunc();
|
||||
std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
|
||||
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
|
||||
ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE);
|
||||
auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0,
|
||||
|
||||
@@ -458,9 +458,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
|
||||
return ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
auto* const thread = system.CurrentScheduler().GetCurrentThread();
|
||||
auto& kernel = system.Kernel();
|
||||
using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type;
|
||||
Thread::ThreadSynchronizationObjects objects(handle_count);
|
||||
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||
|
||||
@@ -1750,9 +1748,9 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
||||
// Only process up to 'target' threads, unless 'target' is less equal 0, in which case process
|
||||
// them all.
|
||||
std::size_t last = waiting_threads.size();
|
||||
if (target > 0)
|
||||
if (target > 0) {
|
||||
last = std::min(waiting_threads.size(), static_cast<std::size_t>(target));
|
||||
auto& time_manager = kernel.TimeManager();
|
||||
}
|
||||
for (std::size_t index = 0; index < last; ++index) {
|
||||
auto& thread = waiting_threads[index];
|
||||
|
||||
@@ -1763,7 +1761,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
||||
|
||||
const std::size_t current_core = system.CurrentCoreIndex();
|
||||
auto& monitor = system.Monitor();
|
||||
auto& memory = system.Memory();
|
||||
|
||||
// Atomically read the value of the mutex.
|
||||
u32 mutex_val = 0;
|
||||
|
||||
@@ -19,7 +19,6 @@ Synchronization::Synchronization(Core::System& system) : system{system} {}
|
||||
void Synchronization::SignalObject(SynchronizationObject& obj) const {
|
||||
auto& kernel = system.Kernel();
|
||||
SchedulerLock lock(kernel);
|
||||
auto& time_manager = kernel.TimeManager();
|
||||
if (obj.IsSignaled()) {
|
||||
for (auto thread : obj.GetWaitingThreads()) {
|
||||
if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
|
||||
|
||||
@@ -13,16 +13,8 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/thread_queue_list.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#endif
|
||||
#include "core/arm/cpu_interrupt_handler.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/cpu_manager.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
@@ -36,6 +28,11 @@
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#endif
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
bool Thread::ShouldWait(const Thread* thread) const {
|
||||
@@ -158,7 +155,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
|
||||
std::string name, VAddr entry_point, u32 priority,
|
||||
u64 arg, s32 processor_id, VAddr stack_top,
|
||||
Process* owner_process) {
|
||||
std::function<void(void*)> init_func = system.GetCpuManager().GetGuestThreadStartFunc();
|
||||
std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
|
||||
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
|
||||
return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top,
|
||||
owner_process, std::move(init_func), init_func_parameter);
|
||||
@@ -540,13 +537,4 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Gets the current thread
|
||||
*/
|
||||
Thread* GetCurrentThread() {
|
||||
return Core::System::GetInstance().CurrentScheduler().GetCurrentThread();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -680,9 +680,4 @@ private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the current thread
|
||||
*/
|
||||
Thread* GetCurrentThread();
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -1407,7 +1407,19 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
|
||||
u32 supported_languages = 0;
|
||||
FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
|
||||
|
||||
const auto res = pm.GetControlMetadata();
|
||||
const auto res = [this] {
|
||||
const auto title_id = system.CurrentProcess()->GetTitleID();
|
||||
|
||||
FileSys::PatchManager pm{title_id};
|
||||
auto res = pm.GetControlMetadata();
|
||||
if (res.first != nullptr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)};
|
||||
return pm_update.GetControlMetadata();
|
||||
}();
|
||||
|
||||
if (res.first != nullptr) {
|
||||
supported_languages = res.first->GetSupportedLanguages();
|
||||
}
|
||||
|
||||
@@ -121,11 +121,83 @@ public:
|
||||
{39, nullptr, "PrepareShutdown"},
|
||||
{40, nullptr, "ListApplyDeltaTask"},
|
||||
{41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
|
||||
{42, nullptr, "Unknown1"},
|
||||
{43, nullptr, "Unknown2"},
|
||||
{44, nullptr, "Unknown3"},
|
||||
{45, nullptr, "Unknown4"},
|
||||
{46, nullptr, "Unknown5"},
|
||||
{42, nullptr, "Unknown42"},
|
||||
{43, nullptr, "Unknown43"},
|
||||
{44, nullptr, "Unknown44"},
|
||||
{45, nullptr, "Unknown45"},
|
||||
{46, nullptr, "Unknown46"},
|
||||
{47, nullptr, "Unknown47"},
|
||||
{48, nullptr, "Unknown48"},
|
||||
{49, nullptr, "Unknown49"},
|
||||
{50, nullptr, "Unknown50"},
|
||||
{51, nullptr, "Unknown51"},
|
||||
{52, nullptr, "Unknown52"},
|
||||
{53, nullptr, "Unknown53"},
|
||||
{54, nullptr, "Unknown54"},
|
||||
{55, nullptr, "Unknown55"},
|
||||
{56, nullptr, "Unknown56"},
|
||||
{57, nullptr, "Unknown57"},
|
||||
{58, nullptr, "Unknown58"},
|
||||
{59, nullptr, "Unknown59"},
|
||||
{60, nullptr, "Unknown60"},
|
||||
{61, nullptr, "Unknown61"},
|
||||
{62, nullptr, "Unknown62"},
|
||||
{63, nullptr, "Unknown63"},
|
||||
{64, nullptr, "Unknown64"},
|
||||
{65, nullptr, "Unknown65"},
|
||||
{66, nullptr, "Unknown66"},
|
||||
{67, nullptr, "Unknown67"},
|
||||
{68, nullptr, "Unknown68"},
|
||||
{69, nullptr, "Unknown69"},
|
||||
{70, nullptr, "Unknown70"},
|
||||
{71, nullptr, "Unknown71"},
|
||||
{72, nullptr, "Unknown72"},
|
||||
{73, nullptr, "Unknown73"},
|
||||
{74, nullptr, "Unknown74"},
|
||||
{75, nullptr, "Unknown75"},
|
||||
{76, nullptr, "Unknown76"},
|
||||
{77, nullptr, "Unknown77"},
|
||||
{78, nullptr, "Unknown78"},
|
||||
{79, nullptr, "Unknown79"},
|
||||
{80, nullptr, "Unknown80"},
|
||||
{81, nullptr, "Unknown81"},
|
||||
{82, nullptr, "Unknown82"},
|
||||
{83, nullptr, "Unknown83"},
|
||||
{84, nullptr, "Unknown84"},
|
||||
{85, nullptr, "Unknown85"},
|
||||
{86, nullptr, "Unknown86"},
|
||||
{87, nullptr, "Unknown87"},
|
||||
{88, nullptr, "Unknown88"},
|
||||
{89, nullptr, "Unknown89"},
|
||||
{90, nullptr, "Unknown90"},
|
||||
{91, nullptr, "Unknown91"},
|
||||
{92, nullptr, "Unknown92"},
|
||||
{93, nullptr, "Unknown93"},
|
||||
{94, nullptr, "Unknown94"},
|
||||
{95, nullptr, "Unknown95"},
|
||||
{96, nullptr, "Unknown96"},
|
||||
{97, nullptr, "Unknown97"},
|
||||
{98, nullptr, "Unknown98"},
|
||||
{99, nullptr, "Unknown99"},
|
||||
{100, nullptr, "Unknown100"},
|
||||
{101, nullptr, "Unknown101"},
|
||||
{102, nullptr, "Unknown102"},
|
||||
{103, nullptr, "Unknown103"},
|
||||
{104, nullptr, "Unknown104"},
|
||||
{105, nullptr, "Unknown105"},
|
||||
{106, nullptr, "Unknown106"},
|
||||
{107, nullptr, "Unknown107"},
|
||||
{108, nullptr, "Unknown108"},
|
||||
{109, nullptr, "Unknown109"},
|
||||
{110, nullptr, "Unknown110"},
|
||||
{111, nullptr, "Unknown111"},
|
||||
{112, nullptr, "Unknown112"},
|
||||
{113, nullptr, "Unknown113"},
|
||||
{114, nullptr, "Unknown114"},
|
||||
{115, nullptr, "Unknown115"},
|
||||
{116, nullptr, "Unknown116"},
|
||||
{117, nullptr, "Unknown117"},
|
||||
{118, nullptr, "Unknown118"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -142,6 +214,7 @@ public:
|
||||
{1, nullptr, "RefreshDebugAvailability"},
|
||||
{2, nullptr, "ClearDebugResponse"},
|
||||
{3, nullptr, "RegisterDebugResponse"},
|
||||
{4, nullptr, "IsLargeResourceAvailable"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -164,6 +237,8 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "RequestDeviceAuthenticationToken"},
|
||||
{1, nullptr, "RequestCachedDeviceAuthenticationToken"},
|
||||
{2, nullptr, "RequestEdgeToken"},
|
||||
{3, nullptr, "RequestCachedEdgeToken"},
|
||||
{100, nullptr, "RequestRegisterDeviceAccount"},
|
||||
{101, nullptr, "RequestUnregisterDeviceAccount"},
|
||||
{102, nullptr, "RequestDeviceAccountStatus"},
|
||||
@@ -181,7 +256,8 @@ public:
|
||||
{305, nullptr, "RequestCreateVirtualAccount"},
|
||||
{306, nullptr, "RequestDeviceLinkStatus"},
|
||||
{400, nullptr, "GetAccountByVirtualAccount"},
|
||||
{500, nullptr, "RequestSyncTicket"},
|
||||
{401, nullptr, "GetVirtualAccount"},
|
||||
{500, nullptr, "RequestSyncTicketLegacy"},
|
||||
{501, nullptr, "RequestDownloadTicket"},
|
||||
{502, nullptr, "RequestDownloadTicketForPrepurchasedContents"},
|
||||
{503, nullptr, "RequestSyncTicket"},
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
{23, nullptr, "DestroyToken"},
|
||||
{24, nullptr, "DestroyTokenWithApplicationId"},
|
||||
{25, nullptr, "QueryIsTokenValid"},
|
||||
{26, nullptr, "ListenToMyApplicationId"},
|
||||
{31, nullptr, "UploadTokenToBaaS"},
|
||||
{32, nullptr, "DestroyTokenForBaaS"},
|
||||
{33, nullptr, "CreateTokenForBaaS"},
|
||||
|
||||
@@ -104,7 +104,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
|
||||
{94, nullptr, "LaunchApplication"},
|
||||
{95, nullptr, "GetApplicationLaunchInfo"},
|
||||
{96, nullptr, "AcquireApplicationLaunchInfo"},
|
||||
{97, nullptr, "GetMainApplicationProgramIndex2"},
|
||||
{97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"},
|
||||
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
{99, nullptr, "LaunchDevMenu"},
|
||||
{100, nullptr, "ResetToFactorySettings"},
|
||||
@@ -254,7 +254,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
|
||||
{2170, nullptr, "GetRightsEnvironmentStatus"},
|
||||
{2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
|
||||
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
|
||||
{2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"},
|
||||
{2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
|
||||
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
|
||||
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
|
||||
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
|
||||
@@ -446,8 +446,8 @@ IApplicationVersionInterface::IApplicationVersionInterface()
|
||||
|
||||
IApplicationVersionInterface::~IApplicationVersionInterface() = default;
|
||||
|
||||
IContentManagerInterface::IContentManagerInterface()
|
||||
: ServiceFramework{"IContentManagerInterface"} {
|
||||
IContentManagementInterface::IContentManagementInterface()
|
||||
: ServiceFramework{"IContentManagementInterface"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{11, nullptr, "CalculateApplicationOccupiedSize"},
|
||||
@@ -464,7 +464,7 @@ IContentManagerInterface::IContentManagerInterface()
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IContentManagerInterface::~IContentManagerInterface() = default;
|
||||
IContentManagementInterface::~IContentManagementInterface() = default;
|
||||
|
||||
IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
|
||||
// clang-format off
|
||||
@@ -546,7 +546,7 @@ NS::NS(const char* name) : ServiceFramework{name} {
|
||||
{7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
|
||||
{7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
|
||||
{7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
|
||||
{7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
|
||||
{7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"},
|
||||
{7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -573,9 +573,9 @@ public:
|
||||
{6, nullptr, "TerminateApplication"},
|
||||
{7, nullptr, "PrepareLaunchProgramFromHost"},
|
||||
{8, nullptr, "LaunchApplication"},
|
||||
{9, nullptr, "LaunchApplicationWithStorageId"},
|
||||
{10, nullptr, "TerminateApplication2"},
|
||||
{11, nullptr, "GetRunningApplicationProcessId"},
|
||||
{9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
|
||||
{10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
|
||||
{11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
|
||||
{12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"},
|
||||
{13, nullptr, "CreateApplicationResourceForDevelop"},
|
||||
{14, nullptr, "IsPreomiaForDevelop"},
|
||||
@@ -637,6 +637,10 @@ public:
|
||||
{9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"},
|
||||
{10, nullptr, "NotifySystemUpdateForContentDelivery"},
|
||||
{11, nullptr, "PrepareShutdown"},
|
||||
{12, nullptr, "Unknown12"},
|
||||
{13, nullptr, "Unknown13"},
|
||||
{14, nullptr, "Unknown14"},
|
||||
{15, nullptr, "Unknown15"},
|
||||
{16, nullptr, "DestroySystemUpdateTask"},
|
||||
{17, nullptr, "RequestSendSystemUpdate"},
|
||||
{18, nullptr, "GetSendSystemUpdateProgress"},
|
||||
|
||||
@@ -40,10 +40,10 @@ public:
|
||||
~IApplicationVersionInterface() override;
|
||||
};
|
||||
|
||||
class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
|
||||
class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> {
|
||||
public:
|
||||
explicit IContentManagerInterface();
|
||||
~IContentManagerInterface() override;
|
||||
explicit IContentManagementInterface();
|
||||
~IContentManagementInterface() override;
|
||||
};
|
||||
|
||||
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
|
||||
|
||||
@@ -163,7 +163,7 @@ PL_U::PL_U(Core::System& system)
|
||||
{5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
|
||||
{6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"},
|
||||
{100, nullptr, "RequestApplicationFunctionAuthorization"},
|
||||
{101, nullptr, "RequestApplicationFunctionAuthorizationForSystem"},
|
||||
{101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
|
||||
{102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
|
||||
{1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
|
||||
{1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"},
|
||||
|
||||
@@ -144,7 +144,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
|
||||
void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
pid = rp.Pop<u64>();
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
|
||||
@@ -154,7 +154,7 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) {
|
||||
void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -187,13 +187,14 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
{4, &NVDRV::QueryEvent, "QueryEvent"},
|
||||
{5, nullptr, "MapSharedMem"},
|
||||
{6, &NVDRV::GetStatus, "GetStatus"},
|
||||
{7, nullptr, "ForceSetClientPID"},
|
||||
{8, &NVDRV::SetClientPID, "SetClientPID"},
|
||||
{7, nullptr, "SetAruidForTest"},
|
||||
{8, &NVDRV::SetAruid, "SetAruid"},
|
||||
{9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
|
||||
{10, nullptr, "InitializeDevtools"},
|
||||
{11, &NVDRV::Ioctl2, "Ioctl2"},
|
||||
{12, &NVDRV::Ioctl3, "Ioctl3"},
|
||||
{13, &NVDRV::FinishInitialize, "FinishInitialize"},
|
||||
{13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled,
|
||||
"SetGraphicsFirmwareMemoryMarginEnabled"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ private:
|
||||
void Close(Kernel::HLERequestContext& ctx);
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
void QueryEvent(Kernel::HLERequestContext& ctx);
|
||||
void SetClientPID(Kernel::HLERequestContext& ctx);
|
||||
void FinishInitialize(Kernel::HLERequestContext& ctx);
|
||||
void SetAruid(Kernel::HLERequestContext& ctx);
|
||||
void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
|
||||
void GetStatus(Kernel::HLERequestContext& ctx);
|
||||
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
|
||||
void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version);
|
||||
|
||||
@@ -10,19 +10,19 @@ namespace Service::Nvidia {
|
||||
|
||||
NVMEMP::NVMEMP() : ServiceFramework("nvmemp") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NVMEMP::Cmd0, "Cmd0"},
|
||||
{1, &NVMEMP::Cmd1, "Cmd1"},
|
||||
{0, &NVMEMP::Open, "Open"},
|
||||
{1, &NVMEMP::GetAruid, "GetAruid"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
NVMEMP::~NVMEMP() = default;
|
||||
|
||||
void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) {
|
||||
void NVMEMP::Open(Kernel::HLERequestContext& ctx) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void NVMEMP::Cmd1(Kernel::HLERequestContext& ctx) {
|
||||
void NVMEMP::GetAruid(Kernel::HLERequestContext& ctx) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ public:
|
||||
~NVMEMP() override;
|
||||
|
||||
private:
|
||||
void Cmd0(Kernel::HLERequestContext& ctx);
|
||||
void Cmd1(Kernel::HLERequestContext& ctx);
|
||||
void Open(Kernel::HLERequestContext& ctx);
|
||||
void GetAruid(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia
|
||||
|
||||
@@ -36,6 +36,9 @@ public:
|
||||
{18, nullptr, "ReleaseIrq"},
|
||||
{19, nullptr, "SetIrqEnable"},
|
||||
{20, nullptr, "SetAspmEnable"},
|
||||
{21, nullptr, "SetResetUponResumeEnable"},
|
||||
{22, nullptr, "Unknown22"},
|
||||
{23, nullptr, "Unknown23"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ public:
|
||||
{24, nullptr, "GetModuleStateTable"},
|
||||
{25, nullptr, "GetPowerDomainStateTable"},
|
||||
{26, nullptr, "GetFuseInfo"},
|
||||
{27, nullptr, "GetDramId"},
|
||||
{28, nullptr, "IsPoweredOn"},
|
||||
{29, nullptr, "GetVoltage"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -78,13 +78,13 @@ public:
|
||||
: ServiceFramework{"pm:dmnt"}, kernel(kernel) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetDebugProcesses"},
|
||||
{1, nullptr, "StartDebugProcess"},
|
||||
{2, &DebugMonitor::GetTitlePid, "GetTitlePid"},
|
||||
{3, nullptr, "EnableDebugForTitleId"},
|
||||
{4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"},
|
||||
{5, nullptr, "EnableDebugForApplication"},
|
||||
{6, nullptr, "DisableDebug"},
|
||||
{0, nullptr, "GetJitDebugProcessIdList"},
|
||||
{1, nullptr, "StartProcess"},
|
||||
{2, &DebugMonitor::GetProcessId, "GetProcessId"},
|
||||
{3, nullptr, "HookToCreateProcess"},
|
||||
{4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"},
|
||||
{5, nullptr, "HookToCreateApplicationProgress"},
|
||||
{6, nullptr, "ClearHook"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void GetTitlePid(Kernel::HLERequestContext& ctx) {
|
||||
void GetProcessId(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto title_id = rp.PopRaw<u64>();
|
||||
|
||||
@@ -114,7 +114,7 @@ private:
|
||||
rb.Push((*process)->GetProcessID());
|
||||
}
|
||||
|
||||
void GetApplicationPid(Kernel::HLERequestContext& ctx) {
|
||||
void GetApplicationProcessId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PM, "called");
|
||||
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
|
||||
}
|
||||
@@ -163,15 +163,15 @@ public:
|
||||
: ServiceFramework{"pm:shell"}, kernel(kernel) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "LaunchProcess"},
|
||||
{1, nullptr, "TerminateProcessByPid"},
|
||||
{2, nullptr, "TerminateProcessByTitleId"},
|
||||
{3, nullptr, "GetProcessEventWaiter"},
|
||||
{4, nullptr, "GetProcessEventType"},
|
||||
{0, nullptr, "LaunchProgram"},
|
||||
{1, nullptr, "TerminateProcess"},
|
||||
{2, nullptr, "TerminateProgram"},
|
||||
{3, nullptr, "GetProcessEventHandle"},
|
||||
{4, nullptr, "GetProcessEventInfo"},
|
||||
{5, nullptr, "NotifyBootFinished"},
|
||||
{6, &Shell::GetApplicationPid, "GetApplicationPid"},
|
||||
{6, &Shell::GetApplicationProcessIdForShell, "GetApplicationProcessIdForShell"},
|
||||
{7, nullptr, "BoostSystemMemoryResourceLimit"},
|
||||
{8, nullptr, "EnableAdditionalSystemThreads"},
|
||||
{8, nullptr, "BoostApplicationThreadResourceLimit"},
|
||||
{9, nullptr, "GetBootFinishedEventHandle"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -180,7 +180,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void GetApplicationPid(Kernel::HLERequestContext& ctx) {
|
||||
void GetApplicationProcessIdForShell(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PM, "called");
|
||||
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@ public:
|
||||
{40101, nullptr, "SetUserAgreementCheckEnabled"},
|
||||
{50100, nullptr, "ReadAllApplicationReportFiles"},
|
||||
{90100, nullptr, "ReadAllReportFiles"},
|
||||
{90101, nullptr, "Unknown90101"},
|
||||
{90102, nullptr, "Unknown90102"},
|
||||
{90200, nullptr, "GetStatistics"},
|
||||
{90201, nullptr, "GetThroughputHistory"},
|
||||
{90300, nullptr, "GetLastUploadError"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
{4, nullptr, "Cancel"},
|
||||
{5, nullptr, "PrintModuleInformation"},
|
||||
{6, nullptr, "GetModuleInformation"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
{15, nullptr, "GetBatteryAgePercentage"},
|
||||
{16, nullptr, "GetBatteryChargeInfoEvent"},
|
||||
{17, nullptr, "GetBatteryChargeInfoFields"},
|
||||
{18, nullptr, "GetBatteryChargeCalibratedEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
namespace Service::SM {
|
||||
|
||||
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
|
||||
void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
|
||||
LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
|
||||
ctx.Session()->ConvertToDomain();
|
||||
@@ -22,7 +22,7 @@ void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push<u32>(1); // Converted sessions start with 1 request handler
|
||||
}
|
||||
|
||||
void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
|
||||
void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
|
||||
// and that we probably want to actually make an entirely new Session, but we still need to
|
||||
// verify this on hardware.
|
||||
@@ -33,10 +33,10 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushMoveObjects(ctx.Session()->GetParent()->Client());
|
||||
}
|
||||
|
||||
void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service, "(STUBBED) called, using DuplicateSession");
|
||||
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject");
|
||||
|
||||
DuplicateSession(ctx);
|
||||
CloneCurrentObject(ctx);
|
||||
}
|
||||
|
||||
void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
@@ -47,13 +47,14 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push<u16>(0x1000);
|
||||
}
|
||||
|
||||
// https://switchbrew.org/wiki/IPC_Marshalling
|
||||
Controller::Controller() : ServiceFramework("IpcController") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0x00000000, &Controller::ConvertSessionToDomain, "ConvertSessionToDomain"},
|
||||
{0x00000001, nullptr, "ConvertDomainToSession"},
|
||||
{0x00000002, &Controller::DuplicateSession, "DuplicateSession"},
|
||||
{0x00000003, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"},
|
||||
{0x00000004, &Controller::DuplicateSessionEx, "DuplicateSessionEx"},
|
||||
{0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"},
|
||||
{1, nullptr, "CopyFromCurrentDomain"},
|
||||
{2, &Controller::CloneCurrentObject, "CloneCurrentObject"},
|
||||
{3, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"},
|
||||
{4, &Controller::CloneCurrentObjectEx, "CloneCurrentObjectEx"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ public:
|
||||
~Controller() override;
|
||||
|
||||
private:
|
||||
void ConvertSessionToDomain(Kernel::HLERequestContext& ctx);
|
||||
void DuplicateSession(Kernel::HLERequestContext& ctx);
|
||||
void DuplicateSessionEx(Kernel::HLERequestContext& ctx);
|
||||
void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx);
|
||||
void CloneCurrentObject(Kernel::HLERequestContext& ctx);
|
||||
void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx);
|
||||
void QueryPointerBufferSize(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
|
||||
{12, nullptr, "GetDeviceId"},
|
||||
{13, nullptr, "DeleteSettings"},
|
||||
{14, nullptr, "ImportSettings"},
|
||||
{15, nullptr, "SetChangeEnvironmentIdentifierDisabled"},
|
||||
{20, nullptr, "Resolve"},
|
||||
{21, nullptr, "ResolveEx"},
|
||||
{30, nullptr, "GetNasServiceSetting"},
|
||||
@@ -28,6 +29,11 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
|
||||
{60, nullptr, "ReadSaveDataFromFsForTest"},
|
||||
{61, nullptr, "WriteSaveDataToFsForTest"},
|
||||
{62, nullptr, "DeleteSaveDataOfFsForTest"},
|
||||
{63, nullptr, "IsChangeEnvironmentIdentifierDisabled"},
|
||||
{64, nullptr, "SetWithoutDomainExchangeFqdns"},
|
||||
{100, nullptr, "GetApplicationServerEnvironmentType"},
|
||||
{101, nullptr, "SetApplicationServerEnvironmentType"},
|
||||
{102, nullptr, "DeleteApplicationServerEnvironmentType"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) {
|
||||
void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
|
||||
struct Parameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 unknown;
|
||||
@@ -29,15 +29,20 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "SetDnsAddressesPrivate"},
|
||||
{1, nullptr, "GetDnsAddressPrivate"},
|
||||
{2, nullptr, "GetHostByName"},
|
||||
{3, nullptr, "GetHostByAddr"},
|
||||
{4, nullptr, "GetHostStringError"},
|
||||
{5, nullptr, "GetGaiStringError"},
|
||||
{6, &SFDNSRES::GetAddrInfo, "GetAddrInfo"},
|
||||
{7, nullptr, "GetNameInfo"},
|
||||
{8, nullptr, "RequestCancelHandle"},
|
||||
{9, nullptr, "CancelSocketCall"},
|
||||
{11, nullptr, "ClearDnsIpServerAddressArray"},
|
||||
{2, nullptr, "GetHostByNameRequest"},
|
||||
{3, nullptr, "GetHostByAddrRequest"},
|
||||
{4, nullptr, "GetHostStringErrorRequest"},
|
||||
{5, nullptr, "GetGaiStringErrorRequest"},
|
||||
{6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"},
|
||||
{7, nullptr, "GetNameInfoRequest"},
|
||||
{8, nullptr, "RequestCancelHandleRequest"},
|
||||
{9, nullptr, "CancelRequest"},
|
||||
{10, nullptr, "GetHostByNameRequestWithOptions"},
|
||||
{11, nullptr, "GetHostByAddrRequestWithOptions"},
|
||||
{12, nullptr, "GetAddrInfoRequestWithOptions"},
|
||||
{13, nullptr, "GetNameInfoRequestWithOptions"},
|
||||
{14, nullptr, "ResolverSetOptionRequest"},
|
||||
{15, nullptr, "ResolverGetOptionRequest"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
~SFDNSRES() override;
|
||||
|
||||
private:
|
||||
void GetAddrInfo(Kernel::HLERequestContext& ctx);
|
||||
void GetAddrInfoRequest(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -9,35 +9,36 @@ namespace Service::SPL {
|
||||
SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetConfig"},
|
||||
{1, nullptr, "UserExpMod"},
|
||||
{1, nullptr, "ModularExponentiate"},
|
||||
{2, nullptr, "GenerateAesKek"},
|
||||
{3, nullptr, "LoadAesKey"},
|
||||
{4, nullptr, "GenerateAesKey"},
|
||||
{5, nullptr, "SetConfig"},
|
||||
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
|
||||
{9, nullptr, "LoadSecureExpModKey"},
|
||||
{10, nullptr, "SecureExpMod"},
|
||||
{9, nullptr, "ImportLotusKey"},
|
||||
{10, nullptr, "DecryptLotusMessage"},
|
||||
{11, nullptr, "IsDevelopment"},
|
||||
{12, nullptr, "GenerateSpecificAesKey"},
|
||||
{13, nullptr, "DecryptPrivk"},
|
||||
{13, nullptr, "DecryptDeviceUniqueData"},
|
||||
{14, nullptr, "DecryptAesKey"},
|
||||
{15, nullptr, "DecryptAesCtr"},
|
||||
{15, nullptr, "CryptAesCtr"},
|
||||
{16, nullptr, "ComputeCmac"},
|
||||
{17, nullptr, "LoadRsaOaepKey"},
|
||||
{18, nullptr, "UnwrapRsaOaepWrappedTitleKey"},
|
||||
{17, nullptr, "ImportEsKey"},
|
||||
{18, nullptr, "UnwrapTitleKey"},
|
||||
{19, nullptr, "LoadTitleKey"},
|
||||
{20, nullptr, "UnwrapAesWrappedTitleKey"},
|
||||
{21, nullptr, "LockAesEngine"},
|
||||
{22, nullptr, "UnlockAesEngine"},
|
||||
{23, nullptr, "GetSplWaitEvent"},
|
||||
{24, nullptr, "SetSharedData"},
|
||||
{25, nullptr, "GetSharedData"},
|
||||
{26, nullptr, "ImportSslRsaKey"},
|
||||
{27, nullptr, "SecureExpModWithSslKey"},
|
||||
{28, nullptr, "ImportEsRsaKey"},
|
||||
{29, nullptr, "SecureExpModWithEsKey"},
|
||||
{30, nullptr, "EncryptManuRsaKeyForImport"},
|
||||
{31, nullptr, "GetPackage2Hash"},
|
||||
{20, nullptr, "PrepareEsCommonKey"},
|
||||
{21, nullptr, "AllocateAesKeyslot"},
|
||||
{22, nullptr, "DeallocateAesKeySlot"},
|
||||
{23, nullptr, "GetAesKeyslotAvailableEvent"},
|
||||
{24, nullptr, "SetBootReason"},
|
||||
{25, nullptr, "GetBootReason"},
|
||||
{26, nullptr, "DecryptAndStoreSslClientCertKey"},
|
||||
{27, nullptr, "ModularExponentiateWithSslClientCertKey"},
|
||||
{28, nullptr, "DecryptAndStoreDrmDeviceCertKey"},
|
||||
{29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"},
|
||||
{30, nullptr, "ReencryptDeviceUniqueData "},
|
||||
{31, nullptr, "PrepareEsArchiveKey"}, // This is also GetPackage2Hash?
|
||||
{32, nullptr, "LoadPreparedAesKey"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -90,6 +90,13 @@ public:
|
||||
: ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
|
||||
{2, nullptr, "GetTestOffset"},
|
||||
{3, nullptr, "SetTestOffset"},
|
||||
{100, nullptr, "GetRtcValue"},
|
||||
{101, nullptr, "IsRtcResetDetected"},
|
||||
{102, nullptr, "GetSetupResultValue"},
|
||||
{200, nullptr, "GetInternalOffset"},
|
||||
{201, nullptr, "SetInternalOffset"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetDsEndpoint"},
|
||||
{1, nullptr, "GetSetupEvent"},
|
||||
{2, nullptr, "Unknown"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "EnableInterface"},
|
||||
{4, nullptr, "DisableInterface"},
|
||||
{5, nullptr, "CtrlInPostBufferAsync"},
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
{9, nullptr, "SetBinaryObjectStore"},
|
||||
{10, nullptr, "Enable"},
|
||||
{11, nullptr, "Disable"},
|
||||
{12, nullptr, "Unknown12"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -69,13 +70,13 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Open"},
|
||||
{1, nullptr, "Close"},
|
||||
{2, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Populate"},
|
||||
{4, nullptr, "PostBufferAsync"},
|
||||
{5, nullptr, "GetXferReport"},
|
||||
{6, nullptr, "PostBufferMultiAsync"},
|
||||
{7, nullptr, "Unknown3"},
|
||||
{8, nullptr, "Unknown4"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -88,13 +89,13 @@ public:
|
||||
explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{0, nullptr, "Unknown0"},
|
||||
{1, nullptr, "SetInterface"},
|
||||
{2, nullptr, "GetInterface"},
|
||||
{3, nullptr, "GetAlternateInterface"},
|
||||
{4, nullptr, "GetCurrentFrame"},
|
||||
{5, nullptr, "CtrlXferAsync"},
|
||||
{6, nullptr, "Unknown2"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "GetCtrlXferReport"},
|
||||
{8, nullptr, "ResetDevice"},
|
||||
{9, nullptr, "OpenUsbEp"},
|
||||
@@ -118,7 +119,7 @@ public:
|
||||
{5, nullptr, "DestroyInterfaceAvailableEvent"},
|
||||
{6, nullptr, "GetInterfaceStateChangeEvent"},
|
||||
{7, nullptr, "AcquireUsbIf"},
|
||||
{8, nullptr, "Unknown1"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -179,8 +180,8 @@ public:
|
||||
{4, nullptr, "GetFwRevision"},
|
||||
{5, nullptr, "GetManufacturerId"},
|
||||
{6, nullptr, "GetDeviceId"},
|
||||
{7, nullptr, "Unknown1"},
|
||||
{8, nullptr, "Unknown2"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -215,12 +216,12 @@ public:
|
||||
explicit USB_PM() : ServiceFramework{"usb:pm"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{1, nullptr, "Unknown2"},
|
||||
{2, nullptr, "Unknown3"},
|
||||
{3, nullptr, "Unknown4"},
|
||||
{4, nullptr, "Unknown5"},
|
||||
{5, nullptr, "Unknown6"},
|
||||
{0, nullptr, "Unknown0"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -700,6 +700,7 @@ public:
|
||||
{3215, nullptr, "SetDisplayGamma"},
|
||||
{3216, nullptr, "GetDisplayCmuLuma"},
|
||||
{3217, nullptr, "SetDisplayCmuLuma"},
|
||||
{6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
|
||||
{8225, nullptr, "GetSharedBufferMemoryHandleId"},
|
||||
{8250, nullptr, "OpenSharedLayer"},
|
||||
{8251, nullptr, "CloseSharedLayer"},
|
||||
@@ -785,6 +786,7 @@ public:
|
||||
{2300, nullptr, "AcquireLayerTexturePresentingEvent"},
|
||||
{2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
|
||||
{2302, nullptr, "GetDisplayHotplugEvent"},
|
||||
{2303, nullptr, "GetDisplayModeChangedEvent"},
|
||||
{2402, nullptr, "GetDisplayHotplugState"},
|
||||
{2501, nullptr, "GetCompositorErrorInfo"},
|
||||
{2601, nullptr, "GetDisplayErrorEvent"},
|
||||
|
||||
@@ -12,6 +12,7 @@ VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &VI_U::GetDisplayService, "GetDisplayService"},
|
||||
{1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -15,34 +15,37 @@ public:
|
||||
explicit WLANInfra() : ServiceFramework{"wlan:inf"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{1, nullptr, "Unknown2"},
|
||||
{0, nullptr, "OpenMode"},
|
||||
{1, nullptr, "CloseMode"},
|
||||
{2, nullptr, "GetMacAddress"},
|
||||
{3, nullptr, "StartScan"},
|
||||
{4, nullptr, "StopScan"},
|
||||
{5, nullptr, "Connect"},
|
||||
{6, nullptr, "CancelConnect"},
|
||||
{7, nullptr, "Disconnect"},
|
||||
{8, nullptr, "Unknown3"},
|
||||
{9, nullptr, "Unknown4"},
|
||||
{8, nullptr, "GetConnectionEvent"},
|
||||
{9, nullptr, "GetConnectionStatus"},
|
||||
{10, nullptr, "GetState"},
|
||||
{11, nullptr, "GetScanResult"},
|
||||
{12, nullptr, "GetRssi"},
|
||||
{13, nullptr, "ChangeRxAntenna"},
|
||||
{14, nullptr, "Unknown5"},
|
||||
{15, nullptr, "Unknown6"},
|
||||
{14, nullptr, "GetFwVersion"},
|
||||
{15, nullptr, "RequestSleep"},
|
||||
{16, nullptr, "RequestWakeUp"},
|
||||
{17, nullptr, "RequestIfUpDown"},
|
||||
{18, nullptr, "Unknown7"},
|
||||
{19, nullptr, "Unknown8"},
|
||||
{20, nullptr, "Unknown9"},
|
||||
{21, nullptr, "Unknown10"},
|
||||
{22, nullptr, "Unknown11"},
|
||||
{23, nullptr, "Unknown12"},
|
||||
{24, nullptr, "Unknown13"},
|
||||
{25, nullptr, "Unknown14"},
|
||||
{26, nullptr, "Unknown15"},
|
||||
{27, nullptr, "Unknown16"},
|
||||
{18, nullptr, "Unknown18"},
|
||||
{19, nullptr, "Unknown19"},
|
||||
{20, nullptr, "Unknown20"},
|
||||
{21, nullptr, "Unknown21"},
|
||||
{22, nullptr, "Unknown22"},
|
||||
{23, nullptr, "Unknown23"},
|
||||
{24, nullptr, "Unknown24"},
|
||||
{25, nullptr, "Unknown25"},
|
||||
{26, nullptr, "Unknown26"},
|
||||
{27, nullptr, "Unknown27"},
|
||||
{28, nullptr, "Unknown28"},
|
||||
{29, nullptr, "Unknown29"},
|
||||
{30, nullptr, "Unknown30"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -55,12 +58,12 @@ public:
|
||||
explicit WLANLocal() : ServiceFramework{"wlan:lcl"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{1, nullptr, "Unknown2"},
|
||||
{2, nullptr, "Unknown3"},
|
||||
{3, nullptr, "Unknown4"},
|
||||
{4, nullptr, "Unknown5"},
|
||||
{5, nullptr, "Unknown6"},
|
||||
{0, nullptr, "Unknown0"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "GetMacAddress"},
|
||||
{7, nullptr, "CreateBss"},
|
||||
{8, nullptr, "DestroyBss"},
|
||||
@@ -72,38 +75,42 @@ public:
|
||||
{14, nullptr, "CancelJoin"},
|
||||
{15, nullptr, "Disconnect"},
|
||||
{16, nullptr, "SetBeaconLostCount"},
|
||||
{17, nullptr, "Unknown7"},
|
||||
{18, nullptr, "Unknown8"},
|
||||
{19, nullptr, "Unknown9"},
|
||||
{17, nullptr, "Unknown17"},
|
||||
{18, nullptr, "Unknown18"},
|
||||
{19, nullptr, "Unknown19"},
|
||||
{20, nullptr, "GetBssIndicationEvent"},
|
||||
{21, nullptr, "GetBssIndicationInfo"},
|
||||
{22, nullptr, "GetState"},
|
||||
{23, nullptr, "GetAllowedChannels"},
|
||||
{24, nullptr, "AddIe"},
|
||||
{25, nullptr, "DeleteIe"},
|
||||
{26, nullptr, "Unknown10"},
|
||||
{27, nullptr, "Unknown11"},
|
||||
{26, nullptr, "Unknown26"},
|
||||
{27, nullptr, "Unknown27"},
|
||||
{28, nullptr, "CreateRxEntry"},
|
||||
{29, nullptr, "DeleteRxEntry"},
|
||||
{30, nullptr, "Unknown12"},
|
||||
{31, nullptr, "Unknown13"},
|
||||
{30, nullptr, "Unknown30"},
|
||||
{31, nullptr, "Unknown31"},
|
||||
{32, nullptr, "AddMatchingDataToRxEntry"},
|
||||
{33, nullptr, "RemoveMatchingDataFromRxEntry"},
|
||||
{34, nullptr, "GetScanResult"},
|
||||
{35, nullptr, "Unknown14"},
|
||||
{35, nullptr, "Unknown35"},
|
||||
{36, nullptr, "SetActionFrameWithBeacon"},
|
||||
{37, nullptr, "CancelActionFrameWithBeacon"},
|
||||
{38, nullptr, "CreateRxEntryForActionFrame"},
|
||||
{39, nullptr, "DeleteRxEntryForActionFrame"},
|
||||
{40, nullptr, "Unknown15"},
|
||||
{41, nullptr, "Unknown16"},
|
||||
{40, nullptr, "Unknown40"},
|
||||
{41, nullptr, "Unknown41"},
|
||||
{42, nullptr, "CancelGetActionFrame"},
|
||||
{43, nullptr, "GetRssi"},
|
||||
{44, nullptr, "Unknown17"},
|
||||
{45, nullptr, "Unknown18"},
|
||||
{46, nullptr, "Unknown19"},
|
||||
{47, nullptr, "Unknown20"},
|
||||
{48, nullptr, "Unknown21"},
|
||||
{44, nullptr, "Unknown44"},
|
||||
{45, nullptr, "Unknown45"},
|
||||
{46, nullptr, "Unknown46"},
|
||||
{47, nullptr, "Unknown47"},
|
||||
{48, nullptr, "Unknown48"},
|
||||
{49, nullptr, "Unknown49"},
|
||||
{50, nullptr, "Unknown50"},
|
||||
{51, nullptr, "Unknown51"},
|
||||
{52, nullptr, "Unknown52"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -142,18 +149,19 @@ public:
|
||||
explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown1"},
|
||||
{1, nullptr, "Unknown2"},
|
||||
{2, nullptr, "Unknown3"},
|
||||
{3, nullptr, "Unknown4"},
|
||||
{4, nullptr, "Unknown5"},
|
||||
{5, nullptr, "Unknown6"},
|
||||
{0, nullptr, "Unknown0"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{6, nullptr, "GetMacAddress"},
|
||||
{7, nullptr, "SwitchTsfTimerFunction"},
|
||||
{8, nullptr, "Unknown7"},
|
||||
{9, nullptr, "Unknown8"},
|
||||
{10, nullptr, "Unknown9"},
|
||||
{11, nullptr, "Unknown10"},
|
||||
{8, nullptr, "Unknown8"},
|
||||
{9, nullptr, "Unknown9"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
{12, nullptr, "Unknown12"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -184,4 +184,9 @@ void RestoreGlobalState() {
|
||||
values.sound_index.SetGlobal(true);
|
||||
}
|
||||
|
||||
void Sanitize() {
|
||||
values.use_asynchronous_gpu_emulation.SetValue(
|
||||
values.use_asynchronous_gpu_emulation.GetValue() || values.use_multi_core.GetValue());
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
@@ -346,31 +346,6 @@ struct TouchscreenInput {
|
||||
u32 rotation_angle;
|
||||
};
|
||||
|
||||
enum class NANDTotalSize : u64 {
|
||||
S29_1GB = 0x747C00000ULL,
|
||||
};
|
||||
|
||||
enum class NANDUserSize : u64 {
|
||||
S26GB = 0x680000000ULL,
|
||||
};
|
||||
|
||||
enum class NANDSystemSize : u64 {
|
||||
S2_5GB = 0xA0000000,
|
||||
};
|
||||
|
||||
enum class SDMCSize : u64 {
|
||||
S1GB = 0x40000000,
|
||||
S2GB = 0x80000000,
|
||||
S4GB = 0x100000000ULL,
|
||||
S8GB = 0x200000000ULL,
|
||||
S16GB = 0x400000000ULL,
|
||||
S32GB = 0x800000000ULL,
|
||||
S64GB = 0x1000000000ULL,
|
||||
S128GB = 0x2000000000ULL,
|
||||
S256GB = 0x4000000000ULL,
|
||||
S1TB = 0x10000000000ULL,
|
||||
};
|
||||
|
||||
enum class RendererBackend {
|
||||
OpenGL = 0,
|
||||
Vulkan = 1,
|
||||
@@ -382,6 +357,11 @@ enum class GPUAccuracy : u32 {
|
||||
Extreme = 2,
|
||||
};
|
||||
|
||||
enum class CPUAccuracy {
|
||||
Accurate = 0,
|
||||
DebugMode = 1,
|
||||
};
|
||||
|
||||
extern bool configuring_global;
|
||||
|
||||
template <typename Type>
|
||||
@@ -427,6 +407,18 @@ struct Values {
|
||||
// Core
|
||||
Setting<bool> use_multi_core;
|
||||
|
||||
// Cpu
|
||||
CPUAccuracy cpu_accuracy;
|
||||
|
||||
bool cpuopt_page_tables;
|
||||
bool cpuopt_block_linking;
|
||||
bool cpuopt_return_stack_buffer;
|
||||
bool cpuopt_fast_dispatcher;
|
||||
bool cpuopt_context_elimination;
|
||||
bool cpuopt_const_prop;
|
||||
bool cpuopt_misc_ir;
|
||||
bool cpuopt_reduce_misalign_checks;
|
||||
|
||||
// Renderer
|
||||
Setting<RendererBackend> renderer_backend;
|
||||
bool renderer_debug;
|
||||
@@ -491,10 +483,6 @@ struct Values {
|
||||
bool gamecard_inserted;
|
||||
bool gamecard_current_game;
|
||||
std::string gamecard_path;
|
||||
NANDTotalSize nand_total_size;
|
||||
NANDSystemSize nand_system_size;
|
||||
NANDUserSize nand_user_size;
|
||||
SDMCSize sdmc_size;
|
||||
|
||||
// Debugging
|
||||
bool record_frame_times;
|
||||
@@ -505,7 +493,6 @@ struct Values {
|
||||
bool dump_nso;
|
||||
bool reporting_services;
|
||||
bool quest_flag;
|
||||
bool disable_cpu_opt;
|
||||
bool disable_macro_jit;
|
||||
|
||||
// Misceallaneous
|
||||
@@ -539,4 +526,7 @@ void LogSettings();
|
||||
// Restore the global state of all applicable settings in the Values struct
|
||||
void RestoreGlobalState();
|
||||
|
||||
// Fixes settings that are known to cause issues with the emulator
|
||||
void Sanitize();
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
@@ -30,7 +30,8 @@ if(SDL2_FOUND)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES})
|
||||
target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR})
|
||||
target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES})
|
||||
|
||||
create_target_directory_groups(input_common)
|
||||
target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <libusb.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "input_common/gcadapter/gc_adapter.h"
|
||||
|
||||
@@ -24,6 +25,7 @@ Adapter::Adapter() {
|
||||
LOG_INFO(Input, "GC Adapter Initialization started");
|
||||
|
||||
current_status = NO_ADAPTER_DETECTED;
|
||||
get_origin.fill(true);
|
||||
|
||||
const int init_res = libusb_init(&libusb_ctx);
|
||||
if (init_res == LIBUSB_SUCCESS) {
|
||||
@@ -33,15 +35,10 @@ Adapter::Adapter() {
|
||||
}
|
||||
}
|
||||
|
||||
GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) {
|
||||
GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) {
|
||||
GCPadStatus pad = {};
|
||||
bool get_origin = false;
|
||||
|
||||
ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4);
|
||||
if (type != ControllerTypes::None) {
|
||||
get_origin = true;
|
||||
}
|
||||
|
||||
adapter_controllers_status[port] = type;
|
||||
|
||||
static constexpr std::array<PadButton, 8> b1_buttons{
|
||||
@@ -57,6 +54,11 @@ GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_pa
|
||||
PadButton::PAD_TRIGGER_L,
|
||||
};
|
||||
|
||||
if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) {
|
||||
// Controller may have been disconnected, recalibrate if reconnected.
|
||||
get_origin[port] = true;
|
||||
}
|
||||
|
||||
if (adapter_controllers_status[port] != ControllerTypes::None) {
|
||||
const u8 b1 = adapter_payload[1 + (9 * port) + 1];
|
||||
const u8 b2 = adapter_payload[1 + (9 * port) + 2];
|
||||
@@ -73,16 +75,22 @@ GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_pa
|
||||
}
|
||||
}
|
||||
|
||||
if (get_origin) {
|
||||
pad.button |= PAD_GET_ORIGIN;
|
||||
}
|
||||
|
||||
pad.stick_x = adapter_payload[1 + (9 * port) + 3];
|
||||
pad.stick_y = adapter_payload[1 + (9 * port) + 4];
|
||||
pad.substick_x = adapter_payload[1 + (9 * port) + 5];
|
||||
pad.substick_y = adapter_payload[1 + (9 * port) + 6];
|
||||
pad.trigger_left = adapter_payload[1 + (9 * port) + 7];
|
||||
pad.trigger_right = adapter_payload[1 + (9 * port) + 8];
|
||||
|
||||
if (get_origin[port]) {
|
||||
origin_status[port].stick_x = pad.stick_x;
|
||||
origin_status[port].stick_y = pad.stick_y;
|
||||
origin_status[port].substick_x = pad.substick_x;
|
||||
origin_status[port].substick_y = pad.substick_y;
|
||||
origin_status[port].trigger_left = pad.trigger_left;
|
||||
origin_status[port].trigger_right = pad.trigger_right;
|
||||
get_origin[port] = false;
|
||||
}
|
||||
}
|
||||
return pad;
|
||||
}
|
||||
@@ -131,31 +139,31 @@ void Adapter::Read() {
|
||||
for (std::size_t port = 0; port < pads.size(); ++port) {
|
||||
pads[port] = GetPadStatus(port, adapter_payload_copy);
|
||||
if (DeviceConnected(port) && configuring) {
|
||||
if (pads[port].button != PAD_GET_ORIGIN) {
|
||||
if (pads[port].button != 0) {
|
||||
pad_queue[port].Push(pads[port]);
|
||||
}
|
||||
|
||||
// Accounting for a threshold here because of some controller variance
|
||||
if (pads[port].stick_x > pads[port].MAIN_STICK_CENTER_X + pads[port].THRESHOLD ||
|
||||
pads[port].stick_x < pads[port].MAIN_STICK_CENTER_X - pads[port].THRESHOLD) {
|
||||
if (pads[port].stick_x > origin_status[port].stick_x + pads[port].THRESHOLD ||
|
||||
pads[port].stick_x < origin_status[port].stick_x - pads[port].THRESHOLD) {
|
||||
pads[port].axis = GCAdapter::PadAxes::StickX;
|
||||
pads[port].axis_value = pads[port].stick_x;
|
||||
pad_queue[port].Push(pads[port]);
|
||||
}
|
||||
if (pads[port].stick_y > pads[port].MAIN_STICK_CENTER_Y + pads[port].THRESHOLD ||
|
||||
pads[port].stick_y < pads[port].MAIN_STICK_CENTER_Y - pads[port].THRESHOLD) {
|
||||
if (pads[port].stick_y > origin_status[port].stick_y + pads[port].THRESHOLD ||
|
||||
pads[port].stick_y < origin_status[port].stick_y - pads[port].THRESHOLD) {
|
||||
pads[port].axis = GCAdapter::PadAxes::StickY;
|
||||
pads[port].axis_value = pads[port].stick_y;
|
||||
pad_queue[port].Push(pads[port]);
|
||||
}
|
||||
if (pads[port].substick_x > pads[port].C_STICK_CENTER_X + pads[port].THRESHOLD ||
|
||||
pads[port].substick_x < pads[port].C_STICK_CENTER_X - pads[port].THRESHOLD) {
|
||||
if (pads[port].substick_x > origin_status[port].substick_x + pads[port].THRESHOLD ||
|
||||
pads[port].substick_x < origin_status[port].substick_x - pads[port].THRESHOLD) {
|
||||
pads[port].axis = GCAdapter::PadAxes::SubstickX;
|
||||
pads[port].axis_value = pads[port].substick_x;
|
||||
pad_queue[port].Push(pads[port]);
|
||||
}
|
||||
if (pads[port].substick_y > pads[port].C_STICK_CENTER_Y + pads[port].THRESHOLD ||
|
||||
pads[port].substick_y < pads[port].C_STICK_CENTER_Y - pads[port].THRESHOLD) {
|
||||
if (pads[port].substick_y > origin_status[port].substick_y + pads[port].THRESHOLD ||
|
||||
pads[port].substick_y < origin_status[port].substick_y - pads[port].THRESHOLD) {
|
||||
pads[port].axis = GCAdapter::PadAxes::SubstickY;
|
||||
pads[port].axis_value = pads[port].substick_y;
|
||||
pad_queue[port].Push(pads[port]);
|
||||
@@ -198,7 +206,7 @@ void Adapter::StartScanThread() {
|
||||
}
|
||||
|
||||
detect_thread_running = true;
|
||||
detect_thread = std::thread([=] { ScanThreadFunc(); });
|
||||
detect_thread = std::thread(&Adapter::ScanThreadFunc, this);
|
||||
}
|
||||
|
||||
void Adapter::StopScanThread() {
|
||||
@@ -227,7 +235,7 @@ void Adapter::Setup() {
|
||||
}
|
||||
|
||||
if (devices != nullptr) {
|
||||
for (std::size_t index = 0; index < device_count; ++index) {
|
||||
for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) {
|
||||
if (CheckDeviceAccess(devices[index])) {
|
||||
// GC Adapter found and accessible, registering it
|
||||
GetGCEndpoint(devices[index]);
|
||||
@@ -236,6 +244,9 @@ void Adapter::Setup() {
|
||||
}
|
||||
libusb_free_device_list(devices, 1);
|
||||
}
|
||||
// Break out of the ScanThreadFunc() loop that is constantly looking for the device
|
||||
// Assumes user has GC adapter plugged in before launch to use the adapter
|
||||
detect_thread_running = false;
|
||||
}
|
||||
|
||||
bool Adapter::CheckDeviceAccess(libusb_device* device) {
|
||||
@@ -344,6 +355,7 @@ void Adapter::Reset() {
|
||||
adapter_input_thread.join();
|
||||
|
||||
adapter_controllers_status.fill(ControllerTypes::None);
|
||||
get_origin.fill(true);
|
||||
current_status = NO_ADAPTER_DETECTED;
|
||||
|
||||
if (usb_adapter_handle) {
|
||||
@@ -357,15 +369,16 @@ void Adapter::Reset() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Adapter::DeviceConnected(int port) {
|
||||
bool Adapter::DeviceConnected(std::size_t port) {
|
||||
return adapter_controllers_status[port] != ControllerTypes::None;
|
||||
}
|
||||
|
||||
void Adapter::ResetDeviceType(int port) {
|
||||
void Adapter::ResetDeviceType(std::size_t port) {
|
||||
adapter_controllers_status[port] = ControllerTypes::None;
|
||||
}
|
||||
|
||||
void Adapter::BeginConfiguration() {
|
||||
get_origin.fill(true);
|
||||
for (auto& pq : pad_queue) {
|
||||
pq.Clear();
|
||||
}
|
||||
@@ -395,4 +408,25 @@ const std::array<GCState, 4>& Adapter::GetPadState() const {
|
||||
return state;
|
||||
}
|
||||
|
||||
int Adapter::GetOriginValue(int port, int axis) const {
|
||||
const auto& status = origin_status[port];
|
||||
|
||||
switch (static_cast<PadAxes>(axis)) {
|
||||
case PadAxes::StickX:
|
||||
return status.stick_x;
|
||||
case PadAxes::StickY:
|
||||
return status.stick_y;
|
||||
case PadAxes::SubstickX:
|
||||
return status.substick_x;
|
||||
case PadAxes::SubstickY:
|
||||
return status.substick_y;
|
||||
case PadAxes::TriggerLeft:
|
||||
return status.trigger_left;
|
||||
case PadAxes::TriggerRight:
|
||||
return status.trigger_right;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GCAdapter
|
||||
|
||||
@@ -8,17 +8,14 @@
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <libusb.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
|
||||
namespace GCAdapter {
|
||||
struct libusb_context;
|
||||
struct libusb_device;
|
||||
struct libusb_device_handle;
|
||||
|
||||
enum {
|
||||
PAD_USE_ORIGIN = 0x0080,
|
||||
PAD_GET_ORIGIN = 0x2000,
|
||||
PAD_ERR_STATUS = 0x8000,
|
||||
};
|
||||
namespace GCAdapter {
|
||||
|
||||
enum class PadButton {
|
||||
PAD_BUTTON_LEFT = 0x0001,
|
||||
@@ -97,14 +94,19 @@ public:
|
||||
void BeginConfiguration();
|
||||
void EndConfiguration();
|
||||
|
||||
/// Returns true if there is a device connected to port
|
||||
bool DeviceConnected(std::size_t port);
|
||||
|
||||
std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
|
||||
const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
|
||||
|
||||
std::array<GCState, 4>& GetPadState();
|
||||
const std::array<GCState, 4>& GetPadState() const;
|
||||
|
||||
int GetOriginValue(int port, int axis) const;
|
||||
|
||||
private:
|
||||
GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload);
|
||||
GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
|
||||
|
||||
void PadToState(const GCPadStatus& pad, GCState& state);
|
||||
|
||||
@@ -116,11 +118,8 @@ private:
|
||||
/// Stop scanning for the adapter
|
||||
void StopScanThread();
|
||||
|
||||
/// Returns true if there is a device connected to port
|
||||
bool DeviceConnected(int port);
|
||||
|
||||
/// Resets status of device connected to port
|
||||
void ResetDeviceType(int port);
|
||||
void ResetDeviceType(std::size_t port);
|
||||
|
||||
/// Returns true if we successfully gain access to GC Adapter
|
||||
bool CheckDeviceAccess(libusb_device* device);
|
||||
@@ -156,6 +155,8 @@ private:
|
||||
|
||||
std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue;
|
||||
std::array<GCState, 4> state;
|
||||
std::array<bool, 4> get_origin;
|
||||
std::array<GCPadStatus, 4> origin_status;
|
||||
};
|
||||
|
||||
} // namespace GCAdapter
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include "common/assert.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "input_common/gcadapter/gc_adapter.h"
|
||||
#include "input_common/gcadapter/gc_poller.h"
|
||||
@@ -20,7 +21,10 @@ public:
|
||||
~GCButton() override;
|
||||
|
||||
bool GetStatus() const override {
|
||||
return gcadapter->GetPadState()[port].buttons.at(button);
|
||||
if (gcadapter->DeviceConnected(port)) {
|
||||
return gcadapter->GetPadState()[port].buttons.at(button);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -34,22 +38,20 @@ public:
|
||||
explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_,
|
||||
GCAdapter::Adapter* adapter)
|
||||
: port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_),
|
||||
gcadapter(adapter) {
|
||||
// L/R triggers range is only in positive direction beginning near 0
|
||||
// 0.0 threshold equates to near half trigger press, but threshold accounts for variability.
|
||||
if (axis > 3) {
|
||||
threshold *= -0.5;
|
||||
}
|
||||
}
|
||||
gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {}
|
||||
|
||||
bool GetStatus() const override {
|
||||
const float axis_value = (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f;
|
||||
if (trigger_if_greater) {
|
||||
// TODO: Might be worthwile to set a slider for the trigger threshold. It is currently
|
||||
// always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
|
||||
return axis_value > threshold;
|
||||
if (gcadapter->DeviceConnected(port)) {
|
||||
const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis);
|
||||
const float axis_value = (current_axis_value - origin_value) / 128.0f;
|
||||
if (trigger_if_greater) {
|
||||
// TODO: Might be worthwile to set a slider for the trigger threshold. It is
|
||||
// currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
|
||||
return axis_value > threshold;
|
||||
}
|
||||
return axis_value < -threshold;
|
||||
}
|
||||
return axis_value < -threshold;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -58,6 +60,7 @@ private:
|
||||
float threshold;
|
||||
bool trigger_if_greater;
|
||||
GCAdapter::Adapter* gcadapter;
|
||||
const float origin_value;
|
||||
};
|
||||
|
||||
GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
|
||||
@@ -94,9 +97,12 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
|
||||
return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater,
|
||||
adapter.get());
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::ParamPackage GCButtonFactory::GetNextInput() {
|
||||
Common::ParamPackage GCButtonFactory::GetNextInput() const {
|
||||
Common::ParamPackage params;
|
||||
GCAdapter::GCPadStatus pad;
|
||||
auto& queue = adapter->GetPadQueue();
|
||||
@@ -144,14 +150,20 @@ void GCButtonFactory::EndConfiguration() {
|
||||
class GCAnalog final : public Input::AnalogDevice {
|
||||
public:
|
||||
GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter)
|
||||
: port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {}
|
||||
: port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
|
||||
origin_value_x(adapter->GetOriginValue(port_, axis_x_)),
|
||||
origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {}
|
||||
|
||||
float GetAxis(int axis) const {
|
||||
std::lock_guard lock{mutex};
|
||||
// division is not by a perfect 128 to account for some variance in center location
|
||||
// e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
|
||||
// [20-230]
|
||||
return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f;
|
||||
if (gcadapter->DeviceConnected(port)) {
|
||||
std::lock_guard lock{mutex};
|
||||
const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
|
||||
// division is not by a perfect 128 to account for some variance in center location
|
||||
// e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
|
||||
// [20-230]
|
||||
return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
std::pair<float, float> GetAnalog(int axis_x, int axis_y) const {
|
||||
@@ -201,8 +213,10 @@ private:
|
||||
const int axis_x;
|
||||
const int axis_y;
|
||||
const float deadzone;
|
||||
mutable std::mutex mutex;
|
||||
GCAdapter::Adapter* gcadapter;
|
||||
const float origin_value_x;
|
||||
const float origin_value_y;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
/// An analog device factory that creates analog devices from GC Adapter
|
||||
@@ -249,7 +263,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
|
||||
const u8 axis = static_cast<u8>(pad.axis);
|
||||
if (analog_x_axis == -1) {
|
||||
analog_x_axis = axis;
|
||||
controller_number = port;
|
||||
controller_number = static_cast<int>(port);
|
||||
} else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) {
|
||||
analog_y_axis = axis;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
*/
|
||||
std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override;
|
||||
|
||||
Common::ParamPackage GetNextInput();
|
||||
Common::ParamPackage GetNextInput() const;
|
||||
|
||||
/// For device input configuration/polling
|
||||
void BeginConfiguration();
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <libusb.h>
|
||||
#include "common/param_package.h"
|
||||
#include "input_common/analog_from_button.h"
|
||||
#include "input_common/gcadapter/gc_adapter.h"
|
||||
|
||||
@@ -234,7 +234,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
|
||||
std::function<void(Status)> status_callback,
|
||||
std::function<void(u16, u16, u16, u16)> data_callback) {
|
||||
|
||||
std::thread([=] {
|
||||
std::thread([=, this] {
|
||||
constexpr u16 CALIBRATION_THRESHOLD = 100;
|
||||
|
||||
u16 min_x{UINT16_MAX};
|
||||
|
||||
@@ -14,50 +14,45 @@
|
||||
|
||||
namespace Tegra::Engines {
|
||||
|
||||
using namespace Texture;
|
||||
|
||||
MaxwellDMA::MaxwellDMA(Core::System& system, MemoryManager& memory_manager)
|
||||
: system{system}, memory_manager{memory_manager} {}
|
||||
|
||||
void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
||||
ASSERT_MSG(method < Regs::NUM_REGS,
|
||||
"Invalid MaxwellDMA register, increase the size of the Regs structure");
|
||||
ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register");
|
||||
|
||||
regs.reg_array[method] = method_argument;
|
||||
|
||||
#define MAXWELLDMA_REG_INDEX(field_name) \
|
||||
(offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32))
|
||||
|
||||
switch (method) {
|
||||
case MAXWELLDMA_REG_INDEX(exec): {
|
||||
HandleCopy();
|
||||
break;
|
||||
if (method == offsetof(Regs, launch_dma) / sizeof(u32)) {
|
||||
Launch();
|
||||
}
|
||||
}
|
||||
|
||||
#undef MAXWELLDMA_REG_INDEX
|
||||
}
|
||||
|
||||
void MaxwellDMA::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||
u32 methods_pending) {
|
||||
for (std::size_t i = 0; i < amount; i++) {
|
||||
for (size_t i = 0; i < amount; ++i) {
|
||||
CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1);
|
||||
}
|
||||
}
|
||||
|
||||
void MaxwellDMA::HandleCopy() {
|
||||
LOG_TRACE(HW_GPU, "Requested a DMA copy");
|
||||
|
||||
const GPUVAddr source = regs.src_address.Address();
|
||||
const GPUVAddr dest = regs.dst_address.Address();
|
||||
void MaxwellDMA::Launch() {
|
||||
LOG_TRACE(Render_OpenGL, "DMA copy 0x{:x} -> 0x{:x}", static_cast<GPUVAddr>(regs.offset_in),
|
||||
static_cast<GPUVAddr>(regs.offset_out));
|
||||
|
||||
// TODO(Subv): Perform more research and implement all features of this engine.
|
||||
ASSERT(regs.exec.enable_swizzle == 0);
|
||||
ASSERT(regs.exec.query_mode == Regs::QueryMode::None);
|
||||
ASSERT(regs.exec.query_intr == Regs::QueryIntr::None);
|
||||
ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2);
|
||||
ASSERT(regs.dst_params.pos_x == 0);
|
||||
ASSERT(regs.dst_params.pos_y == 0);
|
||||
const LaunchDMA& launch = regs.launch_dma;
|
||||
ASSERT(launch.remap_enable == 0);
|
||||
ASSERT(launch.semaphore_type == LaunchDMA::SemaphoreType::NONE);
|
||||
ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE);
|
||||
ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED);
|
||||
ASSERT(regs.dst_params.origin.x == 0);
|
||||
ASSERT(regs.dst_params.origin.y == 0);
|
||||
|
||||
if (!regs.exec.is_dst_linear && !regs.exec.is_src_linear) {
|
||||
const bool is_src_pitch = launch.src_memory_layout == LaunchDMA::MemoryLayout::PITCH;
|
||||
const bool is_dst_pitch = launch.dst_memory_layout == LaunchDMA::MemoryLayout::PITCH;
|
||||
|
||||
if (!is_src_pitch && !is_dst_pitch) {
|
||||
// If both the source and the destination are in block layout, assert.
|
||||
UNREACHABLE_MSG("Tiled->Tiled DMA transfers are not yet implemented");
|
||||
return;
|
||||
@@ -66,144 +61,161 @@ void MaxwellDMA::HandleCopy() {
|
||||
// All copies here update the main memory, so mark all rasterizer states as invalid.
|
||||
system.GPU().Maxwell3D().OnMemoryWrite();
|
||||
|
||||
if (regs.exec.is_dst_linear && regs.exec.is_src_linear) {
|
||||
// When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
|
||||
// buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count,
|
||||
// y_count).
|
||||
if (!regs.exec.enable_2d) {
|
||||
memory_manager.CopyBlock(dest, source, regs.x_count);
|
||||
return;
|
||||
}
|
||||
|
||||
// If both the source and the destination are in linear layout, perform a line-by-line
|
||||
// copy. We're going to take a subrect of size (x_count, y_count) from the source
|
||||
// rectangle. There is no need to manually flush/invalidate the regions because
|
||||
// CopyBlock does that for us.
|
||||
for (u32 line = 0; line < regs.y_count; ++line) {
|
||||
const GPUVAddr source_line = source + line * regs.src_pitch;
|
||||
const GPUVAddr dest_line = dest + line * regs.dst_pitch;
|
||||
memory_manager.CopyBlock(dest_line, source_line, regs.x_count);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(regs.exec.enable_2d == 1);
|
||||
|
||||
if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) {
|
||||
|
||||
ASSERT(regs.src_params.BlockDepth() == 0);
|
||||
// Optimized path for micro copies.
|
||||
if (regs.dst_pitch * regs.y_count < Texture::GetGOBSize() && regs.dst_pitch <= 64) {
|
||||
const u32 bytes_per_pixel = regs.dst_pitch / regs.x_count;
|
||||
const std::size_t src_size = Texture::GetGOBSize();
|
||||
const std::size_t dst_size = regs.dst_pitch * regs.y_count;
|
||||
u32 pos_x = regs.src_params.pos_x;
|
||||
u32 pos_y = regs.src_params.pos_y;
|
||||
const u64 offset =
|
||||
Texture::GetGOBOffset(regs.src_params.size_x, regs.src_params.size_y, pos_x, pos_y,
|
||||
regs.src_params.BlockDepth(), bytes_per_pixel);
|
||||
const u32 x_in_gob = 64 / bytes_per_pixel;
|
||||
pos_x = pos_x % x_in_gob;
|
||||
pos_y = pos_y % 8;
|
||||
|
||||
if (read_buffer.size() < src_size) {
|
||||
read_buffer.resize(src_size);
|
||||
}
|
||||
|
||||
if (write_buffer.size() < dst_size) {
|
||||
write_buffer.resize(dst_size);
|
||||
}
|
||||
|
||||
if (Settings::IsGPULevelExtreme()) {
|
||||
memory_manager.ReadBlock(source + offset, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(dest, write_buffer.data(), dst_size);
|
||||
} else {
|
||||
memory_manager.ReadBlockUnsafe(source + offset, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
Texture::UnswizzleSubrect(regs.x_count, regs.y_count, regs.dst_pitch,
|
||||
regs.src_params.size_x, bytes_per_pixel, read_buffer.data(),
|
||||
write_buffer.data(), regs.src_params.BlockHeight(), pos_x,
|
||||
pos_y);
|
||||
|
||||
memory_manager.WriteBlock(dest, write_buffer.data(), dst_size);
|
||||
|
||||
return;
|
||||
}
|
||||
// If the input is tiled and the output is linear, deswizzle the input and copy it over.
|
||||
const u32 bytes_per_pixel = regs.dst_pitch / regs.x_count;
|
||||
const std::size_t src_size = Texture::CalculateSize(
|
||||
true, bytes_per_pixel, regs.src_params.size_x, regs.src_params.size_y,
|
||||
regs.src_params.size_z, regs.src_params.BlockHeight(), regs.src_params.BlockDepth());
|
||||
|
||||
const std::size_t src_layer_size = Texture::CalculateSize(
|
||||
true, bytes_per_pixel, regs.src_params.size_x, regs.src_params.size_y, 1,
|
||||
regs.src_params.BlockHeight(), regs.src_params.BlockDepth());
|
||||
|
||||
const std::size_t dst_size = regs.dst_pitch * regs.y_count;
|
||||
|
||||
if (read_buffer.size() < src_size) {
|
||||
read_buffer.resize(src_size);
|
||||
}
|
||||
|
||||
if (write_buffer.size() < dst_size) {
|
||||
write_buffer.resize(dst_size);
|
||||
}
|
||||
|
||||
if (Settings::IsGPULevelExtreme()) {
|
||||
memory_manager.ReadBlock(source, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(dest, write_buffer.data(), dst_size);
|
||||
} else {
|
||||
memory_manager.ReadBlockUnsafe(source, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
Texture::UnswizzleSubrect(
|
||||
regs.x_count, regs.y_count, regs.dst_pitch, regs.src_params.size_x, bytes_per_pixel,
|
||||
read_buffer.data() + src_layer_size * regs.src_params.pos_z, write_buffer.data(),
|
||||
regs.src_params.BlockHeight(), regs.src_params.pos_x, regs.src_params.pos_y);
|
||||
|
||||
memory_manager.WriteBlock(dest, write_buffer.data(), dst_size);
|
||||
if (is_src_pitch && is_dst_pitch) {
|
||||
CopyPitchToPitch();
|
||||
} else {
|
||||
ASSERT(regs.dst_params.BlockDepth() == 0);
|
||||
ASSERT(launch.multi_line_enable == 1);
|
||||
|
||||
const u32 bytes_per_pixel = regs.src_pitch / regs.x_count;
|
||||
|
||||
const std::size_t dst_size = Texture::CalculateSize(
|
||||
true, bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y,
|
||||
regs.dst_params.size_z, regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth());
|
||||
|
||||
const std::size_t dst_layer_size = Texture::CalculateSize(
|
||||
true, bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y, 1,
|
||||
regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth());
|
||||
|
||||
const std::size_t src_size = regs.src_pitch * regs.y_count;
|
||||
|
||||
if (read_buffer.size() < src_size) {
|
||||
read_buffer.resize(src_size);
|
||||
}
|
||||
|
||||
if (write_buffer.size() < dst_size) {
|
||||
write_buffer.resize(dst_size);
|
||||
}
|
||||
|
||||
if (Settings::IsGPULevelExtreme()) {
|
||||
memory_manager.ReadBlock(source, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(dest, write_buffer.data(), dst_size);
|
||||
if (!is_src_pitch && is_dst_pitch) {
|
||||
CopyBlockLinearToPitch();
|
||||
} else {
|
||||
memory_manager.ReadBlockUnsafe(source, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size);
|
||||
CopyPitchToBlockLinear();
|
||||
}
|
||||
|
||||
// If the input is linear and the output is tiled, swizzle the input and copy it over.
|
||||
Texture::SwizzleSubrect(
|
||||
regs.x_count, regs.y_count, regs.src_pitch, regs.dst_params.size_x, bytes_per_pixel,
|
||||
write_buffer.data() + dst_layer_size * regs.dst_params.pos_z, read_buffer.data(),
|
||||
regs.dst_params.BlockHeight(), regs.dst_params.pos_x, regs.dst_params.pos_y);
|
||||
|
||||
memory_manager.WriteBlock(dest, write_buffer.data(), dst_size);
|
||||
}
|
||||
}
|
||||
|
||||
void MaxwellDMA::CopyPitchToPitch() {
|
||||
// When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D
|
||||
// buffer of length `line_length_in`.
|
||||
// Otherwise we copy a 2D image of dimensions (line_length_in, line_count).
|
||||
if (!regs.launch_dma.multi_line_enable) {
|
||||
memory_manager.CopyBlock(regs.offset_out, regs.offset_in, regs.line_length_in);
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform a line-by-line copy.
|
||||
// We're going to take a subrect of size (line_length_in, line_count) from the source rectangle.
|
||||
// There is no need to manually flush/invalidate the regions because CopyBlock does that for us.
|
||||
for (u32 line = 0; line < regs.line_count; ++line) {
|
||||
const GPUVAddr source_line = regs.offset_in + static_cast<size_t>(line) * regs.pitch_in;
|
||||
const GPUVAddr dest_line = regs.offset_out + static_cast<size_t>(line) * regs.pitch_out;
|
||||
memory_manager.CopyBlock(dest_line, source_line, regs.line_length_in);
|
||||
}
|
||||
}
|
||||
|
||||
void MaxwellDMA::CopyBlockLinearToPitch() {
|
||||
ASSERT(regs.src_params.block_size.depth == 0);
|
||||
|
||||
// Optimized path for micro copies.
|
||||
const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count;
|
||||
if (dst_size < GOB_SIZE && regs.pitch_out <= GOB_SIZE_X) {
|
||||
FastCopyBlockLinearToPitch();
|
||||
return;
|
||||
}
|
||||
|
||||
// Deswizzle the input and copy it over.
|
||||
const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in;
|
||||
const Parameters& src_params = regs.src_params;
|
||||
const u32 width = src_params.width;
|
||||
const u32 height = src_params.height;
|
||||
const u32 depth = src_params.depth;
|
||||
const u32 block_height = src_params.block_size.height;
|
||||
const u32 block_depth = src_params.block_size.depth;
|
||||
const size_t src_size =
|
||||
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
|
||||
const size_t src_layer_size =
|
||||
CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth);
|
||||
|
||||
if (read_buffer.size() < src_size) {
|
||||
read_buffer.resize(src_size);
|
||||
}
|
||||
if (write_buffer.size() < dst_size) {
|
||||
write_buffer.resize(dst_size);
|
||||
}
|
||||
|
||||
if (Settings::IsGPULevelExtreme()) {
|
||||
memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
} else {
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel,
|
||||
read_buffer.data() + src_layer_size * src_params.layer, write_buffer.data(),
|
||||
block_height, src_params.origin.x, src_params.origin.y);
|
||||
|
||||
memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
void MaxwellDMA::CopyPitchToBlockLinear() {
|
||||
const auto& dst_params = regs.dst_params;
|
||||
const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in;
|
||||
const u32 width = dst_params.width;
|
||||
const u32 height = dst_params.height;
|
||||
const u32 depth = dst_params.depth;
|
||||
const u32 block_height = dst_params.block_size.height;
|
||||
const u32 block_depth = dst_params.block_size.depth;
|
||||
const size_t dst_size =
|
||||
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
|
||||
const size_t dst_layer_size =
|
||||
CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth);
|
||||
|
||||
const size_t src_size = static_cast<size_t>(regs.pitch_in) * regs.line_count;
|
||||
|
||||
if (read_buffer.size() < src_size) {
|
||||
read_buffer.resize(src_size);
|
||||
}
|
||||
if (write_buffer.size() < dst_size) {
|
||||
write_buffer.resize(dst_size);
|
||||
}
|
||||
|
||||
if (Settings::IsGPULevelExtreme()) {
|
||||
memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
} else {
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
// If the input is linear and the output is tiled, swizzle the input and copy it over.
|
||||
if (regs.dst_params.block_size.depth > 0) {
|
||||
ASSERT(dst_params.layer == 0);
|
||||
SwizzleSliceToVoxel(regs.line_length_in, regs.line_count, regs.pitch_in, width, height,
|
||||
bytes_per_pixel, block_height, block_depth, dst_params.origin.x,
|
||||
dst_params.origin.y, write_buffer.data(), read_buffer.data());
|
||||
} else {
|
||||
SwizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_in, width, bytes_per_pixel,
|
||||
write_buffer.data() + dst_layer_size * dst_params.layer, read_buffer.data(),
|
||||
block_height, dst_params.origin.x, dst_params.origin.y);
|
||||
}
|
||||
|
||||
memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
void MaxwellDMA::FastCopyBlockLinearToPitch() {
|
||||
const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in;
|
||||
const size_t src_size = GOB_SIZE;
|
||||
const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count;
|
||||
u32 pos_x = regs.src_params.origin.x;
|
||||
u32 pos_y = regs.src_params.origin.y;
|
||||
const u64 offset = GetGOBOffset(regs.src_params.width, regs.src_params.height, pos_x, pos_y,
|
||||
regs.src_params.block_size.height, bytes_per_pixel);
|
||||
const u32 x_in_gob = 64 / bytes_per_pixel;
|
||||
pos_x = pos_x % x_in_gob;
|
||||
pos_y = pos_y % 8;
|
||||
|
||||
if (read_buffer.size() < src_size) {
|
||||
read_buffer.resize(src_size);
|
||||
}
|
||||
|
||||
if (write_buffer.size() < dst_size) {
|
||||
write_buffer.resize(dst_size);
|
||||
}
|
||||
|
||||
if (Settings::IsGPULevelExtreme()) {
|
||||
memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
} else {
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_in + offset, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width,
|
||||
bytes_per_pixel, read_buffer.data(), write_buffer.data(),
|
||||
regs.src_params.block_size.height, pos_x, pos_y);
|
||||
|
||||
memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
}
|
||||
|
||||
} // namespace Tegra::Engines
|
||||
|
||||
@@ -24,12 +24,167 @@ class MemoryManager;
|
||||
namespace Tegra::Engines {
|
||||
|
||||
/**
|
||||
* This Engine is known as GK104_Copy. Documentation can be found in:
|
||||
* This engine is known as gk104_copy. Documentation can be found in:
|
||||
* https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h
|
||||
* https://github.com/envytools/envytools/blob/master/rnndb/fifo/gk104_copy.xml
|
||||
*/
|
||||
|
||||
class MaxwellDMA final : public EngineInterface {
|
||||
public:
|
||||
struct PackedGPUVAddr {
|
||||
u32 upper;
|
||||
u32 lower;
|
||||
|
||||
constexpr operator GPUVAddr() const noexcept {
|
||||
return (static_cast<GPUVAddr>(upper & 0xff) << 32) | lower;
|
||||
}
|
||||
};
|
||||
|
||||
union BlockSize {
|
||||
BitField<0, 4, u32> width;
|
||||
BitField<4, 4, u32> height;
|
||||
BitField<8, 4, u32> depth;
|
||||
BitField<12, 4, u32> gob_height;
|
||||
};
|
||||
static_assert(sizeof(BlockSize) == 4);
|
||||
|
||||
union Origin {
|
||||
BitField<0, 16, u32> x;
|
||||
BitField<16, 16, u32> y;
|
||||
};
|
||||
static_assert(sizeof(Origin) == 4);
|
||||
|
||||
struct Parameters {
|
||||
BlockSize block_size;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 depth;
|
||||
u32 layer;
|
||||
Origin origin;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 24);
|
||||
|
||||
struct Semaphore {
|
||||
PackedGPUVAddr address;
|
||||
u32 payload;
|
||||
};
|
||||
static_assert(sizeof(Semaphore) == 12);
|
||||
|
||||
struct RenderEnable {
|
||||
enum class Mode : u32 {
|
||||
FALSE = 0,
|
||||
TRUE = 1,
|
||||
CONDITIONAL = 2,
|
||||
RENDER_IF_EQUAL = 3,
|
||||
RENDER_IF_NOT_EQUAL = 4,
|
||||
};
|
||||
|
||||
PackedGPUVAddr address;
|
||||
BitField<0, 3, Mode> mode;
|
||||
};
|
||||
static_assert(sizeof(RenderEnable) == 12);
|
||||
|
||||
enum class PhysModeTarget : u32 {
|
||||
LOCAL_FB = 0,
|
||||
COHERENT_SYSMEM = 1,
|
||||
NONCOHERENT_SYSMEM = 2,
|
||||
};
|
||||
using PhysMode = BitField<0, 2, PhysModeTarget>;
|
||||
|
||||
union LaunchDMA {
|
||||
enum class DataTransferType : u32 {
|
||||
NONE = 0,
|
||||
PIPELINED = 1,
|
||||
NON_PIPELINED = 2,
|
||||
};
|
||||
|
||||
enum class SemaphoreType : u32 {
|
||||
NONE = 0,
|
||||
RELEASE_ONE_WORD_SEMAPHORE = 1,
|
||||
RELEASE_FOUR_WORD_SEMAPHORE = 2,
|
||||
};
|
||||
|
||||
enum class InterruptType : u32 {
|
||||
NONE = 0,
|
||||
BLOCKING = 1,
|
||||
NON_BLOCKING = 2,
|
||||
};
|
||||
|
||||
enum class MemoryLayout : u32 {
|
||||
BLOCKLINEAR = 0,
|
||||
PITCH = 1,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
VIRTUAL = 0,
|
||||
PHYSICAL = 1,
|
||||
};
|
||||
|
||||
enum class SemaphoreReduction : u32 {
|
||||
IMIN = 0,
|
||||
IMAX = 1,
|
||||
IXOR = 2,
|
||||
IAND = 3,
|
||||
IOR = 4,
|
||||
IADD = 5,
|
||||
INC = 6,
|
||||
DEC = 7,
|
||||
FADD = 0xA,
|
||||
};
|
||||
|
||||
enum class SemaphoreReductionSign : u32 {
|
||||
SIGNED = 0,
|
||||
UNSIGNED = 1,
|
||||
};
|
||||
|
||||
enum class BypassL2 : u32 {
|
||||
USE_PTE_SETTING = 0,
|
||||
FORCE_VOLATILE = 1,
|
||||
};
|
||||
|
||||
BitField<0, 2, DataTransferType> data_transfer_type;
|
||||
BitField<2, 1, u32> flush_enable;
|
||||
BitField<3, 2, SemaphoreType> semaphore_type;
|
||||
BitField<5, 2, InterruptType> interrupt_type;
|
||||
BitField<7, 1, MemoryLayout> src_memory_layout;
|
||||
BitField<8, 1, MemoryLayout> dst_memory_layout;
|
||||
BitField<9, 1, u32> multi_line_enable;
|
||||
BitField<10, 1, u32> remap_enable;
|
||||
BitField<11, 1, u32> rmwdisable;
|
||||
BitField<12, 1, Type> src_type;
|
||||
BitField<13, 1, Type> dst_type;
|
||||
BitField<14, 4, SemaphoreReduction> semaphore_reduction;
|
||||
BitField<18, 1, SemaphoreReductionSign> semaphore_reduction_sign;
|
||||
BitField<19, 1, u32> reduction_enable;
|
||||
BitField<20, 1, BypassL2> bypass_l2;
|
||||
};
|
||||
static_assert(sizeof(LaunchDMA) == 4);
|
||||
|
||||
struct RemapConst {
|
||||
enum Swizzle : u32 {
|
||||
SRC_X = 0,
|
||||
SRC_Y = 1,
|
||||
SRC_Z = 2,
|
||||
SRC_W = 3,
|
||||
CONST_A = 4,
|
||||
CONST_B = 5,
|
||||
NO_WRITE = 6,
|
||||
};
|
||||
|
||||
PackedGPUVAddr address;
|
||||
|
||||
union {
|
||||
BitField<0, 3, Swizzle> dst_x;
|
||||
BitField<4, 3, Swizzle> dst_y;
|
||||
BitField<8, 3, Swizzle> dst_z;
|
||||
BitField<12, 3, Swizzle> dst_w;
|
||||
BitField<16, 2, u32> component_size_minus_one;
|
||||
BitField<20, 2, u32> num_src_components_minus_one;
|
||||
BitField<24, 2, u32> num_dst_components_minus_one;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(RemapConst) == 12);
|
||||
|
||||
explicit MaxwellDMA(Core::System& system, MemoryManager& memory_manager);
|
||||
~MaxwellDMA() = default;
|
||||
|
||||
@@ -40,144 +195,19 @@ public:
|
||||
void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||
u32 methods_pending) override;
|
||||
|
||||
struct Regs {
|
||||
static constexpr std::size_t NUM_REGS = 0x1D6;
|
||||
|
||||
struct Parameters {
|
||||
union {
|
||||
BitField<0, 4, u32> block_depth;
|
||||
BitField<4, 4, u32> block_height;
|
||||
BitField<8, 4, u32> block_width;
|
||||
};
|
||||
u32 size_x;
|
||||
u32 size_y;
|
||||
u32 size_z;
|
||||
u32 pos_z;
|
||||
union {
|
||||
BitField<0, 16, u32> pos_x;
|
||||
BitField<16, 16, u32> pos_y;
|
||||
};
|
||||
|
||||
u32 BlockHeight() const {
|
||||
return block_height.Value();
|
||||
}
|
||||
|
||||
u32 BlockDepth() const {
|
||||
return block_depth.Value();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(Parameters) == 24, "Parameters has wrong size");
|
||||
|
||||
enum class ComponentMode : u32 {
|
||||
Src0 = 0,
|
||||
Src1 = 1,
|
||||
Src2 = 2,
|
||||
Src3 = 3,
|
||||
Const0 = 4,
|
||||
Const1 = 5,
|
||||
Zero = 6,
|
||||
};
|
||||
|
||||
enum class CopyMode : u32 {
|
||||
None = 0,
|
||||
Unk1 = 1,
|
||||
Unk2 = 2,
|
||||
};
|
||||
|
||||
enum class QueryMode : u32 {
|
||||
None = 0,
|
||||
Short = 1,
|
||||
Long = 2,
|
||||
};
|
||||
|
||||
enum class QueryIntr : u32 {
|
||||
None = 0,
|
||||
Block = 1,
|
||||
NonBlock = 2,
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
INSERT_UNION_PADDING_WORDS(0xC0);
|
||||
|
||||
struct {
|
||||
union {
|
||||
BitField<0, 2, CopyMode> copy_mode;
|
||||
BitField<2, 1, u32> flush;
|
||||
|
||||
BitField<3, 2, QueryMode> query_mode;
|
||||
BitField<5, 2, QueryIntr> query_intr;
|
||||
|
||||
BitField<7, 1, u32> is_src_linear;
|
||||
BitField<8, 1, u32> is_dst_linear;
|
||||
|
||||
BitField<9, 1, u32> enable_2d;
|
||||
BitField<10, 1, u32> enable_swizzle;
|
||||
};
|
||||
} exec;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0x3F);
|
||||
|
||||
struct {
|
||||
u32 address_high;
|
||||
u32 address_low;
|
||||
|
||||
GPUVAddr Address() const {
|
||||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
|
||||
address_low);
|
||||
}
|
||||
} src_address;
|
||||
|
||||
struct {
|
||||
u32 address_high;
|
||||
u32 address_low;
|
||||
|
||||
GPUVAddr Address() const {
|
||||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
|
||||
address_low);
|
||||
}
|
||||
} dst_address;
|
||||
|
||||
u32 src_pitch;
|
||||
u32 dst_pitch;
|
||||
u32 x_count;
|
||||
u32 y_count;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0xB8);
|
||||
|
||||
u32 const0;
|
||||
u32 const1;
|
||||
union {
|
||||
BitField<0, 4, ComponentMode> component0;
|
||||
BitField<4, 4, ComponentMode> component1;
|
||||
BitField<8, 4, ComponentMode> component2;
|
||||
BitField<12, 4, ComponentMode> component3;
|
||||
BitField<16, 2, u32> component_size;
|
||||
BitField<20, 3, u32> src_num_components;
|
||||
BitField<24, 3, u32> dst_num_components;
|
||||
|
||||
u32 SrcBytePerPixel() const {
|
||||
return src_num_components.Value() * component_size.Value();
|
||||
}
|
||||
u32 DstBytePerPixel() const {
|
||||
return dst_num_components.Value() * component_size.Value();
|
||||
}
|
||||
} swizzle_config;
|
||||
|
||||
Parameters dst_params;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(1);
|
||||
|
||||
Parameters src_params;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0x13);
|
||||
};
|
||||
std::array<u32, NUM_REGS> reg_array;
|
||||
};
|
||||
} regs{};
|
||||
|
||||
private:
|
||||
/// Performs the copy from the source buffer to the destination buffer as configured in the
|
||||
/// registers.
|
||||
void Launch();
|
||||
|
||||
void CopyPitchToPitch();
|
||||
|
||||
void CopyBlockLinearToPitch();
|
||||
|
||||
void CopyPitchToBlockLinear();
|
||||
|
||||
void FastCopyBlockLinearToPitch();
|
||||
|
||||
Core::System& system;
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
@@ -185,28 +215,58 @@ private:
|
||||
std::vector<u8> read_buffer;
|
||||
std::vector<u8> write_buffer;
|
||||
|
||||
/// Performs the copy from the source buffer to the destination buffer as configured in the
|
||||
/// registers.
|
||||
void HandleCopy();
|
||||
};
|
||||
static constexpr std::size_t NUM_REGS = 0x800;
|
||||
struct Regs {
|
||||
union {
|
||||
struct {
|
||||
u32 reserved[0x40];
|
||||
u32 nop;
|
||||
u32 reserved01[0xf];
|
||||
u32 pm_trigger;
|
||||
u32 reserved02[0x3f];
|
||||
Semaphore semaphore;
|
||||
u32 reserved03[0x2];
|
||||
RenderEnable render_enable;
|
||||
PhysMode src_phys_mode;
|
||||
PhysMode dst_phys_mode;
|
||||
u32 reserved04[0x26];
|
||||
LaunchDMA launch_dma;
|
||||
u32 reserved05[0x3f];
|
||||
PackedGPUVAddr offset_in;
|
||||
PackedGPUVAddr offset_out;
|
||||
u32 pitch_in;
|
||||
u32 pitch_out;
|
||||
u32 line_length_in;
|
||||
u32 line_count;
|
||||
u32 reserved06[0xb8];
|
||||
RemapConst remap_const;
|
||||
Parameters dst_params;
|
||||
u32 reserved07[0x1];
|
||||
Parameters src_params;
|
||||
u32 reserved08[0x275];
|
||||
u32 pm_trigger_end;
|
||||
u32 reserved09[0x3ba];
|
||||
};
|
||||
std::array<u32, NUM_REGS> reg_array;
|
||||
};
|
||||
} regs{};
|
||||
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \
|
||||
"Field " #field_name " has invalid position")
|
||||
|
||||
ASSERT_REG_POSITION(exec, 0xC0);
|
||||
ASSERT_REG_POSITION(src_address, 0x100);
|
||||
ASSERT_REG_POSITION(dst_address, 0x102);
|
||||
ASSERT_REG_POSITION(src_pitch, 0x104);
|
||||
ASSERT_REG_POSITION(dst_pitch, 0x105);
|
||||
ASSERT_REG_POSITION(x_count, 0x106);
|
||||
ASSERT_REG_POSITION(y_count, 0x107);
|
||||
ASSERT_REG_POSITION(const0, 0x1C0);
|
||||
ASSERT_REG_POSITION(const1, 0x1C1);
|
||||
ASSERT_REG_POSITION(swizzle_config, 0x1C2);
|
||||
ASSERT_REG_POSITION(dst_params, 0x1C3);
|
||||
ASSERT_REG_POSITION(src_params, 0x1CA);
|
||||
ASSERT_REG_POSITION(launch_dma, 0xC0);
|
||||
ASSERT_REG_POSITION(offset_in, 0x100);
|
||||
ASSERT_REG_POSITION(offset_out, 0x102);
|
||||
ASSERT_REG_POSITION(pitch_in, 0x104);
|
||||
ASSERT_REG_POSITION(pitch_out, 0x105);
|
||||
ASSERT_REG_POSITION(line_length_in, 0x106);
|
||||
ASSERT_REG_POSITION(line_count, 0x107);
|
||||
ASSERT_REG_POSITION(remap_const, 0x1C0);
|
||||
ASSERT_REG_POSITION(dst_params, 0x1C3);
|
||||
ASSERT_REG_POSITION(src_params, 0x1CA);
|
||||
|
||||
#undef ASSERT_REG_POSITION
|
||||
};
|
||||
|
||||
} // namespace Tegra::Engines
|
||||
|
||||
@@ -332,23 +332,23 @@ private:
|
||||
|
||||
if constexpr (has_extended_dynamic_state) {
|
||||
// With extended dynamic states we can specify the length and stride of a vertex buffer
|
||||
// std::array<VkDeviceSize, N> sizes;
|
||||
std::array<VkDeviceSize, N> sizes;
|
||||
std::array<u16, N> strides;
|
||||
// std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin());
|
||||
std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin());
|
||||
std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin());
|
||||
|
||||
if constexpr (is_indexed) {
|
||||
scheduler.Record(
|
||||
[buffers, offsets, strides, index = index](vk::CommandBuffer cmdbuf) {
|
||||
[buffers, offsets, sizes, strides, index = index](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type);
|
||||
cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
|
||||
offsets.data(), nullptr,
|
||||
offsets.data(), sizes.data(),
|
||||
ExpandStrides(strides).data());
|
||||
});
|
||||
} else {
|
||||
scheduler.Record([buffers, offsets, strides](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([buffers, offsets, sizes, strides](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
|
||||
offsets.data(), nullptr,
|
||||
offsets.data(), sizes.data(),
|
||||
ExpandStrides(strides).data());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -343,8 +343,7 @@ std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) co
|
||||
size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed);
|
||||
}
|
||||
if (is_tiled && is_layered) {
|
||||
return Common::AlignBits(size,
|
||||
Tegra::Texture::GetGOBSizeShift() + block_height + block_depth);
|
||||
return Common::AlignBits(size, Tegra::Texture::GOB_SIZE_SHIFT + block_height + block_depth);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -418,7 +417,7 @@ std::tuple<u32, u32, u32> SurfaceParams::GetBlockOffsetXYZ(u32 offset) const {
|
||||
const u32 block_size = GetBlockSize();
|
||||
const u32 block_index = offset / block_size;
|
||||
const u32 gob_offset = offset % block_size;
|
||||
const u32 gob_index = gob_offset / static_cast<u32>(Tegra::Texture::GetGOBSize());
|
||||
const u32 gob_index = gob_offset / static_cast<u32>(Tegra::Texture::GOB_SIZE);
|
||||
const u32 x_gob_pixels = 64U / GetBytesPerPixel();
|
||||
const u32 x_block_pixels = x_gob_pixels << block_width;
|
||||
const u32 y_block_pixels = 8U << block_height;
|
||||
|
||||
@@ -204,7 +204,7 @@ public:
|
||||
static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height,
|
||||
const u32 block_depth) {
|
||||
return Common::AlignBits(out_size,
|
||||
Tegra::Texture::GetGOBSizeShift() + block_height + block_depth);
|
||||
Tegra::Texture::GOB_SIZE_SHIFT + block_height + block_depth);
|
||||
}
|
||||
|
||||
/// Converts a width from a type of surface into another. This helps represent the
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <cstring>
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/textures/decoders.h"
|
||||
#include "video_core/textures/texture.h"
|
||||
@@ -37,20 +38,10 @@ struct alignas(64) SwizzleTable {
|
||||
std::array<std::array<u16, M>, N> values{};
|
||||
};
|
||||
|
||||
constexpr u32 gob_size_x_shift = 6;
|
||||
constexpr u32 gob_size_y_shift = 3;
|
||||
constexpr u32 gob_size_z_shift = 0;
|
||||
constexpr u32 gob_size_shift = gob_size_x_shift + gob_size_y_shift + gob_size_z_shift;
|
||||
constexpr u32 FAST_SWIZZLE_ALIGN = 16;
|
||||
|
||||
constexpr u32 gob_size_x = 1U << gob_size_x_shift;
|
||||
constexpr u32 gob_size_y = 1U << gob_size_y_shift;
|
||||
constexpr u32 gob_size_z = 1U << gob_size_z_shift;
|
||||
constexpr u32 gob_size = 1U << gob_size_shift;
|
||||
|
||||
constexpr u32 fast_swizzle_align = 16;
|
||||
|
||||
constexpr auto legacy_swizzle_table = SwizzleTable<gob_size_y, gob_size_x, gob_size_z>();
|
||||
constexpr auto fast_swizzle_table = SwizzleTable<gob_size_y, 4, fast_swizzle_align>();
|
||||
constexpr auto LEGACY_SWIZZLE_TABLE = SwizzleTable<GOB_SIZE_X, GOB_SIZE_X, GOB_SIZE_Z>();
|
||||
constexpr auto FAST_SWIZZLE_TABLE = SwizzleTable<GOB_SIZE_Y, 4, FAST_SWIZZLE_ALIGN>();
|
||||
|
||||
/**
|
||||
* This function manages ALL the GOBs(Group of Bytes) Inside a single block.
|
||||
@@ -69,17 +60,17 @@ void PreciseProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, con
|
||||
u32 y_address = z_address;
|
||||
u32 pixel_base = layer_z * z + y_start * stride_x;
|
||||
for (u32 y = y_start; y < y_end; y++) {
|
||||
const auto& table = legacy_swizzle_table[y % gob_size_y];
|
||||
const auto& table = LEGACY_SWIZZLE_TABLE[y % GOB_SIZE_Y];
|
||||
for (u32 x = x_start; x < x_end; x++) {
|
||||
const u32 swizzle_offset{y_address + table[x * bytes_per_pixel % gob_size_x]};
|
||||
const u32 swizzle_offset{y_address + table[x * bytes_per_pixel % GOB_SIZE_X]};
|
||||
const u32 pixel_index{x * out_bytes_per_pixel + pixel_base};
|
||||
data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
|
||||
data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
|
||||
std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
|
||||
}
|
||||
pixel_base += stride_x;
|
||||
if ((y + 1) % gob_size_y == 0)
|
||||
y_address += gob_size;
|
||||
if ((y + 1) % GOB_SIZE_Y == 0)
|
||||
y_address += GOB_SIZE;
|
||||
}
|
||||
z_address += xy_block_size;
|
||||
}
|
||||
@@ -104,18 +95,18 @@ void FastProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const
|
||||
u32 y_address = z_address;
|
||||
u32 pixel_base = layer_z * z + y_start * stride_x;
|
||||
for (u32 y = y_start; y < y_end; y++) {
|
||||
const auto& table = fast_swizzle_table[y % gob_size_y];
|
||||
for (u32 xb = x_startb; xb < x_endb; xb += fast_swizzle_align) {
|
||||
const u32 swizzle_offset{y_address + table[(xb / fast_swizzle_align) % 4]};
|
||||
const auto& table = FAST_SWIZZLE_TABLE[y % GOB_SIZE_Y];
|
||||
for (u32 xb = x_startb; xb < x_endb; xb += FAST_SWIZZLE_ALIGN) {
|
||||
const u32 swizzle_offset{y_address + table[(xb / FAST_SWIZZLE_ALIGN) % 4]};
|
||||
const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel;
|
||||
const u32 pixel_index{out_x + pixel_base};
|
||||
data_ptrs[unswizzle ? 1 : 0] = swizzled_data + swizzle_offset;
|
||||
data_ptrs[unswizzle ? 0 : 1] = unswizzled_data + pixel_index;
|
||||
std::memcpy(data_ptrs[0], data_ptrs[1], fast_swizzle_align);
|
||||
std::memcpy(data_ptrs[0], data_ptrs[1], FAST_SWIZZLE_ALIGN);
|
||||
}
|
||||
pixel_base += stride_x;
|
||||
if ((y + 1) % gob_size_y == 0)
|
||||
y_address += gob_size;
|
||||
if ((y + 1) % GOB_SIZE_Y == 0)
|
||||
y_address += GOB_SIZE;
|
||||
}
|
||||
z_address += xy_block_size;
|
||||
}
|
||||
@@ -138,9 +129,9 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool
|
||||
auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); };
|
||||
const u32 stride_x = width * out_bytes_per_pixel;
|
||||
const u32 layer_z = height * stride_x;
|
||||
const u32 gob_elements_x = gob_size_x / bytes_per_pixel;
|
||||
constexpr u32 gob_elements_y = gob_size_y;
|
||||
constexpr u32 gob_elements_z = gob_size_z;
|
||||
const u32 gob_elements_x = GOB_SIZE_X / bytes_per_pixel;
|
||||
constexpr u32 gob_elements_y = GOB_SIZE_Y;
|
||||
constexpr u32 gob_elements_z = GOB_SIZE_Z;
|
||||
const u32 block_x_elements = gob_elements_x;
|
||||
const u32 block_y_elements = gob_elements_y * block_height;
|
||||
const u32 block_z_elements = gob_elements_z * block_depth;
|
||||
@@ -148,7 +139,7 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool
|
||||
const u32 blocks_on_x = div_ceil(aligned_width, block_x_elements);
|
||||
const u32 blocks_on_y = div_ceil(height, block_y_elements);
|
||||
const u32 blocks_on_z = div_ceil(depth, block_z_elements);
|
||||
const u32 xy_block_size = gob_size * block_height;
|
||||
const u32 xy_block_size = GOB_SIZE * block_height;
|
||||
const u32 block_size = xy_block_size * block_depth;
|
||||
u32 tile_offset = 0;
|
||||
for (u32 zb = 0; zb < blocks_on_z; zb++) {
|
||||
@@ -182,7 +173,7 @@ void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel,
|
||||
bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing) {
|
||||
const u32 block_height_size{1U << block_height};
|
||||
const u32 block_depth_size{1U << block_depth};
|
||||
if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) {
|
||||
if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % FAST_SWIZZLE_ALIGN == 0) {
|
||||
SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth,
|
||||
bytes_per_pixel, out_bytes_per_pixel, block_height_size,
|
||||
block_depth_size, width_spacing);
|
||||
@@ -259,25 +250,26 @@ std::vector<u8> UnswizzleTexture(u8* address, u32 tile_size_x, u32 tile_size_y,
|
||||
}
|
||||
|
||||
void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
|
||||
u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data,
|
||||
u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data,
|
||||
u32 block_height_bit, u32 offset_x, u32 offset_y) {
|
||||
const u32 block_height = 1U << block_height_bit;
|
||||
const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + (gob_size_x - 1)) /
|
||||
gob_size_x};
|
||||
const u32 image_width_in_gobs =
|
||||
(swizzled_width * bytes_per_pixel + (GOB_SIZE_X - 1)) / GOB_SIZE_X;
|
||||
for (u32 line = 0; line < subrect_height; ++line) {
|
||||
const u32 dst_y = line + offset_y;
|
||||
const u32 gob_address_y =
|
||||
(dst_y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs +
|
||||
((dst_y % (gob_size_y * block_height)) / gob_size_y) * gob_size;
|
||||
const auto& table = legacy_swizzle_table[dst_y % gob_size_y];
|
||||
(dst_y / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height * image_width_in_gobs +
|
||||
((dst_y % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE;
|
||||
const auto& table = LEGACY_SWIZZLE_TABLE[dst_y % GOB_SIZE_Y];
|
||||
for (u32 x = 0; x < subrect_width; ++x) {
|
||||
const u32 dst_x = x + offset_x;
|
||||
const u32 gob_address =
|
||||
gob_address_y + (dst_x * bytes_per_pixel / gob_size_x) * gob_size * block_height;
|
||||
const u32 swizzled_offset = gob_address + table[(dst_x * bytes_per_pixel) % gob_size_x];
|
||||
u8* source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel;
|
||||
u8* dest_addr = swizzled_data + swizzled_offset;
|
||||
gob_address_y + (dst_x * bytes_per_pixel / GOB_SIZE_X) * GOB_SIZE * block_height;
|
||||
const u32 swizzled_offset = gob_address + table[(dst_x * bytes_per_pixel) % GOB_SIZE_X];
|
||||
const u32 unswizzled_offset = line * source_pitch + x * bytes_per_pixel;
|
||||
|
||||
const u8* const source_line = unswizzled_data + unswizzled_offset;
|
||||
u8* const dest_addr = swizzled_data + swizzled_offset;
|
||||
std::memcpy(dest_addr, source_line, bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
@@ -289,14 +281,15 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32
|
||||
const u32 block_height = 1U << block_height_bit;
|
||||
for (u32 line = 0; line < subrect_height; ++line) {
|
||||
const u32 y2 = line + offset_y;
|
||||
const u32 gob_address_y = (y2 / (gob_size_y * block_height)) * gob_size * block_height +
|
||||
((y2 % (gob_size_y * block_height)) / gob_size_y) * gob_size;
|
||||
const auto& table = legacy_swizzle_table[y2 % gob_size_y];
|
||||
const u32 gob_address_y = (y2 / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height +
|
||||
((y2 % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE;
|
||||
const auto& table = LEGACY_SWIZZLE_TABLE[y2 % GOB_SIZE_Y];
|
||||
for (u32 x = 0; x < subrect_width; ++x) {
|
||||
const u32 x2 = (x + offset_x) * bytes_per_pixel;
|
||||
const u32 gob_address = gob_address_y + (x2 / gob_size_x) * gob_size * block_height;
|
||||
const u32 swizzled_offset = gob_address + table[x2 % gob_size_x];
|
||||
u8* dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel;
|
||||
const u32 gob_address = gob_address_y + (x2 / GOB_SIZE_X) * GOB_SIZE * block_height;
|
||||
const u32 swizzled_offset = gob_address + table[x2 % GOB_SIZE_X];
|
||||
const u32 unswizzled_offset = line * dest_pitch + x * bytes_per_pixel;
|
||||
u8* dest_line = unswizzled_data + unswizzled_offset;
|
||||
u8* source_addr = swizzled_data + swizzled_offset;
|
||||
|
||||
std::memcpy(dest_line, source_addr, bytes_per_pixel);
|
||||
@@ -304,21 +297,48 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32
|
||||
}
|
||||
}
|
||||
|
||||
void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height,
|
||||
u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x,
|
||||
u32 origin_y, u8* output, const u8* input) {
|
||||
UNIMPLEMENTED_IF(origin_x > 0);
|
||||
UNIMPLEMENTED_IF(origin_y > 0);
|
||||
|
||||
const u32 stride = width * bytes_per_pixel;
|
||||
const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X;
|
||||
const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth);
|
||||
|
||||
const u32 block_height_mask = (1U << block_height) - 1;
|
||||
const u32 x_shift = Common::CountTrailingZeroes32(GOB_SIZE << (block_height + block_depth));
|
||||
|
||||
for (u32 line = 0; line < line_count; ++line) {
|
||||
const auto& table = LEGACY_SWIZZLE_TABLE[line % GOB_SIZE_Y];
|
||||
const u32 block_y = line / GOB_SIZE_Y;
|
||||
const u32 dst_offset_y =
|
||||
(block_y >> block_height) * block_size + (block_y & block_height_mask) * GOB_SIZE;
|
||||
for (u32 x = 0; x < line_length_in; ++x) {
|
||||
const u32 dst_offset =
|
||||
((x / GOB_SIZE_X) << x_shift) + dst_offset_y + table[x % GOB_SIZE_X];
|
||||
const u32 src_offset = x * bytes_per_pixel + line * pitch;
|
||||
std::memcpy(output + dst_offset, input + src_offset, bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y,
|
||||
const u32 block_height_bit, const std::size_t copy_size, const u8* source_data,
|
||||
u8* swizzle_data) {
|
||||
const u32 block_height = 1U << block_height_bit;
|
||||
const u32 image_width_in_gobs{(width + gob_size_x - 1) / gob_size_x};
|
||||
const u32 image_width_in_gobs{(width + GOB_SIZE_X - 1) / GOB_SIZE_X};
|
||||
std::size_t count = 0;
|
||||
for (std::size_t y = dst_y; y < height && count < copy_size; ++y) {
|
||||
const std::size_t gob_address_y =
|
||||
(y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs +
|
||||
((y % (gob_size_y * block_height)) / gob_size_y) * gob_size;
|
||||
const auto& table = legacy_swizzle_table[y % gob_size_y];
|
||||
(y / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height * image_width_in_gobs +
|
||||
((y % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE;
|
||||
const auto& table = LEGACY_SWIZZLE_TABLE[y % GOB_SIZE_Y];
|
||||
for (std::size_t x = dst_x; x < width && count < copy_size; ++x) {
|
||||
const std::size_t gob_address =
|
||||
gob_address_y + (x / gob_size_x) * gob_size * block_height;
|
||||
const std::size_t swizzled_offset = gob_address + table[x % gob_size_x];
|
||||
gob_address_y + (x / GOB_SIZE_X) * GOB_SIZE * block_height;
|
||||
const std::size_t swizzled_offset = gob_address + table[x % GOB_SIZE_X];
|
||||
const u8* source_line = source_data + count;
|
||||
u8* dest_addr = swizzle_data + swizzled_offset;
|
||||
count++;
|
||||
@@ -373,9 +393,9 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
|
||||
std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
||||
u32 block_height, u32 block_depth) {
|
||||
if (tiled) {
|
||||
const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, gob_size_x_shift);
|
||||
const u32 aligned_height = Common::AlignBits(height, gob_size_y_shift + block_height);
|
||||
const u32 aligned_depth = Common::AlignBits(depth, gob_size_z_shift + block_depth);
|
||||
const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, GOB_SIZE_X_SHIFT);
|
||||
const u32 aligned_height = Common::AlignBits(height, GOB_SIZE_Y_SHIFT + block_height);
|
||||
const u32 aligned_depth = Common::AlignBits(depth, GOB_SIZE_Z_SHIFT + block_depth);
|
||||
return aligned_width * aligned_height * aligned_depth;
|
||||
} else {
|
||||
return width * height * depth * bytes_per_pixel;
|
||||
@@ -386,14 +406,14 @@ u64 GetGOBOffset(u32 width, u32 height, u32 dst_x, u32 dst_y, u32 block_height,
|
||||
u32 bytes_per_pixel) {
|
||||
auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); };
|
||||
const u32 gobs_in_block = 1 << block_height;
|
||||
const u32 y_blocks = gob_size_y << block_height;
|
||||
const u32 x_per_gob = gob_size_x / bytes_per_pixel;
|
||||
const u32 y_blocks = GOB_SIZE_Y << block_height;
|
||||
const u32 x_per_gob = GOB_SIZE_X / bytes_per_pixel;
|
||||
const u32 x_blocks = div_ceil(width, x_per_gob);
|
||||
const u32 block_size = gob_size * gobs_in_block;
|
||||
const u32 block_size = GOB_SIZE * gobs_in_block;
|
||||
const u32 stride = block_size * x_blocks;
|
||||
const u32 base = (dst_y / y_blocks) * stride + (dst_x / x_per_gob) * block_size;
|
||||
const u32 relative_y = dst_y % y_blocks;
|
||||
return base + (relative_y / gob_size_y) * gob_size;
|
||||
return base + (relative_y / GOB_SIZE_Y) * GOB_SIZE;
|
||||
}
|
||||
|
||||
} // namespace Tegra::Texture
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
|
||||
namespace Tegra::Texture {
|
||||
|
||||
// GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents
|
||||
// an small rect of (64/bytes_per_pixel)X8.
|
||||
inline std::size_t GetGOBSize() {
|
||||
return 512;
|
||||
}
|
||||
constexpr u32 GOB_SIZE_X = 64;
|
||||
constexpr u32 GOB_SIZE_Y = 8;
|
||||
constexpr u32 GOB_SIZE_Z = 1;
|
||||
constexpr u32 GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z;
|
||||
|
||||
inline std::size_t GetGOBSizeShift() {
|
||||
return 9;
|
||||
}
|
||||
constexpr std::size_t GOB_SIZE_X_SHIFT = 6;
|
||||
constexpr std::size_t GOB_SIZE_Y_SHIFT = 3;
|
||||
constexpr std::size_t GOB_SIZE_Z_SHIFT = 0;
|
||||
constexpr std::size_t GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT;
|
||||
|
||||
/// Unswizzles a swizzled texture without changing its format.
|
||||
void UnswizzleTexture(u8* unswizzled_data, u8* address, u32 tile_size_x, u32 tile_size_y,
|
||||
@@ -48,14 +48,32 @@ std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height
|
||||
|
||||
/// Copies an untiled subrectangle into a tiled surface.
|
||||
void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
|
||||
u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height,
|
||||
u32 offset_x, u32 offset_y);
|
||||
u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data,
|
||||
u32 block_height_bit, u32 offset_x, u32 offset_y);
|
||||
|
||||
/// Copies a tiled subrectangle into a linear surface.
|
||||
void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width,
|
||||
u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height,
|
||||
u32 offset_x, u32 offset_y);
|
||||
|
||||
/// @brief Swizzles a 2D array of pixels into a 3D texture
|
||||
/// @param line_length_in Number of pixels per line
|
||||
/// @param line_count Number of lines
|
||||
/// @param pitch Number of bytes per line
|
||||
/// @param width Width of the swizzled texture
|
||||
/// @param height Height of the swizzled texture
|
||||
/// @param bytes_per_pixel Number of bytes used per pixel
|
||||
/// @param block_height Block height shift
|
||||
/// @param block_depth Block depth shift
|
||||
/// @param origin_x Column offset in pixels of the swizzled texture
|
||||
/// @param origin_y Row offset in pixels of the swizzled texture
|
||||
/// @param output Pointer to the pixels of the swizzled texture
|
||||
/// @param input Pointer to the 2D array of pixels used as input
|
||||
/// @pre input and output points to an array large enough to hold the number of bytes used
|
||||
void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height,
|
||||
u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x,
|
||||
u32 origin_y, u8* output, const u8* input);
|
||||
|
||||
void SwizzleKepler(u32 width, u32 height, u32 dst_x, u32 dst_y, u32 block_height,
|
||||
std::size_t copy_size, const u8* source_data, u8* swizzle_data);
|
||||
|
||||
|
||||
@@ -30,6 +30,12 @@ add_executable(yuzu
|
||||
configuration/configure_audio.cpp
|
||||
configuration/configure_audio.h
|
||||
configuration/configure_audio.ui
|
||||
configuration/configure_cpu.cpp
|
||||
configuration/configure_cpu.h
|
||||
configuration/configure_cpu.ui
|
||||
configuration/configure_cpu_debug.cpp
|
||||
configuration/configure_cpu_debug.h
|
||||
configuration/configure_cpu_debug.ui
|
||||
configuration/configure_debug.cpp
|
||||
configuration/configure_debug.h
|
||||
configuration/configure_debug.ui
|
||||
@@ -98,11 +104,13 @@ add_executable(yuzu
|
||||
game_list_p.h
|
||||
game_list_worker.cpp
|
||||
game_list_worker.h
|
||||
hotkeys.cpp
|
||||
hotkeys.h
|
||||
install_dialog.cpp
|
||||
install_dialog.h
|
||||
loading_screen.cpp
|
||||
loading_screen.h
|
||||
loading_screen.ui
|
||||
hotkeys.cpp
|
||||
hotkeys.h
|
||||
main.cpp
|
||||
main.h
|
||||
main.ui
|
||||
@@ -152,7 +160,7 @@ endif()
|
||||
create_target_directory_groups(yuzu)
|
||||
|
||||
target_link_libraries(yuzu PRIVATE common core input_common video_core)
|
||||
target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets)
|
||||
target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::Widgets)
|
||||
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
|
||||
if (ENABLE_VULKAN AND NOT WIN32)
|
||||
|
||||
@@ -505,22 +505,6 @@ void Config::ReadDataStorageValues() {
|
||||
ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
|
||||
Settings::values.gamecard_path =
|
||||
ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString();
|
||||
Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
|
||||
ReadSetting(QStringLiteral("nand_total_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)))
|
||||
.toULongLong());
|
||||
Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
|
||||
ReadSetting(QStringLiteral("nand_user_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)))
|
||||
.toULongLong());
|
||||
Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
|
||||
ReadSetting(QStringLiteral("nand_system_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)))
|
||||
.toULongLong());
|
||||
Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
|
||||
ReadSetting(QStringLiteral("sdmc_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)))
|
||||
.toULongLong());
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
@@ -540,8 +524,6 @@ void Config::ReadDebuggingValues() {
|
||||
Settings::values.reporting_services =
|
||||
ReadSetting(QStringLiteral("reporting_services"), false).toBool();
|
||||
Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool();
|
||||
Settings::values.disable_cpu_opt =
|
||||
ReadSetting(QStringLiteral("disable_cpu_opt"), false).toBool();
|
||||
Settings::values.disable_macro_jit =
|
||||
ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
|
||||
|
||||
@@ -633,6 +615,34 @@ void Config::ReadPathValues() {
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
void Config::ReadCpuValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Cpu"));
|
||||
|
||||
if (global) {
|
||||
Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>(
|
||||
ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt());
|
||||
|
||||
Settings::values.cpuopt_page_tables =
|
||||
ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
|
||||
Settings::values.cpuopt_block_linking =
|
||||
ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool();
|
||||
Settings::values.cpuopt_return_stack_buffer =
|
||||
ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool();
|
||||
Settings::values.cpuopt_fast_dispatcher =
|
||||
ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool();
|
||||
Settings::values.cpuopt_context_elimination =
|
||||
ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool();
|
||||
Settings::values.cpuopt_const_prop =
|
||||
ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool();
|
||||
Settings::values.cpuopt_misc_ir =
|
||||
ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
|
||||
Settings::values.cpuopt_reduce_misalign_checks =
|
||||
ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
|
||||
}
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
void Config::ReadRendererValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||
|
||||
@@ -829,6 +839,7 @@ void Config::ReadValues() {
|
||||
ReadMiscellaneousValues();
|
||||
}
|
||||
ReadCoreValues();
|
||||
ReadCpuValues();
|
||||
ReadRendererValues();
|
||||
ReadAudioValues();
|
||||
ReadSystemValues();
|
||||
@@ -929,6 +940,7 @@ void Config::SaveValues() {
|
||||
SaveMiscellaneousValues();
|
||||
}
|
||||
SaveCoreValues();
|
||||
SaveCpuValues();
|
||||
SaveRendererValues();
|
||||
SaveAudioValues();
|
||||
SaveSystemValues();
|
||||
@@ -1006,18 +1018,7 @@ void Config::SaveDataStorageValues() {
|
||||
false);
|
||||
WriteSetting(QStringLiteral("gamecard_path"),
|
||||
QString::fromStdString(Settings::values.gamecard_path), QStringLiteral(""));
|
||||
WriteSetting(QStringLiteral("nand_total_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)));
|
||||
WriteSetting(QStringLiteral("nand_user_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)));
|
||||
WriteSetting(QStringLiteral("nand_system_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)));
|
||||
WriteSetting(QStringLiteral("sdmc_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)));
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
@@ -1033,7 +1034,6 @@ void Config::SaveDebuggingValues() {
|
||||
WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
|
||||
WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
|
||||
WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
|
||||
WriteSetting(QStringLiteral("disable_cpu_opt"), Settings::values.disable_cpu_opt, false);
|
||||
WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
|
||||
|
||||
qt_config->endGroup();
|
||||
@@ -1097,6 +1097,32 @@ void Config::SavePathValues() {
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
void Config::SaveCpuValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Cpu"));
|
||||
|
||||
if (global) {
|
||||
WriteSetting(QStringLiteral("cpu_accuracy"),
|
||||
static_cast<int>(Settings::values.cpu_accuracy), 0);
|
||||
|
||||
WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
|
||||
true);
|
||||
WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
|
||||
true);
|
||||
WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"),
|
||||
Settings::values.cpuopt_return_stack_buffer, true);
|
||||
WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"),
|
||||
Settings::values.cpuopt_fast_dispatcher, true);
|
||||
WriteSetting(QStringLiteral("cpuopt_context_elimination"),
|
||||
Settings::values.cpuopt_context_elimination, true);
|
||||
WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true);
|
||||
WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
|
||||
WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
|
||||
Settings::values.cpuopt_reduce_misalign_checks, true);
|
||||
}
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
void Config::SaveRendererValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||
|
||||
@@ -1342,11 +1368,13 @@ void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool
|
||||
|
||||
void Config::Reload() {
|
||||
ReadValues();
|
||||
Settings::Sanitize();
|
||||
// To apply default value changes
|
||||
SaveValues();
|
||||
Settings::Apply();
|
||||
}
|
||||
|
||||
void Config::Save() {
|
||||
Settings::Sanitize();
|
||||
SaveValues();
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ private:
|
||||
void ReadDisabledAddOnValues();
|
||||
void ReadMiscellaneousValues();
|
||||
void ReadPathValues();
|
||||
void ReadCpuValues();
|
||||
void ReadRendererValues();
|
||||
void ReadShortcutValues();
|
||||
void ReadSystemValues();
|
||||
@@ -73,6 +74,7 @@ private:
|
||||
void SaveDisabledAddOnValues();
|
||||
void SaveMiscellaneousValues();
|
||||
void SavePathValues();
|
||||
void SaveCpuValues();
|
||||
void SaveRendererValues();
|
||||
void SaveShortcutValues();
|
||||
void SaveSystemValues();
|
||||
|
||||
@@ -78,6 +78,16 @@
|
||||
<string>Hotkeys</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="ConfigureCpu" name="cpuTab">
|
||||
<attribute name="title">
|
||||
<string>CPU</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="ConfigureCpuDebug" name="cpuDebugTab">
|
||||
<attribute name="title">
|
||||
<string>Debug</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="ConfigureGraphics" name="graphicsTab">
|
||||
<attribute name="title">
|
||||
<string>Graphics</string>
|
||||
@@ -158,6 +168,18 @@
|
||||
<header>configuration/configure_debug.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureCpu</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>configuration/configure_cpu.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureCpuDebug</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>configuration/configure_cpu_debug.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureGraphics</class>
|
||||
<extends>QWidget</extends>
|
||||
|
||||
61
src/yuzu/configuration/configure_cpu.cpp
Normal file
61
src/yuzu/configuration/configure_cpu.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "ui_configure_cpu.h"
|
||||
#include "yuzu/configuration/configure_cpu.h"
|
||||
|
||||
ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) {
|
||||
ui->setupUi(this);
|
||||
|
||||
SetConfiguration();
|
||||
|
||||
connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
|
||||
&ConfigureCpu::AccuracyUpdated);
|
||||
}
|
||||
|
||||
ConfigureCpu::~ConfigureCpu() = default;
|
||||
|
||||
void ConfigureCpu::SetConfiguration() {
|
||||
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
||||
|
||||
ui->accuracy->setEnabled(runtime_lock);
|
||||
ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
|
||||
}
|
||||
|
||||
void ConfigureCpu::AccuracyUpdated(int index) {
|
||||
if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
|
||||
const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
|
||||
tr("CPU Debug Mode is only intended for developer "
|
||||
"use. Are you sure you want to enable this?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (result == QMessageBox::No) {
|
||||
ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureCpu::ApplyConfiguration() {
|
||||
Settings::values.cpu_accuracy =
|
||||
static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex());
|
||||
}
|
||||
|
||||
void ConfigureCpu::changeEvent(QEvent* event) {
|
||||
if (event->type() == QEvent::LanguageChange) {
|
||||
RetranslateUI();
|
||||
}
|
||||
|
||||
QWidget::changeEvent(event);
|
||||
}
|
||||
|
||||
void ConfigureCpu::RetranslateUI() {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
33
src/yuzu/configuration/configure_cpu.h
Normal file
33
src/yuzu/configuration/configure_cpu.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QWidget>
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Ui {
|
||||
class ConfigureCpu;
|
||||
}
|
||||
|
||||
class ConfigureCpu : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigureCpu(QWidget* parent = nullptr);
|
||||
~ConfigureCpu() override;
|
||||
|
||||
void ApplyConfiguration();
|
||||
|
||||
private:
|
||||
void changeEvent(QEvent* event) override;
|
||||
void RetranslateUI();
|
||||
|
||||
void AccuracyUpdated(int index);
|
||||
|
||||
void SetConfiguration();
|
||||
|
||||
std::unique_ptr<Ui::ConfigureCpu> ui;
|
||||
};
|
||||
92
src/yuzu/configuration/configure_cpu.ui
Normal file
92
src/yuzu/configuration/configure_cpu.ui
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfigureCpu</class>
|
||||
<widget class="QWidget" name="ConfigureCpu">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>321</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox">
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel">
|
||||
<property name="text">
|
||||
<string>Accuracy:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="accuracy">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Accurate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enable Debug Mode</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel">
|
||||
<property name="wordWrap">
|
||||
<bool>1</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>We recommend setting accuracy to "Accurate".</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_disable_info">
|
||||
<property name="text">
|
||||
<string>CPU settings are available only when game is not running.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
65
src/yuzu/configuration/configure_cpu_debug.cpp
Normal file
65
src/yuzu/configuration/configure_cpu_debug.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "ui_configure_cpu_debug.h"
|
||||
#include "yuzu/configuration/configure_cpu_debug.h"
|
||||
|
||||
ConfigureCpuDebug::ConfigureCpuDebug(QWidget* parent)
|
||||
: QWidget(parent), ui(new Ui::ConfigureCpuDebug) {
|
||||
ui->setupUi(this);
|
||||
|
||||
SetConfiguration();
|
||||
}
|
||||
|
||||
ConfigureCpuDebug::~ConfigureCpuDebug() = default;
|
||||
|
||||
void ConfigureCpuDebug::SetConfiguration() {
|
||||
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
||||
|
||||
ui->cpuopt_page_tables->setEnabled(runtime_lock);
|
||||
ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables);
|
||||
ui->cpuopt_block_linking->setEnabled(runtime_lock);
|
||||
ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking);
|
||||
ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
|
||||
ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer);
|
||||
ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
|
||||
ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher);
|
||||
ui->cpuopt_context_elimination->setEnabled(runtime_lock);
|
||||
ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination);
|
||||
ui->cpuopt_const_prop->setEnabled(runtime_lock);
|
||||
ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop);
|
||||
ui->cpuopt_misc_ir->setEnabled(runtime_lock);
|
||||
ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir);
|
||||
ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
|
||||
ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks);
|
||||
}
|
||||
|
||||
void ConfigureCpuDebug::ApplyConfiguration() {
|
||||
Settings::values.cpuopt_page_tables = ui->cpuopt_page_tables->isChecked();
|
||||
Settings::values.cpuopt_block_linking = ui->cpuopt_block_linking->isChecked();
|
||||
Settings::values.cpuopt_return_stack_buffer = ui->cpuopt_return_stack_buffer->isChecked();
|
||||
Settings::values.cpuopt_fast_dispatcher = ui->cpuopt_fast_dispatcher->isChecked();
|
||||
Settings::values.cpuopt_context_elimination = ui->cpuopt_context_elimination->isChecked();
|
||||
Settings::values.cpuopt_const_prop = ui->cpuopt_const_prop->isChecked();
|
||||
Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked();
|
||||
Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked();
|
||||
}
|
||||
|
||||
void ConfigureCpuDebug::changeEvent(QEvent* event) {
|
||||
if (event->type() == QEvent::LanguageChange) {
|
||||
RetranslateUI();
|
||||
}
|
||||
|
||||
QWidget::changeEvent(event);
|
||||
}
|
||||
|
||||
void ConfigureCpuDebug::RetranslateUI() {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
31
src/yuzu/configuration/configure_cpu_debug.h
Normal file
31
src/yuzu/configuration/configure_cpu_debug.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QWidget>
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Ui {
|
||||
class ConfigureCpuDebug;
|
||||
}
|
||||
|
||||
class ConfigureCpuDebug : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigureCpuDebug(QWidget* parent = nullptr);
|
||||
~ConfigureCpuDebug() override;
|
||||
|
||||
void ApplyConfiguration();
|
||||
|
||||
private:
|
||||
void changeEvent(QEvent* event) override;
|
||||
void RetranslateUI();
|
||||
|
||||
void SetConfiguration();
|
||||
|
||||
std::unique_ptr<Ui::ConfigureCpuDebug> ui;
|
||||
};
|
||||
174
src/yuzu/configuration/configure_cpu_debug.ui
Normal file
174
src/yuzu/configuration/configure_cpu_debug.ui
Normal file
@@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfigureCpuDebug</class>
|
||||
<widget class="QWidget" name="ConfigureCpuDebug">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>321</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox">
|
||||
<property name="title">
|
||||
<string>Toggle CPU Optimizations</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel">
|
||||
<property name="wordWrap">
|
||||
<bool>1</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>
|
||||
<div>
|
||||
<b>For debugging only.</b>
|
||||
<br>
|
||||
If you're not sure what these do, keep all of these enabled.
|
||||
<br>
|
||||
These settings only take effect when CPU Accuracy is "Debug Mode".
|
||||
</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_page_tables">
|
||||
<property name="text">
|
||||
<string>Enable inline page tables</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div>
|
||||
<div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div>
|
||||
<div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_block_linking">
|
||||
<property name="text">
|
||||
<string>Enable block linking</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_return_stack_buffer">
|
||||
<property name="text">
|
||||
<string>Enable return stack buffer</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div>This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_fast_dispatcher">
|
||||
<property name="text">
|
||||
<string>Enable fast dispatcher</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div>Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_context_elimination">
|
||||
<property name="text">
|
||||
<string>Enable context elimination</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_const_prop">
|
||||
<property name="text">
|
||||
<string>Enable constant propagation</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div>Enables IR optimizations that involve constant propagation.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_misc_ir">
|
||||
<property name="text">
|
||||
<string>Enable miscellaneous optimizations</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div>Enables miscellaneous IR optimizations.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cpuopt_reduce_misalign_checks">
|
||||
<property name="text">
|
||||
<string>Enable misalignment check reduction</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>
|
||||
<div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div>
|
||||
<div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div>
|
||||
</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_disable_info">
|
||||
<property name="text">
|
||||
<string>CPU settings are available only when game is not running.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -36,7 +36,6 @@ void ConfigureDebug::SetConfiguration() {
|
||||
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
|
||||
ui->reporting_services->setChecked(Settings::values.reporting_services);
|
||||
ui->quest_flag->setChecked(Settings::values.quest_flag);
|
||||
ui->disable_cpu_opt->setChecked(Settings::values.disable_cpu_opt);
|
||||
ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
|
||||
ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
@@ -51,7 +50,6 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
|
||||
Settings::values.reporting_services = ui->reporting_services->isChecked();
|
||||
Settings::values.quest_flag = ui->quest_flag->isChecked();
|
||||
Settings::values.disable_cpu_opt = ui->disable_cpu_opt->isChecked();
|
||||
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
|
||||
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
|
||||
Debugger::ToggleConsole();
|
||||
|
||||
@@ -228,13 +228,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="disable_cpu_opt">
|
||||
<property name="text">
|
||||
<string>Disable CPU JIT optimizations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -42,6 +42,8 @@ void ConfigureDialog::ApplyConfiguration() {
|
||||
ui->filesystemTab->applyConfiguration();
|
||||
ui->inputTab->ApplyConfiguration();
|
||||
ui->hotkeysTab->ApplyConfiguration(registry);
|
||||
ui->cpuTab->ApplyConfiguration();
|
||||
ui->cpuDebugTab->ApplyConfiguration();
|
||||
ui->graphicsTab->ApplyConfiguration();
|
||||
ui->graphicsAdvancedTab->ApplyConfiguration();
|
||||
ui->audioTab->ApplyConfiguration();
|
||||
@@ -76,9 +78,10 @@ void ConfigureDialog::RetranslateUI() {
|
||||
Q_DECLARE_METATYPE(QList<QWidget*>);
|
||||
|
||||
void ConfigureDialog::PopulateSelectionList() {
|
||||
const std::array<std::pair<QString, QList<QWidget*>>, 5> items{
|
||||
const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
|
||||
{{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}},
|
||||
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
|
||||
{tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}},
|
||||
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
|
||||
{tr("Audio"), {ui->audioTab}},
|
||||
{tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
|
||||
@@ -107,6 +110,8 @@ void ConfigureDialog::UpdateVisibleTabs() {
|
||||
{ui->profileManagerTab, tr("Profiles")},
|
||||
{ui->inputTab, tr("Input")},
|
||||
{ui->hotkeysTab, tr("Hotkeys")},
|
||||
{ui->cpuTab, tr("CPU")},
|
||||
{ui->cpuDebugTab, tr("Debug")},
|
||||
{ui->graphicsTab, tr("Graphics")},
|
||||
{ui->graphicsAdvancedTab, tr("Advanced")},
|
||||
{ui->audioTab, tr("Audio")},
|
||||
|
||||
@@ -11,19 +11,6 @@
|
||||
#include "yuzu/configuration/configure_filesystem.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void SetComboBoxFromData(QComboBox* combo_box, T data) {
|
||||
const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data)));
|
||||
if (index >= combo_box->count() || index < 0)
|
||||
return;
|
||||
|
||||
combo_box->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) {
|
||||
ui->setupUi(this);
|
||||
@@ -73,11 +60,6 @@ void ConfigureFilesystem::setConfiguration() {
|
||||
|
||||
ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
|
||||
|
||||
SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size);
|
||||
SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size);
|
||||
SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size);
|
||||
SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size);
|
||||
|
||||
UpdateEnabledControls();
|
||||
}
|
||||
|
||||
@@ -98,15 +80,6 @@ void ConfigureFilesystem::applyConfiguration() {
|
||||
Settings::values.dump_nso = ui->dump_nso->isChecked();
|
||||
|
||||
UISettings::values.cache_game_list = ui->cache_game_list->isChecked();
|
||||
|
||||
Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
|
||||
ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong());
|
||||
Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
|
||||
ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong());
|
||||
Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
|
||||
ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong());
|
||||
Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
|
||||
ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong());
|
||||
}
|
||||
|
||||
void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) {
|
||||
|
||||
@@ -115,127 +115,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Storage Sizes</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>SD Card</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>System NAND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="sysnand_size">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2.5 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="sdmc_size">
|
||||
<property name="currentText">
|
||||
<string>32 GB</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>32 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>64 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>128 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>256 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 TB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="usrnand_size">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>26 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>User NAND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>NAND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="nand_size">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>29.1 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
|
||||
@@ -65,6 +65,8 @@ void ConfigureGeneral::ApplyConfiguration() {
|
||||
Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
|
||||
Qt::Checked);
|
||||
Settings::values.frame_limit.SetValue(ui->frame_limit->value());
|
||||
}
|
||||
if (Settings::values.use_multi_core.UsingGlobal()) {
|
||||
Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -531,8 +531,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
UISettings::GameDir& game_dir =
|
||||
*selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>();
|
||||
|
||||
QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up"));
|
||||
QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down "));
|
||||
QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up"));
|
||||
QAction* move_down = context_menu.addAction(tr("\u25bc Move Down"));
|
||||
QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
|
||||
|
||||
const int row = selected.row();
|
||||
|
||||
72
src/yuzu/install_dialog.cpp
Normal file
72
src/yuzu/install_dialog.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileInfo>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include "yuzu/install_dialog.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
|
||||
InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) {
|
||||
file_list = new QListWidget(this);
|
||||
|
||||
for (const QString& file : files) {
|
||||
QListWidgetItem* item = new QListWidgetItem(QFileInfo(file).fileName(), file_list);
|
||||
item->setData(Qt::UserRole, file);
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(Qt::Checked);
|
||||
}
|
||||
|
||||
file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 11) / 10);
|
||||
|
||||
vbox_layout = new QVBoxLayout;
|
||||
|
||||
hbox_layout = new QHBoxLayout;
|
||||
|
||||
description = new QLabel(tr("Please confirm these are the files you wish to install."));
|
||||
|
||||
update_description =
|
||||
new QLabel(tr("Installing an Update or DLC will overwrite the previously installed one."));
|
||||
|
||||
buttons = new QDialogButtonBox;
|
||||
buttons->addButton(QDialogButtonBox::Cancel);
|
||||
buttons->addButton(tr("Install"), QDialogButtonBox::AcceptRole);
|
||||
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject);
|
||||
|
||||
hbox_layout->addWidget(buttons);
|
||||
|
||||
vbox_layout->addWidget(description);
|
||||
vbox_layout->addWidget(update_description);
|
||||
vbox_layout->addWidget(file_list);
|
||||
vbox_layout->addLayout(hbox_layout);
|
||||
|
||||
setLayout(vbox_layout);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setWindowTitle(tr("Install Files to NAND"));
|
||||
}
|
||||
|
||||
InstallDialog::~InstallDialog() = default;
|
||||
|
||||
QStringList InstallDialog::GetFiles() const {
|
||||
QStringList files;
|
||||
|
||||
for (int i = 0; i < file_list->count(); ++i) {
|
||||
const QListWidgetItem* item = file_list->item(i);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
files.append(item->data(Qt::UserRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
int InstallDialog::GetMinimumWidth() const {
|
||||
return file_list->width();
|
||||
}
|
||||
36
src/yuzu/install_dialog.h
Normal file
36
src/yuzu/install_dialog.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QCheckBox;
|
||||
class QDialogButtonBox;
|
||||
class QHBoxLayout;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
class QVBoxLayout;
|
||||
|
||||
class InstallDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InstallDialog(QWidget* parent, const QStringList& files);
|
||||
~InstallDialog() override;
|
||||
|
||||
QStringList GetFiles() const;
|
||||
bool ShouldOverwriteFiles() const;
|
||||
int GetMinimumWidth() const;
|
||||
|
||||
private:
|
||||
QListWidget* file_list;
|
||||
|
||||
QVBoxLayout* vbox_layout;
|
||||
QHBoxLayout* hbox_layout;
|
||||
|
||||
QLabel* description;
|
||||
QLabel* update_description;
|
||||
QDialogButtonBox* buttons;
|
||||
};
|
||||
@@ -107,6 +107,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||
#include "yuzu/game_list.h"
|
||||
#include "yuzu/game_list_p.h"
|
||||
#include "yuzu/hotkeys.h"
|
||||
#include "yuzu/install_dialog.h"
|
||||
#include "yuzu/loading_screen.h"
|
||||
#include "yuzu/main.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
@@ -278,17 +279,21 @@ GMainWindow::~GMainWindow() {
|
||||
}
|
||||
|
||||
void GMainWindow::ProfileSelectorSelectProfile() {
|
||||
QtProfileSelectionDialog dialog(this);
|
||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
||||
dialog.setWindowModality(Qt::WindowModal);
|
||||
if (dialog.exec() == QDialog::Rejected) {
|
||||
emit ProfileSelectorFinishedSelection(std::nullopt);
|
||||
return;
|
||||
const Service::Account::ProfileManager manager;
|
||||
int index = 0;
|
||||
if (manager.GetUserCount() != 1) {
|
||||
QtProfileSelectionDialog dialog(this);
|
||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
||||
dialog.setWindowModality(Qt::WindowModal);
|
||||
if (dialog.exec() == QDialog::Rejected) {
|
||||
emit ProfileSelectorFinishedSelection(std::nullopt);
|
||||
return;
|
||||
}
|
||||
index = dialog.GetIndex();
|
||||
}
|
||||
|
||||
Service::Account::ProfileManager manager;
|
||||
const auto uuid = manager.GetUser(static_cast<std::size_t>(dialog.GetIndex()));
|
||||
const auto uuid = manager.GetUser(static_cast<std::size_t>(index));
|
||||
if (!uuid.has_value()) {
|
||||
emit ProfileSelectorFinishedSelection(std::nullopt);
|
||||
return;
|
||||
@@ -847,6 +852,9 @@ void GMainWindow::ConnectWidgetEvents() {
|
||||
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
|
||||
&GMainWindow::OnGameListOpenPerGameProperties);
|
||||
|
||||
connect(this, &GMainWindow::UpdateInstallProgress, this,
|
||||
&GMainWindow::IncrementInstallProgress);
|
||||
|
||||
connect(this, &GMainWindow::EmulationStarting, render_window,
|
||||
&GRenderWindow::OnEmulationStarting);
|
||||
connect(this, &GMainWindow::EmulationStopping, render_window,
|
||||
@@ -1593,187 +1601,255 @@ void GMainWindow::OnMenuLoadFolder() {
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::IncrementInstallProgress() {
|
||||
install_progress->setValue(install_progress->value() + 1);
|
||||
}
|
||||
|
||||
void GMainWindow::OnMenuInstallToNAND() {
|
||||
const QString file_filter =
|
||||
tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
|
||||
"(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge "
|
||||
"(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge "
|
||||
"Image (*.xci)");
|
||||
QString filename = QFileDialog::getOpenFileName(this, tr("Install File"),
|
||||
UISettings::values.roms_path, file_filter);
|
||||
|
||||
if (filename.isEmpty()) {
|
||||
QStringList filenames = QFileDialog::getOpenFileNames(
|
||||
this, tr("Install Files"), UISettings::values.roms_path, file_filter);
|
||||
|
||||
if (filenames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
InstallDialog installDialog(this, filenames);
|
||||
if (installDialog.exec() == QDialog::Rejected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QStringList files = installDialog.GetFiles();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int remaining = filenames.size();
|
||||
|
||||
// This would only overflow above 2^43 bytes (8.796 TB)
|
||||
int total_size = 0;
|
||||
for (const QString& file : files) {
|
||||
total_size += static_cast<int>(QFile(file).size() / 0x1000);
|
||||
}
|
||||
if (total_size < 0) {
|
||||
LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
|
||||
QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
|
||||
QStringList failed_files{}; // Files that failed to install due to errors
|
||||
|
||||
ui.action_Install_File_NAND->setEnabled(false);
|
||||
|
||||
install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this);
|
||||
install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
|
||||
~Qt::WindowMaximizeButtonHint);
|
||||
install_progress->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40);
|
||||
install_progress->show();
|
||||
|
||||
for (const QString& file : files) {
|
||||
install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining));
|
||||
install_progress->setLabelText(
|
||||
tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
|
||||
|
||||
QFuture<InstallResult> future;
|
||||
InstallResult result;
|
||||
|
||||
if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
|
||||
file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
||||
|
||||
future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); });
|
||||
|
||||
while (!future.isFinished()) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
result = future.result();
|
||||
|
||||
} else {
|
||||
result = InstallNCA(file);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
switch (result) {
|
||||
case InstallResult::Success:
|
||||
new_files.append(QFileInfo(file).fileName());
|
||||
break;
|
||||
case InstallResult::Overwrite:
|
||||
overwritten_files.append(QFileInfo(file).fileName());
|
||||
break;
|
||||
case InstallResult::Failure:
|
||||
failed_files.append(QFileInfo(file).fileName());
|
||||
break;
|
||||
}
|
||||
|
||||
--remaining;
|
||||
}
|
||||
|
||||
install_progress->close();
|
||||
|
||||
const QString install_results =
|
||||
(new_files.isEmpty() ? QStringLiteral("")
|
||||
: tr("%n file(s) were newly installed\n", "", new_files.size())) +
|
||||
(overwritten_files.isEmpty()
|
||||
? QStringLiteral("")
|
||||
: tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
|
||||
(failed_files.isEmpty() ? QStringLiteral("")
|
||||
: tr("%n file(s) failed to install\n", "", failed_files.size()));
|
||||
|
||||
QMessageBox::information(this, tr("Install Results"), install_results);
|
||||
game_list->PopulateAsync(UISettings::values.game_dirs);
|
||||
FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
|
||||
"game_list");
|
||||
ui.action_Install_File_NAND->setEnabled(true);
|
||||
}
|
||||
|
||||
InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
|
||||
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
|
||||
const FileSys::VirtualFile& dest, std::size_t block_size) {
|
||||
if (src == nullptr || dest == nullptr)
|
||||
if (src == nullptr || dest == nullptr) {
|
||||
return false;
|
||||
if (!dest->Resize(src->GetSize()))
|
||||
}
|
||||
if (!dest->Resize(src->GetSize())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array<u8, 0x1000> buffer{};
|
||||
const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size());
|
||||
|
||||
QProgressDialog progress(
|
||||
tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())),
|
||||
tr("Cancel"), 0, progress_maximum, this);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
|
||||
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
||||
if (progress.wasCanceled()) {
|
||||
if (install_progress->wasCanceled()) {
|
||||
dest->Resize(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int progress_value = static_cast<int>(i / buffer.size());
|
||||
progress.setValue(progress_value);
|
||||
emit UpdateInstallProgress();
|
||||
|
||||
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
||||
dest->Write(buffer.data(), read, i);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto success = [this]() {
|
||||
QMessageBox::information(this, tr("Successfully Installed"),
|
||||
tr("The file was successfully installed."));
|
||||
game_list->PopulateAsync(UISettings::values.game_dirs);
|
||||
FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
|
||||
DIR_SEP + "game_list");
|
||||
};
|
||||
|
||||
const auto failed = [this]() {
|
||||
QMessageBox::warning(
|
||||
this, tr("Failed to Install"),
|
||||
tr("There was an error while attempting to install the provided file. It "
|
||||
"could have an incorrect format or be missing metadata. Please "
|
||||
"double-check your file and try again."));
|
||||
};
|
||||
|
||||
const auto overwrite = [this]() {
|
||||
return QMessageBox::question(this, tr("Failed to Install"),
|
||||
tr("The file you are attempting to install already exists "
|
||||
"in the cache. Would you like to overwrite it?")) ==
|
||||
QMessageBox::Yes;
|
||||
};
|
||||
|
||||
if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
|
||||
filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
||||
std::shared_ptr<FileSys::NSP> nsp;
|
||||
if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
||||
nsp = std::make_shared<FileSys::NSP>(
|
||||
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
||||
if (nsp->IsExtractedType())
|
||||
failed();
|
||||
} else {
|
||||
const auto xci = std::make_shared<FileSys::XCI>(
|
||||
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
||||
nsp = xci->GetSecurePartitionNSP();
|
||||
}
|
||||
|
||||
if (nsp->GetStatus() != Loader::ResultStatus::Success) {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
const auto res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nsp, false, qt_raw_copy);
|
||||
if (res == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else {
|
||||
if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
||||
if (overwrite()) {
|
||||
const auto res2 = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nsp, true, qt_raw_copy);
|
||||
if (res2 == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else {
|
||||
failed();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
failed();
|
||||
}
|
||||
std::shared_ptr<FileSys::NSP> nsp;
|
||||
if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
||||
nsp = std::make_shared<FileSys::NSP>(
|
||||
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
||||
if (nsp->IsExtractedType()) {
|
||||
return InstallResult::Failure;
|
||||
}
|
||||
} else {
|
||||
const auto nca = std::make_shared<FileSys::NCA>(
|
||||
const auto xci = std::make_shared<FileSys::XCI>(
|
||||
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
||||
const auto id = nca->GetStatus();
|
||||
nsp = xci->GetSecurePartitionNSP();
|
||||
}
|
||||
|
||||
// Game updates necessary are missing base RomFS
|
||||
if (id != Loader::ResultStatus::Success &&
|
||||
id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
||||
failed();
|
||||
return;
|
||||
if (nsp->GetStatus() != Loader::ResultStatus::Success) {
|
||||
return InstallResult::Failure;
|
||||
}
|
||||
const auto res =
|
||||
Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
|
||||
*nsp, true, qt_raw_copy);
|
||||
if (res == FileSys::InstallResult::Success) {
|
||||
return InstallResult::Success;
|
||||
} else if (res == FileSys::InstallResult::OverwriteExisting) {
|
||||
return InstallResult::Overwrite;
|
||||
} else {
|
||||
return InstallResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
InstallResult GMainWindow::InstallNCA(const QString& filename) {
|
||||
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
|
||||
const FileSys::VirtualFile& dest, std::size_t block_size) {
|
||||
if (src == nullptr || dest == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!dest->Resize(src->GetSize())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QStringList tt_options{tr("System Application"),
|
||||
tr("System Archive"),
|
||||
tr("System Application Update"),
|
||||
tr("Firmware Package (Type A)"),
|
||||
tr("Firmware Package (Type B)"),
|
||||
tr("Game"),
|
||||
tr("Game Update"),
|
||||
tr("Game DLC"),
|
||||
tr("Delta Title")};
|
||||
bool ok;
|
||||
const auto item = QInputDialog::getItem(
|
||||
this, tr("Select NCA Install Type..."),
|
||||
tr("Please select the type of title you would like to install this NCA as:\n(In "
|
||||
"most instances, the default 'Game' is fine.)"),
|
||||
tt_options, 5, false, &ok);
|
||||
std::array<u8, 0x1000> buffer{};
|
||||
|
||||
auto index = tt_options.indexOf(item);
|
||||
if (!ok || index == -1) {
|
||||
QMessageBox::warning(this, tr("Failed to Install"),
|
||||
tr("The title type you selected for the NCA is invalid."));
|
||||
return;
|
||||
}
|
||||
|
||||
// If index is equal to or past Game, add the jump in TitleType.
|
||||
if (index >= 5) {
|
||||
index += static_cast<size_t>(FileSys::TitleType::Application) -
|
||||
static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
|
||||
}
|
||||
|
||||
FileSys::InstallResult res;
|
||||
if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
|
||||
res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
|
||||
qt_raw_copy);
|
||||
} else {
|
||||
res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetSystemNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
|
||||
qt_raw_copy);
|
||||
}
|
||||
|
||||
if (res == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
||||
if (overwrite()) {
|
||||
const auto res2 = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index),
|
||||
true, qt_raw_copy);
|
||||
if (res2 == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else {
|
||||
failed();
|
||||
}
|
||||
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
||||
if (install_progress->wasCanceled()) {
|
||||
dest->Resize(0);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
failed();
|
||||
|
||||
emit UpdateInstallProgress();
|
||||
|
||||
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
||||
dest->Write(buffer.data(), read, i);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto nca =
|
||||
std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
||||
const auto id = nca->GetStatus();
|
||||
|
||||
// Game updates necessary are missing base RomFS
|
||||
if (id != Loader::ResultStatus::Success &&
|
||||
id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
||||
return InstallResult::Failure;
|
||||
}
|
||||
|
||||
const QStringList tt_options{tr("System Application"),
|
||||
tr("System Archive"),
|
||||
tr("System Application Update"),
|
||||
tr("Firmware Package (Type A)"),
|
||||
tr("Firmware Package (Type B)"),
|
||||
tr("Game"),
|
||||
tr("Game Update"),
|
||||
tr("Game DLC"),
|
||||
tr("Delta Title")};
|
||||
bool ok;
|
||||
const auto item = QInputDialog::getItem(
|
||||
this, tr("Select NCA Install Type..."),
|
||||
tr("Please select the type of title you would like to install this NCA as:\n(In "
|
||||
"most instances, the default 'Game' is fine.)"),
|
||||
tt_options, 5, false, &ok);
|
||||
|
||||
auto index = tt_options.indexOf(item);
|
||||
if (!ok || index == -1) {
|
||||
QMessageBox::warning(this, tr("Failed to Install"),
|
||||
tr("The title type you selected for the NCA is invalid."));
|
||||
return InstallResult::Failure;
|
||||
}
|
||||
|
||||
// If index is equal to or past Game, add the jump in TitleType.
|
||||
if (index >= 5) {
|
||||
index += static_cast<size_t>(FileSys::TitleType::Application) -
|
||||
static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
|
||||
}
|
||||
|
||||
FileSys::InstallResult res;
|
||||
if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
|
||||
res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
||||
} else {
|
||||
res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetSystemNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
||||
}
|
||||
|
||||
if (res == FileSys::InstallResult::Success) {
|
||||
return InstallResult::Success;
|
||||
} else if (res == FileSys::InstallResult::OverwriteExisting) {
|
||||
return InstallResult::Overwrite;
|
||||
} else {
|
||||
return InstallResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class MicroProfileDialog;
|
||||
class ProfilerWidget;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QProgressDialog;
|
||||
class WaitTreeWidget;
|
||||
enum class GameListOpenTarget;
|
||||
class GameListPlaceholder;
|
||||
@@ -47,6 +48,12 @@ enum class EmulatedDirectoryTarget {
|
||||
SDMC,
|
||||
};
|
||||
|
||||
enum class InstallResult {
|
||||
Success,
|
||||
Overwrite,
|
||||
Failure,
|
||||
};
|
||||
|
||||
enum class ReinitializeKeyBehavior {
|
||||
NoWarning,
|
||||
Warning,
|
||||
@@ -102,6 +109,8 @@ signals:
|
||||
// Signal that tells widgets to update icons to use the current theme
|
||||
void UpdateThemedIcons();
|
||||
|
||||
void UpdateInstallProgress();
|
||||
|
||||
void ErrorDisplayFinished();
|
||||
|
||||
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
|
||||
@@ -198,6 +207,7 @@ private slots:
|
||||
void OnGameListOpenPerGameProperties(const std::string& file);
|
||||
void OnMenuLoadFile();
|
||||
void OnMenuLoadFolder();
|
||||
void IncrementInstallProgress();
|
||||
void OnMenuInstallToNAND();
|
||||
void OnMenuRecentFile();
|
||||
void OnConfigure();
|
||||
@@ -218,6 +228,8 @@ private slots:
|
||||
|
||||
private:
|
||||
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
|
||||
InstallResult InstallNSPXCI(const QString& filename);
|
||||
InstallResult InstallNCA(const QString& filename);
|
||||
void UpdateWindowTitle(const std::string& title_name = {},
|
||||
const std::string& title_version = {});
|
||||
void UpdateStatusBar();
|
||||
@@ -272,6 +284,9 @@ private:
|
||||
|
||||
HotkeyRegistry hotkey_registry;
|
||||
|
||||
// Install progress dialog
|
||||
QProgressDialog* install_progress;
|
||||
|
||||
protected:
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Install File to NAND...</string>
|
||||
<string>Install Files to NAND...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Load_File">
|
||||
|
||||
@@ -335,15 +335,6 @@ void Config::ReadValues() {
|
||||
Settings::values.gamecard_current_game =
|
||||
sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
|
||||
Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
|
||||
Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger(
|
||||
"Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB)));
|
||||
Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger(
|
||||
"Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB)));
|
||||
Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
|
||||
sdl2_config->GetInteger("Data Storage", "nand_system_size",
|
||||
static_cast<long>(Settings::NANDSystemSize::S2_5GB)));
|
||||
Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger(
|
||||
"Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB)));
|
||||
|
||||
// System
|
||||
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
|
||||
@@ -437,8 +428,6 @@ void Config::ReadValues() {
|
||||
Settings::values.reporting_services =
|
||||
sdl2_config->GetBoolean("Debugging", "reporting_services", false);
|
||||
Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
|
||||
Settings::values.disable_cpu_opt =
|
||||
sdl2_config->GetBoolean("Debugging", "disable_cpu_opt", false);
|
||||
Settings::values.disable_macro_jit =
|
||||
sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
|
||||
|
||||
|
||||
@@ -97,6 +97,39 @@ udp_pad_index=
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
use_multi_core=
|
||||
|
||||
[Cpu]
|
||||
# Enable inline page tables optimization (faster guest memory access)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_page_tables =
|
||||
|
||||
# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_block_linking =
|
||||
|
||||
# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_return_stack_buffer =
|
||||
|
||||
# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_fast_dispatcher =
|
||||
|
||||
# Enable context elimination CPU Optimization (reduce host memory use for guest context)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_context_elimination =
|
||||
|
||||
# Enable constant propagation CPU optimization (basic IR optimization)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_const_prop =
|
||||
|
||||
# Enable miscellaneous CPU optimizations (basic IR optimization)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_misc_ir =
|
||||
|
||||
# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_reduce_misalign_checks =
|
||||
|
||||
[Renderer]
|
||||
# Which backend API to use.
|
||||
# 0 (default): OpenGL, 1: Vulkan
|
||||
@@ -283,9 +316,6 @@ dump_nso=false
|
||||
# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
|
||||
# false: Retail/Normal Mode (default), true: Kiosk Mode
|
||||
quest_flag =
|
||||
# Determines whether or not JIT CPU optimizations are enabled
|
||||
# false: Optimizations Enabled, true: Optimizations Disabled
|
||||
disable_cpu_opt =
|
||||
# Enables/Disables the macro JIT compiler
|
||||
disable_macro_jit=false
|
||||
|
||||
|
||||
@@ -12,6 +12,39 @@ const char* sdl2_config_file = R"(
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
use_multi_core=
|
||||
|
||||
[Cpu]
|
||||
# Enable inline page tables optimization (faster guest memory access)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_page_tables =
|
||||
|
||||
# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_block_linking =
|
||||
|
||||
# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_return_stack_buffer =
|
||||
|
||||
# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_fast_dispatcher =
|
||||
|
||||
# Enable context elimination CPU Optimization (reduce host memory use for guest context)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_context_elimination =
|
||||
|
||||
# Enable constant propagation CPU optimization (basic IR optimization)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_const_prop =
|
||||
|
||||
# Enable miscellaneous CPU optimizations (basic IR optimization)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_misc_ir =
|
||||
|
||||
# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_reduce_misalign_checks =
|
||||
|
||||
[Renderer]
|
||||
# Whether to use software or hardware rendering.
|
||||
# 0: Software, 1 (default): Hardware
|
||||
|
||||
Reference in New Issue
Block a user