Compare commits
194 Commits
android-27
...
android-37
Author | SHA1 | Date | |
---|---|---|---|
0f6f7fd552 | |||
26ff214719 | |||
640f7cd945 | |||
1ed9e8812b | |||
9d3a293a4e | |||
3d6ce9dd2b | |||
023b9b38cc | |||
6a43aff745 | |||
1e394c6cdf | |||
37b278a9a8 | |||
83eee1d226 | |||
84cb20bc72 | |||
85e3575496 | |||
7f55c377b0 | |||
9893a4d918 | |||
bed2fc8707 | |||
8d2f0dc707 | |||
cb0b8442f0 | |||
089e385944 | |||
0d470b57ed | |||
755f45a522 | |||
4533769f7f | |||
00d9a9c44e | |||
35bdd5fff3 | |||
7707768f80 | |||
ae19eb1e10 | |||
a09507f271 | |||
dfb7fc8293 | |||
369fcadf08 | |||
4bd4a95d84 | |||
cd80cbc420 | |||
c7c44dc238 | |||
dd1cbd9c56 | |||
096644c01c | |||
fca7d975fd | |||
32b4d63a5b | |||
09e265c116 | |||
36aca262e3 | |||
d6d43e11a3 | |||
9d6f8e88b2 | |||
7aa848080d | |||
55c0b55d1d | |||
d90c622549 | |||
05c8063ac1 | |||
195403c87c | |||
1bc0b673aa | |||
397333b2d5 | |||
b1716a9e14 | |||
ab2921121e | |||
f84e7b4656 | |||
fc1bb93b01 | |||
fb7da1fa11 | |||
85ed10f31f | |||
33d118509a | |||
1d4f813c6a | |||
17b9c1e171 | |||
2911988b85 | |||
ffb384463f | |||
b54c3fba68 | |||
b55a763618 | |||
8e91554e11 | |||
3211623192 | |||
b02e7eea78 | |||
1e093767a8 | |||
267f3c7905 | |||
35872ad95b | |||
127b3da0f1 | |||
ff6a5031d5 | |||
07e8477f5a | |||
ef6406a666 | |||
a14d2a6f83 | |||
c1717b3f47 | |||
ca8509d205 | |||
e7f01128f1 | |||
ecc1feff64 | |||
52cc7b438b | |||
9186f08c3c | |||
8497fb0a04 | |||
54d58130a0 | |||
926f3e3d3e | |||
9de50d6194 | |||
7f708e8d77 | |||
d1de1c3bed | |||
21723879e7 | |||
b2438f1fb7 | |||
ad645c29a4 | |||
62ffaa730f | |||
8b28aa45b9 | |||
8366736b67 | |||
7ffbffe170 | |||
02c48a80f6 | |||
fdbeb84168 | |||
81a96bafe2 | |||
3a7705e774 | |||
69bc8ea148 | |||
3f0cc544cf | |||
c97cbd089b | |||
246740f102 | |||
89f89cf1df | |||
ab795fe0e2 | |||
ee32b17782 | |||
916c6cd1a0 | |||
57a00e01d6 | |||
a7ee9d999f | |||
6935332cba | |||
3240d199a2 | |||
a0883526d6 | |||
7c52bb2772 | |||
27e53990ed | |||
b4f2ad3ff5 | |||
3b0650b70d | |||
512fb3abff | |||
11e7e1b8ce | |||
4903f40efe | |||
04d4b6ab80 | |||
02265f19d9 | |||
7515c502c5 | |||
79024bb955 | |||
c5f8b909ec | |||
0193add060 | |||
2fba913d0b | |||
fe6e765b2d | |||
47d870b11f | |||
b86171d2b5 | |||
81e9cf0934 | |||
163f229d26 | |||
681ebcf4a5 | |||
78b2709373 | |||
8c17a945f7 | |||
d146dd9d12 | |||
9e3c94bb3d | |||
f7948b7b64 | |||
25cea2ef27 | |||
9a2a92673c | |||
d7dd023409 | |||
d373cc3d3f | |||
e6d65bf61c | |||
cd1d8adc49 | |||
09f61656e3 | |||
81860b4317 | |||
b570b719de | |||
3d932416e3 | |||
7734127f9e | |||
3281ea935f | |||
217fa04080 | |||
3337250746 | |||
daa31121ee | |||
c5a3642cb6 | |||
86ed82cdde | |||
432f68ad29 | |||
88d3de4e85 | |||
f055f2dcf4 | |||
4ff8255e4a | |||
4c4bc134a9 | |||
8e15146026 | |||
56960bf9f8 | |||
b11a2a206f | |||
cdb5dea269 | |||
df2bd251fa | |||
97674bc888 | |||
def00e8c55 | |||
23f874ae60 | |||
c1748b229a | |||
8c03ae793e | |||
e2de48f14b | |||
827082c5ac | |||
c530532de7 | |||
d3d9c3568e | |||
464aad52cd | |||
ea4afbfc54 | |||
640e7db60e | |||
f66d617107 | |||
d35577d3ed | |||
39a1ffbb91 | |||
d72ff01726 | |||
9a844bbf0c | |||
3a7a5edcea | |||
05c26411a3 | |||
a4de202cbd | |||
cfb63c68db | |||
bafd569b47 | |||
f8435d676f | |||
75d7e40113 | |||
4a825268d6 | |||
4f545e3024 | |||
a007ac6b9c | |||
b11b4be7cb | |||
d3b94d64d4 | |||
e5b981e1e4 | |||
60773194a0 | |||
e7543e8b84 | |||
4133165607 | |||
5ccfaf0517 | |||
5cffa34288 |
@ -3,4 +3,4 @@
|
||||
|
||||
[codespell]
|
||||
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
|
||||
ignore-words-list = aci,allright,ba,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
|
||||
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
|
||||
|
@ -48,7 +48,7 @@ It is written in C++ with portability in mind, and we actively maintain builds f
|
||||
|
||||
The emulator is capable of running most commercial games at full speed, provided you meet the [necessary hardware requirements](https://yuzu-emu.org/help/quickstart/#hardware-requirements).
|
||||
|
||||
For a full list of games yuzu support, please visit our [Compatibility page](https://yuzu-emu.org/game/)
|
||||
For a full list of games yuzu supports, please visit our [Compatibility page](https://yuzu-emu.org/game/).
|
||||
|
||||
Check out our [website](https://yuzu-emu.org/) for the latest news on exciting features, monthly progress reports, and more!
|
||||
|
||||
|
@ -35,6 +35,7 @@ if (MSVC)
|
||||
# /volatile:iso - Use strict standards-compliant volatile semantics.
|
||||
# /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
|
||||
# /Zc:inline - Let codegen omit inline functions in object files
|
||||
# /Zc:preprocessor - Enable standards-conforming preprocessor
|
||||
# /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null
|
||||
# /GT - Supports fiber safety for data allocated using static thread-local storage
|
||||
add_compile_options(
|
||||
@ -48,6 +49,7 @@ if (MSVC)
|
||||
/volatile:iso
|
||||
/Zc:externConstexpr
|
||||
/Zc:inline
|
||||
/Zc:preprocessor
|
||||
/Zc:throwingNew
|
||||
/GT
|
||||
|
||||
|
@ -150,15 +150,17 @@ void Config::ReadValues() {
|
||||
if (rng_seed_enabled) {
|
||||
Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0));
|
||||
} else {
|
||||
Settings::values.rng_seed.SetValue(std::nullopt);
|
||||
Settings::values.rng_seed.SetValue(0);
|
||||
}
|
||||
Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled);
|
||||
|
||||
const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false);
|
||||
if (custom_rtc_enabled) {
|
||||
Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0);
|
||||
} else {
|
||||
Settings::values.custom_rtc = std::nullopt;
|
||||
Settings::values.custom_rtc = 0;
|
||||
}
|
||||
Settings::values.custom_rtc_enabled = custom_rtc_enabled;
|
||||
|
||||
ReadSetting("System", Settings::values.language_index);
|
||||
ReadSetting("System", Settings::values.region_index);
|
||||
@ -167,7 +169,7 @@ void Config::ReadValues() {
|
||||
|
||||
// Core
|
||||
ReadSetting("Core", Settings::values.use_multi_core);
|
||||
ReadSetting("Core", Settings::values.use_unsafe_extended_memory_layout);
|
||||
ReadSetting("Core", Settings::values.memory_layout_mode);
|
||||
|
||||
// Cpu
|
||||
ReadSetting("Cpu", Settings::values.cpu_accuracy);
|
||||
@ -222,14 +224,17 @@ void Config::ReadValues() {
|
||||
ReadSetting("Renderer", Settings::values.bg_blue);
|
||||
|
||||
// Use GPU accuracy normal by default on Android
|
||||
Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(config->GetInteger(
|
||||
"Renderer", "gpu_accuracy", static_cast<u32>(Settings::GPUAccuracy::Normal)));
|
||||
Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger(
|
||||
"Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal)));
|
||||
|
||||
// Use GPU default anisotropic filtering on Android
|
||||
Settings::values.max_anisotropy = config->GetInteger("Renderer", "max_anisotropy", 1);
|
||||
Settings::values.max_anisotropy =
|
||||
static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1));
|
||||
|
||||
// Disable ASTC compute by default on Android
|
||||
Settings::values.accelerate_astc = config->GetBoolean("Renderer", "accelerate_astc", false);
|
||||
Settings::values.accelerate_astc.SetValue(
|
||||
config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu
|
||||
: Settings::AstcDecodeMode::Cpu);
|
||||
|
||||
// Enable asynchronous presentation by default on Android
|
||||
Settings::values.async_presentation =
|
||||
|
@ -15,6 +15,7 @@
|
||||
#endif
|
||||
#include "audio_core/sink/null_sink.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings_enums.h"
|
||||
|
||||
namespace AudioCore::Sink {
|
||||
namespace {
|
||||
@ -24,7 +25,7 @@ struct SinkDetails {
|
||||
using LatencyFn = u32 (*)();
|
||||
|
||||
/// Name for this sink.
|
||||
std::string_view id;
|
||||
Settings::AudioEngine id;
|
||||
/// A method to call to construct an instance of this type of sink.
|
||||
FactoryFn factory;
|
||||
/// A method to call to list available devices.
|
||||
@ -37,7 +38,7 @@ struct SinkDetails {
|
||||
constexpr SinkDetails sink_details[] = {
|
||||
#ifdef HAVE_CUBEB
|
||||
SinkDetails{
|
||||
"cubeb",
|
||||
Settings::AudioEngine::Cubeb,
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<CubebSink>(device_id);
|
||||
},
|
||||
@ -47,7 +48,7 @@ constexpr SinkDetails sink_details[] = {
|
||||
#endif
|
||||
#ifdef HAVE_SDL2
|
||||
SinkDetails{
|
||||
"sdl2",
|
||||
Settings::AudioEngine::Sdl2,
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<SDLSink>(device_id);
|
||||
},
|
||||
@ -55,46 +56,47 @@ constexpr SinkDetails sink_details[] = {
|
||||
&GetSDLLatency,
|
||||
},
|
||||
#endif
|
||||
SinkDetails{"null",
|
||||
SinkDetails{Settings::AudioEngine::Null,
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<NullSink>(device_id);
|
||||
},
|
||||
[](bool capture) { return std::vector<std::string>{"null"}; }, []() { return 0u; }},
|
||||
};
|
||||
|
||||
const SinkDetails& GetOutputSinkDetails(std::string_view sink_id) {
|
||||
const auto find_backend{[](std::string_view id) {
|
||||
const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
||||
const auto find_backend{[](Settings::AudioEngine id) {
|
||||
return std::find_if(std::begin(sink_details), std::end(sink_details),
|
||||
[&id](const auto& sink_detail) { return sink_detail.id == id; });
|
||||
}};
|
||||
|
||||
auto iter = find_backend(sink_id);
|
||||
|
||||
if (sink_id == "auto") {
|
||||
if (sink_id == Settings::AudioEngine::Auto) {
|
||||
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
||||
// causes audio issues, in that case go with SDL.
|
||||
#if defined(HAVE_CUBEB) && defined(HAVE_SDL2)
|
||||
iter = find_backend("cubeb");
|
||||
iter = find_backend(Settings::AudioEngine::Cubeb);
|
||||
if (iter->latency() > TargetSampleCount * 3) {
|
||||
iter = find_backend("sdl2");
|
||||
iter = find_backend(Settings::AudioEngine::Sdl2);
|
||||
}
|
||||
#else
|
||||
iter = std::begin(sink_details);
|
||||
#endif
|
||||
LOG_INFO(Service_Audio, "Auto-selecting the {} backend", iter->id);
|
||||
LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
|
||||
Settings::CanonicalizeEnum(iter->id));
|
||||
}
|
||||
|
||||
if (iter == std::end(sink_details)) {
|
||||
LOG_ERROR(Audio, "Invalid sink_id {}", sink_id);
|
||||
iter = find_backend("null");
|
||||
LOG_ERROR(Audio, "Invalid sink_id {}", Settings::CanonicalizeEnum(sink_id));
|
||||
iter = find_backend(Settings::AudioEngine::Null);
|
||||
}
|
||||
|
||||
return *iter;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
std::vector<std::string_view> GetSinkIDs() {
|
||||
std::vector<std::string_view> sink_ids(std::size(sink_details));
|
||||
std::vector<Settings::AudioEngine> GetSinkIDs() {
|
||||
std::vector<Settings::AudioEngine> sink_ids(std::size(sink_details));
|
||||
|
||||
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
|
||||
[](const auto& sink) { return sink.id; });
|
||||
@ -102,11 +104,11 @@ std::vector<std::string_view> GetSinkIDs() {
|
||||
return sink_ids;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool capture) {
|
||||
std::vector<std::string> GetDeviceListForSink(Settings::AudioEngine sink_id, bool capture) {
|
||||
return GetOutputSinkDetails(sink_id).list_devices(capture);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) {
|
||||
std::unique_ptr<Sink> CreateSinkFromID(Settings::AudioEngine sink_id, std::string_view device_id) {
|
||||
return GetOutputSinkDetails(sink_id).factory(device_id);
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include "common/settings_enums.h"
|
||||
|
||||
namespace AudioCore {
|
||||
class AudioManager;
|
||||
@ -19,7 +21,7 @@ class Sink;
|
||||
*
|
||||
* @return Vector of available sink names.
|
||||
*/
|
||||
std::vector<std::string_view> GetSinkIDs();
|
||||
std::vector<Settings::AudioEngine> GetSinkIDs();
|
||||
|
||||
/**
|
||||
* Gets the list of devices for a particular sink identified by the given ID.
|
||||
@ -28,7 +30,7 @@ std::vector<std::string_view> GetSinkIDs();
|
||||
* @param capture - Get capture (input) devices, or output devices?
|
||||
* @return Vector of device names.
|
||||
*/
|
||||
std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool capture);
|
||||
std::vector<std::string> GetDeviceListForSink(Settings::AudioEngine sink_id, bool capture);
|
||||
|
||||
/**
|
||||
* Creates an audio sink identified by the given device ID.
|
||||
@ -37,7 +39,7 @@ std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool cap
|
||||
* @param device_id - Name of the device to create.
|
||||
* @return Pointer to the created sink.
|
||||
*/
|
||||
std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id);
|
||||
std::unique_ptr<Sink> CreateSinkFromID(Settings::AudioEngine sink_id, std::string_view device_id);
|
||||
|
||||
} // namespace Sink
|
||||
} // namespace AudioCore
|
||||
|
@ -110,8 +110,12 @@ add_library(common STATIC
|
||||
scratch_buffer.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
settings_common.cpp
|
||||
settings_common.h
|
||||
settings_enums.h
|
||||
settings_input.cpp
|
||||
settings_input.h
|
||||
settings_setting.h
|
||||
socket_types.h
|
||||
spin_lock.cpp
|
||||
spin_lock.h
|
||||
@ -193,9 +197,16 @@ if (MSVC)
|
||||
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
|
||||
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
|
||||
)
|
||||
else()
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(common PRIVATE
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
|
||||
-fsized-deallocation
|
||||
-Werror=unreachable-code-aggressive
|
||||
)
|
||||
target_compile_definitions(common PRIVATE
|
||||
# Clang 14 and earlier have errors when explicitly instantiating Settings::Setting
|
||||
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -108,7 +108,7 @@ public:
|
||||
|
||||
using namespace Common::Literals;
|
||||
// Prevent logs from exceeding a set maximum size in the event that log entries are spammed.
|
||||
const auto write_limit = Settings::values.extended_logging ? 1_GiB : 100_MiB;
|
||||
const auto write_limit = Settings::values.extended_logging.GetValue() ? 1_GiB : 100_MiB;
|
||||
const bool write_limit_exceeded = bytes_written > write_limit;
|
||||
if (entry.log_level >= Level::Error || write_limit_exceeded) {
|
||||
if (write_limit_exceeded) {
|
||||
|
@ -7,9 +7,16 @@
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
#include <compare>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/fs/fs_util.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
@ -17,11 +24,50 @@
|
||||
|
||||
namespace Settings {
|
||||
|
||||
Values values;
|
||||
static bool configuring_global = true;
|
||||
// Clang 14 and earlier have errors when explicitly instantiating these classes
|
||||
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
|
||||
#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
|
||||
#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
|
||||
|
||||
std::string GetTimeZoneString() {
|
||||
const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue());
|
||||
SETTING(AudioEngine, false);
|
||||
SETTING(bool, false);
|
||||
SETTING(int, false);
|
||||
SETTING(std::string, false);
|
||||
SETTING(u16, false);
|
||||
SWITCHABLE(AnisotropyMode, true);
|
||||
SWITCHABLE(AntiAliasing, false);
|
||||
SWITCHABLE(AspectRatio, true);
|
||||
SWITCHABLE(AstcDecodeMode, true);
|
||||
SWITCHABLE(AstcRecompression, true);
|
||||
SWITCHABLE(AudioMode, true);
|
||||
SWITCHABLE(CpuAccuracy, true);
|
||||
SWITCHABLE(FullscreenMode, true);
|
||||
SWITCHABLE(GpuAccuracy, true);
|
||||
SWITCHABLE(Language, true);
|
||||
SWITCHABLE(NvdecEmulation, false);
|
||||
SWITCHABLE(Region, true);
|
||||
SWITCHABLE(RendererBackend, true);
|
||||
SWITCHABLE(ScalingFilter, false);
|
||||
SWITCHABLE(ShaderBackend, true);
|
||||
SWITCHABLE(TimeZone, true);
|
||||
SETTING(VSyncMode, true);
|
||||
SWITCHABLE(bool, false);
|
||||
SWITCHABLE(int, false);
|
||||
SWITCHABLE(int, true);
|
||||
SWITCHABLE(s64, false);
|
||||
SWITCHABLE(u16, true);
|
||||
SWITCHABLE(u32, false);
|
||||
SWITCHABLE(u8, false);
|
||||
SWITCHABLE(u8, true);
|
||||
|
||||
#undef SETTING
|
||||
#undef SWITCHABLE
|
||||
#endif
|
||||
|
||||
Values values;
|
||||
|
||||
std::string GetTimeZoneString(TimeZone time_zone) {
|
||||
const auto time_zone_index = static_cast<std::size_t>(time_zone);
|
||||
ASSERT(time_zone_index < Common::TimeZone::GetTimeZoneStrings().size());
|
||||
|
||||
std::string location_name;
|
||||
@ -61,73 +107,35 @@ void LogSettings() {
|
||||
};
|
||||
|
||||
LOG_INFO(Config, "yuzu Configuration:");
|
||||
log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
|
||||
log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
|
||||
log_setting("System_DeviceName", values.device_name.GetValue());
|
||||
log_setting("System_CurrentUser", values.current_user.GetValue());
|
||||
log_setting("System_LanguageIndex", values.language_index.GetValue());
|
||||
log_setting("System_RegionIndex", values.region_index.GetValue());
|
||||
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
|
||||
log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue());
|
||||
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
|
||||
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
|
||||
log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
|
||||
log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue());
|
||||
log_setting("Renderer_FSRSlider", values.fsr_sharpening_slider.GetValue());
|
||||
log_setting("Renderer_AntiAliasing", values.anti_aliasing.GetValue());
|
||||
log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue());
|
||||
log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
|
||||
log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue());
|
||||
log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
|
||||
log_setting("Renderer_UseAsynchronousGpuEmulation",
|
||||
values.use_asynchronous_gpu_emulation.GetValue());
|
||||
log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
|
||||
log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
|
||||
log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
|
||||
log_setting("Renderer_AstcRecompression", values.astc_recompression.GetValue());
|
||||
log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
|
||||
log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue());
|
||||
log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
|
||||
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
|
||||
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
|
||||
log_setting("Audio_OutputEngine", values.sink_id.GetValue());
|
||||
log_setting("Audio_OutputDevice", values.audio_output_device_id.GetValue());
|
||||
log_setting("Audio_InputDevice", values.audio_input_device_id.GetValue());
|
||||
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
|
||||
for (auto& [category, settings] : values.linkage.by_category) {
|
||||
for (const auto& setting : settings) {
|
||||
if (setting->Id() == values.yuzu_token.Id()) {
|
||||
// Hide the token secret, for security reasons.
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto name = fmt::format(
|
||||
"{:c}{:c} {}.{}", setting->ToString() == setting->DefaultToString() ? '-' : 'M',
|
||||
setting->UsingGlobal() ? '-' : 'C', TranslateCategory(category),
|
||||
setting->GetLabel());
|
||||
|
||||
log_setting(name, setting->Canonicalize());
|
||||
}
|
||||
}
|
||||
log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
|
||||
log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
|
||||
log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
|
||||
log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
|
||||
log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
|
||||
log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
|
||||
log_setting("Debugging_GDBStub", values.use_gdbstub.GetValue());
|
||||
log_setting("Input_EnableMotion", values.motion_enabled.GetValue());
|
||||
log_setting("Input_EnableVibration", values.vibration_enabled.GetValue());
|
||||
log_setting("Input_EnableTouch", values.touchscreen.enabled);
|
||||
log_setting("Input_EnableMouse", values.mouse_enabled.GetValue());
|
||||
log_setting("Input_EnableKeyboard", values.keyboard_enabled.GetValue());
|
||||
log_setting("Input_EnableRingController", values.enable_ring_controller.GetValue());
|
||||
log_setting("Input_EnableIrSensor", values.enable_ir_sensor.GetValue());
|
||||
log_setting("Input_EnableCustomJoycon", values.enable_joycon_driver.GetValue());
|
||||
log_setting("Input_EnableCustomProController", values.enable_procon_driver.GetValue());
|
||||
log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue());
|
||||
}
|
||||
|
||||
bool IsConfiguringGlobal() {
|
||||
return configuring_global;
|
||||
}
|
||||
|
||||
void SetConfiguringGlobal(bool is_global) {
|
||||
configuring_global = is_global;
|
||||
}
|
||||
|
||||
bool IsGPULevelExtreme() {
|
||||
return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme;
|
||||
return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme;
|
||||
}
|
||||
|
||||
bool IsGPULevelHigh() {
|
||||
return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme ||
|
||||
values.gpu_accuracy.GetValue() == GPUAccuracy::High;
|
||||
return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme ||
|
||||
values.gpu_accuracy.GetValue() == GpuAccuracy::High;
|
||||
}
|
||||
|
||||
bool IsFastmemEnabled() {
|
||||
@ -144,6 +152,61 @@ float Volume() {
|
||||
return values.volume.GetValue() / static_cast<f32>(values.volume.GetDefault());
|
||||
}
|
||||
|
||||
const char* TranslateCategory(Category category) {
|
||||
switch (category) {
|
||||
case Category::Audio:
|
||||
return "Audio";
|
||||
case Category::Core:
|
||||
return "Core";
|
||||
case Category::Cpu:
|
||||
case Category::CpuDebug:
|
||||
case Category::CpuUnsafe:
|
||||
return "Cpu";
|
||||
case Category::Renderer:
|
||||
case Category::RendererAdvanced:
|
||||
case Category::RendererDebug:
|
||||
return "Renderer";
|
||||
case Category::System:
|
||||
case Category::SystemAudio:
|
||||
return "System";
|
||||
case Category::DataStorage:
|
||||
return "Data Storage";
|
||||
case Category::Debugging:
|
||||
case Category::DebuggingGraphics:
|
||||
return "Debugging";
|
||||
case Category::Miscellaneous:
|
||||
return "Miscellaneous";
|
||||
case Category::Network:
|
||||
return "Network";
|
||||
case Category::WebService:
|
||||
return "WebService";
|
||||
case Category::AddOns:
|
||||
return "DisabledAddOns";
|
||||
case Category::Controls:
|
||||
return "Controls";
|
||||
case Category::Ui:
|
||||
case Category::UiGeneral:
|
||||
return "UI";
|
||||
case Category::UiLayout:
|
||||
return "UiLayout";
|
||||
case Category::UiGameList:
|
||||
return "UiGameList";
|
||||
case Category::Screenshots:
|
||||
return "Screenshots";
|
||||
case Category::Shortcuts:
|
||||
return "Shortcuts";
|
||||
case Category::Multiplayer:
|
||||
return "Multiplayer";
|
||||
case Category::Services:
|
||||
return "Services";
|
||||
case Category::Paths:
|
||||
return "Paths";
|
||||
case Category::MaxEnum:
|
||||
break;
|
||||
}
|
||||
return "Miscellaneous";
|
||||
}
|
||||
|
||||
void UpdateRescalingInfo() {
|
||||
const auto setup = values.resolution_setup.GetValue();
|
||||
auto& info = values.resolution_info;
|
||||
@ -212,66 +275,19 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Audio
|
||||
values.volume.SetGlobal(true);
|
||||
for (const auto& reset : values.linkage.restore_functions) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Core
|
||||
values.use_multi_core.SetGlobal(true);
|
||||
values.use_unsafe_extended_memory_layout.SetGlobal(true);
|
||||
static bool configuring_global = true;
|
||||
|
||||
// CPU
|
||||
values.cpu_accuracy.SetGlobal(true);
|
||||
values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
|
||||
values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
|
||||
values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true);
|
||||
values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
|
||||
values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
|
||||
values.cpuopt_unsafe_ignore_global_monitor.SetGlobal(true);
|
||||
bool IsConfiguringGlobal() {
|
||||
return configuring_global;
|
||||
}
|
||||
|
||||
// Renderer
|
||||
values.fsr_sharpening_slider.SetGlobal(true);
|
||||
values.renderer_backend.SetGlobal(true);
|
||||
values.async_presentation.SetGlobal(true);
|
||||
values.renderer_force_max_clock.SetGlobal(true);
|
||||
values.vulkan_device.SetGlobal(true);
|
||||
values.fullscreen_mode.SetGlobal(true);
|
||||
values.aspect_ratio.SetGlobal(true);
|
||||
values.resolution_setup.SetGlobal(true);
|
||||
values.scaling_filter.SetGlobal(true);
|
||||
values.anti_aliasing.SetGlobal(true);
|
||||
values.max_anisotropy.SetGlobal(true);
|
||||
values.use_speed_limit.SetGlobal(true);
|
||||
values.speed_limit.SetGlobal(true);
|
||||
values.use_disk_shader_cache.SetGlobal(true);
|
||||
values.gpu_accuracy.SetGlobal(true);
|
||||
values.use_asynchronous_gpu_emulation.SetGlobal(true);
|
||||
values.nvdec_emulation.SetGlobal(true);
|
||||
values.accelerate_astc.SetGlobal(true);
|
||||
values.async_astc.SetGlobal(true);
|
||||
values.astc_recompression.SetGlobal(true);
|
||||
values.use_reactive_flushing.SetGlobal(true);
|
||||
values.shader_backend.SetGlobal(true);
|
||||
values.use_asynchronous_shaders.SetGlobal(true);
|
||||
values.use_fast_gpu_time.SetGlobal(true);
|
||||
values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
|
||||
values.bg_red.SetGlobal(true);
|
||||
values.bg_green.SetGlobal(true);
|
||||
values.bg_blue.SetGlobal(true);
|
||||
values.enable_compute_pipelines.SetGlobal(true);
|
||||
values.use_video_framerate.SetGlobal(true);
|
||||
|
||||
// System
|
||||
values.language_index.SetGlobal(true);
|
||||
values.region_index.SetGlobal(true);
|
||||
values.time_zone_index.SetGlobal(true);
|
||||
values.rng_seed.SetGlobal(true);
|
||||
values.sound_index.SetGlobal(true);
|
||||
|
||||
// Controls
|
||||
values.players.SetGlobal(true);
|
||||
values.use_docked_mode.SetGlobal(true);
|
||||
values.vibration_enabled.SetGlobal(true);
|
||||
values.motion_enabled.SetGlobal(true);
|
||||
void SetConfiguringGlobal(bool is_global) {
|
||||
configuring_global = is_global;
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
|
@ -6,95 +6,21 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings_common.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "common/settings_input.h"
|
||||
#include "common/settings_setting.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
enum class VSyncMode : u32 {
|
||||
Immediate = 0,
|
||||
Mailbox = 1,
|
||||
FIFO = 2,
|
||||
FIFORelaxed = 3,
|
||||
};
|
||||
|
||||
enum class RendererBackend : u32 {
|
||||
OpenGL = 0,
|
||||
Vulkan = 1,
|
||||
Null = 2,
|
||||
};
|
||||
|
||||
enum class ShaderBackend : u32 {
|
||||
GLSL = 0,
|
||||
GLASM = 1,
|
||||
SPIRV = 2,
|
||||
};
|
||||
|
||||
enum class GPUAccuracy : u32 {
|
||||
Normal = 0,
|
||||
High = 1,
|
||||
Extreme = 2,
|
||||
};
|
||||
|
||||
enum class CPUAccuracy : u32 {
|
||||
Auto = 0,
|
||||
Accurate = 1,
|
||||
Unsafe = 2,
|
||||
Paranoid = 3,
|
||||
};
|
||||
|
||||
enum class FullscreenMode : u32 {
|
||||
Borderless = 0,
|
||||
Exclusive = 1,
|
||||
};
|
||||
|
||||
enum class NvdecEmulation : u32 {
|
||||
Off = 0,
|
||||
CPU = 1,
|
||||
GPU = 2,
|
||||
};
|
||||
|
||||
enum class ResolutionSetup : u32 {
|
||||
Res1_2X = 0,
|
||||
Res3_4X = 1,
|
||||
Res1X = 2,
|
||||
Res3_2X = 3,
|
||||
Res2X = 4,
|
||||
Res3X = 5,
|
||||
Res4X = 6,
|
||||
Res5X = 7,
|
||||
Res6X = 8,
|
||||
Res7X = 9,
|
||||
Res8X = 10,
|
||||
};
|
||||
|
||||
enum class ScalingFilter : u32 {
|
||||
NearestNeighbor = 0,
|
||||
Bilinear = 1,
|
||||
Bicubic = 2,
|
||||
Gaussian = 3,
|
||||
ScaleForce = 4,
|
||||
Fsr = 5,
|
||||
LastFilter = Fsr,
|
||||
};
|
||||
|
||||
enum class AntiAliasing : u32 {
|
||||
None = 0,
|
||||
Fxaa = 1,
|
||||
Smaa = 2,
|
||||
LastAA = Smaa,
|
||||
};
|
||||
|
||||
enum class AstcRecompression : u32 {
|
||||
Uncompressed = 0,
|
||||
Bc1 = 1,
|
||||
Bc3 = 2,
|
||||
};
|
||||
const char* TranslateCategory(Settings::Category category);
|
||||
|
||||
struct ResolutionScalingInfo {
|
||||
u32 up_scale{1};
|
||||
@ -119,239 +45,47 @@ struct ResolutionScalingInfo {
|
||||
}
|
||||
};
|
||||
|
||||
/** The Setting class is a simple resource manager. It defines a label and default value alongside
|
||||
* the actual value of the setting for simpler and less-error prone use with frontend
|
||||
* configurations. Specifying a default value and label is required. A minimum and maximum range can
|
||||
* be specified for sanitization.
|
||||
*/
|
||||
template <typename Type, bool ranged = false>
|
||||
class Setting {
|
||||
protected:
|
||||
Setting() = default;
|
||||
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
|
||||
// Instantiate the classes elsewhere (settings.cpp) to reduce compiler/linker work
|
||||
#define SETTING(TYPE, RANGED) extern template class Setting<TYPE, RANGED>
|
||||
#define SWITCHABLE(TYPE, RANGED) extern template class SwitchableSetting<TYPE, RANGED>
|
||||
|
||||
/**
|
||||
* Only sets the setting to the given initializer, leaving the other members to their default
|
||||
* initializers.
|
||||
*
|
||||
* @param global_val Initial value of the setting
|
||||
*/
|
||||
explicit Setting(const Type& val) : value{val} {}
|
||||
SETTING(AudioEngine, false);
|
||||
SETTING(bool, false);
|
||||
SETTING(int, false);
|
||||
SETTING(s32, false);
|
||||
SETTING(std::string, false);
|
||||
SETTING(std::string, false);
|
||||
SETTING(u16, false);
|
||||
SWITCHABLE(AnisotropyMode, true);
|
||||
SWITCHABLE(AntiAliasing, false);
|
||||
SWITCHABLE(AspectRatio, true);
|
||||
SWITCHABLE(AstcDecodeMode, true);
|
||||
SWITCHABLE(AstcRecompression, true);
|
||||
SWITCHABLE(AudioMode, true);
|
||||
SWITCHABLE(CpuAccuracy, true);
|
||||
SWITCHABLE(FullscreenMode, true);
|
||||
SWITCHABLE(GpuAccuracy, true);
|
||||
SWITCHABLE(Language, true);
|
||||
SWITCHABLE(NvdecEmulation, false);
|
||||
SWITCHABLE(Region, true);
|
||||
SWITCHABLE(RendererBackend, true);
|
||||
SWITCHABLE(ScalingFilter, false);
|
||||
SWITCHABLE(ShaderBackend, true);
|
||||
SWITCHABLE(TimeZone, true);
|
||||
SETTING(VSyncMode, true);
|
||||
SWITCHABLE(bool, false);
|
||||
SWITCHABLE(int, false);
|
||||
SWITCHABLE(int, true);
|
||||
SWITCHABLE(s64, false);
|
||||
SWITCHABLE(u16, true);
|
||||
SWITCHABLE(u32, false);
|
||||
SWITCHABLE(u8, false);
|
||||
SWITCHABLE(u8, true);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
*
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit Setting(const Type& default_val, const std::string& name)
|
||||
requires(!ranged)
|
||||
: value{default_val}, default_value{default_val}, label{name} {}
|
||||
virtual ~Setting() = default;
|
||||
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
requires(ranged)
|
||||
: value{default_val},
|
||||
default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting's value.
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
[[nodiscard]] virtual const Type& GetValue() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the setting to the given value.
|
||||
*
|
||||
* @param val The desired value
|
||||
*/
|
||||
virtual void SetValue(const Type& val) {
|
||||
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
|
||||
std::swap(value, temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that this setting was created with.
|
||||
*
|
||||
* @returns A reference to the default value
|
||||
*/
|
||||
[[nodiscard]] const Type& GetDefault() const {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label this setting was created with.
|
||||
*
|
||||
* @returns A reference to the label
|
||||
*/
|
||||
[[nodiscard]] const std::string& GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a value to the setting.
|
||||
*
|
||||
* @param val The desired setting value
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
virtual const Type& operator=(const Type& val) {
|
||||
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
|
||||
std::swap(value, temp);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting.
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
explicit virtual operator const Type&() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type value{}; ///< The setting
|
||||
const Type default_value{}; ///< The default value
|
||||
const Type maximum{}; ///< Maximum allowed value of the setting
|
||||
const Type minimum{}; ///< Minimum allowed value of the setting
|
||||
const std::string label{}; ///< The setting's label
|
||||
};
|
||||
|
||||
/**
|
||||
* The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
|
||||
* custom setting to switch to when a guest application specifically requires it. The effect is that
|
||||
* other components of the emulator can access the setting's intended value without any need for the
|
||||
* component to ask whether the custom or global setting is needed at the moment.
|
||||
*
|
||||
* By default, the global setting is used.
|
||||
*/
|
||||
template <typename Type, bool ranged = false>
|
||||
class SwitchableSetting : virtual public Setting<Type, ranged> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
*
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit SwitchableSetting(const Type& default_val, const std::string& name)
|
||||
requires(!ranged)
|
||||
: Setting<Type>{default_val, name} {}
|
||||
virtual ~SwitchableSetting() = default;
|
||||
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
|
||||
const std::string& name)
|
||||
requires(ranged)
|
||||
: Setting<Type, true>{default_val, min_val, max_val, name} {}
|
||||
|
||||
/**
|
||||
* Tells this setting to represent either the global or custom setting when other member
|
||||
* functions are used.
|
||||
*
|
||||
* @param to_global Whether to use the global or custom setting.
|
||||
*/
|
||||
void SetGlobal(bool to_global) {
|
||||
use_global = to_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this setting is using the global setting or not.
|
||||
*
|
||||
* @returns The global state
|
||||
*/
|
||||
[[nodiscard]] bool UsingGlobal() const {
|
||||
return use_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either the global or custom setting depending on the values of this setting's global
|
||||
* state or if the global value was specifically requested.
|
||||
*
|
||||
* @param need_global Request global value regardless of setting's state; defaults to false
|
||||
*
|
||||
* @returns The required value of the setting
|
||||
*/
|
||||
[[nodiscard]] virtual const Type& GetValue() const override {
|
||||
if (use_global) {
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
[[nodiscard]] virtual const Type& GetValue(bool need_global) const {
|
||||
if (use_global || need_global) {
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current setting value depending on the global state.
|
||||
*
|
||||
* @param val The new value
|
||||
*/
|
||||
void SetValue(const Type& val) override {
|
||||
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||
if (use_global) {
|
||||
std::swap(this->value, temp);
|
||||
} else {
|
||||
std::swap(custom, temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the current setting value depending on the global state.
|
||||
*
|
||||
* @param val The new value
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
const Type& operator=(const Type& val) override {
|
||||
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||
if (use_global) {
|
||||
std::swap(this->value, temp);
|
||||
return this->value;
|
||||
}
|
||||
std::swap(custom, temp);
|
||||
return custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting value depending on the global state.
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
virtual explicit operator const Type&() const override {
|
||||
if (use_global) {
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool use_global{true}; ///< The setting's global state
|
||||
Type custom{}; ///< The custom value of the setting
|
||||
};
|
||||
#undef SETTING
|
||||
#undef SWITCHABLE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The InputSetting class allows for getting a reference to either the global or custom members.
|
||||
@ -391,208 +125,388 @@ struct TouchFromButtonMap {
|
||||
};
|
||||
|
||||
struct Values {
|
||||
Linkage linkage{};
|
||||
|
||||
// Audio
|
||||
Setting<std::string> sink_id{"auto", "output_engine"};
|
||||
Setting<std::string> audio_output_device_id{"auto", "output_device"};
|
||||
Setting<std::string> audio_input_device_id{"auto", "input_device"};
|
||||
Setting<bool> audio_muted{false, "audio_muted"};
|
||||
SwitchableSetting<u8, true> volume{100, 0, 200, "volume"};
|
||||
Setting<bool> dump_audio_commands{false, "dump_audio_commands"};
|
||||
Setting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", Category::Audio,
|
||||
Specialization::RuntimeList};
|
||||
Setting<std::string> audio_output_device_id{linkage, "auto", "output_device", Category::Audio,
|
||||
Specialization::RuntimeList};
|
||||
Setting<std::string> audio_input_device_id{linkage, "auto", "input_device", Category::Audio,
|
||||
Specialization::RuntimeList};
|
||||
SwitchableSetting<AudioMode, true> sound_index{
|
||||
linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround,
|
||||
"sound_index", Category::SystemAudio, Specialization::Default, true,
|
||||
true};
|
||||
SwitchableSetting<u8, true> volume{linkage,
|
||||
100,
|
||||
0,
|
||||
200,
|
||||
"volume",
|
||||
Category::Audio,
|
||||
Specialization::Scalar | Specialization::Percentage,
|
||||
true,
|
||||
true};
|
||||
Setting<bool, false> audio_muted{
|
||||
linkage, false, "audio_muted", Category::Audio, Specialization::Default, false, true};
|
||||
Setting<bool, false> dump_audio_commands{
|
||||
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
||||
|
||||
// Core
|
||||
SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
|
||||
SwitchableSetting<bool> use_unsafe_extended_memory_layout{false,
|
||||
"use_unsafe_extended_memory_layout"};
|
||||
SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
|
||||
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
||||
MemoryLayout::Memory_4Gb,
|
||||
MemoryLayout::Memory_4Gb,
|
||||
MemoryLayout::Memory_8Gb,
|
||||
"memory_layout_mode",
|
||||
Category::Core};
|
||||
SwitchableSetting<bool> use_speed_limit{
|
||||
linkage, true, "use_speed_limit", Category::Core, Specialization::Paired, false, true};
|
||||
SwitchableSetting<u16, true> speed_limit{linkage,
|
||||
100,
|
||||
0,
|
||||
9999,
|
||||
"speed_limit",
|
||||
Category::Core,
|
||||
Specialization::Countable | Specialization::Percentage,
|
||||
true,
|
||||
true,
|
||||
&use_speed_limit};
|
||||
|
||||
// Cpu
|
||||
SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
|
||||
CPUAccuracy::Paranoid, "cpu_accuracy"};
|
||||
// TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
|
||||
Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
|
||||
Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
|
||||
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
|
||||
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
|
||||
"cpu_accuracy", Category::Cpu};
|
||||
Setting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
|
||||
|
||||
Setting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
|
||||
Setting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
|
||||
Setting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
|
||||
Setting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
|
||||
Setting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
|
||||
Setting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
|
||||
Setting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
|
||||
Setting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
|
||||
Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
|
||||
Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
|
||||
Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
|
||||
Setting<bool> cpuopt_ignore_memory_aborts{true, "cpuopt_ignore_memory_aborts"};
|
||||
Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
|
||||
Setting<bool> cpuopt_block_linking{linkage, true, "cpuopt_block_linking", Category::CpuDebug};
|
||||
Setting<bool> cpuopt_return_stack_buffer{linkage, true, "cpuopt_return_stack_buffer",
|
||||
Category::CpuDebug};
|
||||
Setting<bool> cpuopt_fast_dispatcher{linkage, true, "cpuopt_fast_dispatcher",
|
||||
Category::CpuDebug};
|
||||
Setting<bool> cpuopt_context_elimination{linkage, true, "cpuopt_context_elimination",
|
||||
Category::CpuDebug};
|
||||
Setting<bool> cpuopt_const_prop{linkage, true, "cpuopt_const_prop", Category::CpuDebug};
|
||||
Setting<bool> cpuopt_misc_ir{linkage, true, "cpuopt_misc_ir", Category::CpuDebug};
|
||||
Setting<bool> cpuopt_reduce_misalign_checks{linkage, true, "cpuopt_reduce_misalign_checks",
|
||||
Category::CpuDebug};
|
||||
Setting<bool> cpuopt_fastmem{linkage, true, "cpuopt_fastmem", Category::CpuDebug};
|
||||
Setting<bool> cpuopt_fastmem_exclusives{linkage, true, "cpuopt_fastmem_exclusives",
|
||||
Category::CpuDebug};
|
||||
Setting<bool> cpuopt_recompile_exclusives{linkage, true, "cpuopt_recompile_exclusives",
|
||||
Category::CpuDebug};
|
||||
Setting<bool> cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts",
|
||||
Category::CpuDebug};
|
||||
|
||||
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma",
|
||||
Category::CpuUnsafe};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{
|
||||
linkage, true, "cpuopt_unsafe_reduce_fp_error", Category::CpuUnsafe};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
|
||||
true, "cpuopt_unsafe_ignore_standard_fpcr"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
|
||||
linkage, true, "cpuopt_unsafe_ignore_standard_fpcr", Category::CpuUnsafe};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{
|
||||
linkage, true, "cpuopt_unsafe_inaccurate_nan", Category::CpuUnsafe};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{
|
||||
linkage, true, "cpuopt_unsafe_fastmem_check", Category::CpuUnsafe};
|
||||
SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
|
||||
true, "cpuopt_unsafe_ignore_global_monitor"};
|
||||
linkage, true, "cpuopt_unsafe_ignore_global_monitor", Category::CpuUnsafe};
|
||||
|
||||
// Renderer
|
||||
SwitchableSetting<RendererBackend, true> renderer_backend{
|
||||
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
|
||||
SwitchableSetting<bool> async_presentation{false, "async_presentation"};
|
||||
SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
|
||||
Setting<bool> renderer_debug{false, "debug"};
|
||||
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
|
||||
Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
|
||||
Setting<bool> disable_shader_loop_safety_checks{false, "disable_shader_loop_safety_checks"};
|
||||
SwitchableSetting<int> vulkan_device{0, "vulkan_device"};
|
||||
linkage, RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null,
|
||||
"backend", Category::Renderer};
|
||||
SwitchableSetting<ShaderBackend, true> shader_backend{
|
||||
linkage, ShaderBackend::Glsl, ShaderBackend::Glsl, ShaderBackend::SpirV,
|
||||
"shader_backend", Category::Renderer, Specialization::RuntimeList};
|
||||
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
|
||||
Specialization::RuntimeList};
|
||||
|
||||
ResolutionScalingInfo resolution_info{};
|
||||
SwitchableSetting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
|
||||
SwitchableSetting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
|
||||
SwitchableSetting<int, true> fsr_sharpening_slider{25, 0, 200, "fsr_sharpening_slider"};
|
||||
SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
|
||||
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
|
||||
Category::Renderer};
|
||||
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
||||
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
||||
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
|
||||
AstcDecodeMode::Gpu,
|
||||
AstcDecodeMode::Cpu,
|
||||
AstcDecodeMode::CpuAsynchronous,
|
||||
"accelerate_astc",
|
||||
Category::Renderer};
|
||||
Setting<VSyncMode, true> vsync_mode{
|
||||
linkage, VSyncMode::Fifo, VSyncMode::Immediate, VSyncMode::FifoRelaxed,
|
||||
"use_vsync", Category::Renderer, Specialization::RuntimeList, true,
|
||||
true};
|
||||
SwitchableSetting<NvdecEmulation> nvdec_emulation{linkage, NvdecEmulation::Gpu,
|
||||
"nvdec_emulation", Category::Renderer};
|
||||
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||
// Default to exclusive fullscreen on these platforms for now.
|
||||
SwitchableSetting<FullscreenMode, true> fullscreen_mode{
|
||||
SwitchableSetting<FullscreenMode, true> fullscreen_mode{linkage,
|
||||
#ifdef _WIN32
|
||||
FullscreenMode::Borderless,
|
||||
FullscreenMode::Borderless,
|
||||
#else
|
||||
FullscreenMode::Exclusive,
|
||||
FullscreenMode::Exclusive,
|
||||
#endif
|
||||
FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
|
||||
SwitchableSetting<int, true> aspect_ratio{0, 0, 4, "aspect_ratio"};
|
||||
SwitchableSetting<int, true> max_anisotropy{0, 0, 5, "max_anisotropy"};
|
||||
SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
|
||||
SwitchableSetting<u16, true> speed_limit{100, 0, 9999, "speed_limit"};
|
||||
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
||||
SwitchableSetting<GPUAccuracy, true> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
|
||||
GPUAccuracy::Extreme, "gpu_accuracy"};
|
||||
SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
|
||||
SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
|
||||
SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
|
||||
SwitchableSetting<bool> async_astc{false, "async_astc"};
|
||||
Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate,
|
||||
VSyncMode::FIFORelaxed, "use_vsync"};
|
||||
SwitchableSetting<bool> use_reactive_flushing{true, "use_reactive_flushing"};
|
||||
SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL,
|
||||
ShaderBackend::SPIRV, "shader_backend"};
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
|
||||
SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
|
||||
SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
|
||||
"use_vulkan_driver_pipeline_cache"};
|
||||
SwitchableSetting<bool> enable_compute_pipelines{false, "enable_compute_pipelines"};
|
||||
SwitchableSetting<AstcRecompression, true> astc_recompression{
|
||||
AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3,
|
||||
"astc_recompression"};
|
||||
SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"};
|
||||
SwitchableSetting<bool> barrier_feedback_loops{true, "barrier_feedback_loops"};
|
||||
FullscreenMode::Borderless,
|
||||
FullscreenMode::Exclusive,
|
||||
"fullscreen_mode",
|
||||
Category::Renderer,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
SwitchableSetting<AspectRatio, true> aspect_ratio{linkage,
|
||||
AspectRatio::R16_9,
|
||||
AspectRatio::R16_9,
|
||||
AspectRatio::Stretch,
|
||||
"aspect_ratio",
|
||||
Category::Renderer,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<u8> bg_red{0, "bg_red"};
|
||||
SwitchableSetting<u8> bg_green{0, "bg_green"};
|
||||
SwitchableSetting<u8> bg_blue{0, "bg_blue"};
|
||||
ResolutionScalingInfo resolution_info{};
|
||||
SwitchableSetting<ResolutionSetup> resolution_setup{linkage, ResolutionSetup::Res1X,
|
||||
"resolution_setup", Category::Renderer};
|
||||
SwitchableSetting<ScalingFilter> scaling_filter{linkage,
|
||||
ScalingFilter::Bilinear,
|
||||
"scaling_filter",
|
||||
Category::Renderer,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
SwitchableSetting<AntiAliasing> anti_aliasing{linkage,
|
||||
AntiAliasing::None,
|
||||
"anti_aliasing",
|
||||
Category::Renderer,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
SwitchableSetting<int, true> fsr_sharpening_slider{linkage,
|
||||
25,
|
||||
0,
|
||||
200,
|
||||
"fsr_sharpening_slider",
|
||||
Category::Renderer,
|
||||
Specialization::Scalar |
|
||||
Specialization::Percentage,
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<u8, false> bg_red{
|
||||
linkage, 0, "bg_red", Category::Renderer, Specialization::Default, true, true};
|
||||
SwitchableSetting<u8, false> bg_green{
|
||||
linkage, 0, "bg_green", Category::Renderer, Specialization::Default, true, true};
|
||||
SwitchableSetting<u8, false> bg_blue{
|
||||
linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
|
||||
|
||||
SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
|
||||
GpuAccuracy::High,
|
||||
GpuAccuracy::Normal,
|
||||
GpuAccuracy::Extreme,
|
||||
"gpu_accuracy",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
SwitchableSetting<AnisotropyMode, true> max_anisotropy{
|
||||
linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16,
|
||||
"max_anisotropy", Category::RendererAdvanced};
|
||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||
AstcRecompression::Uncompressed,
|
||||
AstcRecompression::Uncompressed,
|
||||
AstcRecompression::Bc3,
|
||||
"astc_recompression",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> use_fast_gpu_time{
|
||||
linkage, true, "use_fast_gpu_time", Category::RendererAdvanced, Specialization::Default,
|
||||
true, true};
|
||||
SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{linkage,
|
||||
true,
|
||||
"use_vulkan_driver_pipeline_cache",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
SwitchableSetting<bool> enable_compute_pipelines{linkage, false, "enable_compute_pipelines",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> use_video_framerate{linkage, false, "use_video_framerate",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
|
||||
Category::RendererAdvanced};
|
||||
|
||||
Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
|
||||
Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",
|
||||
Category::RendererDebug};
|
||||
Setting<bool> enable_nsight_aftermath{linkage, false, "nsight_aftermath",
|
||||
Category::RendererDebug};
|
||||
Setting<bool> disable_shader_loop_safety_checks{
|
||||
linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
|
||||
|
||||
// System
|
||||
SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
|
||||
Setting<std::string> device_name{"Yuzu", "device_name"};
|
||||
SwitchableSetting<Language, true> language_index{linkage,
|
||||
Language::EnglishAmerican,
|
||||
Language::Japanese,
|
||||
Language::PortugueseBrazilian,
|
||||
"language_index",
|
||||
Category::System};
|
||||
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, Region::Japan,
|
||||
Region::Taiwan, "region_index", Category::System};
|
||||
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
|
||||
TimeZone::Auto, TimeZone::Zulu,
|
||||
"time_zone_index", Category::System};
|
||||
// Measured in seconds since epoch
|
||||
std::optional<s64> custom_rtc;
|
||||
SwitchableSetting<bool> custom_rtc_enabled{
|
||||
linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<s64> custom_rtc{
|
||||
linkage, 0, "custom_rtc", Category::System, Specialization::Time,
|
||||
true, true, &custom_rtc_enabled};
|
||||
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
||||
s64 custom_rtc_differential;
|
||||
SwitchableSetting<bool> rng_seed_enabled{
|
||||
linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<u32> rng_seed{
|
||||
linkage, 0, "rng_seed", Category::System, Specialization::Hex,
|
||||
true, true, &rng_seed_enabled};
|
||||
Setting<std::string> device_name{
|
||||
linkage, "yuzu", "device_name", Category::System, Specialization::Default, true, true};
|
||||
|
||||
Setting<s32> current_user{0, "current_user"};
|
||||
SwitchableSetting<s32, true> language_index{1, 0, 17, "language_index"};
|
||||
SwitchableSetting<s32, true> region_index{1, 0, 6, "region_index"};
|
||||
SwitchableSetting<s32, true> time_zone_index{0, 0, 45, "time_zone_index"};
|
||||
SwitchableSetting<s32, true> sound_index{1, 0, 2, "sound_index"};
|
||||
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
|
||||
|
||||
SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System};
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
|
||||
SwitchableSetting<bool> use_docked_mode{true, "use_docked_mode"};
|
||||
Setting<bool> enable_raw_input{
|
||||
linkage, false, "enable_raw_input", Category::Controls, Specialization::Default,
|
||||
// Only read/write enable_raw_input on Windows platforms
|
||||
#ifdef _WIN32
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
};
|
||||
Setting<bool> controller_navigation{linkage, true, "controller_navigation", Category::Controls};
|
||||
Setting<bool> enable_joycon_driver{linkage, true, "enable_joycon_driver", Category::Controls};
|
||||
Setting<bool> enable_procon_driver{linkage, false, "enable_procon_driver", Category::Controls};
|
||||
|
||||
Setting<bool> enable_raw_input{false, "enable_raw_input"};
|
||||
Setting<bool> controller_navigation{true, "controller_navigation"};
|
||||
Setting<bool> enable_joycon_driver{true, "enable_joycon_driver"};
|
||||
Setting<bool> enable_procon_driver{false, "enable_procon_driver"};
|
||||
SwitchableSetting<bool> vibration_enabled{linkage, true, "vibration_enabled",
|
||||
Category::Controls};
|
||||
SwitchableSetting<bool> enable_accurate_vibrations{linkage, false, "enable_accurate_vibrations",
|
||||
Category::Controls};
|
||||
|
||||
SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
|
||||
SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
|
||||
SwitchableSetting<bool> motion_enabled{linkage, true, "motion_enabled", Category::Controls};
|
||||
Setting<std::string> udp_input_servers{linkage, "127.0.0.1:26760", "udp_input_servers",
|
||||
Category::Controls};
|
||||
Setting<bool> enable_udp_controller{linkage, false, "enable_udp_controller",
|
||||
Category::Controls};
|
||||
|
||||
SwitchableSetting<bool> motion_enabled{true, "motion_enabled"};
|
||||
Setting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
|
||||
Setting<bool> enable_udp_controller{false, "enable_udp_controller"};
|
||||
Setting<bool> pause_tas_on_load{linkage, true, "pause_tas_on_load", Category::Controls};
|
||||
Setting<bool> tas_enable{linkage, false, "tas_enable", Category::Controls};
|
||||
Setting<bool> tas_loop{linkage, false, "tas_loop", Category::Controls};
|
||||
|
||||
Setting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
|
||||
Setting<bool> tas_enable{false, "tas_enable"};
|
||||
Setting<bool> tas_loop{false, "tas_loop"};
|
||||
Setting<bool> mouse_panning{
|
||||
linkage, false, "mouse_panning", Category::Controls, Specialization::Default, false};
|
||||
Setting<u8, true> mouse_panning_sensitivity{
|
||||
linkage, 50, 1, 100, "mouse_panning_sensitivity", Category::Controls};
|
||||
Setting<bool> mouse_enabled{linkage, false, "mouse_enabled", Category::Controls};
|
||||
|
||||
Setting<bool> mouse_panning{false, "mouse_panning"};
|
||||
Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"};
|
||||
Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"};
|
||||
Setting<u8, true> mouse_panning_deadzone_counterweight{20, 0, 100,
|
||||
"mouse_panning_deadzone_counterweight"};
|
||||
Setting<u8, true> mouse_panning_decay_strength{18, 0, 100, "mouse_panning_decay_strength"};
|
||||
Setting<u8, true> mouse_panning_min_decay{6, 0, 100, "mouse_panning_min_decay"};
|
||||
Setting<u8, true> mouse_panning_x_sensitivity{
|
||||
linkage, 50, 1, 100, "mouse_panning_x_sensitivity", Category::Controls};
|
||||
Setting<u8, true> mouse_panning_y_sensitivity{
|
||||
linkage, 50, 1, 100, "mouse_panning_y_sensitivity", Category::Controls};
|
||||
Setting<u8, true> mouse_panning_deadzone_counterweight{
|
||||
linkage, 20, 0, 100, "mouse_panning_deadzone_counterweight", Category::Controls};
|
||||
Setting<u8, true> mouse_panning_decay_strength{
|
||||
linkage, 18, 0, 100, "mouse_panning_decay_strength", Category::Controls};
|
||||
Setting<u8, true> mouse_panning_min_decay{
|
||||
linkage, 6, 0, 100, "mouse_panning_min_decay", Category::Controls};
|
||||
|
||||
Setting<bool> mouse_enabled{false, "mouse_enabled"};
|
||||
Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
|
||||
Setting<bool> keyboard_enabled{false, "keyboard_enabled"};
|
||||
Setting<bool> emulate_analog_keyboard{linkage, false, "emulate_analog_keyboard",
|
||||
Category::Controls};
|
||||
Setting<bool> keyboard_enabled{linkage, false, "keyboard_enabled", Category::Controls};
|
||||
|
||||
Setting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
|
||||
Setting<bool> debug_pad_enabled{linkage, false, "debug_pad_enabled", Category::Controls};
|
||||
ButtonsRaw debug_pad_buttons;
|
||||
AnalogsRaw debug_pad_analogs;
|
||||
|
||||
TouchscreenInput touchscreen;
|
||||
|
||||
Setting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"};
|
||||
Setting<int> touch_from_button_map_index{0, "touch_from_button_map"};
|
||||
Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850",
|
||||
"touch_device", Category::Controls};
|
||||
Setting<int> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
|
||||
Category::Controls};
|
||||
std::vector<TouchFromButtonMap> touch_from_button_maps;
|
||||
|
||||
Setting<bool> enable_ring_controller{true, "enable_ring_controller"};
|
||||
Setting<bool> enable_ring_controller{linkage, true, "enable_ring_controller",
|
||||
Category::Controls};
|
||||
RingconRaw ringcon_analogs;
|
||||
|
||||
Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"};
|
||||
Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"};
|
||||
Setting<bool> enable_ir_sensor{linkage, false, "enable_ir_sensor", Category::Controls};
|
||||
Setting<std::string> ir_sensor_device{linkage, "auto", "ir_sensor_device", Category::Controls};
|
||||
|
||||
Setting<bool> random_amiibo_id{false, "random_amiibo_id"};
|
||||
Setting<bool> random_amiibo_id{linkage, false, "random_amiibo_id", Category::Controls};
|
||||
|
||||
// Data Storage
|
||||
Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
|
||||
Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
|
||||
Setting<bool> gamecard_current_game{false, "gamecard_current_game"};
|
||||
Setting<std::string> gamecard_path{std::string(), "gamecard_path"};
|
||||
Setting<bool> use_virtual_sd{linkage, true, "use_virtual_sd", Category::DataStorage};
|
||||
Setting<bool> gamecard_inserted{linkage, false, "gamecard_inserted", Category::DataStorage};
|
||||
Setting<bool> gamecard_current_game{linkage, false, "gamecard_current_game",
|
||||
Category::DataStorage};
|
||||
Setting<std::string> gamecard_path{linkage, std::string(), "gamecard_path",
|
||||
Category::DataStorage};
|
||||
|
||||
// Debugging
|
||||
bool record_frame_times;
|
||||
Setting<bool> use_gdbstub{false, "use_gdbstub"};
|
||||
Setting<u16> gdbstub_port{6543, "gdbstub_port"};
|
||||
Setting<std::string> program_args{std::string(), "program_args"};
|
||||
Setting<bool> dump_exefs{false, "dump_exefs"};
|
||||
Setting<bool> dump_nso{false, "dump_nso"};
|
||||
Setting<bool> dump_shaders{false, "dump_shaders"};
|
||||
Setting<bool> dump_macros{false, "dump_macros"};
|
||||
Setting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
|
||||
Setting<bool> reporting_services{false, "reporting_services"};
|
||||
Setting<bool> quest_flag{false, "quest_flag"};
|
||||
Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
|
||||
Setting<bool> disable_macro_hle{false, "disable_macro_hle"};
|
||||
Setting<bool> extended_logging{false, "extended_logging"};
|
||||
Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
|
||||
Setting<bool> use_auto_stub{false, "use_auto_stub"};
|
||||
Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
|
||||
Setting<bool> create_crash_dumps{false, "create_crash_dumps"};
|
||||
Setting<bool> perform_vulkan_check{true, "perform_vulkan_check"};
|
||||
Setting<bool> use_gdbstub{linkage, false, "use_gdbstub", Category::Debugging};
|
||||
Setting<u16> gdbstub_port{linkage, 6543, "gdbstub_port", Category::Debugging};
|
||||
Setting<std::string> program_args{linkage, std::string(), "program_args", Category::Debugging};
|
||||
Setting<bool> dump_exefs{linkage, false, "dump_exefs", Category::Debugging};
|
||||
Setting<bool> dump_nso{linkage, false, "dump_nso", Category::Debugging};
|
||||
Setting<bool> dump_shaders{
|
||||
linkage, false, "dump_shaders", Category::DebuggingGraphics, Specialization::Default,
|
||||
false};
|
||||
Setting<bool> dump_macros{
|
||||
linkage, false, "dump_macros", Category::DebuggingGraphics, Specialization::Default, false};
|
||||
Setting<bool> enable_fs_access_log{linkage, false, "enable_fs_access_log", Category::Debugging};
|
||||
Setting<bool> reporting_services{
|
||||
linkage, false, "reporting_services", Category::Debugging, Specialization::Default, false};
|
||||
Setting<bool> quest_flag{linkage, false, "quest_flag", Category::Debugging};
|
||||
Setting<bool> disable_macro_jit{linkage, false, "disable_macro_jit",
|
||||
Category::DebuggingGraphics};
|
||||
Setting<bool> disable_macro_hle{linkage, false, "disable_macro_hle",
|
||||
Category::DebuggingGraphics};
|
||||
Setting<bool> extended_logging{
|
||||
linkage, false, "extended_logging", Category::Debugging, Specialization::Default, false};
|
||||
Setting<bool> use_debug_asserts{linkage, false, "use_debug_asserts", Category::Debugging};
|
||||
Setting<bool> use_auto_stub{
|
||||
linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false};
|
||||
Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers",
|
||||
Category::Debugging};
|
||||
Setting<bool> create_crash_dumps{linkage, false, "create_crash_dumps", Category::Debugging};
|
||||
Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
|
||||
|
||||
// Miscellaneous
|
||||
Setting<std::string> log_filter{"*:Info", "log_filter"};
|
||||
Setting<bool> use_dev_keys{false, "use_dev_keys"};
|
||||
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
|
||||
Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
|
||||
|
||||
// Network
|
||||
Setting<std::string> network_interface{std::string(), "network_interface"};
|
||||
Setting<std::string> network_interface{linkage, std::string(), "network_interface",
|
||||
Category::Network};
|
||||
|
||||
// WebService
|
||||
Setting<bool> enable_telemetry{true, "enable_telemetry"};
|
||||
Setting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
|
||||
Setting<std::string> yuzu_username{std::string(), "yuzu_username"};
|
||||
Setting<std::string> yuzu_token{std::string(), "yuzu_token"};
|
||||
Setting<bool> enable_telemetry{linkage, true, "enable_telemetry", Category::WebService};
|
||||
Setting<std::string> web_api_url{linkage, "https://api.yuzu-emu.org", "web_api_url",
|
||||
Category::WebService};
|
||||
Setting<std::string> yuzu_username{linkage, std::string(), "yuzu_username",
|
||||
Category::WebService};
|
||||
Setting<std::string> yuzu_token{linkage, std::string(), "yuzu_token", Category::WebService};
|
||||
|
||||
// Add-Ons
|
||||
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||
@ -600,9 +514,6 @@ struct Values {
|
||||
|
||||
extern Values values;
|
||||
|
||||
bool IsConfiguringGlobal();
|
||||
void SetConfiguringGlobal(bool is_global);
|
||||
|
||||
bool IsGPULevelExtreme();
|
||||
bool IsGPULevelHigh();
|
||||
|
||||
@ -610,7 +521,7 @@ bool IsFastmemEnabled();
|
||||
|
||||
float Volume();
|
||||
|
||||
std::string GetTimeZoneString();
|
||||
std::string GetTimeZoneString(TimeZone time_zone);
|
||||
|
||||
void LogSettings();
|
||||
|
||||
@ -619,4 +530,7 @@ void UpdateRescalingInfo();
|
||||
// Restore the global state of all applicable settings in the Values struct
|
||||
void RestoreGlobalState(bool is_powered_on);
|
||||
|
||||
bool IsConfiguringGlobal();
|
||||
void SetConfiguringGlobal(bool is_global);
|
||||
|
||||
} // namespace Settings
|
||||
|
60
src/common/settings_common.cpp
Normal file
60
src/common/settings_common.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/settings_common.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
BasicSetting::BasicSetting(Linkage& linkage, const std::string& name, enum Category category_,
|
||||
bool save_, bool runtime_modifiable_, u32 specialization_,
|
||||
BasicSetting* other_setting_)
|
||||
: label{name}, category{category_}, id{linkage.count}, save{save_},
|
||||
runtime_modifiable{runtime_modifiable_}, specialization{specialization_},
|
||||
other_setting{other_setting_} {
|
||||
linkage.by_category[category].push_back(this);
|
||||
linkage.count++;
|
||||
}
|
||||
|
||||
BasicSetting::~BasicSetting() = default;
|
||||
|
||||
std::string BasicSetting::ToStringGlobal() const {
|
||||
return this->ToString();
|
||||
}
|
||||
|
||||
bool BasicSetting::UsingGlobal() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void BasicSetting::SetGlobal(bool global) {}
|
||||
|
||||
bool BasicSetting::Save() const {
|
||||
return save;
|
||||
}
|
||||
|
||||
bool BasicSetting::RuntimeModfiable() const {
|
||||
return runtime_modifiable;
|
||||
}
|
||||
|
||||
Category BasicSetting::GetCategory() const {
|
||||
return category;
|
||||
}
|
||||
|
||||
u32 BasicSetting::Specialization() const {
|
||||
return specialization;
|
||||
}
|
||||
|
||||
BasicSetting* BasicSetting::PairedSetting() const {
|
||||
return other_setting;
|
||||
}
|
||||
|
||||
const std::string& BasicSetting::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
Linkage::Linkage(u32 initial_count) : count{initial_count} {}
|
||||
Linkage::~Linkage() = default;
|
||||
|
||||
} // namespace Settings
|
256
src/common/settings_common.h
Normal file
256
src/common/settings_common.h
Normal file
@ -0,0 +1,256 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
enum class Category : u32 {
|
||||
Audio,
|
||||
Core,
|
||||
Cpu,
|
||||
CpuDebug,
|
||||
CpuUnsafe,
|
||||
Renderer,
|
||||
RendererAdvanced,
|
||||
RendererDebug,
|
||||
System,
|
||||
SystemAudio,
|
||||
DataStorage,
|
||||
Debugging,
|
||||
DebuggingGraphics,
|
||||
Miscellaneous,
|
||||
Network,
|
||||
WebService,
|
||||
AddOns,
|
||||
Controls,
|
||||
Ui,
|
||||
UiGeneral,
|
||||
UiLayout,
|
||||
UiGameList,
|
||||
Screenshots,
|
||||
Shortcuts,
|
||||
Multiplayer,
|
||||
Services,
|
||||
Paths,
|
||||
MaxEnum,
|
||||
};
|
||||
|
||||
constexpr u8 SpecializationTypeMask = 0xf;
|
||||
constexpr u8 SpecializationAttributeMask = 0xf0;
|
||||
constexpr u8 SpecializationAttributeOffset = 4;
|
||||
|
||||
// Scalar and countable could have better names
|
||||
enum Specialization : u8 {
|
||||
Default = 0,
|
||||
Time = 1, // Duration or specific moment in time
|
||||
Hex = 2, // Hexadecimal number
|
||||
List = 3, // Setting has specific members
|
||||
RuntimeList = 4, // Members of the list are determined during runtime
|
||||
Scalar = 5, // Values are continuous
|
||||
Countable = 6, // Can be stepped through
|
||||
Paired = 7, // Another setting is associated with this setting
|
||||
|
||||
Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage
|
||||
};
|
||||
|
||||
class BasicSetting;
|
||||
|
||||
class Linkage {
|
||||
public:
|
||||
explicit Linkage(u32 initial_count = 0);
|
||||
~Linkage();
|
||||
std::map<Category, std::vector<BasicSetting*>> by_category{};
|
||||
std::vector<std::function<void()>> restore_functions{};
|
||||
u32 count;
|
||||
};
|
||||
|
||||
/**
|
||||
* BasicSetting is an abstract class that only keeps track of metadata. The string methods are
|
||||
* available to get data values out.
|
||||
*/
|
||||
class BasicSetting {
|
||||
protected:
|
||||
explicit BasicSetting(Linkage& linkage, const std::string& name, Category category_, bool save_,
|
||||
bool runtime_modifiable_, u32 specialization,
|
||||
BasicSetting* other_setting);
|
||||
|
||||
public:
|
||||
virtual ~BasicSetting();
|
||||
|
||||
/*
|
||||
* Data retrieval
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a string representation of the internal data. If the Setting is Switchable, it
|
||||
* respects the internal global state: it is based on GetValue().
|
||||
*
|
||||
* @returns A string representation of the internal data.
|
||||
*/
|
||||
[[nodiscard]] virtual std::string ToString() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the global version of internal data. If the Setting is
|
||||
* not Switchable, it behaves like ToString.
|
||||
*
|
||||
* @returns A string representation of the global version of internal data.
|
||||
*/
|
||||
[[nodiscard]] virtual std::string ToStringGlobal() const;
|
||||
|
||||
/**
|
||||
* @returns A string representation of the Setting's default value.
|
||||
*/
|
||||
[[nodiscard]] virtual std::string DefaultToString() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the minimum value of the setting. If the Setting is not
|
||||
* ranged, the string represents the default initialization of the data type.
|
||||
*
|
||||
* @returns A string representation of the minimum value of the setting.
|
||||
*/
|
||||
[[nodiscard]] virtual std::string MinVal() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the maximum value of the setting. If the Setting is not
|
||||
* ranged, the string represents the default initialization of the data type.
|
||||
*
|
||||
* @returns A string representation of the maximum value of the setting.
|
||||
*/
|
||||
[[nodiscard]] virtual std::string MaxVal() const = 0;
|
||||
|
||||
/**
|
||||
* Takes a string input, converts it to the internal data type if necessary, and then runs
|
||||
* SetValue with it.
|
||||
*
|
||||
* @param load String of the input data.
|
||||
*/
|
||||
virtual void LoadString(const std::string& load) = 0;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the data. If the data is an enum, it returns a string of
|
||||
* the enum value. If the internal data type is not an enum, this is equivalent to ToString.
|
||||
*
|
||||
* e.g. renderer_backend.Canonicalize() == "OpenGL"
|
||||
*
|
||||
* @returns Canonicalized string representation of the internal data
|
||||
*/
|
||||
[[nodiscard]] virtual std::string Canonicalize() const = 0;
|
||||
|
||||
/*
|
||||
* Metadata
|
||||
*/
|
||||
|
||||
/**
|
||||
* @returns A unique identifier for the Setting's internal data type.
|
||||
*/
|
||||
[[nodiscard]] virtual std::type_index TypeId() const = 0;
|
||||
|
||||
/**
|
||||
* Returns true if the Setting's internal data type is an enum.
|
||||
*
|
||||
* @returns True if the Setting's internal data type is an enum
|
||||
*/
|
||||
[[nodiscard]] virtual constexpr bool IsEnum() const = 0;
|
||||
|
||||
/**
|
||||
* Returns true if the current setting is Switchable.
|
||||
*
|
||||
* @returns If the setting is a SwitchableSetting
|
||||
*/
|
||||
[[nodiscard]] virtual constexpr bool Switchable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true to suggest that a frontend can read or write the setting to a configuration
|
||||
* file.
|
||||
*
|
||||
* @returns The save preference
|
||||
*/
|
||||
[[nodiscard]] bool Save() const;
|
||||
|
||||
/**
|
||||
* @returns true if the current setting can be changed while the guest is running.
|
||||
*/
|
||||
[[nodiscard]] bool RuntimeModfiable() const;
|
||||
|
||||
/**
|
||||
* @returns A unique number corresponding to the setting.
|
||||
*/
|
||||
[[nodiscard]] constexpr u32 Id() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setting's category AKA INI group.
|
||||
*
|
||||
* @returns The setting's category
|
||||
*/
|
||||
[[nodiscard]] Category GetCategory() const;
|
||||
|
||||
/**
|
||||
* @returns Extra metadata for data representation in frontend implementations.
|
||||
*/
|
||||
[[nodiscard]] u32 Specialization() const;
|
||||
|
||||
/**
|
||||
* @returns Another BasicSetting if one is paired, or nullptr otherwise.
|
||||
*/
|
||||
[[nodiscard]] BasicSetting* PairedSetting() const;
|
||||
|
||||
/**
|
||||
* Returns the label this setting was created with.
|
||||
*
|
||||
* @returns A reference to the label
|
||||
*/
|
||||
[[nodiscard]] const std::string& GetLabel() const;
|
||||
|
||||
/**
|
||||
* @returns If the Setting checks input values for valid ranges.
|
||||
*/
|
||||
[[nodiscard]] virtual constexpr bool Ranged() const = 0;
|
||||
|
||||
/**
|
||||
* @returns The index of the enum if the underlying setting type is an enum, else max of u32.
|
||||
*/
|
||||
[[nodiscard]] virtual constexpr u32 EnumIndex() const = 0;
|
||||
|
||||
/*
|
||||
* Switchable settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets a setting's global state. True means use the normal setting, false to use a custom
|
||||
* value. Has no effect if the Setting is not Switchable.
|
||||
*
|
||||
* @param global The desired state
|
||||
*/
|
||||
virtual void SetGlobal(bool global);
|
||||
|
||||
/**
|
||||
* Returns true if the setting is using the normal setting value. Always true if the setting is
|
||||
* not Switchable.
|
||||
*
|
||||
* @returns The Setting's global state
|
||||
*/
|
||||
[[nodiscard]] virtual bool UsingGlobal() const;
|
||||
|
||||
private:
|
||||
const std::string label; ///< The setting's label
|
||||
const Category category; ///< The setting's category AKA INI group
|
||||
const u32 id; ///< Unique integer for the setting
|
||||
const bool save; ///< Suggests if the setting should be saved and read to a frontend config
|
||||
const bool
|
||||
runtime_modifiable; ///< Suggests if the setting can be modified while a guest is running
|
||||
const u32 specialization; ///< Extra data to identify representation of a setting
|
||||
BasicSetting* const other_setting; ///< A paired setting
|
||||
};
|
||||
|
||||
} // namespace Settings
|
214
src/common/settings_enums.h
Normal file
214
src/common/settings_enums.h
Normal file
@ -0,0 +1,214 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
template <typename T>
|
||||
struct EnumMetadata {
|
||||
static std::vector<std::pair<std::string, T>> Canonicalizations();
|
||||
static u32 Index();
|
||||
};
|
||||
|
||||
#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
|
||||
#define PAIR_44(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_45(N, __VA_ARGS__))
|
||||
#define PAIR_43(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_44(N, __VA_ARGS__))
|
||||
#define PAIR_42(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_43(N, __VA_ARGS__))
|
||||
#define PAIR_41(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_42(N, __VA_ARGS__))
|
||||
#define PAIR_40(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_41(N, __VA_ARGS__))
|
||||
#define PAIR_39(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_40(N, __VA_ARGS__))
|
||||
#define PAIR_38(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_39(N, __VA_ARGS__))
|
||||
#define PAIR_37(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_38(N, __VA_ARGS__))
|
||||
#define PAIR_36(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_37(N, __VA_ARGS__))
|
||||
#define PAIR_35(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_36(N, __VA_ARGS__))
|
||||
#define PAIR_34(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_35(N, __VA_ARGS__))
|
||||
#define PAIR_33(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_34(N, __VA_ARGS__))
|
||||
#define PAIR_32(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_33(N, __VA_ARGS__))
|
||||
#define PAIR_31(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_32(N, __VA_ARGS__))
|
||||
#define PAIR_30(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_31(N, __VA_ARGS__))
|
||||
#define PAIR_29(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_30(N, __VA_ARGS__))
|
||||
#define PAIR_28(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_29(N, __VA_ARGS__))
|
||||
#define PAIR_27(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_28(N, __VA_ARGS__))
|
||||
#define PAIR_26(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_27(N, __VA_ARGS__))
|
||||
#define PAIR_25(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_26(N, __VA_ARGS__))
|
||||
#define PAIR_24(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_25(N, __VA_ARGS__))
|
||||
#define PAIR_23(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_24(N, __VA_ARGS__))
|
||||
#define PAIR_22(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_23(N, __VA_ARGS__))
|
||||
#define PAIR_21(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_22(N, __VA_ARGS__))
|
||||
#define PAIR_20(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_21(N, __VA_ARGS__))
|
||||
#define PAIR_19(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_20(N, __VA_ARGS__))
|
||||
#define PAIR_18(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_19(N, __VA_ARGS__))
|
||||
#define PAIR_17(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_18(N, __VA_ARGS__))
|
||||
#define PAIR_16(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_17(N, __VA_ARGS__))
|
||||
#define PAIR_15(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_16(N, __VA_ARGS__))
|
||||
#define PAIR_14(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_15(N, __VA_ARGS__))
|
||||
#define PAIR_13(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_14(N, __VA_ARGS__))
|
||||
#define PAIR_12(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_13(N, __VA_ARGS__))
|
||||
#define PAIR_11(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_12(N, __VA_ARGS__))
|
||||
#define PAIR_10(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_11(N, __VA_ARGS__))
|
||||
#define PAIR_9(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_10(N, __VA_ARGS__))
|
||||
#define PAIR_8(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_9(N, __VA_ARGS__))
|
||||
#define PAIR_7(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_8(N, __VA_ARGS__))
|
||||
#define PAIR_6(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_7(N, __VA_ARGS__))
|
||||
#define PAIR_5(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_6(N, __VA_ARGS__))
|
||||
#define PAIR_4(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_5(N, __VA_ARGS__))
|
||||
#define PAIR_3(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_4(N, __VA_ARGS__))
|
||||
#define PAIR_2(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_3(N, __VA_ARGS__))
|
||||
#define PAIR_1(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_2(N, __VA_ARGS__))
|
||||
#define PAIR(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_1(N, __VA_ARGS__))
|
||||
|
||||
#define ENUM(NAME, ...) \
|
||||
enum class NAME : u32 { __VA_ARGS__ }; \
|
||||
template <> \
|
||||
inline std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
|
||||
return {PAIR(NAME, __VA_ARGS__)}; \
|
||||
} \
|
||||
template <> \
|
||||
inline u32 EnumMetadata<NAME>::Index() { \
|
||||
return __COUNTER__; \
|
||||
}
|
||||
|
||||
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||
// canonicalizations
|
||||
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
||||
enum class AudioEngine : u32 {
|
||||
Auto,
|
||||
Cubeb,
|
||||
Sdl2,
|
||||
Null,
|
||||
};
|
||||
|
||||
template <>
|
||||
inline std::vector<std::pair<std::string, AudioEngine>>
|
||||
EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||
return {
|
||||
{"auto", AudioEngine::Auto},
|
||||
{"cubeb", AudioEngine::Cubeb},
|
||||
{"sdl2", AudioEngine::Sdl2},
|
||||
{"null", AudioEngine::Null},
|
||||
};
|
||||
}
|
||||
|
||||
template <>
|
||||
inline u32 EnumMetadata<AudioEngine>::Index() {
|
||||
// This is just a sufficiently large number that is more than the number of other enums declared
|
||||
// here
|
||||
return 100;
|
||||
}
|
||||
|
||||
ENUM(AudioMode, Mono, Stereo, Surround);
|
||||
|
||||
ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
|
||||
Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
|
||||
ChineseSimplified, ChineseTraditional, PortugueseBrazilian);
|
||||
|
||||
ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
|
||||
|
||||
ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt,
|
||||
GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
|
||||
Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
|
||||
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
|
||||
|
||||
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
|
||||
|
||||
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||
|
||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||
|
||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||
|
||||
ENUM(RendererBackend, OpenGL, Vulkan, Null);
|
||||
|
||||
ENUM(ShaderBackend, Glsl, Glasm, SpirV);
|
||||
|
||||
ENUM(GpuAccuracy, Normal, High, Extreme);
|
||||
|
||||
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
||||
|
||||
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
|
||||
|
||||
ENUM(FullscreenMode, Borderless, Exclusive);
|
||||
|
||||
ENUM(NvdecEmulation, Off, Cpu, Gpu);
|
||||
|
||||
ENUM(ResolutionSetup, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X,
|
||||
Res8X);
|
||||
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, MaxEnum);
|
||||
|
||||
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
||||
|
||||
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
|
||||
|
||||
template <typename Type>
|
||||
inline std::string CanonicalizeEnum(Type id) {
|
||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||
for (auto& [name, value] : group) {
|
||||
if (value == id) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type ToEnum(const std::string& canonicalization) {
|
||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||
for (auto& [name, value] : group) {
|
||||
if (name == canonicalization) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
} // namespace Settings
|
||||
|
||||
#undef ENUM
|
||||
#undef PAIR
|
||||
#undef PAIR_1
|
||||
#undef PAIR_2
|
||||
#undef PAIR_3
|
||||
#undef PAIR_4
|
||||
#undef PAIR_5
|
||||
#undef PAIR_6
|
||||
#undef PAIR_7
|
||||
#undef PAIR_8
|
||||
#undef PAIR_9
|
||||
#undef PAIR_10
|
||||
#undef PAIR_12
|
||||
#undef PAIR_13
|
||||
#undef PAIR_14
|
||||
#undef PAIR_15
|
||||
#undef PAIR_16
|
||||
#undef PAIR_17
|
||||
#undef PAIR_18
|
||||
#undef PAIR_19
|
||||
#undef PAIR_20
|
||||
#undef PAIR_22
|
||||
#undef PAIR_23
|
||||
#undef PAIR_24
|
||||
#undef PAIR_25
|
||||
#undef PAIR_26
|
||||
#undef PAIR_27
|
||||
#undef PAIR_28
|
||||
#undef PAIR_29
|
||||
#undef PAIR_30
|
||||
#undef PAIR_32
|
||||
#undef PAIR_33
|
||||
#undef PAIR_34
|
||||
#undef PAIR_35
|
||||
#undef PAIR_36
|
||||
#undef PAIR_37
|
||||
#undef PAIR_38
|
||||
#undef PAIR_39
|
||||
#undef PAIR_40
|
||||
#undef PAIR_42
|
||||
#undef PAIR_43
|
||||
#undef PAIR_44
|
||||
#undef PAIR_45
|
394
src/common/settings_setting.h
Normal file
394
src/common/settings_setting.h
Normal file
@ -0,0 +1,394 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings_common.h"
|
||||
#include "common/settings_enums.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
/** The Setting class is a simple resource manager. It defines a label and default value
|
||||
* alongside the actual value of the setting for simpler and less-error prone use with frontend
|
||||
* configurations. Specifying a default value and label is required. A minimum and maximum range
|
||||
* can be specified for sanitization.
|
||||
*/
|
||||
template <typename Type, bool ranged = false>
|
||||
class Setting : public BasicSetting {
|
||||
protected:
|
||||
Setting() = default;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
*
|
||||
* @param linkage Setting registry
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
* @param category_ Category of the setting AKA INI group
|
||||
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||
*/
|
||||
explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
|
||||
Category category_, u32 specialization_ = Specialization::Default,
|
||||
bool save_ = true, bool runtime_modifiable_ = false,
|
||||
BasicSetting* other_setting_ = nullptr)
|
||||
requires(!ranged)
|
||||
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
|
||||
other_setting_),
|
||||
value{default_val}, default_value{default_val} {}
|
||||
virtual ~Setting() = default;
|
||||
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param linkage Setting registry
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
* @param category_ Category of the setting AKA INI group
|
||||
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||
*/
|
||||
explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
|
||||
const Type& max_val, const std::string& name, Category category_,
|
||||
u32 specialization_ = Specialization::Default, bool save_ = true,
|
||||
bool runtime_modifiable_ = false, BasicSetting* other_setting_ = nullptr)
|
||||
requires(ranged)
|
||||
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
|
||||
other_setting_),
|
||||
value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val} {}
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting's value.
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
[[nodiscard]] virtual const Type& GetValue() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the setting to the given value.
|
||||
*
|
||||
* @param val The desired value
|
||||
*/
|
||||
virtual void SetValue(const Type& val) {
|
||||
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
|
||||
std::swap(value, temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that this setting was created with.
|
||||
*
|
||||
* @returns A reference to the default value
|
||||
*/
|
||||
[[nodiscard]] const Type& GetDefault() const {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool IsEnum() const override {
|
||||
return std::is_enum_v<Type>;
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] std::string ToString(const Type& value_) const {
|
||||
if constexpr (std::is_same_v<Type, std::string>) {
|
||||
return value_;
|
||||
} else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
|
||||
return value_.has_value() ? std::to_string(*value_) : "none";
|
||||
} else if constexpr (std::is_same_v<Type, bool>) {
|
||||
return value_ ? "true" : "false";
|
||||
} else if constexpr (std::is_same_v<Type, AudioEngine>) {
|
||||
// Compatibility with old AudioEngine setting being a string
|
||||
return CanonicalizeEnum(value_);
|
||||
} else {
|
||||
return std::to_string(static_cast<u64>(value_));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Converts the value of the setting to a std::string. Respects the global state if the setting
|
||||
* has one.
|
||||
*
|
||||
* @returns The current setting as a std::string
|
||||
*/
|
||||
[[nodiscard]] std::string ToString() const override {
|
||||
return ToString(this->GetValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value of the setting as a std::string.
|
||||
*
|
||||
* @returns The default value as a string.
|
||||
*/
|
||||
[[nodiscard]] std::string DefaultToString() const override {
|
||||
return ToString(default_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a value to the setting.
|
||||
*
|
||||
* @param val The desired setting value
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
virtual const Type& operator=(const Type& val) {
|
||||
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
|
||||
std::swap(value, temp);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting.
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
explicit virtual operator const Type&() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
|
||||
* thus respecting its constraints.
|
||||
*
|
||||
* @param input The desired value
|
||||
*/
|
||||
void LoadString(const std::string& input) override final {
|
||||
if (input.empty()) {
|
||||
this->SetValue(this->GetDefault());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if constexpr (std::is_same_v<Type, std::string>) {
|
||||
this->SetValue(input);
|
||||
} else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
|
||||
this->SetValue(static_cast<u32>(std::stoul(input)));
|
||||
} else if constexpr (std::is_same_v<Type, bool>) {
|
||||
this->SetValue(input == "true");
|
||||
} else if constexpr (std::is_same_v<Type, AudioEngine>) {
|
||||
this->SetValue(ToEnum<Type>(input));
|
||||
} else {
|
||||
this->SetValue(static_cast<Type>(std::stoll(input)));
|
||||
}
|
||||
} catch (std::invalid_argument&) {
|
||||
this->SetValue(this->GetDefault());
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string Canonicalize() const override final {
|
||||
if constexpr (std::is_enum_v<Type>) {
|
||||
return CanonicalizeEnum(this->GetValue());
|
||||
} else {
|
||||
return ToString(this->GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives us another way to identify the setting without having to go through a string.
|
||||
*
|
||||
* @returns the type_index of the setting's type
|
||||
*/
|
||||
[[nodiscard]] std::type_index TypeId() const override final {
|
||||
return std::type_index(typeid(Type));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 EnumIndex() const override final {
|
||||
if constexpr (std::is_enum_v<Type>) {
|
||||
return EnumMetadata<Type>::Index();
|
||||
} else {
|
||||
return std::numeric_limits<u32>::max();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string MinVal() const override final {
|
||||
return this->ToString(minimum);
|
||||
}
|
||||
[[nodiscard]] std::string MaxVal() const override final {
|
||||
return this->ToString(maximum);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool Ranged() const override {
|
||||
return ranged;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type value{}; ///< The setting
|
||||
const Type default_value{}; ///< The default value
|
||||
const Type maximum{}; ///< Maximum allowed value of the setting
|
||||
const Type minimum{}; ///< Minimum allowed value of the setting
|
||||
};
|
||||
|
||||
/**
|
||||
* The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
|
||||
* custom setting to switch to when a guest application specifically requires it. The effect is that
|
||||
* other components of the emulator can access the setting's intended value without any need for the
|
||||
* component to ask whether the custom or global setting is needed at the moment.
|
||||
*
|
||||
* By default, the global setting is used.
|
||||
*/
|
||||
template <typename Type, bool ranged = false>
|
||||
class SwitchableSetting : virtual public Setting<Type, ranged> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
*
|
||||
* @param linkage Setting registry
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
* @param category_ Category of the setting AKA INI group
|
||||
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||
*/
|
||||
template <typename T = BasicSetting>
|
||||
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
|
||||
Category category_, u32 specialization_ = Specialization::Default,
|
||||
bool save_ = true, bool runtime_modifiable_ = false,
|
||||
typename std::enable_if<!ranged, T*>::type other_setting_ = nullptr)
|
||||
: Setting<Type, false>{
|
||||
linkage, default_val, name, category_, specialization_,
|
||||
save_, runtime_modifiable_, other_setting_} {
|
||||
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
|
||||
}
|
||||
virtual ~SwitchableSetting() = default;
|
||||
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param linkage Setting registry
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
* @param category_ Category of the setting AKA INI group
|
||||
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||
*/
|
||||
template <typename T = BasicSetting>
|
||||
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
|
||||
const Type& max_val, const std::string& name, Category category_,
|
||||
u32 specialization_ = Specialization::Default, bool save_ = true,
|
||||
bool runtime_modifiable_ = false,
|
||||
typename std::enable_if<ranged, T*>::type other_setting_ = nullptr)
|
||||
: Setting<Type, true>{linkage, default_val, min_val,
|
||||
max_val, name, category_,
|
||||
specialization_, save_, runtime_modifiable_,
|
||||
other_setting_} {
|
||||
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells this setting to represent either the global or custom setting when other member
|
||||
* functions are used.
|
||||
*
|
||||
* @param to_global Whether to use the global or custom setting.
|
||||
*/
|
||||
void SetGlobal(bool to_global) override final {
|
||||
use_global = to_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this setting is using the global setting or not.
|
||||
*
|
||||
* @returns The global state
|
||||
*/
|
||||
[[nodiscard]] bool UsingGlobal() const override final {
|
||||
return use_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either the global or custom setting depending on the values of this setting's global
|
||||
* state or if the global value was specifically requested.
|
||||
*
|
||||
* @param need_global Request global value regardless of setting's state; defaults to false
|
||||
*
|
||||
* @returns The required value of the setting
|
||||
*/
|
||||
[[nodiscard]] const Type& GetValue() const override final {
|
||||
if (use_global) {
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
[[nodiscard]] const Type& GetValue(bool need_global) const {
|
||||
if (use_global || need_global) {
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current setting value depending on the global state.
|
||||
*
|
||||
* @param val The new value
|
||||
*/
|
||||
void SetValue(const Type& val) override final {
|
||||
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||
if (use_global) {
|
||||
std::swap(this->value, temp);
|
||||
} else {
|
||||
std::swap(custom, temp);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool Switchable() const override final {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string ToStringGlobal() const override final {
|
||||
return this->ToString(this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the current setting value depending on the global state.
|
||||
*
|
||||
* @param val The new value
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
const Type& operator=(const Type& val) override final {
|
||||
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||
if (use_global) {
|
||||
std::swap(this->value, temp);
|
||||
return this->value;
|
||||
}
|
||||
std::swap(custom, temp);
|
||||
return custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting value depending on the global state.
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
explicit operator const Type&() const override final {
|
||||
if (use_global) {
|
||||
return this->value;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool use_global{true}; ///< The setting's global state
|
||||
Type custom{}; ///< The custom value of the setting
|
||||
};
|
||||
|
||||
} // namespace Settings
|
@ -287,7 +287,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||
}
|
||||
} else {
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
@ -307,7 +307,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||
}
|
||||
|
||||
// Curated optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) {
|
||||
config.unsafe_optimizations = true;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
|
||||
@ -316,7 +316,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||
}
|
||||
|
||||
// Paranoia mode for debugging optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) {
|
||||
config.unsafe_optimizations = false;
|
||||
config.optimizations = Dynarmic::no_optimizations;
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||
}
|
||||
} else {
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
@ -367,7 +367,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||
}
|
||||
|
||||
// Curated optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) {
|
||||
config.unsafe_optimizations = true;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
config.fastmem_address_space_bits = 64;
|
||||
@ -375,7 +375,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||
}
|
||||
|
||||
// Paranoia mode for debugging optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) {
|
||||
config.unsafe_optimizations = false;
|
||||
config.optimizations = Dynarmic::no_optimizations;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/core.h"
|
||||
@ -140,16 +141,13 @@ struct System::Impl {
|
||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
|
||||
extended_memory_layout =
|
||||
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
|
||||
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
|
||||
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
const auto current_time =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
|
||||
Settings::values.custom_rtc_differential =
|
||||
Settings::values.custom_rtc.value_or(current_time) - current_time;
|
||||
RefreshTime();
|
||||
|
||||
// Create a default fs if one doesn't already exist.
|
||||
if (virtual_filesystem == nullptr) {
|
||||
@ -172,7 +170,8 @@ struct System::Impl {
|
||||
void ReinitializeIfNecessary(System& system) {
|
||||
const bool must_reinitialize =
|
||||
is_multicore != Settings::values.use_multi_core.GetValue() ||
|
||||
extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
|
||||
extended_memory_layout != (Settings::values.memory_layout_mode.GetValue() !=
|
||||
Settings::MemoryLayout::Memory_4Gb);
|
||||
|
||||
if (!must_reinitialize) {
|
||||
return;
|
||||
@ -181,11 +180,22 @@ struct System::Impl {
|
||||
LOG_DEBUG(Kernel, "Re-initializing");
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
|
||||
extended_memory_layout =
|
||||
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
|
||||
|
||||
Initialize(system);
|
||||
}
|
||||
|
||||
void RefreshTime() {
|
||||
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
const auto current_time =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
|
||||
Settings::values.custom_rtc_differential =
|
||||
(Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue()
|
||||
: current_time) -
|
||||
current_time;
|
||||
}
|
||||
|
||||
void Run() {
|
||||
std::unique_lock<std::mutex> lk(suspend_guard);
|
||||
|
||||
@ -1028,6 +1038,8 @@ void System::Exit() {
|
||||
}
|
||||
|
||||
void System::ApplySettings() {
|
||||
impl->RefreshTime();
|
||||
|
||||
if (IsPoweredOn()) {
|
||||
Renderer().RefreshBaseSettings();
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ NACP::NACP(VirtualFile file) {
|
||||
NACP::~NACP() = default;
|
||||
|
||||
const LanguageEntry& NACP::GetLanguageEntry() const {
|
||||
Language language = language_to_codes[Settings::values.language_index.GetValue()];
|
||||
Language language =
|
||||
language_to_codes[static_cast<s32>(Settings::values.language_index.GetValue())];
|
||||
|
||||
{
|
||||
const auto& language_entry = raw.language_entries.at(static_cast<u8>(language));
|
||||
|
@ -626,8 +626,8 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
|
||||
auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
|
||||
|
||||
// Get language code from settings
|
||||
const auto language_code =
|
||||
Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
|
||||
const auto language_code = Service::Set::GetLanguageCodeFromIndex(
|
||||
static_cast<u32>(Settings::values.language_index.GetValue()));
|
||||
|
||||
// Convert to application language and get priority list
|
||||
const auto application_language =
|
||||
|
@ -35,7 +35,7 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw_file) {
|
||||
update_raw = std::move(update_raw_file);
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
|
||||
VirtualFile RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
|
||||
if (!updatable) {
|
||||
return file;
|
||||
}
|
||||
@ -45,12 +45,11 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_titl
|
||||
return patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw);
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
|
||||
VirtualFile RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
|
||||
auto nca = content_provider.GetEntry(title_id, type);
|
||||
|
||||
if (nca == nullptr) {
|
||||
// TODO: Find the right error code to use here
|
||||
return ResultUnknown;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PatchManager patch_manager{title_id, filesystem_controller, content_provider};
|
||||
@ -58,28 +57,20 @@ ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecor
|
||||
return patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type);
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex(
|
||||
u64 title_id, u8 program_index, ContentRecordType type) const {
|
||||
VirtualFile RomFSFactory::OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
|
||||
ContentRecordType type) const {
|
||||
const auto res_title_id = GetBaseTitleIDWithProgramIndex(title_id, program_index);
|
||||
|
||||
return OpenPatchedRomFS(res_title_id, type);
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
|
||||
ContentRecordType type) const {
|
||||
VirtualFile RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) const {
|
||||
const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);
|
||||
if (res == nullptr) {
|
||||
// TODO(DarkLordZach): Find the right error code to use here
|
||||
return ResultUnknown;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto romfs = res->GetRomFS();
|
||||
if (romfs == nullptr) {
|
||||
// TODO(DarkLordZach): Find the right error code to use here
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
return romfs;
|
||||
return res->GetRomFS();
|
||||
}
|
||||
|
||||
std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage,
|
||||
|
@ -41,13 +41,11 @@ public:
|
||||
~RomFSFactory();
|
||||
|
||||
void SetPackedUpdate(VirtualFile update_raw_file);
|
||||
[[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
|
||||
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
|
||||
ContentRecordType type) const;
|
||||
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFSWithProgramIndex(
|
||||
u64 title_id, u8 program_index, ContentRecordType type) const;
|
||||
[[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage,
|
||||
ContentRecordType type) const;
|
||||
[[nodiscard]] VirtualFile OpenCurrentProcess(u64 current_process_title_id) const;
|
||||
[[nodiscard]] VirtualFile OpenPatchedRomFS(u64 title_id, ContentRecordType type) const;
|
||||
[[nodiscard]] VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
|
||||
ContentRecordType type) const;
|
||||
[[nodiscard]] VirtualFile Open(u64 title_id, StorageId storage, ContentRecordType type) const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::shared_ptr<NCA> GetEntry(u64 title_id, StorageId storage,
|
||||
|
@ -108,26 +108,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_director
|
||||
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
|
||||
const SaveDataAttribute& meta) const {
|
||||
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||
PrintSaveDataAttributeWarnings(meta);
|
||||
|
||||
const auto save_directory =
|
||||
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||
|
||||
auto out = dir->CreateDirectoryRelative(save_directory);
|
||||
|
||||
// Return an error if the save data doesn't actually exist.
|
||||
if (out == nullptr) {
|
||||
// TODO(DarkLordZach): Find out correct error code.
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
return out;
|
||||
return dir->CreateDirectoryRelative(save_directory);
|
||||
}
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
|
||||
const SaveDataAttribute& meta) const {
|
||||
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||
|
||||
const auto save_directory =
|
||||
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||
@ -138,12 +128,6 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
|
||||
return Create(space, meta);
|
||||
}
|
||||
|
||||
// Return an error if the save data doesn't actually exist.
|
||||
if (out == nullptr) {
|
||||
// TODO(Subv): Find out correct error code.
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,8 @@ public:
|
||||
explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_);
|
||||
~SaveDataFactory();
|
||||
|
||||
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
||||
VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
||||
VirtualDir Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
||||
|
||||
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
||||
|
||||
|
@ -23,7 +23,7 @@ SDMCFactory::SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_)
|
||||
|
||||
SDMCFactory::~SDMCFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SDMCFactory::Open() const {
|
||||
VirtualDir SDMCFactory::Open() const {
|
||||
return sd_dir;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
explicit SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_);
|
||||
~SDMCFactory();
|
||||
|
||||
ResultVal<VirtualDir> Open() const;
|
||||
VirtualDir Open() const;
|
||||
|
||||
VirtualDir GetSDMCModificationLoadRoot(u64 title_id) const;
|
||||
VirtualDir GetSDMCContentDirectory() const;
|
||||
|
@ -35,13 +35,27 @@ namespace {
|
||||
using namespace Common::Literals;
|
||||
|
||||
u32 GetMemorySizeForInit() {
|
||||
return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemorySize_8GB
|
||||
: Smc::MemorySize_4GB;
|
||||
switch (Settings::values.memory_layout_mode.GetValue()) {
|
||||
case Settings::MemoryLayout::Memory_4Gb:
|
||||
return Smc::MemorySize_4GB;
|
||||
case Settings::MemoryLayout::Memory_6Gb:
|
||||
return Smc::MemorySize_6GB;
|
||||
case Settings::MemoryLayout::Memory_8Gb:
|
||||
return Smc::MemorySize_8GB;
|
||||
}
|
||||
return Smc::MemorySize_4GB;
|
||||
}
|
||||
|
||||
Smc::MemoryArrangement GetMemoryArrangeForInit() {
|
||||
return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemoryArrangement_8GB
|
||||
: Smc::MemoryArrangement_4GB;
|
||||
switch (Settings::values.memory_layout_mode.GetValue()) {
|
||||
case Settings::MemoryLayout::Memory_4Gb:
|
||||
return Smc::MemoryArrangement_4GB;
|
||||
case Settings::MemoryLayout::Memory_6Gb:
|
||||
return Smc::MemoryArrangement_6GB;
|
||||
case Settings::MemoryLayout::Memory_8Gb:
|
||||
return Smc::MemoryArrangement_8GB;
|
||||
}
|
||||
return Smc::MemoryArrangement_4GB;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -768,7 +768,7 @@ Result KPageTable::UnmapProcessMemory(KProcessAddress dst_addr, size_t size,
|
||||
m_memory_block_slab_manager, num_allocator_blocks);
|
||||
R_TRY(allocator_result);
|
||||
|
||||
CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
|
||||
R_TRY(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
|
||||
|
||||
// Apply the memory block update.
|
||||
m_memory_block_manager.Update(std::addressof(allocator), dst_addr, num_pages,
|
||||
|
@ -81,7 +81,8 @@ Result KProcess::Initialize(KProcess* process, Core::System& system, std::string
|
||||
process->m_capabilities.InitializeForMetadatalessProcess();
|
||||
process->m_is_initialized = true;
|
||||
|
||||
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
|
||||
std::mt19937 rng(Settings::values.rng_seed_enabled ? Settings::values.rng_seed.GetValue()
|
||||
: static_cast<u32>(std::time(nullptr)));
|
||||
std::uniform_int_distribution<u64> distribution;
|
||||
std::generate(process->m_random_entropy.begin(), process->m_random_entropy.end(),
|
||||
[&] { return distribution(rng); });
|
||||
|
@ -283,159 +283,6 @@ private:
|
||||
u32 description_end;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an optional value type. It holds a `Result` and, if that code is ResultSuccess, it
|
||||
* also holds a result of type `T`. If the code is an error code (not ResultSuccess), then trying
|
||||
* to access the inner value with operator* is undefined behavior and will assert with Unwrap().
|
||||
* Users of this class must be cognizant to check the status of the ResultVal with operator bool(),
|
||||
* Code(), Succeeded() or Failed() prior to accessing the inner value.
|
||||
*
|
||||
* An example of how it could be used:
|
||||
* \code
|
||||
* ResultVal<int> Frobnicate(float strength) {
|
||||
* if (strength < 0.f || strength > 1.0f) {
|
||||
* // Can't frobnicate too weakly or too strongly
|
||||
* return Result{ErrorModule::Common, 1};
|
||||
* } else {
|
||||
* // Frobnicated! Give caller a cookie
|
||||
* return 42;
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \code
|
||||
* auto frob_result = Frobnicate(0.75f);
|
||||
* if (frob_result) {
|
||||
* // Frobbed ok
|
||||
* printf("My cookie is %d\n", *frob_result);
|
||||
* } else {
|
||||
* printf("Guess I overdid it. :( Error code: %ux\n", frob_result.Code().raw);
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class ResultVal {
|
||||
public:
|
||||
constexpr ResultVal() : expected{} {}
|
||||
|
||||
constexpr ResultVal(Result code) : expected{Common::Unexpected(code)} {}
|
||||
|
||||
constexpr ResultVal(ResultRange range) : expected{Common::Unexpected(range)} {}
|
||||
|
||||
template <typename U>
|
||||
constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {}
|
||||
|
||||
template <typename... Args>
|
||||
constexpr ResultVal(Args&&... args) : expected{std::in_place, std::forward<Args>(args)...} {}
|
||||
|
||||
~ResultVal() = default;
|
||||
|
||||
constexpr ResultVal(const ResultVal&) = default;
|
||||
constexpr ResultVal(ResultVal&&) = default;
|
||||
|
||||
ResultVal& operator=(const ResultVal&) = default;
|
||||
ResultVal& operator=(ResultVal&&) = default;
|
||||
|
||||
[[nodiscard]] constexpr explicit operator bool() const noexcept {
|
||||
return expected.has_value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Result Code() const {
|
||||
return expected.has_value() ? ResultSuccess : expected.error();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool Succeeded() const {
|
||||
return expected.has_value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool Failed() const {
|
||||
return !expected.has_value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T* operator->() {
|
||||
return std::addressof(expected.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T* operator->() const {
|
||||
return std::addressof(expected.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& operator*() & {
|
||||
return *expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& operator*() const& {
|
||||
return *expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T&& operator*() && {
|
||||
return *expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T&& operator*() const&& {
|
||||
return *expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& Unwrap() & {
|
||||
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||
return expected.value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& Unwrap() const& {
|
||||
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||
return expected.value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T&& Unwrap() && {
|
||||
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||
return std::move(expected.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T&& Unwrap() const&& {
|
||||
ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
|
||||
return std::move(expected.value());
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] constexpr T ValueOr(U&& v) const& {
|
||||
return expected.value_or(v);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] constexpr T ValueOr(U&& v) && {
|
||||
return expected.value_or(v);
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO (Morph): Replace this with C++23 std::expected.
|
||||
Common::Expected<T, Result> expected;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
|
||||
* the contained value and assigns it to `target`, which can be either an l-value expression or a
|
||||
* variable declaration. If it fails the return code is returned from the current function. Thus it
|
||||
* can be used to cascade errors out, achieving something akin to exception handling.
|
||||
*/
|
||||
#define CASCADE_RESULT(target, source) \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).Failed()) { \
|
||||
return CONCAT2(check_result_L, __LINE__).Code(); \
|
||||
} \
|
||||
target = std::move(*CONCAT2(check_result_L, __LINE__))
|
||||
|
||||
/**
|
||||
* Analogous to CASCADE_RESULT, but for a bare Result. The code will be propagated if
|
||||
* non-success, or discarded otherwise.
|
||||
*/
|
||||
#define CASCADE_CODE(source) \
|
||||
do { \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).IsError()) { \
|
||||
return CONCAT2(check_result_L, __LINE__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define R_SUCCEEDED(res) (static_cast<Result>(res).IsSuccess())
|
||||
#define R_FAILED(res) (static_cast<Result>(res).IsFailure())
|
||||
|
||||
|
@ -765,15 +765,16 @@ Result Module::Interface::InitializeApplicationInfoBase() {
|
||||
// TODO(ogniK): This should be changed to reflect the target process for when we have multiple
|
||||
// processes emulated. As we don't actually have pid support we should assume we're just using
|
||||
// our own process
|
||||
const auto launch_property =
|
||||
system.GetARPManager().GetLaunchProperty(system.GetApplicationProcessProgramID());
|
||||
Glue::ApplicationLaunchProperty launch_property{};
|
||||
const auto result = system.GetARPManager().GetLaunchProperty(
|
||||
&launch_property, system.GetApplicationProcessProgramID());
|
||||
|
||||
if (launch_property.Failed()) {
|
||||
if (result != ResultSuccess) {
|
||||
LOG_ERROR(Service_ACC, "Failed to get launch property");
|
||||
return Account::ResultInvalidApplication;
|
||||
}
|
||||
|
||||
switch (launch_property->base_game_storage_id) {
|
||||
switch (launch_property.base_game_storage_id) {
|
||||
case FileSys::StorageId::GameCard:
|
||||
application_info.application_type = ApplicationType::GameCard;
|
||||
break;
|
||||
@ -785,7 +786,7 @@ Result Module::Interface::InitializeApplicationInfoBase() {
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Service_ACC, "Invalid game storage ID! storage_id={}",
|
||||
launch_property->base_game_storage_id);
|
||||
launch_property.base_game_storage_id);
|
||||
return Account::ResultInvalidApplication;
|
||||
}
|
||||
|
||||
|
@ -1317,6 +1317,50 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
rb.PushIpcInterface<IStorage>(system, std::move(memory));
|
||||
}
|
||||
|
||||
ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
||||
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "PopInData"},
|
||||
{1, nullptr, "PushOutData"},
|
||||
{2, nullptr, "PopInteractiveInData"},
|
||||
{3, nullptr, "PushInteractiveOutData"},
|
||||
{5, nullptr, "GetPopInDataEvent"},
|
||||
{6, nullptr, "GetPopInteractiveInDataEvent"},
|
||||
{10, nullptr, "ExitProcessAndReturn"},
|
||||
{11, nullptr, "GetLibraryAppletInfo"},
|
||||
{12, nullptr, "GetMainAppletIdentityInfo"},
|
||||
{13, nullptr, "CanUseApplicationCore"},
|
||||
{14, nullptr, "GetCallerAppletIdentityInfo"},
|
||||
{15, nullptr, "GetMainAppletApplicationControlProperty"},
|
||||
{16, nullptr, "GetMainAppletStorageId"},
|
||||
{17, nullptr, "GetCallerAppletIdentityInfoStack"},
|
||||
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
|
||||
{19, nullptr, "GetDesirableKeyboardLayout"},
|
||||
{20, nullptr, "PopExtraStorage"},
|
||||
{25, nullptr, "GetPopExtraStorageEvent"},
|
||||
{30, nullptr, "UnpopInData"},
|
||||
{31, nullptr, "UnpopExtraStorage"},
|
||||
{40, nullptr, "GetIndirectLayerProducerHandle"},
|
||||
{50, nullptr, "ReportVisibleError"},
|
||||
{51, nullptr, "ReportVisibleErrorWithErrorContext"},
|
||||
{60, nullptr, "GetMainAppletApplicationDesiredLanguage"},
|
||||
{70, nullptr, "GetCurrentApplicationId"},
|
||||
{80, nullptr, "RequestExitToSelf"},
|
||||
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
|
||||
{100, nullptr, "CreateGameMovieTrimmer"},
|
||||
{101, nullptr, "ReserveResourceForMovieOperation"},
|
||||
{102, nullptr, "UnreserveResourceForMovieOperation"},
|
||||
{110, nullptr, "GetMainAppletAvailableUsers"},
|
||||
{120, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
|
||||
{140, nullptr, "SetApplicationMemoryReservation"},
|
||||
{150, nullptr, "ShouldSetGpuTimeSliceManually"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
|
||||
|
||||
IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
: ServiceFramework{system_, "IApplicationFunctions"}, service_context{system,
|
||||
"IApplicationFunctions"} {
|
||||
@ -1534,11 +1578,13 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
|
||||
attribute.title_id = system.GetApplicationProcessProgramID();
|
||||
attribute.user_id = user_id;
|
||||
attribute.type = FileSys::SaveDataType::SaveData;
|
||||
|
||||
FileSys::VirtualDir save_data{};
|
||||
const auto res = system.GetFileSystemController().CreateSaveData(
|
||||
FileSys::SaveDataSpaceId::NandUser, attribute);
|
||||
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(res);
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
|
||||
@ -1623,26 +1669,30 @@ void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
|
||||
auto app_man = ns_am2->GetApplicationManagerInterface();
|
||||
|
||||
// Get desired application language
|
||||
const auto res_lang = app_man->GetApplicationDesiredLanguage(supported_languages);
|
||||
if (res_lang.Failed()) {
|
||||
u8 desired_language{};
|
||||
const auto res_lang =
|
||||
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
|
||||
if (res_lang != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res_lang.Code());
|
||||
rb.Push(res_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert to settings language code.
|
||||
const auto res_code = app_man->ConvertApplicationLanguageToLanguageCode(*res_lang);
|
||||
if (res_code.Failed()) {
|
||||
u64 language_code{};
|
||||
const auto res_code =
|
||||
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
|
||||
if (res_code != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res_code.Code());
|
||||
rb.Push(res_code);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_AM, "got desired_language={:016X}", *res_code);
|
||||
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(*res_code);
|
||||
rb.Push(language_code);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
|
||||
|
@ -22,30 +22,6 @@ class Nvnflinger;
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
// This is nn::settings::Language
|
||||
enum SystemLanguage {
|
||||
Japanese = 0,
|
||||
English = 1, // en-US
|
||||
French = 2,
|
||||
German = 3,
|
||||
Italian = 4,
|
||||
Spanish = 5,
|
||||
Chinese = 6,
|
||||
Korean = 7,
|
||||
Dutch = 8,
|
||||
Portuguese = 9,
|
||||
Russian = 10,
|
||||
Taiwanese = 11,
|
||||
BritishEnglish = 12, // en-GB
|
||||
CanadianFrench = 13,
|
||||
LatinAmericanSpanish = 14, // es-419
|
||||
// 4.0.0+
|
||||
SimplifiedChinese = 15,
|
||||
TraditionalChinese = 16,
|
||||
// 10.1.0+
|
||||
BrazilianPortuguese = 17,
|
||||
};
|
||||
|
||||
class AppletMessageQueue {
|
||||
public:
|
||||
// This is nn::am::AppletMessage
|
||||
@ -314,6 +290,12 @@ private:
|
||||
void CreateHandleStorage(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletSelfAccessor(Core::System& system_);
|
||||
~ILibraryAppletSelfAccessor() override;
|
||||
};
|
||||
|
||||
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
|
||||
public:
|
||||
explicit IApplicationFunctions(Core::System& system_);
|
||||
|
@ -26,8 +26,10 @@ public:
|
||||
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
|
||||
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
|
||||
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &ILibraryAppletProxy::GetApplicationFunctions, "GetApplicationFunctions"},
|
||||
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
|
||||
{21, nullptr, "GetAppletCommonFunctions"},
|
||||
{22, nullptr, "GetHomeMenuFunctions"},
|
||||
{23, nullptr, "GetGlobalStateController"},
|
||||
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
@ -100,12 +102,12 @@ private:
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>(system);
|
||||
}
|
||||
|
||||
void GetApplicationFunctions(HLERequestContext& ctx) {
|
||||
void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IApplicationFunctions>(system);
|
||||
rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system);
|
||||
}
|
||||
|
||||
Nvnflinger::Nvnflinger& nvnflinger;
|
||||
|
@ -22,13 +22,13 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
|
||||
{9, nullptr, "GetAudioOutputMode"},
|
||||
{10, nullptr, "SetAudioOutputMode"},
|
||||
{11, nullptr, "SetForceMutePolicy"},
|
||||
{12, nullptr, "GetForceMutePolicy"},
|
||||
{13, nullptr, "GetOutputModeSetting"},
|
||||
{12, &AudCtl::GetForceMutePolicy, "GetForceMutePolicy"},
|
||||
{13, &AudCtl::GetOutputModeSetting, "GetOutputModeSetting"},
|
||||
{14, nullptr, "SetOutputModeSetting"},
|
||||
{15, nullptr, "SetOutputTarget"},
|
||||
{16, nullptr, "SetInputTargetForceEnabled"},
|
||||
{17, nullptr, "SetHeadphoneOutputLevelMode"},
|
||||
{18, nullptr, "GetHeadphoneOutputLevelMode"},
|
||||
{18, &AudCtl::GetHeadphoneOutputLevelMode, "GetHeadphoneOutputLevelMode"},
|
||||
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
|
||||
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
|
||||
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
|
||||
@ -41,7 +41,7 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
|
||||
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
|
||||
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
|
||||
{30, nullptr, "SetSpeakerAutoMuteEnabled"},
|
||||
{31, nullptr, "IsSpeakerAutoMuteEnabled"},
|
||||
{31, &AudCtl::IsSpeakerAutoMuteEnabled, "IsSpeakerAutoMuteEnabled"},
|
||||
{32, nullptr, "GetActiveOutputTarget"},
|
||||
{33, nullptr, "GetTargetDeviceInfo"},
|
||||
{34, nullptr, "AcquireTargetNotification"},
|
||||
@ -96,4 +96,42 @@ void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) {
|
||||
rb.Push(target_max_volume);
|
||||
}
|
||||
|
||||
void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(ForceMutePolicy::Disable);
|
||||
}
|
||||
|
||||
void AudCtl::GetOutputModeSetting(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto value = rp.Pop<u32>();
|
||||
|
||||
LOG_WARNING(Audio, "(STUBBED) called, value={}", value);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(AudioOutputMode::PcmAuto);
|
||||
}
|
||||
|
||||
void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(HeadphoneOutputLevelMode::Normal);
|
||||
}
|
||||
|
||||
void AudCtl::IsSpeakerAutoMuteEnabled(HLERequestContext& ctx) {
|
||||
const bool is_speaker_auto_mute_enabled = false;
|
||||
|
||||
LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}",
|
||||
is_speaker_auto_mute_enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_speaker_auto_mute_enabled);
|
||||
}
|
||||
|
||||
} // namespace Service::Audio
|
||||
|
@ -17,8 +17,30 @@ public:
|
||||
~AudCtl() override;
|
||||
|
||||
private:
|
||||
enum class AudioOutputMode {
|
||||
Invalid,
|
||||
Pcm1ch,
|
||||
Pcm2ch,
|
||||
Pcm6ch,
|
||||
PcmAuto,
|
||||
};
|
||||
|
||||
enum class ForceMutePolicy {
|
||||
Disable,
|
||||
SpeakerMuteOnHeadphoneUnplugged,
|
||||
};
|
||||
|
||||
enum class HeadphoneOutputLevelMode {
|
||||
Normal,
|
||||
HighPower,
|
||||
};
|
||||
|
||||
void GetTargetVolumeMin(HLERequestContext& ctx);
|
||||
void GetTargetVolumeMax(HLERequestContext& ctx);
|
||||
void GetForceMutePolicy(HLERequestContext& ctx);
|
||||
void GetOutputModeSetting(HLERequestContext& ctx);
|
||||
void GetHeadphoneOutputLevelMode(HLERequestContext& ctx);
|
||||
void IsSpeakerAutoMuteEnabled(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Audio
|
||||
|
@ -57,8 +57,8 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
const auto entry_type = GetEntryType(path);
|
||||
if (entry_type.Code() == ResultSuccess) {
|
||||
FileSys::EntryType entry_type{};
|
||||
if (GetEntryType(&entry_type, path) == ResultSuccess) {
|
||||
return FileSys::ERROR_PATH_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
@ -210,8 +210,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
|
||||
FileSys::Mode mode) const {
|
||||
Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
|
||||
const std::string& path_, FileSys::Mode mode) const {
|
||||
const std::string path(Common::FS::SanitizePath(path_));
|
||||
std::string_view npath = path;
|
||||
while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
|
||||
@ -224,50 +224,68 @@ ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::
|
||||
}
|
||||
|
||||
if (mode == FileSys::Mode::Append) {
|
||||
return std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
|
||||
*out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
|
||||
} else {
|
||||
*out_file = file;
|
||||
}
|
||||
|
||||
return file;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
|
||||
Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_directory,
|
||||
const std::string& path_) {
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, path);
|
||||
if (dir == nullptr) {
|
||||
// TODO(DarkLordZach): Find a better error code for this
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
return dir;
|
||||
*out_directory = dir;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
|
||||
const std::string& path_) const {
|
||||
Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type,
|
||||
const std::string& path_) const {
|
||||
std::string path(Common::FS::SanitizePath(path_));
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir == nullptr)
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
auto filename = Common::FS::GetFilename(path);
|
||||
// TODO(Subv): Some games use the '/' path, find out what this means.
|
||||
if (filename.empty())
|
||||
return FileSys::EntryType::Directory;
|
||||
|
||||
if (dir->GetFile(filename) != nullptr)
|
||||
return FileSys::EntryType::File;
|
||||
if (dir->GetSubdirectory(filename) != nullptr)
|
||||
return FileSys::EntryType::Directory;
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::FileTimeStampRaw> VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
|
||||
const std::string& path) const {
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir == nullptr) {
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
if (GetEntryType(path).Failed()) {
|
||||
|
||||
auto filename = Common::FS::GetFilename(path);
|
||||
// TODO(Subv): Some games use the '/' path, find out what this means.
|
||||
if (filename.empty()) {
|
||||
*out_entry_type = FileSys::EntryType::Directory;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
if (dir->GetFile(filename) != nullptr) {
|
||||
*out_entry_type = FileSys::EntryType::File;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
if (dir->GetSubdirectory(filename) != nullptr) {
|
||||
*out_entry_type = FileSys::EntryType::Directory;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
|
||||
FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const {
|
||||
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
|
||||
if (dir == nullptr) {
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
return dir->GetFileTimeStamp(Common::FS::GetFilename(path));
|
||||
|
||||
FileSys::EntryType entry_type;
|
||||
if (GetEntryType(&entry_type, path) != ResultSuccess) {
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
*out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path));
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
FileSystemController::FileSystemController(Core::System& system_) : system{system_} {}
|
||||
@ -310,57 +328,54 @@ void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
|
||||
romfs_factory->SetPackedUpdate(std::move(update_raw));
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
|
||||
FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const {
|
||||
LOG_TRACE(Service_FS, "Opening RomFS for current process");
|
||||
|
||||
if (romfs_factory == nullptr) {
|
||||
// TODO(bunnei): Find a better error code for this
|
||||
return ResultUnknown;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS(
|
||||
u64 title_id, FileSys::ContentRecordType type) const {
|
||||
FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id,
|
||||
FileSys::ContentRecordType type) const {
|
||||
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id);
|
||||
|
||||
if (romfs_factory == nullptr) {
|
||||
// TODO: Find a better error code for this
|
||||
return ResultUnknown;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return romfs_factory->OpenPatchedRomFS(title_id, type);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFSWithProgramIndex(
|
||||
FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex(
|
||||
u64 title_id, u8 program_index, FileSys::ContentRecordType type) const {
|
||||
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id,
|
||||
program_index);
|
||||
|
||||
if (romfs_factory == nullptr) {
|
||||
// TODO: Find a better error code for this
|
||||
return ResultUnknown;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
|
||||
u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
|
||||
FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||
FileSys::ContentRecordType type) const {
|
||||
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
|
||||
title_id, storage_id, type);
|
||||
|
||||
if (romfs_factory == nullptr) {
|
||||
// TODO(bunnei): Find a better error code for this
|
||||
return ResultUnknown;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return romfs_factory->Open(title_id, storage_id, type);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const {
|
||||
Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data,
|
||||
FileSys::SaveDataSpaceId space,
|
||||
const FileSys::SaveDataAttribute& save_struct) const {
|
||||
LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
|
||||
save_struct.DebugInfo());
|
||||
|
||||
@ -368,11 +383,18 @@ ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
return save_data_factory->Create(space, save_struct);
|
||||
auto save_data = save_data_factory->Create(space, save_struct);
|
||||
if (save_data == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
*out_save_data = save_data;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const {
|
||||
Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data,
|
||||
FileSys::SaveDataSpaceId space,
|
||||
const FileSys::SaveDataAttribute& attribute) const {
|
||||
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space,
|
||||
attribute.DebugInfo());
|
||||
|
||||
@ -380,32 +402,50 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
return save_data_factory->Open(space, attribute);
|
||||
auto save_data = save_data_factory->Open(space, attribute);
|
||||
if (save_data == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
*out_save_data = save_data;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
|
||||
FileSys::SaveDataSpaceId space) const {
|
||||
Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
|
||||
FileSys::SaveDataSpaceId space) const {
|
||||
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space);
|
||||
|
||||
if (save_data_factory == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
return save_data_factory->GetSaveDataSpaceDirectory(space);
|
||||
auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space);
|
||||
if (save_data_space == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
*out_save_data_space = save_data_space;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
|
||||
Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
|
||||
LOG_TRACE(Service_FS, "Opening SDMC");
|
||||
|
||||
if (sdmc_factory == nullptr) {
|
||||
return FileSys::ERROR_SD_CARD_NOT_FOUND;
|
||||
}
|
||||
|
||||
return sdmc_factory->Open();
|
||||
auto sdmc = sdmc_factory->Open();
|
||||
if (sdmc == nullptr) {
|
||||
return FileSys::ERROR_SD_CARD_NOT_FOUND;
|
||||
}
|
||||
|
||||
*out_sdmc = sdmc;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
|
||||
FileSys::BisPartitionId id) const {
|
||||
Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
|
||||
FileSys::BisPartitionId id) const {
|
||||
LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
|
||||
|
||||
if (bis_factory == nullptr) {
|
||||
@ -417,11 +457,12 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
|
||||
return FileSys::ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return part;
|
||||
*out_bis_partition = part;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
|
||||
FileSys::BisPartitionId id) const {
|
||||
Result FileSystemController::OpenBISPartitionStorage(
|
||||
FileSys::VirtualFile* out_bis_partition_storage, FileSys::BisPartitionId id) const {
|
||||
LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
|
||||
|
||||
if (bis_factory == nullptr) {
|
||||
@ -433,7 +474,8 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
|
||||
return FileSys::ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return part;
|
||||
*out_bis_partition_storage = part;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
|
||||
|
@ -64,21 +64,24 @@ public:
|
||||
Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
|
||||
|
||||
void SetPackedUpdate(FileSys::VirtualFile update_raw);
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
|
||||
ResultVal<FileSys::VirtualFile> OpenPatchedRomFS(u64 title_id,
|
||||
FileSys::ContentRecordType type) const;
|
||||
ResultVal<FileSys::VirtualFile> OpenPatchedRomFSWithProgramIndex(
|
||||
u64 title_id, u8 program_index, FileSys::ContentRecordType type) const;
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||
FileSys::ContentRecordType type) const;
|
||||
ResultVal<FileSys::VirtualDir> CreateSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC() const;
|
||||
ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
|
||||
ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
|
||||
FileSys::VirtualFile OpenRomFSCurrentProcess() const;
|
||||
FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const;
|
||||
FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
|
||||
FileSys::ContentRecordType type) const;
|
||||
FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||
FileSys::ContentRecordType type) const;
|
||||
|
||||
Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
|
||||
const FileSys::SaveDataAttribute& save_struct) const;
|
||||
Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
|
||||
const FileSys::SaveDataAttribute& save_struct) const;
|
||||
Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
|
||||
FileSys::SaveDataSpaceId space) const;
|
||||
Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const;
|
||||
Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
|
||||
FileSys::BisPartitionId id) const;
|
||||
Result OpenBISPartitionStorage(FileSys::VirtualFile* out_bis_partition_storage,
|
||||
FileSys::BisPartitionId id) const;
|
||||
|
||||
u64 GetFreeSpaceSize(FileSys::StorageId id) const;
|
||||
u64 GetTotalSpaceSize(FileSys::StorageId id) const;
|
||||
@ -224,26 +227,28 @@ public:
|
||||
* @param mode Mode to open the file with
|
||||
* @return Opened file, or error code
|
||||
*/
|
||||
ResultVal<FileSys::VirtualFile> OpenFile(const std::string& path, FileSys::Mode mode) const;
|
||||
Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path,
|
||||
FileSys::Mode mode) const;
|
||||
|
||||
/**
|
||||
* Open a directory specified by its path
|
||||
* @param path Path relative to the archive
|
||||
* @return Opened directory, or error code
|
||||
*/
|
||||
ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
|
||||
Result OpenDirectory(FileSys::VirtualDir* out_directory, const std::string& path);
|
||||
|
||||
/**
|
||||
* Get the type of the specified path
|
||||
* @return The type of the specified path or error code
|
||||
*/
|
||||
ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const;
|
||||
Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const;
|
||||
|
||||
/**
|
||||
* Get the timestamp of the specified path
|
||||
* @return The timestamp of the specified path or error code
|
||||
*/
|
||||
ResultVal<FileSys::FileTimeStampRaw> GetFileTimeStampRaw(const std::string& path) const;
|
||||
Result GetFileTimeStampRaw(FileSys::FileTimeStampRaw* out_time_stamp_raw,
|
||||
const std::string& path) const;
|
||||
|
||||
private:
|
||||
FileSys::VirtualDir backing;
|
||||
|
@ -419,14 +419,15 @@ public:
|
||||
|
||||
LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
|
||||
|
||||
auto result = backend.OpenFile(name, mode);
|
||||
if (result.Failed()) {
|
||||
FileSys::VirtualFile vfs_file{};
|
||||
auto result = backend.OpenFile(&vfs_file, name, mode);
|
||||
if (result != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
auto file = std::make_shared<IFile>(system, result.Unwrap());
|
||||
auto file = std::make_shared<IFile>(system, vfs_file);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -444,14 +445,15 @@ public:
|
||||
|
||||
LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
|
||||
|
||||
auto result = backend.OpenDirectory(name);
|
||||
if (result.Failed()) {
|
||||
FileSys::VirtualDir vfs_dir{};
|
||||
auto result = backend.OpenDirectory(&vfs_dir, name);
|
||||
if (result != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
auto directory = std::make_shared<IDirectory>(system, result.Unwrap());
|
||||
auto directory = std::make_shared<IDirectory>(system, vfs_dir);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -464,16 +466,17 @@ public:
|
||||
|
||||
LOG_DEBUG(Service_FS, "called. file={}", name);
|
||||
|
||||
auto result = backend.GetEntryType(name);
|
||||
if (result.Failed()) {
|
||||
FileSys::EntryType vfs_entry_type{};
|
||||
auto result = backend.GetEntryType(&vfs_entry_type, name);
|
||||
if (result != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(static_cast<u32>(*result));
|
||||
rb.Push<u32>(static_cast<u32>(vfs_entry_type));
|
||||
}
|
||||
|
||||
void Commit(HLERequestContext& ctx) {
|
||||
@ -505,16 +508,17 @@ public:
|
||||
|
||||
LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
|
||||
|
||||
auto result = backend.GetFileTimeStampRaw(name);
|
||||
if (result.Failed()) {
|
||||
FileSys::FileTimeStampRaw vfs_timestamp{};
|
||||
auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
|
||||
if (result != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(*result);
|
||||
rb.PushRaw(vfs_timestamp);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -572,14 +576,15 @@ private:
|
||||
}
|
||||
|
||||
void FindAllSaves(FileSys::SaveDataSpaceId space) {
|
||||
const auto save_root = fsc.OpenSaveDataSpace(space);
|
||||
FileSys::VirtualDir save_root{};
|
||||
const auto result = fsc.OpenSaveDataSpace(&save_root, space);
|
||||
|
||||
if (save_root.Failed() || *save_root == nullptr) {
|
||||
if (result != ResultSuccess || save_root == nullptr) {
|
||||
LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& type : (*save_root)->GetSubdirectories()) {
|
||||
for (const auto& type : save_root->GetSubdirectories()) {
|
||||
if (type->GetName() == "save") {
|
||||
for (const auto& save_id : type->GetSubdirectories()) {
|
||||
for (const auto& user_id : save_id->GetSubdirectories()) {
|
||||
@ -837,9 +842,11 @@ void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
auto filesystem =
|
||||
std::make_shared<IFileSystem>(system, fsc.OpenSDMC().Unwrap(),
|
||||
SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
|
||||
FileSys::VirtualDir sdmc_dir{};
|
||||
fsc.OpenSDMC(&sdmc_dir);
|
||||
|
||||
auto filesystem = std::make_shared<IFileSystem>(
|
||||
system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -856,7 +863,8 @@ void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
|
||||
uid[1], uid[0]);
|
||||
|
||||
fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
|
||||
FileSys::VirtualDir save_data_dir{};
|
||||
fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -874,8 +882,9 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
|
||||
|
||||
LOG_INFO(Service_FS, "called.");
|
||||
|
||||
auto dir = fsc.OpenSaveData(parameters.space_id, parameters.attribute);
|
||||
if (dir.Failed()) {
|
||||
FileSys::VirtualDir dir{};
|
||||
auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute);
|
||||
if (result != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
|
||||
return;
|
||||
@ -899,8 +908,8 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()),
|
||||
SizeGetter::FromStorageId(fsc, id));
|
||||
auto filesystem =
|
||||
std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -970,7 +979,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
|
||||
|
||||
if (!romfs) {
|
||||
auto current_romfs = fsc.OpenRomFSCurrentProcess();
|
||||
if (current_romfs.Failed()) {
|
||||
if (!current_romfs) {
|
||||
// TODO (bunnei): Find the right error code to use here
|
||||
LOG_CRITICAL(Service_FS, "no file system interface available!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@ -978,7 +987,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
romfs = current_romfs.Unwrap();
|
||||
romfs = current_romfs;
|
||||
}
|
||||
|
||||
auto storage = std::make_shared<IStorage>(system, romfs);
|
||||
@ -999,7 +1008,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
|
||||
|
||||
auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
|
||||
if (data.Failed()) {
|
||||
if (!data) {
|
||||
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
|
||||
|
||||
if (archive != nullptr) {
|
||||
@ -1021,7 +1030,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
|
||||
const FileSys::PatchManager pm{title_id, fsc, content_provider};
|
||||
|
||||
auto storage = std::make_shared<IStorage>(
|
||||
system, pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
|
||||
system, pm.PatchRomFS(std::move(data), 0, FileSys::ContentRecordType::Data));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -1051,7 +1060,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
|
||||
fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index,
|
||||
FileSys::ContentRecordType::Program);
|
||||
|
||||
if (patched_romfs.Failed()) {
|
||||
if (!patched_romfs) {
|
||||
// TODO: Find the right error code to use here
|
||||
LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
|
||||
|
||||
@ -1060,7 +1069,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs.Unwrap()));
|
||||
auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
|
@ -65,18 +65,19 @@ void ARP_R::GetApplicationLaunchProperty(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto res = manager.GetLaunchProperty(*title_id);
|
||||
ApplicationLaunchProperty launch_property{};
|
||||
const auto res = manager.GetLaunchProperty(&launch_property, *title_id);
|
||||
|
||||
if (res.Failed()) {
|
||||
if (res != ResultSuccess) {
|
||||
LOG_ERROR(Service_ARP, "Failed to get launch property!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(res);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(*res);
|
||||
rb.PushRaw(launch_property);
|
||||
}
|
||||
|
||||
void ARP_R::GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx) {
|
||||
@ -85,18 +86,19 @@ void ARP_R::GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx
|
||||
|
||||
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
|
||||
|
||||
const auto res = manager.GetLaunchProperty(title_id);
|
||||
ApplicationLaunchProperty launch_property{};
|
||||
const auto res = manager.GetLaunchProperty(&launch_property, title_id);
|
||||
|
||||
if (res.Failed()) {
|
||||
if (res != ResultSuccess) {
|
||||
LOG_ERROR(Service_ARP, "Failed to get launch property!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(res);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(*res);
|
||||
rb.PushRaw(launch_property);
|
||||
}
|
||||
|
||||
void ARP_R::GetApplicationControlProperty(HLERequestContext& ctx) {
|
||||
@ -113,16 +115,17 @@ void ARP_R::GetApplicationControlProperty(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto res = manager.GetControlProperty(*title_id);
|
||||
std::vector<u8> nacp_data;
|
||||
const auto res = manager.GetControlProperty(&nacp_data, *title_id);
|
||||
|
||||
if (res.Failed()) {
|
||||
if (res != ResultSuccess) {
|
||||
LOG_ERROR(Service_ARP, "Failed to get control property!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(res);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(*res);
|
||||
ctx.WriteBuffer(nacp_data);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -134,16 +137,17 @@ void ARP_R::GetApplicationControlPropertyWithApplicationId(HLERequestContext& ct
|
||||
|
||||
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
|
||||
|
||||
const auto res = manager.GetControlProperty(title_id);
|
||||
std::vector<u8> nacp_data;
|
||||
const auto res = manager.GetControlProperty(&nacp_data, title_id);
|
||||
|
||||
if (res.Failed()) {
|
||||
if (res != ResultSuccess) {
|
||||
LOG_ERROR(Service_ARP, "Failed to get control property!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(res);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(*res);
|
||||
ctx.WriteBuffer(nacp_data);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
|
@ -15,7 +15,8 @@ ARPManager::ARPManager() = default;
|
||||
|
||||
ARPManager::~ARPManager() = default;
|
||||
|
||||
ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id) const {
|
||||
Result ARPManager::GetLaunchProperty(ApplicationLaunchProperty* out_launch_property,
|
||||
u64 title_id) const {
|
||||
if (title_id == 0) {
|
||||
return Glue::ResultInvalidProcessId;
|
||||
}
|
||||
@ -25,10 +26,11 @@ ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id)
|
||||
return Glue::ResultProcessIdNotRegistered;
|
||||
}
|
||||
|
||||
return iter->second.launch;
|
||||
*out_launch_property = iter->second.launch;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
|
||||
Result ARPManager::GetControlProperty(std::vector<u8>* out_control_property, u64 title_id) const {
|
||||
if (title_id == 0) {
|
||||
return Glue::ResultInvalidProcessId;
|
||||
}
|
||||
@ -38,7 +40,8 @@ ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
|
||||
return Glue::ResultProcessIdNotRegistered;
|
||||
}
|
||||
|
||||
return iter->second.control;
|
||||
*out_control_property = iter->second.control;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,
|
||||
|
@ -32,12 +32,12 @@ public:
|
||||
// Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was
|
||||
// previously registered, otherwise ResultProcessIdNotRegistered if it was never registered or
|
||||
// ResultInvalidProcessId if the title ID is 0.
|
||||
ResultVal<ApplicationLaunchProperty> GetLaunchProperty(u64 title_id) const;
|
||||
Result GetLaunchProperty(ApplicationLaunchProperty* out_launch_property, u64 title_id) const;
|
||||
|
||||
// Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to
|
||||
// the provided title ID if it was previously registered, otherwise ResultProcessIdNotRegistered
|
||||
// if it was never registered or ResultInvalidProcessId if the title ID is 0.
|
||||
ResultVal<std::vector<u8>> GetControlProperty(u64 title_id) const;
|
||||
Result GetControlProperty(std::vector<u8>* out_control_property, u64 title_id) const;
|
||||
|
||||
// Adds a new entry to the internal database with the provided parameters, returning
|
||||
// ResultProcessIdNotRegistered if attempting to re-register a title ID without an intermediate
|
||||
|
@ -357,7 +357,8 @@ public:
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) {
|
||||
Result MapProcessCodeMemory(VAddr* out_map_location, Kernel::KProcess* process, VAddr base_addr,
|
||||
u64 size) {
|
||||
auto& page_table{process->GetPageTable()};
|
||||
VAddr addr{};
|
||||
|
||||
@ -372,20 +373,21 @@ public:
|
||||
R_TRY(result);
|
||||
|
||||
if (ValidateRegionForMap(page_table, addr, size)) {
|
||||
return addr;
|
||||
*out_map_location = addr;
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_INSUFFICIENT_ADDRESS_SPACE;
|
||||
}
|
||||
|
||||
ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
|
||||
VAddr bss_addr, std::size_t bss_size, std::size_t size) {
|
||||
Result MapNro(VAddr* out_map_location, Kernel::KProcess* process, VAddr nro_addr,
|
||||
std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) {
|
||||
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
|
||||
auto& page_table{process->GetPageTable()};
|
||||
VAddr addr{};
|
||||
|
||||
CASCADE_RESULT(addr, MapProcessCodeMemory(process, nro_addr, nro_size));
|
||||
R_TRY(MapProcessCodeMemory(&addr, process, nro_addr, nro_size));
|
||||
|
||||
if (bss_size) {
|
||||
auto block_guard = detail::ScopeExit([&] {
|
||||
@ -411,7 +413,8 @@ public:
|
||||
}
|
||||
|
||||
if (ValidateRegionForMap(page_table, addr, size)) {
|
||||
return addr;
|
||||
*out_map_location = addr;
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,9 +440,9 @@ public:
|
||||
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
|
||||
nro_header.segment_headers[DATA_INDEX].memory_size);
|
||||
|
||||
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
|
||||
R_TRY(process->GetPageTable().SetProcessMemoryPermission(
|
||||
text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
|
||||
CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission(
|
||||
R_TRY(process->GetPageTable().SetProcessMemoryPermission(
|
||||
ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
|
||||
|
||||
return process->GetPageTable().SetProcessMemoryPermission(
|
||||
@ -542,31 +545,32 @@ public:
|
||||
}
|
||||
|
||||
// Map memory for the NRO
|
||||
const auto map_result{MapNro(system.ApplicationProcess(), nro_address, nro_size,
|
||||
bss_address, bss_size, nro_size + bss_size)};
|
||||
if (map_result.Failed()) {
|
||||
VAddr map_location{};
|
||||
const auto map_result{MapNro(&map_location, system.ApplicationProcess(), nro_address,
|
||||
nro_size, bss_address, bss_size, nro_size + bss_size)};
|
||||
if (map_result != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(map_result.Code());
|
||||
rb.Push(map_result);
|
||||
}
|
||||
|
||||
// Load the NRO into the mapped memory
|
||||
if (const auto result{
|
||||
LoadNro(system.ApplicationProcess(), header, nro_address, *map_result)};
|
||||
LoadNro(system.ApplicationProcess(), header, nro_address, map_location)};
|
||||
result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(map_result.Code());
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
// Track the loaded NRO
|
||||
nro.insert_or_assign(*map_result,
|
||||
NROInfo{hash, *map_result, nro_size, bss_address, bss_size,
|
||||
nro.insert_or_assign(map_location,
|
||||
NROInfo{hash, map_location, nro_size, bss_address, bss_size,
|
||||
header.segment_headers[TEXT_INDEX].memory_size,
|
||||
header.segment_headers[RO_INDEX].memory_size,
|
||||
header.segment_headers[DATA_INDEX].memory_size, nro_address});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(*map_result);
|
||||
rb.Push(map_location);
|
||||
}
|
||||
|
||||
Result UnmapNro(const NROInfo& info) {
|
||||
@ -574,19 +578,19 @@ public:
|
||||
auto& page_table{system.ApplicationProcess()->GetPageTable()};
|
||||
|
||||
if (info.bss_size != 0) {
|
||||
CASCADE_CODE(page_table.UnmapCodeMemory(
|
||||
R_TRY(page_table.UnmapCodeMemory(
|
||||
info.nro_address + info.text_size + info.ro_size + info.data_size, info.bss_address,
|
||||
info.bss_size, Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
|
||||
}
|
||||
|
||||
CASCADE_CODE(page_table.UnmapCodeMemory(
|
||||
R_TRY(page_table.UnmapCodeMemory(
|
||||
info.nro_address + info.text_size + info.ro_size,
|
||||
info.src_addr + info.text_size + info.ro_size, info.data_size,
|
||||
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
|
||||
CASCADE_CODE(page_table.UnmapCodeMemory(
|
||||
R_TRY(page_table.UnmapCodeMemory(
|
||||
info.nro_address + info.text_size, info.src_addr + info.text_size, info.ro_size,
|
||||
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
|
||||
CASCADE_CODE(page_table.UnmapCodeMemory(
|
||||
R_TRY(page_table.UnmapCodeMemory(
|
||||
info.nro_address, info.src_addr, info.text_size,
|
||||
Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
|
||||
return ResultSuccess;
|
||||
|
@ -101,20 +101,14 @@ private:
|
||||
|
||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||
|
||||
const auto result{manager.GetDefault(source_flag)};
|
||||
if (result.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
return;
|
||||
}
|
||||
|
||||
if (result->size() > 0) {
|
||||
ctx.WriteBuffer(SerializeArray(*result));
|
||||
const auto default_miis{manager.GetDefault(source_flag)};
|
||||
if (default_miis.size() > 0) {
|
||||
ctx.WriteBuffer(SerializeArray(default_miis));
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(static_cast<u32>(result->size()));
|
||||
rb.Push<u32>(static_cast<u32>(default_miis.size()));
|
||||
}
|
||||
|
||||
void Get1(HLERequestContext& ctx) {
|
||||
@ -123,15 +117,10 @@ private:
|
||||
|
||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||
|
||||
const auto result{manager.GetDefault(source_flag)};
|
||||
if (result.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
return;
|
||||
}
|
||||
const auto default_miis{manager.GetDefault(source_flag)};
|
||||
|
||||
std::vector<CharInfo> values;
|
||||
for (const auto& element : *result) {
|
||||
for (const auto& element : default_miis) {
|
||||
values.emplace_back(element.info);
|
||||
}
|
||||
|
||||
@ -139,7 +128,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(static_cast<u32>(result->size()));
|
||||
rb.Push<u32>(static_cast<u32>(default_miis.size()));
|
||||
}
|
||||
|
||||
void UpdateLatest(HLERequestContext& ctx) {
|
||||
@ -149,16 +138,17 @@ private:
|
||||
|
||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||
|
||||
const auto result{manager.UpdateLatest(info, source_flag)};
|
||||
if (result.Failed()) {
|
||||
CharInfo new_char_info{};
|
||||
const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)};
|
||||
if (result != ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<CharInfo>(*result);
|
||||
rb.PushRaw<CharInfo>(new_char_info);
|
||||
}
|
||||
|
||||
void BuildRandom(HLERequestContext& ctx) {
|
||||
|
@ -409,8 +409,7 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const {
|
||||
return static_cast<u32>(count);
|
||||
}
|
||||
|
||||
ResultVal<CharInfo> MiiManager::UpdateLatest([[maybe_unused]] const CharInfo& info,
|
||||
SourceFlag source_flag) {
|
||||
Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag) {
|
||||
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||
return ERROR_CANNOT_FIND_ENTRY;
|
||||
}
|
||||
@ -672,7 +671,7 @@ bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) {
|
||||
std::vector<MiiInfoElement> MiiManager::GetDefault(SourceFlag source_flag) {
|
||||
std::vector<MiiInfoElement> result;
|
||||
|
||||
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
||||
|
@ -19,12 +19,12 @@ public:
|
||||
bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter);
|
||||
bool IsFullDatabase() const;
|
||||
u32 GetCount(SourceFlag source_flag) const;
|
||||
ResultVal<CharInfo> UpdateLatest(const CharInfo& info, SourceFlag source_flag);
|
||||
Result UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag);
|
||||
CharInfo BuildRandom(Age age, Gender gender, Race race);
|
||||
CharInfo BuildDefault(std::size_t index);
|
||||
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
|
||||
bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
|
||||
ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);
|
||||
std::vector<MiiInfoElement> GetDefault(SourceFlag source_flag);
|
||||
Result GetIndex(const CharInfo& info, u32& index);
|
||||
|
||||
// This is nn::mii::detail::Ver::StoreDataRaw::BuildFromStoreData
|
||||
|
@ -392,24 +392,25 @@ void IApplicationManagerInterface::GetApplicationDesiredLanguage(HLERequestConte
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto supported_languages = rp.Pop<u32>();
|
||||
|
||||
const auto res = GetApplicationDesiredLanguage(supported_languages);
|
||||
if (res.Succeeded()) {
|
||||
u8 desired_language{};
|
||||
const auto res = GetApplicationDesiredLanguage(&desired_language, supported_languages);
|
||||
if (res == ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(*res);
|
||||
rb.Push<u32>(desired_language);
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(res);
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
|
||||
const u32 supported_languages) {
|
||||
Result IApplicationManagerInterface::GetApplicationDesiredLanguage(u8* out_desired_language,
|
||||
const u32 supported_languages) {
|
||||
LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
|
||||
|
||||
// Get language code from settings
|
||||
const auto language_code =
|
||||
Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
|
||||
Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue()));
|
||||
|
||||
// Convert to application language, get priority list
|
||||
const auto application_language = ConvertToApplicationLanguage(language_code);
|
||||
@ -430,7 +431,8 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
|
||||
for (const auto lang : *priority_list) {
|
||||
const auto supported_flag = GetSupportedLanguageFlag(lang);
|
||||
if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
|
||||
return static_cast<u8>(lang);
|
||||
*out_desired_language = static_cast<u8>(lang);
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,19 +446,20 @@ void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto application_language = rp.Pop<u8>();
|
||||
|
||||
const auto res = ConvertApplicationLanguageToLanguageCode(application_language);
|
||||
if (res.Succeeded()) {
|
||||
u64 language_code{};
|
||||
const auto res = ConvertApplicationLanguageToLanguageCode(&language_code, application_language);
|
||||
if (res == ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(*res);
|
||||
rb.Push(language_code);
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(res);
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
|
||||
u8 application_language) {
|
||||
Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
|
||||
u64* out_language_code, u8 application_language) {
|
||||
const auto language_code =
|
||||
ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language));
|
||||
if (language_code == std::nullopt) {
|
||||
@ -464,7 +467,8 @@ ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguag
|
||||
return Service::NS::ResultApplicationLanguageNotFound;
|
||||
}
|
||||
|
||||
return static_cast<u64>(*language_code);
|
||||
*out_language_code = static_cast<u64>(*language_code);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_)
|
||||
@ -618,12 +622,13 @@ void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequ
|
||||
static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
std::vector<u8> nacp_data{};
|
||||
const auto parameters{rp.PopRaw<RequestParameters>()};
|
||||
const auto nacp_data{system.GetARPManager().GetControlProperty(parameters.application_id)};
|
||||
const auto result = nacp_data ? ResultSuccess : ResultUnknown;
|
||||
const auto result =
|
||||
system.GetARPManager().GetControlProperty(&nacp_data, parameters.application_id);
|
||||
|
||||
if (nacp_data) {
|
||||
ctx.WriteBuffer(nacp_data->data(), nacp_data->size());
|
||||
if (result == ResultSuccess) {
|
||||
ctx.WriteBuffer(nacp_data.data(), nacp_data.size());
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
@ -28,8 +28,9 @@ public:
|
||||
explicit IApplicationManagerInterface(Core::System& system_);
|
||||
~IApplicationManagerInterface() override;
|
||||
|
||||
ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages);
|
||||
ResultVal<u64> ConvertApplicationLanguageToLanguageCode(u8 application_language);
|
||||
Result GetApplicationDesiredLanguage(u8* out_desired_language, u32 supported_languages);
|
||||
Result ConvertApplicationLanguageToLanguageCode(u64* out_language_code,
|
||||
u8 application_language);
|
||||
|
||||
private:
|
||||
void GetApplicationControlData(HLERequestContext& ctx);
|
||||
|
@ -183,7 +183,7 @@ std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
|
||||
return layer->GetBinderId();
|
||||
}
|
||||
|
||||
ResultVal<Kernel::KReadableEvent*> Nvnflinger::FindVsyncEvent(u64 display_id) {
|
||||
Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) {
|
||||
const auto lock_guard = Lock();
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
@ -191,7 +191,7 @@ ResultVal<Kernel::KReadableEvent*> Nvnflinger::FindVsyncEvent(u64 display_id) {
|
||||
return VI::ResultNotFound;
|
||||
}
|
||||
|
||||
return display->GetVSyncEvent();
|
||||
return display->GetVSyncEvent(out_vsync_event);
|
||||
}
|
||||
|
||||
VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
///
|
||||
/// If an invalid display ID is provided, then VI::ResultNotFound is returned.
|
||||
/// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned.
|
||||
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> FindVsyncEvent(u64 display_id);
|
||||
[[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id);
|
||||
|
||||
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
|
||||
/// finished.
|
||||
|
@ -8,15 +8,16 @@
|
||||
|
||||
namespace Service::OLSC {
|
||||
|
||||
class OLSC final : public ServiceFramework<OLSC> {
|
||||
class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
|
||||
public:
|
||||
explicit OLSC(Core::System& system_) : ServiceFramework{system_, "olsc:u"} {
|
||||
explicit IOlscServiceForApplication(Core::System& system_)
|
||||
: ServiceFramework{system_, "olsc:u"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &OLSC::Initialize, "Initialize"},
|
||||
{0, &IOlscServiceForApplication::Initialize, "Initialize"},
|
||||
{10, nullptr, "VerifySaveDataBackupLicenseAsync"},
|
||||
{13, &OLSC::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
|
||||
{14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
|
||||
{13, &IOlscServiceForApplication::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
|
||||
{14, &IOlscServiceForApplication::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
|
||||
{15, nullptr, "SetCustomData"},
|
||||
{16, nullptr, "DeleteSaveDataBackupSetting"},
|
||||
{18, nullptr, "GetSaveDataBackupInfoCache"},
|
||||
@ -72,10 +73,155 @@ private:
|
||||
bool initialized{};
|
||||
};
|
||||
|
||||
class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
|
||||
public:
|
||||
explicit INativeHandleHolder(Core::System& system_)
|
||||
: ServiceFramework{system_, "INativeHandleHolder"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetNativeHandle"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
|
||||
public:
|
||||
explicit ITransferTaskListController(Core::System& system_)
|
||||
: ServiceFramework{system_, "ITransferTaskListController"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown0"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, &ITransferTaskListController::GetNativeHandleHolder , "GetNativeHandleHolder"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "GetRemoteStorageController"},
|
||||
{9, &ITransferTaskListController::GetNativeHandleHolder, "GetNativeHandleHolder2"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
{12, nullptr, "Unknown12"},
|
||||
{13, nullptr, "Unknown13"},
|
||||
{14, nullptr, "Unknown14"},
|
||||
{15, nullptr, "Unknown15"},
|
||||
{16, nullptr, "Unknown16"},
|
||||
{17, nullptr, "Unknown17"},
|
||||
{18, nullptr, "Unknown18"},
|
||||
{19, nullptr, "Unknown19"},
|
||||
{20, nullptr, "Unknown20"},
|
||||
{21, nullptr, "Unknown21"},
|
||||
{22, nullptr, "Unknown22"},
|
||||
{23, nullptr, "Unknown23"},
|
||||
{24, nullptr, "Unknown24"},
|
||||
{25, nullptr, "Unknown25"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetNativeHandleHolder(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_OLSC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<INativeHandleHolder>(system);
|
||||
}
|
||||
};
|
||||
|
||||
class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
|
||||
public:
|
||||
explicit IOlscServiceForSystemService(Core::System& system_)
|
||||
: ServiceFramework{system_, "olsc:s"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IOlscServiceForSystemService::OpenTransferTaskListController, "OpenTransferTaskListController"},
|
||||
{1, nullptr, "OpenRemoteStorageController"},
|
||||
{2, nullptr, "OpenDaemonController"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
{12, nullptr, "Unknown12"},
|
||||
{13, nullptr, "Unknown13"},
|
||||
{100, nullptr, "ListLastTransferTaskErrorInfo"},
|
||||
{101, nullptr, "GetLastErrorInfoCount"},
|
||||
{102, nullptr, "RemoveLastErrorInfoOld"},
|
||||
{103, nullptr, "GetLastErrorInfo"},
|
||||
{104, nullptr, "GetLastErrorEventHolder"},
|
||||
{105, nullptr, "GetLastTransferTaskErrorInfo"},
|
||||
{200, nullptr, "GetDataTransferPolicyInfo"},
|
||||
{201, nullptr, "RemoveDataTransferPolicyInfo"},
|
||||
{202, nullptr, "UpdateDataTransferPolicyOld"},
|
||||
{203, nullptr, "UpdateDataTransferPolicy"},
|
||||
{204, nullptr, "CleanupDataTransferPolicyInfo"},
|
||||
{205, nullptr, "RequestDataTransferPolicy"},
|
||||
{300, nullptr, "GetAutoTransferSeriesInfo"},
|
||||
{301, nullptr, "UpdateAutoTransferSeriesInfo"},
|
||||
{400, nullptr, "CleanupSaveDataArchiveInfoType1"},
|
||||
{900, nullptr, "CleanupTransferTask"},
|
||||
{902, nullptr, "CleanupSeriesInfoType0"},
|
||||
{903, nullptr, "CleanupSaveDataArchiveInfoType0"},
|
||||
{904, nullptr, "CleanupApplicationAutoTransferSetting"},
|
||||
{905, nullptr, "CleanupErrorHistory"},
|
||||
{906, nullptr, "SetLastError"},
|
||||
{907, nullptr, "AddSaveDataArchiveInfoType0"},
|
||||
{908, nullptr, "RemoveSeriesInfoType0"},
|
||||
{909, nullptr, "GetSeriesInfoType0"},
|
||||
{910, nullptr, "RemoveLastErrorInfo"},
|
||||
{911, nullptr, "CleanupSeriesInfoType1"},
|
||||
{912, nullptr, "RemoveSeriesInfoType1"},
|
||||
{913, nullptr, "GetSeriesInfoType1"},
|
||||
{1000, nullptr, "UpdateIssueOld"},
|
||||
{1010, nullptr, "Unknown1010"},
|
||||
{1011, nullptr, "ListIssueInfoOld"},
|
||||
{1012, nullptr, "GetIssueOld"},
|
||||
{1013, nullptr, "GetIssue2Old"},
|
||||
{1014, nullptr, "GetIssue3Old"},
|
||||
{1020, nullptr, "RepairIssueOld"},
|
||||
{1021, nullptr, "RepairIssueWithUserIdOld"},
|
||||
{1022, nullptr, "RepairIssue2Old"},
|
||||
{1023, nullptr, "RepairIssue3Old"},
|
||||
{1024, nullptr, "Unknown1024"},
|
||||
{1100, nullptr, "UpdateIssue"},
|
||||
{1110, nullptr, "Unknown1110"},
|
||||
{1111, nullptr, "ListIssueInfo"},
|
||||
{1112, nullptr, "GetIssue"},
|
||||
{1113, nullptr, "GetIssue2"},
|
||||
{1114, nullptr, "GetIssue3"},
|
||||
{1120, nullptr, "RepairIssue"},
|
||||
{1121, nullptr, "RepairIssueWithUserId"},
|
||||
{1122, nullptr, "RepairIssue2"},
|
||||
{1123, nullptr, "RepairIssue3"},
|
||||
{1124, nullptr, "Unknown1124"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void OpenTransferTaskListController(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_OLSC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ITransferTaskListController>(system);
|
||||
}
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
|
||||
server_manager->RegisterNamedService("olsc:u", std::make_shared<OLSC>(system));
|
||||
server_manager->RegisterNamedService("olsc:u",
|
||||
std::make_shared<IOlscServiceForApplication>(system));
|
||||
server_manager->RegisterNamedService("olsc:s",
|
||||
std::make_shared<IOlscServiceForSystemService>(system));
|
||||
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/pctl/pctl.h"
|
||||
#include "core/hle/service/pctl/pctl_module.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
@ -24,7 +25,8 @@ constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
|
||||
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
|
||||
public:
|
||||
explicit IParentalControlService(Core::System& system_, Capability capability_)
|
||||
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_} {
|
||||
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
|
||||
service_context{system_, "IParentalControlService"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &IParentalControlService::Initialize, "Initialize"},
|
||||
@ -33,7 +35,7 @@ public:
|
||||
{1003, nullptr, "ConfirmResumeApplicationPermission"},
|
||||
{1004, nullptr, "ConfirmSnsPostPermission"},
|
||||
{1005, nullptr, "ConfirmSystemSettingsPermission"},
|
||||
{1006, nullptr, "IsRestrictionTemporaryUnlocked"},
|
||||
{1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
|
||||
{1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
|
||||
{1008, nullptr, "EnterRestrictedSystemSettings"},
|
||||
{1009, nullptr, "LeaveRestrictedSystemSettings"},
|
||||
@ -47,14 +49,14 @@ public:
|
||||
{1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
|
||||
{1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
|
||||
{1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
|
||||
{1032, nullptr, "GetSafetyLevel"},
|
||||
{1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
|
||||
{1033, nullptr, "SetSafetyLevel"},
|
||||
{1034, nullptr, "GetSafetyLevelSettings"},
|
||||
{1035, nullptr, "GetCurrentSettings"},
|
||||
{1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
|
||||
{1036, nullptr, "SetCustomSafetyLevelSettings"},
|
||||
{1037, nullptr, "GetDefaultRatingOrganization"},
|
||||
{1038, nullptr, "SetDefaultRatingOrganization"},
|
||||
{1039, nullptr, "GetFreeCommunicationApplicationListCount"},
|
||||
{1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
|
||||
{1042, nullptr, "AddToFreeCommunicationApplicationList"},
|
||||
{1043, nullptr, "DeleteSettings"},
|
||||
{1044, nullptr, "GetFreeCommunicationApplicationList"},
|
||||
@ -76,7 +78,7 @@ public:
|
||||
{1206, nullptr, "GetPinCodeLength"},
|
||||
{1207, nullptr, "GetPinCodeChangedEvent"},
|
||||
{1208, nullptr, "GetPinCode"},
|
||||
{1403, nullptr, "IsPairingActive"},
|
||||
{1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
|
||||
{1406, nullptr, "GetSettingsLastUpdated"},
|
||||
{1411, nullptr, "GetPairingAccountInfo"},
|
||||
{1421, nullptr, "GetAccountNickname"},
|
||||
@ -84,18 +86,18 @@ public:
|
||||
{1425, nullptr, "RequestPostEvents"},
|
||||
{1426, nullptr, "GetPostEventInterval"},
|
||||
{1427, nullptr, "SetPostEventInterval"},
|
||||
{1432, nullptr, "GetSynchronizationEvent"},
|
||||
{1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
|
||||
{1451, nullptr, "StartPlayTimer"},
|
||||
{1452, nullptr, "StopPlayTimer"},
|
||||
{1453, nullptr, "IsPlayTimerEnabled"},
|
||||
{1454, nullptr, "GetPlayTimerRemainingTime"},
|
||||
{1455, nullptr, "IsRestrictedByPlayTimer"},
|
||||
{1456, nullptr, "GetPlayTimerSettings"},
|
||||
{1457, nullptr, "GetPlayTimerEventToRequestSuspension"},
|
||||
{1458, nullptr, "IsPlayTimerAlarmDisabled"},
|
||||
{1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
|
||||
{1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
|
||||
{1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
|
||||
{1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
|
||||
{1472, nullptr, "CancelNetworkRequest"},
|
||||
{1473, nullptr, "GetUnlinkedEvent"},
|
||||
{1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
|
||||
{1474, nullptr, "ClearUnlinkedEvent"},
|
||||
{1601, nullptr, "DisableAllFeatures"},
|
||||
{1602, nullptr, "PostEnableAllFeatures"},
|
||||
@ -131,6 +133,12 @@ public:
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
synchronization_event =
|
||||
service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
|
||||
unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
|
||||
request_suspension_event =
|
||||
service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
@ -228,6 +236,17 @@ private:
|
||||
states.free_communication = true;
|
||||
}
|
||||
|
||||
void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
|
||||
const bool is_temporary_unlocked = false;
|
||||
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
|
||||
is_temporary_unlocked);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_temporary_unlocked);
|
||||
}
|
||||
|
||||
void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
states.stereo_vision = true;
|
||||
@ -268,6 +287,34 @@ private:
|
||||
rb.Push(pin_code[0] != '\0');
|
||||
}
|
||||
|
||||
void GetSafetyLevel(HLERequestContext& ctx) {
|
||||
const u32 safety_level = 0;
|
||||
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(safety_level);
|
||||
}
|
||||
|
||||
void GetCurrentSettings(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(restriction_settings);
|
||||
}
|
||||
|
||||
void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
|
||||
const u32 count = 4;
|
||||
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
@ -300,6 +347,61 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void IsPairingActive(HLERequestContext& ctx) {
|
||||
const bool is_pairing_active = false;
|
||||
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_pairing_active);
|
||||
}
|
||||
|
||||
void GetSynchronizationEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(synchronization_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void GetPlayTimerSettings(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
|
||||
const PlayTimerSettings timer_settings{};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 15};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(timer_settings);
|
||||
}
|
||||
|
||||
void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
|
||||
const bool is_play_timer_alarm_disabled = false;
|
||||
|
||||
LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
|
||||
is_play_timer_alarm_disabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_play_timer_alarm_disabled);
|
||||
}
|
||||
|
||||
void GetUnlinkedEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(unlinked_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void SetStereoVisionRestriction(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto can_use = rp.Pop<bool>();
|
||||
@ -364,10 +466,30 @@ private:
|
||||
bool disabled{};
|
||||
};
|
||||
|
||||
// This is nn::pctl::RestrictionSettings
|
||||
struct RestrictionSettings {
|
||||
u8 rating_age;
|
||||
bool sns_post_restriction;
|
||||
bool free_communication_restriction;
|
||||
};
|
||||
static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
|
||||
|
||||
// This is nn::pctl::PlayTimerSettings
|
||||
struct PlayTimerSettings {
|
||||
std::array<u32, 13> settings;
|
||||
};
|
||||
static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
|
||||
|
||||
States states{};
|
||||
ParentalControlSettings settings{};
|
||||
RestrictionSettings restriction_settings{};
|
||||
std::array<char, 8> pin_code{};
|
||||
Capability capability{};
|
||||
|
||||
Kernel::KEvent* synchronization_event;
|
||||
Kernel::KEvent* unlinked_event;
|
||||
Kernel::KEvent* request_suspension_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
void Module::Interface::CreateService(HLERequestContext& ctx) {
|
||||
|
@ -102,16 +102,17 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
|
||||
m_system.ServiceManager().RegisterService(service_name, max_sessions, handler)));
|
||||
|
||||
// Get the registered port.
|
||||
auto port = m_system.ServiceManager().GetServicePort(service_name);
|
||||
ASSERT(port.Succeeded());
|
||||
Kernel::KPort* port{};
|
||||
ASSERT(
|
||||
R_SUCCEEDED(m_system.ServiceManager().GetServicePort(std::addressof(port), service_name)));
|
||||
|
||||
// Open a new reference to the server port.
|
||||
(*port)->GetServerPort().Open();
|
||||
port->GetServerPort().Open();
|
||||
|
||||
// Begin tracking the server port.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_ports.emplace(std::addressof((*port)->GetServerPort()), std::move(handler));
|
||||
m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler));
|
||||
}
|
||||
|
||||
// Signal the wakeup event.
|
||||
|
@ -11,66 +11,6 @@
|
||||
|
||||
namespace Service::Set {
|
||||
namespace {
|
||||
constexpr std::array<LanguageCode, 18> available_language_codes = {{
|
||||
LanguageCode::JA,
|
||||
LanguageCode::EN_US,
|
||||
LanguageCode::FR,
|
||||
LanguageCode::DE,
|
||||
LanguageCode::IT,
|
||||
LanguageCode::ES,
|
||||
LanguageCode::ZH_CN,
|
||||
LanguageCode::KO,
|
||||
LanguageCode::NL,
|
||||
LanguageCode::PT,
|
||||
LanguageCode::RU,
|
||||
LanguageCode::ZH_TW,
|
||||
LanguageCode::EN_GB,
|
||||
LanguageCode::FR_CA,
|
||||
LanguageCode::ES_419,
|
||||
LanguageCode::ZH_HANS,
|
||||
LanguageCode::ZH_HANT,
|
||||
LanguageCode::PT_BR,
|
||||
}};
|
||||
|
||||
enum class KeyboardLayout : u64 {
|
||||
Japanese = 0,
|
||||
EnglishUs = 1,
|
||||
EnglishUsInternational = 2,
|
||||
EnglishUk = 3,
|
||||
French = 4,
|
||||
FrenchCa = 5,
|
||||
Spanish = 6,
|
||||
SpanishLatin = 7,
|
||||
German = 8,
|
||||
Italian = 9,
|
||||
Portuguese = 10,
|
||||
Russian = 11,
|
||||
Korean = 12,
|
||||
ChineseSimplified = 13,
|
||||
ChineseTraditional = 14,
|
||||
};
|
||||
|
||||
constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
|
||||
{LanguageCode::JA, KeyboardLayout::Japanese},
|
||||
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
|
||||
{LanguageCode::FR, KeyboardLayout::French},
|
||||
{LanguageCode::DE, KeyboardLayout::German},
|
||||
{LanguageCode::IT, KeyboardLayout::Italian},
|
||||
{LanguageCode::ES, KeyboardLayout::Spanish},
|
||||
{LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::KO, KeyboardLayout::Korean},
|
||||
{LanguageCode::NL, KeyboardLayout::EnglishUsInternational},
|
||||
{LanguageCode::PT, KeyboardLayout::Portuguese},
|
||||
{LanguageCode::RU, KeyboardLayout::Russian},
|
||||
{LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::EN_GB, KeyboardLayout::EnglishUk},
|
||||
{LanguageCode::FR_CA, KeyboardLayout::FrenchCa},
|
||||
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
|
||||
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
|
||||
}};
|
||||
|
||||
constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF;
|
||||
constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40;
|
||||
|
||||
@ -93,7 +33,8 @@ void GetAvailableLanguageCodesImpl(HLERequestContext& ctx, std::size_t max_entri
|
||||
}
|
||||
|
||||
void GetKeyCodeMapImpl(HLERequestContext& ctx) {
|
||||
const auto language_code = available_language_codes[Settings::values.language_index.GetValue()];
|
||||
const auto language_code =
|
||||
available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())];
|
||||
const auto key_code =
|
||||
std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
|
||||
[=](const auto& element) { return element.first == language_code; });
|
||||
@ -162,7 +103,7 @@ void SET::GetQuestFlag(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
|
||||
rb.Push(static_cast<s32>(Settings::values.quest_flag.GetValue()));
|
||||
}
|
||||
|
||||
void SET::GetLanguageCode(HLERequestContext& ctx) {
|
||||
@ -170,7 +111,8 @@ void SET::GetLanguageCode(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(available_language_codes[Settings::values.language_index.GetValue()]);
|
||||
rb.PushEnum(
|
||||
available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]);
|
||||
}
|
||||
|
||||
void SET::GetRegionCode(HLERequestContext& ctx) {
|
||||
@ -178,7 +120,7 @@ void SET::GetRegionCode(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(Settings::values.region_index.GetValue());
|
||||
rb.Push(static_cast<u32>(Settings::values.region_index.GetValue()));
|
||||
}
|
||||
|
||||
void SET::GetKeyCodeMap(HLERequestContext& ctx) {
|
||||
|
@ -32,6 +32,67 @@ enum class LanguageCode : u64 {
|
||||
ZH_HANT = 0x00746E61482D687A,
|
||||
PT_BR = 0x00000052422D7470,
|
||||
};
|
||||
|
||||
enum class KeyboardLayout : u64 {
|
||||
Japanese = 0,
|
||||
EnglishUs = 1,
|
||||
EnglishUsInternational = 2,
|
||||
EnglishUk = 3,
|
||||
French = 4,
|
||||
FrenchCa = 5,
|
||||
Spanish = 6,
|
||||
SpanishLatin = 7,
|
||||
German = 8,
|
||||
Italian = 9,
|
||||
Portuguese = 10,
|
||||
Russian = 11,
|
||||
Korean = 12,
|
||||
ChineseSimplified = 13,
|
||||
ChineseTraditional = 14,
|
||||
};
|
||||
|
||||
constexpr std::array<LanguageCode, 18> available_language_codes = {{
|
||||
LanguageCode::JA,
|
||||
LanguageCode::EN_US,
|
||||
LanguageCode::FR,
|
||||
LanguageCode::DE,
|
||||
LanguageCode::IT,
|
||||
LanguageCode::ES,
|
||||
LanguageCode::ZH_CN,
|
||||
LanguageCode::KO,
|
||||
LanguageCode::NL,
|
||||
LanguageCode::PT,
|
||||
LanguageCode::RU,
|
||||
LanguageCode::ZH_TW,
|
||||
LanguageCode::EN_GB,
|
||||
LanguageCode::FR_CA,
|
||||
LanguageCode::ES_419,
|
||||
LanguageCode::ZH_HANS,
|
||||
LanguageCode::ZH_HANT,
|
||||
LanguageCode::PT_BR,
|
||||
}};
|
||||
|
||||
static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
|
||||
{LanguageCode::JA, KeyboardLayout::Japanese},
|
||||
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
|
||||
{LanguageCode::FR, KeyboardLayout::French},
|
||||
{LanguageCode::DE, KeyboardLayout::German},
|
||||
{LanguageCode::IT, KeyboardLayout::Italian},
|
||||
{LanguageCode::ES, KeyboardLayout::Spanish},
|
||||
{LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::KO, KeyboardLayout::Korean},
|
||||
{LanguageCode::NL, KeyboardLayout::EnglishUsInternational},
|
||||
{LanguageCode::PT, KeyboardLayout::Portuguese},
|
||||
{LanguageCode::RU, KeyboardLayout::Russian},
|
||||
{LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::EN_GB, KeyboardLayout::EnglishUk},
|
||||
{LanguageCode::FR_CA, KeyboardLayout::FrenchCa},
|
||||
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
|
||||
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
|
||||
}};
|
||||
|
||||
LanguageCode GetLanguageCodeFromIndex(std::size_t idx);
|
||||
|
||||
class SET final : public ServiceFramework<SET> {
|
||||
|
@ -4,10 +4,12 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/system_archive/system_version.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
#include "core/hle/service/set/set_sys.h"
|
||||
|
||||
namespace Service::Set {
|
||||
@ -73,6 +75,16 @@ void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type)
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void SET_SYS::SetLanguageCode(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
language_code_setting = rp.PopEnum<LanguageCode>();
|
||||
|
||||
LOG_INFO(Service_SET, "called, language_code={}", language_code_setting);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version1);
|
||||
@ -83,21 +95,113 @@ void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
|
||||
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version2);
|
||||
}
|
||||
|
||||
void SET_SYS::GetAccountSettings(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(account_settings);
|
||||
}
|
||||
|
||||
void SET_SYS::SetAccountSettings(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
account_settings = rp.PopRaw<AccountSettings>();
|
||||
|
||||
LOG_INFO(Service_SET, "called, account_settings_flags={}", account_settings.flags);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetEulaVersions(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
|
||||
ctx.WriteBuffer(eula_versions);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(eula_versions.size()));
|
||||
}
|
||||
|
||||
void SET_SYS::SetEulaVersions(HLERequestContext& ctx) {
|
||||
const auto elements = ctx.GetReadBufferNumElements<EulaVersion>();
|
||||
const auto buffer_data = ctx.ReadBuffer();
|
||||
|
||||
LOG_INFO(Service_SET, "called, elements={}", elements);
|
||||
|
||||
eula_versions.resize(elements);
|
||||
for (std::size_t index = 0; index < elements; index++) {
|
||||
const std::size_t start_index = index * sizeof(EulaVersion);
|
||||
memcpy(eula_versions.data() + start_index, buffer_data.data() + start_index,
|
||||
sizeof(EulaVersion));
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetColorSetId(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(color_set);
|
||||
}
|
||||
|
||||
void SET_SYS::SetColorSetId(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
color_set = rp.PopEnum<ColorSet>();
|
||||
|
||||
LOG_DEBUG(Service_SET, "called, color_set={}", color_set);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetNotificationSettings(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 8};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(notification_settings);
|
||||
}
|
||||
|
||||
void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
notification_settings = rp.PopRaw<NotificationSettings>();
|
||||
|
||||
LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}",
|
||||
notification_settings.flags.raw, notification_settings.volume,
|
||||
notification_settings.start_time.hour, notification_settings.start_time.minute,
|
||||
notification_settings.stop_time.hour, notification_settings.stop_time.minute);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetAccountNotificationSettings(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
|
||||
ctx.WriteBuffer(account_notifications);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(account_notifications.size()));
|
||||
}
|
||||
|
||||
void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) {
|
||||
const auto elements = ctx.GetReadBufferNumElements<AccountNotificationSettings>();
|
||||
const auto buffer_data = ctx.ReadBuffer();
|
||||
|
||||
LOG_INFO(Service_SET, "called, elements={}", elements);
|
||||
|
||||
account_notifications.resize(elements);
|
||||
for (std::size_t index = 0; index < elements; index++) {
|
||||
const std::size_t start_index = index * sizeof(AccountNotificationSettings);
|
||||
memcpy(account_notifications.data() + start_index, buffer_data.data() + start_index,
|
||||
sizeof(AccountNotificationSettings));
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
@ -177,17 +281,218 @@ void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) {
|
||||
rb.Push(response);
|
||||
}
|
||||
|
||||
void SET_SYS::GetDeviceNickName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
void SET_SYS::GetTvSettings(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(tv_settings);
|
||||
}
|
||||
|
||||
void SET_SYS::SetTvSettings(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
tv_settings = rp.PopRaw<TvSettings>();
|
||||
|
||||
LOG_INFO(Service_SET,
|
||||
"called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, "
|
||||
"rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}",
|
||||
tv_settings.flags.raw, tv_settings.cmu_mode, tv_settings.constrast_ratio,
|
||||
tv_settings.hdmi_content_type, tv_settings.rgb_range, tv_settings.tv_gama,
|
||||
tv_settings.tv_resolution, tv_settings.tv_underscan);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetQuestFlag(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(QuestFlag::Retail);
|
||||
}
|
||||
|
||||
void SET_SYS::SetRegionCode(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
region_code = rp.PopEnum<RegionCode>();
|
||||
|
||||
LOG_INFO(Service_SET, "called, region_code={}", region_code);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetPrimaryAlbumStorage(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(PrimaryAlbumStorage::SdCard);
|
||||
}
|
||||
|
||||
void SET_SYS::GetSleepSettings(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(sleep_settings);
|
||||
}
|
||||
|
||||
void SET_SYS::SetSleepSettings(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
sleep_settings = rp.PopRaw<SleepSettings>();
|
||||
|
||||
LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}",
|
||||
sleep_settings.flags.raw, sleep_settings.handheld_sleep_plan,
|
||||
sleep_settings.console_sleep_plan);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetInitialLaunchSettings(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(launch_settings);
|
||||
}
|
||||
|
||||
void SET_SYS::SetInitialLaunchSettings(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
launch_settings = rp.PopRaw<InitialLaunchSettings>();
|
||||
|
||||
LOG_INFO(Service_SET, "called, flags={}, timestamp={}", launch_settings.flags.raw,
|
||||
launch_settings.timestamp.time_point);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetDeviceNickName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
ctx.WriteBuffer(::Settings::values.device_name.GetValue());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::SetDeviceNickName(HLERequestContext& ctx) {
|
||||
const std::string device_name = Common::StringFromBuffer(ctx.ReadBuffer());
|
||||
|
||||
LOG_INFO(Service_SET, "called, device_name={}", device_name);
|
||||
|
||||
::Settings::values.device_name = device_name;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetProductModel(HLERequestContext& ctx) {
|
||||
const u32 product_model = 1;
|
||||
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called, product_model={}", product_model);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(product_model);
|
||||
}
|
||||
|
||||
void SET_SYS::GetMiiAuthorId(HLERequestContext& ctx) {
|
||||
const auto author_id = Common::UUID::MakeDefault();
|
||||
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called, author_id={}", author_id.FormattedString());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(author_id);
|
||||
}
|
||||
|
||||
void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) {
|
||||
u8 auto_update_flag{};
|
||||
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called, auto_update_flag={}", auto_update_flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(auto_update_flag);
|
||||
}
|
||||
|
||||
void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) {
|
||||
u8 battery_percentage_flag{1};
|
||||
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}",
|
||||
battery_percentage_flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(battery_percentage_flag);
|
||||
}
|
||||
|
||||
void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(ErrorReportSharePermission::Denied);
|
||||
}
|
||||
|
||||
void SET_SYS::GetAppletLaunchFlags(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(applet_launch_flag);
|
||||
}
|
||||
|
||||
void SET_SYS::SetAppletLaunchFlags(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
applet_launch_flag = rp.Pop<u32>();
|
||||
|
||||
LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SET_SYS::GetKeyboardLayout(HLERequestContext& ctx) {
|
||||
const auto language_code =
|
||||
available_language_codes[static_cast<s32>(::Settings::values.language_index.GetValue())];
|
||||
const auto key_code =
|
||||
std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
|
||||
[=](const auto& element) { return element.first == language_code; });
|
||||
|
||||
KeyboardLayout selected_keyboard_layout = KeyboardLayout::EnglishUs;
|
||||
if (key_code != language_to_layout.end()) {
|
||||
selected_keyboard_layout = key_code->second;
|
||||
}
|
||||
|
||||
LOG_INFO(Service_SET, "called, selected_keyboard_layout={}", selected_keyboard_layout);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(selected_keyboard_layout));
|
||||
}
|
||||
|
||||
void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(ChineseTraditionalInputMethod::Unknown0);
|
||||
}
|
||||
|
||||
void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(false);
|
||||
}
|
||||
|
||||
SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "SetLanguageCode"},
|
||||
{0, &SET_SYS::SetLanguageCode, "SetLanguageCode"},
|
||||
{1, nullptr, "SetNetworkSettings"},
|
||||
{2, nullptr, "GetNetworkSettings"},
|
||||
{3, &SET_SYS::GetFirmwareVersion, "GetFirmwareVersion"},
|
||||
@ -203,35 +508,35 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{14, nullptr, "SetExternalSteadyClockSourceId"},
|
||||
{15, nullptr, "GetUserSystemClockContext"},
|
||||
{16, nullptr, "SetUserSystemClockContext"},
|
||||
{17, nullptr, "GetAccountSettings"},
|
||||
{18, nullptr, "SetAccountSettings"},
|
||||
{17, &SET_SYS::GetAccountSettings, "GetAccountSettings"},
|
||||
{18, &SET_SYS::SetAccountSettings, "SetAccountSettings"},
|
||||
{19, nullptr, "GetAudioVolume"},
|
||||
{20, nullptr, "SetAudioVolume"},
|
||||
{21, nullptr, "GetEulaVersions"},
|
||||
{22, nullptr, "SetEulaVersions"},
|
||||
{21, &SET_SYS::GetEulaVersions, "GetEulaVersions"},
|
||||
{22, &SET_SYS::SetEulaVersions, "SetEulaVersions"},
|
||||
{23, &SET_SYS::GetColorSetId, "GetColorSetId"},
|
||||
{24, &SET_SYS::SetColorSetId, "SetColorSetId"},
|
||||
{25, nullptr, "GetConsoleInformationUploadFlag"},
|
||||
{26, nullptr, "SetConsoleInformationUploadFlag"},
|
||||
{27, nullptr, "GetAutomaticApplicationDownloadFlag"},
|
||||
{28, nullptr, "SetAutomaticApplicationDownloadFlag"},
|
||||
{29, nullptr, "GetNotificationSettings"},
|
||||
{30, nullptr, "SetNotificationSettings"},
|
||||
{31, nullptr, "GetAccountNotificationSettings"},
|
||||
{32, nullptr, "SetAccountNotificationSettings"},
|
||||
{29, &SET_SYS::GetNotificationSettings, "GetNotificationSettings"},
|
||||
{30, &SET_SYS::SetNotificationSettings, "SetNotificationSettings"},
|
||||
{31, &SET_SYS::GetAccountNotificationSettings, "GetAccountNotificationSettings"},
|
||||
{32, &SET_SYS::SetAccountNotificationSettings, "SetAccountNotificationSettings"},
|
||||
{35, nullptr, "GetVibrationMasterVolume"},
|
||||
{36, nullptr, "SetVibrationMasterVolume"},
|
||||
{37, &SET_SYS::GetSettingsItemValueSize, "GetSettingsItemValueSize"},
|
||||
{38, &SET_SYS::GetSettingsItemValue, "GetSettingsItemValue"},
|
||||
{39, nullptr, "GetTvSettings"},
|
||||
{40, nullptr, "SetTvSettings"},
|
||||
{39, &SET_SYS::GetTvSettings, "GetTvSettings"},
|
||||
{40, &SET_SYS::SetTvSettings, "SetTvSettings"},
|
||||
{41, nullptr, "GetEdid"},
|
||||
{42, nullptr, "SetEdid"},
|
||||
{43, nullptr, "GetAudioOutputMode"},
|
||||
{44, nullptr, "SetAudioOutputMode"},
|
||||
{45, nullptr, "IsForceMuteOnHeadphoneRemoved"},
|
||||
{46, nullptr, "SetForceMuteOnHeadphoneRemoved"},
|
||||
{47, nullptr, "GetQuestFlag"},
|
||||
{47, &SET_SYS::GetQuestFlag, "GetQuestFlag"},
|
||||
{48, nullptr, "SetQuestFlag"},
|
||||
{49, nullptr, "GetDataDeletionSettings"},
|
||||
{50, nullptr, "SetDataDeletionSettings"},
|
||||
@ -241,13 +546,13 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{54, nullptr, "SetDeviceTimeZoneLocationName"},
|
||||
{55, nullptr, "GetWirelessCertificationFileSize"},
|
||||
{56, nullptr, "GetWirelessCertificationFile"},
|
||||
{57, nullptr, "SetRegionCode"},
|
||||
{57, &SET_SYS::SetRegionCode, "SetRegionCode"},
|
||||
{58, nullptr, "GetNetworkSystemClockContext"},
|
||||
{59, nullptr, "SetNetworkSystemClockContext"},
|
||||
{60, nullptr, "IsUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{61, nullptr, "SetUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{62, nullptr, "GetDebugModeFlag"},
|
||||
{63, nullptr, "GetPrimaryAlbumStorage"},
|
||||
{63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"},
|
||||
{64, nullptr, "SetPrimaryAlbumStorage"},
|
||||
{65, nullptr, "GetUsb30EnableFlag"},
|
||||
{66, nullptr, "SetUsb30EnableFlag"},
|
||||
@ -255,15 +560,15 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{68, nullptr, "GetSerialNumber"},
|
||||
{69, nullptr, "GetNfcEnableFlag"},
|
||||
{70, nullptr, "SetNfcEnableFlag"},
|
||||
{71, nullptr, "GetSleepSettings"},
|
||||
{72, nullptr, "SetSleepSettings"},
|
||||
{71, &SET_SYS::GetSleepSettings, "GetSleepSettings"},
|
||||
{72, &SET_SYS::SetSleepSettings, "SetSleepSettings"},
|
||||
{73, nullptr, "GetWirelessLanEnableFlag"},
|
||||
{74, nullptr, "SetWirelessLanEnableFlag"},
|
||||
{75, nullptr, "GetInitialLaunchSettings"},
|
||||
{76, nullptr, "SetInitialLaunchSettings"},
|
||||
{75, &SET_SYS::GetInitialLaunchSettings, "GetInitialLaunchSettings"},
|
||||
{76, &SET_SYS::SetInitialLaunchSettings, "SetInitialLaunchSettings"},
|
||||
{77, &SET_SYS::GetDeviceNickName, "GetDeviceNickName"},
|
||||
{78, nullptr, "SetDeviceNickName"},
|
||||
{79, nullptr, "GetProductModel"},
|
||||
{78, &SET_SYS::SetDeviceNickName, "SetDeviceNickName"},
|
||||
{79, &SET_SYS::GetProductModel, "GetProductModel"},
|
||||
{80, nullptr, "GetLdnChannel"},
|
||||
{81, nullptr, "SetLdnChannel"},
|
||||
{82, nullptr, "AcquireTelemetryDirtyFlagEventHandle"},
|
||||
@ -274,16 +579,16 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{87, nullptr, "SetPtmFuelGaugeParameter"},
|
||||
{88, nullptr, "GetBluetoothEnableFlag"},
|
||||
{89, nullptr, "SetBluetoothEnableFlag"},
|
||||
{90, nullptr, "GetMiiAuthorId"},
|
||||
{90, &SET_SYS::GetMiiAuthorId, "GetMiiAuthorId"},
|
||||
{91, nullptr, "SetShutdownRtcValue"},
|
||||
{92, nullptr, "GetShutdownRtcValue"},
|
||||
{93, nullptr, "AcquireFatalDirtyFlagEventHandle"},
|
||||
{94, nullptr, "GetFatalDirtyFlags"},
|
||||
{95, nullptr, "GetAutoUpdateEnableFlag"},
|
||||
{95, &SET_SYS::GetAutoUpdateEnableFlag, "GetAutoUpdateEnableFlag"},
|
||||
{96, nullptr, "SetAutoUpdateEnableFlag"},
|
||||
{97, nullptr, "GetNxControllerSettings"},
|
||||
{98, nullptr, "SetNxControllerSettings"},
|
||||
{99, nullptr, "GetBatteryPercentageFlag"},
|
||||
{99, &SET_SYS::GetBatteryPercentageFlag, "GetBatteryPercentageFlag"},
|
||||
{100, nullptr, "SetBatteryPercentageFlag"},
|
||||
{101, nullptr, "GetExternalRtcResetFlag"},
|
||||
{102, nullptr, "SetExternalRtcResetFlag"},
|
||||
@ -308,10 +613,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{121, nullptr, "SetPushNotificationActivityModeOnSleep"},
|
||||
{122, nullptr, "GetServiceDiscoveryControlSettings"},
|
||||
{123, nullptr, "SetServiceDiscoveryControlSettings"},
|
||||
{124, nullptr, "GetErrorReportSharePermission"},
|
||||
{124, &SET_SYS::GetErrorReportSharePermission, "GetErrorReportSharePermission"},
|
||||
{125, nullptr, "SetErrorReportSharePermission"},
|
||||
{126, nullptr, "GetAppletLaunchFlags"},
|
||||
{127, nullptr, "SetAppletLaunchFlags"},
|
||||
{126, &SET_SYS::GetAppletLaunchFlags, "GetAppletLaunchFlags"},
|
||||
{127, &SET_SYS::SetAppletLaunchFlags, "SetAppletLaunchFlags"},
|
||||
{128, nullptr, "GetConsoleSixAxisSensorAccelerationBias"},
|
||||
{129, nullptr, "SetConsoleSixAxisSensorAccelerationBias"},
|
||||
{130, nullptr, "GetConsoleSixAxisSensorAngularVelocityBias"},
|
||||
@ -320,7 +625,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{133, nullptr, "SetConsoleSixAxisSensorAccelerationGain"},
|
||||
{134, nullptr, "GetConsoleSixAxisSensorAngularVelocityGain"},
|
||||
{135, nullptr, "SetConsoleSixAxisSensorAngularVelocityGain"},
|
||||
{136, nullptr, "GetKeyboardLayout"},
|
||||
{136, &SET_SYS::GetKeyboardLayout, "GetKeyboardLayout"},
|
||||
{137, nullptr, "SetKeyboardLayout"},
|
||||
{138, nullptr, "GetWebInspectorFlag"},
|
||||
{139, nullptr, "GetAllowedSslHosts"},
|
||||
@ -354,7 +659,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{167, nullptr, "SetUsb30DeviceEnableFlag"},
|
||||
{168, nullptr, "GetThemeId"},
|
||||
{169, nullptr, "SetThemeId"},
|
||||
{170, nullptr, "GetChineseTraditionalInputMethod"},
|
||||
{170, &SET_SYS::GetChineseTraditionalInputMethod, "GetChineseTraditionalInputMethod"},
|
||||
{171, nullptr, "SetChineseTraditionalInputMethod"},
|
||||
{172, nullptr, "GetPtmCycleCountReliability"},
|
||||
{173, nullptr, "SetPtmCycleCountReliability"},
|
||||
@ -385,12 +690,16 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"},
|
||||
{199, nullptr, "GetButtonConfigRegisteredSettings"},
|
||||
{200, nullptr, "SetButtonConfigRegisteredSettings"},
|
||||
{201, nullptr, "GetFieldTestingFlag"},
|
||||
{201, &SET_SYS::GetFieldTestingFlag, "GetFieldTestingFlag"},
|
||||
{202, nullptr, "SetFieldTestingFlag"},
|
||||
{203, nullptr, "GetPanelCrcMode"},
|
||||
{204, nullptr, "SetPanelCrcMode"},
|
||||
{205, nullptr, "GetNxControllerSettingsEx"},
|
||||
{206, nullptr, "SetNxControllerSettingsEx"},
|
||||
{207, nullptr, "GetHearingProtectionSafeguardFlag"},
|
||||
{208, nullptr, "SetHearingProtectionSafeguardFlag"},
|
||||
{209, nullptr, "GetHearingProtectionSafeguardRemainingTime"},
|
||||
{210, nullptr, "SetHearingProtectionSafeguardRemainingTime"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@ -23,15 +25,331 @@ private:
|
||||
BasicBlack = 1,
|
||||
};
|
||||
|
||||
void GetSettingsItemValueSize(HLERequestContext& ctx);
|
||||
void GetSettingsItemValue(HLERequestContext& ctx);
|
||||
/// Indicates the current console is a retail or kiosk unit
|
||||
enum class QuestFlag : u8 {
|
||||
Retail = 0,
|
||||
Kiosk = 1,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::TvResolution
|
||||
enum class TvResolution : u32 {
|
||||
Auto,
|
||||
Resolution1080p,
|
||||
Resolution720p,
|
||||
Resolution480p,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::HdmiContentType
|
||||
enum class HdmiContentType : u32 {
|
||||
None,
|
||||
Graphics,
|
||||
Cinema,
|
||||
Photo,
|
||||
Game,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::RgbRange
|
||||
enum class RgbRange : u32 {
|
||||
Auto,
|
||||
Full,
|
||||
Limited,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::CmuMode
|
||||
enum class CmuMode : u32 {
|
||||
None,
|
||||
ColorInvert,
|
||||
HighContrast,
|
||||
GrayScale,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::PrimaryAlbumStorage
|
||||
enum class PrimaryAlbumStorage : u32 {
|
||||
Nand,
|
||||
SdCard,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::NotificationVolume
|
||||
enum class NotificationVolume : u32 {
|
||||
Mute,
|
||||
Low,
|
||||
High,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::ChineseTraditionalInputMethod
|
||||
enum class ChineseTraditionalInputMethod : u32 {
|
||||
Unknown0 = 0,
|
||||
Unknown1 = 1,
|
||||
Unknown2 = 2,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::ErrorReportSharePermission
|
||||
enum class ErrorReportSharePermission : u32 {
|
||||
NotConfirmed,
|
||||
Granted,
|
||||
Denied,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::FriendPresenceOverlayPermission
|
||||
enum class FriendPresenceOverlayPermission : u8 {
|
||||
NotConfirmed,
|
||||
NoDisplay,
|
||||
FavoriteFriends,
|
||||
Friends,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::HandheldSleepPlan
|
||||
enum class HandheldSleepPlan : u32 {
|
||||
Sleep1Min,
|
||||
Sleep3Min,
|
||||
Sleep5Min,
|
||||
Sleep10Min,
|
||||
Sleep30Min,
|
||||
Never,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::ConsoleSleepPlan
|
||||
enum class ConsoleSleepPlan : u32 {
|
||||
Sleep1Hour,
|
||||
Sleep2Hour,
|
||||
Sleep3Hour,
|
||||
Sleep6Hour,
|
||||
Sleep12Hour,
|
||||
Never,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::RegionCode
|
||||
enum class RegionCode : u32 {
|
||||
Japan,
|
||||
Usa,
|
||||
Europe,
|
||||
Australia,
|
||||
HongKongTaiwanKorea,
|
||||
China,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::EulaVersionClockType
|
||||
enum class EulaVersionClockType : u32 {
|
||||
NetworkSystemClock,
|
||||
SteadyClock,
|
||||
};
|
||||
|
||||
/// This is nn::settings::system::SleepFlag
|
||||
struct SleepFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> SleepsWhilePlayingMedia;
|
||||
BitField<1, 1, u32> WakesAtPowerStateChange;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::TvFlag
|
||||
struct TvFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> Allows4k;
|
||||
BitField<1, 1, u32> Allows3d;
|
||||
BitField<2, 1, u32> AllowsCec;
|
||||
BitField<3, 1, u32> PreventsScreenBurnIn;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::InitialLaunchFlag
|
||||
struct InitialLaunchFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> InitialLaunchCompletionFlag;
|
||||
BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
|
||||
BitField<16, 1, u32> InitialLaunchTimestampFlag;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::NotificationFlag
|
||||
struct NotificationFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> RingtoneFlag;
|
||||
BitField<1, 1, u32> DownloadCompletionFlag;
|
||||
BitField<8, 1, u32> EnablesNews;
|
||||
BitField<9, 1, u32> IncomingLampFlag;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::AccountNotificationFlag
|
||||
struct AccountNotificationFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> FriendOnlineFlag;
|
||||
BitField<1, 1, u32> FriendRequestFlag;
|
||||
BitField<8, 1, u32> CoralInvitationFlag;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(AccountNotificationFlag) == 4,
|
||||
"AccountNotificationFlag is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::TvSettings
|
||||
struct TvSettings {
|
||||
TvFlag flags;
|
||||
TvResolution tv_resolution;
|
||||
HdmiContentType hdmi_content_type;
|
||||
RgbRange rgb_range;
|
||||
CmuMode cmu_mode;
|
||||
u32 tv_underscan;
|
||||
f32 tv_gama;
|
||||
f32 constrast_ratio;
|
||||
};
|
||||
static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::NotificationTime
|
||||
struct NotificationTime {
|
||||
u32 hour;
|
||||
u32 minute;
|
||||
};
|
||||
static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::NotificationSettings
|
||||
struct NotificationSettings {
|
||||
NotificationFlag flags;
|
||||
NotificationVolume volume;
|
||||
NotificationTime start_time;
|
||||
NotificationTime stop_time;
|
||||
};
|
||||
static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::AccountSettings
|
||||
struct AccountSettings {
|
||||
u32 flags;
|
||||
};
|
||||
static_assert(sizeof(AccountSettings) == 0x4, "AccountSettings is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::AccountNotificationSettings
|
||||
struct AccountNotificationSettings {
|
||||
Common::UUID uid;
|
||||
AccountNotificationFlag flags;
|
||||
FriendPresenceOverlayPermission friend_presence_permission;
|
||||
FriendPresenceOverlayPermission friend_invitation_permission;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
};
|
||||
static_assert(sizeof(AccountNotificationSettings) == 0x18,
|
||||
"AccountNotificationSettings is an invalid size");
|
||||
|
||||
/// This is nn::settings::system::InitialLaunchSettings
|
||||
struct SleepSettings {
|
||||
SleepFlag flags;
|
||||
HandheldSleepPlan handheld_sleep_plan;
|
||||
ConsoleSleepPlan console_sleep_plan;
|
||||
};
|
||||
static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
|
||||
|
||||
/// This is nn::settings::system::InitialLaunchSettings
|
||||
struct InitialLaunchSettings {
|
||||
InitialLaunchFlag flags;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
Time::Clock::SteadyClockTimePoint timestamp;
|
||||
};
|
||||
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
|
||||
|
||||
/// This is nn::settings::system::InitialLaunchSettings
|
||||
struct EulaVersion {
|
||||
u32 version;
|
||||
RegionCode region_code;
|
||||
EulaVersionClockType clock_type;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
s64 posix_time;
|
||||
Time::Clock::SteadyClockTimePoint timestamp;
|
||||
};
|
||||
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
|
||||
|
||||
void SetLanguageCode(HLERequestContext& ctx);
|
||||
void GetFirmwareVersion(HLERequestContext& ctx);
|
||||
void GetFirmwareVersion2(HLERequestContext& ctx);
|
||||
void GetAccountSettings(HLERequestContext& ctx);
|
||||
void SetAccountSettings(HLERequestContext& ctx);
|
||||
void GetEulaVersions(HLERequestContext& ctx);
|
||||
void SetEulaVersions(HLERequestContext& ctx);
|
||||
void GetColorSetId(HLERequestContext& ctx);
|
||||
void SetColorSetId(HLERequestContext& ctx);
|
||||
void GetNotificationSettings(HLERequestContext& ctx);
|
||||
void SetNotificationSettings(HLERequestContext& ctx);
|
||||
void GetAccountNotificationSettings(HLERequestContext& ctx);
|
||||
void SetAccountNotificationSettings(HLERequestContext& ctx);
|
||||
void GetSettingsItemValueSize(HLERequestContext& ctx);
|
||||
void GetSettingsItemValue(HLERequestContext& ctx);
|
||||
void GetTvSettings(HLERequestContext& ctx);
|
||||
void SetTvSettings(HLERequestContext& ctx);
|
||||
void GetQuestFlag(HLERequestContext& ctx);
|
||||
void SetRegionCode(HLERequestContext& ctx);
|
||||
void GetPrimaryAlbumStorage(HLERequestContext& ctx);
|
||||
void GetSleepSettings(HLERequestContext& ctx);
|
||||
void SetSleepSettings(HLERequestContext& ctx);
|
||||
void GetInitialLaunchSettings(HLERequestContext& ctx);
|
||||
void SetInitialLaunchSettings(HLERequestContext& ctx);
|
||||
void GetDeviceNickName(HLERequestContext& ctx);
|
||||
void SetDeviceNickName(HLERequestContext& ctx);
|
||||
void GetProductModel(HLERequestContext& ctx);
|
||||
void GetMiiAuthorId(HLERequestContext& ctx);
|
||||
void GetAutoUpdateEnableFlag(HLERequestContext& ctx);
|
||||
void GetBatteryPercentageFlag(HLERequestContext& ctx);
|
||||
void GetErrorReportSharePermission(HLERequestContext& ctx);
|
||||
void GetAppletLaunchFlags(HLERequestContext& ctx);
|
||||
void SetAppletLaunchFlags(HLERequestContext& ctx);
|
||||
void GetKeyboardLayout(HLERequestContext& ctx);
|
||||
void GetChineseTraditionalInputMethod(HLERequestContext& ctx);
|
||||
void GetFieldTestingFlag(HLERequestContext& ctx);
|
||||
|
||||
AccountSettings account_settings{
|
||||
.flags = {},
|
||||
};
|
||||
|
||||
ColorSet color_set = ColorSet::BasicWhite;
|
||||
|
||||
NotificationSettings notification_settings{
|
||||
.flags = {0x300},
|
||||
.volume = NotificationVolume::High,
|
||||
.start_time = {.hour = 9, .minute = 0},
|
||||
.stop_time = {.hour = 21, .minute = 0},
|
||||
};
|
||||
|
||||
std::vector<AccountNotificationSettings> account_notifications{};
|
||||
|
||||
TvSettings tv_settings{
|
||||
.flags = {0xc},
|
||||
.tv_resolution = TvResolution::Auto,
|
||||
.hdmi_content_type = HdmiContentType::Game,
|
||||
.rgb_range = RgbRange::Auto,
|
||||
.cmu_mode = CmuMode::None,
|
||||
.tv_underscan = {},
|
||||
.tv_gama = 1.0f,
|
||||
.constrast_ratio = 0.5f,
|
||||
};
|
||||
|
||||
InitialLaunchSettings launch_settings{
|
||||
.flags = {0x10001},
|
||||
.timestamp = {},
|
||||
};
|
||||
|
||||
SleepSettings sleep_settings{
|
||||
.flags = {0x3},
|
||||
.handheld_sleep_plan = HandheldSleepPlan::Sleep10Min,
|
||||
.console_sleep_plan = ConsoleSleepPlan::Sleep1Hour,
|
||||
};
|
||||
|
||||
u32 applet_launch_flag{};
|
||||
|
||||
std::vector<EulaVersion> eula_versions{};
|
||||
|
||||
RegionCode region_code;
|
||||
|
||||
LanguageCode language_code_setting;
|
||||
};
|
||||
|
||||
} // namespace Service::Set
|
||||
|
@ -52,8 +52,7 @@ static Result ValidateServiceName(const std::string& name) {
|
||||
|
||||
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
|
||||
SessionRequestHandlerPtr handler) {
|
||||
|
||||
CASCADE_CODE(ValidateServiceName(name));
|
||||
R_TRY(ValidateServiceName(name));
|
||||
|
||||
std::scoped_lock lk{lock};
|
||||
if (registered_services.find(name) != registered_services.end()) {
|
||||
@ -77,7 +76,7 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
|
||||
}
|
||||
|
||||
Result ServiceManager::UnregisterService(const std::string& name) {
|
||||
CASCADE_CODE(ValidateServiceName(name));
|
||||
R_TRY(ValidateServiceName(name));
|
||||
|
||||
std::scoped_lock lk{lock};
|
||||
const auto iter = registered_services.find(name);
|
||||
@ -92,8 +91,8 @@ Result ServiceManager::UnregisterService(const std::string& name) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
|
||||
CASCADE_CODE(ValidateServiceName(name));
|
||||
Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::string& name) {
|
||||
R_TRY(ValidateServiceName(name));
|
||||
|
||||
std::scoped_lock lk{lock};
|
||||
auto it = service_ports.find(name);
|
||||
@ -102,7 +101,8 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
|
||||
return Service::SM::ResultNotRegistered;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
*out_port = it->second;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,32 +122,34 @@ void SM::Initialize(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void SM::GetService(HLERequestContext& ctx) {
|
||||
auto result = GetServiceImpl(ctx);
|
||||
Kernel::KClientSession* client_session{};
|
||||
auto result = GetServiceImpl(&client_session, ctx);
|
||||
if (ctx.GetIsDeferred()) {
|
||||
// Don't overwrite the command buffer.
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Succeeded()) {
|
||||
if (result == ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(result.Code());
|
||||
rb.PushMoveObjects(result.Unwrap());
|
||||
rb.Push(result);
|
||||
rb.PushMoveObjects(client_session);
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result.Code());
|
||||
rb.Push(result);
|
||||
}
|
||||
}
|
||||
|
||||
void SM::GetServiceTipc(HLERequestContext& ctx) {
|
||||
auto result = GetServiceImpl(ctx);
|
||||
Kernel::KClientSession* client_session{};
|
||||
auto result = GetServiceImpl(&client_session, ctx);
|
||||
if (ctx.GetIsDeferred()) {
|
||||
// Don't overwrite the command buffer.
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(result.Code());
|
||||
rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
|
||||
rb.Push(result);
|
||||
rb.PushMoveObjects(result == ResultSuccess ? client_session : nullptr);
|
||||
}
|
||||
|
||||
static std::string PopServiceName(IPC::RequestParser& rp) {
|
||||
@ -161,7 +163,7 @@ static std::string PopServiceName(IPC::RequestParser& rp) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
|
||||
Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx) {
|
||||
if (!ctx.GetManager()->GetIsInitializedForSm()) {
|
||||
return Service::SM::ResultInvalidClient;
|
||||
}
|
||||
@ -170,18 +172,18 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
|
||||
std::string name(PopServiceName(rp));
|
||||
|
||||
// Find the named port.
|
||||
auto port_result = service_manager.GetServicePort(name);
|
||||
if (port_result.Code() == Service::SM::ResultInvalidServiceName) {
|
||||
Kernel::KPort* port{};
|
||||
auto port_result = service_manager.GetServicePort(&port, name);
|
||||
if (port_result == Service::SM::ResultInvalidServiceName) {
|
||||
LOG_ERROR(Service_SM, "Invalid service name '{}'", name);
|
||||
return Service::SM::ResultInvalidServiceName;
|
||||
}
|
||||
|
||||
if (port_result.Failed()) {
|
||||
if (port_result != ResultSuccess) {
|
||||
LOG_INFO(Service_SM, "Waiting for service {} to become available", name);
|
||||
ctx.SetIsDeferred();
|
||||
return Service::SM::ResultNotRegistered;
|
||||
}
|
||||
auto& port = port_result.Unwrap();
|
||||
|
||||
// Create a new session.
|
||||
Kernel::KClientSession* session{};
|
||||
@ -192,7 +194,8 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
|
||||
|
||||
return session;
|
||||
*out_client_session = session;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void SM::RegisterService(HLERequestContext& ctx) {
|
||||
|
@ -42,7 +42,7 @@ private:
|
||||
void RegisterService(HLERequestContext& ctx);
|
||||
void UnregisterService(HLERequestContext& ctx);
|
||||
|
||||
ResultVal<Kernel::KClientSession*> GetServiceImpl(HLERequestContext& ctx);
|
||||
Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
|
||||
|
||||
ServiceManager& service_manager;
|
||||
Kernel::KernelCore& kernel;
|
||||
@ -55,7 +55,7 @@ public:
|
||||
|
||||
Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler);
|
||||
Result UnregisterService(const std::string& name);
|
||||
ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
|
||||
Result GetServicePort(Kernel::KPort** out_port, const std::string& name);
|
||||
|
||||
template <Common::DerivedFrom<SessionRequestHandler> T>
|
||||
std::shared_ptr<T> GetService(const std::string& service_name) const {
|
||||
|
@ -54,7 +54,7 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
|
||||
static std::string ResolveImpl(const std::string& fqdn_in) {
|
||||
// The real implementation makes various substitutions.
|
||||
// For now we just return the string as-is, which is good enough when not
|
||||
// connecting to real Nintendo servers.
|
||||
@ -64,13 +64,10 @@ static ResultVal<std::string> ResolveImpl(const std::string& fqdn_in) {
|
||||
|
||||
static Result ResolveCommon(const std::string& fqdn_in, std::array<char, 0x100>& fqdn_out) {
|
||||
const auto res = ResolveImpl(fqdn_in);
|
||||
if (res.Failed()) {
|
||||
return res.Code();
|
||||
}
|
||||
if (res->size() >= fqdn_out.size()) {
|
||||
if (res.size() >= fqdn_out.size()) {
|
||||
return ResultOverflow;
|
||||
}
|
||||
std::memcpy(fqdn_out.data(), res->c_str(), res->size() + 1);
|
||||
std::memcpy(fqdn_out.data(), res.c_str(), res.size() + 1);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,8 @@ namespace Service::SPL {
|
||||
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
|
||||
const char* name)
|
||||
: ServiceFramework{system_, name}, module{std::move(module_)},
|
||||
rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {}
|
||||
rng(Settings::values.rng_seed_enabled ? Settings::values.rng_seed.GetValue()
|
||||
: static_cast<u32>(std::time(nullptr))) {}
|
||||
|
||||
Module::Interface::~Interface() = default;
|
||||
|
||||
@ -29,10 +30,10 @@ void Module::Interface::GetConfig(HLERequestContext& ctx) {
|
||||
|
||||
// This should call svcCallSecureMonitor with the appropriate args.
|
||||
// Since we do not have it implemented yet, we will use this for now.
|
||||
const auto smc_result = GetConfigImpl(config_item);
|
||||
const auto result_code = smc_result.Code();
|
||||
u64 smc_result{};
|
||||
const auto result_code = GetConfigImpl(&smc_result, config_item);
|
||||
|
||||
if (smc_result.Failed()) {
|
||||
if (result_code != ResultSuccess) {
|
||||
LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item,
|
||||
result_code.raw);
|
||||
|
||||
@ -41,11 +42,11 @@ void Module::Interface::GetConfig(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item,
|
||||
result_code.raw, *smc_result);
|
||||
result_code.raw, smc_result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(result_code);
|
||||
rb.Push(*smc_result);
|
||||
rb.Push(smc_result);
|
||||
}
|
||||
|
||||
void Module::Interface::ModularExponentiate(HLERequestContext& ctx) {
|
||||
@ -98,7 +99,7 @@ void Module::Interface::GetBootReason(HLERequestContext& ctx) {
|
||||
rb.Push(ResultSecureMonitorNotImplemented);
|
||||
}
|
||||
|
||||
ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
|
||||
Result Module::Interface::GetConfigImpl(u64* out_config, ConfigItem config_item) const {
|
||||
switch (config_item) {
|
||||
case ConfigItem::DisableProgramVerification:
|
||||
case ConfigItem::DramId:
|
||||
@ -120,40 +121,50 @@ ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
|
||||
return ResultSecureMonitorNotImplemented;
|
||||
case ConfigItem::ExosphereApiVersion:
|
||||
// Get information about the current exosphere version.
|
||||
return (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
|
||||
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
|
||||
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
|
||||
(static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()));
|
||||
*out_config = (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) |
|
||||
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) |
|
||||
(u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) |
|
||||
(static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()));
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereNeedsReboot:
|
||||
// We are executing, so we aren't in the process of rebooting.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereNeedsShutdown:
|
||||
// We are executing, so we aren't in the process of shutting down.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereGitCommitHash:
|
||||
// Get information about the current exosphere git commit hash.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereHasRcmBugPatch:
|
||||
// Get information about whether this unit has the RCM bug patched.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereBlankProdInfo:
|
||||
// Get whether this unit should simulate a "blanked" PRODINFO.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereAllowCalWrites:
|
||||
// Get whether this unit should allow writing to the calibration partition.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereEmummcType:
|
||||
// Get what kind of emummc this unit has active.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExospherePayloadAddress:
|
||||
// Gets the physical address of the reboot payload buffer, if one exists.
|
||||
return ResultSecureMonitorNotInitialized;
|
||||
case ConfigItem::ExosphereLogConfiguration:
|
||||
// Get the log configuration.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
case ConfigItem::ExosphereForceEnableUsb30:
|
||||
// Get whether usb 3.0 should be force-enabled.
|
||||
return u64{0};
|
||||
*out_config = u64{0};
|
||||
return ResultSuccess;
|
||||
default:
|
||||
return ResultSecureMonitorInvalidArgument;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
std::shared_ptr<Module> module;
|
||||
|
||||
private:
|
||||
ResultVal<u64> GetConfigImpl(ConfigItem config_item) const;
|
||||
Result GetConfigImpl(u64* out_config, ConfigItem config_item) const;
|
||||
|
||||
std::mt19937 rng;
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "common/string_util.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@ -141,12 +142,12 @@ private:
|
||||
bool did_set_host_name = false;
|
||||
bool did_handshake = false;
|
||||
|
||||
ResultVal<s32> SetSocketDescriptorImpl(s32 fd) {
|
||||
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
|
||||
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
|
||||
ASSERT(!did_handshake);
|
||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
|
||||
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
|
||||
s32 ret_fd;
|
||||
|
||||
// Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor
|
||||
if (do_not_close_socket) {
|
||||
auto res = bsd->DuplicateSocketImpl(fd);
|
||||
@ -156,9 +157,9 @@ private:
|
||||
}
|
||||
fd = *res;
|
||||
fd_to_close = fd;
|
||||
ret_fd = fd;
|
||||
*out_fd = fd;
|
||||
} else {
|
||||
ret_fd = -1;
|
||||
*out_fd = -1;
|
||||
}
|
||||
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
|
||||
if (!sock.has_value()) {
|
||||
@ -167,7 +168,7 @@ private:
|
||||
}
|
||||
socket = std::move(*sock);
|
||||
backend->SetSocket(socket);
|
||||
return ret_fd;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result SetHostNameImpl(const std::string& hostname) {
|
||||
@ -247,34 +248,36 @@ private:
|
||||
return ret;
|
||||
}
|
||||
|
||||
ResultVal<std::vector<u8>> ReadImpl(size_t size) {
|
||||
Result ReadImpl(std::vector<u8>* out_data, size_t size) {
|
||||
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
|
||||
std::vector<u8> res(size);
|
||||
ResultVal<size_t> actual = backend->Read(res);
|
||||
if (actual.Failed()) {
|
||||
return actual.Code();
|
||||
size_t actual_size{};
|
||||
Result res = backend->Read(&actual_size, *out_data);
|
||||
if (res != ResultSuccess) {
|
||||
return res;
|
||||
}
|
||||
res.resize(*actual);
|
||||
out_data->resize(actual_size);
|
||||
return res;
|
||||
}
|
||||
|
||||
ResultVal<size_t> WriteImpl(std::span<const u8> data) {
|
||||
Result WriteImpl(size_t* out_size, std::span<const u8> data) {
|
||||
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
|
||||
return backend->Write(data);
|
||||
return backend->Write(out_size, data);
|
||||
}
|
||||
|
||||
ResultVal<s32> PendingImpl() {
|
||||
Result PendingImpl(s32* out_pending) {
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called.");
|
||||
return 0;
|
||||
*out_pending = 0;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void SetSocketDescriptor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const s32 fd = rp.Pop<s32>();
|
||||
const ResultVal<s32> res = SetSocketDescriptorImpl(fd);
|
||||
const s32 in_fd = rp.Pop<s32>();
|
||||
s32 out_fd{-1};
|
||||
const Result res = SetSocketDescriptorImpl(&out_fd, in_fd);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res.Code());
|
||||
rb.Push<s32>(res.ValueOr(-1));
|
||||
rb.Push(res);
|
||||
rb.Push<s32>(out_fd);
|
||||
}
|
||||
|
||||
void SetHostName(HLERequestContext& ctx) {
|
||||
@ -313,14 +316,15 @@ private:
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0x8);
|
||||
|
||||
const Result res = DoHandshakeImpl();
|
||||
Result res = DoHandshakeImpl();
|
||||
OutputParameters out{};
|
||||
if (res == ResultSuccess) {
|
||||
auto certs = backend->GetServerCerts();
|
||||
if (certs.Succeeded()) {
|
||||
const std::vector<u8> certs_buf = SerializeServerCerts(*certs);
|
||||
std::vector<std::vector<u8>> certs;
|
||||
res = backend->GetServerCerts(&certs);
|
||||
if (res == ResultSuccess) {
|
||||
const std::vector<u8> certs_buf = SerializeServerCerts(certs);
|
||||
ctx.WriteBuffer(certs_buf);
|
||||
out.certs_count = static_cast<u32>(certs->size());
|
||||
out.certs_count = static_cast<u32>(certs.size());
|
||||
out.certs_size = static_cast<u32>(certs_buf.size());
|
||||
}
|
||||
}
|
||||
@ -330,29 +334,32 @@ private:
|
||||
}
|
||||
|
||||
void Read(HLERequestContext& ctx) {
|
||||
const ResultVal<std::vector<u8>> res = ReadImpl(ctx.GetWriteBufferSize());
|
||||
std::vector<u8> output_bytes;
|
||||
const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize());
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res.Code());
|
||||
if (res.Succeeded()) {
|
||||
rb.Push(static_cast<u32>(res->size()));
|
||||
ctx.WriteBuffer(*res);
|
||||
rb.Push(res);
|
||||
if (res == ResultSuccess) {
|
||||
rb.Push(static_cast<u32>(output_bytes.size()));
|
||||
ctx.WriteBuffer(output_bytes);
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(0));
|
||||
}
|
||||
}
|
||||
|
||||
void Write(HLERequestContext& ctx) {
|
||||
const ResultVal<size_t> res = WriteImpl(ctx.ReadBuffer());
|
||||
size_t write_size{0};
|
||||
const Result res = WriteImpl(&write_size, ctx.ReadBuffer());
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res.Code());
|
||||
rb.Push(static_cast<u32>(res.ValueOr(0)));
|
||||
rb.Push(res);
|
||||
rb.Push(static_cast<u32>(write_size));
|
||||
}
|
||||
|
||||
void Pending(HLERequestContext& ctx) {
|
||||
const ResultVal<s32> res = PendingImpl();
|
||||
s32 pending_size{0};
|
||||
const Result res = PendingImpl(&pending_size);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res.Code());
|
||||
rb.Push<s32>(res.ValueOr(0));
|
||||
rb.Push(res);
|
||||
rb.Push<s32>(pending_size);
|
||||
}
|
||||
|
||||
void SetSessionCacheMode(HLERequestContext& ctx) {
|
||||
@ -438,13 +445,14 @@ private:
|
||||
void CreateConnection(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SSL, "called");
|
||||
|
||||
auto backend_res = CreateSSLConnectionBackend();
|
||||
std::unique_ptr<SSLConnectionBackend> backend;
|
||||
const Result res = CreateSSLConnectionBackend(&backend);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(backend_res.Code());
|
||||
if (backend_res.Succeeded()) {
|
||||
rb.Push(res);
|
||||
if (res == ResultSuccess) {
|
||||
rb.PushIpcInterface<ISslConnection>(system, ssl_version, shared_data,
|
||||
std::move(*backend_res));
|
||||
std::move(backend));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,11 +35,11 @@ public:
|
||||
virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
|
||||
virtual Result SetHostName(const std::string& hostname) = 0;
|
||||
virtual Result DoHandshake() = 0;
|
||||
virtual ResultVal<size_t> Read(std::span<u8> data) = 0;
|
||||
virtual ResultVal<size_t> Write(std::span<const u8> data) = 0;
|
||||
virtual ResultVal<std::vector<std::vector<u8>>> GetServerCerts() = 0;
|
||||
virtual Result Read(size_t* out_size, std::span<u8> data) = 0;
|
||||
virtual Result Write(size_t* out_size, std::span<const u8> data) = 0;
|
||||
virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0;
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend();
|
||||
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend);
|
||||
|
||||
} // namespace Service::SSL
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
namespace Service::SSL {
|
||||
|
||||
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
|
||||
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
|
||||
LOG_ERROR(Service_SSL,
|
||||
"Can't create SSL connection because no SSL backend is available on this platform");
|
||||
return ResultInternalError;
|
||||
|
@ -105,31 +105,30 @@ public:
|
||||
return ResultInternalError;
|
||||
}
|
||||
}
|
||||
return HandleReturn("SSL_do_handshake", 0, ret).Code();
|
||||
return HandleReturn("SSL_do_handshake", 0, ret);
|
||||
}
|
||||
|
||||
ResultVal<size_t> Read(std::span<u8> data) override {
|
||||
size_t actual;
|
||||
const int ret = SSL_read_ex(ssl, data.data(), data.size(), &actual);
|
||||
return HandleReturn("SSL_read_ex", actual, ret);
|
||||
Result Read(size_t* out_size, std::span<u8> data) override {
|
||||
const int ret = SSL_read_ex(ssl, data.data(), data.size(), out_size);
|
||||
return HandleReturn("SSL_read_ex", out_size, ret);
|
||||
}
|
||||
|
||||
ResultVal<size_t> Write(std::span<const u8> data) override {
|
||||
size_t actual;
|
||||
const int ret = SSL_write_ex(ssl, data.data(), data.size(), &actual);
|
||||
return HandleReturn("SSL_write_ex", actual, ret);
|
||||
Result Write(size_t* out_size, std::span<const u8> data) override {
|
||||
const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size);
|
||||
return HandleReturn("SSL_write_ex", out_size, ret);
|
||||
}
|
||||
|
||||
ResultVal<size_t> HandleReturn(const char* what, size_t actual, int ret) {
|
||||
Result HandleReturn(const char* what, size_t* actual, int ret) {
|
||||
const int ssl_err = SSL_get_error(ssl, ret);
|
||||
CheckOpenSSLErrors();
|
||||
switch (ssl_err) {
|
||||
case SSL_ERROR_NONE:
|
||||
return actual;
|
||||
return ResultSuccess;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_ZERO_RETURN", what);
|
||||
// DoHandshake special-cases this, but for Read and Write:
|
||||
return size_t(0);
|
||||
*actual = 0;
|
||||
return ResultSuccess;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_WANT_READ", what);
|
||||
return ResultWouldBlock;
|
||||
@ -139,20 +138,20 @@ public:
|
||||
default:
|
||||
if (ssl_err == SSL_ERROR_SYSCALL && got_read_eof) {
|
||||
LOG_DEBUG(Service_SSL, "{} => SSL_ERROR_SYSCALL because server hung up", what);
|
||||
return size_t(0);
|
||||
*actual = 0;
|
||||
return ResultSuccess;
|
||||
}
|
||||
LOG_ERROR(Service_SSL, "{} => other SSL_get_error return value {}", what, ssl_err);
|
||||
return ResultInternalError;
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
|
||||
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
|
||||
STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
|
||||
if (!chain) {
|
||||
LOG_ERROR(Service_SSL, "SSL_get_peer_cert_chain returned nullptr");
|
||||
return ResultInternalError;
|
||||
}
|
||||
std::vector<std::vector<u8>> ret;
|
||||
int count = sk_X509_num(chain);
|
||||
ASSERT(count >= 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
@ -161,10 +160,10 @@ public:
|
||||
unsigned char* buf = nullptr;
|
||||
int len = i2d_X509(x509, &buf);
|
||||
ASSERT_OR_EXECUTE(len >= 0 && buf, { continue; });
|
||||
ret.emplace_back(buf, buf + len);
|
||||
out_certs->emplace_back(buf, buf + len);
|
||||
OPENSSL_free(buf);
|
||||
}
|
||||
return ret;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
~SSLConnectionBackendOpenSSL() {
|
||||
@ -253,13 +252,13 @@ public:
|
||||
std::shared_ptr<Network::SocketBase> socket;
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
|
||||
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
|
||||
auto conn = std::make_unique<SSLConnectionBackendOpenSSL>();
|
||||
const Result res = conn->Init();
|
||||
if (res.IsFailure()) {
|
||||
return res;
|
||||
}
|
||||
return conn;
|
||||
|
||||
R_TRY(conn->Init());
|
||||
|
||||
*out_backend = std::move(conn);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -299,21 +299,22 @@ public:
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<size_t> Read(std::span<u8> data) override {
|
||||
Result Read(size_t* out_size, std::span<u8> data) override {
|
||||
*out_size = 0;
|
||||
if (handshake_state != HandshakeState::Connected) {
|
||||
LOG_ERROR(Service_SSL, "Called Read but we did not successfully handshake");
|
||||
return ResultInternalError;
|
||||
}
|
||||
if (data.size() == 0 || got_read_eof) {
|
||||
return size_t(0);
|
||||
return ResultSuccess;
|
||||
}
|
||||
while (1) {
|
||||
if (!cleartext_read_buf.empty()) {
|
||||
const size_t read_size = std::min(cleartext_read_buf.size(), data.size());
|
||||
std::memcpy(data.data(), cleartext_read_buf.data(), read_size);
|
||||
*out_size = std::min(cleartext_read_buf.size(), data.size());
|
||||
std::memcpy(data.data(), cleartext_read_buf.data(), *out_size);
|
||||
cleartext_read_buf.erase(cleartext_read_buf.begin(),
|
||||
cleartext_read_buf.begin() + read_size);
|
||||
return read_size;
|
||||
cleartext_read_buf.begin() + *out_size);
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (!ciphertext_read_buf.empty()) {
|
||||
SecBuffer empty{
|
||||
@ -366,7 +367,8 @@ public:
|
||||
case SEC_I_CONTEXT_EXPIRED:
|
||||
// Server hung up by sending close_notify.
|
||||
got_read_eof = true;
|
||||
return size_t(0);
|
||||
*out_size = 0;
|
||||
return ResultSuccess;
|
||||
default:
|
||||
LOG_ERROR(Service_SSL, "DecryptMessage failed: {}",
|
||||
Common::NativeErrorToString(ret));
|
||||
@ -379,18 +381,21 @@ public:
|
||||
}
|
||||
if (ciphertext_read_buf.empty()) {
|
||||
got_read_eof = true;
|
||||
return size_t(0);
|
||||
*out_size = 0;
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal<size_t> Write(std::span<const u8> data) override {
|
||||
Result Write(size_t* out_size, std::span<const u8> data) override {
|
||||
*out_size = 0;
|
||||
|
||||
if (handshake_state != HandshakeState::Connected) {
|
||||
LOG_ERROR(Service_SSL, "Called Write but we did not successfully handshake");
|
||||
return ResultInternalError;
|
||||
}
|
||||
if (data.size() == 0) {
|
||||
return size_t(0);
|
||||
return ResultSuccess;
|
||||
}
|
||||
data = data.subspan(0, std::min<size_t>(data.size(), stream_sizes.cbMaximumMessage));
|
||||
if (!cleartext_write_buf.empty()) {
|
||||
@ -402,7 +407,7 @@ public:
|
||||
LOG_ERROR(Service_SSL, "Called Write but buffer does not match previous buffer");
|
||||
return ResultInternalError;
|
||||
}
|
||||
return WriteAlreadyEncryptedData();
|
||||
return WriteAlreadyEncryptedData(out_size);
|
||||
} else {
|
||||
cleartext_write_buf.assign(data.begin(), data.end());
|
||||
}
|
||||
@ -448,21 +453,21 @@ public:
|
||||
tmp_data_buf.end());
|
||||
ciphertext_write_buf.insert(ciphertext_write_buf.end(), trailer_buf.begin(),
|
||||
trailer_buf.end());
|
||||
return WriteAlreadyEncryptedData();
|
||||
return WriteAlreadyEncryptedData(out_size);
|
||||
}
|
||||
|
||||
ResultVal<size_t> WriteAlreadyEncryptedData() {
|
||||
Result WriteAlreadyEncryptedData(size_t* out_size) {
|
||||
const Result r = FlushCiphertextWriteBuf();
|
||||
if (r != ResultSuccess) {
|
||||
return r;
|
||||
}
|
||||
// write buf is empty
|
||||
const size_t cleartext_bytes_written = cleartext_write_buf.size();
|
||||
*out_size = cleartext_write_buf.size();
|
||||
cleartext_write_buf.clear();
|
||||
return cleartext_bytes_written;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
|
||||
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
|
||||
PCCERT_CONTEXT returned_cert = nullptr;
|
||||
const SECURITY_STATUS ret =
|
||||
QueryContextAttributes(&ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &returned_cert);
|
||||
@ -473,16 +478,15 @@ public:
|
||||
return ResultInternalError;
|
||||
}
|
||||
PCCERT_CONTEXT some_cert = nullptr;
|
||||
std::vector<std::vector<u8>> certs;
|
||||
while ((some_cert = CertEnumCertificatesInStore(returned_cert->hCertStore, some_cert))) {
|
||||
certs.emplace_back(static_cast<u8*>(some_cert->pbCertEncoded),
|
||||
static_cast<u8*>(some_cert->pbCertEncoded) +
|
||||
some_cert->cbCertEncoded);
|
||||
out_certs->emplace_back(static_cast<u8*>(some_cert->pbCertEncoded),
|
||||
static_cast<u8*>(some_cert->pbCertEncoded) +
|
||||
some_cert->cbCertEncoded);
|
||||
}
|
||||
std::reverse(certs.begin(),
|
||||
certs.end()); // Windows returns certs in reverse order from what we want
|
||||
std::reverse(out_certs->begin(),
|
||||
out_certs->end()); // Windows returns certs in reverse order from what we want
|
||||
CertFreeCertificateContext(returned_cert);
|
||||
return certs;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
~SSLConnectionBackendSchannel() {
|
||||
@ -532,13 +536,13 @@ public:
|
||||
size_t read_buf_fill_size = 0;
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
|
||||
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
|
||||
auto conn = std::make_unique<SSLConnectionBackendSchannel>();
|
||||
const Result res = conn->Init();
|
||||
if (res.IsFailure()) {
|
||||
return res;
|
||||
}
|
||||
return conn;
|
||||
|
||||
R_TRY(conn->Init());
|
||||
|
||||
*out_backend = std::move(conn);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
} // namespace Service::SSL
|
||||
|
@ -103,24 +103,20 @@ public:
|
||||
return HandleReturn("SSLHandshake", 0, status).Code();
|
||||
}
|
||||
|
||||
ResultVal<size_t> Read(std::span<u8> data) override {
|
||||
size_t actual;
|
||||
OSStatus status = SSLRead(context, data.data(), data.size(), &actual);
|
||||
;
|
||||
return HandleReturn("SSLRead", actual, status);
|
||||
Result Read(size_t* out_size, std::span<u8> data) override {
|
||||
OSStatus status = SSLRead(context, data.data(), data.size(), out_size);
|
||||
return HandleReturn("SSLRead", out_size, status);
|
||||
}
|
||||
|
||||
ResultVal<size_t> Write(std::span<const u8> data) override {
|
||||
size_t actual;
|
||||
OSStatus status = SSLWrite(context, data.data(), data.size(), &actual);
|
||||
;
|
||||
return HandleReturn("SSLWrite", actual, status);
|
||||
Result Write(size_t* out_size, std::span<const u8> data) override {
|
||||
OSStatus status = SSLWrite(context, data.data(), data.size(), out_size);
|
||||
return HandleReturn("SSLWrite", out_size, status);
|
||||
}
|
||||
|
||||
ResultVal<size_t> HandleReturn(const char* what, size_t actual, OSStatus status) {
|
||||
Result HandleReturn(const char* what, size_t* actual, OSStatus status) {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return actual;
|
||||
return ResultSuccess;
|
||||
case errSSLWouldBlock:
|
||||
return ResultWouldBlock;
|
||||
default: {
|
||||
@ -136,22 +132,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal<std::vector<std::vector<u8>>> GetServerCerts() override {
|
||||
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
|
||||
CFReleaser<SecTrustRef> trust;
|
||||
OSStatus status = SSLCopyPeerTrust(context, &trust.ptr);
|
||||
if (status) {
|
||||
LOG_ERROR(Service_SSL, "SSLCopyPeerTrust failed: {}", OSStatusToString(status));
|
||||
return ResultInternalError;
|
||||
}
|
||||
std::vector<std::vector<u8>> ret;
|
||||
for (CFIndex i = 0, count = SecTrustGetCertificateCount(trust); i < count; i++) {
|
||||
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
|
||||
CFReleaser<CFDataRef> data(SecCertificateCopyData(cert));
|
||||
ASSERT_OR_EXECUTE(data, { return ResultInternalError; });
|
||||
const u8* ptr = CFDataGetBytePtr(data);
|
||||
ret.emplace_back(ptr, ptr + CFDataGetLength(data));
|
||||
out_certs->emplace_back(ptr, ptr + CFDataGetLength(data));
|
||||
}
|
||||
return ret;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static OSStatus ReadCallback(SSLConnectionRef connection, void* data, size_t* dataLength) {
|
||||
@ -210,13 +205,13 @@ private:
|
||||
std::shared_ptr<Network::SocketBase> socket;
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<SSLConnectionBackend>> CreateSSLConnectionBackend() {
|
||||
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
|
||||
auto conn = std::make_unique<SSLConnectionBackendSecureTransport>();
|
||||
const Result res = conn->Init();
|
||||
if (res.IsFailure()) {
|
||||
return res;
|
||||
}
|
||||
return conn;
|
||||
|
||||
R_TRY(conn->Init());
|
||||
|
||||
*out_backend = std::move(conn);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
} // namespace Service::SSL
|
||||
|
@ -78,7 +78,8 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
|
||||
location_name_cache{BuildLocationNameCache(time_zone_binary)} {}
|
||||
|
||||
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
|
||||
const auto timezone_setting = Settings::GetTimeZoneString();
|
||||
const auto timezone_setting =
|
||||
Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
|
||||
|
||||
if (FileSys::VirtualFile vfs_file;
|
||||
GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) {
|
||||
|
@ -58,14 +58,15 @@ const Layer& Display::GetLayer(std::size_t index) const {
|
||||
return *layers.at(index);
|
||||
}
|
||||
|
||||
ResultVal<Kernel::KReadableEvent*> Display::GetVSyncEvent() {
|
||||
Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) {
|
||||
if (got_vsync_event) {
|
||||
return ResultPermissionDenied;
|
||||
}
|
||||
|
||||
got_vsync_event = true;
|
||||
|
||||
return GetVSyncEventUnchecked();
|
||||
*out_vsync_event = GetVSyncEventUnchecked();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() {
|
||||
|
@ -85,7 +85,7 @@ public:
|
||||
* @returns The internal Vsync event if it has not yet been retrieved,
|
||||
* VI::ResultPermissionDenied otherwise.
|
||||
*/
|
||||
[[nodiscard]] ResultVal<Kernel::KReadableEvent*> GetVSyncEvent();
|
||||
[[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event);
|
||||
|
||||
/// Gets the internal vsync event.
|
||||
Kernel::KReadableEvent* GetVSyncEventUnchecked();
|
||||
|
@ -683,9 +683,9 @@ private:
|
||||
|
||||
LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
|
||||
|
||||
const auto vsync_event = nv_flinger.FindVsyncEvent(display_id);
|
||||
if (vsync_event.Failed()) {
|
||||
const auto result = vsync_event.Code();
|
||||
Kernel::KReadableEvent* vsync_event{};
|
||||
const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id);
|
||||
if (result != ResultSuccess) {
|
||||
if (result == ResultNotFound) {
|
||||
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
|
||||
}
|
||||
@ -697,7 +697,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(*vsync_event);
|
||||
rb.PushCopyObjects(vsync_event);
|
||||
}
|
||||
|
||||
void ConvertScalingMode(HLERequestContext& ctx) {
|
||||
@ -705,15 +705,16 @@ private:
|
||||
const auto mode = rp.PopEnum<NintendoScaleMode>();
|
||||
LOG_DEBUG(Service_VI, "called mode={}", mode);
|
||||
|
||||
const auto converted_mode = ConvertScalingModeImpl(mode);
|
||||
ConvertedScaleMode converted_mode{};
|
||||
const auto result = ConvertScalingModeImpl(&converted_mode, mode);
|
||||
|
||||
if (converted_mode.Succeeded()) {
|
||||
if (result == ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(*converted_mode);
|
||||
rb.PushEnum(converted_mode);
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(converted_mode.Code());
|
||||
rb.Push(result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -760,18 +761,24 @@ private:
|
||||
rb.Push(alignment);
|
||||
}
|
||||
|
||||
static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) {
|
||||
static Result ConvertScalingModeImpl(ConvertedScaleMode* out_scaling_mode,
|
||||
NintendoScaleMode mode) {
|
||||
switch (mode) {
|
||||
case NintendoScaleMode::None:
|
||||
return ConvertedScaleMode::None;
|
||||
*out_scaling_mode = ConvertedScaleMode::None;
|
||||
return ResultSuccess;
|
||||
case NintendoScaleMode::Freeze:
|
||||
return ConvertedScaleMode::Freeze;
|
||||
*out_scaling_mode = ConvertedScaleMode::Freeze;
|
||||
return ResultSuccess;
|
||||
case NintendoScaleMode::ScaleToWindow:
|
||||
return ConvertedScaleMode::ScaleToWindow;
|
||||
*out_scaling_mode = ConvertedScaleMode::ScaleToWindow;
|
||||
return ResultSuccess;
|
||||
case NintendoScaleMode::ScaleAndCrop:
|
||||
return ConvertedScaleMode::ScaleAndCrop;
|
||||
*out_scaling_mode = ConvertedScaleMode::ScaleAndCrop;
|
||||
return ResultSuccess;
|
||||
case NintendoScaleMode::PreserveAspectRatio:
|
||||
return ConvertedScaleMode::PreserveAspectRatio;
|
||||
*out_scaling_mode = ConvertedScaleMode::PreserveAspectRatio;
|
||||
return ResultSuccess;
|
||||
default:
|
||||
LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode);
|
||||
return ResultOperationFailed;
|
||||
|
@ -509,9 +509,9 @@ class GuestMemory {
|
||||
|
||||
public:
|
||||
GuestMemory() = delete;
|
||||
explicit GuestMemory(M& memory_, u64 addr_, std::size_t size_,
|
||||
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
|
||||
Common::ScratchBuffer<T>* backup = nullptr)
|
||||
: memory{memory_}, addr{addr_}, size{size_} {
|
||||
: m_memory{memory}, m_addr{addr}, m_size{size} {
|
||||
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Read) {
|
||||
Read(addr, size, backup);
|
||||
@ -521,89 +521,97 @@ public:
|
||||
~GuestMemory() = default;
|
||||
|
||||
T* data() noexcept {
|
||||
return data_span.data();
|
||||
return m_data_span.data();
|
||||
}
|
||||
|
||||
const T* data() const noexcept {
|
||||
return data_span.data();
|
||||
return m_data_span.data();
|
||||
}
|
||||
|
||||
size_t size() const noexcept {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
size_t size_bytes() const noexcept {
|
||||
return this->size() * sizeof(T);
|
||||
}
|
||||
|
||||
[[nodiscard]] T* begin() noexcept {
|
||||
return data();
|
||||
return this->data();
|
||||
}
|
||||
|
||||
[[nodiscard]] const T* begin() const noexcept {
|
||||
return data();
|
||||
return this->data();
|
||||
}
|
||||
|
||||
[[nodiscard]] T* end() noexcept {
|
||||
return data() + size;
|
||||
return this->data() + this->size();
|
||||
}
|
||||
|
||||
[[nodiscard]] const T* end() const noexcept {
|
||||
return data() + size;
|
||||
return this->data() + this->size();
|
||||
}
|
||||
|
||||
T& operator[](size_t index) noexcept {
|
||||
return data_span[index];
|
||||
return m_data_span[index];
|
||||
}
|
||||
|
||||
const T& operator[](size_t index) const noexcept {
|
||||
return data_span[index];
|
||||
return m_data_span[index];
|
||||
}
|
||||
|
||||
void SetAddressAndSize(u64 addr_, std::size_t size_) noexcept {
|
||||
addr = addr_;
|
||||
size = size_;
|
||||
addr_changed = true;
|
||||
void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
|
||||
m_addr = addr;
|
||||
m_size = size;
|
||||
m_addr_changed = true;
|
||||
}
|
||||
|
||||
std::span<T> Read(u64 addr_, std::size_t size_,
|
||||
std::span<T> Read(u64 addr, std::size_t size,
|
||||
Common::ScratchBuffer<T>* backup = nullptr) noexcept {
|
||||
addr = addr_;
|
||||
size = size_;
|
||||
if (size == 0) {
|
||||
is_data_copy = true;
|
||||
m_addr = addr;
|
||||
m_size = size;
|
||||
if (m_size == 0) {
|
||||
m_is_data_copy = true;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (TrySetSpan()) {
|
||||
if (this->TrySetSpan()) {
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
memory.FlushRegion(addr, size * sizeof(T));
|
||||
m_memory.FlushRegion(m_addr, this->size_bytes());
|
||||
}
|
||||
} else {
|
||||
if (backup) {
|
||||
backup->resize_destructive(size);
|
||||
data_span = *backup;
|
||||
backup->resize_destructive(this->size());
|
||||
m_data_span = *backup;
|
||||
} else {
|
||||
data_copy.resize(size);
|
||||
data_span = std::span(data_copy);
|
||||
m_data_copy.resize(this->size());
|
||||
m_data_span = std::span(m_data_copy);
|
||||
}
|
||||
is_data_copy = true;
|
||||
span_valid = true;
|
||||
m_is_data_copy = true;
|
||||
m_span_valid = true;
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
memory.ReadBlock(addr, data_span.data(), size * sizeof(T));
|
||||
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
|
||||
} else {
|
||||
memory.ReadBlockUnsafe(addr, data_span.data(), size * sizeof(T));
|
||||
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
|
||||
}
|
||||
}
|
||||
return data_span;
|
||||
return m_data_span;
|
||||
}
|
||||
|
||||
void Write(std::span<T> write_data) noexcept {
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
|
||||
memory.WriteBlockCached(addr, write_data.data(), size * sizeof(T));
|
||||
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
|
||||
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
memory.WriteBlock(addr, write_data.data(), size * sizeof(T));
|
||||
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
|
||||
} else {
|
||||
memory.WriteBlockUnsafe(addr, write_data.data(), size * sizeof(T));
|
||||
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
bool TrySetSpan() noexcept {
|
||||
if (u8* ptr = memory.GetSpan(addr, size * sizeof(T)); ptr) {
|
||||
data_span = {reinterpret_cast<T*>(ptr), size};
|
||||
span_valid = true;
|
||||
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
|
||||
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
|
||||
m_span_valid = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -611,36 +619,36 @@ public:
|
||||
|
||||
protected:
|
||||
bool IsDataCopy() const noexcept {
|
||||
return is_data_copy;
|
||||
return m_is_data_copy;
|
||||
}
|
||||
|
||||
bool AddressChanged() const noexcept {
|
||||
return addr_changed;
|
||||
return m_addr_changed;
|
||||
}
|
||||
|
||||
M& memory;
|
||||
u64 addr;
|
||||
size_t size;
|
||||
std::span<T> data_span{};
|
||||
std::vector<T> data_copy;
|
||||
bool span_valid{false};
|
||||
bool is_data_copy{false};
|
||||
bool addr_changed{false};
|
||||
M& m_memory;
|
||||
u64 m_addr{};
|
||||
size_t m_size{};
|
||||
std::span<T> m_data_span{};
|
||||
std::vector<T> m_data_copy{};
|
||||
bool m_span_valid{false};
|
||||
bool m_is_data_copy{false};
|
||||
bool m_addr_changed{false};
|
||||
};
|
||||
|
||||
template <typename M, typename T, GuestMemoryFlags FLAGS>
|
||||
class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
|
||||
public:
|
||||
GuestMemoryScoped() = delete;
|
||||
explicit GuestMemoryScoped(M& memory_, u64 addr_, std::size_t size_,
|
||||
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
|
||||
Common::ScratchBuffer<T>* backup = nullptr)
|
||||
: GuestMemory<M, T, FLAGS>(memory_, addr_, size_, backup) {
|
||||
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
|
||||
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
|
||||
if (!this->TrySetSpan()) {
|
||||
if (backup) {
|
||||
this->data_span = *backup;
|
||||
this->span_valid = true;
|
||||
this->is_data_copy = true;
|
||||
this->m_data_span = *backup;
|
||||
this->m_span_valid = true;
|
||||
this->m_is_data_copy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -648,24 +656,21 @@ public:
|
||||
|
||||
~GuestMemoryScoped() {
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Write) {
|
||||
if (this->size == 0) [[unlikely]] {
|
||||
if (this->size() == 0) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->AddressChanged() || this->IsDataCopy()) {
|
||||
ASSERT(this->span_valid);
|
||||
ASSERT(this->m_span_valid);
|
||||
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
|
||||
this->memory.WriteBlockCached(this->addr, this->data_span.data(),
|
||||
this->size * sizeof(T));
|
||||
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
|
||||
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
this->memory.WriteBlock(this->addr, this->data_span.data(),
|
||||
this->size * sizeof(T));
|
||||
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
|
||||
} else {
|
||||
this->memory.WriteBlockUnsafe(this->addr, this->data_span.data(),
|
||||
this->size * sizeof(T));
|
||||
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
|
||||
}
|
||||
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
|
||||
this->memory.InvalidateRegion(this->addr, this->size * sizeof(T));
|
||||
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,13 +61,13 @@ static const char* TranslateRenderer(Settings::RendererBackend backend) {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) {
|
||||
static const char* TranslateGPUAccuracyLevel(Settings::GpuAccuracy backend) {
|
||||
switch (backend) {
|
||||
case Settings::GPUAccuracy::Normal:
|
||||
case Settings::GpuAccuracy::Normal:
|
||||
return "Normal";
|
||||
case Settings::GPUAccuracy::High:
|
||||
case Settings::GpuAccuracy::High:
|
||||
return "High";
|
||||
case Settings::GPUAccuracy::Extreme:
|
||||
case Settings::GpuAccuracy::Extreme:
|
||||
return "Extreme";
|
||||
}
|
||||
return "Unknown";
|
||||
@ -77,9 +77,9 @@ static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) {
|
||||
switch (backend) {
|
||||
case Settings::NvdecEmulation::Off:
|
||||
return "Off";
|
||||
case Settings::NvdecEmulation::CPU:
|
||||
case Settings::NvdecEmulation::Cpu:
|
||||
return "CPU";
|
||||
case Settings::NvdecEmulation::GPU:
|
||||
case Settings::NvdecEmulation::Gpu:
|
||||
return "GPU";
|
||||
}
|
||||
return "Unknown";
|
||||
@ -91,14 +91,26 @@ static constexpr const char* TranslateVSyncMode(Settings::VSyncMode mode) {
|
||||
return "Immediate";
|
||||
case Settings::VSyncMode::Mailbox:
|
||||
return "Mailbox";
|
||||
case Settings::VSyncMode::FIFO:
|
||||
case Settings::VSyncMode::Fifo:
|
||||
return "FIFO";
|
||||
case Settings::VSyncMode::FIFORelaxed:
|
||||
case Settings::VSyncMode::FifoRelaxed:
|
||||
return "FIFO Relaxed";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static constexpr const char* TranslateASTCDecodeMode(Settings::AstcDecodeMode mode) {
|
||||
switch (mode) {
|
||||
case Settings::AstcDecodeMode::Cpu:
|
||||
return "CPU";
|
||||
case Settings::AstcDecodeMode::Gpu:
|
||||
return "GPU";
|
||||
case Settings::AstcDecodeMode::CpuAsynchronous:
|
||||
return "CPU Asynchronous";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
u64 GetTelemetryId() {
|
||||
u64 telemetry_id{};
|
||||
const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id";
|
||||
@ -240,7 +252,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
|
||||
// Log user configuration information
|
||||
constexpr auto field_type = Telemetry::FieldType::UserConfig;
|
||||
AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
|
||||
AddField(field_type, "Audio_SinkId",
|
||||
Settings::CanonicalizeEnum(Settings::values.sink_id.GetValue()));
|
||||
AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
|
||||
AddField(field_type, "Renderer_Backend",
|
||||
TranslateRenderer(Settings::values.renderer_backend.GetValue()));
|
||||
@ -254,7 +267,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
Settings::values.use_asynchronous_gpu_emulation.GetValue());
|
||||
AddField(field_type, "Renderer_NvdecEmulation",
|
||||
TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue()));
|
||||
AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue());
|
||||
AddField(field_type, "Renderer_AccelerateASTC",
|
||||
TranslateASTCDecodeMode(Settings::values.accelerate_astc.GetValue()));
|
||||
AddField(field_type, "Renderer_UseVsync",
|
||||
TranslateVSyncMode(Settings::values.vsync_mode.GetValue()));
|
||||
AddField(field_type, "Renderer_ShaderBackend",
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
[[nodiscard]] virtual std::optional<ReplaceConstant> GetReplaceConstBuffer(u32 bank,
|
||||
u32 offset) = 0;
|
||||
|
||||
virtual void Dump(u64 hash) = 0;
|
||||
virtual void Dump(u64 pipeline_hash, u64 shader_hash) = 0;
|
||||
|
||||
[[nodiscard]] const ProgramHeader& SPH() const noexcept {
|
||||
return sph;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/polyfill_ranges.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
|
@ -247,7 +247,7 @@ void Codec::Initialize() {
|
||||
av_codec = avcodec_find_decoder(codec);
|
||||
|
||||
InitializeAvCodecContext();
|
||||
if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::GPU) {
|
||||
if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) {
|
||||
InitializeGpuDecoder();
|
||||
}
|
||||
if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
|
||||
|
@ -84,7 +84,7 @@ std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters
|
||||
|
||||
// TODO (ameerj): Where do we get this number, it seems to be particular for each stream
|
||||
const auto nvdec_decoding = Settings::values.nvdec_emulation.GetValue();
|
||||
const bool uses_gpu_decoding = nvdec_decoding == Settings::NvdecEmulation::GPU;
|
||||
const bool uses_gpu_decoding = nvdec_decoding == Settings::NvdecEmulation::Gpu;
|
||||
const u32 max_num_ref_frames = uses_gpu_decoding ? 6u : 16u;
|
||||
writer.WriteUe(max_num_ref_frames);
|
||||
writer.WriteBit(false);
|
||||
|
@ -34,13 +34,13 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac
|
||||
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
|
||||
program_manager{program_manager_}, info{info_} {
|
||||
switch (device.GetShaderBackend()) {
|
||||
case Settings::ShaderBackend::GLSL:
|
||||
case Settings::ShaderBackend::Glsl:
|
||||
source_program = CreateProgram(code, GL_COMPUTE_SHADER);
|
||||
break;
|
||||
case Settings::ShaderBackend::GLASM:
|
||||
case Settings::ShaderBackend::Glasm:
|
||||
assembly_program = CompileProgram(code, GL_COMPUTE_PROGRAM_NV);
|
||||
break;
|
||||
case Settings::ShaderBackend::SPIRV:
|
||||
case Settings::ShaderBackend::SpirV:
|
||||
source_program = CreateProgram(code_v, GL_COMPUTE_SHADER);
|
||||
break;
|
||||
}
|
||||
|
@ -106,6 +106,43 @@ bool IsASTCSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HasSlowSoftwareAstc(std::string_view vendor_name, std::string_view renderer) {
|
||||
// ifdef for Unix reduces string comparisons for non-Windows drivers, and Intel
|
||||
#ifdef YUZU_UNIX
|
||||
// Sorted vaguely by how likely a vendor is to appear
|
||||
if (vendor_name == "AMD") {
|
||||
// RadeonSI
|
||||
return true;
|
||||
}
|
||||
if (vendor_name == "Intel") {
|
||||
// Must be inside YUZU_UNIX ifdef as the Windows driver uses the same vendor string
|
||||
// iris, crocus
|
||||
const bool is_intel_dg = (renderer.find("DG") != std::string_view::npos);
|
||||
return is_intel_dg;
|
||||
}
|
||||
if (vendor_name == "nouveau") {
|
||||
return true;
|
||||
}
|
||||
if (vendor_name == "X.Org") {
|
||||
// R600
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (vendor_name == "Collabora Ltd") {
|
||||
// Zink
|
||||
return true;
|
||||
}
|
||||
if (vendor_name == "Microsoft Corporation") {
|
||||
// d3d12
|
||||
return true;
|
||||
}
|
||||
if (vendor_name == "Mesa/X.org") {
|
||||
// llvmpipe, softpipe, virgl
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) {
|
||||
const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
|
||||
return nsight || HasExtension(extensions, "GL_EXT_debug_tool") ||
|
||||
@ -120,12 +157,16 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
|
||||
}
|
||||
vendor_name = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
const std::vector extensions = GetExtensions();
|
||||
|
||||
const bool is_nvidia = vendor_name == "NVIDIA Corporation";
|
||||
const bool is_amd = vendor_name == "ATI Technologies Inc.";
|
||||
const bool is_intel = vendor_name == "Intel";
|
||||
|
||||
const bool has_slow_software_astc =
|
||||
!is_nvidia && !is_amd && HasSlowSoftwareAstc(vendor_name, renderer);
|
||||
|
||||
#ifdef __unix__
|
||||
constexpr bool is_linux = true;
|
||||
#else
|
||||
@ -152,7 +193,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
|
||||
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
|
||||
has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
|
||||
has_texture_shadow_lod = HasExtension(extensions, "GL_EXT_texture_shadow_lod");
|
||||
has_astc = IsASTCSupported();
|
||||
has_astc = !has_slow_software_astc && IsASTCSupported();
|
||||
has_variable_aoffi = TestVariableAoffi();
|
||||
has_component_indexing_bug = is_amd;
|
||||
has_precise_bug = TestPreciseBug();
|
||||
@ -177,15 +218,15 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
|
||||
has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
|
||||
|
||||
shader_backend = Settings::values.shader_backend.GetValue();
|
||||
use_assembly_shaders = shader_backend == Settings::ShaderBackend::GLASM &&
|
||||
use_assembly_shaders = shader_backend == Settings::ShaderBackend::Glasm &&
|
||||
GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
|
||||
GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
|
||||
if (shader_backend == Settings::ShaderBackend::GLASM && !use_assembly_shaders) {
|
||||
if (shader_backend == Settings::ShaderBackend::Glasm && !use_assembly_shaders) {
|
||||
LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
|
||||
shader_backend = Settings::ShaderBackend::GLSL;
|
||||
shader_backend = Settings::ShaderBackend::Glsl;
|
||||
}
|
||||
|
||||
if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia) {
|
||||
if (shader_backend == Settings::ShaderBackend::Glsl && is_nvidia) {
|
||||
const std::string_view driver_version = version.substr(13);
|
||||
const int version_major =
|
||||
std::atoi(driver_version.substr(0, driver_version.find(".")).data());
|
||||
|
@ -236,18 +236,18 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
|
||||
force_context_flush](ShaderContext::Context*) mutable {
|
||||
for (size_t stage = 0; stage < 5; ++stage) {
|
||||
switch (backend) {
|
||||
case Settings::ShaderBackend::GLSL:
|
||||
case Settings::ShaderBackend::Glsl:
|
||||
if (!sources_[stage].empty()) {
|
||||
source_programs[stage] = CreateProgram(sources_[stage], Stage(stage));
|
||||
}
|
||||
break;
|
||||
case Settings::ShaderBackend::GLASM:
|
||||
case Settings::ShaderBackend::Glasm:
|
||||
if (!sources_[stage].empty()) {
|
||||
assembly_programs[stage] =
|
||||
CompileProgram(sources_[stage], AssemblyStage(stage));
|
||||
}
|
||||
break;
|
||||
case Settings::ShaderBackend::SPIRV:
|
||||
case Settings::ShaderBackend::SpirV:
|
||||
if (!sources_spirv_[stage].empty()) {
|
||||
source_programs[stage] = CreateProgram(sources_spirv_[stage], Stage(stage));
|
||||
}
|
||||
|
@ -445,7 +445,8 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||
ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key,
|
||||
std::span<Shader::Environment* const> envs, bool use_shader_workers,
|
||||
bool force_context_flush) try {
|
||||
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
|
||||
auto hash = key.Hash();
|
||||
LOG_INFO(Render_OpenGL, "0x{:016x}", hash);
|
||||
size_t env_index{};
|
||||
u32 total_storage_buffers{};
|
||||
std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs;
|
||||
@ -474,7 +475,7 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||
Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
|
||||
|
||||
if (Settings::values.dump_shaders) {
|
||||
env.Dump(key.unique_hashes[index]);
|
||||
env.Dump(hash, key.unique_hashes[index]);
|
||||
}
|
||||
|
||||
if (!uses_vertex_a || index != 1) {
|
||||
@ -522,14 +523,14 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||
const auto runtime_info{
|
||||
MakeRuntimeInfo(key, program, previous_program, glasm_use_storage_buffers, use_glasm)};
|
||||
switch (device.GetShaderBackend()) {
|
||||
case Settings::ShaderBackend::GLSL:
|
||||
case Settings::ShaderBackend::Glsl:
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
sources[stage_index] = EmitGLSL(profile, runtime_info, program, binding);
|
||||
break;
|
||||
case Settings::ShaderBackend::GLASM:
|
||||
case Settings::ShaderBackend::Glasm:
|
||||
sources[stage_index] = EmitGLASM(profile, runtime_info, program, binding);
|
||||
break;
|
||||
case Settings::ShaderBackend::SPIRV:
|
||||
case Settings::ShaderBackend::SpirV:
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding);
|
||||
break;
|
||||
@ -566,12 +567,13 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||
std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||
ShaderContext::ShaderPools& pools, const ComputePipelineKey& key, Shader::Environment& env,
|
||||
bool force_context_flush) try {
|
||||
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
|
||||
auto hash = key.Hash();
|
||||
LOG_INFO(Render_OpenGL, "0x{:016x}", hash);
|
||||
|
||||
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
||||
|
||||
if (Settings::values.dump_shaders) {
|
||||
env.Dump(key.Hash());
|
||||
env.Dump(hash, key.unique_hash);
|
||||
}
|
||||
|
||||
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||
@ -582,13 +584,13 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||
std::string code{};
|
||||
std::vector<u32> code_spirv;
|
||||
switch (device.GetShaderBackend()) {
|
||||
case Settings::ShaderBackend::GLSL:
|
||||
case Settings::ShaderBackend::Glsl:
|
||||
code = EmitGLSL(profile, program);
|
||||
break;
|
||||
case Settings::ShaderBackend::GLASM:
|
||||
case Settings::ShaderBackend::Glasm:
|
||||
code = EmitGLASM(profile, info, program);
|
||||
break;
|
||||
case Settings::ShaderBackend::SPIRV:
|
||||
case Settings::ShaderBackend::SpirV:
|
||||
code_spirv = EmitSPIRV(profile, program);
|
||||
break;
|
||||
}
|
||||
|
@ -232,10 +232,9 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
|
||||
[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
|
||||
const VideoCommon::ImageInfo& info) {
|
||||
if (IsPixelFormatASTC(info.format) && info.size.depth == 1 && !runtime.HasNativeASTC()) {
|
||||
return Settings::values.accelerate_astc.GetValue() &&
|
||||
return Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu &&
|
||||
Settings::values.astc_recompression.GetValue() ==
|
||||
Settings::AstcRecompression::Uncompressed &&
|
||||
!Settings::values.async_astc.GetValue();
|
||||
Settings::AstcRecompression::Uncompressed;
|
||||
}
|
||||
// Disable other accelerated uploads for now as they don't implement swizzled uploads
|
||||
return false;
|
||||
@ -267,7 +266,8 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
|
||||
[[nodiscard]] bool CanBeDecodedAsync(const TextureCacheRuntime& runtime,
|
||||
const VideoCommon::ImageInfo& info) {
|
||||
if (IsPixelFormatASTC(info.format) && !runtime.HasNativeASTC()) {
|
||||
return Settings::values.async_astc.GetValue();
|
||||
return Settings::values.accelerate_astc.GetValue() ==
|
||||
Settings::AstcDecodeMode::CpuAsynchronous;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -473,7 +473,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||
glBindTextureUnit(0, screen_info.display_texture);
|
||||
|
||||
auto anti_aliasing = Settings::values.anti_aliasing.GetValue();
|
||||
if (anti_aliasing > Settings::AntiAliasing::LastAA) {
|
||||
if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) {
|
||||
LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing);
|
||||
anti_aliasing = Settings::AntiAliasing::None;
|
||||
Settings::values.anti_aliasing.SetValue(anti_aliasing);
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "video_core/host_shaders/blit_color_float_frag_spv.h"
|
||||
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
|
||||
@ -19,7 +21,6 @@
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||
#include "video_core/surface.h"
|
||||
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
|
@ -7,11 +7,12 @@
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
||||
|
||||
#include "common/dynamic_library.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_vulkan/vk_blit_screen.h"
|
||||
#include "video_core/renderer_vulkan/vk_present_manager.h"
|
||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||
#include "video_core/renderer_vulkan/vk_swapchain.h"
|
||||
|
@ -7,8 +7,9 @@
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/div_ceil.h"
|
||||
@ -16,7 +18,6 @@
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||
#include "video_core/texture_cache/accelerated_swizzle.h"
|
||||
#include "video_core/texture_cache/types.h"
|
||||
|
@ -7,9 +7,10 @@
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "video_core/renderer_vulkan/pipeline_helper.h"
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_helper.h"
|
||||
#include "video_core/renderer_vulkan/pipeline_statistics.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||
|
@ -584,7 +584,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
ShaderPools& pools, const GraphicsPipelineCacheKey& key,
|
||||
std::span<Shader::Environment* const> envs, PipelineStatistics* statistics,
|
||||
bool build_in_parallel) try {
|
||||
LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash());
|
||||
auto hash = key.Hash();
|
||||
LOG_INFO(Render_Vulkan, "0x{:016x}", hash);
|
||||
size_t env_index{0};
|
||||
std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs;
|
||||
const bool uses_vertex_a{key.unique_hashes[0] != 0};
|
||||
@ -611,7 +612,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))};
|
||||
Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
|
||||
if (Settings::values.dump_shaders) {
|
||||
env.Dump(key.unique_hashes[index]);
|
||||
env.Dump(hash, key.unique_hashes[index]);
|
||||
}
|
||||
if (!uses_vertex_a || index != 1) {
|
||||
// Normal path
|
||||
@ -712,18 +713,19 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env,
|
||||
PipelineStatistics* statistics, bool build_in_parallel) try {
|
||||
auto hash = key.Hash();
|
||||
if (device.HasBrokenCompute()) {
|
||||
LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash());
|
||||
LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", hash);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash());
|
||||
LOG_INFO(Render_Vulkan, "0x{:016x}", hash);
|
||||
|
||||
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
||||
|
||||
// Dump it before error.
|
||||
if (Settings::values.dump_shaders) {
|
||||
env.Dump(key.Hash());
|
||||
env.Dump(hash, key.unique_hash);
|
||||
}
|
||||
|
||||
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
@ -18,7 +20,6 @@
|
||||
#include "video_core/renderer_vulkan/blit_image.h"
|
||||
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
|
@ -7,13 +7,14 @@
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/control/channel_state_cache.h"
|
||||
#include "video_core/engines/maxwell_dma.h"
|
||||
#include "video_core/rasterizer_accelerated.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_vulkan/blit_image.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_fence_manager.h"
|
||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||
|
@ -6,11 +6,12 @@
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_query_cache.h"
|
||||
|
||||
#include "common/microprofile.h"
|
||||
#include "common/thread.h"
|
||||
#include "video_core/renderer_vulkan/vk_command_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
||||
#include "video_core/renderer_vulkan/vk_query_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
|
@ -45,8 +45,8 @@ static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
|
||||
return mode;
|
||||
}
|
||||
switch (mode) {
|
||||
case Settings::VSyncMode::FIFO:
|
||||
case Settings::VSyncMode::FIFORelaxed:
|
||||
case Settings::VSyncMode::Fifo:
|
||||
case Settings::VSyncMode::FifoRelaxed:
|
||||
if (has_mailbox) {
|
||||
return Settings::VSyncMode::Mailbox;
|
||||
} else if (has_imm) {
|
||||
@ -59,8 +59,8 @@ static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
|
||||
}();
|
||||
if ((setting == Settings::VSyncMode::Mailbox && !has_mailbox) ||
|
||||
(setting == Settings::VSyncMode::Immediate && !has_imm) ||
|
||||
(setting == Settings::VSyncMode::FIFORelaxed && !has_fifo_relaxed)) {
|
||||
setting = Settings::VSyncMode::FIFO;
|
||||
(setting == Settings::VSyncMode::FifoRelaxed && !has_fifo_relaxed)) {
|
||||
setting = Settings::VSyncMode::Fifo;
|
||||
}
|
||||
|
||||
switch (setting) {
|
||||
@ -68,9 +68,9 @@ static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
|
||||
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
case Settings::VSyncMode::Mailbox:
|
||||
return VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
case Settings::VSyncMode::FIFO:
|
||||
case Settings::VSyncMode::Fifo:
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
case Settings::VSyncMode::FIFORelaxed:
|
||||
case Settings::VSyncMode::FifoRelaxed:
|
||||
return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
default:
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "common/bit_util.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
|
||||
#include "video_core/engines/fermi_2d.h"
|
||||
#include "video_core/renderer_vulkan/blit_image.h"
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
@ -18,7 +20,6 @@
|
||||
#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
#include "video_core/texture_cache/formatter.h"
|
||||
#include "video_core/texture_cache/samples_helper.h"
|
||||
#include "video_core/texture_cache/util.h"
|
||||
@ -817,7 +818,7 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
||||
: device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_},
|
||||
staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_},
|
||||
render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} {
|
||||
if (Settings::values.accelerate_astc) {
|
||||
if (Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu) {
|
||||
astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
|
||||
compute_pass_descriptor_queue, memory_allocator);
|
||||
}
|
||||
@ -1301,12 +1302,19 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
||||
runtime->ViewFormats(info.format))),
|
||||
aspect_mask(ImageAspectMask(info.format)) {
|
||||
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
|
||||
if (Settings::values.async_astc.GetValue()) {
|
||||
switch (Settings::values.accelerate_astc.GetValue()) {
|
||||
case Settings::AstcDecodeMode::Gpu:
|
||||
if (Settings::values.astc_recompression.GetValue() ==
|
||||
Settings::AstcRecompression::Uncompressed &&
|
||||
info.size.depth == 1) {
|
||||
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||
}
|
||||
break;
|
||||
case Settings::AstcDecodeMode::CpuAsynchronous:
|
||||
flags |= VideoCommon::ImageFlagBits::AsynchronousDecode;
|
||||
} else if (Settings::values.astc_recompression.GetValue() ==
|
||||
Settings::AstcRecompression::Uncompressed &&
|
||||
Settings::values.accelerate_astc.GetValue() && info.size.depth == 1) {
|
||||
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
flags |= VideoCommon::ImageFlagBits::Converted;
|
||||
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
|
||||
|
@ -5,11 +5,12 @@
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "video_core/texture_cache/texture_cache_base.h"
|
||||
|
||||
#include "shader_recompiler/shader_info.h"
|
||||
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
||||
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
||||
#include "video_core/texture_cache/image_view_base.h"
|
||||
#include "video_core/texture_cache/texture_cache_base.h"
|
||||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
|
@ -51,6 +51,11 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) {
|
||||
}
|
||||
const auto& shader_config{maxwell3d->regs.pipelines[index]};
|
||||
const auto program{static_cast<Tegra::Engines::Maxwell3D::Regs::ShaderType>(index)};
|
||||
if (program == Tegra::Engines::Maxwell3D::Regs::ShaderType::Pixel &&
|
||||
!maxwell3d->regs.rasterize_enable) {
|
||||
unique_hashes[index] = 0;
|
||||
continue;
|
||||
}
|
||||
const GPUVAddr shader_addr{base_addr + shader_config.offset};
|
||||
const std::optional<VAddr> cpu_shader_addr{gpu_memory->GpuToCpuAddress(shader_addr)};
|
||||
if (!cpu_shader_addr) {
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
protected:
|
||||
struct GraphicsEnvironments {
|
||||
std::array<GraphicsEnvironment, NUM_PROGRAMS> envs;
|
||||
std::array<Shader::Environment*, NUM_PROGRAMS> env_ptrs;
|
||||
std::array<Shader::Environment*, NUM_PROGRAMS> env_ptrs{};
|
||||
|
||||
std::span<Shader::Environment* const> Span() const noexcept {
|
||||
return std::span(env_ptrs.begin(), std::ranges::find(env_ptrs, nullptr));
|
||||
|
@ -102,7 +102,8 @@ static std::string_view StageToPrefix(Shader::Stage stage) {
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpImpl(u64 hash, const u64* code, u32 read_highest, u32 read_lowest,
|
||||
static void DumpImpl(u64 pipeline_hash, u64 shader_hash, std::span<const u64> code,
|
||||
[[maybe_unused]] u32 read_highest, [[maybe_unused]] u32 read_lowest,
|
||||
u32 initial_offset, Shader::Stage stage) {
|
||||
const auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
|
||||
const auto base_dir{shader_dir / "shaders"};
|
||||
@ -111,13 +112,18 @@ static void DumpImpl(u64 hash, const u64* code, u32 read_highest, u32 read_lowes
|
||||
return;
|
||||
}
|
||||
const auto prefix = StageToPrefix(stage);
|
||||
const auto name{base_dir / fmt::format("{}{:016x}.ash", prefix, hash)};
|
||||
const size_t real_size = read_highest - read_lowest + initial_offset;
|
||||
const size_t padding_needed = ((32 - (real_size % 32)) % 32);
|
||||
const auto name{base_dir /
|
||||
fmt::format("{:016x}_{}_{:016x}.ash", pipeline_hash, prefix, shader_hash)};
|
||||
std::fstream shader_file(name, std::ios::out | std::ios::binary);
|
||||
ASSERT(initial_offset % sizeof(u64) == 0);
|
||||
const size_t jump_index = initial_offset / sizeof(u64);
|
||||
shader_file.write(reinterpret_cast<const char*>(code + jump_index), real_size);
|
||||
for (size_t i = 0; i < padding_needed; i++) {
|
||||
const size_t code_size = code.size_bytes() - initial_offset;
|
||||
shader_file.write(reinterpret_cast<const char*>(&code[jump_index]), code_size);
|
||||
|
||||
// + 1 instruction, due to the fact that we skip the final self branch instruction in the code,
|
||||
// but we need to consider it for padding, otherwise nvdisasm rages.
|
||||
const size_t padding_needed = (32 - ((code_size + INST_SIZE) % 32)) % 32;
|
||||
for (size_t i = 0; i < INST_SIZE + padding_needed; i++) {
|
||||
shader_file.put(0);
|
||||
}
|
||||
}
|
||||
@ -197,8 +203,8 @@ u64 GenericEnvironment::CalculateHash() const {
|
||||
return Common::CityHash64(data.get(), size);
|
||||
}
|
||||
|
||||
void GenericEnvironment::Dump(u64 hash) {
|
||||
DumpImpl(hash, code.data(), read_highest, read_lowest, initial_offset, stage);
|
||||
void GenericEnvironment::Dump(u64 pipeline_hash, u64 shader_hash) {
|
||||
DumpImpl(pipeline_hash, shader_hash, code, read_highest, read_lowest, initial_offset, stage);
|
||||
}
|
||||
|
||||
void GenericEnvironment::Serialize(std::ofstream& file) const {
|
||||
@ -282,6 +288,7 @@ std::optional<u64> GenericEnvironment::TryFindSize() {
|
||||
Tegra::Texture::TICEntry GenericEnvironment::ReadTextureInfo(GPUVAddr tic_addr, u32 tic_limit,
|
||||
bool via_header_index, u32 raw) {
|
||||
const auto handle{Tegra::Texture::TexturePair(raw, via_header_index)};
|
||||
ASSERT(handle.first <= tic_limit);
|
||||
const GPUVAddr descriptor_addr{tic_addr + handle.first * sizeof(Tegra::Texture::TICEntry)};
|
||||
Tegra::Texture::TICEntry entry;
|
||||
gpu_memory->ReadBlock(descriptor_addr, &entry, sizeof(entry));
|
||||
@ -465,8 +472,8 @@ void FileEnvironment::Deserialize(std::ifstream& file) {
|
||||
.read(reinterpret_cast<char*>(&read_highest), sizeof(read_highest))
|
||||
.read(reinterpret_cast<char*>(&viewport_transform_state), sizeof(viewport_transform_state))
|
||||
.read(reinterpret_cast<char*>(&stage), sizeof(stage));
|
||||
code = std::make_unique<u64[]>(Common::DivCeil(code_size, sizeof(u64)));
|
||||
file.read(reinterpret_cast<char*>(code.get()), code_size);
|
||||
code.resize(Common::DivCeil(code_size, sizeof(u64)));
|
||||
file.read(reinterpret_cast<char*>(code.data()), code_size);
|
||||
for (size_t i = 0; i < num_texture_types; ++i) {
|
||||
u32 key;
|
||||
Shader::TextureType type;
|
||||
@ -509,8 +516,8 @@ void FileEnvironment::Deserialize(std::ifstream& file) {
|
||||
is_propietary_driver = texture_bound == 2;
|
||||
}
|
||||
|
||||
void FileEnvironment::Dump(u64 hash) {
|
||||
DumpImpl(hash, code.get(), read_highest, read_lowest, initial_offset, stage);
|
||||
void FileEnvironment::Dump(u64 pipeline_hash, u64 shader_hash) {
|
||||
DumpImpl(pipeline_hash, shader_hash, code, read_highest, read_lowest, initial_offset, stage);
|
||||
}
|
||||
|
||||
u64 FileEnvironment::ReadInstruction(u32 address) {
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
|
||||
[[nodiscard]] u64 CalculateHash() const;
|
||||
|
||||
void Dump(u64 hash) override;
|
||||
void Dump(u64 pipeline_hash, u64 shader_hash) override;
|
||||
|
||||
void Serialize(std::ofstream& file) const;
|
||||
|
||||
@ -188,10 +188,10 @@ public:
|
||||
return cbuf_replacements.size() != 0;
|
||||
}
|
||||
|
||||
void Dump(u64 hash) override;
|
||||
void Dump(u64 pipeline_hash, u64 shader_hash) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<u64[]> code;
|
||||
std::vector<u64> code;
|
||||
std::unordered_map<u32, Shader::TextureType> texture_types;
|
||||
std::unordered_map<u32, Shader::TexturePixelFormat> texture_pixel_formats;
|
||||
std::unordered_map<u64, u32> cbuf_values;
|
||||
|
@ -72,12 +72,12 @@ float TSCEntry::MaxAnisotropy() const noexcept {
|
||||
}
|
||||
const auto anisotropic_settings = Settings::values.max_anisotropy.GetValue();
|
||||
s32 added_anisotropic{};
|
||||
if (anisotropic_settings == 0) {
|
||||
if (anisotropic_settings == Settings::AnisotropyMode::Automatic) {
|
||||
added_anisotropic = Settings::values.resolution_info.up_scale >>
|
||||
Settings::values.resolution_info.down_shift;
|
||||
added_anisotropic = std::max(added_anisotropic - 1, 0);
|
||||
} else {
|
||||
added_anisotropic = Settings::values.max_anisotropy.GetValue() - 1U;
|
||||
added_anisotropic = static_cast<u32>(Settings::values.max_anisotropy.GetValue()) - 1U;
|
||||
}
|
||||
return static_cast<float>(1U << (max_anisotropy + added_anisotropic));
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user