Compare commits

..

28 Commits

Author SHA1 Message Date
Merry
40e39ddd46 dynarmic: Abort watchpoints ASAP 2022-07-15 10:03:30 +01:00
liamwhite
53fb4a78a3 Merge pull request #8540 from lat9nq/copy-nv-ffmpeg
ci/windows: Copy what of FFmpeg not already present
2022-07-14 20:44:00 -04:00
liamwhite
1a85c18600 Merge pull request #8539 from Morph1984/gha-update-actions
ci: Update various actions from v2 to v3
2022-07-14 20:43:30 -04:00
liamwhite
381381c7e0 Merge pull request #8571 from merryhime/update-dynarmic
externals: Update dynarmic to 6.1.1
2022-07-14 20:41:51 -04:00
liamwhite
2fed6dd7e1 Merge pull request #8536 from Morph1984/fix-webapplet-input
qt_web_browser: Fix button inputs with QtWebEngine
2022-07-14 20:41:41 -04:00
liamwhite
9627c550a0 Merge pull request #8510 from german77/vibration
input_common: sdl: lower vibration frequency and use it's own unique thread
2022-07-14 20:41:29 -04:00
Merry
adc617ccc4 externals: Update dynarmic to 6.1.1
Fixes for fast dispatcher
2022-07-12 11:31:08 +01:00
bunnei
802bbb2263 Merge pull request #8559 from liamwhite/waiter-list
kernel: fix usage of waiter_list in Finalize
2022-07-11 12:10:01 -07:00
Fernando S
6c72b7f011 Merge pull request #8528 from Morph1984/astc10x6
renderer_(gl/vk): Implement ASTC_10x6_UNORM
2022-07-10 13:16:23 +02:00
Fernando S
25e47738f7 Merge pull request #8561 from Kelebek1/Audio-CoreTiming
Rework CoreTiming events
2022-07-10 10:29:56 +02:00
Kelebek1
b23c6b456c PR 2022-07-10 08:29:37 +01:00
Kelebek1
240650f6a6 Rework CoreTiming 2022-07-10 06:59:40 +01:00
liamwhite
c765d5be0b Merge pull request #8531 from FernandoS27/core-timing-fix-reg
Core timing: use only one thread.
2022-07-10 00:47:05 -04:00
Liam
1611c53c12 kernel: fix usage of waiter_list in Finalize 2022-07-09 18:54:54 -04:00
Mai
313f047f97 Merge pull request #8501 from liamwhite/backtrace-again
core/arm: better support for backtrace generation
2022-07-07 23:49:54 -04:00
liamwhite
7e75593c20 Merge pull request #8502 from liamwhite/end-wait
kernel: clean up waiting implementation
2022-07-07 17:31:49 -04:00
Fernando S
d244677df9 Merge pull request #8492 from german77/no_more_errors
service: hid: Correct some mistakes and add more validations
2022-07-07 08:29:34 +02:00
Morph
ec4cba9de8 Merge pull request #8522 from lat9nq/consolidate-settings
settings: Consolidate RangedSetting's with regular ones
2022-07-07 01:22:01 -04:00
lat9nq
caef92a584 ci/windows: Copy what of FFmpeg not already present
Prevents overwriting libwinpthreads.dll when one should already be
present from the first DLL search.
2022-07-05 22:32:12 -04:00
Morph
4fa625c4fa ci: Update various actions from v2 to v3 2022-07-05 20:41:49 -04:00
Morph
cbef6b1fca qt_web_browser: Fix button inputs with QtWebEngine
Button inputs were broken as button was assumed to be the bit position of NpadButton prior to the input rewrite. Since this was changed to use NpadButton directly, we should count the number of trailing zeros to determine the bit position.
2022-07-05 20:34:10 -04:00
Morph
aec129c1ab renderer_(gl/vk): Implement ASTC_10x6_UNORM
- Used by Monster Hunter Rise Update 10.0.2
2022-07-05 20:33:43 -04:00
Fernando Sahmkow
d3cb9201f1 Core timing: use only one thread. 2022-07-02 23:02:16 +02:00
lat9nq
ca36722a54 settings: Consolidate RangedSetting's with regular ones
The latest git version of GCC has issues with my diamond inheritance
shenanigans. Since that's now two compilers that don't like it I thought
it'd be best to just axe all of it and just have the two templates like
before.

This rolls the features of BasicRangedSetting into BasicSetting, and
likewise RangedSetting into Setting. It also renames them from
BasicSetting and Setting to Setting and SwitchableSetting respectively.
Now longer name corresponds to more complex thing.
2022-06-30 12:39:48 -04:00
german77
5e7e55b98a input_common: sdl: lower vibration frequency and use it's own unique thread 2022-06-28 19:22:16 -05:00
Narr the Reg
36148fe7f6 service: hid: Correct some mistakes and add more validations 2022-06-28 19:14:55 -05:00
Liam
075155022e kernel: clean up waiting implementation 2022-06-25 13:36:14 -04:00
Liam
8f8c0b69dc core/arm: better support for backtrace generation 2022-06-25 12:54:24 -04:00
50 changed files with 570 additions and 517 deletions

View File

@@ -65,7 +65,7 @@ python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll
# copy FFmpeg libraries
EXTERNALS_PATH="$(pwd)/build/externals"
FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin"
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -nv {} package/ ';'
# copy libraries from yuzu.exe path
find "$(pwd)/build/bin/" -type f -regex ".*\.dll" -exec cp -v {} package/ ';'

View File

@@ -13,7 +13,7 @@ jobs:
container: yuzuemu/build-environments:linux-transifex
if: ${{ github.repository == 'yuzu-emu/yuzu' && !github.head_ref }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
fetch-depth: 0

View File

@@ -12,7 +12,7 @@ jobs:
image: yuzuemu/build-environments:linux-clang-format
options: -u 1001
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: false
- name: 'Verify Formatting'
@@ -35,12 +35,12 @@ jobs:
image: yuzuemu/build-environments:${{ matrix.image }}
options: -u 1001
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
fetch-depth: 0
- name: Set up cache
uses: actions/cache@v2
uses: actions/cache@v3
id: ccache-restore
with:
path: ~/.ccache
@@ -69,7 +69,7 @@ jobs:
runs-on: windows-2019
steps:
- name: Set up cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/.buildcache
key: ${{ runner.os }}-msvc-${{ github.sha }}
@@ -89,7 +89,7 @@ jobs:
echo %PATH% >> %GITHUB_PATH%
- name: Set up MSVC
uses: ilammy/msvc-dev-cmd@v1
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
fetch-depth: 0

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <limits>
#include <optional>
#include <vector>
#include "audio_core/audio_out.h"
@@ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor
stream = audio_out->OpenStream(
core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
process_event = Core::Timing::CreateEvent(
fmt::format("AudioRenderer-Instance{}-Process", instance_number),
[this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); });
process_event =
Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number),
[this](std::uintptr_t, s64, std::chrono::nanoseconds) {
ReleaseAndQueueBuffers();
return std::nullopt;
});
for (s32 i = 0; i < NUM_BUFFERS; ++i) {
QueueMixedBuffer(i);
}

View File

@@ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format
ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_)
: sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)},
sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} {
release_event =
Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
release_event = Core::Timing::CreateEvent(
name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) {
ReleaseActiveBuffer(ns_late);
return std::nullopt;
});
}

View File

