early-access version 1840
This commit is contained in:
parent
755af6b65b
commit
cae72a4c69
71 changed files with 1818 additions and 1257 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 1838.
|
This is the source code for early-access 1840.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ StreamPtr AudioOut::OpenStream(Core::Timing::CoreTiming& core_timing, u32 sample
|
||||||
u32 num_channels, std::string&& name,
|
u32 num_channels, std::string&& name,
|
||||||
Stream::ReleaseCallback&& release_callback) {
|
Stream::ReleaseCallback&& release_callback) {
|
||||||
if (!sink) {
|
if (!sink) {
|
||||||
sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
|
sink = CreateSinkFromID(Settings::values.sink_id.GetValue(),
|
||||||
|
Settings::values.audio_device_id.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<Stream>(
|
return std::make_shared<Stream>(
|
||||||
|
|
|
@ -41,7 +41,7 @@ void LogSettings() {
|
||||||
LOG_INFO(Config, "yuzu Configuration:");
|
LOG_INFO(Config, "yuzu Configuration:");
|
||||||
log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
|
log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
|
||||||
log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
|
log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
|
||||||
log_setting("System_CurrentUser", values.current_user);
|
log_setting("System_CurrentUser", values.current_user.GetValue());
|
||||||
log_setting("System_LanguageIndex", values.language_index.GetValue());
|
log_setting("System_LanguageIndex", values.language_index.GetValue());
|
||||||
log_setting("System_RegionIndex", values.region_index.GetValue());
|
log_setting("System_RegionIndex", values.region_index.GetValue());
|
||||||
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
|
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
|
||||||
|
@ -61,18 +61,18 @@ void LogSettings() {
|
||||||
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
|
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
|
||||||
log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
|
log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
|
||||||
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
|
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
|
||||||
log_setting("Audio_OutputEngine", values.sink_id);
|
log_setting("Audio_OutputEngine", values.sink_id.GetValue());
|
||||||
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
|
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
|
||||||
log_setting("Audio_OutputDevice", values.audio_device_id);
|
log_setting("Audio_OutputDevice", values.audio_device_id.GetValue());
|
||||||
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
|
||||||
log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
|
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_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
|
||||||
log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
|
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_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
|
||||||
log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
|
log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
|
||||||
log_setting("Debugging_ProgramArgs", values.program_args);
|
log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
|
||||||
log_setting("Services_BCATBackend", values.bcat_backend);
|
log_setting("Services_BCATBackend", values.bcat_backend.GetValue());
|
||||||
log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local);
|
log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsConfiguringGlobal() {
|
bool IsConfiguringGlobal() {
|
||||||
|
@ -94,7 +94,7 @@ bool IsGPULevelHigh() {
|
||||||
|
|
||||||
bool IsFastmemEnabled() {
|
bool IsFastmemEnabled() {
|
||||||
if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) {
|
if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) {
|
||||||
return values.cpuopt_fastmem;
|
return static_cast<bool>(values.cpuopt_fastmem);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,12 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/settings_input.h"
|
#include "common/settings_input.h"
|
||||||
|
#include "input_common/udp/client.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
@ -34,68 +36,236 @@ enum class CPUAccuracy : u32 {
|
||||||
DebugMode = 2,
|
DebugMode = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** The BasicSetting 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. Setting a default value and label is required, though subclasses may deviate from
|
||||||
|
* this requirement.
|
||||||
|
*/
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
class Setting final {
|
class BasicSetting {
|
||||||
|
protected:
|
||||||
|
BasicSetting() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 BasicSetting(const Type& global_val) : global{global_val} {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Setting() = default;
|
/**
|
||||||
explicit Setting(Type val) : global{val} {}
|
* Sets a default value, label, and setting value.
|
||||||
~Setting() = default;
|
*
|
||||||
void SetGlobal(bool to_global) {
|
* @param default_val Intial value of the setting, and default value of the setting
|
||||||
use_global = to_global;
|
* @param name Label for the setting
|
||||||
}
|
*/
|
||||||
bool UsingGlobal() const {
|
explicit BasicSetting(const Type& default_val, const std::string& name)
|
||||||
return use_global;
|
: default_value{default_val}, global{default_val}, label{name} {}
|
||||||
}
|
~BasicSetting() = default;
|
||||||
Type GetValue(bool need_global = false) const {
|
|
||||||
if (use_global || need_global) {
|
/**
|
||||||
|
* Returns a reference to the setting's value.
|
||||||
|
*
|
||||||
|
* @returns A reference to the setting
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const Type& GetValue() const {
|
||||||
return global;
|
return global;
|
||||||
}
|
}
|
||||||
return local;
|
|
||||||
}
|
/**
|
||||||
|
* Sets the setting to the given value.
|
||||||
|
*
|
||||||
|
* @param value The desired value
|
||||||
|
*/
|
||||||
void SetValue(const Type& value) {
|
void SetValue(const Type& value) {
|
||||||
if (use_global) {
|
Type temp{value};
|
||||||
global = value;
|
std::swap(global, temp);
|
||||||
} else {
|
|
||||||
local = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/**
|
||||||
bool use_global = true;
|
* Returns the value that this setting was created with.
|
||||||
Type global{};
|
*
|
||||||
Type local{};
|
* @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 value The desired setting value
|
||||||
|
*
|
||||||
|
* @returns A reference to the setting
|
||||||
|
*/
|
||||||
|
const Type& operator=(const Type& value) {
|
||||||
|
Type temp{value};
|
||||||
|
std::swap(global, temp);
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the setting.
|
||||||
|
*
|
||||||
|
* @returns A reference to the setting
|
||||||
|
*/
|
||||||
|
explicit operator const Type&() const {
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const Type default_value{}; ///< The default value
|
||||||
|
Type global{}; ///< The setting
|
||||||
|
const std::string label{}; ///< The setting's label
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The InputSetting class allows for getting a reference to either the global or local members.
|
* The Setting class is a slightly more complex version of the BasicSetting 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.
|
||||||
|
*
|
||||||
|
* Like the BasicSetting, this requires setting a default value and label to use.
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
class Setting final : public BasicSetting<Type> {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Sets a default value, label, and setting value.
|
||||||
|
*
|
||||||
|
* @param default_val Intial 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)
|
||||||
|
: BasicSetting<Type>(default_val, name) {}
|
||||||
|
~Setting() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells this setting to represent either the global or custom setting when other member
|
||||||
|
* functions are used. Setting to_global to true means using the global setting, to false
|
||||||
|
* false for the custom setting.
|
||||||
|
*
|
||||||
|
* @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]] const Type& GetValue(bool need_global = false) const {
|
||||||
|
if (use_global || need_global) {
|
||||||
|
return this->global;
|
||||||
|
}
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current setting value depending on the global state.
|
||||||
|
*
|
||||||
|
* @param value The new value
|
||||||
|
*/
|
||||||
|
void SetValue(const Type& value) {
|
||||||
|
Type temp{value};
|
||||||
|
if (use_global) {
|
||||||
|
std::swap(this->global, temp);
|
||||||
|
} else {
|
||||||
|
std::swap(custom, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns the current setting value depending on the global state.
|
||||||
|
*
|
||||||
|
* @param value The new value
|
||||||
|
*
|
||||||
|
* @returns A reference to the current setting value
|
||||||
|
*/
|
||||||
|
const Type& operator=(const Type& value) {
|
||||||
|
Type temp{value};
|
||||||
|
if (use_global) {
|
||||||
|
std::swap(this->global, temp);
|
||||||
|
return this->global;
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
if (use_global) {
|
||||||
|
return this->global;
|
||||||
|
}
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool use_global{true}; ///< The setting's global state
|
||||||
|
Type custom{}; ///< The custom value of the setting
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The InputSetting class allows for getting a reference to either the global or custom members.
|
||||||
* This is required as we cannot easily modify the values of user-defined types within containers
|
* This is required as we cannot easily modify the values of user-defined types within containers
|
||||||
* using the SetValue() member function found in the Setting class. The primary purpose of this
|
* using the SetValue() member function found in the Setting class. The primary purpose of this
|
||||||
* class is to store an array of 10 PlayerInput structs for both the global and local (per-game)
|
* class is to store an array of 10 PlayerInput structs for both the global and custom setting and
|
||||||
* setting and allows for easily accessing and modifying both settings.
|
* allows for easily accessing and modifying both settings.
|
||||||
*/
|
*/
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
class InputSetting final {
|
class InputSetting final {
|
||||||
public:
|
public:
|
||||||
InputSetting() = default;
|
InputSetting() = default;
|
||||||
explicit InputSetting(Type val) : global{val} {}
|
explicit InputSetting(Type val) : BasicSetting<Type>(val) {}
|
||||||
~InputSetting() = default;
|
~InputSetting() = default;
|
||||||
void SetGlobal(bool to_global) {
|
void SetGlobal(bool to_global) {
|
||||||
use_global = to_global;
|
use_global = to_global;
|
||||||
}
|
}
|
||||||
bool UsingGlobal() const {
|
[[nodiscard]] bool UsingGlobal() const {
|
||||||
return use_global;
|
return use_global;
|
||||||
}
|
}
|
||||||
Type& GetValue(bool need_global = false) {
|
[[nodiscard]] Type& GetValue(bool need_global = false) {
|
||||||
if (use_global || need_global) {
|
if (use_global || need_global) {
|
||||||
return global;
|
return global;
|
||||||
}
|
}
|
||||||
return local;
|
return custom;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool use_global = true;
|
bool use_global{true}; ///< The setting's global state
|
||||||
Type global{};
|
Type global{}; ///< The setting
|
||||||
Type local{};
|
Type custom{}; ///< The custom setting value
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TouchFromButtonMap {
|
struct TouchFromButtonMap {
|
||||||
|
@ -105,144 +275,155 @@ struct TouchFromButtonMap {
|
||||||
|
|
||||||
struct Values {
|
struct Values {
|
||||||
// Audio
|
// Audio
|
||||||
std::string audio_device_id;
|
BasicSetting<std::string> audio_device_id{"auto", "output_device"};
|
||||||
std::string sink_id;
|
BasicSetting<std::string> sink_id{"auto", "output_engine"};
|
||||||
bool audio_muted;
|
BasicSetting<bool> audio_muted{false, "audio_muted"};
|
||||||
Setting<bool> enable_audio_stretching;
|
Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
|
||||||
Setting<float> volume;
|
Setting<float> volume{1.0f, "volume"};
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
Setting<bool> use_multi_core;
|
Setting<bool> use_multi_core{true, "use_multi_core"};
|
||||||
|
|
||||||
// Cpu
|
// Cpu
|
||||||
Setting<CPUAccuracy> cpu_accuracy;
|
Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Accurate, "cpu_accuracy"};
|
||||||
|
|
||||||
bool cpuopt_page_tables;
|
BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
|
||||||
bool cpuopt_block_linking;
|
BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
|
||||||
bool cpuopt_return_stack_buffer;
|
BasicSetting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
|
||||||
bool cpuopt_fast_dispatcher;
|
BasicSetting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
|
||||||
bool cpuopt_context_elimination;
|
BasicSetting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
|
||||||
bool cpuopt_const_prop;
|
BasicSetting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
|
||||||
bool cpuopt_misc_ir;
|
BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
|
||||||
bool cpuopt_reduce_misalign_checks;
|
BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
|
||||||
bool cpuopt_fastmem;
|
BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
|
||||||
|
|
||||||
Setting<bool> cpuopt_unsafe_unfuse_fma;
|
Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
|
||||||
Setting<bool> cpuopt_unsafe_reduce_fp_error;
|
Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
|
||||||
Setting<bool> cpuopt_unsafe_ignore_standard_fpcr;
|
Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
|
||||||
Setting<bool> cpuopt_unsafe_inaccurate_nan;
|
Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
|
||||||
Setting<bool> cpuopt_unsafe_fastmem_check;
|
Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
Setting<RendererBackend> renderer_backend;
|
Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
|
||||||
bool renderer_debug;
|
BasicSetting<bool> renderer_debug{false, "debug"};
|
||||||
Setting<int> vulkan_device;
|
Setting<int> vulkan_device{0, "vulkan_device"};
|
||||||
|
|
||||||
Setting<u16> resolution_factor{1};
|
Setting<u16> resolution_factor{1, "resolution_factor"};
|
||||||
Setting<int> fullscreen_mode;
|
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||||
Setting<int> aspect_ratio;
|
// Default to exclusive fullscreen on these platforms for now.
|
||||||
Setting<int> max_anisotropy;
|
Setting<int> fullscreen_mode{
|
||||||
Setting<bool> use_frame_limit;
|
#ifdef _WIN32
|
||||||
Setting<u16> frame_limit;
|
0,
|
||||||
Setting<bool> use_disk_shader_cache;
|
#else
|
||||||
Setting<GPUAccuracy> gpu_accuracy;
|
1,
|
||||||
Setting<bool> use_asynchronous_gpu_emulation;
|
#endif
|
||||||
Setting<bool> use_nvdec_emulation;
|
"fullscreen_mode"};
|
||||||
Setting<bool> accelerate_astc;
|
Setting<int> aspect_ratio{0, "aspect_ratio"};
|
||||||
Setting<bool> use_vsync;
|
Setting<int> max_anisotropy{0, "max_anisotropy"};
|
||||||
Setting<bool> disable_fps_limit;
|
Setting<bool> use_frame_limit{true, "use_frame_limit"};
|
||||||
Setting<bool> use_assembly_shaders;
|
Setting<u16> frame_limit{100, "frame_limit"};
|
||||||
Setting<bool> use_asynchronous_shaders;
|
Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
||||||
Setting<bool> use_fast_gpu_time;
|
Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
|
||||||
Setting<bool> use_caches_gc;
|
Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
|
||||||
|
Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
|
||||||
|
Setting<bool> accelerate_astc{true, "accelerate_astc"};
|
||||||
|
Setting<bool> use_vsync{true, "use_vsync"};
|
||||||
|
Setting<bool> disable_fps_limit{false, "disable_fps_limit"};
|
||||||
|
Setting<bool> use_assembly_shaders{false, "use_assembly_shaders"};
|
||||||
|
Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
|
||||||
|
Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
|
||||||
|
Setting<bool> use_caches_gc{false, "use_caches_gc"};
|
||||||
|
|
||||||
Setting<float> bg_red;
|
Setting<float> bg_red{0.0f, "bg_red"};
|
||||||
Setting<float> bg_green;
|
Setting<float> bg_green{0.0f, "bg_green"};
|
||||||
Setting<float> bg_blue;
|
Setting<float> bg_blue{0.0f, "bg_blue"};
|
||||||
|
|
||||||
// System
|
// System
|
||||||
Setting<std::optional<u32>> rng_seed;
|
Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
|
||||||
// Measured in seconds since epoch
|
// Measured in seconds since epoch
|
||||||
std::optional<std::chrono::seconds> custom_rtc;
|
std::optional<std::chrono::seconds> custom_rtc;
|
||||||
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
||||||
std::chrono::seconds custom_rtc_differential;
|
std::chrono::seconds custom_rtc_differential;
|
||||||
|
|
||||||
s32 current_user;
|
BasicSetting<s32> current_user{0, "current_user"};
|
||||||
Setting<s32> language_index;
|
Setting<s32> language_index{1, "language_index"};
|
||||||
Setting<s32> region_index;
|
Setting<s32> region_index{1, "region_index"};
|
||||||
Setting<s32> time_zone_index;
|
Setting<s32> time_zone_index{0, "time_zone_index"};
|
||||||
Setting<s32> sound_index;
|
Setting<s32> sound_index{1, "sound_index"};
|
||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
InputSetting<std::array<PlayerInput, 10>> players;
|
InputSetting<std::array<PlayerInput, 10>> players;
|
||||||
|
|
||||||
Setting<bool> use_docked_mode;
|
Setting<bool> use_docked_mode{true, "use_docked_mode"};
|
||||||
|
|
||||||
Setting<bool> vibration_enabled;
|
Setting<bool> vibration_enabled{true, "vibration_enabled"};
|
||||||
Setting<bool> enable_accurate_vibrations;
|
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
|
||||||
|
|
||||||
Setting<bool> motion_enabled;
|
Setting<bool> motion_enabled{true, "motion_enabled"};
|
||||||
std::string motion_device;
|
BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01",
|
||||||
std::string udp_input_servers;
|
"motion_device"};
|
||||||
|
BasicSetting<std::string> udp_input_servers{InputCommon::CemuhookUDP::DEFAULT_SRV,
|
||||||
|
"udp_input_servers"};
|
||||||
|
|
||||||
bool mouse_panning;
|
BasicSetting<bool> mouse_panning{false, "mouse_panning"};
|
||||||
float mouse_panning_sensitivity;
|
BasicSetting<float> mouse_panning_sensitivity{1.0f, "mouse_panning_sensitivity"};
|
||||||
bool mouse_enabled;
|
BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
|
||||||
std::string mouse_device;
|
std::string mouse_device;
|
||||||
MouseButtonsRaw mouse_buttons;
|
MouseButtonsRaw mouse_buttons;
|
||||||
|
|
||||||
bool emulate_analog_keyboard;
|
BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
|
||||||
bool keyboard_enabled;
|
BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
|
||||||
KeyboardKeysRaw keyboard_keys;
|
KeyboardKeysRaw keyboard_keys;
|
||||||
KeyboardModsRaw keyboard_mods;
|
KeyboardModsRaw keyboard_mods;
|
||||||
|
|
||||||
bool debug_pad_enabled;
|
BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
|
||||||
ButtonsRaw debug_pad_buttons;
|
ButtonsRaw debug_pad_buttons;
|
||||||
AnalogsRaw debug_pad_analogs;
|
AnalogsRaw debug_pad_analogs;
|
||||||
|
|
||||||
TouchscreenInput touchscreen;
|
TouchscreenInput touchscreen;
|
||||||
|
|
||||||
bool use_touch_from_button;
|
BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};
|
||||||
std::string touch_device;
|
BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
|
||||||
int touch_from_button_map_index;
|
"touch_device"};
|
||||||
|
BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
|
||||||
std::vector<TouchFromButtonMap> touch_from_button_maps;
|
std::vector<TouchFromButtonMap> touch_from_button_maps;
|
||||||
|
|
||||||
std::atomic_bool is_device_reload_pending{true};
|
std::atomic_bool is_device_reload_pending{true};
|
||||||
|
|
||||||
// Data Storage
|
// Data Storage
|
||||||
bool use_virtual_sd;
|
BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
|
||||||
bool gamecard_inserted;
|
BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};
|
||||||
bool gamecard_current_game;
|
BasicSetting<bool> gamecard_current_game{false, "gamecard_current_game"};
|
||||||
std::string gamecard_path;
|
BasicSetting<std::string> gamecard_path{std::string(), "gamecard_path"};
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
bool record_frame_times;
|
bool record_frame_times;
|
||||||
bool use_gdbstub;
|
BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
|
||||||
u16 gdbstub_port;
|
BasicSetting<u16> gdbstub_port{0, "gdbstub_port"};
|
||||||
std::string program_args;
|
BasicSetting<std::string> program_args{std::string(), "program_args"};
|
||||||
bool dump_exefs;
|
BasicSetting<bool> dump_exefs{false, "dump_exefs"};
|
||||||
bool dump_nso;
|
BasicSetting<bool> dump_nso{false, "dump_nso"};
|
||||||
bool enable_fs_access_log;
|
BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
|
||||||
bool reporting_services;
|
BasicSetting<bool> reporting_services{false, "reporting_services"};
|
||||||
bool quest_flag;
|
BasicSetting<bool> quest_flag{false, "quest_flag"};
|
||||||
bool disable_macro_jit;
|
BasicSetting<bool> disable_macro_jit{false, "disable_macro_jit"};
|
||||||
bool extended_logging;
|
BasicSetting<bool> extended_logging{false, "extended_logging"};
|
||||||
bool use_debug_asserts;
|
BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
|
||||||
bool use_auto_stub;
|
BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
std::string log_filter;
|
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
|
||||||
bool use_dev_keys;
|
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
std::string bcat_backend;
|
BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
|
||||||
bool bcat_boxcat_local;
|
BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
|
||||||
|
|
||||||
// WebService
|
// WebService
|
||||||
bool enable_telemetry;
|
BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
|
||||||
std::string web_api_url;
|
BasicSetting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
|
||||||
std::string yuzu_username;
|
BasicSetting<std::string> yuzu_username{std::string(), "yuzu_username"};
|
||||||
std::string yuzu_token;
|
BasicSetting<std::string> yuzu_token{std::string(), "yuzu_token"};
|
||||||
|
|
||||||
// Add-Ons
|
// Add-Ons
|
||||||
std::map<u64, std::vector<std::string>> disabled_addons;
|
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||||
|
|
|
@ -517,6 +517,8 @@ add_library(core STATIC
|
||||||
hle/service/psc/psc.h
|
hle/service/psc/psc.h
|
||||||
hle/service/ptm/psm.cpp
|
hle/service/ptm/psm.cpp
|
||||||
hle/service/ptm/psm.h
|
hle/service/ptm/psm.h
|
||||||
|
hle/service/kernel_helpers.cpp
|
||||||
|
hle/service/kernel_helpers.h
|
||||||
hle/service/service.cpp
|
hle/service/service.cpp
|
||||||
hle/service/service.h
|
hle/service/service.h
|
||||||
hle/service/set/set.cpp
|
hle/service/set/set.cpp
|
||||||
|
|
|
@ -263,9 +263,9 @@ struct System::Impl {
|
||||||
if (Settings::values.gamecard_inserted) {
|
if (Settings::values.gamecard_inserted) {
|
||||||
if (Settings::values.gamecard_current_game) {
|
if (Settings::values.gamecard_current_game) {
|
||||||
fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
|
fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
|
||||||
} else if (!Settings::values.gamecard_path.empty()) {
|
} else if (!Settings::values.gamecard_path.GetValue().empty()) {
|
||||||
fs_controller.SetGameCard(
|
fs_controller.SetGameCard(GetGameFileFromPath(
|
||||||
GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
|
virtual_filesystem, static_cast<std::string>(Settings::values.gamecard_path)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ ProfileSelectApplet::~ProfileSelectApplet() = default;
|
||||||
void DefaultProfileSelectApplet::SelectProfile(
|
void DefaultProfileSelectApplet::SelectProfile(
|
||||||
std::function<void(std::optional<Common::UUID>)> callback) const {
|
std::function<void(std::optional<Common::UUID>)> callback) const {
|
||||||
Service::Account::ProfileManager manager;
|
Service::Account::ProfileManager manager;
|
||||||
callback(manager.GetUser(Settings::values.current_user).value_or(Common::UUID{}));
|
callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
|
||||||
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
|
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,9 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co
|
||||||
|
|
||||||
void SessionRequestHandler::ClientConnected(KServerSession* session) {
|
void SessionRequestHandler::ClientConnected(KServerSession* session) {
|
||||||
session->ClientConnected(shared_from_this());
|
session->ClientConnected(shared_from_this());
|
||||||
|
|
||||||
|
// Ensure our server session is tracked globally.
|
||||||
|
kernel.RegisterServerSession(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
|
void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "core/hle/kernel/k_auto_object.h"
|
#include "core/hle/kernel/k_auto_object.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -11,4 +12,12 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KAutoObject::RegisterWithKernel() {
|
||||||
|
kernel.RegisterKernelObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KAutoObject::UnregisterWithKernel() {
|
||||||
|
kernel.UnregisterKernelObject(this);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -85,8 +85,12 @@ private:
|
||||||
KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
|
KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {}
|
explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {
|
||||||
virtual ~KAutoObject() = default;
|
RegisterWithKernel();
|
||||||
|
}
|
||||||
|
virtual ~KAutoObject() {
|
||||||
|
UnregisterWithKernel();
|
||||||
|
}
|
||||||
|
|
||||||
static KAutoObject* Create(KAutoObject* ptr);
|
static KAutoObject* Create(KAutoObject* ptr);
|
||||||
|
|
||||||
|
@ -166,6 +170,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RegisterWithKernel();
|
||||||
|
void UnregisterWithKernel();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
KernelCore& kernel;
|
KernelCore& kernel;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/device_memory.h"
|
#include "core/device_memory.h"
|
||||||
|
@ -43,6 +44,8 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority
|
||||||
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
|
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
|
||||||
|
|
||||||
KThread* thread = KThread::Create(system.Kernel());
|
KThread* thread = KThread::Create(system.Kernel());
|
||||||
|
SCOPE_EXIT({ thread->Close(); });
|
||||||
|
|
||||||
ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
|
ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
|
||||||
owner_process.GetIdealCoreId(), &owner_process)
|
owner_process.GetIdealCoreId(), &owner_process)
|
||||||
.IsSuccess());
|
.IsSuccess());
|
||||||
|
@ -162,7 +165,7 @@ void KProcess::DecrementThreadCount() {
|
||||||
ASSERT(num_threads > 0);
|
ASSERT(num_threads > 0);
|
||||||
|
|
||||||
if (const auto count = --num_threads; count == 0) {
|
if (const auto count = --num_threads; count == 0) {
|
||||||
UNIMPLEMENTED_MSG("Process termination is not implemented!");
|
LOG_WARNING(Kernel, "Process termination is not fully implemented.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,6 +409,9 @@ void KProcess::Finalize() {
|
||||||
resource_limit->Close();
|
resource_limit->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finalize the handle table and close any open handles.
|
||||||
|
handle_table.Finalize();
|
||||||
|
|
||||||
// Perform inherited finalization.
|
// Perform inherited finalization.
|
||||||
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
|
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,10 @@ namespace Kernel {
|
||||||
|
|
||||||
KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
|
KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
|
||||||
|
|
||||||
KServerSession::~KServerSession() {}
|
KServerSession::~KServerSession() {
|
||||||
|
// Ensure that the global list tracking server sessions does not hold on to a reference.
|
||||||
|
kernel.UnregisterServerSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
|
void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
|
||||||
std::shared_ptr<SessionRequestManager> manager_) {
|
std::shared_ptr<SessionRequestManager> manager_) {
|
||||||
|
|
|
@ -61,6 +61,7 @@ struct KernelCore::Impl {
|
||||||
void Initialize(KernelCore& kernel) {
|
void Initialize(KernelCore& kernel) {
|
||||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||||
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
|
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
|
||||||
|
global_handle_table->Initialize(KHandleTable::MaxTableSize);
|
||||||
|
|
||||||
is_phantom_mode_for_singlecore = false;
|
is_phantom_mode_for_singlecore = false;
|
||||||
|
|
||||||
|
@ -90,9 +91,39 @@ struct KernelCore::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
|
// Shutdown all processes.
|
||||||
|
if (current_process) {
|
||||||
|
current_process->Finalize();
|
||||||
|
current_process->Close();
|
||||||
|
current_process = nullptr;
|
||||||
|
}
|
||||||
process_list.clear();
|
process_list.clear();
|
||||||
|
|
||||||
// Ensures all service threads gracefully shutdown
|
// Close all open server ports.
|
||||||
|
std::unordered_set<KServerPort*> server_ports_;
|
||||||
|
{
|
||||||
|
std::lock_guard lk(server_ports_lock);
|
||||||
|
server_ports_ = server_ports;
|
||||||
|
server_ports.clear();
|
||||||
|
}
|
||||||
|
for (auto* server_port : server_ports_) {
|
||||||
|
server_port->Close();
|
||||||
|
}
|
||||||
|
// Close all open server sessions.
|
||||||
|
std::unordered_set<KServerSession*> server_sessions_;
|
||||||
|
{
|
||||||
|
std::lock_guard lk(server_sessions_lock);
|
||||||
|
server_sessions_ = server_sessions;
|
||||||
|
server_sessions.clear();
|
||||||
|
}
|
||||||
|
for (auto* server_session : server_sessions_) {
|
||||||
|
server_session->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the object list container is finalized and properly shutdown.
|
||||||
|
object_list_container.Finalize();
|
||||||
|
|
||||||
|
// Ensures all service threads gracefully shutdown.
|
||||||
service_threads.clear();
|
service_threads.clear();
|
||||||
|
|
||||||
next_object_id = 0;
|
next_object_id = 0;
|
||||||
|
@ -111,11 +142,7 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
cores.clear();
|
cores.clear();
|
||||||
|
|
||||||
if (current_process) {
|
global_handle_table->Finalize();
|
||||||
current_process->Close();
|
|
||||||
current_process = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
global_handle_table.reset();
|
global_handle_table.reset();
|
||||||
|
|
||||||
preemption_event = nullptr;
|
preemption_event = nullptr;
|
||||||
|
@ -142,6 +169,16 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
||||||
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
|
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
|
||||||
|
|
||||||
|
// Track kernel objects that were not freed on shutdown
|
||||||
|
{
|
||||||
|
std::lock_guard lk(registered_objects_lock);
|
||||||
|
if (registered_objects.size()) {
|
||||||
|
LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!",
|
||||||
|
registered_objects.size());
|
||||||
|
registered_objects.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializePhysicalCores() {
|
void InitializePhysicalCores() {
|
||||||
|
@ -630,6 +667,21 @@ struct KernelCore::Impl {
|
||||||
user_slab_heap_size);
|
user_slab_heap_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KClientPort* CreateNamedServicePort(std::string name) {
|
||||||
|
auto search = service_interface_factory.find(name);
|
||||||
|
if (search == service_interface_factory.end()) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
KClientPort* port = &search->second(system.ServiceManager(), system);
|
||||||
|
{
|
||||||
|
std::lock_guard lk(server_ports_lock);
|
||||||
|
server_ports.insert(&port->GetParent()->GetServerPort());
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
std::atomic<u32> next_object_id{0};
|
std::atomic<u32> next_object_id{0};
|
||||||
std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
|
std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
|
||||||
std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin};
|
std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin};
|
||||||
|
@ -656,6 +708,12 @@ struct KernelCore::Impl {
|
||||||
/// the ConnectToPort SVC.
|
/// the ConnectToPort SVC.
|
||||||
std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
|
std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
|
||||||
NamedPortTable named_ports;
|
NamedPortTable named_ports;
|
||||||
|
std::unordered_set<KServerPort*> server_ports;
|
||||||
|
std::unordered_set<KServerSession*> server_sessions;
|
||||||
|
std::unordered_set<KAutoObject*> registered_objects;
|
||||||
|
std::mutex server_ports_lock;
|
||||||
|
std::mutex server_sessions_lock;
|
||||||
|
std::mutex registered_objects_lock;
|
||||||
|
|
||||||
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
||||||
std::vector<Kernel::PhysicalCore> cores;
|
std::vector<Kernel::PhysicalCore> cores;
|
||||||
|
@ -844,12 +902,27 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&
|
||||||
}
|
}
|
||||||
|
|
||||||
KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
|
KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
|
||||||
auto search = impl->service_interface_factory.find(name);
|
return impl->CreateNamedServicePort(std::move(name));
|
||||||
if (search == impl->service_interface_factory.end()) {
|
}
|
||||||
UNIMPLEMENTED();
|
|
||||||
return {};
|
void KernelCore::RegisterServerSession(KServerSession* server_session) {
|
||||||
}
|
std::lock_guard lk(impl->server_sessions_lock);
|
||||||
return &search->second(impl->system.ServiceManager(), impl->system);
|
impl->server_sessions.insert(server_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::UnregisterServerSession(KServerSession* server_session) {
|
||||||
|
std::lock_guard lk(impl->server_sessions_lock);
|
||||||
|
impl->server_sessions.erase(server_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::RegisterKernelObject(KAutoObject* object) {
|
||||||
|
std::lock_guard lk(impl->registered_objects_lock);
|
||||||
|
impl->registered_objects.insert(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::UnregisterKernelObject(KAutoObject* object) {
|
||||||
|
std::lock_guard lk(impl->registered_objects_lock);
|
||||||
|
impl->registered_objects.erase(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
|
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
|
||||||
|
|
|
@ -45,6 +45,7 @@ class KPort;
|
||||||
class KProcess;
|
class KProcess;
|
||||||
class KResourceLimit;
|
class KResourceLimit;
|
||||||
class KScheduler;
|
class KScheduler;
|
||||||
|
class KServerSession;
|
||||||
class KSession;
|
class KSession;
|
||||||
class KSharedMemory;
|
class KSharedMemory;
|
||||||
class KThread;
|
class KThread;
|
||||||
|
@ -185,6 +186,22 @@ public:
|
||||||
/// Opens a port to a service previously registered with RegisterNamedService.
|
/// Opens a port to a service previously registered with RegisterNamedService.
|
||||||
KClientPort* CreateNamedServicePort(std::string name);
|
KClientPort* CreateNamedServicePort(std::string name);
|
||||||
|
|
||||||
|
/// Registers a server session with the gobal emulation state, to be freed on shutdown. This is
|
||||||
|
/// necessary because we do not emulate processes for HLE sessions.
|
||||||
|
void RegisterServerSession(KServerSession* server_session);
|
||||||
|
|
||||||
|
/// Unregisters a server session previously registered with RegisterServerSession when it was
|
||||||
|
/// destroyed during the current emulation session.
|
||||||
|
void UnregisterServerSession(KServerSession* server_session);
|
||||||
|
|
||||||
|
/// Registers all kernel objects with the global emulation state, this is purely for tracking
|
||||||
|
/// leaks after emulation has been shutdown.
|
||||||
|
void RegisterKernelObject(KAutoObject* object);
|
||||||
|
|
||||||
|
/// Unregisters a kernel object previously registered with RegisterKernelObject when it was
|
||||||
|
/// destroyed during the current emulation session.
|
||||||
|
void UnregisterKernelObject(KAutoObject* object);
|
||||||
|
|
||||||
/// Determines whether or not the given port is a valid named port.
|
/// Determines whether or not the given port is a valid named port.
|
||||||
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
|
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
|
||||||
|
|
||||||
|
|
|
@ -298,6 +298,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr po
|
||||||
// Create a session.
|
// Create a session.
|
||||||
KClientSession* session{};
|
KClientSession* session{};
|
||||||
R_TRY(port->CreateSession(std::addressof(session)));
|
R_TRY(port->CreateSession(std::addressof(session)));
|
||||||
|
port->Close();
|
||||||
|
|
||||||
// Register the session in the table, close the extra reference.
|
// Register the session in the table, close the extra reference.
|
||||||
handle_table.Register(*out, session);
|
handle_table.Register(*out, session);
|
||||||
|
|
|
@ -48,7 +48,8 @@ ProfileManager::ProfileManager() {
|
||||||
CreateNewUser(UUID::Generate(), "yuzu");
|
CreateNewUser(UUID::Generate(), "yuzu");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1);
|
auto current =
|
||||||
|
std::clamp<int>(static_cast<s32>(Settings::values.current_user), 0, MAX_USERS - 1);
|
||||||
|
|
||||||
// If user index don't exist. Load the first user and change the active user
|
// If user index don't exist. Load the first user and change the active user
|
||||||
if (!UserExistsIndex(current)) {
|
if (!UserExistsIndex(current)) {
|
||||||
|
|
|
@ -1443,7 +1443,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
|
||||||
params.is_account_selected = 1;
|
params.is_account_selected = 1;
|
||||||
|
|
||||||
Account::ProfileManager profile_manager{};
|
Account::ProfileManager profile_manager{};
|
||||||
const auto uuid = profile_manager.GetUser(Settings::values.current_user);
|
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
|
||||||
ASSERT(uuid);
|
ASSERT(uuid);
|
||||||
params.current_user = uuid->uuid;
|
params.current_user = uuid->uuid;
|
||||||
|
|
||||||
|
|
|
@ -579,7 +579,7 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
|
||||||
std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
|
std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
|
||||||
DirectoryGetter getter) {
|
DirectoryGetter getter) {
|
||||||
#ifdef YUZU_ENABLE_BOXCAT
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
if (Settings::values.bcat_backend == "boxcat") {
|
if (Settings::values.bcat_backend.GetValue() == "boxcat") {
|
||||||
return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
|
return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "core/hle/kernel/k_writable_event.h"
|
#include "core/hle/kernel/k_writable_event.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
#include "core/hle/service/hid/controllers/npad.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
|
||||||
|
@ -147,7 +148,9 @@ bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
|
||||||
device_handle.device_index < DeviceIndex::MaxDeviceIndex;
|
device_handle.device_index < DeviceIndex::MaxDeviceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller_NPad::Controller_NPad(Core::System& system_) : ControllerBase{system_} {
|
Controller_NPad::Controller_NPad(Core::System& system_,
|
||||||
|
KernelHelpers::ServiceContext& service_context_)
|
||||||
|
: ControllerBase{system_}, service_context{service_context_} {
|
||||||
latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
|
latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,8 +256,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
|
||||||
void Controller_NPad::OnInit() {
|
void Controller_NPad::OnInit() {
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
|
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
|
||||||
styleset_changed_events[i] = Kernel::KEvent::Create(kernel);
|
styleset_changed_events[i] =
|
||||||
styleset_changed_events[i]->Initialize(fmt::format("npad:NpadStyleSetChanged_{}", i));
|
service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsControllerActivated()) {
|
if (!IsControllerActivated()) {
|
||||||
|
@ -344,8 +347,7 @@ void Controller_NPad::OnRelease() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
|
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
|
||||||
styleset_changed_events[i]->Close();
|
service_context.CloseEvent(styleset_changed_events[i]);
|
||||||
styleset_changed_events[i] = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,10 @@ class KEvent;
|
||||||
class KReadableEvent;
|
class KReadableEvent;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
namespace Service::KernelHelpers {
|
||||||
|
class ServiceContext;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
|
|
||||||
constexpr u32 NPAD_HANDHELD = 32;
|
constexpr u32 NPAD_HANDHELD = 32;
|
||||||
|
@ -27,7 +31,8 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
|
||||||
|
|
||||||
class Controller_NPad final : public ControllerBase {
|
class Controller_NPad final : public ControllerBase {
|
||||||
public:
|
public:
|
||||||
explicit Controller_NPad(Core::System& system_);
|
explicit Controller_NPad(Core::System& system_,
|
||||||
|
KernelHelpers::ServiceContext& service_context_);
|
||||||
~Controller_NPad() override;
|
~Controller_NPad() override;
|
||||||
|
|
||||||
// Called when the controller is initialized
|
// Called when the controller is initialized
|
||||||
|
@ -566,6 +571,7 @@ private:
|
||||||
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
|
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
|
||||||
10>;
|
10>;
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext& service_context;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
ButtonArray buttons;
|
ButtonArray buttons;
|
||||||
StickArray sticks;
|
StickArray sticks;
|
||||||
|
|
|
@ -46,8 +46,9 @@ constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; //
|
||||||
constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
|
constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
|
||||||
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
|
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
|
||||||
|
|
||||||
IAppletResource::IAppletResource(Core::System& system_)
|
IAppletResource::IAppletResource(Core::System& system_,
|
||||||
: ServiceFramework{system_, "IAppletResource"} {
|
KernelHelpers::ServiceContext& service_context_)
|
||||||
|
: ServiceFramework{system_, "IAppletResource"}, service_context{service_context_} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
||||||
};
|
};
|
||||||
|
@ -63,7 +64,7 @@ IAppletResource::IAppletResource(Core::System& system_)
|
||||||
MakeController<Controller_Stubbed>(HidController::CaptureButton);
|
MakeController<Controller_Stubbed>(HidController::CaptureButton);
|
||||||
MakeController<Controller_Stubbed>(HidController::InputDetector);
|
MakeController<Controller_Stubbed>(HidController::InputDetector);
|
||||||
MakeController<Controller_Stubbed>(HidController::UniquePad);
|
MakeController<Controller_Stubbed>(HidController::UniquePad);
|
||||||
MakeController<Controller_NPad>(HidController::NPad);
|
MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad);
|
||||||
MakeController<Controller_Gesture>(HidController::Gesture);
|
MakeController<Controller_Gesture>(HidController::Gesture);
|
||||||
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
|
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
|
||||||
|
|
||||||
|
@ -191,13 +192,14 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
|
std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
|
||||||
if (applet_resource == nullptr) {
|
if (applet_resource == nullptr) {
|
||||||
applet_resource = std::make_shared<IAppletResource>(system);
|
applet_resource = std::make_shared<IAppletResource>(system, service_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return applet_resource;
|
return applet_resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
|
Hid::Hid(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "hid"}, service_context{system_, service_name} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
|
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
|
||||||
|
@ -347,7 +349,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||||
|
|
||||||
if (applet_resource == nullptr) {
|
if (applet_resource == nullptr) {
|
||||||
applet_resource = std::make_shared<IAppletResource>(system);
|
applet_resource = std::make_shared<IAppletResource>(system, service_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core::Timing {
|
||||||
|
@ -39,7 +40,8 @@ enum class HidController : std::size_t {
|
||||||
|
|
||||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||||
public:
|
public:
|
||||||
explicit IAppletResource(Core::System& system_);
|
explicit IAppletResource(Core::System& system_,
|
||||||
|
KernelHelpers::ServiceContext& service_context_);
|
||||||
~IAppletResource() override;
|
~IAppletResource() override;
|
||||||
|
|
||||||
void ActivateController(HidController controller);
|
void ActivateController(HidController controller);
|
||||||
|
@ -60,11 +62,18 @@ private:
|
||||||
void MakeController(HidController controller) {
|
void MakeController(HidController controller) {
|
||||||
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system);
|
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system);
|
||||||
}
|
}
|
||||||
|
template <typename T>
|
||||||
|
void MakeControllerWithServiceContext(HidController controller) {
|
||||||
|
controllers[static_cast<std::size_t>(controller)] =
|
||||||
|
std::make_unique<T>(system, service_context);
|
||||||
|
}
|
||||||
|
|
||||||
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
|
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
|
||||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext& service_context;
|
||||||
|
|
||||||
std::shared_ptr<Core::Timing::EventType> pad_update_event;
|
std::shared_ptr<Core::Timing::EventType> pad_update_event;
|
||||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||||
|
|
||||||
|
@ -176,6 +185,8 @@ private:
|
||||||
static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
|
static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
|
||||||
|
|
||||||
std::shared_ptr<IAppletResource> applet_resource;
|
std::shared_ptr<IAppletResource> applet_resource;
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Reload input devices. Used when input configuration changed
|
/// Reload input devices. Used when input configuration changed
|
||||||
|
|
64
src/core/hle/service/kernel_helpers.cpp
Executable file
64
src/core/hle/service/kernel_helpers.cpp
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright 2021 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
#include "core/hle/kernel/k_readable_event.h"
|
||||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||||
|
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||||
|
#include "core/hle/kernel/k_writable_event.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
|
||||||
|
namespace Service::KernelHelpers {
|
||||||
|
|
||||||
|
ServiceContext::ServiceContext(Core::System& system_, std::string name_)
|
||||||
|
: kernel(system_.Kernel()) {
|
||||||
|
process = Kernel::KProcess::Create(kernel);
|
||||||
|
ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_),
|
||||||
|
Kernel::KProcess::ProcessType::Userland)
|
||||||
|
.IsSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceContext::~ServiceContext() {
|
||||||
|
process->Close();
|
||||||
|
process = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
|
||||||
|
// Reserve a new event from the process resource limit
|
||||||
|
Kernel::KScopedResourceReservation event_reservation(process,
|
||||||
|
Kernel::LimitableResource::Events);
|
||||||
|
if (!event_reservation.Succeeded()) {
|
||||||
|
LOG_CRITICAL(Service, "Resource limit reached!");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new event.
|
||||||
|
auto* event = Kernel::KEvent::Create(kernel);
|
||||||
|
if (!event) {
|
||||||
|
LOG_CRITICAL(Service, "Unable to create event!");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the event.
|
||||||
|
event->Initialize(std::move(name));
|
||||||
|
|
||||||
|
// Commit the thread reservation.
|
||||||
|
event_reservation.Commit();
|
||||||
|
|
||||||
|
// Register the event.
|
||||||
|
Kernel::KEvent::Register(kernel, event);
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServiceContext::CloseEvent(Kernel::KEvent* event) {
|
||||||
|
event->GetReadableEvent().Close();
|
||||||
|
event->GetWritableEvent().Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::KernelHelpers
|
35
src/core/hle/service/kernel_helpers.h
Executable file
35
src/core/hle/service/kernel_helpers.h
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright 2021 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class KernelCore;
|
||||||
|
class KEvent;
|
||||||
|
class KProcess;
|
||||||
|
} // namespace Kernel
|
||||||
|
|
||||||
|
namespace Service::KernelHelpers {
|
||||||
|
|
||||||
|
class ServiceContext {
|
||||||
|
public:
|
||||||
|
ServiceContext(Core::System& system_, std::string name_);
|
||||||
|
~ServiceContext();
|
||||||
|
|
||||||
|
Kernel::KEvent* CreateEvent(std::string&& name);
|
||||||
|
|
||||||
|
void CloseEvent(Kernel::KEvent* event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Kernel::KernelCore& kernel;
|
||||||
|
Kernel::KProcess* process{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::KernelHelpers
|
|
@ -179,7 +179,7 @@ private:
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
|
||||||
if (Settings::values.bcat_backend == "none") {
|
if (Settings::values.bcat_backend.GetValue() == "none") {
|
||||||
rb.PushEnum(RequestState::NotSubmitted);
|
rb.PushEnum(RequestState::NotSubmitted);
|
||||||
} else {
|
} else {
|
||||||
rb.PushEnum(RequestState::Connected);
|
rb.PushEnum(RequestState::Connected);
|
||||||
|
@ -384,7 +384,7 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
if (Settings::values.bcat_backend == "none") {
|
if (Settings::values.bcat_backend.GetValue() == "none") {
|
||||||
rb.Push<u8>(0);
|
rb.Push<u8>(0);
|
||||||
} else {
|
} else {
|
||||||
rb.Push<u8>(1);
|
rb.Push<u8>(1);
|
||||||
|
@ -395,7 +395,7 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
if (Settings::values.bcat_backend == "none") {
|
if (Settings::values.bcat_backend.GetValue() == "none") {
|
||||||
rb.Push<u8>(0);
|
rb.Push<u8>(0);
|
||||||
} else {
|
} else {
|
||||||
rb.Push<u8>(1);
|
rb.Push<u8>(1);
|
||||||
|
|
|
@ -39,11 +39,12 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
|
||||||
nvflinger.SetNVDrvInstance(module_);
|
nvflinger.SetNVDrvInstance(module_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
|
Module::Module(Core::System& system)
|
||||||
|
: syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} {
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||||
events_interface.events[i].event = Kernel::KEvent::Create(kernel);
|
events_interface.events[i].event =
|
||||||
events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i));
|
service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i));
|
||||||
events_interface.status[i] = EventState::Free;
|
events_interface.status[i] = EventState::Free;
|
||||||
events_interface.registered[i] = false;
|
events_interface.registered[i] = false;
|
||||||
}
|
}
|
||||||
|
@ -65,8 +66,7 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
|
||||||
|
|
||||||
Module::~Module() {
|
Module::~Module() {
|
||||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||||
events_interface.events[i].event->Close();
|
service_context.CloseEvent(events_interface.events[i].event);
|
||||||
events_interface.events[i].event = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
#include "core/hle/service/nvdrv/syncpoint_manager.h"
|
#include "core/hle/service/nvdrv/syncpoint_manager.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
@ -154,6 +155,8 @@ private:
|
||||||
std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
|
std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
|
||||||
|
|
||||||
EventInterface events_interface;
|
EventInterface events_interface;
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Registers all NVDRV services with the specified service manager.
|
/// Registers all NVDRV services with the specified service manager.
|
||||||
|
|
|
@ -104,23 +104,22 @@ ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||||
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
||||||
const auto guard = LockService();
|
const auto guard = LockService();
|
||||||
|
|
||||||
ASSERT(!port_installed);
|
ASSERT(!service_registered);
|
||||||
|
|
||||||
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
|
service_manager.RegisterService(service_name, max_sessions, shared_from_this());
|
||||||
port->SetSessionHandler(shared_from_this());
|
service_registered = true;
|
||||||
port_installed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
|
Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
|
||||||
const auto guard = LockService();
|
const auto guard = LockService();
|
||||||
|
|
||||||
ASSERT(!port_installed);
|
ASSERT(!service_registered);
|
||||||
|
|
||||||
auto* port = Kernel::KPort::Create(kernel);
|
auto* port = Kernel::KPort::Create(kernel);
|
||||||
port->Initialize(max_sessions, false, service_name);
|
port->Initialize(max_sessions, false, service_name);
|
||||||
port->GetServerPort().SetSessionHandler(shared_from_this());
|
port->GetServerPort().SetSessionHandler(shared_from_this());
|
||||||
|
|
||||||
port_installed = true;
|
service_registered = true;
|
||||||
|
|
||||||
return port->GetClientPort();
|
return port->GetClientPort();
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,9 @@ protected:
|
||||||
/// System context that the service operates under.
|
/// System context that the service operates under.
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
|
/// Identifier string used to connect to the service.
|
||||||
|
std::string service_name;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend class ServiceFramework;
|
friend class ServiceFramework;
|
||||||
|
@ -117,14 +120,12 @@ private:
|
||||||
void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
|
void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
|
||||||
void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
|
void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
|
||||||
|
|
||||||
/// Identifier string used to connect to the service.
|
|
||||||
std::string service_name;
|
|
||||||
/// Maximum number of concurrent sessions that this service can handle.
|
/// Maximum number of concurrent sessions that this service can handle.
|
||||||
u32 max_sessions;
|
u32 max_sessions;
|
||||||
|
|
||||||
/// Flag to store if a port was already create/installed to detect multiple install attempts,
|
/// Flag to store if a port was already create/installed to detect multiple install attempts,
|
||||||
/// which is not supported.
|
/// which is not supported.
|
||||||
bool port_installed = false;
|
bool service_registered = false;
|
||||||
|
|
||||||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||||
InvokerFn* handler_invoker;
|
InvokerFn* handler_invoker;
|
||||||
|
|
|
@ -160,7 +160,7 @@ void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push(static_cast<u32>(Settings::values.quest_flag));
|
rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
|
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/k_client_port.h"
|
#include "core/hle/kernel/k_client_port.h"
|
||||||
|
@ -40,17 +41,13 @@ static ResultCode ValidateServiceName(const std::string& name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
|
Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
|
||||||
ASSERT(self.sm_interface.expired());
|
self.sm_interface = std::make_shared<SM>(self, system);
|
||||||
|
|
||||||
auto sm = std::make_shared<SM>(self, system);
|
|
||||||
self.sm_interface = sm;
|
|
||||||
self.controller_interface = std::make_unique<Controller>(system);
|
self.controller_interface = std::make_unique<Controller>(system);
|
||||||
|
return self.sm_interface->CreatePort();
|
||||||
return sm->CreatePort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
|
ResultCode ServiceManager::RegisterService(std::string name, u32 max_sessions,
|
||||||
u32 max_sessions) {
|
Kernel::SessionRequestHandlerPtr handler) {
|
||||||
|
|
||||||
CASCADE_CODE(ValidateServiceName(name));
|
CASCADE_CODE(ValidateServiceName(name));
|
||||||
|
|
||||||
|
@ -59,12 +56,9 @@ ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name
|
||||||
return ERR_ALREADY_REGISTERED;
|
return ERR_ALREADY_REGISTERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* port = Kernel::KPort::Create(kernel);
|
registered_services.emplace(std::move(name), handler);
|
||||||
port->Initialize(max_sessions, false, name);
|
|
||||||
|
|
||||||
registered_services.emplace(std::move(name), port);
|
return ResultSuccess;
|
||||||
|
|
||||||
return MakeResult(&port->GetServerPort());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ServiceManager::UnregisterService(const std::string& name) {
|
ResultCode ServiceManager::UnregisterService(const std::string& name) {
|
||||||
|
@ -76,14 +70,11 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {
|
||||||
return ERR_SERVICE_NOT_REGISTERED;
|
return ERR_SERVICE_NOT_REGISTERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter->second->Close();
|
|
||||||
|
|
||||||
registered_services.erase(iter);
|
registered_services.erase(iter);
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
|
ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
|
||||||
|
|
||||||
CASCADE_CODE(ValidateServiceName(name));
|
CASCADE_CODE(ValidateServiceName(name));
|
||||||
auto it = registered_services.find(name);
|
auto it = registered_services.find(name);
|
||||||
if (it == registered_services.end()) {
|
if (it == registered_services.end()) {
|
||||||
|
@ -91,10 +82,13 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
|
||||||
return ERR_SERVICE_NOT_REGISTERED;
|
return ERR_SERVICE_NOT_REGISTERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeResult(it->second);
|
auto* port = Kernel::KPort::Create(kernel);
|
||||||
}
|
port->Initialize(ServerSessionCountMax, false, name);
|
||||||
|
auto handler = it->second;
|
||||||
|
port->GetServerPort().SetSessionHandler(std::move(handler));
|
||||||
|
|
||||||
SM::~SM() = default;
|
return MakeResult(port);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SM::Initialize service function
|
* SM::Initialize service function
|
||||||
|
@ -156,11 +150,15 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
|
||||||
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
|
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
|
||||||
return port_result.Code();
|
return port_result.Code();
|
||||||
}
|
}
|
||||||
auto& port = port_result.Unwrap()->GetClientPort();
|
auto& port = port_result.Unwrap();
|
||||||
|
SCOPE_EXIT({ port->GetClientPort().Close(); });
|
||||||
|
|
||||||
|
server_ports.emplace_back(&port->GetServerPort());
|
||||||
|
|
||||||
// Create a new session.
|
// Create a new session.
|
||||||
Kernel::KClientSession* session{};
|
Kernel::KClientSession* session{};
|
||||||
if (const auto result = port.CreateSession(std::addressof(session)); result.IsError()) {
|
if (const auto result = port->GetClientPort().CreateSession(std::addressof(session));
|
||||||
|
result.IsError()) {
|
||||||
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
|
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -180,20 +178,21 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
|
LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
|
||||||
max_session_count, is_light);
|
max_session_count, is_light);
|
||||||
|
|
||||||
auto handle = service_manager.RegisterService(name, max_session_count);
|
if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr);
|
||||||
if (handle.Failed()) {
|
result.IsError()) {
|
||||||
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
|
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw);
|
||||||
handle.Code().raw);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(handle.Code());
|
rb.Push(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
auto* port = Kernel::KPort::Create(kernel);
|
||||||
rb.Push(handle.Code());
|
port->Initialize(ServerSessionCountMax, is_light, name);
|
||||||
|
SCOPE_EXIT({ port->GetClientPort().Close(); });
|
||||||
|
|
||||||
auto server_port = handle.Unwrap();
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||||
rb.PushMoveObjects(server_port);
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushMoveObjects(port->GetServerPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
|
void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -225,4 +224,10 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SM::~SM() {
|
||||||
|
for (auto& server_port : server_ports) {
|
||||||
|
server_port->Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::SM
|
} // namespace Service::SM
|
||||||
|
|
|
@ -49,6 +49,7 @@ private:
|
||||||
ServiceManager& service_manager;
|
ServiceManager& service_manager;
|
||||||
bool is_initialized{};
|
bool is_initialized{};
|
||||||
Kernel::KernelCore& kernel;
|
Kernel::KernelCore& kernel;
|
||||||
|
std::vector<Kernel::KServerPort*> server_ports;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ServiceManager {
|
class ServiceManager {
|
||||||
|
@ -58,7 +59,8 @@ public:
|
||||||
explicit ServiceManager(Kernel::KernelCore& kernel_);
|
explicit ServiceManager(Kernel::KernelCore& kernel_);
|
||||||
~ServiceManager();
|
~ServiceManager();
|
||||||
|
|
||||||
ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions);
|
ResultCode RegisterService(std::string name, u32 max_sessions,
|
||||||
|
Kernel::SessionRequestHandlerPtr handler);
|
||||||
ResultCode UnregisterService(const std::string& name);
|
ResultCode UnregisterService(const std::string& name);
|
||||||
ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
|
ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
|
||||||
|
|
||||||
|
@ -69,21 +71,17 @@ public:
|
||||||
LOG_DEBUG(Service, "Can't find service: {}", service_name);
|
LOG_DEBUG(Service, "Can't find service: {}", service_name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto* port = service->second;
|
return std::static_pointer_cast<T>(service->second);
|
||||||
if (port == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return std::static_pointer_cast<T>(port->GetServerPort().GetSessionRequestHandler());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvokeControlRequest(Kernel::HLERequestContext& context);
|
void InvokeControlRequest(Kernel::HLERequestContext& context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::weak_ptr<SM> sm_interface;
|
std::shared_ptr<SM> sm_interface;
|
||||||
std::unique_ptr<Controller> controller_interface;
|
std::unique_ptr<Controller> controller_interface;
|
||||||
|
|
||||||
/// Map of registered services, retrieved using GetServicePort.
|
/// Map of registered services, retrieved using GetServicePort.
|
||||||
std::unordered_map<std::string, Kernel::KPort*> registered_services;
|
std::unordered_map<std::string, Kernel::SessionRequestHandlerPtr> registered_services;
|
||||||
|
|
||||||
/// Kernel context
|
/// Kernel context
|
||||||
Kernel::KernelCore& kernel;
|
Kernel::KernelCore& kernel;
|
||||||
|
|
|
@ -155,8 +155,8 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
|
||||||
codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
|
codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Settings::values.program_args.empty()) {
|
if (!Settings::values.program_args.GetValue().empty()) {
|
||||||
const auto arg_data = Settings::values.program_args;
|
const auto arg_data = Settings::values.program_args.GetValue();
|
||||||
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
|
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
|
||||||
NSOArgumentHeader args_header{
|
NSOArgumentHeader args_header{
|
||||||
NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
|
NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
|
||||||
|
|
|
@ -104,8 +104,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
||||||
codeset.segments[i].size = nso_header.segments[i].size;
|
codeset.segments[i].size = nso_header.segments[i].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_pass_arguments && !Settings::values.program_args.empty()) {
|
if (should_pass_arguments && !Settings::values.program_args.GetValue().empty()) {
|
||||||
const auto arg_data{Settings::values.program_args};
|
const auto arg_data{Settings::values.program_args.GetValue()};
|
||||||
|
|
||||||
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
|
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
|
||||||
NSOArgumentHeader args_header{
|
NSOArgumentHeader args_header{
|
||||||
|
|
|
@ -397,7 +397,7 @@ void Reporter::ClearFSAccessLog() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Reporter::IsReportingEnabled() const {
|
bool Reporter::IsReportingEnabled() const {
|
||||||
return Settings::values.reporting_services;
|
return Settings::values.reporting_services.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -135,7 +135,7 @@ u64 RegenerateTelemetryId() {
|
||||||
|
|
||||||
bool VerifyLogin(const std::string& username, const std::string& token) {
|
bool VerifyLogin(const std::string& username, const std::string& token) {
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
return WebService::VerifyLogin(Settings::values.web_api_url, username, token);
|
return WebService::VerifyLogin(Settings::values.web_api_url.GetValue(), username, token);
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -152,7 +152,8 @@ TelemetrySession::~TelemetrySession() {
|
||||||
|
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
auto backend = std::make_unique<WebService::TelemetryJson>(
|
auto backend = std::make_unique<WebService::TelemetryJson>(
|
||||||
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
|
Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
|
||||||
|
Settings::values.yuzu_token.GetValue());
|
||||||
#else
|
#else
|
||||||
auto backend = std::make_unique<Telemetry::NullVisitor>();
|
auto backend = std::make_unique<Telemetry::NullVisitor>();
|
||||||
#endif
|
#endif
|
||||||
|
@ -212,7 +213,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||||
|
|
||||||
// Log user configuration information
|
// Log user configuration information
|
||||||
constexpr auto field_type = Telemetry::FieldType::UserConfig;
|
constexpr auto field_type = Telemetry::FieldType::UserConfig;
|
||||||
AddField(field_type, "Audio_SinkId", Settings::values.sink_id);
|
AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
|
||||||
AddField(field_type, "Audio_EnableAudioStretching",
|
AddField(field_type, "Audio_EnableAudioStretching",
|
||||||
Settings::values.enable_audio_stretching.GetValue());
|
Settings::values.enable_audio_stretching.GetValue());
|
||||||
AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
|
AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
|
||||||
|
@ -242,7 +243,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||||
bool TelemetrySession::SubmitTestcase() {
|
bool TelemetrySession::SubmitTestcase() {
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
auto backend = std::make_unique<WebService::TelemetryJson>(
|
auto backend = std::make_unique<WebService::TelemetryJson>(
|
||||||
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
|
Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
|
||||||
|
Settings::values.yuzu_token.GetValue());
|
||||||
field_collection.Accept(*backend);
|
field_collection.Accept(*backend);
|
||||||
return backend->SubmitTestcase();
|
return backend->SubmitTestcase();
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -84,7 +84,8 @@ public:
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
const auto axis_value =
|
const auto axis_value =
|
||||||
static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
|
static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
|
||||||
return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range);
|
return axis_value * Settings::values.mouse_panning_sensitivity.GetValue() /
|
||||||
|
(100.0f * range);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
|
std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
|
||||||
|
|
|
@ -13,7 +13,7 @@ class TouchFromButtonDevice final : public Input::TouchDevice {
|
||||||
public:
|
public:
|
||||||
TouchFromButtonDevice() {
|
TouchFromButtonDevice() {
|
||||||
const auto button_index =
|
const auto button_index =
|
||||||
static_cast<std::size_t>(Settings::values.touch_from_button_map_index);
|
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
|
||||||
const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
|
const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
|
||||||
|
|
||||||
for (const auto& config_entry : buttons) {
|
for (const auto& config_entry : buttons) {
|
||||||
|
|
|
@ -201,7 +201,7 @@ bool Client::DeviceConnected(std::size_t pad) const {
|
||||||
void Client::ReloadSockets() {
|
void Client::ReloadSockets() {
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
std::stringstream servers_ss(Settings::values.udp_input_servers);
|
std::stringstream servers_ss(static_cast<std::string>(Settings::values.udp_input_servers));
|
||||||
std::string server_token;
|
std::string server_token;
|
||||||
std::size_t client = 0;
|
std::size_t client = 0;
|
||||||
while (std::getline(servers_ss, server_token, ',')) {
|
while (std::getline(servers_ss, server_token, ',')) {
|
||||||
|
@ -370,7 +370,7 @@ std::optional<std::size_t> Client::GetUnusedFingerID() const {
|
||||||
|
|
||||||
void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) {
|
void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) {
|
||||||
// TODO: Use custom calibration per device
|
// TODO: Use custom calibration per device
|
||||||
const Common::ParamPackage touch_param(Settings::values.touch_device);
|
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
|
||||||
const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100));
|
const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100));
|
||||||
const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50));
|
const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50));
|
||||||
const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800));
|
const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800));
|
||||||
|
|
|
@ -103,8 +103,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
|
||||||
case ThiMethod::SetMethod1:
|
case ThiMethod::SetMethod1:
|
||||||
LOG_DEBUG(Service_NVDRV, "NVDEC method 0x{:X}",
|
LOG_DEBUG(Service_NVDRV, "NVDEC method 0x{:X}",
|
||||||
static_cast<u32>(nvdec_thi_state.method_0));
|
static_cast<u32>(nvdec_thi_state.method_0));
|
||||||
nvdec_processor->ProcessMethod(static_cast<Nvdec::Method>(nvdec_thi_state.method_0),
|
nvdec_processor->ProcessMethod(nvdec_thi_state.method_0, data);
|
||||||
data);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -23,8 +23,8 @@ void AVFrameDeleter(AVFrame* ptr) {
|
||||||
av_free(ptr);
|
av_free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Codec::Codec(GPU& gpu_)
|
Codec::Codec(GPU& gpu_, const NvdecCommon::NvdecRegisters& regs)
|
||||||
: gpu(gpu_), h264_decoder(std::make_unique<Decoder::H264>(gpu)),
|
: gpu(gpu_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(gpu)),
|
||||||
vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {}
|
vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {}
|
||||||
|
|
||||||
Codec::~Codec() {
|
Codec::~Codec() {
|
||||||
|
@ -43,30 +43,19 @@ Codec::~Codec() {
|
||||||
avcodec_close(av_codec_ctx);
|
avcodec_close(av_codec_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) {
|
void Codec::Initialize() {
|
||||||
if (current_codec != codec) {
|
AVCodecID codec{AV_CODEC_ID_NONE};
|
||||||
LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", static_cast<u32>(codec));
|
switch (current_codec) {
|
||||||
current_codec = codec;
|
case NvdecCommon::VideoCodec::H264:
|
||||||
}
|
codec = AV_CODEC_ID_H264;
|
||||||
}
|
break;
|
||||||
|
case NvdecCommon::VideoCodec::Vp9:
|
||||||
void Codec::StateWrite(u32 offset, u64 arguments) {
|
codec = AV_CODEC_ID_VP9;
|
||||||
u8* const state_offset = reinterpret_cast<u8*>(&state) + offset * sizeof(u64);
|
break;
|
||||||
std::memcpy(state_offset, &arguments, sizeof(u64));
|
default:
|
||||||
}
|
|
||||||
|
|
||||||
void Codec::Decode() {
|
|
||||||
bool is_first_frame = false;
|
|
||||||
if (!initialized) {
|
|
||||||
if (current_codec == NvdecCommon::VideoCodec::H264) {
|
|
||||||
av_codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
|
||||||
} else if (current_codec == NvdecCommon::VideoCodec::Vp9) {
|
|
||||||
av_codec = avcodec_find_decoder(AV_CODEC_ID_VP9);
|
|
||||||
} else {
|
|
||||||
LOG_ERROR(Service_NVDRV, "Unknown video codec {}", current_codec);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
av_codec = avcodec_find_decoder(codec);
|
||||||
av_codec_ctx = avcodec_alloc_context3(av_codec);
|
av_codec_ctx = avcodec_alloc_context3(av_codec);
|
||||||
av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
|
av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
|
||||||
|
|
||||||
|
@ -79,10 +68,23 @@ void Codec::Decode() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
is_first_frame = true;
|
return;
|
||||||
}
|
}
|
||||||
bool vp9_hidden_frame = false;
|
|
||||||
|
|
||||||
|
void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) {
|
||||||
|
if (current_codec != codec) {
|
||||||
|
current_codec = codec;
|
||||||
|
LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", GetCurrentCodecName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec::Decode() {
|
||||||
|
const bool is_first_frame = !initialized;
|
||||||
|
if (!initialized) {
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vp9_hidden_frame = false;
|
||||||
AVPacket packet{};
|
AVPacket packet{};
|
||||||
av_init_packet(&packet);
|
av_init_packet(&packet);
|
||||||
std::vector<u8> frame_data;
|
std::vector<u8> frame_data;
|
||||||
|
@ -95,7 +97,7 @@ void Codec::Decode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
packet.data = frame_data.data();
|
packet.data = frame_data.data();
|
||||||
packet.size = static_cast<int>(frame_data.size());
|
packet.size = static_cast<s32>(frame_data.size());
|
||||||
|
|
||||||
avcodec_send_packet(av_codec_ctx, &packet);
|
avcodec_send_packet(av_codec_ctx, &packet);
|
||||||
|
|
||||||
|
@ -127,4 +129,21 @@ NvdecCommon::VideoCodec Codec::GetCurrentCodec() const {
|
||||||
return current_codec;
|
return current_codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string_view Codec::GetCurrentCodecName() const {
|
||||||
|
switch (current_codec) {
|
||||||
|
case NvdecCommon::VideoCodec::None:
|
||||||
|
return "None";
|
||||||
|
case NvdecCommon::VideoCodec::H264:
|
||||||
|
return "H264";
|
||||||
|
case NvdecCommon::VideoCodec::Vp8:
|
||||||
|
return "VP8";
|
||||||
|
case NvdecCommon::VideoCodec::H265:
|
||||||
|
return "H265";
|
||||||
|
case NvdecCommon::VideoCodec::Vp9:
|
||||||
|
return "VP9";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Tegra
|
} // namespace Tegra
|
||||||
|
|
|
@ -42,15 +42,15 @@ class VP9;
|
||||||
|
|
||||||
class Codec {
|
class Codec {
|
||||||
public:
|
public:
|
||||||
explicit Codec(GPU& gpu);
|
explicit Codec(GPU& gpu, const NvdecCommon::NvdecRegisters& regs);
|
||||||
~Codec();
|
~Codec();
|
||||||
|
|
||||||
|
/// Initialize the codec, returning success or failure
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
/// Sets NVDEC video stream codec
|
/// Sets NVDEC video stream codec
|
||||||
void SetTargetCodec(NvdecCommon::VideoCodec codec);
|
void SetTargetCodec(NvdecCommon::VideoCodec codec);
|
||||||
|
|
||||||
/// Populate NvdecRegisters state with argument value at the provided offset
|
|
||||||
void StateWrite(u32 offset, u64 arguments);
|
|
||||||
|
|
||||||
/// Call decoders to construct headers, decode AVFrame with ffmpeg
|
/// Call decoders to construct headers, decode AVFrame with ffmpeg
|
||||||
void Decode();
|
void Decode();
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ public:
|
||||||
|
|
||||||
/// Returns the value of current_codec
|
/// Returns the value of current_codec
|
||||||
[[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const;
|
[[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const;
|
||||||
|
/// Return name of the current codec
|
||||||
|
[[nodiscard]] std::string_view GetCurrentCodecName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool initialized{};
|
bool initialized{};
|
||||||
|
@ -68,10 +70,10 @@ private:
|
||||||
AVCodecContext* av_codec_ctx{nullptr};
|
AVCodecContext* av_codec_ctx{nullptr};
|
||||||
|
|
||||||
GPU& gpu;
|
GPU& gpu;
|
||||||
|
const NvdecCommon::NvdecRegisters& state;
|
||||||
std::unique_ptr<Decoder::H264> h264_decoder;
|
std::unique_ptr<Decoder::H264> h264_decoder;
|
||||||
std::unique_ptr<Decoder::VP9> vp9_decoder;
|
std::unique_ptr<Decoder::VP9> vp9_decoder;
|
||||||
|
|
||||||
NvdecCommon::NvdecRegisters state{};
|
|
||||||
std::queue<AVFramePtr> av_frames{};
|
std::queue<AVFramePtr> av_frames{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,16 +45,17 @@ H264::~H264() = default;
|
||||||
|
|
||||||
const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state,
|
const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state,
|
||||||
bool is_first_frame) {
|
bool is_first_frame) {
|
||||||
H264DecoderContext context{};
|
H264DecoderContext context;
|
||||||
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext));
|
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext));
|
||||||
|
|
||||||
const s32 frame_number = static_cast<s32>((context.h264_parameter_set.flags >> 46) & 0x1ffff);
|
const s64 frame_number = context.h264_parameter_set.frame_number.Value();
|
||||||
if (!is_first_frame && frame_number != 0) {
|
if (!is_first_frame && frame_number != 0) {
|
||||||
frame.resize(context.frame_data_size);
|
frame.resize(context.stream_len);
|
||||||
|
|
||||||
gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size());
|
gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size());
|
||||||
} else {
|
return frame;
|
||||||
/// Encode header
|
}
|
||||||
|
|
||||||
|
// Encode header
|
||||||
H264BitWriter writer{};
|
H264BitWriter writer{};
|
||||||
writer.WriteU(1, 24);
|
writer.WriteU(1, 24);
|
||||||
writer.WriteU(0, 1);
|
writer.WriteU(0, 1);
|
||||||
|
@ -64,8 +65,8 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
|
||||||
writer.WriteU(0, 8);
|
writer.WriteU(0, 8);
|
||||||
writer.WriteU(31, 8);
|
writer.WriteU(31, 8);
|
||||||
writer.WriteUe(0);
|
writer.WriteUe(0);
|
||||||
const auto chroma_format_idc =
|
const u32 chroma_format_idc =
|
||||||
static_cast<u32>((context.h264_parameter_set.flags >> 12) & 3);
|
static_cast<u32>(context.h264_parameter_set.chroma_format_idc.Value());
|
||||||
writer.WriteUe(chroma_format_idc);
|
writer.WriteUe(chroma_format_idc);
|
||||||
if (chroma_format_idc == 3) {
|
if (chroma_format_idc == 3) {
|
||||||
writer.WriteBit(false);
|
writer.WriteBit(false);
|
||||||
|
@ -76,11 +77,13 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
|
||||||
writer.WriteBit(false); // QpprimeYZeroTransformBypassFlag
|
writer.WriteBit(false); // QpprimeYZeroTransformBypassFlag
|
||||||
writer.WriteBit(false); // Scaling matrix present flag
|
writer.WriteBit(false); // Scaling matrix present flag
|
||||||
|
|
||||||
const auto order_cnt_type = static_cast<u32>((context.h264_parameter_set.flags >> 14) & 3);
|
writer.WriteUe(static_cast<u32>(context.h264_parameter_set.log2_max_frame_num_minus4.Value()));
|
||||||
writer.WriteUe(static_cast<u32>((context.h264_parameter_set.flags >> 8) & 0xf));
|
|
||||||
|
const auto order_cnt_type =
|
||||||
|
static_cast<u32>(context.h264_parameter_set.pic_order_cnt_type.Value());
|
||||||
writer.WriteUe(order_cnt_type);
|
writer.WriteUe(order_cnt_type);
|
||||||
if (order_cnt_type == 0) {
|
if (order_cnt_type == 0) {
|
||||||
writer.WriteUe(context.h264_parameter_set.log2_max_pic_order_cnt);
|
writer.WriteUe(context.h264_parameter_set.log2_max_pic_order_cnt_lsb_minus4);
|
||||||
} else if (order_cnt_type == 1) {
|
} else if (order_cnt_type == 1) {
|
||||||
writer.WriteBit(context.h264_parameter_set.delta_pic_order_always_zero_flag != 0);
|
writer.WriteBit(context.h264_parameter_set.delta_pic_order_always_zero_flag != 0);
|
||||||
|
|
||||||
|
@ -89,7 +92,7 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
|
||||||
writer.WriteUe(0);
|
writer.WriteUe(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const s32 pic_height = context.h264_parameter_set.pic_height_in_map_units /
|
const s32 pic_height = context.h264_parameter_set.frame_height_in_map_units /
|
||||||
(context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2);
|
(context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2);
|
||||||
|
|
||||||
writer.WriteUe(16);
|
writer.WriteUe(16);
|
||||||
|
@ -99,10 +102,10 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
|
||||||
writer.WriteBit(context.h264_parameter_set.frame_mbs_only_flag != 0);
|
writer.WriteBit(context.h264_parameter_set.frame_mbs_only_flag != 0);
|
||||||
|
|
||||||
if (!context.h264_parameter_set.frame_mbs_only_flag) {
|
if (!context.h264_parameter_set.frame_mbs_only_flag) {
|
||||||
writer.WriteBit(((context.h264_parameter_set.flags >> 0) & 1) != 0);
|
writer.WriteBit(context.h264_parameter_set.flags.mbaff_frame.Value() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteBit(((context.h264_parameter_set.flags >> 1) & 1) != 0);
|
writer.WriteBit(context.h264_parameter_set.flags.direct_8x8_inference.Value() != 0);
|
||||||
writer.WriteBit(false); // Frame cropping flag
|
writer.WriteBit(false); // Frame cropping flag
|
||||||
writer.WriteBit(false); // VUI parameter present flag
|
writer.WriteBit(false); // VUI parameter present flag
|
||||||
|
|
||||||
|
@ -122,57 +125,49 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
|
||||||
writer.WriteUe(0);
|
writer.WriteUe(0);
|
||||||
writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active);
|
writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active);
|
||||||
writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active);
|
writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active);
|
||||||
writer.WriteBit(((context.h264_parameter_set.flags >> 2) & 1) != 0);
|
writer.WriteBit(context.h264_parameter_set.flags.weighted_pred.Value() != 0);
|
||||||
writer.WriteU(static_cast<s32>((context.h264_parameter_set.flags >> 32) & 0x3), 2);
|
writer.WriteU(static_cast<s32>(context.h264_parameter_set.weighted_bipred_idc.Value()), 2);
|
||||||
s32 pic_init_qp = static_cast<s32>((context.h264_parameter_set.flags >> 16) & 0x3f);
|
s32 pic_init_qp = static_cast<s32>(context.h264_parameter_set.pic_init_qp_minus26.Value());
|
||||||
pic_init_qp = (pic_init_qp << 26) >> 26;
|
|
||||||
writer.WriteSe(pic_init_qp);
|
writer.WriteSe(pic_init_qp);
|
||||||
writer.WriteSe(0);
|
writer.WriteSe(0);
|
||||||
s32 chroma_qp_index_offset =
|
s32 chroma_qp_index_offset =
|
||||||
static_cast<s32>((context.h264_parameter_set.flags >> 22) & 0x1f);
|
static_cast<s32>(context.h264_parameter_set.chroma_qp_index_offset.Value());
|
||||||
chroma_qp_index_offset = (chroma_qp_index_offset << 27) >> 27;
|
|
||||||
|
|
||||||
writer.WriteSe(chroma_qp_index_offset);
|
writer.WriteSe(chroma_qp_index_offset);
|
||||||
writer.WriteBit(context.h264_parameter_set.deblocking_filter_control_flag != 0);
|
writer.WriteBit(context.h264_parameter_set.deblocking_filter_control_present_flag != 0);
|
||||||
writer.WriteBit(((context.h264_parameter_set.flags >> 3) & 1) != 0);
|
writer.WriteBit(context.h264_parameter_set.flags.constrained_intra_pred.Value() != 0);
|
||||||
writer.WriteBit(context.h264_parameter_set.redundant_pic_count_flag != 0);
|
writer.WriteBit(context.h264_parameter_set.redundant_pic_cnt_present_flag != 0);
|
||||||
writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0);
|
writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0);
|
||||||
|
|
||||||
writer.WriteBit(true);
|
writer.WriteBit(true);
|
||||||
|
|
||||||
for (s32 index = 0; index < 6; index++) {
|
for (s32 index = 0; index < 6; index++) {
|
||||||
writer.WriteBit(true);
|
writer.WriteBit(true);
|
||||||
const auto matrix_x4 =
|
std::span<const u8> matrix{context.weight_scale};
|
||||||
std::vector<u8>(context.scaling_matrix_4.begin(), context.scaling_matrix_4.end());
|
writer.WriteScalingList(matrix, index * 16, 16);
|
||||||
writer.WriteScalingList(matrix_x4, index * 16, 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.h264_parameter_set.transform_8x8_mode_flag) {
|
if (context.h264_parameter_set.transform_8x8_mode_flag) {
|
||||||
for (s32 index = 0; index < 2; index++) {
|
for (s32 index = 0; index < 2; index++) {
|
||||||
writer.WriteBit(true);
|
writer.WriteBit(true);
|
||||||
const auto matrix_x8 = std::vector<u8>(context.scaling_matrix_8.begin(),
|
std::span<const u8> matrix{context.weight_scale_8x8};
|
||||||
context.scaling_matrix_8.end());
|
writer.WriteScalingList(matrix, index * 64, 64);
|
||||||
|
|
||||||
writer.WriteScalingList(matrix_x8, index * 64, 64);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 chroma_qp_index_offset2 =
|
s32 chroma_qp_index_offset2 =
|
||||||
static_cast<s32>((context.h264_parameter_set.flags >> 27) & 0x1f);
|
static_cast<s32>(context.h264_parameter_set.second_chroma_qp_index_offset.Value());
|
||||||
chroma_qp_index_offset2 = (chroma_qp_index_offset2 << 27) >> 27;
|
|
||||||
|
|
||||||
writer.WriteSe(chroma_qp_index_offset2);
|
writer.WriteSe(chroma_qp_index_offset2);
|
||||||
|
|
||||||
writer.End();
|
writer.End();
|
||||||
|
|
||||||
const auto& encoded_header = writer.GetByteArray();
|
const auto& encoded_header = writer.GetByteArray();
|
||||||
frame.resize(encoded_header.size() + context.frame_data_size);
|
frame.resize(encoded_header.size() + context.stream_len);
|
||||||
std::memcpy(frame.data(), encoded_header.data(), encoded_header.size());
|
std::memcpy(frame.data(), encoded_header.data(), encoded_header.size());
|
||||||
|
|
||||||
gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset,
|
gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset,
|
||||||
frame.data() + encoded_header.size(),
|
frame.data() + encoded_header.size(), context.stream_len);
|
||||||
context.frame_data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +197,7 @@ void H264BitWriter::WriteBit(bool state) {
|
||||||
WriteBits(state ? 1 : 0, 1);
|
WriteBits(state ? 1 : 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void H264BitWriter::WriteScalingList(const std::vector<u8>& list, s32 start, s32 count) {
|
void H264BitWriter::WriteScalingList(std::span<const u8> list, s32 start, s32 count) {
|
||||||
std::vector<u8> scan(count);
|
std::vector<u8> scan(count);
|
||||||
if (count == 16) {
|
if (count == 16) {
|
||||||
std::memcpy(scan.data(), zig_zag_scan.data(), scan.size());
|
std::memcpy(scan.data(), zig_zag_scan.data(), scan.size());
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/command_classes/nvdec_common.h"
|
#include "video_core/command_classes/nvdec_common.h"
|
||||||
|
@ -48,7 +50,7 @@ public:
|
||||||
|
|
||||||
/// Based on section 7.3.2.1.1.1 and Table 7-4 in the H.264 specification
|
/// Based on section 7.3.2.1.1.1 and Table 7-4 in the H.264 specification
|
||||||
/// Writes the scaling matrices of the sream
|
/// Writes the scaling matrices of the sream
|
||||||
void WriteScalingList(const std::vector<u8>& list, s32 start, s32 count);
|
void WriteScalingList(std::span<const u8> list, s32 start, s32 count);
|
||||||
|
|
||||||
/// Return the bitstream as a vector.
|
/// Return the bitstream as a vector.
|
||||||
[[nodiscard]] std::vector<u8>& GetByteArray();
|
[[nodiscard]] std::vector<u8>& GetByteArray();
|
||||||
|
@ -78,40 +80,110 @@ public:
|
||||||
const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false);
|
const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct H264ParameterSet {
|
|
||||||
u32 log2_max_pic_order_cnt{};
|
|
||||||
u32 delta_pic_order_always_zero_flag{};
|
|
||||||
u32 frame_mbs_only_flag{};
|
|
||||||
u32 pic_width_in_mbs{};
|
|
||||||
u32 pic_height_in_map_units{};
|
|
||||||
INSERT_PADDING_WORDS(1);
|
|
||||||
u32 entropy_coding_mode_flag{};
|
|
||||||
u32 bottom_field_pic_order_flag{};
|
|
||||||
u32 num_refidx_l0_default_active{};
|
|
||||||
u32 num_refidx_l1_default_active{};
|
|
||||||
u32 deblocking_filter_control_flag{};
|
|
||||||
u32 redundant_pic_count_flag{};
|
|
||||||
u32 transform_8x8_mode_flag{};
|
|
||||||
INSERT_PADDING_WORDS(9);
|
|
||||||
u64 flags{};
|
|
||||||
u32 frame_number{};
|
|
||||||
u32 frame_number2{};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(H264ParameterSet) == 0x68, "H264ParameterSet is an invalid size");
|
|
||||||
|
|
||||||
struct H264DecoderContext {
|
|
||||||
INSERT_PADDING_BYTES(0x48);
|
|
||||||
u32 frame_data_size{};
|
|
||||||
INSERT_PADDING_BYTES(0xc);
|
|
||||||
H264ParameterSet h264_parameter_set{};
|
|
||||||
INSERT_PADDING_BYTES(0x100);
|
|
||||||
std::array<u8, 0x60> scaling_matrix_4;
|
|
||||||
std::array<u8, 0x80> scaling_matrix_8;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(H264DecoderContext) == 0x2a0, "H264DecoderContext is an invalid size");
|
|
||||||
|
|
||||||
std::vector<u8> frame;
|
std::vector<u8> frame;
|
||||||
GPU& gpu;
|
GPU& gpu;
|
||||||
|
|
||||||
|
struct H264ParameterSet {
|
||||||
|
s32 log2_max_pic_order_cnt_lsb_minus4; ///< 0x00
|
||||||
|
s32 delta_pic_order_always_zero_flag; ///< 0x04
|
||||||
|
s32 frame_mbs_only_flag; ///< 0x08
|
||||||
|
u32 pic_width_in_mbs; ///< 0x0C
|
||||||
|
u32 frame_height_in_map_units; ///< 0x10
|
||||||
|
union { ///< 0x14
|
||||||
|
BitField<0, 2, u32> tile_format;
|
||||||
|
BitField<2, 3, u32> gob_height;
|
||||||
|
};
|
||||||
|
u32 entropy_coding_mode_flag; ///< 0x18
|
||||||
|
s32 pic_order_present_flag; ///< 0x1C
|
||||||
|
s32 num_refidx_l0_default_active; ///< 0x20
|
||||||
|
s32 num_refidx_l1_default_active; ///< 0x24
|
||||||
|
s32 deblocking_filter_control_present_flag; ///< 0x28
|
||||||
|
s32 redundant_pic_cnt_present_flag; ///< 0x2C
|
||||||
|
u32 transform_8x8_mode_flag; ///< 0x30
|
||||||
|
u32 pitch_luma; ///< 0x34
|
||||||
|
u32 pitch_chroma; ///< 0x38
|
||||||
|
u32 luma_top_offset; ///< 0x3C
|
||||||
|
u32 luma_bot_offset; ///< 0x40
|
||||||
|
u32 luma_frame_offset; ///< 0x44
|
||||||
|
u32 chroma_top_offset; ///< 0x48
|
||||||
|
u32 chroma_bot_offset; ///< 0x4C
|
||||||
|
u32 chroma_frame_offset; ///< 0x50
|
||||||
|
u32 hist_buffer_size; ///< 0x54
|
||||||
|
union { ///< 0x58
|
||||||
|
union {
|
||||||
|
BitField<0, 1, u64> mbaff_frame;
|
||||||
|
BitField<1, 1, u64> direct_8x8_inference;
|
||||||
|
BitField<2, 1, u64> weighted_pred;
|
||||||
|
BitField<3, 1, u64> constrained_intra_pred;
|
||||||
|
BitField<4, 1, u64> ref_pic;
|
||||||
|
BitField<5, 1, u64> field_pic;
|
||||||
|
BitField<6, 1, u64> bottom_field;
|
||||||
|
BitField<7, 1, u64> second_field;
|
||||||
|
} flags;
|
||||||
|
BitField<8, 4, u64> log2_max_frame_num_minus4;
|
||||||
|
BitField<12, 2, u64> chroma_format_idc;
|
||||||
|
BitField<14, 2, u64> pic_order_cnt_type;
|
||||||
|
BitField<16, 6, s64> pic_init_qp_minus26;
|
||||||
|
BitField<22, 5, s64> chroma_qp_index_offset;
|
||||||
|
BitField<27, 5, s64> second_chroma_qp_index_offset;
|
||||||
|
BitField<32, 2, u64> weighted_bipred_idc;
|
||||||
|
BitField<34, 7, u64> curr_pic_idx;
|
||||||
|
BitField<41, 5, u64> curr_col_idx;
|
||||||
|
BitField<46, 16, u64> frame_number;
|
||||||
|
BitField<62, 1, u64> frame_surfaces;
|
||||||
|
BitField<63, 1, u64> output_memory_layout;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(H264ParameterSet) == 0x60, "H264ParameterSet is an invalid size");
|
||||||
|
|
||||||
|
struct H264DecoderContext {
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(18); ///< 0x0000
|
||||||
|
u32 stream_len; ///< 0x0048
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(3); ///< 0x004C
|
||||||
|
H264ParameterSet h264_parameter_set; ///< 0x0058
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(66); ///< 0x00B8
|
||||||
|
std::array<u8, 0x60> weight_scale; ///< 0x01C0
|
||||||
|
std::array<u8, 0x80> weight_scale_8x8; ///< 0x0220
|
||||||
|
};
|
||||||
|
static_assert(sizeof(H264DecoderContext) == 0x2A0, "H264DecoderContext is an invalid size");
|
||||||
|
|
||||||
|
#define ASSERT_POSITION(field_name, position) \
|
||||||
|
static_assert(offsetof(H264ParameterSet, field_name) == position, \
|
||||||
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
|
ASSERT_POSITION(log2_max_pic_order_cnt_lsb_minus4, 0x00);
|
||||||
|
ASSERT_POSITION(delta_pic_order_always_zero_flag, 0x04);
|
||||||
|
ASSERT_POSITION(frame_mbs_only_flag, 0x08);
|
||||||
|
ASSERT_POSITION(pic_width_in_mbs, 0x0C);
|
||||||
|
ASSERT_POSITION(frame_height_in_map_units, 0x10);
|
||||||
|
ASSERT_POSITION(tile_format, 0x14);
|
||||||
|
ASSERT_POSITION(entropy_coding_mode_flag, 0x18);
|
||||||
|
ASSERT_POSITION(pic_order_present_flag, 0x1C);
|
||||||
|
ASSERT_POSITION(num_refidx_l0_default_active, 0x20);
|
||||||
|
ASSERT_POSITION(num_refidx_l1_default_active, 0x24);
|
||||||
|
ASSERT_POSITION(deblocking_filter_control_present_flag, 0x28);
|
||||||
|
ASSERT_POSITION(redundant_pic_cnt_present_flag, 0x2C);
|
||||||
|
ASSERT_POSITION(transform_8x8_mode_flag, 0x30);
|
||||||
|
ASSERT_POSITION(pitch_luma, 0x34);
|
||||||
|
ASSERT_POSITION(pitch_chroma, 0x38);
|
||||||
|
ASSERT_POSITION(luma_top_offset, 0x3C);
|
||||||
|
ASSERT_POSITION(luma_bot_offset, 0x40);
|
||||||
|
ASSERT_POSITION(luma_frame_offset, 0x44);
|
||||||
|
ASSERT_POSITION(chroma_top_offset, 0x48);
|
||||||
|
ASSERT_POSITION(chroma_bot_offset, 0x4C);
|
||||||
|
ASSERT_POSITION(chroma_frame_offset, 0x50);
|
||||||
|
ASSERT_POSITION(hist_buffer_size, 0x54);
|
||||||
|
ASSERT_POSITION(flags, 0x58);
|
||||||
|
#undef ASSERT_POSITION
|
||||||
|
|
||||||
|
#define ASSERT_POSITION(field_name, position) \
|
||||||
|
static_assert(offsetof(H264DecoderContext, field_name) == position, \
|
||||||
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
|
ASSERT_POSITION(stream_len, 0x48);
|
||||||
|
ASSERT_POSITION(h264_parameter_set, 0x58);
|
||||||
|
ASSERT_POSITION(weight_scale, 0x1C0);
|
||||||
|
#undef ASSERT_POSITION
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Decoder
|
} // namespace Decoder
|
||||||
|
|
|
@ -354,7 +354,7 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_
|
||||||
}
|
}
|
||||||
|
|
||||||
Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) {
|
Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) {
|
||||||
PictureInfo picture_info{};
|
PictureInfo picture_info;
|
||||||
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo));
|
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo));
|
||||||
Vp9PictureInfo vp9_info = picture_info.Convert();
|
Vp9PictureInfo vp9_info = picture_info.Convert();
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state)
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP9::InsertEntropy(u64 offset, Vp9EntropyProbs& dst) {
|
void VP9::InsertEntropy(u64 offset, Vp9EntropyProbs& dst) {
|
||||||
EntropyProbs entropy{};
|
EntropyProbs entropy;
|
||||||
gpu.MemoryManager().ReadBlock(offset, &entropy, sizeof(EntropyProbs));
|
gpu.MemoryManager().ReadBlock(offset, &entropy, sizeof(EntropyProbs));
|
||||||
entropy.Convert(dst);
|
entropy.Convert(dst);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ class GPU;
|
||||||
|
|
||||||
namespace Decoder {
|
namespace Decoder {
|
||||||
struct Vp9FrameDimensions {
|
struct Vp9FrameDimensions {
|
||||||
s16 width{};
|
s16 width;
|
||||||
s16 height{};
|
s16 height;
|
||||||
s16 luma_pitch{};
|
s16 luma_pitch;
|
||||||
s16 chroma_pitch{};
|
s16 chroma_pitch;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Vp9FrameDimensions) == 0x8, "Vp9 Vp9FrameDimensions is an invalid size");
|
static_assert(sizeof(Vp9FrameDimensions) == 0x8, "Vp9 Vp9FrameDimensions is an invalid size");
|
||||||
|
|
||||||
|
@ -49,87 +49,87 @@ enum class TxMode {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Segmentation {
|
struct Segmentation {
|
||||||
u8 enabled{};
|
u8 enabled;
|
||||||
u8 update_map{};
|
u8 update_map;
|
||||||
u8 temporal_update{};
|
u8 temporal_update;
|
||||||
u8 abs_delta{};
|
u8 abs_delta;
|
||||||
std::array<u32, 8> feature_mask{};
|
std::array<u32, 8> feature_mask;
|
||||||
std::array<std::array<s16, 4>, 8> feature_data{};
|
std::array<std::array<s16, 4>, 8> feature_data;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Segmentation) == 0x64, "Segmentation is an invalid size");
|
static_assert(sizeof(Segmentation) == 0x64, "Segmentation is an invalid size");
|
||||||
|
|
||||||
struct LoopFilter {
|
struct LoopFilter {
|
||||||
u8 mode_ref_delta_enabled{};
|
u8 mode_ref_delta_enabled;
|
||||||
std::array<s8, 4> ref_deltas{};
|
std::array<s8, 4> ref_deltas;
|
||||||
std::array<s8, 2> mode_deltas{};
|
std::array<s8, 2> mode_deltas;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(LoopFilter) == 0x7, "LoopFilter is an invalid size");
|
static_assert(sizeof(LoopFilter) == 0x7, "LoopFilter is an invalid size");
|
||||||
|
|
||||||
struct Vp9EntropyProbs {
|
struct Vp9EntropyProbs {
|
||||||
std::array<u8, 36> y_mode_prob{};
|
std::array<u8, 36> y_mode_prob; ///< 0x0000
|
||||||
std::array<u8, 64> partition_prob{};
|
std::array<u8, 64> partition_prob; ///< 0x0024
|
||||||
std::array<u8, 1728> coef_probs{};
|
std::array<u8, 1728> coef_probs; ///< 0x0064
|
||||||
std::array<u8, 8> switchable_interp_prob{};
|
std::array<u8, 8> switchable_interp_prob; ///< 0x0724
|
||||||
std::array<u8, 28> inter_mode_prob{};
|
std::array<u8, 28> inter_mode_prob; ///< 0x072C
|
||||||
std::array<u8, 4> intra_inter_prob{};
|
std::array<u8, 4> intra_inter_prob; ///< 0x0748
|
||||||
std::array<u8, 5> comp_inter_prob{};
|
std::array<u8, 5> comp_inter_prob; ///< 0x074C
|
||||||
std::array<u8, 10> single_ref_prob{};
|
std::array<u8, 10> single_ref_prob; ///< 0x0751
|
||||||
std::array<u8, 5> comp_ref_prob{};
|
std::array<u8, 5> comp_ref_prob; ///< 0x075B
|
||||||
std::array<u8, 6> tx_32x32_prob{};
|
std::array<u8, 6> tx_32x32_prob; ///< 0x0760
|
||||||
std::array<u8, 4> tx_16x16_prob{};
|
std::array<u8, 4> tx_16x16_prob; ///< 0x0766
|
||||||
std::array<u8, 2> tx_8x8_prob{};
|
std::array<u8, 2> tx_8x8_prob; ///< 0x076A
|
||||||
std::array<u8, 3> skip_probs{};
|
std::array<u8, 3> skip_probs; ///< 0x076C
|
||||||
std::array<u8, 3> joints{};
|
std::array<u8, 3> joints; ///< 0x076F
|
||||||
std::array<u8, 2> sign{};
|
std::array<u8, 2> sign; ///< 0x0772
|
||||||
std::array<u8, 20> classes{};
|
std::array<u8, 20> classes; ///< 0x0774
|
||||||
std::array<u8, 2> class_0{};
|
std::array<u8, 2> class_0; ///< 0x0788
|
||||||
std::array<u8, 20> prob_bits{};
|
std::array<u8, 20> prob_bits; ///< 0x078A
|
||||||
std::array<u8, 12> class_0_fr{};
|
std::array<u8, 12> class_0_fr; ///< 0x079E
|
||||||
std::array<u8, 6> fr{};
|
std::array<u8, 6> fr; ///< 0x07AA
|
||||||
std::array<u8, 2> class_0_hp{};
|
std::array<u8, 2> class_0_hp; ///< 0x07B0
|
||||||
std::array<u8, 2> high_precision{};
|
std::array<u8, 2> high_precision; ///< 0x07B2
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Vp9EntropyProbs) == 0x7B4, "Vp9EntropyProbs is an invalid size");
|
static_assert(sizeof(Vp9EntropyProbs) == 0x7B4, "Vp9EntropyProbs is an invalid size");
|
||||||
|
|
||||||
struct Vp9PictureInfo {
|
struct Vp9PictureInfo {
|
||||||
bool is_key_frame{};
|
bool is_key_frame;
|
||||||
bool intra_only{};
|
bool intra_only;
|
||||||
bool last_frame_was_key{};
|
bool last_frame_was_key;
|
||||||
bool frame_size_changed{};
|
bool frame_size_changed;
|
||||||
bool error_resilient_mode{};
|
bool error_resilient_mode;
|
||||||
bool last_frame_shown{};
|
bool last_frame_shown;
|
||||||
bool show_frame{};
|
bool show_frame;
|
||||||
std::array<s8, 4> ref_frame_sign_bias{};
|
std::array<s8, 4> ref_frame_sign_bias;
|
||||||
s32 base_q_index{};
|
s32 base_q_index;
|
||||||
s32 y_dc_delta_q{};
|
s32 y_dc_delta_q;
|
||||||
s32 uv_dc_delta_q{};
|
s32 uv_dc_delta_q;
|
||||||
s32 uv_ac_delta_q{};
|
s32 uv_ac_delta_q;
|
||||||
bool lossless{};
|
bool lossless;
|
||||||
s32 transform_mode{};
|
s32 transform_mode;
|
||||||
bool allow_high_precision_mv{};
|
bool allow_high_precision_mv;
|
||||||
s32 interp_filter{};
|
s32 interp_filter;
|
||||||
s32 reference_mode{};
|
s32 reference_mode;
|
||||||
s8 comp_fixed_ref{};
|
s8 comp_fixed_ref;
|
||||||
std::array<s8, 2> comp_var_ref{};
|
std::array<s8, 2> comp_var_ref;
|
||||||
s32 log2_tile_cols{};
|
s32 log2_tile_cols;
|
||||||
s32 log2_tile_rows{};
|
s32 log2_tile_rows;
|
||||||
bool segment_enabled{};
|
bool segment_enabled;
|
||||||
bool segment_map_update{};
|
bool segment_map_update;
|
||||||
bool segment_map_temporal_update{};
|
bool segment_map_temporal_update;
|
||||||
s32 segment_abs_delta{};
|
s32 segment_abs_delta;
|
||||||
std::array<u32, 8> segment_feature_enable{};
|
std::array<u32, 8> segment_feature_enable;
|
||||||
std::array<std::array<s16, 4>, 8> segment_feature_data{};
|
std::array<std::array<s16, 4>, 8> segment_feature_data;
|
||||||
bool mode_ref_delta_enabled{};
|
bool mode_ref_delta_enabled;
|
||||||
bool use_prev_in_find_mv_refs{};
|
bool use_prev_in_find_mv_refs;
|
||||||
std::array<s8, 4> ref_deltas{};
|
std::array<s8, 4> ref_deltas;
|
||||||
std::array<s8, 2> mode_deltas{};
|
std::array<s8, 2> mode_deltas;
|
||||||
Vp9EntropyProbs entropy{};
|
Vp9EntropyProbs entropy;
|
||||||
Vp9FrameDimensions frame_size{};
|
Vp9FrameDimensions frame_size;
|
||||||
u8 first_level{};
|
u8 first_level;
|
||||||
u8 sharpness_level{};
|
u8 sharpness_level;
|
||||||
u32 bitstream_size{};
|
u32 bitstream_size;
|
||||||
std::array<u64, 4> frame_offsets{};
|
std::array<u64, 4> frame_offsets;
|
||||||
std::array<bool, 4> refresh_frame{};
|
std::array<bool, 4> refresh_frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Vp9FrameContainer {
|
struct Vp9FrameContainer {
|
||||||
|
@ -138,35 +138,35 @@ struct Vp9FrameContainer {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PictureInfo {
|
struct PictureInfo {
|
||||||
INSERT_PADDING_WORDS(12);
|
INSERT_PADDING_WORDS_NOINIT(12); ///< 0x00
|
||||||
u32 bitstream_size{};
|
u32 bitstream_size; ///< 0x30
|
||||||
INSERT_PADDING_WORDS(5);
|
INSERT_PADDING_WORDS_NOINIT(5); ///< 0x34
|
||||||
Vp9FrameDimensions last_frame_size{};
|
Vp9FrameDimensions last_frame_size; ///< 0x48
|
||||||
Vp9FrameDimensions golden_frame_size{};
|
Vp9FrameDimensions golden_frame_size; ///< 0x50
|
||||||
Vp9FrameDimensions alt_frame_size{};
|
Vp9FrameDimensions alt_frame_size; ///< 0x58
|
||||||
Vp9FrameDimensions current_frame_size{};
|
Vp9FrameDimensions current_frame_size; ///< 0x60
|
||||||
u32 vp9_flags{};
|
u32 vp9_flags; ///< 0x68
|
||||||
std::array<s8, 4> ref_frame_sign_bias{};
|
std::array<s8, 4> ref_frame_sign_bias; ///< 0x6C
|
||||||
u8 first_level{};
|
u8 first_level; ///< 0x70
|
||||||
u8 sharpness_level{};
|
u8 sharpness_level; ///< 0x71
|
||||||
u8 base_q_index{};
|
u8 base_q_index; ///< 0x72
|
||||||
u8 y_dc_delta_q{};
|
u8 y_dc_delta_q; ///< 0x73
|
||||||
u8 uv_ac_delta_q{};
|
u8 uv_ac_delta_q; ///< 0x74
|
||||||
u8 uv_dc_delta_q{};
|
u8 uv_dc_delta_q; ///< 0x75
|
||||||
u8 lossless{};
|
u8 lossless; ///< 0x76
|
||||||
u8 tx_mode{};
|
u8 tx_mode; ///< 0x77
|
||||||
u8 allow_high_precision_mv{};
|
u8 allow_high_precision_mv; ///< 0x78
|
||||||
u8 interp_filter{};
|
u8 interp_filter; ///< 0x79
|
||||||
u8 reference_mode{};
|
u8 reference_mode; ///< 0x7A
|
||||||
s8 comp_fixed_ref{};
|
s8 comp_fixed_ref; ///< 0x7B
|
||||||
std::array<s8, 2> comp_var_ref{};
|
std::array<s8, 2> comp_var_ref; ///< 0x7C
|
||||||
u8 log2_tile_cols{};
|
u8 log2_tile_cols; ///< 0x7E
|
||||||
u8 log2_tile_rows{};
|
u8 log2_tile_rows; ///< 0x7F
|
||||||
Segmentation segmentation{};
|
Segmentation segmentation; ///< 0x80
|
||||||
LoopFilter loop_filter{};
|
LoopFilter loop_filter; ///< 0xE4
|
||||||
INSERT_PADDING_BYTES(5);
|
INSERT_PADDING_BYTES_NOINIT(5); ///< 0xEB
|
||||||
u32 surface_params{};
|
u32 surface_params; ///< 0xF0
|
||||||
INSERT_PADDING_WORDS(3);
|
INSERT_PADDING_WORDS_NOINIT(3); ///< 0xF4
|
||||||
|
|
||||||
[[nodiscard]] Vp9PictureInfo Convert() const {
|
[[nodiscard]] Vp9PictureInfo Convert() const {
|
||||||
return {
|
return {
|
||||||
|
@ -176,6 +176,7 @@ struct PictureInfo {
|
||||||
.frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0,
|
.frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0,
|
||||||
.error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0,
|
.error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0,
|
||||||
.last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0,
|
.last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0,
|
||||||
|
.show_frame = false,
|
||||||
.ref_frame_sign_bias = ref_frame_sign_bias,
|
.ref_frame_sign_bias = ref_frame_sign_bias,
|
||||||
.base_q_index = base_q_index,
|
.base_q_index = base_q_index,
|
||||||
.y_dc_delta_q = y_dc_delta_q,
|
.y_dc_delta_q = y_dc_delta_q,
|
||||||
|
@ -204,45 +205,48 @@ struct PictureInfo {
|
||||||
!(vp9_flags == (FrameFlags::LastFrameIsKeyFrame)),
|
!(vp9_flags == (FrameFlags::LastFrameIsKeyFrame)),
|
||||||
.ref_deltas = loop_filter.ref_deltas,
|
.ref_deltas = loop_filter.ref_deltas,
|
||||||
.mode_deltas = loop_filter.mode_deltas,
|
.mode_deltas = loop_filter.mode_deltas,
|
||||||
|
.entropy{},
|
||||||
.frame_size = current_frame_size,
|
.frame_size = current_frame_size,
|
||||||
.first_level = first_level,
|
.first_level = first_level,
|
||||||
.sharpness_level = sharpness_level,
|
.sharpness_level = sharpness_level,
|
||||||
.bitstream_size = bitstream_size,
|
.bitstream_size = bitstream_size,
|
||||||
|
.frame_offsets{},
|
||||||
|
.refresh_frame{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(PictureInfo) == 0x100, "PictureInfo is an invalid size");
|
static_assert(sizeof(PictureInfo) == 0x100, "PictureInfo is an invalid size");
|
||||||
|
|
||||||
struct EntropyProbs {
|
struct EntropyProbs {
|
||||||
INSERT_PADDING_BYTES(1024);
|
INSERT_PADDING_BYTES_NOINIT(1024); ///< 0x0000
|
||||||
std::array<u8, 28> inter_mode_prob{};
|
std::array<u8, 28> inter_mode_prob; ///< 0x0400
|
||||||
std::array<u8, 4> intra_inter_prob{};
|
std::array<u8, 4> intra_inter_prob; ///< 0x041C
|
||||||
INSERT_PADDING_BYTES(80);
|
INSERT_PADDING_BYTES_NOINIT(80); ///< 0x0420
|
||||||
std::array<u8, 2> tx_8x8_prob{};
|
std::array<u8, 2> tx_8x8_prob; ///< 0x0470
|
||||||
std::array<u8, 4> tx_16x16_prob{};
|
std::array<u8, 4> tx_16x16_prob; ///< 0x0472
|
||||||
std::array<u8, 6> tx_32x32_prob{};
|
std::array<u8, 6> tx_32x32_prob; ///< 0x0476
|
||||||
std::array<u8, 4> y_mode_prob_e8{};
|
std::array<u8, 4> y_mode_prob_e8; ///< 0x047C
|
||||||
std::array<std::array<u8, 8>, 4> y_mode_prob_e0e7{};
|
std::array<std::array<u8, 8>, 4> y_mode_prob_e0e7; ///< 0x0480
|
||||||
INSERT_PADDING_BYTES(64);
|
INSERT_PADDING_BYTES_NOINIT(64); ///< 0x04A0
|
||||||
std::array<u8, 64> partition_prob{};
|
std::array<u8, 64> partition_prob; ///< 0x04E0
|
||||||
INSERT_PADDING_BYTES(10);
|
INSERT_PADDING_BYTES_NOINIT(10); ///< 0x0520
|
||||||
std::array<u8, 8> switchable_interp_prob{};
|
std::array<u8, 8> switchable_interp_prob; ///< 0x052A
|
||||||
std::array<u8, 5> comp_inter_prob{};
|
std::array<u8, 5> comp_inter_prob; ///< 0x0532
|
||||||
std::array<u8, 3> skip_probs{};
|
std::array<u8, 3> skip_probs; ///< 0x0537
|
||||||
INSERT_PADDING_BYTES(1);
|
INSERT_PADDING_BYTES_NOINIT(1); ///< 0x053A
|
||||||
std::array<u8, 3> joints{};
|
std::array<u8, 3> joints; ///< 0x053B
|
||||||
std::array<u8, 2> sign{};
|
std::array<u8, 2> sign; ///< 0x053E
|
||||||
std::array<u8, 2> class_0{};
|
std::array<u8, 2> class_0; ///< 0x0540
|
||||||
std::array<u8, 6> fr{};
|
std::array<u8, 6> fr; ///< 0x0542
|
||||||
std::array<u8, 2> class_0_hp{};
|
std::array<u8, 2> class_0_hp; ///< 0x0548
|
||||||
std::array<u8, 2> high_precision{};
|
std::array<u8, 2> high_precision; ///< 0x054A
|
||||||
std::array<u8, 20> classes{};
|
std::array<u8, 20> classes; ///< 0x054C
|
||||||
std::array<u8, 12> class_0_fr{};
|
std::array<u8, 12> class_0_fr; ///< 0x0560
|
||||||
std::array<u8, 20> pred_bits{};
|
std::array<u8, 20> pred_bits; ///< 0x056C
|
||||||
std::array<u8, 10> single_ref_prob{};
|
std::array<u8, 10> single_ref_prob; ///< 0x0580
|
||||||
std::array<u8, 5> comp_ref_prob{};
|
std::array<u8, 5> comp_ref_prob; ///< 0x058A
|
||||||
INSERT_PADDING_BYTES(17);
|
INSERT_PADDING_BYTES_NOINIT(17); ///< 0x058F
|
||||||
std::array<u8, 2304> coef_probs{};
|
std::array<u8, 2304> coef_probs; ///< 0x05A0
|
||||||
|
|
||||||
void Convert(Vp9EntropyProbs& fc) {
|
void Convert(Vp9EntropyProbs& fc) {
|
||||||
fc.inter_mode_prob = inter_mode_prob;
|
fc.inter_mode_prob = inter_mode_prob;
|
||||||
|
@ -293,10 +297,45 @@ struct RefPoolElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameContexts {
|
struct FrameContexts {
|
||||||
s64 from{};
|
s64 from;
|
||||||
bool adapted{};
|
bool adapted;
|
||||||
Vp9EntropyProbs probs{};
|
Vp9EntropyProbs probs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ASSERT_POSITION(field_name, position) \
|
||||||
|
static_assert(offsetof(Vp9EntropyProbs, field_name) == position, \
|
||||||
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
|
ASSERT_POSITION(partition_prob, 0x0024);
|
||||||
|
ASSERT_POSITION(switchable_interp_prob, 0x0724);
|
||||||
|
ASSERT_POSITION(sign, 0x0772);
|
||||||
|
ASSERT_POSITION(class_0_fr, 0x079E);
|
||||||
|
ASSERT_POSITION(high_precision, 0x07B2);
|
||||||
|
#undef ASSERT_POSITION
|
||||||
|
|
||||||
|
#define ASSERT_POSITION(field_name, position) \
|
||||||
|
static_assert(offsetof(PictureInfo, field_name) == position, \
|
||||||
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
|
ASSERT_POSITION(bitstream_size, 0x30);
|
||||||
|
ASSERT_POSITION(last_frame_size, 0x48);
|
||||||
|
ASSERT_POSITION(first_level, 0x70);
|
||||||
|
ASSERT_POSITION(segmentation, 0x80);
|
||||||
|
ASSERT_POSITION(loop_filter, 0xE4);
|
||||||
|
ASSERT_POSITION(surface_params, 0xF0);
|
||||||
|
#undef ASSERT_POSITION
|
||||||
|
|
||||||
|
#define ASSERT_POSITION(field_name, position) \
|
||||||
|
static_assert(offsetof(EntropyProbs, field_name) == position, \
|
||||||
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
|
ASSERT_POSITION(inter_mode_prob, 0x400);
|
||||||
|
ASSERT_POSITION(tx_8x8_prob, 0x470);
|
||||||
|
ASSERT_POSITION(partition_prob, 0x4E0);
|
||||||
|
ASSERT_POSITION(class_0, 0x540);
|
||||||
|
ASSERT_POSITION(class_0_fr, 0x560);
|
||||||
|
ASSERT_POSITION(coef_probs, 0x5A0);
|
||||||
|
#undef ASSERT_POSITION
|
||||||
|
|
||||||
}; // namespace Decoder
|
}; // namespace Decoder
|
||||||
}; // namespace Tegra
|
}; // namespace Tegra
|
||||||
|
|
|
@ -8,22 +8,21 @@
|
||||||
|
|
||||||
namespace Tegra {
|
namespace Tegra {
|
||||||
|
|
||||||
Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), codec(std::make_unique<Codec>(gpu)) {}
|
#define NVDEC_REG_INDEX(field_name) \
|
||||||
|
(offsetof(NvdecCommon::NvdecRegisters, field_name) / sizeof(u64))
|
||||||
|
|
||||||
|
Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), state{}, codec(std::make_unique<Codec>(gpu, state)) {}
|
||||||
|
|
||||||
Nvdec::~Nvdec() = default;
|
Nvdec::~Nvdec() = default;
|
||||||
|
|
||||||
void Nvdec::ProcessMethod(Method method, u32 argument) {
|
void Nvdec::ProcessMethod(u32 method, u32 argument) {
|
||||||
if (method == Method::SetVideoCodec) {
|
state.reg_array[method] = static_cast<u64>(argument) << 8;
|
||||||
codec->StateWrite(static_cast<u32>(method), argument);
|
|
||||||
} else {
|
|
||||||
codec->StateWrite(static_cast<u32>(method), static_cast<u64>(argument) << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case Method::SetVideoCodec:
|
case NVDEC_REG_INDEX(set_codec_id):
|
||||||
codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(argument));
|
codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(argument));
|
||||||
break;
|
break;
|
||||||
case Method::Execute:
|
case NVDEC_REG_INDEX(execute):
|
||||||
Execute();
|
Execute();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,16 +14,11 @@ class GPU;
|
||||||
|
|
||||||
class Nvdec {
|
class Nvdec {
|
||||||
public:
|
public:
|
||||||
enum class Method : u32 {
|
|
||||||
SetVideoCodec = 0x80,
|
|
||||||
Execute = 0xc0,
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit Nvdec(GPU& gpu);
|
explicit Nvdec(GPU& gpu);
|
||||||
~Nvdec();
|
~Nvdec();
|
||||||
|
|
||||||
/// Writes the method into the state, Invoke Execute() if encountered
|
/// Writes the method into the state, Invoke Execute() if encountered
|
||||||
void ProcessMethod(Method method, u32 argument);
|
void ProcessMethod(u32 method, u32 argument);
|
||||||
|
|
||||||
/// Return most recently decoded frame
|
/// Return most recently decoded frame
|
||||||
[[nodiscard]] AVFramePtr GetFrame();
|
[[nodiscard]] AVFramePtr GetFrame();
|
||||||
|
@ -33,6 +28,7 @@ private:
|
||||||
void Execute();
|
void Execute();
|
||||||
|
|
||||||
GPU& gpu;
|
GPU& gpu;
|
||||||
|
NvdecCommon::NvdecRegisters state;
|
||||||
std::unique_ptr<Codec> codec;
|
std::unique_ptr<Codec> codec;
|
||||||
};
|
};
|
||||||
} // namespace Tegra
|
} // namespace Tegra
|
||||||
|
|
|
@ -4,40 +4,13 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Tegra::NvdecCommon {
|
namespace Tegra::NvdecCommon {
|
||||||
|
|
||||||
struct NvdecRegisters {
|
enum class VideoCodec : u64 {
|
||||||
INSERT_PADDING_WORDS(256);
|
|
||||||
u64 set_codec_id{};
|
|
||||||
INSERT_PADDING_WORDS(254);
|
|
||||||
u64 set_platform_id{};
|
|
||||||
u64 picture_info_offset{};
|
|
||||||
u64 frame_bitstream_offset{};
|
|
||||||
u64 frame_number{};
|
|
||||||
u64 h264_slice_data_offsets{};
|
|
||||||
u64 h264_mv_dump_offset{};
|
|
||||||
INSERT_PADDING_WORDS(6);
|
|
||||||
u64 frame_stats_offset{};
|
|
||||||
u64 h264_last_surface_luma_offset{};
|
|
||||||
u64 h264_last_surface_chroma_offset{};
|
|
||||||
std::array<u64, 17> surface_luma_offset{};
|
|
||||||
std::array<u64, 17> surface_chroma_offset{};
|
|
||||||
INSERT_PADDING_WORDS(132);
|
|
||||||
u64 vp9_entropy_probs_offset{};
|
|
||||||
u64 vp9_backward_updates_offset{};
|
|
||||||
u64 vp9_last_frame_segmap_offset{};
|
|
||||||
u64 vp9_curr_frame_segmap_offset{};
|
|
||||||
INSERT_PADDING_WORDS(2);
|
|
||||||
u64 vp9_last_frame_mvs_offset{};
|
|
||||||
u64 vp9_curr_frame_mvs_offset{};
|
|
||||||
INSERT_PADDING_WORDS(2);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(NvdecRegisters) == (0xBC0), "NvdecRegisters is incorrect size");
|
|
||||||
|
|
||||||
enum class VideoCodec : u32 {
|
|
||||||
None = 0x0,
|
None = 0x0,
|
||||||
H264 = 0x3,
|
H264 = 0x3,
|
||||||
Vp8 = 0x5,
|
Vp8 = 0x5,
|
||||||
|
@ -45,4 +18,76 @@ enum class VideoCodec : u32 {
|
||||||
Vp9 = 0x9,
|
Vp9 = 0x9,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NVDEC should use a 32-bit address space, but is mapped to 64-bit,
|
||||||
|
// doubling the sizes here is compensating for that.
|
||||||
|
struct NvdecRegisters {
|
||||||
|
static constexpr std::size_t NUM_REGS = 0x178;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(256); ///< 0x0000
|
||||||
|
VideoCodec set_codec_id; ///< 0x0400
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(126); ///< 0x0408
|
||||||
|
u64 execute; ///< 0x0600
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(126); ///< 0x0608
|
||||||
|
struct { ///< 0x0800
|
||||||
|
union {
|
||||||
|
BitField<0, 3, VideoCodec> codec;
|
||||||
|
BitField<4, 1, u64> gp_timer_on;
|
||||||
|
BitField<13, 1, u64> mb_timer_on;
|
||||||
|
BitField<14, 1, u64> intra_frame_pslc;
|
||||||
|
BitField<17, 1, u64> all_intra_frame;
|
||||||
|
};
|
||||||
|
} control_params;
|
||||||
|
u64 picture_info_offset; ///< 0x0808
|
||||||
|
u64 frame_bitstream_offset; ///< 0x0810
|
||||||
|
u64 frame_number; ///< 0x0818
|
||||||
|
u64 h264_slice_data_offsets; ///< 0x0820
|
||||||
|
u64 h264_mv_dump_offset; ///< 0x0828
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(6); ///< 0x0830
|
||||||
|
u64 frame_stats_offset; ///< 0x0848
|
||||||
|
u64 h264_last_surface_luma_offset; ///< 0x0850
|
||||||
|
u64 h264_last_surface_chroma_offset; ///< 0x0858
|
||||||
|
std::array<u64, 17> surface_luma_offset; ///< 0x0860
|
||||||
|
std::array<u64, 17> surface_chroma_offset; ///< 0x08E8
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(132); ///< 0x0970
|
||||||
|
u64 vp9_entropy_probs_offset; ///< 0x0B80
|
||||||
|
u64 vp9_backward_updates_offset; ///< 0x0B88
|
||||||
|
u64 vp9_last_frame_segmap_offset; ///< 0x0B90
|
||||||
|
u64 vp9_curr_frame_segmap_offset; ///< 0x0B98
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(2); ///< 0x0BA0
|
||||||
|
u64 vp9_last_frame_mvs_offset; ///< 0x0BA8
|
||||||
|
u64 vp9_curr_frame_mvs_offset; ///< 0x0BB0
|
||||||
|
INSERT_PADDING_WORDS_NOINIT(2); ///< 0x0BB8
|
||||||
|
};
|
||||||
|
std::array<u64, NUM_REGS> reg_array;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NvdecRegisters) == (0xBC0), "NvdecRegisters is incorrect size");
|
||||||
|
|
||||||
|
#define ASSERT_REG_POSITION(field_name, position) \
|
||||||
|
static_assert(offsetof(NvdecRegisters, field_name) == position * sizeof(u64), \
|
||||||
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
|
ASSERT_REG_POSITION(set_codec_id, 0x80);
|
||||||
|
ASSERT_REG_POSITION(execute, 0xC0);
|
||||||
|
ASSERT_REG_POSITION(control_params, 0x100);
|
||||||
|
ASSERT_REG_POSITION(picture_info_offset, 0x101);
|
||||||
|
ASSERT_REG_POSITION(frame_bitstream_offset, 0x102);
|
||||||
|
ASSERT_REG_POSITION(frame_number, 0x103);
|
||||||
|
ASSERT_REG_POSITION(h264_slice_data_offsets, 0x104);
|
||||||
|
ASSERT_REG_POSITION(frame_stats_offset, 0x109);
|
||||||
|
ASSERT_REG_POSITION(h264_last_surface_luma_offset, 0x10A);
|
||||||
|
ASSERT_REG_POSITION(h264_last_surface_chroma_offset, 0x10B);
|
||||||
|
ASSERT_REG_POSITION(surface_luma_offset, 0x10C);
|
||||||
|
ASSERT_REG_POSITION(surface_chroma_offset, 0x11D);
|
||||||
|
ASSERT_REG_POSITION(vp9_entropy_probs_offset, 0x170);
|
||||||
|
ASSERT_REG_POSITION(vp9_backward_updates_offset, 0x171);
|
||||||
|
ASSERT_REG_POSITION(vp9_last_frame_segmap_offset, 0x172);
|
||||||
|
ASSERT_REG_POSITION(vp9_curr_frame_segmap_offset, 0x173);
|
||||||
|
ASSERT_REG_POSITION(vp9_last_frame_mvs_offset, 0x175);
|
||||||
|
ASSERT_REG_POSITION(vp9_curr_frame_mvs_offset, 0x176);
|
||||||
|
|
||||||
|
#undef ASSERT_REG_POSITION
|
||||||
|
|
||||||
} // namespace Tegra::NvdecCommon
|
} // namespace Tegra::NvdecCommon
|
||||||
|
|
|
@ -103,7 +103,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
|
||||||
gpu(gpu_),
|
gpu(gpu_),
|
||||||
library(OpenLibrary()),
|
library(OpenLibrary()),
|
||||||
instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
|
instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
|
||||||
true, Settings::values.renderer_debug)),
|
true, Settings::values.renderer_debug.GetValue())),
|
||||||
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
|
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
|
||||||
surface(CreateSurface(instance, render_window)),
|
surface(CreateSurface(instance, render_window)),
|
||||||
device(CreateDevice(instance, dld, *surface)),
|
device(CreateDevice(instance, dld, *surface)),
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -102,28 +102,75 @@ private:
|
||||||
void SaveUILayoutValues();
|
void SaveUILayoutValues();
|
||||||
void SaveWebServiceValues();
|
void SaveWebServiceValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a setting from the qt_config.
|
||||||
|
*
|
||||||
|
* @param name The setting's identifier
|
||||||
|
* @param default_value The value to use when the setting is not already present in the config
|
||||||
|
*/
|
||||||
QVariant ReadSetting(const QString& name) const;
|
QVariant ReadSetting(const QString& name) const;
|
||||||
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
|
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
|
||||||
// Templated ReadSettingGlobal functions will also look for the use_global setting and set
|
|
||||||
// both the value and the global state properly
|
/**
|
||||||
template <typename Type>
|
* Only reads a setting from the qt_config if the current config is a global config, or if the
|
||||||
void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name);
|
* current config is a custom config and the setting is overriding the global setting. Otherwise
|
||||||
template <typename Type>
|
* it does nothing.
|
||||||
void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
|
*
|
||||||
const QVariant& default_value);
|
* @param setting The variable to be modified
|
||||||
|
* @param name The setting's identifier
|
||||||
|
* @param default_value The value to use when the setting is not already present in the config
|
||||||
|
*/
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
|
void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
|
||||||
// Templated WriteSettingGlobal functions will also write the global state if needed and will
|
|
||||||
// skip writing the actual setting if it defers to the global value
|
/**
|
||||||
|
* Writes a setting to the qt_config.
|
||||||
|
*
|
||||||
|
* @param name The setting's idetentifier
|
||||||
|
* @param value Value of the setting
|
||||||
|
* @param default_value Default of the setting if not present in qt_config
|
||||||
|
* @param use_global Specifies if the custom or global config should be in use, for custom
|
||||||
|
* configs
|
||||||
|
*/
|
||||||
void WriteSetting(const QString& name, const QVariant& value);
|
void WriteSetting(const QString& name, const QVariant& value);
|
||||||
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
|
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
|
||||||
|
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
|
||||||
|
bool use_global);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a value from the qt_config and applies it to the setting, using its label and default
|
||||||
|
* value. If the config is a custom config, this will also read the global state of the setting
|
||||||
|
* and apply that information to it.
|
||||||
|
*
|
||||||
|
* @param The setting
|
||||||
|
*/
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting);
|
void ReadGlobalSetting(Settings::Setting<Type>& setting);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a value to the qt_config using the setting's label and default value. If the config is a
|
||||||
|
* custom config, it will apply the global state, and the custom value if needed.
|
||||||
|
*
|
||||||
|
* @param The setting
|
||||||
|
*/
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
|
void WriteGlobalSetting(const Settings::Setting<Type>& setting);
|
||||||
const QVariant& default_value);
|
|
||||||
void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
|
/**
|
||||||
const QVariant& default_value);
|
* Reads a value from the qt_config using the setting's label and default value and applies the
|
||||||
|
* value to the setting.
|
||||||
|
*
|
||||||
|
* @param The setting
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
void ReadBasicSetting(Settings::BasicSetting<Type>& setting);
|
||||||
|
|
||||||
|
/** Sets a value from the setting in the qt_config using the setting's label and default value.
|
||||||
|
*
|
||||||
|
* @param The setting
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
void WriteBasicSetting(const Settings::BasicSetting<Type>& setting);
|
||||||
|
|
||||||
ConfigType type;
|
ConfigType type;
|
||||||
std::unique_ptr<QSettings> qt_config;
|
std::unique_ptr<QSettings> qt_config;
|
||||||
|
|
|
@ -69,7 +69,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
|
||||||
[[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box);
|
[[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box);
|
||||||
|
|
||||||
int new_sink_index = 0;
|
int new_sink_index = 0;
|
||||||
const QString sink_id = QString::fromStdString(Settings::values.sink_id);
|
const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue());
|
||||||
for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
|
for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
|
||||||
if (ui->output_sink_combo_box->itemText(index) == sink_id) {
|
if (ui->output_sink_combo_box->itemText(index) == sink_id) {
|
||||||
new_sink_index = index;
|
new_sink_index = index;
|
||||||
|
@ -83,7 +83,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
|
||||||
void ConfigureAudio::SetAudioDeviceFromDeviceID() {
|
void ConfigureAudio::SetAudioDeviceFromDeviceID() {
|
||||||
int new_device_index = -1;
|
int new_device_index = -1;
|
||||||
|
|
||||||
const QString device_id = QString::fromStdString(Settings::values.audio_device_id);
|
const QString device_id = QString::fromStdString(Settings::values.audio_device_id.GetValue());
|
||||||
for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
|
for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
|
||||||
if (ui->audio_device_combo_box->itemText(index) == device_id) {
|
if (ui->audio_device_combo_box->itemText(index) == device_id) {
|
||||||
new_device_index = index;
|
new_device_index = index;
|
||||||
|
@ -106,9 +106,9 @@ void ConfigureAudio::ApplyConfiguration() {
|
||||||
Settings::values.sink_id =
|
Settings::values.sink_id =
|
||||||
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
|
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
|
||||||
.toStdString();
|
.toStdString();
|
||||||
Settings::values.audio_device_id =
|
Settings::values.audio_device_id.SetValue(
|
||||||
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
|
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
|
||||||
.toStdString();
|
.toStdString());
|
||||||
|
|
||||||
// Guard if during game and set to game-specific value
|
// Guard if during game and set to game-specific value
|
||||||
if (Settings::values.volume.UsingGlobal()) {
|
if (Settings::values.volume.UsingGlobal()) {
|
||||||
|
|
|
@ -24,23 +24,26 @@ void ConfigureCpuDebug::SetConfiguration() {
|
||||||
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
||||||
|
|
||||||
ui->cpuopt_page_tables->setEnabled(runtime_lock);
|
ui->cpuopt_page_tables->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables);
|
ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables.GetValue());
|
||||||
ui->cpuopt_block_linking->setEnabled(runtime_lock);
|
ui->cpuopt_block_linking->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking);
|
ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking.GetValue());
|
||||||
ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
|
ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer);
|
ui->cpuopt_return_stack_buffer->setChecked(
|
||||||
|
Settings::values.cpuopt_return_stack_buffer.GetValue());
|
||||||
ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
|
ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher);
|
ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher.GetValue());
|
||||||
ui->cpuopt_context_elimination->setEnabled(runtime_lock);
|
ui->cpuopt_context_elimination->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination);
|
ui->cpuopt_context_elimination->setChecked(
|
||||||
|
Settings::values.cpuopt_context_elimination.GetValue());
|
||||||
ui->cpuopt_const_prop->setEnabled(runtime_lock);
|
ui->cpuopt_const_prop->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop);
|
ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop.GetValue());
|
||||||
ui->cpuopt_misc_ir->setEnabled(runtime_lock);
|
ui->cpuopt_misc_ir->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir);
|
ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir.GetValue());
|
||||||
ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
|
ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks);
|
ui->cpuopt_reduce_misalign_checks->setChecked(
|
||||||
|
Settings::values.cpuopt_reduce_misalign_checks.GetValue());
|
||||||
ui->cpuopt_fastmem->setEnabled(runtime_lock);
|
ui->cpuopt_fastmem->setEnabled(runtime_lock);
|
||||||
ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem);
|
ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCpuDebug::ApplyConfiguration() {
|
void ConfigureCpuDebug::ApplyConfiguration() {
|
||||||
|
|
|
@ -31,20 +31,21 @@ void ConfigureDebug::SetConfiguration() {
|
||||||
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
||||||
|
|
||||||
ui->toggle_console->setEnabled(runtime_lock);
|
ui->toggle_console->setEnabled(runtime_lock);
|
||||||
ui->toggle_console->setChecked(UISettings::values.show_console);
|
ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
|
||||||
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
|
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
|
||||||
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
|
ui->homebrew_args_edit->setText(
|
||||||
|
QString::fromStdString(Settings::values.program_args.GetValue()));
|
||||||
ui->fs_access_log->setEnabled(runtime_lock);
|
ui->fs_access_log->setEnabled(runtime_lock);
|
||||||
ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log);
|
ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log.GetValue());
|
||||||
ui->reporting_services->setChecked(Settings::values.reporting_services);
|
ui->reporting_services->setChecked(Settings::values.reporting_services.GetValue());
|
||||||
ui->quest_flag->setChecked(Settings::values.quest_flag);
|
ui->quest_flag->setChecked(Settings::values.quest_flag.GetValue());
|
||||||
ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts);
|
ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts.GetValue());
|
||||||
ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
|
ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue());
|
||||||
ui->enable_graphics_debugging->setEnabled(runtime_lock);
|
ui->enable_graphics_debugging->setEnabled(runtime_lock);
|
||||||
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
|
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
|
||||||
ui->disable_macro_jit->setEnabled(runtime_lock);
|
ui->disable_macro_jit->setEnabled(runtime_lock);
|
||||||
ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit);
|
ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue());
|
||||||
ui->extended_logging->setChecked(Settings::values.extended_logging);
|
ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDebug::ApplyConfiguration() {
|
void ConfigureDebug::ApplyConfiguration() {
|
||||||
|
@ -61,7 +62,7 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||||
Settings::values.extended_logging = ui->extended_logging->isChecked();
|
Settings::values.extended_logging = ui->extended_logging->isChecked();
|
||||||
Debugger::ToggleConsole();
|
Debugger::ToggleConsole();
|
||||||
Common::Log::Filter filter;
|
Common::Log::Filter filter;
|
||||||
filter.ParseFilterString(Settings::values.log_filter);
|
filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
||||||
Common::Log::SetGlobalFilter(filter);
|
Common::Log::SetGlobalFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,18 +43,19 @@ void ConfigureFilesystem::setConfiguration() {
|
||||||
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir)));
|
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir)));
|
||||||
ui->sdmc_directory_edit->setText(
|
ui->sdmc_directory_edit->setText(
|
||||||
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::SDMCDir)));
|
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::SDMCDir)));
|
||||||
ui->gamecard_path_edit->setText(QString::fromStdString(Settings::values.gamecard_path));
|
ui->gamecard_path_edit->setText(
|
||||||
|
QString::fromStdString(Settings::values.gamecard_path.GetValue()));
|
||||||
ui->dump_path_edit->setText(
|
ui->dump_path_edit->setText(
|
||||||
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir)));
|
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir)));
|
||||||
ui->load_path_edit->setText(
|
ui->load_path_edit->setText(
|
||||||
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir)));
|
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir)));
|
||||||
|
|
||||||
ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted);
|
ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted.GetValue());
|
||||||
ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game);
|
ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game.GetValue());
|
||||||
ui->dump_exefs->setChecked(Settings::values.dump_exefs);
|
ui->dump_exefs->setChecked(Settings::values.dump_exefs.GetValue());
|
||||||
ui->dump_nso->setChecked(Settings::values.dump_nso);
|
ui->dump_nso->setChecked(Settings::values.dump_nso.GetValue());
|
||||||
|
|
||||||
ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
|
ui->cache_game_list->setChecked(UISettings::values.cache_game_list.GetValue());
|
||||||
|
|
||||||
UpdateEnabledControls();
|
UpdateEnabledControls();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,10 @@ void ConfigureGeneral::SetConfiguration() {
|
||||||
ui->use_multi_core->setEnabled(runtime_lock);
|
ui->use_multi_core->setEnabled(runtime_lock);
|
||||||
ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
|
ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
|
||||||
|
|
||||||
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
|
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
|
||||||
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
|
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
|
||||||
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
|
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
|
||||||
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse);
|
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
|
||||||
|
|
||||||
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
|
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
|
||||||
ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
|
ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
|
||||||
|
|
|
@ -148,12 +148,12 @@ void ConfigureInputAdvanced::LoadConfiguration() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
|
ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled.GetValue());
|
||||||
ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
|
ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue());
|
||||||
ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
|
ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue());
|
||||||
ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard);
|
ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue());
|
||||||
ui->mouse_panning->setChecked(Settings::values.mouse_panning);
|
ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue());
|
||||||
ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity);
|
ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue());
|
||||||
ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
|
ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
|
||||||
|
|
||||||
UpdateUIEnabled();
|
UpdateUIEnabled();
|
||||||
|
|
|
@ -101,15 +101,16 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
|
||||||
ConfigureMotionTouch::~ConfigureMotionTouch() = default;
|
ConfigureMotionTouch::~ConfigureMotionTouch() = default;
|
||||||
|
|
||||||
void ConfigureMotionTouch::SetConfiguration() {
|
void ConfigureMotionTouch::SetConfiguration() {
|
||||||
const Common::ParamPackage motion_param(Settings::values.motion_device);
|
const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue());
|
||||||
const Common::ParamPackage touch_param(Settings::values.touch_device);
|
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
|
||||||
|
|
||||||
ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button);
|
ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue());
|
||||||
touch_from_button_maps = Settings::values.touch_from_button_maps;
|
touch_from_button_maps = Settings::values.touch_from_button_maps;
|
||||||
for (const auto& touch_map : touch_from_button_maps) {
|
for (const auto& touch_map : touch_from_button_maps) {
|
||||||
ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
|
ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
|
||||||
}
|
}
|
||||||
ui->touch_from_button_map->setCurrentIndex(Settings::values.touch_from_button_map_index);
|
ui->touch_from_button_map->setCurrentIndex(
|
||||||
|
Settings::values.touch_from_button_map_index.GetValue());
|
||||||
ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
|
ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
|
||||||
|
|
||||||
min_x = touch_param.Get("min_x", 100);
|
min_x = touch_param.Get("min_x", 100);
|
||||||
|
@ -124,7 +125,7 @@ void ConfigureMotionTouch::SetConfiguration() {
|
||||||
udp_server_list_model->setStringList({});
|
udp_server_list_model->setStringList({});
|
||||||
ui->udp_server_list->setModel(udp_server_list_model);
|
ui->udp_server_list->setModel(udp_server_list_model);
|
||||||
|
|
||||||
std::stringstream ss(Settings::values.udp_input_servers);
|
std::stringstream ss(Settings::values.udp_input_servers.GetValue());
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
while (std::getline(ss, token, ',')) {
|
while (std::getline(ss, token, ',')) {
|
||||||
|
|
|
@ -166,7 +166,7 @@ void ConfigureProfileManager::PopulateUserList() {
|
||||||
void ConfigureProfileManager::UpdateCurrentUser() {
|
void ConfigureProfileManager::UpdateCurrentUser() {
|
||||||
ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS);
|
ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS);
|
||||||
|
|
||||||
const auto& current_user = profile_manager->GetUser(Settings::values.current_user);
|
const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
|
||||||
ASSERT(current_user);
|
ASSERT(current_user);
|
||||||
const auto username = GetAccountUsername(*profile_manager, *current_user);
|
const auto username = GetAccountUsername(*profile_manager, *current_user);
|
||||||
|
|
||||||
|
@ -245,15 +245,18 @@ void ConfigureProfileManager::DeleteUser() {
|
||||||
this, tr("Confirm Delete"),
|
this, tr("Confirm Delete"),
|
||||||
tr("You are about to delete user with name \"%1\". Are you sure?").arg(username));
|
tr("You are about to delete user with name \"%1\". Are you sure?").arg(username));
|
||||||
|
|
||||||
if (confirm == QMessageBox::No)
|
if (confirm == QMessageBox::No) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings::values.current_user == tree_view->currentIndex().row())
|
if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) {
|
||||||
Settings::values.current_user = 0;
|
Settings::values.current_user = 0;
|
||||||
|
}
|
||||||
UpdateCurrentUser();
|
UpdateCurrentUser();
|
||||||
|
|
||||||
if (!profile_manager->RemoveUser(*uuid))
|
if (!profile_manager->RemoveUser(*uuid)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
item_model->removeRows(tree_view->currentIndex().row(), 1);
|
item_model->removeRows(tree_view->currentIndex().row(), 1);
|
||||||
tree_view->clearSelection();
|
tree_view->clearSelection();
|
||||||
|
|
|
@ -65,7 +65,7 @@ void ConfigureService::RetranslateUi() {
|
||||||
|
|
||||||
void ConfigureService::SetConfiguration() {
|
void ConfigureService::SetConfiguration() {
|
||||||
const int index =
|
const int index =
|
||||||
ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend));
|
ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
|
||||||
ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
|
ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,11 +113,12 @@ void ConfigureUi::SetConfiguration() {
|
||||||
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
|
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
|
||||||
ui->language_combobox->setCurrentIndex(
|
ui->language_combobox->setCurrentIndex(
|
||||||
ui->language_combobox->findData(UISettings::values.language));
|
ui->language_combobox->findData(UISettings::values.language));
|
||||||
ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
|
ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
|
||||||
ui->icon_size_combobox->setCurrentIndex(
|
ui->icon_size_combobox->setCurrentIndex(
|
||||||
ui->icon_size_combobox->findData(UISettings::values.icon_size));
|
ui->icon_size_combobox->findData(UISettings::values.icon_size.GetValue()));
|
||||||
|
|
||||||
ui->enable_screenshot_save_as->setChecked(UISettings::values.enable_screenshot_save_as);
|
ui->enable_screenshot_save_as->setChecked(
|
||||||
|
UISettings::values.enable_screenshot_save_as.GetValue());
|
||||||
ui->screenshot_path_edit->setText(QString::fromStdString(
|
ui->screenshot_path_edit->setText(QString::fromStdString(
|
||||||
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)));
|
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)));
|
||||||
}
|
}
|
||||||
|
@ -178,7 +179,7 @@ void ConfigureUi::InitializeRowComboBoxes() {
|
||||||
|
|
||||||
void ConfigureUi::UpdateFirstRowComboBox(bool init) {
|
void ConfigureUi::UpdateFirstRowComboBox(bool init) {
|
||||||
const int currentIndex =
|
const int currentIndex =
|
||||||
init ? UISettings::values.row_1_text_id
|
init ? UISettings::values.row_1_text_id.GetValue()
|
||||||
: ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
|
: ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
|
||||||
|
|
||||||
ui->row_1_text_combobox->clear();
|
ui->row_1_text_combobox->clear();
|
||||||
|
@ -197,7 +198,7 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
|
||||||
|
|
||||||
void ConfigureUi::UpdateSecondRowComboBox(bool init) {
|
void ConfigureUi::UpdateSecondRowComboBox(bool init) {
|
||||||
const int currentIndex =
|
const int currentIndex =
|
||||||
init ? UISettings::values.row_2_text_id
|
init ? UISettings::values.row_2_text_id.GetValue()
|
||||||
: ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
|
: ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
|
||||||
|
|
||||||
ui->row_2_text_combobox->clear();
|
ui->row_2_text_combobox->clear();
|
||||||
|
|
|
@ -88,22 +88,22 @@ void ConfigureWeb::SetConfiguration() {
|
||||||
ui->web_signup_link->setOpenExternalLinks(true);
|
ui->web_signup_link->setOpenExternalLinks(true);
|
||||||
ui->web_token_info_link->setOpenExternalLinks(true);
|
ui->web_token_info_link->setOpenExternalLinks(true);
|
||||||
|
|
||||||
if (Settings::values.yuzu_username.empty()) {
|
if (Settings::values.yuzu_username.GetValue().empty()) {
|
||||||
ui->username->setText(tr("Unspecified"));
|
ui->username->setText(tr("Unspecified"));
|
||||||
} else {
|
} else {
|
||||||
ui->username->setText(QString::fromStdString(Settings::values.yuzu_username));
|
ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry);
|
ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry.GetValue());
|
||||||
ui->edit_token->setText(QString::fromStdString(
|
ui->edit_token->setText(QString::fromStdString(GenerateDisplayToken(
|
||||||
GenerateDisplayToken(Settings::values.yuzu_username, Settings::values.yuzu_token)));
|
Settings::values.yuzu_username.GetValue(), Settings::values.yuzu_token.GetValue())));
|
||||||
|
|
||||||
// Connect after setting the values, to avoid calling OnLoginChanged now
|
// Connect after setting the values, to avoid calling OnLoginChanged now
|
||||||
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
|
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
|
||||||
|
|
||||||
user_verified = true;
|
user_verified = true;
|
||||||
|
|
||||||
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence);
|
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::ApplyConfiguration() {
|
void ConfigureWeb::ApplyConfiguration() {
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
void ToggleConsole() {
|
void ToggleConsole() {
|
||||||
static bool console_shown = false;
|
static bool console_shown = false;
|
||||||
if (console_shown == UISettings::values.show_console) {
|
if (console_shown == UISettings::values.show_console.GetValue()) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
console_shown = UISettings::values.show_console;
|
console_shown = UISettings::values.show_console.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(_DEBUG)
|
#if defined(_WIN32) && !defined(_DEBUG)
|
||||||
|
|
|
@ -244,7 +244,8 @@ void GameList::OnUpdateThemedIcons() {
|
||||||
for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) {
|
for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) {
|
||||||
QStandardItem* child = item_model->invisibleRootItem()->child(i);
|
QStandardItem* child = item_model->invisibleRootItem()->child(i);
|
||||||
|
|
||||||
const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
|
const int icon_size =
|
||||||
|
std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
|
||||||
switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) {
|
switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) {
|
||||||
case GameListItemType::SdmcDir:
|
case GameListItemType::SdmcDir:
|
||||||
child->setData(
|
child->setData(
|
||||||
|
|
|
@ -80,7 +80,7 @@ public:
|
||||||
setData(qulonglong(program_id), ProgramIdRole);
|
setData(qulonglong(program_id), ProgramIdRole);
|
||||||
setData(game_type, FileTypeRole);
|
setData(game_type, FileTypeRole);
|
||||||
|
|
||||||
const u32 size = UISettings::values.icon_size;
|
const u32 size = UISettings::values.icon_size.GetValue();
|
||||||
|
|
||||||
QPixmap picture;
|
QPixmap picture;
|
||||||
if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
|
if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
|
||||||
|
@ -108,8 +108,8 @@ public:
|
||||||
data(TitleRole).toString(),
|
data(TitleRole).toString(),
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
|
const auto& row1 = row_data.at(UISettings::values.row_1_text_id.GetValue());
|
||||||
const int row2_id = UISettings::values.row_2_text_id;
|
const int row2_id = UISettings::values.row_2_text_id.GetValue();
|
||||||
|
|
||||||
if (role == SortRole) {
|
if (role == SortRole) {
|
||||||
return row1.toLower();
|
return row1.toLower();
|
||||||
|
@ -233,7 +233,8 @@ public:
|
||||||
UISettings::GameDir* game_dir = &directory;
|
UISettings::GameDir* game_dir = &directory;
|
||||||
setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole);
|
setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole);
|
||||||
|
|
||||||
const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
|
const int icon_size =
|
||||||
|
std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
|
||||||
switch (dir_type) {
|
switch (dir_type) {
|
||||||
case GameListItemType::SdmcDir:
|
case GameListItemType::SdmcDir:
|
||||||
setData(
|
setData(
|
||||||
|
@ -294,7 +295,8 @@ public:
|
||||||
explicit GameListAddDir() {
|
explicit GameListAddDir() {
|
||||||
setData(type(), TypeRole);
|
setData(type(), TypeRole);
|
||||||
|
|
||||||
const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
|
const int icon_size =
|
||||||
|
std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
|
||||||
setData(QIcon::fromTheme(QStringLiteral("plus"))
|
setData(QIcon::fromTheme(QStringLiteral("plus"))
|
||||||
.pixmap(icon_size)
|
.pixmap(icon_size)
|
||||||
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
|
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
|
||||||
|
@ -316,7 +318,8 @@ public:
|
||||||
explicit GameListFavorites() {
|
explicit GameListFavorites() {
|
||||||
setData(type(), TypeRole);
|
setData(type(), TypeRole);
|
||||||
|
|
||||||
const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
|
const int icon_size =
|
||||||
|
std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
|
||||||
setData(QIcon::fromTheme(QStringLiteral("star"))
|
setData(QIcon::fromTheme(QStringLiteral("star"))
|
||||||
.pixmap(icon_size)
|
.pixmap(icon_size)
|
||||||
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
|
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
|
||||||
|
|
|
@ -156,11 +156,13 @@ enum class CalloutFlag : uint32_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
void GMainWindow::ShowTelemetryCallout() {
|
void GMainWindow::ShowTelemetryCallout() {
|
||||||
if (UISettings::values.callout_flags & static_cast<uint32_t>(CalloutFlag::Telemetry)) {
|
if (UISettings::values.callout_flags.GetValue() &
|
||||||
|
static_cast<uint32_t>(CalloutFlag::Telemetry)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UISettings::values.callout_flags |= static_cast<uint32_t>(CalloutFlag::Telemetry);
|
UISettings::values.callout_flags =
|
||||||
|
UISettings::values.callout_flags.GetValue() | static_cast<uint32_t>(CalloutFlag::Telemetry);
|
||||||
const QString telemetry_message =
|
const QString telemetry_message =
|
||||||
tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
|
tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
|
||||||
"data is collected</a> to help improve yuzu. "
|
"data is collected</a> to help improve yuzu. "
|
||||||
|
@ -177,7 +179,7 @@ static void InitializeLogging() {
|
||||||
using namespace Common;
|
using namespace Common;
|
||||||
|
|
||||||
Log::Filter log_filter;
|
Log::Filter log_filter;
|
||||||
log_filter.ParseFilterString(Settings::values.log_filter);
|
log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
||||||
Log::SetGlobalFilter(log_filter);
|
Log::SetGlobalFilter(log_filter);
|
||||||
|
|
||||||
const auto log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir);
|
const auto log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir);
|
||||||
|
@ -216,7 +218,7 @@ GMainWindow::GMainWindow()
|
||||||
default_theme_paths = QIcon::themeSearchPaths();
|
default_theme_paths = QIcon::themeSearchPaths();
|
||||||
UpdateUITheme();
|
UpdateUITheme();
|
||||||
|
|
||||||
SetDiscordEnabled(UISettings::values.enable_discord_presence);
|
SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
|
||||||
discord_rpc->Update();
|
discord_rpc->Update();
|
||||||
|
|
||||||
RegisterMetaTypes();
|
RegisterMetaTypes();
|
||||||
|
@ -1060,23 +1062,24 @@ void GMainWindow::RestoreUIState() {
|
||||||
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
||||||
#if MICROPROFILE_ENABLED
|
#if MICROPROFILE_ENABLED
|
||||||
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
|
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
|
||||||
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
|
microProfileDialog->setVisible(UISettings::values.microprofile_visible.GetValue());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
game_list->LoadInterfaceLayout();
|
game_list->LoadInterfaceLayout();
|
||||||
|
|
||||||
ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
|
ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode.GetValue());
|
||||||
ToggleWindowMode();
|
ToggleWindowMode();
|
||||||
|
|
||||||
ui.action_Fullscreen->setChecked(UISettings::values.fullscreen);
|
ui.action_Fullscreen->setChecked(UISettings::values.fullscreen.GetValue());
|
||||||
|
|
||||||
ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
|
ui.action_Display_Dock_Widget_Headers->setChecked(
|
||||||
|
UISettings::values.display_titlebar.GetValue());
|
||||||
OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
|
OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
|
||||||
|
|
||||||
ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar);
|
ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar.GetValue());
|
||||||
game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked());
|
game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked());
|
||||||
|
|
||||||
ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
|
ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
|
||||||
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
|
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
|
||||||
Debugger::ToggleConsole();
|
Debugger::ToggleConsole();
|
||||||
}
|
}
|
||||||
|
@ -1243,13 +1246,14 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
|
||||||
const Core::System::ResultStatus result{
|
const Core::System::ResultStatus result{
|
||||||
system.Load(*render_window, filename.toStdString(), program_index)};
|
system.Load(*render_window, filename.toStdString(), program_index)};
|
||||||
|
|
||||||
const auto drd_callout =
|
const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
|
||||||
(UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
|
static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
|
||||||
|
|
||||||
if (result == Core::System::ResultStatus::Success &&
|
if (result == Core::System::ResultStatus::Success &&
|
||||||
system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory &&
|
system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory &&
|
||||||
drd_callout) {
|
drd_callout) {
|
||||||
UISettings::values.callout_flags |= static_cast<u32>(CalloutFlag::DRDDeprecation);
|
UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() |
|
||||||
|
static_cast<u32>(CalloutFlag::DRDDeprecation);
|
||||||
QMessageBox::warning(
|
QMessageBox::warning(
|
||||||
this, tr("Warning Outdated Game Format"),
|
this, tr("Warning Outdated Game Format"),
|
||||||
tr("You are using the deconstructed ROM directory format for this game, which is an "
|
tr("You are using the deconstructed ROM directory format for this game, which is an "
|
||||||
|
@ -2453,7 +2457,8 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnMenuReportCompatibility() {
|
void GMainWindow::OnMenuReportCompatibility() {
|
||||||
if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) {
|
if (!Settings::values.yuzu_token.GetValue().empty() &&
|
||||||
|
!Settings::values.yuzu_username.GetValue().empty()) {
|
||||||
CompatDB compatdb{this};
|
CompatDB compatdb{this};
|
||||||
compatdb.exec();
|
compatdb.exec();
|
||||||
} else {
|
} else {
|
||||||
|
@ -2618,7 +2623,7 @@ void GMainWindow::ResetWindowSize1080() {
|
||||||
|
|
||||||
void GMainWindow::OnConfigure() {
|
void GMainWindow::OnConfigure() {
|
||||||
const auto old_theme = UISettings::values.theme;
|
const auto old_theme = UISettings::values.theme;
|
||||||
const bool old_discord_presence = UISettings::values.enable_discord_presence;
|
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
|
||||||
|
|
||||||
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
|
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
|
||||||
connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
|
connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
|
||||||
|
@ -2675,8 +2680,8 @@ void GMainWindow::OnConfigure() {
|
||||||
if (UISettings::values.theme != old_theme) {
|
if (UISettings::values.theme != old_theme) {
|
||||||
UpdateUITheme();
|
UpdateUITheme();
|
||||||
}
|
}
|
||||||
if (UISettings::values.enable_discord_presence != old_discord_presence) {
|
if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) {
|
||||||
SetDiscordEnabled(UISettings::values.enable_discord_presence);
|
SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
|
||||||
}
|
}
|
||||||
emit UpdateThemedIcons();
|
emit UpdateThemedIcons();
|
||||||
|
|
||||||
|
@ -2832,7 +2837,8 @@ void GMainWindow::OnCaptureScreenshot() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, filename);
|
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor.GetValue(),
|
||||||
|
filename);
|
||||||
OnStartGame();
|
OnStartGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/settings.h"
|
||||||
|
|
||||||
namespace UISettings {
|
namespace UISettings {
|
||||||
|
|
||||||
|
@ -48,26 +49,26 @@ struct Values {
|
||||||
QByteArray gamelist_header_state;
|
QByteArray gamelist_header_state;
|
||||||
|
|
||||||
QByteArray microprofile_geometry;
|
QByteArray microprofile_geometry;
|
||||||
bool microprofile_visible;
|
Settings::BasicSetting<bool> microprofile_visible{false, "microProfileDialogVisible"};
|
||||||
|
|
||||||
bool single_window_mode;
|
Settings::BasicSetting<bool> single_window_mode{true, "singleWindowMode"};
|
||||||
bool fullscreen;
|
Settings::BasicSetting<bool> fullscreen{false, "fullscreen"};
|
||||||
bool display_titlebar;
|
Settings::BasicSetting<bool> display_titlebar{true, "displayTitleBars"};
|
||||||
bool show_filter_bar;
|
Settings::BasicSetting<bool> show_filter_bar{true, "showFilterBar"};
|
||||||
bool show_status_bar;
|
Settings::BasicSetting<bool> show_status_bar{true, "showStatusBar"};
|
||||||
|
|
||||||
bool confirm_before_closing;
|
Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"};
|
||||||
bool first_start;
|
Settings::BasicSetting<bool> first_start{true, "firstStart"};
|
||||||
bool pause_when_in_background;
|
Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
|
||||||
bool hide_mouse;
|
Settings::BasicSetting<bool> hide_mouse{false, "hideInactiveMouse"};
|
||||||
|
|
||||||
bool select_user_on_boot;
|
Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"};
|
||||||
|
|
||||||
// Discord RPC
|
// Discord RPC
|
||||||
bool enable_discord_presence;
|
Settings::BasicSetting<bool> enable_discord_presence{true, "enable_discord_presence"};
|
||||||
|
|
||||||
bool enable_screenshot_save_as;
|
Settings::BasicSetting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
|
||||||
u16 screenshot_resolution_factor;
|
Settings::BasicSetting<u16> screenshot_resolution_factor{0, "screenshot_resolution_factor"};
|
||||||
|
|
||||||
QString roms_path;
|
QString roms_path;
|
||||||
QString symbols_path;
|
QString symbols_path;
|
||||||
|
@ -83,18 +84,18 @@ struct Values {
|
||||||
// Shortcut name <Shortcut, context>
|
// Shortcut name <Shortcut, context>
|
||||||
std::vector<Shortcut> shortcuts;
|
std::vector<Shortcut> shortcuts;
|
||||||
|
|
||||||
uint32_t callout_flags;
|
Settings::BasicSetting<uint32_t> callout_flags{0, "calloutFlags"};
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
bool show_console;
|
Settings::BasicSetting<bool> show_console{false, "showConsole"};
|
||||||
|
|
||||||
// Game List
|
// Game List
|
||||||
bool show_add_ons;
|
Settings::BasicSetting<bool> show_add_ons{true, "show_add_ons"};
|
||||||
uint32_t icon_size;
|
Settings::BasicSetting<uint32_t> icon_size{64, "icon_size"};
|
||||||
uint8_t row_1_text_id;
|
Settings::BasicSetting<uint8_t> row_1_text_id{3, "row_1_text_id"};
|
||||||
uint8_t row_2_text_id;
|
Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"};
|
||||||
std::atomic_bool is_game_list_reload_pending{false};
|
std::atomic_bool is_game_list_reload_pending{false};
|
||||||
bool cache_game_list;
|
Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"};
|
||||||
|
|
||||||
bool configuration_applied;
|
bool configuration_applied;
|
||||||
bool reset_to_defaults;
|
bool reset_to_defaults;
|
||||||
|
|
|
@ -241,6 +241,24 @@ static const std::array<int, 8> keyboard_mods{
|
||||||
SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI,
|
SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void Config::ReadSetting(const std::string& group, Settings::BasicSetting<float>& setting) {
|
||||||
|
setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) {
|
||||||
|
setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool>& setting) {
|
||||||
|
setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
||||||
|
}
|
||||||
|
template <typename Type>
|
||||||
|
void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting) {
|
||||||
|
setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
|
||||||
|
static_cast<long>(setting.GetDefault())));
|
||||||
|
}
|
||||||
|
|
||||||
void Config::ReadValues() {
|
void Config::ReadValues() {
|
||||||
// Controls
|
// Controls
|
||||||
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||||
|
@ -264,8 +282,7 @@ void Config::ReadValues() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::values.mouse_enabled =
|
ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "mouse_enabled", false);
|
|
||||||
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
|
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
|
||||||
std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
|
std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
|
||||||
Settings::values.mouse_buttons[i] = sdl2_config->Get(
|
Settings::values.mouse_buttons[i] = sdl2_config->Get(
|
||||||
|
@ -275,14 +292,11 @@ void Config::ReadValues() {
|
||||||
Settings::values.mouse_buttons[i] = default_param;
|
Settings::values.mouse_buttons[i] = default_param;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::values.motion_device = sdl2_config->Get(
|
ReadSetting("ControlsGeneral", Settings::values.motion_device);
|
||||||
"ControlsGeneral", "motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01");
|
|
||||||
|
|
||||||
Settings::values.keyboard_enabled =
|
ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "keyboard_enabled", false);
|
|
||||||
|
|
||||||
Settings::values.debug_pad_enabled =
|
ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "debug_pad_enabled", false);
|
|
||||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||||
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||||
Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
|
Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
|
||||||
|
@ -303,12 +317,9 @@ void Config::ReadValues() {
|
||||||
Settings::values.debug_pad_analogs[i] = default_param;
|
Settings::values.debug_pad_analogs[i] = default_param;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::values.vibration_enabled.SetValue(
|
ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true));
|
ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
|
||||||
Settings::values.enable_accurate_vibrations.SetValue(
|
ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "enable_accurate_vibrations", false));
|
|
||||||
Settings::values.motion_enabled.SetValue(
|
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
|
|
||||||
Settings::values.touchscreen.enabled =
|
Settings::values.touchscreen.enabled =
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
|
sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
|
||||||
Settings::values.touchscreen.rotation_angle =
|
Settings::values.touchscreen.rotation_angle =
|
||||||
|
@ -349,13 +360,11 @@ void Config::ReadValues() {
|
||||||
Settings::TouchFromButtonMap{"default", {}});
|
Settings::TouchFromButtonMap{"default", {}});
|
||||||
num_touch_from_button_maps = 1;
|
num_touch_from_button_maps = 1;
|
||||||
}
|
}
|
||||||
Settings::values.use_touch_from_button =
|
ReadSetting("ControlsGeneral", Settings::values.use_touch_from_button);
|
||||||
sdl2_config->GetBoolean("ControlsGeneral", "use_touch_from_button", false);
|
Settings::values.touch_from_button_map_index = std::clamp(
|
||||||
Settings::values.touch_from_button_map_index =
|
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
|
||||||
std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
|
|
||||||
|
|
||||||
Settings::values.udp_input_servers =
|
ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
|
||||||
sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_SRV);
|
|
||||||
|
|
||||||
std::transform(keyboard_keys.begin(), keyboard_keys.end(),
|
std::transform(keyboard_keys.begin(), keyboard_keys.end(),
|
||||||
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
|
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
|
||||||
|
@ -367,8 +376,7 @@ void Config::ReadValues() {
|
||||||
Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
|
Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
|
||||||
|
|
||||||
// Data Storage
|
// Data Storage
|
||||||
Settings::values.use_virtual_sd =
|
ReadSetting("Data Storage", Settings::values.use_virtual_sd);
|
||||||
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
|
|
||||||
FS::SetYuzuPath(FS::YuzuPath::NANDDir,
|
FS::SetYuzuPath(FS::YuzuPath::NANDDir,
|
||||||
sdl2_config->Get("Data Storage", "nand_directory",
|
sdl2_config->Get("Data Storage", "nand_directory",
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
|
FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
|
||||||
|
@ -381,18 +389,16 @@ void Config::ReadValues() {
|
||||||
FS::SetYuzuPath(FS::YuzuPath::DumpDir,
|
FS::SetYuzuPath(FS::YuzuPath::DumpDir,
|
||||||
sdl2_config->Get("Data Storage", "dump_directory",
|
sdl2_config->Get("Data Storage", "dump_directory",
|
||||||
FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
|
FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
|
||||||
Settings::values.gamecard_inserted =
|
ReadSetting("Data Storage", Settings::values.gamecard_inserted);
|
||||||
sdl2_config->GetBoolean("Data Storage", "gamecard_inserted", false);
|
ReadSetting("Data Storage", Settings::values.gamecard_current_game);
|
||||||
Settings::values.gamecard_current_game =
|
ReadSetting("Data Storage", Settings::values.gamecard_path);
|
||||||
sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
|
|
||||||
Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
|
|
||||||
|
|
||||||
// System
|
// System
|
||||||
Settings::values.use_docked_mode.SetValue(
|
ReadSetting("System", Settings::values.use_docked_mode);
|
||||||
sdl2_config->GetBoolean("System", "use_docked_mode", true));
|
|
||||||
|
|
||||||
Settings::values.current_user = std::clamp<int>(
|
ReadSetting("System", Settings::values.current_user);
|
||||||
sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1);
|
Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
|
||||||
|
Service::Account::MAX_USERS - 1);
|
||||||
|
|
||||||
const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
|
const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
|
||||||
if (rng_seed_enabled) {
|
if (rng_seed_enabled) {
|
||||||
|
@ -409,89 +415,60 @@ void Config::ReadValues() {
|
||||||
Settings::values.custom_rtc = std::nullopt;
|
Settings::values.custom_rtc = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::values.language_index.SetValue(
|
ReadSetting("System", Settings::values.language_index);
|
||||||
sdl2_config->GetInteger("System", "language_index", 1));
|
ReadSetting("System", Settings::values.time_zone_index);
|
||||||
Settings::values.time_zone_index.SetValue(
|
|
||||||
sdl2_config->GetInteger("System", "time_zone_index", 0));
|
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
Settings::values.use_multi_core.SetValue(
|
ReadSetting("Core", Settings::values.use_multi_core);
|
||||||
sdl2_config->GetBoolean("Core", "use_multi_core", true));
|
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
const int renderer_backend = sdl2_config->GetInteger(
|
ReadSetting("Renderer", Settings::values.renderer_backend);
|
||||||
"Renderer", "backend", static_cast<int>(Settings::RendererBackend::OpenGL));
|
ReadSetting("Renderer", Settings::values.renderer_debug);
|
||||||
Settings::values.renderer_backend.SetValue(
|
ReadSetting("Renderer", Settings::values.vulkan_device);
|
||||||
static_cast<Settings::RendererBackend>(renderer_backend));
|
|
||||||
Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false);
|
|
||||||
Settings::values.vulkan_device.SetValue(
|
|
||||||
sdl2_config->GetInteger("Renderer", "vulkan_device", 0));
|
|
||||||
|
|
||||||
Settings::values.aspect_ratio.SetValue(
|
ReadSetting("Renderer", Settings::values.aspect_ratio);
|
||||||
static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)));
|
ReadSetting("Renderer", Settings::values.max_anisotropy);
|
||||||
Settings::values.max_anisotropy.SetValue(
|
ReadSetting("Renderer", Settings::values.use_frame_limit);
|
||||||
static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)));
|
ReadSetting("Renderer", Settings::values.frame_limit);
|
||||||
Settings::values.use_frame_limit.SetValue(
|
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
||||||
sdl2_config->GetBoolean("Renderer", "use_frame_limit", true));
|
ReadSetting("Renderer", Settings::values.gpu_accuracy);
|
||||||
Settings::values.frame_limit.SetValue(
|
ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
|
||||||
static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)));
|
ReadSetting("Renderer", Settings::values.use_vsync);
|
||||||
Settings::values.use_disk_shader_cache.SetValue(
|
ReadSetting("Renderer", Settings::values.disable_fps_limit);
|
||||||
sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false));
|
ReadSetting("Renderer", Settings::values.use_assembly_shaders);
|
||||||
const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 1);
|
ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
|
||||||
Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
|
ReadSetting("Renderer", Settings::values.use_nvdec_emulation);
|
||||||
Settings::values.use_asynchronous_gpu_emulation.SetValue(
|
ReadSetting("Renderer", Settings::values.accelerate_astc);
|
||||||
sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", true));
|
ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
|
||||||
Settings::values.use_vsync.SetValue(
|
|
||||||
static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
|
|
||||||
Settings::values.disable_fps_limit.SetValue(
|
|
||||||
sdl2_config->GetBoolean("Renderer", "disable_fps_limit", false));
|
|
||||||
Settings::values.use_assembly_shaders.SetValue(
|
|
||||||
sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", true));
|
|
||||||
Settings::values.use_asynchronous_shaders.SetValue(
|
|
||||||
sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false));
|
|
||||||
Settings::values.use_nvdec_emulation.SetValue(
|
|
||||||
sdl2_config->GetBoolean("Renderer", "use_nvdec_emulation", true));
|
|
||||||
Settings::values.accelerate_astc.SetValue(
|
|
||||||
sdl2_config->GetBoolean("Renderer", "accelerate_astc", true));
|
|
||||||
Settings::values.use_fast_gpu_time.SetValue(
|
|
||||||
sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
|
|
||||||
|
|
||||||
Settings::values.bg_red.SetValue(
|
ReadSetting("Renderer", Settings::values.bg_red);
|
||||||
static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
|
ReadSetting("Renderer", Settings::values.bg_green);
|
||||||
Settings::values.bg_green.SetValue(
|
ReadSetting("Renderer", Settings::values.bg_blue);
|
||||||
static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
|
|
||||||
Settings::values.bg_blue.SetValue(
|
|
||||||
static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
|
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
|
ReadSetting("Audio", Settings::values.sink_id);
|
||||||
Settings::values.enable_audio_stretching.SetValue(
|
ReadSetting("Audio", Settings::values.enable_audio_stretching);
|
||||||
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true));
|
ReadSetting("Audio", Settings::values.audio_device_id);
|
||||||
Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
|
ReadSetting("Audio", Settings::values.volume);
|
||||||
Settings::values.volume.SetValue(
|
|
||||||
static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)));
|
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
|
// log_filter has a different default here than from common
|
||||||
Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false);
|
Settings::values.log_filter =
|
||||||
|
sdl2_config->Get("Miscellaneous", Settings::values.log_filter.GetLabel(), "*:Trace");
|
||||||
|
ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
Settings::values.record_frame_times =
|
Settings::values.record_frame_times =
|
||||||
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
||||||
Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
|
ReadSetting("Debugging", Settings::values.program_args);
|
||||||
Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
|
ReadSetting("Debugging", Settings::values.dump_exefs);
|
||||||
Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
|
ReadSetting("Debugging", Settings::values.dump_nso);
|
||||||
Settings::values.enable_fs_access_log =
|
ReadSetting("Debugging", Settings::values.enable_fs_access_log);
|
||||||
sdl2_config->GetBoolean("Debugging", "enable_fs_access_log", false);
|
ReadSetting("Debugging", Settings::values.reporting_services);
|
||||||
Settings::values.reporting_services =
|
ReadSetting("Debugging", Settings::values.quest_flag);
|
||||||
sdl2_config->GetBoolean("Debugging", "reporting_services", false);
|
ReadSetting("Debugging", Settings::values.use_debug_asserts);
|
||||||
Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
|
ReadSetting("Debugging", Settings::values.use_auto_stub);
|
||||||
Settings::values.use_debug_asserts =
|
ReadSetting("Debugging", Settings::values.disable_macro_jit);
|
||||||
sdl2_config->GetBoolean("Debugging", "use_debug_asserts", false);
|
|
||||||
Settings::values.use_auto_stub = sdl2_config->GetBoolean("Debugging", "use_auto_stub", false);
|
|
||||||
|
|
||||||
Settings::values.disable_macro_jit =
|
|
||||||
sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
|
|
||||||
|
|
||||||
const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
|
const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
|
||||||
std::stringstream ss(title_list);
|
std::stringstream ss(title_list);
|
||||||
|
@ -511,17 +488,14 @@ void Config::ReadValues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web Service
|
// Web Service
|
||||||
Settings::values.enable_telemetry =
|
ReadSetting("WebService", Settings::values.enable_telemetry);
|
||||||
sdl2_config->GetBoolean("WebService", "enable_telemetry", true);
|
ReadSetting("WebService", Settings::values.web_api_url);
|
||||||
Settings::values.web_api_url =
|
ReadSetting("WebService", Settings::values.yuzu_username);
|
||||||
sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org");
|
ReadSetting("WebService", Settings::values.yuzu_token);
|
||||||
Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", "");
|
|
||||||
Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", "");
|
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "none");
|
ReadSetting("Services", Settings::values.bcat_backend);
|
||||||
Settings::values.bcat_boxcat_local =
|
ReadSetting("Services", Settings::values.bcat_boxcat_local);
|
||||||
sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::Reload() {
|
void Config::Reload() {
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
|
|
||||||
class INIReader;
|
class INIReader;
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
|
@ -22,4 +24,14 @@ public:
|
||||||
~Config();
|
~Config();
|
||||||
|
|
||||||
void Reload();
|
void Reload();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Applies a value read from the sdl2_config to a BasicSetting.
|
||||||
|
*
|
||||||
|
* @param group The name of the INI group
|
||||||
|
* @param setting The yuzu setting to modify
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
void ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting);
|
||||||
};
|
};
|
||||||
|
|
|
@ -78,7 +78,7 @@ static void InitializeLogging() {
|
||||||
using namespace Common;
|
using namespace Common;
|
||||||
|
|
||||||
Log::Filter log_filter(Log::Level::Debug);
|
Log::Filter log_filter(Log::Level::Debug);
|
||||||
log_filter.ParseFilterString(Settings::values.log_filter);
|
log_filter.ParseFilterString(static_cast<std::string>(Settings::values.log_filter));
|
||||||
Log::SetGlobalFilter(log_filter);
|
Log::SetGlobalFilter(log_filter);
|
||||||
|
|
||||||
Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
|
Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
|
||||||
|
|
Loading…
Reference in a new issue