Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c6d7da88c7 | |||
| 79824d7d1b | |||
| 9a48f252ae | |||
| f2599534f8 | |||
| 00ce8eff65 | |||
| af79911017 | |||
| b8becb0608 | |||
| 81b2ba1479 | |||
| 7d464f73c9 | |||
| 776f391ff6 | |||
| bc19d28963 | |||
| 1ef64112b3 | |||
| 4503a4ac43 | |||
| 69214ef678 | |||
| 7059bb2bf8 | |||
| 1bfe950acb | |||
| ed5f1a45b7 | |||
| 289f59dabd | |||
| be1a3f7a0f | |||
| 907b2324d3 | |||
| 977904dd84 | |||
| 58219d1f36 | |||
| 5e78ad4378 | |||
| 4a09517336 | |||
| 2c8f4ed27f | |||
| f75544a943 | |||
| cf38faee9b | |||
| 73638ca593 | |||
| 63915bf2de | |||
| 35327dbde3 | |||
| 0e4d4b4beb | |||
| 7dca756f30 | |||
| 2794242331 | |||
| 420987c5bf | |||
| 849c6db335 | |||
| 975a7b3a78 | |||
| 0ddbbb64e5 | |||
| da34d37044 | |||
| c147e9a90e | |||
| a10e112e64 | |||
| bf5b5c1bf4 | |||
| 2c8d337418 | |||
| f28dd32275 | |||
| dc06e11a7b | |||
| eebf39b3c0 | |||
| 5c541b0b42 | |||
| c8b8674ffc | |||
| 87b6e14d7c | |||
| 7ab5767157 | |||
| 5edc96f4a4 | |||
| a949ee0410 | |||
| c7ad195fd3 | |||
| 7905eb0254 | |||
| 92a3daf029 | |||
| 91a4a924b1 | |||
| 8542f2f3fc | |||
| 4d0bdef17d | |||
| 2f0e1f5d02 | |||
| b9f915e07a | |||
| dbcc093d88 | |||
| 38f658d21e | |||
| cf1cd3321d | |||
| 299c5594e6 | |||
| 0e5c74bc9e | |||
| 7a8de138df | |||
| b91b76df4f | |||
| 35b17fa5e0 | |||
| 20e51402b0 |
+4
-3
@@ -47,9 +47,10 @@ if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
|
||||
message(STATUS "Copying pre-commit hook")
|
||||
file(COPY hooks/pre-commit
|
||||
DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
|
||||
if (EXISTS ${PROJECT_SOURCE_DIR}/.git/)
|
||||
message(STATUS "Copying pre-commit hook")
|
||||
file(COPY hooks/pre-commit DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Sanity check : Check that all submodules are present
|
||||
|
||||
@@ -30,7 +30,8 @@ StreamPtr AudioOut::OpenStream(Core::Timing::CoreTiming& core_timing, u32 sample
|
||||
u32 num_channels, std::string&& name,
|
||||
Stream::ReleaseCallback&& release_callback) {
|
||||
if (!sink) {
|
||||
sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
|
||||
sink = CreateSinkFromID(Settings::values.sink_id.GetValue(),
|
||||
Settings::values.audio_device_id.GetValue());
|
||||
}
|
||||
|
||||
return std::make_shared<Stream>(
|
||||
|
||||
@@ -42,6 +42,15 @@ void ApplyMix(std::span<s32> output, std::span<const s32> input, s32 gain, s32 s
|
||||
|
||||
s32 ApplyMixRamp(std::span<s32> output, std::span<const s32> input, float gain, float delta,
|
||||
s32 sample_count) {
|
||||
// XC2 passes in NaN mix volumes, causing further issues as we handle everything as s32 rather
|
||||
// than float, so the NaN propogation is lost. As the samples get further modified for
|
||||
// volume etc, they can get out of NaN range, so a later heuristic for catching this is
|
||||
// more difficult. Handle it here by setting these samples to silence.
|
||||
if (std::isnan(gain)) {
|
||||
gain = 0.0f;
|
||||
delta = 0.0f;
|
||||
}
|
||||
|
||||
s32 x = 0;
|
||||
for (s32 i = 0; i < sample_count; i++) {
|
||||
x = static_cast<s32>(static_cast<float>(input[i]) * gain);
|
||||
@@ -403,7 +412,10 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
|
||||
}
|
||||
} else {
|
||||
switch (in_params.sample_format) {
|
||||
case SampleFormat::Pcm8:
|
||||
case SampleFormat::Pcm16:
|
||||
case SampleFormat::Pcm32:
|
||||
case SampleFormat::PcmFloat:
|
||||
DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel,
|
||||
worker_params.sample_rate, worker_params.sample_count,
|
||||
in_params.node_id);
|
||||
@@ -1009,9 +1021,10 @@ void CommandGenerator::GenerateFinalMixCommand() {
|
||||
}
|
||||
}
|
||||
|
||||
s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
|
||||
s32 sample_start_offset, s32 sample_end_offset, s32 sample_count,
|
||||
s32 channel, std::size_t mix_offset) {
|
||||
template <typename T>
|
||||
s32 CommandGenerator::DecodePcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
|
||||
s32 sample_start_offset, s32 sample_end_offset, s32 sample_count,
|
||||
s32 channel, std::size_t mix_offset) {
|
||||
const auto& in_params = voice_info.GetInParams();
|
||||
const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
|
||||
if (wave_buffer.buffer_address == 0) {
|
||||
@@ -1025,24 +1038,37 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
|
||||
}
|
||||
const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset;
|
||||
const auto start_offset =
|
||||
((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(s16);
|
||||
((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(T);
|
||||
const auto buffer_pos = wave_buffer.buffer_address + start_offset;
|
||||
const auto samples_processed = std::min(sample_count, samples_remaining);
|
||||
|
||||
if (in_params.channel_count == 1) {
|
||||
std::vector<s16> buffer(samples_processed);
|
||||
memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
|
||||
for (std::size_t i = 0; i < buffer.size(); i++) {
|
||||
sample_buffer[mix_offset + i] = buffer[i];
|
||||
}
|
||||
} else {
|
||||
const auto channel_count = in_params.channel_count;
|
||||
std::vector<s16> buffer(samples_processed * channel_count);
|
||||
memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
|
||||
const auto channel_count = in_params.channel_count;
|
||||
std::vector<T> buffer(samples_processed * channel_count);
|
||||
memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(T));
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
|
||||
sample_buffer[mix_offset + i] = static_cast<s32>(buffer[i * channel_count + channel] *
|
||||
std::numeric_limits<s16>::max());
|
||||
}
|
||||
} else if constexpr (sizeof(T) == 1) {
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
|
||||
sample_buffer[mix_offset + i] =
|
||||
static_cast<s32>(static_cast<f32>(buffer[i * channel_count + channel] /
|
||||
std::numeric_limits<s8>::max()) *
|
||||
std::numeric_limits<s16>::max());
|
||||
}
|
||||
} else if constexpr (sizeof(T) == 2) {
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
|
||||
sample_buffer[mix_offset + i] = buffer[i * channel_count + channel];
|
||||
}
|
||||
} else {
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
|
||||
sample_buffer[mix_offset + i] =
|
||||
static_cast<s32>(static_cast<f32>(buffer[i * channel_count + channel] /
|
||||
std::numeric_limits<s32>::max()) *
|
||||
std::numeric_limits<s16>::max());
|
||||
}
|
||||
}
|
||||
|
||||
return samples_processed;
|
||||
@@ -1258,10 +1284,25 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::s
|
||||
|
||||
s32 samples_decoded{0};
|
||||
switch (in_params.sample_format) {
|
||||
case SampleFormat::Pcm8:
|
||||
samples_decoded =
|
||||
DecodePcm<s8>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
|
||||
samples_to_read - samples_read, channel, temp_mix_offset);
|
||||
break;
|
||||
case SampleFormat::Pcm16:
|
||||
samples_decoded =
|
||||
DecodePcm16(voice_info, dsp_state, samples_offset_start, samples_offset_end,
|
||||
samples_to_read - samples_read, channel, temp_mix_offset);
|
||||
DecodePcm<s16>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
|
||||
samples_to_read - samples_read, channel, temp_mix_offset);
|
||||
break;
|
||||
case SampleFormat::Pcm32:
|
||||
samples_decoded =
|
||||
DecodePcm<s32>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
|
||||
samples_to_read - samples_read, channel, temp_mix_offset);
|
||||
break;
|
||||
case SampleFormat::PcmFloat:
|
||||
samples_decoded =
|
||||
DecodePcm<f32>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
|
||||
samples_to_read - samples_read, channel, temp_mix_offset);
|
||||
break;
|
||||
case SampleFormat::Adpcm:
|
||||
samples_decoded =
|
||||
|
||||
@@ -88,8 +88,9 @@ private:
|
||||
std::vector<u8>& work_buffer);
|
||||
void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear);
|
||||
// DSP Code
|
||||
s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
|
||||
s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
|
||||
template <typename T>
|
||||
s32 DecodePcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
|
||||
s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
|
||||
s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
|
||||
s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
|
||||
void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::span<s32> output,
|
||||
|
||||
@@ -180,7 +180,6 @@ add_library(common STATIC
|
||||
thread.cpp
|
||||
thread.h
|
||||
thread_queue_list.h
|
||||
thread_worker.cpp
|
||||
thread_worker.h
|
||||
threadsafe_queue.h
|
||||
time_zone.cpp
|
||||
@@ -188,6 +187,7 @@ add_library(common STATIC
|
||||
tiny_mt.h
|
||||
tree.h
|
||||
uint128.h
|
||||
unique_function.h
|
||||
uuid.cpp
|
||||
uuid.h
|
||||
vector_math.h
|
||||
|
||||
@@ -41,7 +41,7 @@ void LogSettings() {
|
||||
LOG_INFO(Config, "yuzu Configuration:");
|
||||
log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
|
||||
log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
|
||||
log_setting("System_CurrentUser", values.current_user);
|
||||
log_setting("System_CurrentUser", values.current_user.GetValue());
|
||||
log_setting("System_LanguageIndex", values.language_index.GetValue());
|
||||
log_setting("System_RegionIndex", values.region_index.GetValue());
|
||||
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
|
||||
@@ -61,18 +61,18 @@ void LogSettings() {
|
||||
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
|
||||
log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
|
||||
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
|
||||
log_setting("Audio_OutputEngine", values.sink_id);
|
||||
log_setting("Audio_OutputEngine", values.sink_id.GetValue());
|
||||
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
|
||||
log_setting("Audio_OutputDevice", values.audio_device_id);
|
||||
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
||||
log_setting("Audio_OutputDevice", values.audio_device_id.GetValue());
|
||||
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
|
||||
log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
|
||||
log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
|
||||
log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
|
||||
log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
|
||||
log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
|
||||
log_setting("Debugging_ProgramArgs", values.program_args);
|
||||
log_setting("Services_BCATBackend", values.bcat_backend);
|
||||
log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local);
|
||||
log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
|
||||
log_setting("Services_BCATBackend", values.bcat_backend.GetValue());
|
||||
log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local.GetValue());
|
||||
}
|
||||
|
||||
bool IsConfiguringGlobal() {
|
||||
@@ -93,8 +93,8 @@ bool IsGPULevelHigh() {
|
||||
}
|
||||
|
||||
bool IsFastmemEnabled() {
|
||||
if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) {
|
||||
return values.cpuopt_fastmem;
|
||||
if (values.cpu_debug_mode) {
|
||||
return static_cast<bool>(values.cpuopt_fastmem);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+311
-128
@@ -10,10 +10,12 @@
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings_input.h"
|
||||
#include "input_common/udp/client.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
@@ -29,73 +31,240 @@ enum class GPUAccuracy : u32 {
|
||||
};
|
||||
|
||||
enum class CPUAccuracy : u32 {
|
||||
Accurate = 0,
|
||||
Unsafe = 1,
|
||||
DebugMode = 2,
|
||||
Auto = 0,
|
||||
Accurate = 1,
|
||||
Unsafe = 2,
|
||||
};
|
||||
|
||||
/** The BasicSetting class is a simple resource manager. It defines a label and default value
|
||||
* alongside the actual value of the setting for simpler and less-error prone use with frontend
|
||||
* configurations. Setting a default value and label is required, though subclasses may deviate from
|
||||
* this requirement.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Setting final {
|
||||
class BasicSetting {
|
||||
protected:
|
||||
BasicSetting() = default;
|
||||
|
||||
/**
|
||||
* Only sets the setting to the given initializer, leaving the other members to their default
|
||||
* initializers.
|
||||
*
|
||||
* @param global_val Initial value of the setting
|
||||
*/
|
||||
explicit BasicSetting(const Type& global_val) : global{global_val} {}
|
||||
|
||||
public:
|
||||
Setting() = default;
|
||||
explicit Setting(Type val) : global{val} {}
|
||||
~Setting() = default;
|
||||
void SetGlobal(bool to_global) {
|
||||
use_global = to_global;
|
||||
}
|
||||
bool UsingGlobal() const {
|
||||
return use_global;
|
||||
}
|
||||
Type GetValue(bool need_global = false) const {
|
||||
if (use_global || need_global) {
|
||||
return global;
|
||||
}
|
||||
return local;
|
||||
}
|
||||
void SetValue(const Type& value) {
|
||||
if (use_global) {
|
||||
global = value;
|
||||
} else {
|
||||
local = value;
|
||||
}
|
||||
/**
|
||||
* 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 BasicSetting(const Type& default_val, const std::string& name)
|
||||
: default_value{default_val}, global{default_val}, label{name} {}
|
||||
~BasicSetting() = default;
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting's value.
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
[[nodiscard]] const Type& GetValue() const {
|
||||
return global;
|
||||
}
|
||||
|
||||
private:
|
||||
bool use_global = true;
|
||||
Type global{};
|
||||
Type local{};
|
||||
/**
|
||||
* Sets the setting to the given value.
|
||||
*
|
||||
* @param value The desired value
|
||||
*/
|
||||
void SetValue(const Type& value) {
|
||||
Type temp{value};
|
||||
std::swap(global, temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that this setting was created with.
|
||||
*
|
||||
* @returns A reference to the default value
|
||||
*/
|
||||
[[nodiscard]] const Type& GetDefault() const {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label this setting was created with.
|
||||
*
|
||||
* @returns A reference to the label
|
||||
*/
|
||||
[[nodiscard]] const std::string& GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a value to the setting.
|
||||
*
|
||||
* @param value The desired setting value
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
const Type& operator=(const Type& value) {
|
||||
Type temp{value};
|
||||
std::swap(global, temp);
|
||||
return global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting.
|
||||
*
|
||||
* @returns A reference to the setting
|
||||
*/
|
||||
explicit operator const Type&() const {
|
||||
return global;
|
||||
}
|
||||
|
||||
protected:
|
||||
const Type default_value{}; ///< The default value
|
||||
Type global{}; ///< The setting
|
||||
const std::string label{}; ///< The setting's label
|
||||
};
|
||||
|
||||
/**
|
||||
* The InputSetting class allows for getting a reference to either the global or local members.
|
||||
* The Setting class is a slightly more complex version of the BasicSetting class. This adds a
|
||||
* custom setting to switch to when a guest application specifically requires it. The effect is that
|
||||
* other components of the emulator can access the setting's intended value without any need for the
|
||||
* component to ask whether the custom or global setting is needed at the moment.
|
||||
*
|
||||
* By default, the global setting is used.
|
||||
*
|
||||
* Like the BasicSetting, this requires setting a default value and label to use.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Setting final : public BasicSetting<Type> {
|
||||
public:
|
||||
/**
|
||||
* Sets a default value, label, and setting value.
|
||||
*
|
||||
* @param default_val Intial value of the setting, and default value of the setting
|
||||
* @param name Label for the setting
|
||||
*/
|
||||
explicit Setting(const Type& default_val, const std::string& name)
|
||||
: BasicSetting<Type>(default_val, name) {}
|
||||
~Setting() = default;
|
||||
|
||||
/**
|
||||
* Tells this setting to represent either the global or custom setting when other member
|
||||
* functions are used.
|
||||
*
|
||||
* @param to_global Whether to use the global or custom setting.
|
||||
*/
|
||||
void SetGlobal(bool to_global) {
|
||||
use_global = to_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this setting is using the global setting or not.
|
||||
*
|
||||
* @returns The global state
|
||||
*/
|
||||
[[nodiscard]] bool UsingGlobal() const {
|
||||
return use_global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either the global or custom setting depending on the values of this setting's global
|
||||
* state or if the global value was specifically requested.
|
||||
*
|
||||
* @param need_global Request global value regardless of setting's state; defaults to false
|
||||
*
|
||||
* @returns The required value of the setting
|
||||
*/
|
||||
[[nodiscard]] const Type& GetValue(bool need_global = false) const {
|
||||
if (use_global || need_global) {
|
||||
return this->global;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current setting value depending on the global state.
|
||||
*
|
||||
* @param value The new value
|
||||
*/
|
||||
void SetValue(const Type& value) {
|
||||
Type temp{value};
|
||||
if (use_global) {
|
||||
std::swap(this->global, temp);
|
||||
} else {
|
||||
std::swap(custom, temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the current setting value depending on the global state.
|
||||
*
|
||||
* @param value The new value
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
const Type& operator=(const Type& value) {
|
||||
Type temp{value};
|
||||
if (use_global) {
|
||||
std::swap(this->global, temp);
|
||||
return this->global;
|
||||
}
|
||||
std::swap(custom, temp);
|
||||
return custom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting value depending on the global state.
|
||||
*
|
||||
* @returns A reference to the current setting value
|
||||
*/
|
||||
explicit operator const Type&() const {
|
||||
if (use_global) {
|
||||
return this->global;
|
||||
}
|
||||
return custom;
|
||||
}
|
||||
|
||||
private:
|
||||
bool use_global{true}; ///< The setting's global state
|
||||
Type custom{}; ///< The custom value of the setting
|
||||
};
|
||||
|
||||
/**
|
||||
* The InputSetting class allows for getting a reference to either the global or custom members.
|
||||
* This is required as we cannot easily modify the values of user-defined types within containers
|
||||
* using the SetValue() member function found in the Setting class. The primary purpose of this
|
||||
* class is to store an array of 10 PlayerInput structs for both the global and local (per-game)
|
||||
* setting and allows for easily accessing and modifying both settings.
|
||||
* class is to store an array of 10 PlayerInput structs for both the global and custom setting and
|
||||
* allows for easily accessing and modifying both settings.
|
||||
*/
|
||||
template <typename Type>
|
||||
class InputSetting final {
|
||||
public:
|
||||
InputSetting() = default;
|
||||
explicit InputSetting(Type val) : global{val} {}
|
||||
explicit InputSetting(Type val) : BasicSetting<Type>(val) {}
|
||||
~InputSetting() = default;
|
||||
void SetGlobal(bool to_global) {
|
||||
use_global = to_global;
|
||||
}
|
||||
bool UsingGlobal() const {
|
||||
[[nodiscard]] bool UsingGlobal() const {
|
||||
return use_global;
|
||||
}
|
||||
Type& GetValue(bool need_global = false) {
|
||||
[[nodiscard]] Type& GetValue(bool need_global = false) {
|
||||
if (use_global || need_global) {
|
||||
return global;
|
||||
}
|
||||
return local;
|
||||
return custom;
|
||||
}
|
||||
|
||||
private:
|
||||
bool use_global = true;
|
||||
Type global{};
|
||||
Type local{};
|
||||
bool use_global{true}; ///< The setting's global state
|
||||
Type global{}; ///< The setting
|
||||
Type custom{}; ///< The custom setting value
|
||||
};
|
||||
|
||||
struct TouchFromButtonMap {
|
||||
@@ -105,144 +274,158 @@ struct TouchFromButtonMap {
|
||||
|
||||
struct Values {
|
||||
// Audio
|
||||
std::string audio_device_id;
|
||||
std::string sink_id;
|
||||
bool audio_muted;
|
||||
Setting<bool> enable_audio_stretching;
|
||||
Setting<float> volume;
|
||||
BasicSetting<std::string> audio_device_id{"auto", "output_device"};
|
||||
BasicSetting<std::string> sink_id{"auto", "output_engine"};
|
||||
BasicSetting<bool> audio_muted{false, "audio_muted"};
|
||||
Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
|
||||
Setting<float> volume{1.0f, "volume"};
|
||||
|
||||
// Core
|
||||
Setting<bool> use_multi_core;
|
||||
Setting<bool> use_multi_core{true, "use_multi_core"};
|
||||
|
||||
// Cpu
|
||||
Setting<CPUAccuracy> cpu_accuracy;
|
||||
Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, "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"};
|
||||
|
||||
bool cpuopt_page_tables;
|
||||
bool cpuopt_block_linking;
|
||||
bool cpuopt_return_stack_buffer;
|
||||
bool cpuopt_fast_dispatcher;
|
||||
bool cpuopt_context_elimination;
|
||||
bool cpuopt_const_prop;
|
||||
bool cpuopt_misc_ir;
|
||||
bool cpuopt_reduce_misalign_checks;
|
||||
bool cpuopt_fastmem;
|
||||
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"};
|
||||
|
||||
Setting<bool> cpuopt_unsafe_unfuse_fma;
|
||||
Setting<bool> cpuopt_unsafe_reduce_fp_error;
|
||||
Setting<bool> cpuopt_unsafe_ignore_standard_fpcr;
|
||||
Setting<bool> cpuopt_unsafe_inaccurate_nan;
|
||||
Setting<bool> cpuopt_unsafe_fastmem_check;
|
||||
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"};
|
||||
|
||||
// Renderer
|
||||
Setting<RendererBackend> renderer_backend;
|
||||
bool renderer_debug;
|
||||
Setting<int> vulkan_device;
|
||||
Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
|
||||
BasicSetting<bool> renderer_debug{false, "debug"};
|
||||
Setting<int> vulkan_device{0, "vulkan_device"};
|
||||
|
||||
Setting<u16> resolution_factor{1};
|
||||
Setting<int> fullscreen_mode;
|
||||
Setting<int> aspect_ratio;
|
||||
Setting<int> max_anisotropy;
|
||||
Setting<bool> use_frame_limit;
|
||||
Setting<u16> frame_limit;
|
||||
Setting<bool> use_disk_shader_cache;
|
||||
Setting<GPUAccuracy> gpu_accuracy;
|
||||
Setting<bool> use_asynchronous_gpu_emulation;
|
||||
Setting<bool> use_nvdec_emulation;
|
||||
Setting<bool> accelerate_astc;
|
||||
Setting<bool> use_vsync;
|
||||
Setting<bool> disable_fps_limit;
|
||||
Setting<bool> use_assembly_shaders;
|
||||
Setting<bool> use_asynchronous_shaders;
|
||||
Setting<bool> use_fast_gpu_time;
|
||||
Setting<bool> use_caches_gc;
|
||||
Setting<u16> resolution_factor{1, "resolution_factor"};
|
||||
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||
// Default to exclusive fullscreen on these platforms for now.
|
||||
Setting<int> fullscreen_mode{
|
||||
#ifdef _WIN32
|
||||
0,
|
||||
#else
|
||||
1,
|
||||
#endif
|
||||
"fullscreen_mode"};
|
||||
Setting<int> aspect_ratio{0, "aspect_ratio"};
|
||||
Setting<int> max_anisotropy{0, "max_anisotropy"};
|
||||
Setting<bool> use_frame_limit{true, "use_frame_limit"};
|
||||
Setting<u16> frame_limit{100, "frame_limit"};
|
||||
Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
|
||||
Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
|
||||
Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
|
||||
Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
|
||||
Setting<bool> accelerate_astc{true, "accelerate_astc"};
|
||||
Setting<bool> use_vsync{true, "use_vsync"};
|
||||
BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
|
||||
Setting<bool> use_assembly_shaders{false, "use_assembly_shaders"};
|
||||
Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
|
||||
Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
|
||||
Setting<bool> use_caches_gc{false, "use_caches_gc"};
|
||||
|
||||
Setting<float> bg_red;
|
||||
Setting<float> bg_green;
|
||||
Setting<float> bg_blue;
|
||||
Setting<float> bg_red{0.0f, "bg_red"};
|
||||
Setting<float> bg_green{0.0f, "bg_green"};
|
||||
Setting<float> bg_blue{0.0f, "bg_blue"};
|
||||
|
||||
// System
|
||||
Setting<std::optional<u32>> rng_seed;
|
||||
Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
|
||||
// Measured in seconds since epoch
|
||||
std::optional<std::chrono::seconds> custom_rtc;
|
||||
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
|
||||
std::chrono::seconds custom_rtc_differential;
|
||||
|
||||
s32 current_user;
|
||||
Setting<s32> language_index;
|
||||
Setting<s32> region_index;
|
||||
Setting<s32> time_zone_index;
|
||||
Setting<s32> sound_index;
|
||||
BasicSetting<s32> current_user{0, "current_user"};
|
||||
Setting<s32> language_index{1, "language_index"};
|
||||
Setting<s32> region_index{1, "region_index"};
|
||||
Setting<s32> time_zone_index{0, "time_zone_index"};
|
||||
Setting<s32> sound_index{1, "sound_index"};
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
|
||||
Setting<bool> use_docked_mode;
|
||||
Setting<bool> use_docked_mode{true, "use_docked_mode"};
|
||||
|
||||
Setting<bool> vibration_enabled;
|
||||
Setting<bool> enable_accurate_vibrations;
|
||||
Setting<bool> vibration_enabled{true, "vibration_enabled"};
|
||||
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
|
||||
|
||||
Setting<bool> motion_enabled;
|
||||
std::string motion_device;
|
||||
std::string udp_input_servers;
|
||||
Setting<bool> motion_enabled{true, "motion_enabled"};
|
||||
BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01",
|
||||
"motion_device"};
|
||||
BasicSetting<std::string> udp_input_servers{InputCommon::CemuhookUDP::DEFAULT_SRV,
|
||||
"udp_input_servers"};
|
||||
|
||||
bool mouse_panning;
|
||||
float mouse_panning_sensitivity;
|
||||
bool mouse_enabled;
|
||||
BasicSetting<bool> mouse_panning{false, "mouse_panning"};
|
||||
BasicSetting<float> mouse_panning_sensitivity{1.0f, "mouse_panning_sensitivity"};
|
||||
BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
|
||||
std::string mouse_device;
|
||||
MouseButtonsRaw mouse_buttons;
|
||||
|
||||
bool emulate_analog_keyboard;
|
||||
bool keyboard_enabled;
|
||||
BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
|
||||
BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
|
||||
KeyboardKeysRaw keyboard_keys;
|
||||
KeyboardModsRaw keyboard_mods;
|
||||
|
||||
bool debug_pad_enabled;
|
||||
BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
|
||||
ButtonsRaw debug_pad_buttons;
|
||||
AnalogsRaw debug_pad_analogs;
|
||||
|
||||
TouchscreenInput touchscreen;
|
||||
|
||||
bool use_touch_from_button;
|
||||
std::string touch_device;
|
||||
int touch_from_button_map_index;
|
||||
BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};
|
||||
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"};
|
||||
std::vector<TouchFromButtonMap> touch_from_button_maps;
|
||||
|
||||
std::atomic_bool is_device_reload_pending{true};
|
||||
|
||||
// Data Storage
|
||||
bool use_virtual_sd;
|
||||
bool gamecard_inserted;
|
||||
bool gamecard_current_game;
|
||||
std::string gamecard_path;
|
||||
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"};
|
||||
|
||||
// Debugging
|
||||
bool record_frame_times;
|
||||
bool use_gdbstub;
|
||||
u16 gdbstub_port;
|
||||
std::string program_args;
|
||||
bool dump_exefs;
|
||||
bool dump_nso;
|
||||
bool enable_fs_access_log;
|
||||
bool reporting_services;
|
||||
bool quest_flag;
|
||||
bool disable_macro_jit;
|
||||
bool extended_logging;
|
||||
bool use_debug_asserts;
|
||||
bool use_auto_stub;
|
||||
BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
|
||||
BasicSetting<u16> gdbstub_port{0, "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> 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"};
|
||||
|
||||
// Miscellaneous
|
||||
std::string log_filter;
|
||||
bool use_dev_keys;
|
||||
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
|
||||
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
|
||||
|
||||
// Services
|
||||
std::string bcat_backend;
|
||||
bool bcat_boxcat_local;
|
||||
BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
|
||||
BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
|
||||
|
||||
// WebService
|
||||
bool enable_telemetry;
|
||||
std::string web_api_url;
|
||||
std::string yuzu_username;
|
||||
std::string yuzu_token;
|
||||
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"};
|
||||
|
||||
// Add-Ons
|
||||
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/thread.h"
|
||||
#include "common/thread_worker.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) {
|
||||
for (std::size_t i = 0; i < num_workers; ++i)
|
||||
threads.emplace_back([this, thread_name{std::string{name}}] {
|
||||
Common::SetCurrentThreadName(thread_name.c_str());
|
||||
|
||||
// Wait for first request
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
condition.wait(lock, [this] { return stop || !requests.empty(); });
|
||||
}
|
||||
|
||||
while (true) {
|
||||
std::function<void()> task;
|
||||
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
condition.wait(lock, [this] { return stop || !requests.empty(); });
|
||||
if (stop || requests.empty()) {
|
||||
return;
|
||||
}
|
||||
task = std::move(requests.front());
|
||||
requests.pop();
|
||||
}
|
||||
|
||||
task();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ThreadWorker::~ThreadWorker() {
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
stop = true;
|
||||
}
|
||||
condition.notify_all();
|
||||
for (std::thread& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadWorker::QueueWork(std::function<void()>&& work) {
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
requests.emplace(work);
|
||||
}
|
||||
condition.notify_one();
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
@@ -7,24 +7,110 @@
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <stop_token>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include "common/thread.h"
|
||||
#include "common/unique_function.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
class ThreadWorker final {
|
||||
template <class StateType = void>
|
||||
class StatefulThreadWorker {
|
||||
static constexpr bool with_state = !std::is_same_v<StateType, void>;
|
||||
|
||||
struct DummyCallable {
|
||||
int operator()() const noexcept {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
using Task =
|
||||
std::conditional_t<with_state, UniqueFunction<void, StateType*>, UniqueFunction<void>>;
|
||||
using StateMaker = std::conditional_t<with_state, std::function<StateType()>, DummyCallable>;
|
||||
|
||||
public:
|
||||
explicit ThreadWorker(std::size_t num_workers, const std::string& name);
|
||||
~ThreadWorker();
|
||||
void QueueWork(std::function<void()>&& work);
|
||||
explicit StatefulThreadWorker(size_t num_workers, std::string name, StateMaker func = {})
|
||||
: workers_queued{num_workers}, thread_name{std::move(name)} {
|
||||
const auto lambda = [this, func](std::stop_token stop_token) {
|
||||
Common::SetCurrentThreadName(thread_name.c_str());
|
||||
{
|
||||
std::conditional_t<with_state, StateType, int> state{func()};
|
||||
while (!stop_token.stop_requested()) {
|
||||
Task task;
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
if (requests.empty()) {
|
||||
wait_condition.notify_all();
|
||||
}
|
||||
condition.wait(lock, stop_token, [this] { return !requests.empty(); });
|
||||
if (stop_token.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
task = std::move(requests.front());
|
||||
requests.pop();
|
||||
}
|
||||
if constexpr (with_state) {
|
||||
task(&state);
|
||||
} else {
|
||||
task();
|
||||
}
|
||||
++work_done;
|
||||
}
|
||||
}
|
||||
++workers_stopped;
|
||||
wait_condition.notify_all();
|
||||
};
|
||||
threads.reserve(num_workers);
|
||||
for (size_t i = 0; i < num_workers; ++i) {
|
||||
threads.emplace_back(lambda);
|
||||
}
|
||||
}
|
||||
|
||||
StatefulThreadWorker& operator=(const StatefulThreadWorker&) = delete;
|
||||
StatefulThreadWorker(const StatefulThreadWorker&) = delete;
|
||||
|
||||
StatefulThreadWorker& operator=(StatefulThreadWorker&&) = delete;
|
||||
StatefulThreadWorker(StatefulThreadWorker&&) = delete;
|
||||
|
||||
void QueueWork(Task work) {
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
requests.emplace(std::move(work));
|
||||
++work_scheduled;
|
||||
}
|
||||
condition.notify_one();
|
||||
}
|
||||
|
||||
void WaitForRequests(std::stop_token stop_token = {}) {
|
||||
std::stop_callback callback(stop_token, [this] {
|
||||
for (auto& thread : threads) {
|
||||
thread.request_stop();
|
||||
}
|
||||
});
|
||||
std::unique_lock lock{queue_mutex};
|
||||
wait_condition.wait(lock, [this] {
|
||||
return workers_stopped >= workers_queued || work_done >= work_scheduled;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::thread> threads;
|
||||
std::queue<std::function<void()>> requests;
|
||||
std::queue<Task> requests;
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
std::atomic_bool stop{};
|
||||
std::condition_variable_any condition;
|
||||
std::condition_variable wait_condition;
|
||||
std::atomic<size_t> work_scheduled{};
|
||||
std::atomic<size_t> work_done{};
|
||||
std::atomic<size_t> workers_stopped{};
|
||||
std::atomic<size_t> workers_queued{};
|
||||
std::string thread_name;
|
||||
std::vector<std::jthread> threads;
|
||||
};
|
||||
|
||||
using ThreadWorker = StatefulThreadWorker<>;
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace Common {
|
||||
|
||||
/// General purpose function wrapper similar to std::function.
|
||||
/// Unlike std::function, the captured values don't have to be copyable.
|
||||
/// This class can be moved but not copied.
|
||||
template <typename ResultType, typename... Args>
|
||||
class UniqueFunction {
|
||||
class CallableBase {
|
||||
public:
|
||||
virtual ~CallableBase() = default;
|
||||
virtual ResultType operator()(Args&&...) = 0;
|
||||
};
|
||||
|
||||
template <typename Functor>
|
||||
class Callable final : public CallableBase {
|
||||
public:
|
||||
Callable(Functor&& functor_) : functor{std::move(functor_)} {}
|
||||
~Callable() override = default;
|
||||
|
||||
ResultType operator()(Args&&... args) override {
|
||||
return functor(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Functor functor;
|
||||
};
|
||||
|
||||
public:
|
||||
UniqueFunction() = default;
|
||||
|
||||
template <typename Functor>
|
||||
UniqueFunction(Functor&& functor)
|
||||
: callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
|
||||
|
||||
UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
|
||||
UniqueFunction(UniqueFunction&& rhs) noexcept = default;
|
||||
|
||||
UniqueFunction& operator=(const UniqueFunction&) = delete;
|
||||
UniqueFunction(const UniqueFunction&) = delete;
|
||||
|
||||
ResultType operator()(Args&&... args) const {
|
||||
return (*callable)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return static_cast<bool>(callable);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CallableBase> callable;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
+36
-36
@@ -272,22 +272,22 @@ add_library(core STATIC
|
||||
hle/service/am/applet_ae.h
|
||||
hle/service/am/applet_oe.cpp
|
||||
hle/service/am/applet_oe.h
|
||||
hle/service/am/applets/applet_controller.cpp
|
||||
hle/service/am/applets/applet_controller.h
|
||||
hle/service/am/applets/applet_error.cpp
|
||||
hle/service/am/applets/applet_error.h
|
||||
hle/service/am/applets/applet_general_backend.cpp
|
||||
hle/service/am/applets/applet_general_backend.h
|
||||
hle/service/am/applets/applet_profile_select.cpp
|
||||
hle/service/am/applets/applet_profile_select.h
|
||||
hle/service/am/applets/applet_software_keyboard.cpp
|
||||
hle/service/am/applets/applet_software_keyboard.h
|
||||
hle/service/am/applets/applet_software_keyboard_types.h
|
||||
hle/service/am/applets/applet_web_browser.cpp
|
||||
hle/service/am/applets/applet_web_browser.h
|
||||
hle/service/am/applets/applet_web_browser_types.h
|
||||
hle/service/am/applets/applets.cpp
|
||||
hle/service/am/applets/applets.h
|
||||
hle/service/am/applets/controller.cpp
|
||||
hle/service/am/applets/controller.h
|
||||
hle/service/am/applets/error.cpp
|
||||
hle/service/am/applets/error.h
|
||||
hle/service/am/applets/general_backend.cpp
|
||||
hle/service/am/applets/general_backend.h
|
||||
hle/service/am/applets/profile_select.cpp
|
||||
hle/service/am/applets/profile_select.h
|
||||
hle/service/am/applets/software_keyboard.cpp
|
||||
hle/service/am/applets/software_keyboard.h
|
||||
hle/service/am/applets/software_keyboard_types.h
|
||||
hle/service/am/applets/web_browser.cpp
|
||||
hle/service/am/applets/web_browser.h
|
||||
hle/service/am/applets/web_types.h
|
||||
hle/service/am/idle.cpp
|
||||
hle/service/am/idle.h
|
||||
hle/service/am/omm.cpp
|
||||
@@ -300,10 +300,10 @@ add_library(core STATIC
|
||||
hle/service/aoc/aoc_u.h
|
||||
hle/service/apm/apm.cpp
|
||||
hle/service/apm/apm.h
|
||||
hle/service/apm/controller.cpp
|
||||
hle/service/apm/controller.h
|
||||
hle/service/apm/interface.cpp
|
||||
hle/service/apm/interface.h
|
||||
hle/service/apm/apm_controller.cpp
|
||||
hle/service/apm/apm_controller.h
|
||||
hle/service/apm/apm_interface.cpp
|
||||
hle/service/apm/apm_interface.h
|
||||
hle/service/audio/audctl.cpp
|
||||
hle/service/audio/audctl.h
|
||||
hle/service/audio/auddbg.cpp
|
||||
@@ -335,8 +335,8 @@ add_library(core STATIC
|
||||
hle/service/bcat/backend/backend.h
|
||||
hle/service/bcat/bcat.cpp
|
||||
hle/service/bcat/bcat.h
|
||||
hle/service/bcat/module.cpp
|
||||
hle/service/bcat/module.h
|
||||
hle/service/bcat/bcat_module.cpp
|
||||
hle/service/bcat/bcat_module.h
|
||||
hle/service/bpc/bpc.cpp
|
||||
hle/service/bpc/bpc.h
|
||||
hle/service/btdrv/btdrv.cpp
|
||||
@@ -382,8 +382,8 @@ add_library(core STATIC
|
||||
hle/service/friend/errors.h
|
||||
hle/service/friend/friend.cpp
|
||||
hle/service/friend/friend.h
|
||||
hle/service/friend/interface.cpp
|
||||
hle/service/friend/interface.h
|
||||
hle/service/friend/friend_interface.cpp
|
||||
hle/service/friend/friend_interface.h
|
||||
hle/service/glue/arp.cpp
|
||||
hle/service/glue/arp.h
|
||||
hle/service/glue/bgtc.cpp
|
||||
@@ -393,8 +393,8 @@ add_library(core STATIC
|
||||
hle/service/glue/errors.h
|
||||
hle/service/glue/glue.cpp
|
||||
hle/service/glue/glue.h
|
||||
hle/service/glue/manager.cpp
|
||||
hle/service/glue/manager.h
|
||||
hle/service/glue/glue_manager.cpp
|
||||
hle/service/glue/glue_manager.h
|
||||
hle/service/grc/grc.cpp
|
||||
hle/service/grc/grc.h
|
||||
hle/service/hid/hid.cpp
|
||||
@@ -435,10 +435,10 @@ add_library(core STATIC
|
||||
hle/service/lm/lm.h
|
||||
hle/service/mig/mig.cpp
|
||||
hle/service/mig/mig.h
|
||||
hle/service/mii/manager.cpp
|
||||
hle/service/mii/manager.h
|
||||
hle/service/mii/mii.cpp
|
||||
hle/service/mii/mii.h
|
||||
hle/service/mii/mii_manager.cpp
|
||||
hle/service/mii/mii_manager.h
|
||||
hle/service/mii/raw_data.cpp
|
||||
hle/service/mii/raw_data.h
|
||||
hle/service/mii/types.h
|
||||
@@ -486,11 +486,11 @@ add_library(core STATIC
|
||||
hle/service/nvdrv/devices/nvhost_vic.h
|
||||
hle/service/nvdrv/devices/nvmap.cpp
|
||||
hle/service/nvdrv/devices/nvmap.h
|
||||
hle/service/nvdrv/interface.cpp
|
||||
hle/service/nvdrv/interface.h
|
||||
hle/service/nvdrv/nvdata.h
|
||||
hle/service/nvdrv/nvdrv.cpp
|
||||
hle/service/nvdrv/nvdrv.h
|
||||
hle/service/nvdrv/nvdrv_interface.cpp
|
||||
hle/service/nvdrv/nvdrv_interface.h
|
||||
hle/service/nvdrv/nvmemp.cpp
|
||||
hle/service/nvdrv/nvmemp.h
|
||||
hle/service/nvdrv/syncpoint_manager.cpp
|
||||
@@ -503,10 +503,10 @@ add_library(core STATIC
|
||||
hle/service/olsc/olsc.h
|
||||
hle/service/pcie/pcie.cpp
|
||||
hle/service/pcie/pcie.h
|
||||
hle/service/pctl/module.cpp
|
||||
hle/service/pctl/module.h
|
||||
hle/service/pctl/pctl.cpp
|
||||
hle/service/pctl/pctl.h
|
||||
hle/service/pctl/pctl_module.cpp
|
||||
hle/service/pctl/pctl_module.h
|
||||
hle/service/pcv/pcv.cpp
|
||||
hle/service/pcv/pcv.h
|
||||
hle/service/pm/pm.cpp
|
||||
@@ -529,10 +529,10 @@ add_library(core STATIC
|
||||
hle/service/set/set_sys.h
|
||||
hle/service/set/settings.cpp
|
||||
hle/service/set/settings.h
|
||||
hle/service/sm/controller.cpp
|
||||
hle/service/sm/controller.h
|
||||
hle/service/sm/sm.cpp
|
||||
hle/service/sm/sm.h
|
||||
hle/service/sm/sm_controller.cpp
|
||||
hle/service/sm/sm_controller.h
|
||||
hle/service/sockets/bsd.cpp
|
||||
hle/service/sockets/bsd.h
|
||||
hle/service/sockets/ethc.cpp
|
||||
@@ -547,10 +547,10 @@ add_library(core STATIC
|
||||
hle/service/sockets/sockets_translate.h
|
||||
hle/service/spl/csrng.cpp
|
||||
hle/service/spl/csrng.h
|
||||
hle/service/spl/module.cpp
|
||||
hle/service/spl/module.h
|
||||
hle/service/spl/spl.cpp
|
||||
hle/service/spl/spl.h
|
||||
hle/service/spl/spl_module.cpp
|
||||
hle/service/spl/spl_module.h
|
||||
hle/service/spl/spl_results.h
|
||||
hle/service/spl/spl_types.h
|
||||
hle/service/ssl/ssl.cpp
|
||||
@@ -559,8 +559,6 @@ add_library(core STATIC
|
||||
hle/service/time/ephemeral_network_system_clock_context_writer.h
|
||||
hle/service/time/ephemeral_network_system_clock_core.h
|
||||
hle/service/time/errors.h
|
||||
hle/service/time/interface.cpp
|
||||
hle/service/time/interface.h
|
||||
hle/service/time/local_system_clock_context_writer.h
|
||||
hle/service/time/network_system_clock_context_writer.h
|
||||
hle/service/time/standard_local_system_clock_core.h
|
||||
@@ -578,6 +576,8 @@ add_library(core STATIC
|
||||
hle/service/time/tick_based_steady_clock_core.h
|
||||
hle/service/time/time.cpp
|
||||
hle/service/time/time.h
|
||||
hle/service/time/time_interface.cpp
|
||||
hle/service/time/time_interface.h
|
||||
hle/service/time/time_manager.cpp
|
||||
hle/service/time/time_manager.h
|
||||
hle/service/time/time_sharedmemory.cpp
|
||||
|
||||
@@ -150,7 +150,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||
config.far_code_offset = 400_MiB;
|
||||
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
|
||||
if (Settings::values.cpu_debug_mode) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
@@ -183,20 +183,28 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
|
||||
}
|
||||
}
|
||||
|
||||
// Curated optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
|
||||
config.unsafe_optimizations = true;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
|
||||
}
|
||||
|
||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||
config.far_code_offset = 400_MiB;
|
||||
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
|
||||
if (Settings::values.cpu_debug_mode) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
@@ -223,20 +223,28 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_fastmem_check.GetValue()) {
|
||||
if (Settings::values.cpuopt_unsafe_fastmem_check) {
|
||||
config.fastmem_address_space_bits = 64;
|
||||
}
|
||||
}
|
||||
|
||||
// Curated optimizations
|
||||
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
|
||||
config.unsafe_optimizations = true;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
|
||||
config.fastmem_address_space_bits = 64;
|
||||
}
|
||||
|
||||
return std::make_shared<Dynarmic::A64::Jit>(config);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -35,9 +35,9 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/apm/controller.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/glue/manager.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
@@ -263,9 +263,9 @@ struct System::Impl {
|
||||
if (Settings::values.gamecard_inserted) {
|
||||
if (Settings::values.gamecard_current_game) {
|
||||
fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
|
||||
} else if (!Settings::values.gamecard_path.empty()) {
|
||||
fs_controller.SetGameCard(
|
||||
GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
|
||||
} else if (!Settings::values.gamecard_path.GetValue().empty()) {
|
||||
const auto gamecard_path = Settings::values.gamecard_path.GetValue();
|
||||
fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, gamecard_path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
|
||||
@@ -13,7 +13,7 @@ ProfileSelectApplet::~ProfileSelectApplet() = default;
|
||||
void DefaultProfileSelectApplet::SelectProfile(
|
||||
std::function<void(std::optional<Common::UUID>)> callback) const {
|
||||
Service::Account::ProfileManager manager;
|
||||
callback(manager.GetUser(Settings::values.current_user).value_or(Common::UUID{}));
|
||||
callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
|
||||
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/service/am/applets/software_keyboard_types.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
#include "core/hle/service/am/applets/web_types.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hardware_interrupt_manager.h"
|
||||
#include "core/hle/service/nvdrv/interface.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv_interface.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Core::Hardware {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "core/hle/service/acc/errors.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/glue/arp.h"
|
||||
#include "core/hle/service/glue/manager.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/glue/manager.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::Account {
|
||||
|
||||
@@ -48,7 +48,8 @@ ProfileManager::ProfileManager() {
|
||||
CreateNewUser(UUID::Generate(), "yuzu");
|
||||
}
|
||||
|
||||
auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1);
|
||||
auto current =
|
||||
std::clamp<int>(static_cast<s32>(Settings::values.current_user), 0, MAX_USERS - 1);
|
||||
|
||||
// If user index don't exist. Load the first user and change the active user
|
||||
if (!UserExistsIndex(current)) {
|
||||
|
||||
@@ -24,16 +24,16 @@
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/web_browser.h"
|
||||
#include "core/hle/service/am/idle.h"
|
||||
#include "core/hle/service/am/omm.h"
|
||||
#include "core/hle/service/am/spsm.h"
|
||||
#include "core/hle/service/am/tcap.h"
|
||||
#include "core/hle/service/apm/controller.h"
|
||||
#include "core/hle/service/apm/interface.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
@@ -1443,7 +1443,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
|
||||
params.is_account_selected = 1;
|
||||
|
||||
Account::ProfileManager profile_manager{};
|
||||
const auto uuid = profile_manager.GetUser(Settings::values.current_user);
|
||||
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
|
||||
ASSERT(uuid);
|
||||
params.current_user = uuid->uuid;
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/controller.h"
|
||||
#include "core/hle/service/am/applets/applet_controller.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/error.h"
|
||||
#include "core/hle/service/am/applets/applet_error.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/general_backend.h"
|
||||
#include "core/hle/service/am/applets/applet_general_backend.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
+1
-1
@@ -7,8 +7,8 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/web_browser.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ns/pl_u.h"
|
||||
|
||||
+1
-1
@@ -11,8 +11,8 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser_types.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/web_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -17,13 +17,13 @@
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applet_controller.h"
|
||||
#include "core/hle/service/am/applets/applet_error.h"
|
||||
#include "core/hle/service/am/applets/applet_general_backend.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/controller.h"
|
||||
#include "core/hle/service/am/applets/error.h"
|
||||
#include "core/hle/service/am/applets/general_backend.h"
|
||||
#include "core/hle/service/am/applets/profile_select.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/web_browser.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/apm/apm.h"
|
||||
#include "core/hle/service/apm/interface.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
|
||||
namespace Service::APM {
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/apm/controller.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
|
||||
namespace Service::APM {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/apm/apm.h"
|
||||
#include "core/hle/service/apm/controller.h"
|
||||
#include "core/hle/service/apm/interface.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
|
||||
namespace Service::APM {
|
||||
|
||||
@@ -290,7 +290,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(1);
|
||||
rb.Push<u32>(2);
|
||||
}
|
||||
|
||||
// Should be similar to QueryAudioDeviceOutputEvent
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#ifndef __clang__
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
#endif
|
||||
#include <httplib.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/bcat/module.h"
|
||||
#include "core/hle/service/bcat/bcat_module.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
#include "core/hle/service/bcat/bcat.h"
|
||||
#include "core/hle/service/bcat/module.h"
|
||||
#include "core/hle/service/bcat/bcat_module.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
|
||||
namespace Service::BCAT {
|
||||
@@ -579,7 +579,7 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
|
||||
std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
|
||||
DirectoryGetter getter) {
|
||||
#ifdef YUZU_ENABLE_BOXCAT
|
||||
if (Settings::values.bcat_backend == "boxcat") {
|
||||
if (Settings::values.bcat_backend.GetValue() == "boxcat") {
|
||||
return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
|
||||
}
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/service/friend/errors.h"
|
||||
#include "core/hle/service/friend/friend.h"
|
||||
#include "core/hle/service/friend/interface.h"
|
||||
#include "core/hle/service/friend/friend_interface.h"
|
||||
|
||||
namespace Service::Friend {
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/friend/interface.h"
|
||||
#include "core/hle/service/friend/friend_interface.h"
|
||||
|
||||
namespace Service::Friend {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/glue/arp.h"
|
||||
#include "core/hle/service/glue/errors.h"
|
||||
#include "core/hle/service/glue/manager.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::Glue {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/glue/errors.h"
|
||||
#include "core/hle/service/glue/manager.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
|
||||
namespace Service::Glue {
|
||||
|
||||
@@ -941,6 +941,11 @@ void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_de
|
||||
|
||||
void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
|
||||
std::size_t device_index) {
|
||||
if (!Settings::values.vibration_enabled.GetValue()) {
|
||||
vibration_devices_mounted[npad_index][device_index] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (vibrations[npad_index][device_index]) {
|
||||
vibration_devices_mounted[npad_index][device_index] =
|
||||
vibrations[npad_index][device_index]->GetStatus() == 1;
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/mii/manager.h"
|
||||
#include "core/hle/service/mii/mii.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "common/string_util.h"
|
||||
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/mii/manager.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
#include "core/hle/service/mii/raw_data.h"
|
||||
#include "core/hle/service/mii/types.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/mii/manager.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
|
||||
namespace Service::Mii::RawData {
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
if (Settings::values.bcat_backend == "none") {
|
||||
if (Settings::values.bcat_backend.GetValue() == "none") {
|
||||
rb.PushEnum(RequestState::NotSubmitted);
|
||||
} else {
|
||||
rb.PushEnum(RequestState::Connected);
|
||||
@@ -384,7 +384,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
if (Settings::values.bcat_backend == "none") {
|
||||
if (Settings::values.bcat_backend.GetValue() == "none") {
|
||||
rb.Push<u8>(0);
|
||||
} else {
|
||||
rb.Push<u8>(1);
|
||||
@@ -395,7 +395,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
if (Settings::values.bcat_backend == "none") {
|
||||
if (Settings::values.bcat_backend.GetValue() == "none") {
|
||||
rb.Push<u8>(0);
|
||||
} else {
|
||||
rb.Push<u8>(1);
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/interface.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv_interface.h"
|
||||
#include "core/hle/service/nvdrv/nvmemp.h"
|
||||
#include "core/hle/service/nvdrv/syncpoint_manager.h"
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
|
||||
+1
-1
@@ -10,9 +10,9 @@
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/nvdrv/interface.h"
|
||||
#include "core/hle/service/nvdrv/nvdata.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv_interface.h"
|
||||
|
||||
namespace Service::Nvidia {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/pctl/module.h"
|
||||
#include "core/hle/service/pctl/pctl_module.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/pctl/module.h"
|
||||
#include "core/hle/service/pctl/pctl.h"
|
||||
#include "core/hle/service/pctl/pctl_module.h"
|
||||
|
||||
namespace Service::PCTL {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "core/hle/service/aoc/aoc_u.h"
|
||||
#include "core/hle/service/apm/apm.h"
|
||||
#include "core/hle/service/audio/audio.h"
|
||||
#include "core/hle/service/bcat/module.h"
|
||||
#include "core/hle/service/bcat/bcat_module.h"
|
||||
#include "core/hle/service/bpc/bpc.h"
|
||||
#include "core/hle/service/btdrv/btdrv.h"
|
||||
#include "core/hle/service/btm/btm.h"
|
||||
@@ -54,7 +54,7 @@
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
#include "core/hle/service/olsc/olsc.h"
|
||||
#include "core/hle/service/pcie/pcie.h"
|
||||
#include "core/hle/service/pctl/module.h"
|
||||
#include "core/hle/service/pctl/pctl_module.h"
|
||||
#include "core/hle/service/pcv/pcv.h"
|
||||
#include "core/hle/service/pm/pm.h"
|
||||
#include "core/hle/service/prepo/prepo.h"
|
||||
@@ -64,7 +64,7 @@
|
||||
#include "core/hle/service/set/settings.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/sockets/sockets.h"
|
||||
#include "core/hle/service/spl/module.h"
|
||||
#include "core/hle/service/spl/spl_module.h"
|
||||
#include "core/hle/service/ssl/ssl.h"
|
||||
#include "core/hle/service/time/time.h"
|
||||
#include "core/hle/service/usb/usb.h"
|
||||
|
||||
@@ -160,7 +160,7 @@ void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(Settings::values.quest_flag));
|
||||
rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
|
||||
}
|
||||
|
||||
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include "core/hle/kernel/k_server_session.h"
|
||||
#include "core/hle/kernel/k_session.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/sm/controller.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/sm/sm_controller.h"
|
||||
|
||||
namespace Service::SM {
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "core/hle/kernel/k_server_port.h"
|
||||
#include "core/hle/kernel/k_server_session.h"
|
||||
#include "core/hle/kernel/k_session.h"
|
||||
#include "core/hle/service/sm/controller.h"
|
||||
#include "core/hle/service/sm/sm_controller.h"
|
||||
|
||||
namespace Service::SM {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/spl/module.h"
|
||||
#include "core/hle/service/spl/spl_module.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/spl/module.h"
|
||||
#include "core/hle/service/spl/spl_module.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include "core/hle/api_version.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/spl/csrng.h"
|
||||
#include "core/hle/service/spl/module.h"
|
||||
#include "core/hle/service/spl/spl.h"
|
||||
#include "core/hle/service/spl/spl_module.h"
|
||||
|
||||
namespace Service::SPL {
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/time/interface.h"
|
||||
#include "core/hle/service/time/time.h"
|
||||
#include "core/hle/service/time/time_interface.h"
|
||||
#include "core/hle/service/time/time_sharedmemory.h"
|
||||
#include "core/hle/service/time/time_zone_service.h"
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/time/interface.h"
|
||||
#include "core/hle/service/time/time_interface.h"
|
||||
|
||||
namespace Service::Time {
|
||||
|
||||
@@ -155,8 +155,8 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
|
||||
codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
|
||||
}
|
||||
|
||||
if (!Settings::values.program_args.empty()) {
|
||||
const auto arg_data = Settings::values.program_args;
|
||||
if (!Settings::values.program_args.GetValue().empty()) {
|
||||
const auto arg_data = Settings::values.program_args.GetValue();
|
||||
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
|
||||
NSOArgumentHeader args_header{
|
||||
NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
|
||||
|
||||
@@ -104,8 +104,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
||||
codeset.segments[i].size = nso_header.segments[i].size;
|
||||
}
|
||||
|
||||
if (should_pass_arguments && !Settings::values.program_args.empty()) {
|
||||
const auto arg_data{Settings::values.program_args};
|
||||
if (should_pass_arguments && !Settings::values.program_args.GetValue().empty()) {
|
||||
const auto arg_data{Settings::values.program_args.GetValue()};
|
||||
|
||||
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
|
||||
NSOArgumentHeader args_header{
|
||||
|
||||
@@ -397,7 +397,7 @@ void Reporter::ClearFSAccessLog() const {
|
||||
}
|
||||
|
||||
bool Reporter::IsReportingEnabled() const {
|
||||
return Settings::values.reporting_services;
|
||||
return Settings::values.reporting_services.GetValue();
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -135,7 +135,7 @@ u64 RegenerateTelemetryId() {
|
||||
|
||||
bool VerifyLogin(const std::string& username, const std::string& token) {
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
return WebService::VerifyLogin(Settings::values.web_api_url, username, token);
|
||||
return WebService::VerifyLogin(Settings::values.web_api_url.GetValue(), username, token);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -152,7 +152,8 @@ TelemetrySession::~TelemetrySession() {
|
||||
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
auto backend = std::make_unique<WebService::TelemetryJson>(
|
||||
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
|
||||
Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
|
||||
Settings::values.yuzu_token.GetValue());
|
||||
#else
|
||||
auto backend = std::make_unique<Telemetry::NullVisitor>();
|
||||
#endif
|
||||
@@ -212,7 +213,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
|
||||
// Log user configuration information
|
||||
constexpr auto field_type = Telemetry::FieldType::UserConfig;
|
||||
AddField(field_type, "Audio_SinkId", Settings::values.sink_id);
|
||||
AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
|
||||
AddField(field_type, "Audio_EnableAudioStretching",
|
||||
Settings::values.enable_audio_stretching.GetValue());
|
||||
AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
|
||||
@@ -242,7 +243,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
bool TelemetrySession::SubmitTestcase() {
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
auto backend = std::make_unique<WebService::TelemetryJson>(
|
||||
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
|
||||
Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
|
||||
Settings::values.yuzu_token.GetValue());
|
||||
field_collection.Accept(*backend);
|
||||
return backend->SubmitTestcase();
|
||||
#else
|
||||
|
||||
@@ -294,8 +294,8 @@ void InputSubsystem::ReloadInputDevices() {
|
||||
impl->udp->ReloadSockets();
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
|
||||
Polling::DeviceType type) const {
|
||||
std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers([
|
||||
[maybe_unused]] Polling::DeviceType type) const {
|
||||
#ifdef HAVE_SDL2
|
||||
return impl->sdl->GetPollers(type);
|
||||
#else
|
||||
|
||||
@@ -84,7 +84,8 @@ public:
|
||||
std::lock_guard lock{mutex};
|
||||
const auto axis_value =
|
||||
static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
|
||||
return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range);
|
||||
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue();
|
||||
return axis_value * sensitivity / (100.0f * range);
|
||||
}
|
||||
|
||||
std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
|
||||
|
||||
@@ -13,7 +13,7 @@ class TouchFromButtonDevice final : public Input::TouchDevice {
|
||||
public:
|
||||
TouchFromButtonDevice() {
|
||||
const auto button_index =
|
||||
static_cast<std::size_t>(Settings::values.touch_from_button_map_index);
|
||||
static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
|
||||
const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
|
||||
|
||||
for (const auto& config_entry : buttons) {
|
||||
|
||||
@@ -201,7 +201,7 @@ bool Client::DeviceConnected(std::size_t pad) const {
|
||||
void Client::ReloadSockets() {
|
||||
Reset();
|
||||
|
||||
std::stringstream servers_ss(Settings::values.udp_input_servers);
|
||||
std::stringstream servers_ss(static_cast<std::string>(Settings::values.udp_input_servers));
|
||||
std::string server_token;
|
||||
std::size_t client = 0;
|
||||
while (std::getline(servers_ss, server_token, ',')) {
|
||||
@@ -370,7 +370,7 @@ std::optional<std::size_t> Client::GetUnusedFingerID() const {
|
||||
|
||||
void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) {
|
||||
// TODO: Use custom calibration per device
|
||||
const Common::ParamPackage touch_param(Settings::values.touch_device);
|
||||
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
|
||||
const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100));
|
||||
const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50));
|
||||
const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800));
|
||||
|
||||
@@ -5,6 +5,7 @@ add_executable(tests
|
||||
common/host_memory.cpp
|
||||
common/param_package.cpp
|
||||
common/ring_buffer.cpp
|
||||
common/unique_function.cpp
|
||||
core/core_timing.cpp
|
||||
core/network/network.cpp
|
||||
tests.cpp
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include "common/unique_function.h"
|
||||
|
||||
namespace {
|
||||
struct Noisy {
|
||||
Noisy() : state{"Default constructed"} {}
|
||||
Noisy(Noisy&& rhs) noexcept : state{"Move constructed"} {
|
||||
rhs.state = "Moved away";
|
||||
}
|
||||
Noisy& operator=(Noisy&& rhs) noexcept {
|
||||
state = "Move assigned";
|
||||
rhs.state = "Moved away";
|
||||
}
|
||||
Noisy(const Noisy&) : state{"Copied constructed"} {}
|
||||
Noisy& operator=(const Noisy&) {
|
||||
state = "Copied assigned";
|
||||
}
|
||||
|
||||
std::string state;
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
TEST_CASE("UniqueFunction", "[common]") {
|
||||
SECTION("Capture reference") {
|
||||
int value = 0;
|
||||
Common::UniqueFunction<void> func = [&value] { value = 5; };
|
||||
func();
|
||||
REQUIRE(value == 5);
|
||||
}
|
||||
SECTION("Capture pointer") {
|
||||
int value = 0;
|
||||
int* pointer = &value;
|
||||
Common::UniqueFunction<void> func = [pointer] { *pointer = 5; };
|
||||
func();
|
||||
REQUIRE(value == 5);
|
||||
}
|
||||
SECTION("Move object") {
|
||||
Noisy noisy;
|
||||
REQUIRE(noisy.state == "Default constructed");
|
||||
|
||||
Common::UniqueFunction<void> func = [noisy = std::move(noisy)] {
|
||||
REQUIRE(noisy.state == "Move constructed");
|
||||
};
|
||||
REQUIRE(noisy.state == "Moved away");
|
||||
func();
|
||||
}
|
||||
SECTION("Move construct function") {
|
||||
int value = 0;
|
||||
Common::UniqueFunction<void> func = [&value] { value = 5; };
|
||||
Common::UniqueFunction<void> new_func = std::move(func);
|
||||
new_func();
|
||||
REQUIRE(value == 5);
|
||||
}
|
||||
SECTION("Move assign function") {
|
||||
int value = 0;
|
||||
Common::UniqueFunction<void> func = [&value] { value = 5; };
|
||||
Common::UniqueFunction<void> new_func;
|
||||
new_func = std::move(func);
|
||||
new_func();
|
||||
REQUIRE(value == 5);
|
||||
}
|
||||
SECTION("Default construct then assign function") {
|
||||
int value = 0;
|
||||
Common::UniqueFunction<void> func;
|
||||
func = [&value] { value = 5; };
|
||||
func();
|
||||
REQUIRE(value == 5);
|
||||
}
|
||||
SECTION("Pass arguments") {
|
||||
int result = 0;
|
||||
Common::UniqueFunction<void, int, int> func = [&result](int a, int b) { result = a + b; };
|
||||
func(5, 4);
|
||||
REQUIRE(result == 9);
|
||||
}
|
||||
SECTION("Pass arguments and return value") {
|
||||
Common::UniqueFunction<int, int, int> func = [](int a, int b) { return a + b; };
|
||||
REQUIRE(func(5, 4) == 9);
|
||||
}
|
||||
SECTION("Destructor") {
|
||||
int num_destroyed = 0;
|
||||
struct Foo {
|
||||
Foo(int* num_) : num{num_} {}
|
||||
Foo(Foo&& rhs) : num{std::exchange(rhs.num, nullptr)} {}
|
||||
Foo(const Foo&) = delete;
|
||||
|
||||
~Foo() {
|
||||
if (num) {
|
||||
++*num;
|
||||
}
|
||||
}
|
||||
|
||||
int* num = nullptr;
|
||||
};
|
||||
Foo object{&num_destroyed};
|
||||
{
|
||||
Common::UniqueFunction<void> func = [object = std::move(object)] {};
|
||||
REQUIRE(num_destroyed == 0);
|
||||
}
|
||||
REQUIRE(num_destroyed == 1);
|
||||
}
|
||||
}
|
||||
@@ -536,7 +536,7 @@ TEST_CASE("BufferBase: Cached write downloads") {
|
||||
REQUIRE(rasterizer.Count() == 63);
|
||||
buffer.MarkRegionAsGpuModified(c + PAGE, PAGE);
|
||||
int num = 0;
|
||||
buffer.ForEachDownloadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
|
||||
buffer.ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; });
|
||||
buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
|
||||
REQUIRE(num == 0);
|
||||
REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE));
|
||||
|
||||
@@ -226,19 +226,24 @@ public:
|
||||
/// Call 'func' for each CPU modified range and unmark those pages as CPU modified
|
||||
template <typename Func>
|
||||
void ForEachUploadRange(VAddr query_cpu_range, u64 size, Func&& func) {
|
||||
ForEachModifiedRange<Type::CPU>(query_cpu_range, size, func);
|
||||
ForEachModifiedRange<Type::CPU>(query_cpu_range, size, true, func);
|
||||
}
|
||||
|
||||
/// Call 'func' for each GPU modified range and unmark those pages as GPU modified
|
||||
template <typename Func>
|
||||
void ForEachDownloadRange(VAddr query_cpu_range, u64 size, Func&& func) {
|
||||
ForEachModifiedRange<Type::GPU>(query_cpu_range, size, func);
|
||||
void ForEachDownloadRange(VAddr query_cpu_range, u64 size, bool clear, Func&& func) {
|
||||
ForEachModifiedRange<Type::GPU>(query_cpu_range, size, clear, func);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void ForEachDownloadRangeAndClear(VAddr query_cpu_range, u64 size, Func&& func) {
|
||||
ForEachModifiedRange<Type::GPU>(query_cpu_range, size, true, func);
|
||||
}
|
||||
|
||||
/// Call 'func' for each GPU modified range and unmark those pages as GPU modified
|
||||
template <typename Func>
|
||||
void ForEachDownloadRange(Func&& func) {
|
||||
ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), func);
|
||||
ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), true, func);
|
||||
}
|
||||
|
||||
/// Mark buffer as picked
|
||||
@@ -415,7 +420,7 @@ private:
|
||||
* @param func Function to call for each turned off region
|
||||
*/
|
||||
template <Type type, typename Func>
|
||||
void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) {
|
||||
void ForEachModifiedRange(VAddr query_cpu_range, s64 size, bool clear, Func&& func) {
|
||||
static_assert(type != Type::Untracked);
|
||||
|
||||
const s64 difference = query_cpu_range - cpu_addr;
|
||||
@@ -467,7 +472,9 @@ private:
|
||||
bits = (bits << left_offset) >> left_offset;
|
||||
|
||||
const u64 current_word = state_words[word_index] & bits;
|
||||
state_words[word_index] &= ~bits;
|
||||
if (clear) {
|
||||
state_words[word_index] &= ~bits;
|
||||
}
|
||||
|
||||
if constexpr (type == Type::CPU) {
|
||||
const u64 current_bits = untracked_words[word_index] & bits;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/div_ceil.h"
|
||||
@@ -77,6 +78,9 @@ class BufferCache {
|
||||
using Runtime = typename P::Runtime;
|
||||
using Buffer = typename P::Buffer;
|
||||
|
||||
using IntervalSet = boost::icl::interval_set<VAddr>;
|
||||
using IntervalType = typename IntervalSet::interval_type;
|
||||
|
||||
struct Empty {};
|
||||
|
||||
struct OverlapResult {
|
||||
@@ -148,18 +152,26 @@ public:
|
||||
/// Return true when there are uncommitted buffers to be downloaded
|
||||
[[nodiscard]] bool HasUncommittedFlushes() const noexcept;
|
||||
|
||||
void AccumulateFlushes();
|
||||
|
||||
/// Return true when the caller should wait for async downloads
|
||||
[[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
|
||||
|
||||
/// Commit asynchronous downloads
|
||||
void CommitAsyncFlushes();
|
||||
void CommitAsyncFlushesHigh();
|
||||
|
||||
/// Pop asynchronous downloads
|
||||
void PopAsyncFlushes();
|
||||
|
||||
[[nodiscard]] bool DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount);
|
||||
|
||||
/// Return true when a CPU region is modified from the GPU
|
||||
[[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
|
||||
|
||||
/// Return true when a CPU region is modified from the CPU
|
||||
[[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size);
|
||||
|
||||
std::mutex mutex;
|
||||
|
||||
private:
|
||||
@@ -190,6 +202,36 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void ForEachWrittenRange(VAddr cpu_addr, u64 size, Func&& func) {
|
||||
const VAddr start_address = cpu_addr;
|
||||
const VAddr end_address = start_address + size;
|
||||
const VAddr search_base =
|
||||
static_cast<VAddr>(std::min<s64>(0LL, static_cast<s64>(start_address - size)));
|
||||
const IntervalType search_interval{search_base, search_base + 1};
|
||||
auto it = common_ranges.lower_bound(search_interval);
|
||||
if (it == common_ranges.end()) {
|
||||
it = common_ranges.begin();
|
||||
}
|
||||
for (; it != common_ranges.end(); it++) {
|
||||
VAddr inter_addr_end = it->upper();
|
||||
VAddr inter_addr = it->lower();
|
||||
if (inter_addr >= end_address) {
|
||||
break;
|
||||
}
|
||||
if (inter_addr_end <= start_address) {
|
||||
continue;
|
||||
}
|
||||
if (inter_addr_end > end_address) {
|
||||
inter_addr_end = end_address;
|
||||
}
|
||||
if (inter_addr < start_address) {
|
||||
inter_addr = start_address;
|
||||
}
|
||||
func(inter_addr, inter_addr_end);
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsRangeGranular(VAddr cpu_addr, size_t size) {
|
||||
return (cpu_addr & ~Core::Memory::PAGE_MASK) ==
|
||||
((cpu_addr + size) & ~Core::Memory::PAGE_MASK);
|
||||
@@ -272,8 +314,6 @@ private:
|
||||
|
||||
void DeleteBuffer(BufferId buffer_id);
|
||||
|
||||
void ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id);
|
||||
|
||||
void NotifyBufferDeletion();
|
||||
|
||||
[[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr) const;
|
||||
@@ -327,9 +367,9 @@ private:
|
||||
|
||||
std::vector<BufferId> cached_write_buffer_ids;
|
||||
|
||||
// TODO: This data structure is not optimal and it should be reworked
|
||||
std::vector<BufferId> uncommitted_downloads;
|
||||
std::deque<std::vector<BufferId>> committed_downloads;
|
||||
IntervalSet uncommitted_ranges;
|
||||
IntervalSet common_ranges;
|
||||
std::deque<IntervalSet> committed_ranges;
|
||||
|
||||
size_t immediate_buffer_capacity = 0;
|
||||
std::unique_ptr<u8[]> immediate_buffer_alloc;
|
||||
@@ -352,6 +392,7 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
|
||||
// Ensure the first slot is used for the null buffer
|
||||
void(slot_buffers.insert(runtime, NullBufferParams{}));
|
||||
deletion_iterator = slot_buffers.end();
|
||||
common_ranges.clear();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -421,6 +462,68 @@ void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
|
||||
});
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
|
||||
const std::optional<VAddr> cpu_src_address = gpu_memory.GpuToCpuAddress(src_address);
|
||||
const std::optional<VAddr> cpu_dest_address = gpu_memory.GpuToCpuAddress(dest_address);
|
||||
if (!cpu_src_address || !cpu_dest_address) {
|
||||
return false;
|
||||
}
|
||||
const bool source_dirty = IsRegionGpuModified(*cpu_src_address, amount);
|
||||
const bool dest_dirty = IsRegionGpuModified(*cpu_dest_address, amount);
|
||||
if (!source_dirty && !dest_dirty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount};
|
||||
uncommitted_ranges.subtract(subtract_interval);
|
||||
for (auto& interval_set : committed_ranges) {
|
||||
interval_set.subtract(subtract_interval);
|
||||
}
|
||||
|
||||
BufferId buffer_a;
|
||||
BufferId buffer_b;
|
||||
do {
|
||||
has_deleted_buffers = false;
|
||||
buffer_a = FindBuffer(*cpu_src_address, static_cast<u32>(amount));
|
||||
buffer_b = FindBuffer(*cpu_dest_address, static_cast<u32>(amount));
|
||||
} while (has_deleted_buffers);
|
||||
auto& src_buffer = slot_buffers[buffer_a];
|
||||
auto& dest_buffer = slot_buffers[buffer_b];
|
||||
SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount));
|
||||
SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount));
|
||||
std::array copies{BufferCopy{
|
||||
.src_offset = src_buffer.Offset(*cpu_src_address),
|
||||
.dst_offset = dest_buffer.Offset(*cpu_dest_address),
|
||||
.size = amount,
|
||||
}};
|
||||
|
||||
boost::container::small_vector<IntervalType, 4> tmp_intervals;
|
||||
auto mirror = [&](VAddr base_address, VAddr base_address_end) {
|
||||
const u64 size = base_address_end - base_address;
|
||||
const VAddr diff = base_address - *cpu_src_address;
|
||||
const VAddr new_base_address = *cpu_dest_address + diff;
|
||||
const IntervalType add_interval{new_base_address, new_base_address + size};
|
||||
uncommitted_ranges.add(add_interval);
|
||||
tmp_intervals.push_back(add_interval);
|
||||
};
|
||||
ForEachWrittenRange(*cpu_src_address, amount, mirror);
|
||||
// This subtraction in this order is important for overlapping copies.
|
||||
common_ranges.subtract(subtract_interval);
|
||||
for (const IntervalType add_interval : tmp_intervals) {
|
||||
common_ranges.add(add_interval);
|
||||
}
|
||||
|
||||
runtime.CopyBuffer(dest_buffer, src_buffer, copies);
|
||||
if (source_dirty) {
|
||||
dest_buffer.MarkRegionAsGpuModified(*cpu_dest_address, amount);
|
||||
}
|
||||
std::vector<u8> tmp_buffer(amount);
|
||||
cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount);
|
||||
cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
|
||||
u32 size) {
|
||||
@@ -547,29 +650,30 @@ void BufferCache<P>::FlushCachedWrites() {
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::HasUncommittedFlushes() const noexcept {
|
||||
return !uncommitted_downloads.empty();
|
||||
return !uncommitted_ranges.empty() || !committed_ranges.empty();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::AccumulateFlushes() {
|
||||
if (Settings::values.gpu_accuracy.GetValue() != Settings::GPUAccuracy::High) {
|
||||
uncommitted_ranges.clear();
|
||||
return;
|
||||
}
|
||||
if (uncommitted_ranges.empty()) {
|
||||
return;
|
||||
}
|
||||
committed_ranges.emplace_back(std::move(uncommitted_ranges));
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
|
||||
return !committed_downloads.empty() && !committed_downloads.front().empty();
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::CommitAsyncFlushes() {
|
||||
// This is intentionally passing the value by copy
|
||||
committed_downloads.push_front(uncommitted_downloads);
|
||||
uncommitted_downloads.clear();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::PopAsyncFlushes() {
|
||||
if (committed_downloads.empty()) {
|
||||
return;
|
||||
}
|
||||
auto scope_exit_pop_download = detail::ScopeExit([this] { committed_downloads.pop_back(); });
|
||||
const std::span<const BufferId> download_ids = committed_downloads.back();
|
||||
if (download_ids.empty()) {
|
||||
void BufferCache<P>::CommitAsyncFlushesHigh() {
|
||||
AccumulateFlushes();
|
||||
if (committed_ranges.empty()) {
|
||||
return;
|
||||
}
|
||||
MICROPROFILE_SCOPE(GPU_DownloadMemory);
|
||||
@@ -577,20 +681,43 @@ void BufferCache<P>::PopAsyncFlushes() {
|
||||
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads;
|
||||
u64 total_size_bytes = 0;
|
||||
u64 largest_copy = 0;
|
||||
for (const BufferId buffer_id : download_ids) {
|
||||
slot_buffers[buffer_id].ForEachDownloadRange([&](u64 range_offset, u64 range_size) {
|
||||
downloads.push_back({
|
||||
BufferCopy{
|
||||
.src_offset = range_offset,
|
||||
.dst_offset = total_size_bytes,
|
||||
.size = range_size,
|
||||
},
|
||||
buffer_id,
|
||||
for (const IntervalSet& intervals : committed_ranges) {
|
||||
for (auto& interval : intervals) {
|
||||
const std::size_t size = interval.upper() - interval.lower();
|
||||
const VAddr cpu_addr = interval.lower();
|
||||
ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
|
||||
boost::container::small_vector<BufferCopy, 1> copies;
|
||||
buffer.ForEachDownloadRangeAndClear(
|
||||
cpu_addr, size, [&](u64 range_offset, u64 range_size) {
|
||||
const VAddr buffer_addr = buffer.CpuAddr();
|
||||
const auto add_download = [&](VAddr start, VAddr end) {
|
||||
const u64 new_offset = start - buffer_addr;
|
||||
const u64 new_size = end - start;
|
||||
downloads.push_back({
|
||||
BufferCopy{
|
||||
.src_offset = new_offset,
|
||||
.dst_offset = total_size_bytes,
|
||||
.size = new_size,
|
||||
},
|
||||
buffer_id,
|
||||
});
|
||||
// Align up to avoid cache conflicts
|
||||
constexpr u64 align = 256ULL;
|
||||
constexpr u64 mask = ~(align - 1ULL);
|
||||
total_size_bytes += (new_size + align - 1) & mask;
|
||||
largest_copy = std::max(largest_copy, new_size);
|
||||
};
|
||||
|
||||
const VAddr start_address = buffer_addr + range_offset;
|
||||
const VAddr end_address = start_address + range_size;
|
||||
ForEachWrittenRange(start_address, range_size, add_download);
|
||||
const IntervalType subtract_interval{start_address, end_address};
|
||||
common_ranges.subtract(subtract_interval);
|
||||
});
|
||||
});
|
||||
total_size_bytes += range_size;
|
||||
largest_copy = std::max(largest_copy, range_size);
|
||||
});
|
||||
}
|
||||
}
|
||||
committed_ranges.clear();
|
||||
if (downloads.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -622,6 +749,19 @@ void BufferCache<P>::PopAsyncFlushes() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::CommitAsyncFlushes() {
|
||||
if (Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High) {
|
||||
CommitAsyncFlushesHigh();
|
||||
} else {
|
||||
uncommitted_ranges.clear();
|
||||
committed_ranges.clear();
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::PopAsyncFlushes() {}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
|
||||
const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
|
||||
@@ -641,6 +781,25 @@ bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) {
|
||||
const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
|
||||
for (u64 page = addr >> PAGE_BITS; page < page_end;) {
|
||||
const BufferId image_id = page_table[page];
|
||||
if (!image_id) {
|
||||
++page;
|
||||
continue;
|
||||
}
|
||||
Buffer& buffer = slot_buffers[image_id];
|
||||
if (buffer.IsRegionCpuModified(addr, size)) {
|
||||
return true;
|
||||
}
|
||||
const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes();
|
||||
page = Common::DivCeil(end_addr, PAGE_SIZE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindHostIndexBuffer() {
|
||||
Buffer& buffer = slot_buffers[index_buffer.buffer_id];
|
||||
@@ -649,7 +808,9 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
||||
const u32 size = index_buffer.size;
|
||||
SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
|
||||
if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||
runtime.BindIndexBuffer(buffer, offset, size);
|
||||
const u32 new_offset = offset + maxwell3d.regs.index_array.first *
|
||||
maxwell3d.regs.index_array.FormatSizeInBytes();
|
||||
runtime.BindIndexBuffer(buffer, new_offset, size);
|
||||
} else {
|
||||
runtime.BindIndexBuffer(maxwell3d.regs.draw.topology, maxwell3d.regs.index_array.format,
|
||||
maxwell3d.regs.index_array.first, maxwell3d.regs.index_array.count,
|
||||
@@ -863,7 +1024,7 @@ void BufferCache<P>::UpdateIndexBuffer() {
|
||||
const GPUVAddr gpu_addr_end = index_array.EndAddress();
|
||||
const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr_begin);
|
||||
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
|
||||
const u32 draw_size = index_array.count * index_array.FormatSizeInBytes();
|
||||
const u32 draw_size = (index_array.count + index_array.first) * index_array.FormatSizeInBytes();
|
||||
const u32 size = std::min(address_size, draw_size);
|
||||
if (size == 0 || !cpu_addr) {
|
||||
index_buffer = NULL_BINDING;
|
||||
@@ -1010,16 +1171,16 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 s
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
buffer.MarkRegionAsGpuModified(cpu_addr, size);
|
||||
|
||||
const bool is_accuracy_high = Settings::IsGPULevelHigh();
|
||||
const IntervalType base_interval{cpu_addr, cpu_addr + size};
|
||||
common_ranges.add(base_interval);
|
||||
|
||||
const bool is_accuracy_high =
|
||||
Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High;
|
||||
const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
|
||||
if (!is_accuracy_high || !is_async) {
|
||||
if (!is_async && !is_accuracy_high) {
|
||||
return;
|
||||
}
|
||||
if (std::ranges::find(uncommitted_downloads, buffer_id) != uncommitted_downloads.end()) {
|
||||
// Already inserted
|
||||
return;
|
||||
}
|
||||
uncommitted_downloads.push_back(buffer_id);
|
||||
uncommitted_ranges.add(base_interval);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -1103,7 +1264,6 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
|
||||
if (!copies.empty()) {
|
||||
runtime.CopyBuffer(slot_buffers[new_buffer_id], overlap, copies);
|
||||
}
|
||||
ReplaceBufferDownloads(overlap_id, new_buffer_id);
|
||||
DeleteBuffer(overlap_id);
|
||||
}
|
||||
|
||||
@@ -1244,14 +1404,28 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
|
||||
boost::container::small_vector<BufferCopy, 1> copies;
|
||||
u64 total_size_bytes = 0;
|
||||
u64 largest_copy = 0;
|
||||
buffer.ForEachDownloadRange(cpu_addr, size, [&](u64 range_offset, u64 range_size) {
|
||||
copies.push_back(BufferCopy{
|
||||
.src_offset = range_offset,
|
||||
.dst_offset = total_size_bytes,
|
||||
.size = range_size,
|
||||
});
|
||||
total_size_bytes += range_size;
|
||||
largest_copy = std::max(largest_copy, range_size);
|
||||
buffer.ForEachDownloadRangeAndClear(cpu_addr, size, [&](u64 range_offset, u64 range_size) {
|
||||
const VAddr buffer_addr = buffer.CpuAddr();
|
||||
const auto add_download = [&](VAddr start, VAddr end) {
|
||||
const u64 new_offset = start - buffer_addr;
|
||||
const u64 new_size = end - start;
|
||||
copies.push_back(BufferCopy{
|
||||
.src_offset = new_offset,
|
||||
.dst_offset = total_size_bytes,
|
||||
.size = new_size,
|
||||
});
|
||||
// Align up to avoid cache conflicts
|
||||
constexpr u64 align = 256ULL;
|
||||
constexpr u64 mask = ~(align - 1ULL);
|
||||
total_size_bytes += (new_size + align - 1) & mask;
|
||||
largest_copy = std::max(largest_copy, new_size);
|
||||
};
|
||||
|
||||
const VAddr start_address = buffer_addr + range_offset;
|
||||
const VAddr end_address = start_address + range_size;
|
||||
ForEachWrittenRange(start_address, range_size, add_download);
|
||||
const IntervalType subtract_interval{start_address, end_address};
|
||||
common_ranges.subtract(subtract_interval);
|
||||
});
|
||||
if (total_size_bytes == 0) {
|
||||
return;
|
||||
@@ -1315,18 +1489,6 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id) {
|
||||
NotifyBufferDeletion();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id) {
|
||||
const auto replace = [old_buffer_id, new_buffer_id](std::vector<BufferId>& buffers) {
|
||||
std::ranges::replace(buffers, old_buffer_id, new_buffer_id);
|
||||
if (auto it = std::ranges::find(buffers, new_buffer_id); it != buffers.end()) {
|
||||
buffers.erase(std::remove(it + 1, buffers.end(), new_buffer_id), buffers.end());
|
||||
}
|
||||
};
|
||||
replace(uncommitted_downloads);
|
||||
std::ranges::for_each(committed_downloads, replace);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::NotifyBufferDeletion() {
|
||||
if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
|
||||
@@ -1349,15 +1511,9 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
|
||||
if (!cpu_addr || size == 0) {
|
||||
return NULL_BINDING;
|
||||
}
|
||||
// HACK(Rodrigo): This is the number of bytes bound in host beyond the guest API's range.
|
||||
// It exists due to some games like Astral Chain operate out of bounds.
|
||||
// Binding the whole map range would be technically correct, but games have large maps that make
|
||||
// this approach unaffordable for now.
|
||||
static constexpr u32 arbitrary_extra_bytes = 0xc000;
|
||||
const u32 bytes_to_map_end = static_cast<u32>(gpu_memory.BytesToMapEnd(gpu_addr));
|
||||
const Binding binding{
|
||||
.cpu_addr = *cpu_addr,
|
||||
.size = std::min(size + arbitrary_extra_bytes, bytes_to_map_end),
|
||||
.size = size,
|
||||
.buffer_id = BufferId{},
|
||||
};
|
||||
return binding;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "common/cityhash.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/dma_pusher.h"
|
||||
@@ -76,8 +77,13 @@ bool DmaPusher::Step() {
|
||||
|
||||
// Push buffer non-empty, read a word
|
||||
command_headers.resize(command_list_header.size);
|
||||
gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(),
|
||||
command_list_header.size * sizeof(u32));
|
||||
if (Settings::IsGPULevelHigh()) {
|
||||
gpu.MemoryManager().ReadBlock(dma_get, command_headers.data(),
|
||||
command_list_header.size * sizeof(u32));
|
||||
} else {
|
||||
gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(),
|
||||
command_list_header.size * sizeof(u32));
|
||||
}
|
||||
}
|
||||
for (std::size_t index = 0; index < command_headers.size();) {
|
||||
const CommandHeader& command_header = command_headers[index];
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include "video_core/engines/fermi_2d.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/surface.h"
|
||||
|
||||
using VideoCore::Surface::BytesPerBlock;
|
||||
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||
|
||||
namespace Tegra::Engines {
|
||||
|
||||
@@ -49,7 +53,7 @@ void Fermi2D::Blit() {
|
||||
UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled");
|
||||
|
||||
const auto& args = regs.pixels_from_memory;
|
||||
const Config config{
|
||||
Config config{
|
||||
.operation = regs.operation,
|
||||
.filter = args.sample_mode.filter,
|
||||
.dst_x0 = args.dst_x0,
|
||||
@@ -61,7 +65,21 @@ void Fermi2D::Blit() {
|
||||
.src_x1 = static_cast<s32>((args.du_dx * args.dst_width + args.src_x0) >> 32),
|
||||
.src_y1 = static_cast<s32>((args.dv_dy * args.dst_height + args.src_y0) >> 32),
|
||||
};
|
||||
if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, config)) {
|
||||
Surface src = regs.src;
|
||||
const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
|
||||
const auto need_align_to_pitch =
|
||||
src.linear == Tegra::Engines::Fermi2D::MemoryLayout::Pitch &&
|
||||
static_cast<s32>(src.width) == config.src_x1 &&
|
||||
config.src_x1 > static_cast<s32>(src.pitch / bytes_per_pixel) && config.src_x0 > 0;
|
||||
if (need_align_to_pitch) {
|
||||
auto address = src.Address() + config.src_x0 * bytes_per_pixel;
|
||||
src.addr_upper = static_cast<u32>(address >> 32);
|
||||
src.addr_lower = static_cast<u32>(address);
|
||||
src.width -= config.src_x0;
|
||||
config.src_x1 -= config.src_x0;
|
||||
config.src_x0 = 0;
|
||||
}
|
||||
if (!rasterizer->AccelerateSurfaceCopy(src, regs.dst, config)) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_)
|
||||
|
||||
MaxwellDMA::~MaxwellDMA() = default;
|
||||
|
||||
void MaxwellDMA::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
|
||||
rasterizer = rasterizer_;
|
||||
}
|
||||
|
||||
void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
||||
ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register");
|
||||
|
||||
@@ -44,7 +48,6 @@ void MaxwellDMA::Launch() {
|
||||
|
||||
// TODO(Subv): Perform more research and implement all features of this engine.
|
||||
const LaunchDMA& launch = regs.launch_dma;
|
||||
ASSERT(launch.remap_enable == 0);
|
||||
ASSERT(launch.semaphore_type == LaunchDMA::SemaphoreType::NONE);
|
||||
ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE);
|
||||
ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED);
|
||||
@@ -77,11 +80,29 @@ void MaxwellDMA::CopyPitchToPitch() {
|
||||
// When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D
|
||||
// buffer of length `line_length_in`.
|
||||
// Otherwise we copy a 2D image of dimensions (line_length_in, line_count).
|
||||
auto& accelerate = rasterizer->AccessAccelerateDMA();
|
||||
if (!regs.launch_dma.multi_line_enable) {
|
||||
memory_manager.CopyBlock(regs.offset_out, regs.offset_in, regs.line_length_in);
|
||||
const bool is_buffer_clear = regs.launch_dma.remap_enable != 0 &&
|
||||
regs.remap_const.dst_x == RemapConst::Swizzle::CONST_A;
|
||||
// TODO: allow multisized components.
|
||||
if (is_buffer_clear) {
|
||||
ASSERT(regs.remap_const.component_size_minus_one == 3);
|
||||
std::vector<u32> tmp_buffer(regs.line_length_in, regs.remap_consta_value);
|
||||
memory_manager.WriteBlock(regs.offset_out, reinterpret_cast<u8*>(tmp_buffer.data()),
|
||||
regs.line_length_in * sizeof(u32));
|
||||
return;
|
||||
}
|
||||
UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
|
||||
if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
|
||||
std::vector<u8> tmp_buffer(regs.line_length_in);
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), regs.line_length_in);
|
||||
memory_manager.WriteBlock(regs.offset_out, tmp_buffer.data(), regs.line_length_in);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
|
||||
|
||||
// Perform a line-by-line copy.
|
||||
// We're going to take a subrect of size (line_length_in, line_count) from the source rectangle.
|
||||
// There is no need to manually flush/invalidate the regions because CopyBlock does that for us.
|
||||
@@ -105,6 +126,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
|
||||
}
|
||||
|
||||
// Deswizzle the input and copy it over.
|
||||
UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
|
||||
const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in;
|
||||
const Parameters& src_params = regs.src_params;
|
||||
const u32 width = src_params.width;
|
||||
@@ -134,6 +156,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
|
||||
|
||||
void MaxwellDMA::CopyPitchToBlockLinear() {
|
||||
UNIMPLEMENTED_IF_MSG(regs.dst_params.block_size.width != 0, "Block width is not one");
|
||||
UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
|
||||
|
||||
const auto& dst_params = regs.dst_params;
|
||||
const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in;
|
||||
@@ -156,13 +179,8 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
|
||||
write_buffer.resize(dst_size);
|
||||
}
|
||||
|
||||
if (Settings::IsGPULevelExtreme()) {
|
||||
memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
} else {
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
|
||||
}
|
||||
memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
|
||||
memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
|
||||
|
||||
// If the input is linear and the output is tiled, swizzle the input and copy it over.
|
||||
if (regs.dst_params.block_size.depth > 0) {
|
||||
|
||||
@@ -21,8 +21,18 @@ namespace Tegra {
|
||||
class MemoryManager;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
|
||||
namespace Tegra::Engines {
|
||||
|
||||
class AccelerateDMAInterface {
|
||||
public:
|
||||
/// Write the value to the register identified by method.
|
||||
virtual bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* This engine is known as gk104_copy. Documentation can be found in:
|
||||
* https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h
|
||||
@@ -187,6 +197,8 @@ public:
|
||||
};
|
||||
static_assert(sizeof(RemapConst) == 12);
|
||||
|
||||
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
|
||||
|
||||
explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_);
|
||||
~MaxwellDMA() override;
|
||||
|
||||
@@ -213,6 +225,7 @@ private:
|
||||
Core::System& system;
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
VideoCore::RasterizerInterface* rasterizer;
|
||||
|
||||
std::vector<u8> read_buffer;
|
||||
std::vector<u8> write_buffer;
|
||||
@@ -240,7 +253,9 @@ private:
|
||||
u32 pitch_out;
|
||||
u32 line_length_in;
|
||||
u32 line_count;
|
||||
u32 reserved06[0xb8];
|
||||
u32 reserved06[0xb6];
|
||||
u32 remap_consta_value;
|
||||
u32 remap_constb_value;
|
||||
RemapConst remap_const;
|
||||
Parameters dst_params;
|
||||
u32 reserved07[0x1];
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <queue>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "video_core/delayed_destruction_ring.h"
|
||||
#include "video_core/gpu.h"
|
||||
@@ -53,6 +54,12 @@ public:
|
||||
delayed_destruction_ring.Tick();
|
||||
}
|
||||
|
||||
// Unlike other fences, this one doesn't
|
||||
void SignalOrdering() {
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
buffer_cache.AccumulateFlushes();
|
||||
}
|
||||
|
||||
void SignalSemaphore(GPUVAddr addr, u32 value) {
|
||||
TryReleasePendingFences();
|
||||
const bool should_flush = ShouldFlush();
|
||||
|
||||
@@ -50,6 +50,7 @@ void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
|
||||
maxwell_3d->BindRasterizer(rasterizer);
|
||||
fermi_2d->BindRasterizer(rasterizer);
|
||||
kepler_compute->BindRasterizer(rasterizer);
|
||||
maxwell_dma->BindRasterizer(rasterizer);
|
||||
}
|
||||
|
||||
Engines::Maxwell3D& GPU::Maxwell3D() {
|
||||
@@ -268,11 +269,13 @@ void GPU::CallPullerMethod(const MethodCall& method_call) {
|
||||
case BufferMethods::SemaphoreAddressHigh:
|
||||
case BufferMethods::SemaphoreAddressLow:
|
||||
case BufferMethods::SemaphoreSequence:
|
||||
case BufferMethods::RefCnt:
|
||||
case BufferMethods::UnkCacheFlush:
|
||||
case BufferMethods::WrcacheFlush:
|
||||
case BufferMethods::FenceValue:
|
||||
break;
|
||||
case BufferMethods::RefCnt:
|
||||
rasterizer->SignalReference();
|
||||
break;
|
||||
case BufferMethods::FenceAction:
|
||||
ProcessFenceActionMethod();
|
||||
break;
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
|
||||
namespace Tegra {
|
||||
class MemoryManager;
|
||||
namespace Engines {
|
||||
class AccelerateDMAInterface;
|
||||
}
|
||||
} // namespace Tegra
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
@@ -63,6 +66,9 @@ public:
|
||||
/// Signal a GPU based syncpoint as a fence
|
||||
virtual void SignalSyncPoint(u32 value) = 0;
|
||||
|
||||
/// Signal a GPU based reference as point
|
||||
virtual void SignalReference() = 0;
|
||||
|
||||
/// Release all pending fences.
|
||||
virtual void ReleaseFences() = 0;
|
||||
|
||||
@@ -116,6 +122,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() = 0;
|
||||
|
||||
/// Attempt to use a faster method to display the framebuffer to screen
|
||||
[[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config,
|
||||
VAddr framebuffer_addr, u32 pixel_stride) {
|
||||
|
||||
@@ -171,7 +171,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
buffer_cache_runtime(device),
|
||||
buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
|
||||
shader_cache(*this, emu_window_, gpu, maxwell3d, kepler_compute, gpu_memory, device),
|
||||
query_cache(*this, maxwell3d, gpu_memory),
|
||||
query_cache(*this, maxwell3d, gpu_memory), accelerate_dma(buffer_cache),
|
||||
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
|
||||
async_shaders(emu_window_) {
|
||||
if (device.UseAsynchronousShaders()) {
|
||||
@@ -634,6 +634,13 @@ void RasterizerOpenGL::SignalSyncPoint(u32 value) {
|
||||
fence_manager.SignalSyncPoint(value);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SignalReference() {
|
||||
if (!gpu.IsAsync()) {
|
||||
return;
|
||||
}
|
||||
fence_manager.SignalOrdering();
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::ReleaseFences() {
|
||||
if (!gpu.IsAsync()) {
|
||||
return;
|
||||
@@ -650,6 +657,7 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
|
||||
|
||||
void RasterizerOpenGL::WaitForIdle() {
|
||||
glMemoryBarrier(GL_ALL_BARRIER_BITS);
|
||||
SignalReference();
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::FragmentBarrier() {
|
||||
@@ -693,6 +701,10 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surf
|
||||
return true;
|
||||
}
|
||||
|
||||
Tegra::Engines::AccelerateDMAInterface& RasterizerOpenGL::AccessAccelerateDMA() {
|
||||
return accelerate_dma;
|
||||
}
|
||||
|
||||
bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
|
||||
VAddr framebuffer_addr, u32 pixel_stride) {
|
||||
if (framebuffer_addr == 0) {
|
||||
@@ -1388,4 +1400,11 @@ void RasterizerOpenGL::EndTransformFeedback() {
|
||||
glEndTransformFeedback();
|
||||
}
|
||||
|
||||
AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
|
||||
|
||||
bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
return buffer_cache.DMACopy(src_address, dest_address, amount);
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/engines/const_buffer_info.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/engines/maxwell_dma.h"
|
||||
#include "video_core/rasterizer_accelerated.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
@@ -58,6 +59,16 @@ struct BindlessSSBO {
|
||||
};
|
||||
static_assert(sizeof(BindlessSSBO) * CHAR_BIT == 128);
|
||||
|
||||
class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface {
|
||||
public:
|
||||
explicit AccelerateDMA(BufferCache& buffer_cache);
|
||||
|
||||
bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) override;
|
||||
|
||||
private:
|
||||
BufferCache& buffer_cache;
|
||||
};
|
||||
|
||||
class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
|
||||
public:
|
||||
explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
|
||||
@@ -83,6 +94,7 @@ public:
|
||||
void ModifyGPUMemory(GPUVAddr addr, u64 size) override;
|
||||
void SignalSemaphore(GPUVAddr addr, u32 value) override;
|
||||
void SignalSyncPoint(u32 value) override;
|
||||
void SignalReference() override;
|
||||
void ReleaseFences() override;
|
||||
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
|
||||
void WaitForIdle() override;
|
||||
@@ -93,6 +105,7 @@ public:
|
||||
bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Config& copy_config) override;
|
||||
Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
|
||||
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
|
||||
u32 pixel_stride) override;
|
||||
void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
|
||||
@@ -233,6 +246,7 @@ private:
|
||||
BufferCache buffer_cache;
|
||||
ShaderCacheOpenGL shader_cache;
|
||||
QueryCache query_cache;
|
||||
AccelerateDMA accelerate_dma;
|
||||
FenceManagerOpenGL fence_manager;
|
||||
|
||||
VideoCommon::Shader::AsyncShaders async_shaders;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user