@@ -101,15 +101,15 @@ struct ResolutionScalingInfo {
}
};
/** 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.
/** The Setting class is a simple resource manager. It defines a label and default value alongside
* the actual value of the setting for simpler and less-error prone use with frontend
* configurations. Specifying a default value and label is required. A minimum and maximum range can
* be specified for sanitization.
*/
template <typename Type>
class BasicSetting {
class Setting {
protected:
BasicSetting() = default;
Setting() = default;
/**
* Only sets the setting to the given initializer, leaving the other members to their default
@@ -117,7 +117,7 @@ protected:
*
* @param global_val Initial value of the setting
*/
explicit BasicSetting(const Type& global_val) : global{global_val} {}
explicit Setting(const Type& val) : value{val} {}
public:
/**
@@ -126,9 +126,22 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
explicit BasicSetting(const Type& default_val, const std::string& name)
: default_value{default_val}, global{default_val}, label{name} {}
virtual ~BasicSetting() = default;
explicit Setting(const Type& default_val, const std::string& name)
: value{default_val}, default_value{default_val}, ranged{false}, label{name} {}
virtual ~Setting() = default;
/**
* Sets a default value, minimum value, maximum value, and label.
*
* @param default_val Intial value of the setting, and default value of the setting
* @param min_val Sets the minimum allowed value of the setting
* @param max_val Sets the maximum allowed value of the setting
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
: value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
ranged{true}, label{name} {}
/**
* Returns a reference to the setting's value.
@@ -136,17 +149,17 @@ public:
* @returns A reference to the setting
*/
[[nodiscard]] virtual const Type& GetValue() const {
return global;
return value;
}
/**
* Sets the setting to the given value.
*
* @param value The desired value
* @param val The desired value
*/
virtual void SetValue(const Type& value) {
Type temp{value};
std::swap(global, temp);
virtual void SetValue(const Type& val) {
Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
}
/**
@@ -170,14 +183,14 @@ public:
/**
* Assigns a value to the setting.
*
* @param value The desired setting value
* @param val The desired setting value
*
* @returns A reference to the setting
*/
virtual const Type& operator=(const Type& value) {
Type temp{value};
std::swap(global, temp);
return global;
virtual const Type& operator=(const Type& val) {
Type temp{(ranged) ? std::clamp(val, minimum, maximum) : val};
std::swap(value, temp);
return value;
}
/**
@@ -186,23 +199,39 @@ public:
* @returns A reference to the setting
*/
explicit virtual operator const Type&() const {
return global;
return value;
}
protected:
Type value{}; ///< The setting
const Type default_value{}; ///< The default value
Type global{}; ///< The setting
const Type maximum{}; ///< Maximum allowed value of the setting
const Type minimum{}; ///< Minimum allowed value of the setting
const bool ranged; ///< The setting has sanitization ranges
const std::string label{}; ///< The setting's label
};
/**
* BasicRangedSetting class is intended for use with quantifiable settings that need a more
* restrictive range than implicitly defined by its type. Implements a minimum and maximum that is
* simply used to sanitize SetValue and the assignment overload.
* The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
* custom setting to switch to when a guest application specifically requires it. The effect is that
* other components of the emulator can access the setting's intended value without any need for the
* component to ask whether the custom or global setting is needed at the moment.
*
* By default, the global setting is used.
*/
template <typename Type>
class BasicRangedSetting : virtual public BasicSetting<Type> {
class SwitchableSetting : virtual public Setting<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 SwitchableSetting(const Type& default_val, const std::string& name)
: Setting<Type>{default_val, name} {}
virtual ~SwitchableSetting() = default;
/**
* Sets a default value, minimum value, maximum value, and label.
*
@@ -211,57 +240,9 @@ public:
* @param max_val Sets the maximum allowed value of the setting
* @param name Label for the setting
*/
explicit BasicRangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
: BasicSetting<Type>{default_val, name}, minimum{min_val}, maximum{max_val} {}
virtual ~BasicRangedSetting() = default;
/**
* Like BasicSetting's SetValue, except value is clamped to the range of the setting.
*
* @param value The desired value
*/
void SetValue(const Type& value) override {
this->global = std::clamp(value, minimum, maximum);
}
/**
* Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
*
* @param value The desired value
* @returns A reference to the setting's value
*/
const Type& operator=(const Type& value) override {
this->global = std::clamp(value, minimum, maximum);
return this->global;
}
const Type minimum; ///< Minimum allowed value of the setting
const Type maximum; ///< Maximum allowed value of the setting
};
/**
* 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 : virtual 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) {}
virtual ~Setting() = default;
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
: Setting<Type>{default_val, min_val, max_val, name} {}
/**
* Tells this setting to represent either the global or custom setting when other member
@@ -292,13 +273,13 @@ public:
*/
[[nodiscard]] virtual const Type& GetValue() const override {
if (use_global) {
return this->global;
return this->value;
}
return custom;
}
[[nodiscard]] virtual const Type& GetValue(bool need_global) const {
if (use_global || need_global) {
return this->global;
return this->value;
}
return custom;
}
@@ -306,12 +287,12 @@ public:
/**
* Sets the current setting value depending on the global state.
*
* @param value The new value
* @param val The new value
*/
void SetValue(const Type& value) override {
Type temp{value};
void SetValue(const Type& val) override {
Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->global, temp);
std::swap(this->value, temp);
} else {
std::swap(custom, temp);
}
@@ -320,15 +301,15 @@ public:
/**
* Assigns the current setting value depending on the global state.
*
* @param value The new value
* @param val The new value
*
* @returns A reference to the current setting value
*/
const Type& operator=(const Type& value) override {
Type temp{value};
const Type& operator=(const Type& val) override {
Type temp{(this->ranged) ? std::clamp(val, this->minimum, this->maximum) : val};
if (use_global) {
std::swap(this->global, temp);
return this->global;
std::swap(this->value, temp);
return this->value;
}
std::swap(custom, temp);
return custom;
@@ -341,7 +322,7 @@ public:
*/
virtual explicit operator const Type&() const override {
if (use_global) {
return this->global;
return this->value;
}
return custom;
}
@@ -351,75 +332,6 @@ protected:
Type custom{}; ///< The custom value of the setting
};
/**
* RangedSetting is a Setting that implements a maximum and minimum value for its setting. Intended
* for use with quantifiable settings.
*/
template <typename Type>
class RangedSetting final : public BasicRangedSetting<Type>, public Setting<Type> {
public:
/**
* Sets a default value, minimum value, maximum value, and label.
*
* @param default_val Intial value of the setting, and default value of the setting
* @param min_val Sets the minimum allowed value of the setting
* @param max_val Sets the maximum allowed value of the setting
* @param name Label for the setting
*/
explicit RangedSetting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
: BasicSetting<Type>{default_val, name},
BasicRangedSetting<Type>{default_val, min_val, max_val, name}, Setting<Type>{default_val,
name} {}
virtual ~RangedSetting() = default;
// The following are needed to avoid a MSVC bug
// (source: https://stackoverflow.com/questions/469508)
[[nodiscard]] const Type& GetValue() const override {
return Setting<Type>::GetValue();
}
[[nodiscard]] const Type& GetValue(bool need_global) const override {
return Setting<Type>::GetValue(need_global);
}
explicit operator const Type&() const override {
if (this->use_global) {
return this->global;
}
return this->custom;
}
/**
* Like BasicSetting's SetValue, except value is clamped to the range of the setting. Sets the
* appropriate value depending on the global state.
*
* @param value The desired value
*/
void SetValue(const Type& value) override {
const Type temp = std::clamp(value, this->minimum, this->maximum);
if (this->use_global) {
this->global = temp;
}
this->custom = temp;
}
/**
* Like BasicSetting's assignment overload, except value is clamped to the range of the setting.
* Uses the appropriate value depending on the global state.
*
* @param value The desired value
* @returns A reference to the setting's value
*/
const Type& operator=(const Type& value) override {
const Type temp = std::clamp(value, this->minimum, this->maximum);
if (this->use_global) {
this->global = temp;
return this->global;
}
this->custom = temp;
return this->custom;
}
};
/**
* 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
@@ -431,7 +343,7 @@ template <typename Type>
class InputSetting final {
public:
InputSetting() = default;
explicit InputSetting(Type val) : BasicSetting<Type>(val) {}
explicit InputSetting(Type val) : Setting<Type>(val) {}
~InputSetting() = default;
void SetGlobal(bool to_global) {
use_global = to_global;
@@ -459,175 +371,175 @@ struct TouchFromButtonMap {
struct Values {
// Audio
BasicSetting<std::string> audio_device_id{"auto", "output_device"};
BasicSetting<std::string> sink_id{"auto", "output_engine"};
BasicSetting<bool> audio_muted{false, "audio_muted"};
RangedSetting<u8> volume{100, 0, 100, "volume"};
Setting<std::string> audio_device_id{"auto", "output_device"};
Setting<std::string> sink_id{"auto", "output_engine"};
Setting<bool> audio_muted{false, "audio_muted"};
SwitchableSetting<u8> volume{100, 0, 100, "volume"};
// Core
Setting<bool> use_multi_core{true, "use_multi_core"};
Setting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
// Cpu
RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
CPUAccuracy::Paranoid, "cpu_accuracy"};
SwitchableSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
CPUAccuracy::Paranoid, "cpu_accuracy"};
// TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
BasicSetting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
BasicSetting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
BasicSetting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
BasicSetting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
BasicSetting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
BasicSetting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
Setting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
Setting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
Setting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
Setting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
Setting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
Setting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
Setting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
Setting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
Setting<bool> cpuopt_unsafe_ignore_global_monitor{true, "cpuopt_unsafe_ignore_global_monitor"};
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
true, "cpuopt_unsafe_ignore_standard_fpcr"};
SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
true, "cpuopt_unsafe_ignore_global_monitor"};
// Renderer
RangedSetting<RendererBackend> renderer_backend{
SwitchableSetting<RendererBackend> renderer_backend{
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
BasicSetting<bool> renderer_debug{false, "debug"};
BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"};
BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
BasicSetting<bool> disable_shader_loop_safety_checks{false,
"disable_shader_loop_safety_checks"};
Setting<int> vulkan_device{0, "vulkan_device"};
Setting<bool> renderer_debug{false, "debug"};
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
Setting<bool> disable_shader_loop_safety_checks{false, "disable_shader_loop_safety_checks"};
SwitchableSetting<int> vulkan_device{0, "vulkan_device"};
ResolutionScalingInfo resolution_info{};
Setting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
Setting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
Setting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
SwitchableSetting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
SwitchableSetting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
// *nix platforms may have issues with the borderless windowed fullscreen mode.
// Default to exclusive fullscreen on these platforms for now.
RangedSetting<FullscreenMode> fullscreen_mode{
SwitchableSetting<FullscreenMode> fullscreen_mode{
#ifdef _WIN32
FullscreenMode::Borderless,
#else
FullscreenMode::Exclusive,
#endif
FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
RangedSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
RangedSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"};
Setting<bool> use_speed_limit{true, "use_speed_limit"};
RangedSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
RangedSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
GPUAccuracy::Extreme, "gpu_accuracy"};
Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
Setting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
Setting<bool> accelerate_astc{true, "accelerate_astc"};
Setting<bool> use_vsync{true, "use_vsync"};
RangedSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
RangedSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
ShaderBackend::SPIRV, "shader_backend"};
Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
SwitchableSetting<int> aspect_ratio{0, 0, 3, "aspect_ratio"};
SwitchableSetting<int> max_anisotropy{0, 0, 5, "max_anisotropy"};
SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
SwitchableSetting<u16> speed_limit{100, 0, 9999, "speed_limit"};
SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
SwitchableSetting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
GPUAccuracy::Extreme, "gpu_accuracy"};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
SwitchableSetting<bool> use_vsync{true, "use_vsync"};
SwitchableSetting<u16> fps_cap{1000, 1, 1000, "fps_cap"};
Setting<bool> disable_fps_limit{false, "disable_fps_limit"};
SwitchableSetting<ShaderBackend> shader_backend{ShaderBackend::GLASM, ShaderBackend::GLSL,
ShaderBackend::SPIRV, "shader_backend"};
SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
Setting<u8> bg_red{0, "bg_red"};
Setting<u8> bg_green{0, "bg_green"};
Setting<u8> bg_blue{0, "bg_blue"};
SwitchableSetting<u8> bg_red{0, "bg_red"};
SwitchableSetting<u8> bg_green{0, "bg_green"};
SwitchableSetting<u8> bg_blue{0, "bg_blue"};
// System
Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
// Measured in seconds since epoch
std::optional<s64> custom_rtc;
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
s64 custom_rtc_differential;
BasicSetting<s32> current_user{0, "current_user"};
RangedSetting<s32> language_index{1, 0, 17, "language_index"};
RangedSetting<s32> region_index{1, 0, 6, "region_index"};
RangedSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
RangedSetting<s32> sound_index{1, 0, 2, "sound_index"};
Setting<s32> current_user{0, "current_user"};
SwitchableSetting<s32> language_index{1, 0, 17, "language_index"};
SwitchableSetting<s32> region_index{1, 0, 6, "region_index"};
SwitchableSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
SwitchableSetting<s32> sound_index{1, 0, 2, "sound_index"};
// Controls
InputSetting<std::array<PlayerInput, 10>> players;
Setting<bool> use_docked_mode{true, "use_docked_mode"};
SwitchableSetting<bool> use_docked_mode{true, "use_docked_mode"};
BasicSetting<bool> enable_raw_input{false, "enable_raw_input"};
BasicSetting<bool> controller_navigation{true, "controller_navigation"};
Setting<bool> enable_raw_input{false, "enable_raw_input"};
Setting<bool> controller_navigation{true, "controller_navigation"};
Setting<bool> vibration_enabled{true, "vibration_enabled"};
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
Setting<bool> motion_enabled{true, "motion_enabled"};
BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
BasicSetting<bool> enable_udp_controller{false, "enable_udp_controller"};
SwitchableSetting<bool> motion_enabled{true, "motion_enabled"};
Setting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
Setting<bool> enable_udp_controller{false, "enable_udp_controller"};
BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
BasicSetting<bool> tas_enable{false, "tas_enable"};
BasicSetting<bool> tas_loop{false, "tas_loop"};
Setting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
Setting<bool> tas_enable{false, "tas_enable"};
Setting<bool> tas_loop{false, "tas_loop"};
BasicSetting<bool> mouse_panning{false, "mouse_panning"};
BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
Setting<bool> mouse_panning{false, "mouse_panning"};
Setting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
Setting<bool> mouse_enabled{false, "mouse_enabled"};
BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
Setting<bool> keyboard_enabled{false, "keyboard_enabled"};
BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
Setting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
ButtonsRaw debug_pad_buttons;
AnalogsRaw debug_pad_analogs;
TouchscreenInput touchscreen;
BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
"touch_device"};
BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
Setting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"};
Setting<int> touch_from_button_map_index{0, "touch_from_button_map"};
std::vector<TouchFromButtonMap> touch_from_button_maps;
BasicSetting<bool> enable_ring_controller{true, "enable_ring_controller"};
Setting<bool> enable_ring_controller{true, "enable_ring_controller"};
RingconRaw ringcon_analogs;
// Data Storage
BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};
BasicSetting<bool> gamecard_current_game{false, "gamecard_current_game"};
BasicSetting<std::string> gamecard_path{std::string(), "gamecard_path"};
Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
Setting<bool> gamecard_current_game{false, "gamecard_current_game"};
Setting<std::string> gamecard_path{std::string(), "gamecard_path"};
// Debugging
bool record_frame_times;
BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
BasicSetting<u16> gdbstub_port{6543, "gdbstub_port"};
BasicSetting<std::string> program_args{std::string(), "program_args"};
BasicSetting<bool> dump_exefs{false, "dump_exefs"};
BasicSetting<bool> dump_nso{false, "dump_nso"};
BasicSetting<bool> dump_shaders{false, "dump_shaders"};
BasicSetting<bool> dump_macros{false, "dump_macros"};
BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
BasicSetting<bool> reporting_services{false, "reporting_services"};
BasicSetting<bool> quest_flag{false, "quest_flag"};
BasicSetting<bool> disable_macro_jit{false, "disable_macro_jit"};
BasicSetting<bool> extended_logging{false, "extended_logging"};
BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
BasicSetting<bool> enable_all_controllers{false, "enable_all_controllers"};
Setting<bool> use_gdbstub{false, "use_gdbstub"};
Setting<u16> gdbstub_port{6543, "gdbstub_port"};
Setting<std::string> program_args{std::string(), "program_args"};
Setting<bool> dump_exefs{false, "dump_exefs"};
Setting<bool> dump_nso{false, "dump_nso"};
Setting<bool> dump_shaders{false, "dump_shaders"};
Setting<bool> dump_macros{false, "dump_macros"};
Setting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
Setting<bool> reporting_services{false, "reporting_services"};
Setting<bool> quest_flag{false, "quest_flag"};
Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
Setting<bool> extended_logging{false, "extended_logging"};
Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
Setting<bool> use_auto_stub{false, "use_auto_stub"};
Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
// Miscellaneous
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
Setting<std::string> log_filter{"*:Info", "log_filter"};
Setting<bool> use_dev_keys{false, "use_dev_keys"};
// Network
BasicSetting<std::string> network_interface{std::string(), "network_interface"};
Setting<std::string> network_interface{std::string(), "network_interface"};
// WebService
BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
BasicSetting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
BasicSetting<std::string> yuzu_username{std::string(), "yuzu_username"};
BasicSetting<std::string> yuzu_token{std::string(), "yuzu_token"};
Setting<bool> enable_telemetry{true, "enable_telemetry"};
Setting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
Setting<std::string> yuzu_username{std::string(), "yuzu_username"};
Setting<std::string> yuzu_token{std::string(), "yuzu_token"};
// Add-Ons
std::map<u64, std::vector<std::string>> disabled_addons;

View File

@@ -67,7 +67,7 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
const auto& caps = GetCPUCaps();
u64 rtsc_frequency = 0;
if (caps.invariant_tsc) {
rtsc_frequency = caps.tsc_frequency ? caps.tsc_frequency : EstimateRDTSCFrequency();
rtsc_frequency = EstimateRDTSCFrequency();
}
// Fallback to StandardWallClock if the hardware TSC does not have the precision greater than:

View File

@@ -161,22 +161,6 @@ static CPUCaps Detect() {
caps.invariant_tsc = Common::Bit<8>(cpu_id[3]);
}
if (max_std_fn >= 0x15) {
__cpuid(cpu_id, 0x15);
caps.tsc_crystal_ratio_denominator = cpu_id[0];
caps.tsc_crystal_ratio_numerator = cpu_id[1];
caps.crystal_frequency = cpu_id[2];
// Some CPU models might not return a crystal frequency.
// The CPU model can be detected to use the values from turbostat
// https://github.com/torvalds/linux/blob/master/tools/power/x86/turbostat/turbostat.c#L5569
// but it's easier to just estimate the TSC tick rate for these cases.
if (caps.tsc_crystal_ratio_denominator) {
caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) *
caps.tsc_crystal_ratio_numerator /
caps.tsc_crystal_ratio_denominator;
}
}
if (max_std_fn >= 0x16) {
__cpuid(cpu_id, 0x16);
caps.base_frequency = cpu_id[0];

View File

@@ -30,11 +30,6 @@ struct CPUCaps {
u32 max_frequency;
u32 bus_frequency;
u32 tsc_crystal_ratio_denominator;
u32 tsc_crystal_ratio_numerator;
u32 crystal_frequency;
u64 tsc_frequency; // Derived from the above three values
bool sse : 1;
bool sse2 : 1;
bool sse3 : 1;

View File

@@ -1,6 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef _MSC_VER
#include <cxxabi.h>
#endif
#include <map>
#include <optional>
#include "common/bit_field.h"
@@ -68,8 +72,19 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
if (symbol_set != symbols.end()) {
const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
if (symbol.has_value()) {
#ifdef _MSC_VER
// TODO(DarkLordZach): Add demangling of symbol names.
entry.name = *symbol;
#else
int status{-1};
char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)};
if (status == 0 && demangled != nullptr) {
entry.name = demangled;
std::free(demangled);
} else {
entry.name = *symbol;
}
#endif
}
}
}
@@ -132,7 +147,6 @@ void ARM_Interface::Run() {
// Notify the debugger and go to sleep if a watchpoint was hit.
if (Has(hr, watchpoint)) {
RewindBreakpointInstruction();
if (system.DebuggerEnabled()) {
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
}

View File

@@ -203,7 +203,7 @@ public:
static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4;
static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5;
static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::MemoryAbort;
static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6;
protected:

View File

@@ -155,7 +155,7 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.halted_watchpoint = match;
ReturnException(parent.jit.load()->Regs()[15], ARM_Interface::watchpoint);
parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
return false;
}
@@ -204,7 +204,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
// Code cache size
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Allow memory fault handling to work
if (system.DebuggerEnabled()) {
@@ -215,7 +214,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
if (!page_table) {
// Don't waste too much memory on null_jit
config.code_cache_size = 8_MiB;
config.far_code_offset = 4_MiB;
}
// Safe optimizations
@@ -427,18 +425,38 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system,
u64 sp, u64 lr) {
// No way to get accurate stack traces in A32 yet
return {};
u64 fp, u64 lr, u64 pc) {
std::vector<BacktraceEntry> out;
auto& memory = system.Memory();
out.push_back({"", 0, pc, 0, ""});
// fp (= r11) points to the last frame record.
// Frame records are two words long:
// fp+0 : pointer to previous frame record
// fp+4 : value of lr for frame
while (true) {
out.push_back({"", 0, lr, 0, ""});
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
break;
}
lr = memory.Read32(fp + 4);
fp = memory.Read32(fp);
}
SymbolicateBacktrace(system, out);
return out;
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext(
System& system, const ThreadContext32& ctx) {
return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]);
const auto& reg = ctx.cpu_registers;
return GetBacktrace(system, reg[11], reg[14], reg[15]);
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const {
return GetBacktrace(system, GetReg(13), GetReg(14));
return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15));
}
} // namespace Core

View File

@@ -78,7 +78,7 @@ protected:
private:
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 sp, u64 lr);
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =

View File

@@ -198,7 +198,7 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.halted_watchpoint = match;
ReturnException(parent.jit.load()->GetPC(), ARM_Interface::watchpoint);
parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
return false;
}
@@ -264,7 +264,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
// Code cache size
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Allow memory fault handling to work
if (system.DebuggerEnabled()) {
@@ -275,7 +274,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
if (!page_table) {
// Don't waste too much memory on null_jit
config.code_cache_size = 8_MiB;
config.far_code_offset = 4_MiB;
}
// Safe optimizations
@@ -494,22 +492,22 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system,
u64 fp, u64 lr) {
u64 fp, u64 lr, u64 pc) {
std::vector<BacktraceEntry> out;
auto& memory = system.Memory();
// fp (= r29) points to the last frame record.
// Note that this is the frame record for the *previous* frame, not the current one.
// Note we need to subtract 4 from our last read to get the proper address
out.push_back({"", 0, pc, 0, ""});
// fp (= x29) points to the previous frame record.
// Frame records are two words long:
// fp+0 : pointer to previous frame record
// fp+8 : value of lr for frame
while (true) {
out.push_back({"", 0, lr, 0, ""});
if (!fp) {
if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
break;
}
lr = memory.Read64(fp + 8) - 4;
lr = memory.Read64(fp + 8);
fp = memory.Read64(fp);
}
@@ -520,11 +518,12 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext(
System& system, const ThreadContext64& ctx) {
return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]);
const auto& reg = ctx.cpu_registers;
return GetBacktrace(system, reg[29], reg[30], ctx.pc);
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const {
return GetBacktrace(system, GetReg(29), GetReg(30));
return GetBacktrace(system, GetReg(29), GetReg(30), GetPC());
}
} // namespace Core

View File

@@ -73,7 +73,7 @@ private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr);
static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =

View File

@@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
}
struct CoreTiming::Event {
u64 time;
s64 time;
u64 fifo_order;
std::uintptr_t user_data;
std::weak_ptr<EventType> type;
s64 reschedule_time;
// Sort by time, unless the times are the same, in which case sort by
// the order added to the queue
@@ -58,15 +59,11 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
event_fifo_id = 0;
shutting_down = false;
ticks = 0;
const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) {
const auto hardware_concurrency = std::thread::hardware_concurrency();
size_t id = 0;
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
if (hardware_concurrency > 8) {
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
}
worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0);
}
}
@@ -81,6 +78,7 @@ void CoreTiming::Shutdown() {
thread.join();
}
worker_threads.clear();
pause_callbacks.clear();
ClearPendingEvents();
has_started = false;
}
@@ -98,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) {
}
}
paused_state.store(is_paused_, std::memory_order_relaxed);
if (!is_paused_) {
pause_end_time = GetGlobalTimeNs().count();
}
for (auto& cb : pause_callbacks) {
cb(is_paused_);
}
}
void CoreTiming::SyncPause(bool is_paused_) {
@@ -121,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) {
wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
}
}
if (!is_paused_) {
pause_end_time = GetGlobalTimeNs().count();
}
for (auto& cb : pause_callbacks) {
cb(is_paused_);
}
}
bool CoreTiming::IsRunning() const {
@@ -134,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const {
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data) {
std::uintptr_t user_data, bool absolute_time) {
std::unique_lock main_lock(event_mutex);
const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type});
event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0});
pending_events.fetch_add(1, std::memory_order_relaxed);
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
if (is_multicore) {
event_cv.notify_one();
}
}
void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
std::chrono::nanoseconds resched_time,
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data, bool absolute_time) {
std::unique_lock main_lock(event_mutex);
const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
event_queue.emplace_back(
Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()});
pending_events.fetch_add(1, std::memory_order_relaxed);
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
@@ -218,6 +250,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
}
}
void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
std::unique_lock main_lock(event_mutex);
pause_callbacks.emplace_back(std::move(callback));
}
std::optional<s64> CoreTiming::Advance() {
global_timer = GetGlobalTimeNs().count();
@@ -228,17 +265,31 @@ std::optional<s64> CoreTiming::Advance() {
event_queue.pop_back();
if (const auto event_type{evt.type.lock()}) {
sequence_mutex.lock();
event_mutex.unlock();
event_type->guard.lock();
sequence_mutex.unlock();
const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time);
event_type->callback(evt.user_data, std::chrono::nanoseconds{delay});
event_type->guard.unlock();
const auto new_schedule_time{event_type->callback(
evt.user_data, evt.time,
std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
event_mutex.lock();
pending_events.fetch_sub(1, std::memory_order_relaxed);
if (evt.reschedule_time != 0) {
// If this event was scheduled into a pause, its time now is going to be way behind.
// Re-set this event to continue from the end of the pause.
auto next_time{evt.time + evt.reschedule_time};
if (evt.time < pause_end_time) {
next_time = pause_end_time + evt.reschedule_time;
}
const auto next_schedule_time{new_schedule_time.has_value()
? new_schedule_time.value().count()
: evt.reschedule_time};
event_queue.emplace_back(
Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time});
pending_events.fetch_add(1, std::memory_order_relaxed);
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
}
global_timer = GetGlobalTimeNs().count();

View File

@@ -20,8 +20,9 @@
namespace Core::Timing {
/// A callback that may be scheduled for a particular core timing event.
using TimedCallback =
std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>;
using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
using PauseCallback = std::function<void(bool paused)>;
/// Contains the characteristics of a particular event.
struct EventType {
@@ -32,7 +33,6 @@ struct EventType {
TimedCallback callback;
/// A pointer to the name of the event.
const std::string name;
mutable std::mutex guard;
};
/**
@@ -94,7 +94,15 @@ public:
/// Schedules an event in core timing
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0);
const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
bool absolute_time = false);
/// Schedules an event which will automatically re-schedule itself with the given time, until
/// unscheduled
void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
std::chrono::nanoseconds resched_time,
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data = 0, bool absolute_time = false);
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
@@ -126,6 +134,9 @@ public:
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
std::optional<s64> Advance();
/// Register a callback function to be called when coretiming pauses.
void RegisterPauseCallback(PauseCallback&& callback);
private:
struct Event;
@@ -137,7 +148,7 @@ private:
std::unique_ptr<Common::WallClock> clock;
u64 global_timer = 0;
s64 global_timer = 0;
// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
// We don't use std::priority_queue because we need to be able to serialize, unserialize and
@@ -157,17 +168,19 @@ private:
std::condition_variable wait_pause_cv;
std::condition_variable wait_signal_cv;
mutable std::mutex event_mutex;
mutable std::mutex sequence_mutex;
std::atomic<bool> paused_state{};
bool is_paused{};
bool shutting_down{};
bool is_multicore{};
size_t pause_count{};
s64 pause_end_time{};
/// Cycle timing
u64 ticks{};
s64 downcount{};
std::vector<PauseCallback> pause_callbacks{};
};
/// Creates a core timing event with the given name and callback.

View File

@@ -11,11 +11,14 @@ namespace Core::Hardware {
InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
gpu_interrupt_event = Core::Timing::CreateEvent(
"GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) {
"GPUInterrupt",
[this](std::uintptr_t message, u64 time,
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
const u32 syncpt = static_cast<u32>(message >> 32);
const u32 value = static_cast<u32>(message);
nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
return std::nullopt;
});
}

View File

@@ -272,6 +272,7 @@ enum class VibrationDeviceType : u32 {
Unknown = 0,
LinearResonantActuator = 1,
GcErm = 2,
N64 = 3,
};
// This is nn::hid::VibrationGcErmCommand

View File

@@ -161,7 +161,7 @@ bool KProcess::ReleaseUserException(KThread* thread) {
std::addressof(num_waiters),
reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
next != nullptr) {
next->SetState(ThreadState::Runnable);
next->EndWait(ResultSuccess);
}
KScheduler::SetSchedulerUpdateNeeded(kernel);

View File

@@ -308,14 +308,20 @@ void KThread::Finalize() {
auto it = waiter_list.begin();
while (it != waiter_list.end()) {
// Clear the lock owner
it->SetLockOwner(nullptr);
// Get the thread.
KThread* const waiter = std::addressof(*it);
// The thread shouldn't be a kernel waiter.
ASSERT(!IsKernelAddressKey(waiter->GetAddressKey()));
// Clear the lock owner.
waiter->SetLockOwner(nullptr);
// Erase the waiter from our list.
it = waiter_list.erase(it);
// Cancel the thread's wait.
it->CancelWait(ResultInvalidState, true);
waiter->CancelWait(ResultInvalidState, true);
}
}
@@ -480,9 +486,7 @@ void KThread::Unpin() {
// Resume any threads that began waiting on us while we were pinned.
for (auto it = pinned_waiter_list.begin(); it != pinned_waiter_list.end(); ++it) {
if (it->GetState() == ThreadState::Waiting) {
it->SetState(ThreadState::Runnable);
}
it->EndWait(ResultSuccess);
}
}
@@ -877,6 +881,7 @@ void KThread::AddWaiterImpl(KThread* thread) {
// Keep track of how many kernel waiters we have.
if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters++) >= 0);
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
// Insert the waiter.
@@ -890,6 +895,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) {
// Keep track of how many kernel waiters we have.
if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters--) > 0);
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
// Remove the waiter.
@@ -965,6 +971,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
// Keep track of how many kernel waiters we have.
if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters--) > 0);
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
it = waiter_list.erase(it);

View File

@@ -234,17 +234,18 @@ struct KernelCore::Impl {
void InitializePreemption(KernelCore& kernel) {
preemption_event = Core::Timing::CreateEvent(
"PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) {
"PreemptionCallback",
[this, &kernel](std::uintptr_t, s64 time,
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
{
KScopedSchedulerLock lock(kernel);
global_scheduler_context->PreemptThreads();
}
const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
return std::nullopt;
});
const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event);
}
void InitializeShutdownThreads() {

View File

@@ -11,15 +11,17 @@
namespace Kernel {
TimeManager::TimeManager(Core::System& system_) : system{system_} {
time_manager_event_type =
Core::Timing::CreateEvent("Kernel::TimeManagerCallback",
[this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
KThread* thread = reinterpret_cast<KThread*>(thread_handle);
{
KScopedSchedulerLock sl(system.Kernel());
thread->OnTimer();
}
});
time_manager_event_type = Core::Timing::CreateEvent(
"Kernel::TimeManagerCallback",
[this](std::uintptr_t thread_handle, s64 time,
std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
KThread* thread = reinterpret_cast<KThread*>(thread_handle);
{
KScopedSchedulerLock sl(system.Kernel());
thread->OnTimer();
}
return std::nullopt;
});
}
void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {

View File

@@ -49,28 +49,41 @@ bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) {
}
}
bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) {
Result Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) {
const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
return npad_id && npad_type && device_index;
if (!npad_type) {
return VibrationInvalidStyleIndex;
}
if (!npad_id) {
return VibrationInvalidNpadId;
}
if (!device_index) {
return VibrationDeviceIndexOutOfRange;
}
return ResultSuccess;
}
Result Controller_NPad::VerifyValidSixAxisSensorHandle(
const Core::HID::SixAxisSensorHandle& device_handle) {
const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
if (!npad_id) {
return InvalidNpadId;
}
const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
if (!device_index) {
return NpadDeviceIndexOutOfRange;
}
// This doesn't get validated on nnsdk
const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
if (!npad_type) {
return NpadInvalidHandle;
}
return ResultSuccess;
}
@@ -705,6 +718,11 @@ Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const {
}
void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) {
ASSERT_MSG(false, "Activation mode should be always None, Single or Dual");
return;
}
handheld_activation_mode = activation_mode;
}
@@ -820,11 +838,11 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
const auto now = steady_clock::now();
// Filter out non-zero vibrations that are within 10ms of each other.
// Filter out non-zero vibrations that are within 15ms of each other.
if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) &&
duration_cast<milliseconds>(
now - controller.vibration[device_index].last_vibration_timepoint) <
milliseconds(10)) {
milliseconds(15)) {
return false;
}
@@ -840,7 +858,7 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
void Controller_NPad::VibrateController(
const Core::HID::VibrationDeviceHandle& vibration_device_handle,
const Core::HID::VibrationValue& vibration_value) {
if (!IsDeviceHandleValid(vibration_device_handle)) {
if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return;
}
@@ -903,7 +921,7 @@ void Controller_NPad::VibrateControllers(
Core::HID::VibrationValue Controller_NPad::GetLastVibration(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
if (!IsDeviceHandleValid(vibration_device_handle)) {
if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return {};
}
@@ -914,7 +932,7 @@ Core::HID::VibrationValue Controller_NPad::GetLastVibration(
void Controller_NPad::InitializeVibrationDevice(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
if (!IsDeviceHandleValid(vibration_device_handle)) {
if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return;
}
@@ -941,7 +959,7 @@ void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
bool Controller_NPad::IsVibrationDeviceMounted(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
if (!IsDeviceHandleValid(vibration_device_handle)) {
if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return false;
}

View File

@@ -81,6 +81,7 @@ public:
Dual = 0,
Single = 1,
None = 2,
MaxActivationMode = 3,
};
// This is nn::hid::NpadCommunicationMode
@@ -196,7 +197,7 @@ public:
Core::HID::NpadButton GetAndResetPressState();
static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
static Result VerifyValidSixAxisSensorHandle(
const Core::HID::SixAxisSensorHandle& device_handle);

View File

@@ -9,6 +9,9 @@ namespace Service::HID {
constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
constexpr Result VibrationInvalidStyleIndex{ErrorModule::HID, 122};
constexpr Result VibrationInvalidNpadId{ErrorModule::HID, 123};
constexpr Result VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
constexpr Result NpadIsSameType{ErrorModule::HID, 602};

View File

@@ -74,26 +74,34 @@ IAppletResource::IAppletResource(Core::System& system_,
// Register update callbacks
pad_update_event = Core::Timing::CreateEvent(
"HID::UpdatePadCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateControllers(user_data, ns_late);
return std::nullopt;
});
mouse_keyboard_update_event = Core::Timing::CreateEvent(
"HID::UpdateMouseKeyboardCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateMouseKeyboard(user_data, ns_late);
return std::nullopt;
});
motion_update_event = Core::Timing::CreateEvent(
"HID::UpdateMotionCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateMotion(user_data, ns_late);
return std::nullopt;
});
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event);
system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event);
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
mouse_keyboard_update_event);
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
motion_update_event);
system.HIDCore().ReloadInputDevices();
}
@@ -135,13 +143,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
}
controller->OnUpdate(core_timing);
}
// If ns_late is higher than the update rate ignore the delay
if (ns_late > pad_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
}
void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
@@ -150,26 +151,12 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > mouse_keyboard_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event);
}
void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > motion_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
}
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
@@ -778,7 +765,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
bool is_at_rest{};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -786,7 +773,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push(ResultSuccess);
rb.Push(is_at_rest);
}
@@ -803,8 +790,8 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
bool is_firmware_available{};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.IsFirmwareUpdateAvailableForSixAxisSensor(
parameters.sixaxis_handle, is_firmware_available);
controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
is_firmware_available);
LOG_WARNING(
Service_HID,
@@ -813,7 +800,7 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push(ResultSuccess);
rb.Push(is_firmware_available);
}
@@ -1083,13 +1070,13 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.DisconnectNpad(parameters.npad_id);
controller.DisconnectNpad(parameters.npad_id);
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
rb.Push(ResultSuccess);
}
void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
@@ -1165,15 +1152,14 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result =
controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
Controller_NPad::NpadJoyAssignmentMode::Single);
controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
rb.Push(ResultSuccess);
}
void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
@@ -1189,15 +1175,15 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
Controller_NPad::NpadJoyAssignmentMode::Single);
controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id,
parameters.npad_joy_device_type);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
rb.Push(ResultSuccess);
}
void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
@@ -1212,14 +1198,13 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.SetNpadMode(parameters.npad_id, {},
Controller_NPad::NpadJoyAssignmentMode::Dual);
controller.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
rb.Push(ResultSuccess);
}
void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
@@ -1412,8 +1397,11 @@ void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
const auto& controller =
GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
Core::HID::VibrationDeviceInfo vibration_device_info;
bool check_device_index = false;
switch (vibration_device_handle.npad_type) {
case Core::HID::NpadStyleIndex::ProController:
@@ -1421,34 +1409,46 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::JoyconLeft:
case Core::HID::NpadStyleIndex::JoyconRight:
default:
vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
check_device_index = true;
break;
case Core::HID::NpadStyleIndex::GameCube:
vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
break;
case Core::HID::NpadStyleIndex::Pokeball:
case Core::HID::NpadStyleIndex::N64:
vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
break;
default:
vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
break;
}
switch (vibration_device_handle.device_index) {
case Core::HID::DeviceIndex::Left:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
break;
case Core::HID::DeviceIndex::Right:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
break;
case Core::HID::DeviceIndex::None:
default:
ASSERT_MSG(false, "DeviceIndex should never be None!");
vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
break;
vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
if (check_device_index) {
switch (vibration_device_handle.device_index) {
case Core::HID::DeviceIndex::Left:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
break;
case Core::HID::DeviceIndex::Right:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
break;
case Core::HID::DeviceIndex::None:
default:
ASSERT_MSG(false, "DeviceIndex should never be None!");
break;
}
}
LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
vibration_device_info.type, vibration_device_info.position);
const auto result = controller.IsDeviceHandleValid(vibration_device_handle);
if (result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushRaw(vibration_device_info);

View File

@@ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_)
// Register update callbacks
hidbus_update_event = Core::Timing::CreateEvent(
"Hidbus::UpdateCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateHidbus(user_data, ns_late);
return std::nullopt;
});
system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event);
system_.CoreTiming().ScheduleLoopingEvent(hidbus_update_ns, hidbus_update_ns,
hidbus_update_event);
}
HidBus::~HidBus() {
@@ -63,8 +66,6 @@ HidBus::~HidBus() {
}
void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
if (is_hidbus_enabled) {
for (std::size_t i = 0; i < devices.size(); ++i) {
if (!devices[i].is_device_initializated) {
@@ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_
sizeof(HidbusStatusManagerEntry));
}
}
// If ns_late is higher than the update rate ignore the delay
if (ns_late > hidbus_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(hidbus_update_ns - ns_late, hidbus_update_event);
}
std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const {

View File

@@ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
// Schedule the screen composition events
composition_event = Core::Timing::CreateEvent(
"ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
"ScreenComposition",
[this](std::uintptr_t, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto lock_guard = Lock();
Compose();
const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
const auto ticks_delta = ticks - ns_late;
const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta);
this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
return std::max(std::chrono::nanoseconds::zero(),
std::chrono::nanoseconds(GetNextTicks()) - ns_late);
});
if (system.IsMulticore()) {
vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
} else {
system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, composition_event);
}
}

View File

@@ -184,10 +184,12 @@ CheatEngine::~CheatEngine() {
void CheatEngine::Initialize() {
event = Core::Timing::CreateEvent(
"CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
FrameCallback(user_data, ns_late);
return std::nullopt;
});
core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event);
core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event);
metadata.process_id = system.CurrentProcess()->GetProcessID();
metadata.title_id = system.GetCurrentProcessProgramID();
@@ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late
MICROPROFILE_SCOPE(Cheat_Engine);
vm.Execute(metadata);
core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event);
}
} // namespace Core::Memory

View File

@@ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m
: core_timing{core_timing_}, memory{memory_} {
event = Core::Timing::CreateEvent(
"MemoryFreezer::FrameCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
FrameCallback(user_data, ns_late);
return std::nullopt;
});
core_timing.ScheduleEvent(memory_freezer_ns, event);
}

View File

@@ -438,10 +438,17 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
using namespace std::chrono_literals;
while (initialized) {
SDL_PumpEvents();
SendVibrations();
std::this_thread::sleep_for(1ms);
}
});
vibration_thread = std::thread([this] {
Common::SetCurrentThreadName("yuzu:input:SDL_Vibration");
using namespace std::chrono_literals;
while (initialized) {
SendVibrations();
std::this_thread::sleep_for(10ms);
}
});
}
// Because the events for joystick connection happens before we have our event watcher added, we
// can just open all the joysticks right here
@@ -457,6 +464,7 @@ SDLDriver::~SDLDriver() {
initialized = false;
if (start_thread) {
poll_thread.join();
vibration_thread.join();
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
}
}

View File

@@ -128,5 +128,6 @@ private:
std::atomic<bool> initialized = false;
std::thread poll_thread;
std::thread vibration_thread;
};
} // namespace InputCommon

View File

@@ -9,6 +9,7 @@
#include <cstdlib>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include "core/core.h"
@@ -25,13 +26,15 @@ u64 expected_callback = 0;
std::mutex control_mutex;
template <unsigned int IDX>
void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
std::optional<std::chrono::nanoseconds> HostCallbackTemplate(std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) {
std::unique_lock<std::mutex> lk(control_mutex);
static_assert(IDX < CB_IDS.size(), "IDX out of range");
callbacks_ran_flags.set(IDX);
REQUIRE(CB_IDS[IDX] == user_data);
delays[IDX] = ns_late.count();
++expected_callback;
return std::nullopt;
}
struct ScopeInit final {

View File

@@ -131,9 +131,12 @@ constexpr std::array VIEW_CLASS_ASTC_8x8_RGBA{
// PixelFormat::ASTC_2D_10X5_SRGB
// Missing formats:
// PixelFormat::ASTC_2D_10X6_UNORM
// PixelFormat::ASTC_2D_10X6_SRGB
constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{
PixelFormat::ASTC_2D_10X6_UNORM,
};
constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{
PixelFormat::ASTC_2D_10X8_UNORM,
PixelFormat::ASTC_2D_10X8_SRGB,
@@ -226,6 +229,7 @@ constexpr Table MakeViewTable() {
EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA);
EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA);
EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA);
EnableRange(view, VIEW_CLASS_ASTC_10x6_RGBA);
EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA);
EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA);
EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA);

View File

@@ -98,6 +98,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
{GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB
{GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM
{GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB
{GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM
{GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM
{GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB
{GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM

View File

@@ -195,6 +195,7 @@ struct FormatTuple {
{VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB
{VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM
{VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB
{VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM
{VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM
{VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB
{VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM

View File

@@ -247,6 +247,7 @@ bool IsPixelFormatASTC(PixelFormat format) {
case PixelFormat::ASTC_2D_10X8_SRGB:
case PixelFormat::ASTC_2D_6X6_UNORM:
case PixelFormat::ASTC_2D_6X6_SRGB:
case PixelFormat::ASTC_2D_10X6_UNORM:
case PixelFormat::ASTC_2D_10X10_UNORM:
case PixelFormat::ASTC_2D_10X10_SRGB:
case PixelFormat::ASTC_2D_12X12_UNORM:

View File

@@ -94,6 +94,7 @@ enum class PixelFormat {
ASTC_2D_10X8_SRGB,
ASTC_2D_6X6_UNORM,
ASTC_2D_6X6_SRGB,
ASTC_2D_10X6_UNORM,
ASTC_2D_10X10_UNORM,
ASTC_2D_10X10_SRGB,
ASTC_2D_12X12_UNORM,
@@ -227,6 +228,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
10, // ASTC_2D_10X8_SRGB
6, // ASTC_2D_6X6_UNORM
6, // ASTC_2D_6X6_SRGB
10, // ASTC_2D_10X6_UNORM
10, // ASTC_2D_10X10_UNORM
10, // ASTC_2D_10X10_SRGB
12, // ASTC_2D_12X12_UNORM
@@ -329,6 +331,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
8, // ASTC_2D_10X8_SRGB
6, // ASTC_2D_6X6_UNORM
6, // ASTC_2D_6X6_SRGB
6, // ASTC_2D_10X6_UNORM
10, // ASTC_2D_10X10_UNORM
10, // ASTC_2D_10X10_SRGB
12, // ASTC_2D_12X12_UNORM
@@ -431,6 +434,7 @@ constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
128, // ASTC_2D_10X8_SRGB
128, // ASTC_2D_6X6_UNORM
128, // ASTC_2D_6X6_SRGB
128, // ASTC_2D_10X6_UNORM
128, // ASTC_2D_10X10_UNORM
128, // ASTC_2D_10X10_SRGB
128, // ASTC_2D_12X12_UNORM

View File

@@ -206,6 +206,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
return PixelFormat::ASTC_2D_6X6_UNORM;
case Hash(TextureFormat::ASTC_2D_6X6, UNORM, SRGB):
return PixelFormat::ASTC_2D_6X6_SRGB;
case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR):
return PixelFormat::ASTC_2D_10X6_UNORM;
case Hash(TextureFormat::ASTC_2D_10X10, UNORM, LINEAR):
return PixelFormat::ASTC_2D_10X10_UNORM;
case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB):

View File

@@ -175,6 +175,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
return "ASTC_2D_6X6_UNORM";
case PixelFormat::ASTC_2D_6X6_SRGB:
return "ASTC_2D_6X6_SRGB";
case PixelFormat::ASTC_2D_10X6_UNORM:
return "ASTC_2D_10X6_UNORM";
case PixelFormat::ASTC_2D_10X10_UNORM:
return "ASTC_2D_10X10_UNORM";
case PixelFormat::ASTC_2D_10X10_SRGB:

View File

@@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef YUZU_USE_QT_WEB_ENGINE
#include <bit>
#include <QApplication>
#include <QKeyEvent>
@@ -211,8 +213,10 @@ template <Core::HID::NpadButton... T>
void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) {
const auto button_index = std::countr_zero(static_cast<u64>(button));
page()->runJavaScript(
QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)),
QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(button_index),
[this, button](const QVariant& variant) {
if (variant.toBool()) {
switch (button) {
@@ -236,7 +240,7 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
page()->runJavaScript(
QStringLiteral("if (yuzu_key_callbacks[%1] != null) { yuzu_key_callbacks[%1](); }")
.arg(static_cast<u8>(button)));
.arg(button_index));
}
};

View File

@@ -133,7 +133,7 @@ void Config::Initialize(const std::string& config_name) {
// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
// can it implicitly convert a QVariant back to a {std::,Q}string
template <>
void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
void Config::ReadBasicSetting(Settings::Setting<std::string>& setting) {
const QString name = QString::fromStdString(setting.GetLabel());
const auto default_value = QString::fromStdString(setting.GetDefault());
if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
@@ -144,7 +144,7 @@ void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
}
template <typename Type>
void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
void Config::ReadBasicSetting(Settings::Setting<Type>& setting) {
const QString name = QString::fromStdString(setting.GetLabel());
const Type default_value = setting.GetDefault();
if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
@@ -157,7 +157,7 @@ void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant
template <>
void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& setting) {
void Config::WriteBasicSetting(const Settings::Setting<std::string>& setting) {
const QString name = QString::fromStdString(setting.GetLabel());
const std::string& value = setting.GetValue();
qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
@@ -165,7 +165,7 @@ void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& settin
}
template <typename Type>
void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) {
void Config::WriteBasicSetting(const Settings::Setting<Type>& setting) {
const QString name = QString::fromStdString(setting.GetLabel());
const Type value = setting.GetValue();
qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
@@ -173,7 +173,7 @@ void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) {
}
template <typename Type>
void Config::WriteGlobalSetting(const Settings::Setting<Type>& setting) {
void Config::WriteGlobalSetting(const Settings::SwitchableSetting<Type>& setting) {
const QString name = QString::fromStdString(setting.GetLabel());
const Type& value = setting.GetValue(global);
if (!global) {
@@ -1422,7 +1422,7 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
}
template <typename Type>
void Config::ReadGlobalSetting(Settings::Setting<Type>& setting) {
void Config::ReadGlobalSetting(Settings::SwitchableSetting<Type>& setting) {
QString name = QString::fromStdString(setting.GetLabel());
const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
setting.SetGlobal(use_global);

View File

@@ -160,7 +160,7 @@ private:
* @param The setting
*/
template <typename Type>
void ReadGlobalSetting(Settings::Setting<Type>& setting);
void ReadGlobalSetting(Settings::SwitchableSetting<Type>& setting);
/**
* Sets a value to the qt_config using the setting's label and default value. If the config is a
@@ -169,7 +169,7 @@ private:
* @param The setting
*/
template <typename Type>
void WriteGlobalSetting(const Settings::Setting<Type>& setting);
void WriteGlobalSetting(const Settings::SwitchableSetting<Type>& setting);
/**
* Reads a value from the qt_config using the setting's label and default value and applies the
@@ -178,14 +178,14 @@ private:
* @param The setting
*/
template <typename Type>
void ReadBasicSetting(Settings::BasicSetting<Type>& setting);
void ReadBasicSetting(Settings::Setting<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);
void WriteBasicSetting(const Settings::Setting<Type>& setting);
ConfigType type;
std::unique_ptr<QSettings> qt_config;

View File

@@ -9,7 +9,7 @@
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_per_game.h"
void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
void ConfigurationShared::ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting,
const QCheckBox* checkbox,
const CheckState& tracker) {
if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
@@ -25,7 +25,7 @@ void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
}
void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
const Settings::Setting<bool>* setting) {
const Settings::SwitchableSetting<bool>* setting) {
if (setting->UsingGlobal()) {
checkbox->setCheckState(Qt::PartiallyChecked);
} else {
@@ -45,7 +45,7 @@ void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
}
void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox,
const Settings::Setting<bool>& setting,
const Settings::SwitchableSetting<bool>& setting,
CheckState& tracker) {
if (setting.UsingGlobal()) {
tracker = CheckState::Global;

View File

@@ -25,10 +25,10 @@ enum class CheckState {
// Global-aware apply and set functions
// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox,
void ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting, const QCheckBox* checkbox,
const CheckState& tracker);
template <typename Type>
void ApplyPerGameSetting(Settings::Setting<Type>* setting, const QComboBox* combobox) {
void ApplyPerGameSetting(Settings::SwitchableSetting<Type>* setting, const QComboBox* combobox) {
if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
setting->SetValue(static_cast<Type>(combobox->currentIndex()));
} else if (!Settings::IsConfiguringGlobal()) {
@@ -43,10 +43,10 @@ void ApplyPerGameSetting(Settings::Setting<Type>* setting, const QComboBox* comb
}
// Sets a Qt UI element given a Settings::Setting
void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting);
template <typename Type>
void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Type>* setting) {
void SetPerGameSetting(QComboBox* combobox, const Settings::SwitchableSetting<Type>* setting) {
combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
: static_cast<int>(setting->GetValue()) +
ConfigurationShared::USE_GLOBAL_OFFSET);
@@ -56,7 +56,7 @@ void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Type>* setti
void SetHighlight(QWidget* widget, bool highlighted);
// Sets up a QCheckBox like a tristate one, given a Setting
void SetColoredTristate(QCheckBox* checkbox, const Settings::Setting<bool>& setting,
void SetColoredTristate(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>& setting,
CheckState& tracker);
void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
CheckState& tracker);

View File

@@ -64,28 +64,28 @@ struct Values {
QByteArray gamelist_header_state;
QByteArray microprofile_geometry;
Settings::BasicSetting<bool> microprofile_visible{false, "microProfileDialogVisible"};
Settings::Setting<bool> microprofile_visible{false, "microProfileDialogVisible"};
Settings::BasicSetting<bool> single_window_mode{true, "singleWindowMode"};
Settings::BasicSetting<bool> fullscreen{false, "fullscreen"};
Settings::BasicSetting<bool> display_titlebar{true, "displayTitleBars"};
Settings::BasicSetting<bool> show_filter_bar{true, "showFilterBar"};
Settings::BasicSetting<bool> show_status_bar{true, "showStatusBar"};
Settings::Setting<bool> single_window_mode{true, "singleWindowMode"};
Settings::Setting<bool> fullscreen{false, "fullscreen"};
Settings::Setting<bool> display_titlebar{true, "displayTitleBars"};
Settings::Setting<bool> show_filter_bar{true, "showFilterBar"};
Settings::Setting<bool> show_status_bar{true, "showStatusBar"};
Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"};
Settings::BasicSetting<bool> first_start{true, "firstStart"};
Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"};
Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"};
Settings::Setting<bool> confirm_before_closing{true, "confirmClose"};
Settings::Setting<bool> first_start{true, "firstStart"};
Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"};
// Set when Vulkan is known to crash the application
Settings::BasicSetting<bool> has_broken_vulkan{false, "has_broken_vulkan"};
Settings::Setting<bool> has_broken_vulkan{false, "has_broken_vulkan"};
Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"};
Settings::Setting<bool> select_user_on_boot{false, "select_user_on_boot"};
// Discord RPC
Settings::BasicSetting<bool> enable_discord_presence{true, "enable_discord_presence"};
Settings::Setting<bool> enable_discord_presence{true, "enable_discord_presence"};
Settings::BasicSetting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
Settings::Setting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
QString roms_path;
QString symbols_path;
@@ -100,25 +100,25 @@ struct Values {
// Shortcut name <Shortcut, context>
std::vector<Shortcut> shortcuts;
Settings::BasicSetting<uint32_t> callout_flags{0, "calloutFlags"};
Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};
// logging
Settings::BasicSetting<bool> show_console{false, "showConsole"};
Settings::Setting<bool> show_console{false, "showConsole"};
// Game List
Settings::BasicSetting<bool> show_add_ons{true, "show_add_ons"};
Settings::BasicSetting<uint32_t> game_icon_size{64, "game_icon_size"};
Settings::BasicSetting<uint32_t> folder_icon_size{48, "folder_icon_size"};
Settings::BasicSetting<uint8_t> row_1_text_id{3, "row_1_text_id"};
Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"};
Settings::Setting<bool> show_add_ons{true, "show_add_ons"};
Settings::Setting<uint32_t> game_icon_size{64, "game_icon_size"};
Settings::Setting<uint32_t> folder_icon_size{48, "folder_icon_size"};
Settings::Setting<uint8_t> row_1_text_id{3, "row_1_text_id"};
Settings::Setting<uint8_t> row_2_text_id{2, "row_2_text_id"};
std::atomic_bool is_game_list_reload_pending{false};
Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"};
Settings::BasicSetting<bool> favorites_expanded{true, "favorites_expanded"};
Settings::Setting<bool> cache_game_list{true, "cache_game_list"};
Settings::Setting<bool> favorites_expanded{true, "favorites_expanded"};
QVector<u64> favorited_ids;
bool configuration_applied;
bool reset_to_defaults;
Settings::BasicSetting<bool> disable_web_applet{true, "disable_web_applet"};
Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"};
};
extern Values values;

View File

@@ -90,17 +90,17 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs>
}};
template <>
void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) {
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
}
template <>
void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool>& setting) {
void Config::ReadSetting(const std::string& group, Settings::Setting<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) {
void Config::ReadSetting(const std::string& group, Settings::Setting<Type>& setting) {
setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
static_cast<long>(setting.GetDefault())));
}

View File

@@ -28,11 +28,11 @@ public:
private:
/**
* Applies a value read from the sdl2_config to a BasicSetting.
* Applies a value read from the sdl2_config to a Setting.
*
* @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);
void ReadSetting(const std::string& group, Settings::Setting<Type>& setting);
};