Compare commits
30 Commits
android-51
...
android-54
Author | SHA1 | Date | |
---|---|---|---|
6af28cc01b | |||
1615a86375 | |||
199de26995 | |||
954144e22b | |||
c2f827b85e | |||
ada4697300 | |||
acc99433c7 | |||
6c4abd23be | |||
84b384fbea | |||
3620533995 | |||
c5105b65d5 | |||
1ac2615adb | |||
d7a0b8c373 | |||
6bb02dcb8a | |||
32c453a5f1 | |||
91eb5afd0b | |||
2e55459e03 | |||
8677d98a10 | |||
1cdd11d9f5 | |||
39c8ddcda2 | |||
00af46c356 | |||
ce0f1baf51 | |||
75f5b3177d | |||
3c45452fae | |||
ab862207d7 | |||
7f8335f4ae | |||
6ed5b581f0 | |||
387ede76d2 | |||
8a4cb3f902 | |||
0e443dcb05 |
@ -1,3 +1,11 @@
|
||||
| Pull Request | Commit | Title | Author | Merged? |
|
||||
|----|----|----|----|----|
|
||||
|
||||
|
||||
End of merge log. You can find the original README.md below the break.
|
||||
|
||||
-----
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
5
dist/qt_themes/default/style.qss
vendored
5
dist/qt_themes/default/style.qss
vendored
@ -78,6 +78,11 @@ QPushButton#buttonRefreshDevices {
|
||||
max-height: 21px;
|
||||
}
|
||||
|
||||
QPushButton#button_reset_defaults {
|
||||
min-width: 57px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
QWidget#bottomPerGameInput,
|
||||
QWidget#topControllerApplet,
|
||||
QWidget#bottomControllerApplet,
|
||||
|
@ -2228,6 +2228,10 @@ QPushButton#buttonRefreshDevices {
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
QPushButton#button_reset_defaults {
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
QSpinBox#spinboxLStickRange,
|
||||
QSpinBox#spinboxRStickRange,
|
||||
QSpinBox#vibrationSpinPlayer1,
|
||||
|
14
externals/CMakeLists.txt
vendored
14
externals/CMakeLists.txt
vendored
@ -42,6 +42,11 @@ endif()
|
||||
# mbedtls
|
||||
add_subdirectory(mbedtls)
|
||||
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(mbedcrypto PRIVATE
|
||||
-Wno-unused-but-set-variable
|
||||
-Wno-string-concatenation)
|
||||
endif()
|
||||
|
||||
# MicroProfile
|
||||
add_library(microprofile INTERFACE)
|
||||
@ -94,6 +99,12 @@ if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
|
||||
set(BUILD_TOOLS OFF)
|
||||
add_subdirectory(cubeb)
|
||||
add_library(cubeb::cubeb ALIAS cubeb)
|
||||
if (NOT MSVC)
|
||||
if (TARGET speex)
|
||||
target_compile_options(speex PRIVATE -Wno-sign-compare)
|
||||
endif()
|
||||
target_compile_options(cubeb PRIVATE -Wno-implicit-const-int-float-conversion)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# DiscordRPC
|
||||
@ -151,6 +162,9 @@ endif()
|
||||
if (NOT TARGET LLVM::Demangle)
|
||||
add_library(demangle demangle/ItaniumDemangle.cpp)
|
||||
target_include_directories(demangle PUBLIC ./demangle)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(demangle PRIVATE -Wno-deprecated-declarations) # std::is_pod
|
||||
endif()
|
||||
add_library(LLVM::Demangle ALIAS demangle)
|
||||
endif()
|
||||
|
||||
|
@ -114,16 +114,19 @@ else()
|
||||
-Wno-attributes
|
||||
-Wno-invalid-offsetof
|
||||
-Wno-unused-parameter
|
||||
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=shadow-uncaptured-local>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=implicit-fallthrough>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=type-limits>
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
|
||||
)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
|
||||
add_compile_options(
|
||||
-Wno-braced-scalar-init
|
||||
-Wno-unused-private-field
|
||||
-Wno-nullability-completeness
|
||||
-Werror=shadow-uncaptured-local
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=type-limits
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options("-mcx16")
|
||||
add_compile_options("-fwrapv")
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "input_common/main.h"
|
||||
#include "jni/config.h"
|
||||
@ -144,7 +145,9 @@ void Config::ReadValues() {
|
||||
Service::Account::MAX_USERS - 1);
|
||||
|
||||
// Disable docked mode by default on Android
|
||||
Settings::values.use_docked_mode = config->GetBoolean("System", "use_docked_mode", false);
|
||||
Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false)
|
||||
? Settings::ConsoleMode::Docked
|
||||
: Settings::ConsoleMode::Handheld);
|
||||
|
||||
const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false);
|
||||
if (rng_seed_enabled) {
|
||||
|
@ -420,7 +420,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Settings::values.use_docked_mode.GetValue();
|
||||
return !Settings::IsDockedMode();
|
||||
}
|
||||
|
||||
void SetDeviceType([[maybe_unused]] int index, int type) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "audio_core/sink/cubeb_sink.h"
|
||||
#include "audio_core/sink/sink_stream.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -332,25 +333,38 @@ std::vector<std::string> ListCubebSinkDevices(bool capture) {
|
||||
return device_list;
|
||||
}
|
||||
|
||||
u32 GetCubebLatency() {
|
||||
cubeb* ctx;
|
||||
namespace {
|
||||
static long TmpDataCallback(cubeb_stream*, void*, const void*, void*, long) {
|
||||
return TargetSampleCount;
|
||||
}
|
||||
static void TmpStateCallback(cubeb_stream*, void*, cubeb_state) {}
|
||||
} // namespace
|
||||
|
||||
bool IsCubebSuitable() {
|
||||
#if !defined(HAVE_CUBEB)
|
||||
return false;
|
||||
#else
|
||||
cubeb* ctx{nullptr};
|
||||
|
||||
#ifdef _WIN32
|
||||
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
#endif
|
||||
|
||||
// Init cubeb
|
||||
if (cubeb_init(&ctx, "yuzu Latency Getter", nullptr) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||
// Return a large latency so we choose SDL instead.
|
||||
return 10000u;
|
||||
LOG_ERROR(Audio_Sink, "Cubeb failed to init, it is not suitable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SCOPE_EXIT({ cubeb_destroy(ctx); });
|
||||
|
||||
#ifdef _WIN32
|
||||
if (SUCCEEDED(com_init_result)) {
|
||||
CoUninitialize();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get min latency
|
||||
cubeb_stream_params params{};
|
||||
params.rate = TargetSampleRate;
|
||||
params.channels = 2;
|
||||
@ -361,12 +375,27 @@ u32 GetCubebLatency() {
|
||||
u32 latency{0};
|
||||
const auto latency_error = cubeb_get_min_latency(ctx, ¶ms, &latency);
|
||||
if (latency_error != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error);
|
||||
latency = TargetSampleCount * 2;
|
||||
LOG_ERROR(Audio_Sink, "Cubeb could not get min latency, it is not suitable.");
|
||||
return false;
|
||||
}
|
||||
latency = std::max(latency, TargetSampleCount * 2);
|
||||
cubeb_destroy(ctx);
|
||||
return latency;
|
||||
|
||||
// Test opening a device with standard parameters
|
||||
cubeb_devid output_device{0};
|
||||
cubeb_devid input_device{0};
|
||||
std::string name{"Yuzu test"};
|
||||
cubeb_stream* stream{nullptr};
|
||||
|
||||
if (cubeb_stream_init(ctx, &stream, name.c_str(), input_device, nullptr, output_device, ¶ms,
|
||||
latency, &TmpDataCallback, &TmpStateCallback, nullptr) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Cubeb could not open a device, it is not suitable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
cubeb_stream_stop(stream);
|
||||
cubeb_stream_destroy(stream);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
|
@ -97,10 +97,11 @@ private:
|
||||
std::vector<std::string> ListCubebSinkDevices(bool capture);
|
||||
|
||||
/**
|
||||
* Get the reported latency for this sink.
|
||||
* Check if this backend is suitable for use.
|
||||
* Checks if enabled, its latency, whether it opens successfully, etc.
|
||||
*
|
||||
* @return Minimum latency for this sink.
|
||||
* @return True is this backend is suitable, false otherwise.
|
||||
*/
|
||||
u32 GetCubebLatency();
|
||||
bool IsCubebSuitable();
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "audio_core/sink/sdl2_sink.h"
|
||||
#include "audio_core/sink/sink_stream.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::Sink {
|
||||
@ -84,6 +85,7 @@ public:
|
||||
}
|
||||
|
||||
Stop();
|
||||
SDL_ClearQueuedAudio(device);
|
||||
SDL_CloseAudioDevice(device);
|
||||
}
|
||||
|
||||
@ -227,8 +229,42 @@ std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
||||
return device_list;
|
||||
}
|
||||
|
||||
u32 GetSDLLatency() {
|
||||
return TargetSampleCount * 2;
|
||||
bool IsSDLSuitable() {
|
||||
#if !defined(HAVE_SDL2)
|
||||
return false;
|
||||
#else
|
||||
// Check SDL can init
|
||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We can set any latency frequency we want with SDL, so no need to check that.
|
||||
|
||||
// Check we can open a device with standard parameters
|
||||
SDL_AudioSpec spec;
|
||||
spec.freq = TargetSampleRate;
|
||||
spec.channels = 2u;
|
||||
spec.format = AUDIO_S16SYS;
|
||||
spec.samples = TargetSampleCount * 2;
|
||||
spec.callback = nullptr;
|
||||
spec.userdata = nullptr;
|
||||
|
||||
SDL_AudioSpec obtained;
|
||||
auto device = SDL_OpenAudioDevice(nullptr, false, &spec, &obtained, false);
|
||||
|
||||
if (device == 0) {
|
||||
LOG_ERROR(Audio_Sink, "SDL failed to open a device, it is not suitable. Error: {}",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_CloseAudioDevice(device);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
|
@ -88,10 +88,11 @@ private:
|
||||
std::vector<std::string> ListSDLSinkDevices(bool capture);
|
||||
|
||||
/**
|
||||
* Get the reported latency for this sink.
|
||||
* Check if this backend is suitable for use.
|
||||
* Checks if enabled, its latency, whether it opens successfully, etc.
|
||||
*
|
||||
* @return Minimum latency for this sink.
|
||||
* @return True is this backend is suitable, false otherwise.
|
||||
*/
|
||||
u32 GetSDLLatency();
|
||||
bool IsSDLSuitable();
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
|
@ -22,7 +22,7 @@ namespace {
|
||||
struct SinkDetails {
|
||||
using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view);
|
||||
using ListDevicesFn = std::vector<std::string> (*)(bool);
|
||||
using LatencyFn = u32 (*)();
|
||||
using SuitableFn = bool (*)();
|
||||
|
||||
/// Name for this sink.
|
||||
Settings::AudioEngine id;
|
||||
@ -30,8 +30,8 @@ struct SinkDetails {
|
||||
FactoryFn factory;
|
||||
/// A method to call to list available devices.
|
||||
ListDevicesFn list_devices;
|
||||
/// Method to get the latency of this backend.
|
||||
LatencyFn latency;
|
||||
/// Check whether this backend is suitable to be used.
|
||||
SuitableFn is_suitable;
|
||||
};
|
||||
|
||||
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
||||
@ -43,7 +43,7 @@ constexpr SinkDetails sink_details[] = {
|
||||
return std::make_unique<CubebSink>(device_id);
|
||||
},
|
||||
&ListCubebSinkDevices,
|
||||
&GetCubebLatency,
|
||||
&IsCubebSuitable,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_SDL2
|
||||
@ -53,14 +53,17 @@ constexpr SinkDetails sink_details[] = {
|
||||
return std::make_unique<SDLSink>(device_id);
|
||||
},
|
||||
&ListSDLSinkDevices,
|
||||
&GetSDLLatency,
|
||||
&IsSDLSuitable,
|
||||
},
|
||||
#endif
|
||||
SinkDetails{Settings::AudioEngine::Null,
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<NullSink>(device_id);
|
||||
},
|
||||
[](bool capture) { return std::vector<std::string>{"null"}; }, []() { return 0u; }},
|
||||
SinkDetails{
|
||||
Settings::AudioEngine::Null,
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<NullSink>(device_id);
|
||||
},
|
||||
[](bool capture) { return std::vector<std::string>{"null"}; },
|
||||
[]() { return true; },
|
||||
},
|
||||
};
|
||||
|
||||
const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
||||
@ -72,18 +75,22 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
||||
auto iter = find_backend(sink_id);
|
||||
|
||||
if (sink_id == Settings::AudioEngine::Auto) {
|
||||
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
||||
// causes audio issues, in that case go with SDL.
|
||||
#if defined(HAVE_CUBEB) && defined(HAVE_SDL2)
|
||||
iter = find_backend(Settings::AudioEngine::Cubeb);
|
||||
if (iter->latency() > TargetSampleCount * 3) {
|
||||
iter = find_backend(Settings::AudioEngine::Sdl2);
|
||||
// Auto-select a backend. Use the sink details ordering, preferring cubeb first, checking
|
||||
// that the backend is available and suitable to use.
|
||||
for (auto& details : sink_details) {
|
||||
if (details.is_suitable()) {
|
||||
iter = &details;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
iter = std::begin(sink_details);
|
||||
#endif
|
||||
LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
|
||||
Settings::CanonicalizeEnum(iter->id));
|
||||
} else {
|
||||
if (iter != std::end(sink_details) && !iter->is_suitable()) {
|
||||
LOG_ERROR(Service_Audio, "Selected backend {} is not suitable, falling back to null",
|
||||
Settings::CanonicalizeEnum(iter->id));
|
||||
iter = find_backend(Settings::AudioEngine::Null);
|
||||
}
|
||||
}
|
||||
|
||||
if (iter == std::end(sink_details)) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <version>
|
||||
#include "common/settings_enums.h"
|
||||
#if __cpp_lib_chrono >= 201907L
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
@ -145,6 +146,10 @@ bool IsFastmemEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsDockedMode() {
|
||||
return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked;
|
||||
}
|
||||
|
||||
float Volume() {
|
||||
if (values.audio_muted) {
|
||||
return 0.0f;
|
||||
|
@ -379,7 +379,13 @@ struct Values {
|
||||
|
||||
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
|
||||
|
||||
SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System};
|
||||
SwitchableSetting<ConsoleMode> use_docked_mode{linkage,
|
||||
ConsoleMode::Docked,
|
||||
"use_docked_mode",
|
||||
Category::System,
|
||||
Specialization::Radio,
|
||||
true,
|
||||
true};
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
@ -519,6 +525,8 @@ bool IsGPULevelHigh();
|
||||
|
||||
bool IsFastmemEnabled();
|
||||
|
||||
bool IsDockedMode();
|
||||
|
||||
float Volume();
|
||||
|
||||
std::string GetTimeZoneString(TimeZone time_zone);
|
||||
|
@ -56,6 +56,7 @@ enum Specialization : u8 {
|
||||
Scalar = 5, // Values are continuous
|
||||
Countable = 6, // Can be stepped through
|
||||
Paired = 7, // Another setting is associated with this setting
|
||||
Radio = 8, // Setting should be presented in a radio group
|
||||
|
||||
Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage
|
||||
};
|
||||
|
@ -146,6 +146,8 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
||||
|
||||
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
|
||||
|
||||
ENUM(ConsoleMode, Handheld, Docked);
|
||||
|
||||
template <typename Type>
|
||||
inline std::string CanonicalizeEnum(Type id) {
|
||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||
|
@ -460,11 +460,6 @@ S operator&(const S& i, const swap_struct_t<T, F> v) {
|
||||
return i & v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator&(const swap_struct_t<T, F> v, const S& i) {
|
||||
return static_cast<S>(v.swap() & i);
|
||||
}
|
||||
|
||||
// Comparison
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator<(const S& p, const swap_struct_t<T, F> v) {
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
@ -62,7 +64,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
|
||||
controller->Connect(true);
|
||||
}
|
||||
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
||||
!Settings::values.use_docked_mode.GetValue()) {
|
||||
!Settings::IsDockedMode()) {
|
||||
// We should *never* reach here under any normal circumstances.
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
controller->Connect(true);
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
|
||||
namespace Layout {
|
||||
@ -49,7 +50,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
|
||||
}
|
||||
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(f32 res_scale) {
|
||||
const bool is_docked = Settings::values.use_docked_mode.GetValue();
|
||||
const bool is_docked = Settings::IsDockedMode();
|
||||
const u32 screen_width = is_docked ? ScreenDocked::Width : ScreenUndocked::Width;
|
||||
const u32 screen_height = is_docked ? ScreenDocked::Height : ScreenUndocked::Height;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
@ -833,7 +834,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
if (Settings::values.use_docked_mode.GetValue()) {
|
||||
if (Settings::IsDockedMode()) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
} else {
|
||||
@ -921,7 +922,7 @@ void IStorage::Open(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()};
|
||||
const bool use_docked_mode{Settings::IsDockedMode()};
|
||||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
|
||||
@ -67,8 +68,7 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
|
||||
}
|
||||
|
||||
PerformanceMode Controller::GetCurrentPerformanceMode() const {
|
||||
return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Boost
|
||||
: PerformanceMode::Normal;
|
||||
return Settings::IsDockedMode() ? PerformanceMode::Boost : PerformanceMode::Normal;
|
||||
}
|
||||
|
||||
PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
|
||||
|
@ -174,7 +174,7 @@ public:
|
||||
{6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
|
||||
{7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
|
||||
{8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
|
||||
{9, nullptr, "DecodeInterleavedForMultiStream"},
|
||||
{9, &IHardwareOpusDecoderManager::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@ -206,6 +206,16 @@ private:
|
||||
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior);
|
||||
}
|
||||
|
||||
void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto extra_behavior = rp.Pop<bool>() ? OpusDecoderState::ExtraBehavior::ResetContext
|
||||
: OpusDecoderState::ExtraBehavior::None;
|
||||
|
||||
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior);
|
||||
}
|
||||
|
||||
OpusDecoderState decoder_state;
|
||||
};
|
||||
|
||||
@ -354,6 +364,40 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
|
||||
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
|
||||
}
|
||||
|
||||
void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
|
||||
OpusMultiStreamParametersEx params;
|
||||
std::memcpy(¶ms, ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
|
||||
|
||||
const auto& sample_rate = params.sample_rate;
|
||||
const auto& channel_count = params.channel_count;
|
||||
|
||||
LOG_INFO(
|
||||
Audio,
|
||||
"called with sample_rate={}, channel_count={}, number_streams={}, number_stereo_streams={}",
|
||||
sample_rate, channel_count, params.number_streams, params.number_stereo_streams);
|
||||
|
||||
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
|
||||
sample_rate == 12000 || sample_rate == 8000,
|
||||
"Invalid sample rate");
|
||||
|
||||
int error = 0;
|
||||
OpusDecoderPtr decoder{opus_multistream_decoder_create(
|
||||
sample_rate, static_cast<int>(channel_count), params.number_streams,
|
||||
params.number_stereo_streams, params.channel_mappings.data(), &error)};
|
||||
if (error != OPUS_OK || decoder == nullptr) {
|
||||
LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IHardwareOpusDecoderManager>(
|
||||
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
|
||||
}
|
||||
|
||||
HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
|
||||
@ -362,7 +406,8 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
|
||||
{3, nullptr, "GetWorkBufferSizeForMultiStream"},
|
||||
{4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
|
||||
{5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
|
||||
{6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
|
||||
{6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
|
||||
"OpenHardwareOpusDecoderForMultiStreamEx"},
|
||||
{7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
|
||||
{8, nullptr, "GetWorkBufferSizeExEx"},
|
||||
{9, nullptr, "GetWorkBufferSizeForMultiStreamExEx"},
|
||||
|
@ -18,8 +18,10 @@ struct OpusMultiStreamParametersEx {
|
||||
u32 number_stereo_streams;
|
||||
u32 use_large_frame_size;
|
||||
u32 padding;
|
||||
std::array<u32, 64> channel_mappings;
|
||||
std::array<u8, 0x100> channel_mappings;
|
||||
};
|
||||
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,
|
||||
"OpusMultiStreamParametersEx has incorrect size");
|
||||
|
||||
class HwOpus final : public ServiceFramework<HwOpus> {
|
||||
public:
|
||||
@ -29,6 +31,7 @@ public:
|
||||
private:
|
||||
void OpenHardwareOpusDecoder(HLERequestContext& ctx);
|
||||
void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
|
||||
void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
|
||||
void GetWorkBufferSize(HLERequestContext& ctx);
|
||||
void GetWorkBufferSizeEx(HLERequestContext& ctx);
|
||||
void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
|
||||
|
@ -331,7 +331,7 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties()
|
||||
};
|
||||
|
||||
// Hack: There is no touch in docked but games still allow it
|
||||
if (Settings::values.use_docked_mode.GetValue()) {
|
||||
if (Settings::IsDockedMode()) {
|
||||
gesture.points[id] = {
|
||||
.x = static_cast<s32>(active_x * Layout::ScreenDocked::Width),
|
||||
.y = static_cast<s32>(active_y * Layout::ScreenDocked::Height),
|
||||
|
@ -1518,7 +1518,7 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller
|
||||
return false;
|
||||
}
|
||||
// Handheld shouldn't be supported in docked mode
|
||||
if (Settings::values.use_docked_mode.GetValue()) {
|
||||
if (Settings::IsDockedMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ private:
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
if (Settings::values.use_docked_mode.GetValue()) {
|
||||
if (Settings::IsDockedMode()) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
} else {
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
@ -275,7 +276,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
static_cast<u32>(Settings::values.shader_backend.GetValue()));
|
||||
AddField(field_type, "Renderer_UseAsynchronousShaders",
|
||||
Settings::values.use_asynchronous_shaders.GetValue());
|
||||
AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue());
|
||||
AddField(field_type, "System_UseDockedMode", Settings::IsDockedMode());
|
||||
}
|
||||
|
||||
bool TelemetrySession::SubmitTestcase() {
|
||||
|
@ -835,15 +835,15 @@ public:
|
||||
return input_engine->SupportsNfc(identifier);
|
||||
}
|
||||
|
||||
Common::Input::NfcState StartNfcPolling() {
|
||||
Common::Input::NfcState StartNfcPolling() override {
|
||||
return input_engine->StartNfcPolling(identifier);
|
||||
}
|
||||
|
||||
Common::Input::NfcState StopNfcPolling() {
|
||||
Common::Input::NfcState StopNfcPolling() override {
|
||||
return input_engine->StopNfcPolling(identifier);
|
||||
}
|
||||
|
||||
Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) {
|
||||
Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) override {
|
||||
return input_engine->ReadAmiiboData(identifier, out_data);
|
||||
}
|
||||
|
||||
@ -852,11 +852,11 @@ public:
|
||||
}
|
||||
|
||||
Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request,
|
||||
Common::Input::MifareRequest& out_data) {
|
||||
Common::Input::MifareRequest& out_data) override {
|
||||
return input_engine->ReadMifareData(identifier, request, out_data);
|
||||
}
|
||||
|
||||
Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) {
|
||||
Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) override {
|
||||
return input_engine->WriteMifareData(identifier, request);
|
||||
}
|
||||
|
||||
|
@ -289,8 +289,11 @@ std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_ad
|
||||
MarkWrittenBuffer(buffer_id, *cpu_addr, size);
|
||||
break;
|
||||
case ObtainBufferOperation::DiscardWrite: {
|
||||
IntervalType interval{*cpu_addr, size};
|
||||
VAddr cpu_addr_start = Common::AlignDown(*cpu_addr, 64);
|
||||
VAddr cpu_addr_end = Common::AlignUp(*cpu_addr + size, 64);
|
||||
IntervalType interval{cpu_addr_start, cpu_addr_end};
|
||||
ClearDownload(interval);
|
||||
common_ranges.subtract(interval);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1159,6 +1162,11 @@ void BufferCache<P>::UpdateDrawIndirect() {
|
||||
.size = static_cast<u32>(size),
|
||||
.buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
|
||||
};
|
||||
VAddr cpu_addr_start = Common::AlignDown(*cpu_addr, 64);
|
||||
VAddr cpu_addr_end = Common::AlignUp(*cpu_addr + size, 64);
|
||||
IntervalType interval{cpu_addr_start, cpu_addr_end};
|
||||
ClearDownload(interval);
|
||||
common_ranges.subtract(interval);
|
||||
};
|
||||
if (current_draw_indirect->include_count) {
|
||||
update(current_draw_indirect->count_start_address, sizeof(u32),
|
||||
|
@ -27,14 +27,24 @@ MICROPROFILE_DEFINE(MacroHLE, "GPU", "Execute macro HLE", MP_RGB(128, 192, 192))
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
static void Dump(u64 hash, std::span<const u32> code) {
|
||||
static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) {
|
||||
const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
|
||||
const auto macro_dir{base_dir / "macros"};
|
||||
if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories");
|
||||
return;
|
||||
}
|
||||
const auto name{macro_dir / fmt::format("{:016x}.macro", hash)};
|
||||
auto name{macro_dir / fmt::format("{:016x}.macro", hash)};
|
||||
|
||||
if (decompiled) {
|
||||
auto new_name{macro_dir / fmt::format("decompiled_{:016x}.macro", hash)};
|
||||
if (Common::FS::Exists(name)) {
|
||||
(void)Common::FS::RenameFile(name, new_name);
|
||||
return;
|
||||
}
|
||||
name = new_name;
|
||||
}
|
||||
|
||||
std::fstream macro_file(name, std::ios::out | std::ios::binary);
|
||||
if (!macro_file) {
|
||||
LOG_ERROR(Common_Filesystem, "Unable to open or create file at {}",
|
||||
@ -90,9 +100,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
if (!mid_method.has_value()) {
|
||||
cache_info.lle_program = Compile(macro_code->second);
|
||||
cache_info.hash = Common::HashValue(macro_code->second);
|
||||
if (Settings::values.dump_macros) {
|
||||
Dump(cache_info.hash, macro_code->second);
|
||||
}
|
||||
} else {
|
||||
const auto& macro_cached = uploaded_macro_code[mid_method.value()];
|
||||
const auto rebased_method = method - mid_method.value();
|
||||
@ -102,9 +109,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
code.size() * sizeof(u32));
|
||||
cache_info.hash = Common::HashValue(code);
|
||||
cache_info.lle_program = Compile(code);
|
||||
if (Settings::values.dump_macros) {
|
||||
Dump(cache_info.hash, code);
|
||||
}
|
||||
}
|
||||
|
||||
auto hle_program = hle_macros->GetHLEProgram(cache_info.hash);
|
||||
@ -117,6 +121,10 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
MICROPROFILE_SCOPE(MacroHLE);
|
||||
cache_info.hle_program->Execute(parameters, method);
|
||||
}
|
||||
|
||||
if (Settings::values.dump_macros) {
|
||||
Dump(cache_info.hash, macro_code->second, cache_info.has_hle_program);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -611,9 +611,6 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
|
||||
const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))};
|
||||
Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
|
||||
if (Settings::values.dump_shaders) {
|
||||
env.Dump(hash, key.unique_hashes[index]);
|
||||
}
|
||||
if (!uses_vertex_a || index != 1) {
|
||||
// Normal path
|
||||
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
|
||||
@ -624,6 +621,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
|
||||
}
|
||||
|
||||
if (Settings::values.dump_shaders) {
|
||||
env.Dump(hash, key.unique_hashes[index]);
|
||||
}
|
||||
|
||||
if (programs[index].info.requires_layer_emulation) {
|
||||
layer_source_program = &programs[index];
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // for deprecated OpenSSL functions
|
||||
#endif
|
||||
#include <jwt/jwt.hpp>
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <thread>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
@ -226,9 +228,11 @@ int QtControllerSelectorDialog::exec() {
|
||||
}
|
||||
|
||||
void QtControllerSelectorDialog::ApplyConfiguration() {
|
||||
const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
|
||||
Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
|
||||
OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system);
|
||||
const bool pre_docked_mode = Settings::IsDockedMode();
|
||||
const bool docked_mode_selected = ui->radioDocked->isChecked();
|
||||
Settings::values.use_docked_mode.SetValue(
|
||||
docked_mode_selected ? Settings::ConsoleMode::Docked : Settings::ConsoleMode::Handheld);
|
||||
OnDockedModeChanged(pre_docked_mode, docked_mode_selected, system);
|
||||
|
||||
Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
|
||||
Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
|
||||
@ -616,8 +620,8 @@ void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) {
|
||||
ui->radioDocked->setEnabled(!is_handheld);
|
||||
ui->radioUndocked->setEnabled(!is_handheld);
|
||||
|
||||
ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue());
|
||||
ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue());
|
||||
ui->radioDocked->setChecked(Settings::IsDockedMode());
|
||||
ui->radioUndocked->setChecked(!Settings::IsDockedMode());
|
||||
|
||||
// Also force into undocked mode if the controller type is handheld.
|
||||
if (is_handheld) {
|
||||
|
@ -928,8 +928,8 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) {
|
||||
const Layout::FramebufferLayout layout{[]() {
|
||||
u32 height = UISettings::values.screenshot_height.GetValue();
|
||||
if (height == 0) {
|
||||
height = Settings::values.use_docked_mode.GetValue() ? Layout::ScreenDocked::Height
|
||||
: Layout::ScreenUndocked::Height;
|
||||
height = Settings::IsDockedMode() ? Layout::ScreenDocked::Height
|
||||
: Layout::ScreenUndocked::Height;
|
||||
height *= Settings::values.resolution_info.up_factor;
|
||||
}
|
||||
const u32 width =
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_common.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
@ -85,9 +86,9 @@ const std::map<Settings::ScalingFilter, QString> Config::scaling_filter_texts_ma
|
||||
{Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))},
|
||||
};
|
||||
|
||||
const std::map<bool, QString> Config::use_docked_mode_texts_map = {
|
||||
{true, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))},
|
||||
{false, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
|
||||
const std::map<Settings::ConsoleMode, QString> Config::use_docked_mode_texts_map = {
|
||||
{Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))},
|
||||
{Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
|
||||
};
|
||||
|
||||
const std::map<Settings::GpuAccuracy, QString> Config::gpu_accuracy_texts_map = {
|
||||
@ -376,7 +377,7 @@ void Config::ReadControlValues() {
|
||||
const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
|
||||
if (controller_type == Settings::ControllerType::Handheld) {
|
||||
Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig());
|
||||
Settings::values.use_docked_mode.SetValue(false);
|
||||
Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld);
|
||||
}
|
||||
|
||||
if (IsCustomConfig()) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <QMetaType>
|
||||
#include <QVariant>
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
|
||||
class QSettings;
|
||||
@ -51,7 +52,7 @@ public:
|
||||
|
||||
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
|
||||
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;
|
||||
static const std::map<bool, QString> use_docked_mode_texts_map;
|
||||
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map;
|
||||
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map;
|
||||
static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map;
|
||||
static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map;
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
@ -197,9 +199,11 @@ void ConfigureInput::ApplyConfiguration() {
|
||||
|
||||
advanced->ApplyConfiguration();
|
||||
|
||||
const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
|
||||
Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
|
||||
OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system);
|
||||
const bool pre_docked_mode = Settings::IsDockedMode();
|
||||
const bool docked_mode_selected = ui->radioDocked->isChecked();
|
||||
Settings::values.use_docked_mode.SetValue(
|
||||
docked_mode_selected ? Settings::ConsoleMode::Docked : Settings::ConsoleMode::Handheld);
|
||||
OnDockedModeChanged(pre_docked_mode, docked_mode_selected, system);
|
||||
|
||||
Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
|
||||
Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
|
||||
@ -267,8 +271,8 @@ void ConfigureInput::UpdateDockedState(bool is_handheld) {
|
||||
ui->radioDocked->setEnabled(!is_handheld);
|
||||
ui->radioUndocked->setEnabled(!is_handheld);
|
||||
|
||||
ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue());
|
||||
ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue());
|
||||
ui->radioDocked->setChecked(Settings::IsDockedMode());
|
||||
ui->radioUndocked->setChecked(!Settings::IsDockedMode());
|
||||
|
||||
// Also force into undocked mode if the controller type is handheld.
|
||||
if (is_handheld) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "common/fs/fs_util.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "common/settings_input.h"
|
||||
#include "configuration/shared_widget.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
@ -98,6 +99,12 @@ void ConfigurePerGame::ApplyConfiguration() {
|
||||
addons_tab->ApplyConfiguration();
|
||||
input_tab->ApplyConfiguration();
|
||||
|
||||
if (Settings::IsDockedMode() && Settings::values.players.GetValue()[0].controller_type ==
|
||||
Settings::ControllerType::Handheld) {
|
||||
Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld);
|
||||
Settings::values.use_docked_mode.SetGlobal(true);
|
||||
}
|
||||
|
||||
system.ApplySettings();
|
||||
Settings::LogSettings();
|
||||
|
||||
|
@ -106,6 +106,11 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) {
|
||||
push(Settings::values.linkage.by_category[Settings::Category::System]);
|
||||
|
||||
for (auto setting : settings) {
|
||||
if (setting->Id() == Settings::values.use_docked_mode.Id() &&
|
||||
Settings::IsConfiguringGlobal()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs);
|
||||
|
||||
if (widget == nullptr) {
|
||||
|
@ -135,7 +135,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
||||
INSERT(Settings, region_index, "Region:", "");
|
||||
INSERT(Settings, time_zone_index, "Time Zone:", "");
|
||||
INSERT(Settings, sound_index, "Sound Output Mode:", "");
|
||||
INSERT(Settings, use_docked_mode, "", "");
|
||||
INSERT(Settings, use_docked_mode, "Console Mode:", "");
|
||||
INSERT(Settings, current_user, "", "");
|
||||
|
||||
// Controls
|
||||
@ -379,6 +379,9 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||
PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"),
|
||||
PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"),
|
||||
}});
|
||||
translations->insert(
|
||||
{Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
|
||||
{PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}});
|
||||
|
||||
#undef PAIR
|
||||
#undef CTX_PAIR
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <QLineEdit>
|
||||
#include <QObject>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QSizePolicy>
|
||||
#include <QSlider>
|
||||
@ -171,6 +172,65 @@ QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
|
||||
return combobox;
|
||||
}
|
||||
|
||||
QWidget* Widget::CreateRadioGroup(std::function<std::string()>& serializer,
|
||||
std::function<void()>& restore_func,
|
||||
const std::function<void()>& touch) {
|
||||
const auto type = setting.EnumIndex();
|
||||
|
||||
QWidget* group = new QWidget(this);
|
||||
QHBoxLayout* layout = new QHBoxLayout(group);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
group->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
|
||||
const ComboboxTranslations* enumeration{nullptr};
|
||||
if (combobox_enumerations.contains(type)) {
|
||||
enumeration = &combobox_enumerations.at(type);
|
||||
for (const auto& [id, name] : *enumeration) {
|
||||
QRadioButton* radio_button = new QRadioButton(name, group);
|
||||
layout->addWidget(radio_button);
|
||||
radio_buttons.push_back({id, radio_button});
|
||||
}
|
||||
} else {
|
||||
return group;
|
||||
}
|
||||
|
||||
const auto get_selected = [=]() -> u32 {
|
||||
for (const auto& [id, button] : radio_buttons) {
|
||||
if (button->isChecked()) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
const auto set_index = [=](u32 value) {
|
||||
for (const auto& [id, button] : radio_buttons) {
|
||||
button->setChecked(id == value);
|
||||
}
|
||||
};
|
||||
|
||||
const u32 setting_value = std::stoi(setting.ToString());
|
||||
set_index(setting_value);
|
||||
|
||||
serializer = [get_selected]() {
|
||||
int current = get_selected();
|
||||
return std::to_string(current);
|
||||
};
|
||||
|
||||
restore_func = [this, set_index]() {
|
||||
const u32 global_value = std::stoi(RelevantDefault(setting));
|
||||
set_index(global_value);
|
||||
};
|
||||
|
||||
if (!Settings::IsConfiguringGlobal()) {
|
||||
for (const auto& [id, button] : radio_buttons) {
|
||||
QObject::connect(button, &QAbstractButton::clicked, [touch]() { touch(); });
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
QWidget* Widget::CreateLineEdit(std::function<std::string()>& serializer,
|
||||
std::function<void()>& restore_func,
|
||||
const std::function<void()>& touch, bool managed) {
|
||||
@ -411,6 +471,8 @@ void Widget::SetupComponent(const QString& label, std::function<void()>& load_fu
|
||||
return RequestType::Slider;
|
||||
case Settings::Specialization::Countable:
|
||||
return RequestType::SpinBox;
|
||||
case Settings::Specialization::Radio:
|
||||
return RequestType::RadioGroup;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -439,7 +501,11 @@ void Widget::SetupComponent(const QString& label, std::function<void()>& load_fu
|
||||
if (setting.TypeId() == typeid(bool)) {
|
||||
data_component = CreateCheckBox(&setting, label, serializer, restore_func, touch);
|
||||
} else if (setting.IsEnum()) {
|
||||
data_component = CreateCombobox(serializer, restore_func, touch);
|
||||
if (request == RequestType::RadioGroup) {
|
||||
data_component = CreateRadioGroup(serializer, restore_func, touch);
|
||||
} else {
|
||||
data_component = CreateCombobox(serializer, restore_func, touch);
|
||||
}
|
||||
} else if (type == typeid(u32) || type == typeid(int) || type == typeid(u16) ||
|
||||
type == typeid(s64) || type == typeid(u8)) {
|
||||
switch (request) {
|
||||
|
@ -22,6 +22,7 @@ class QObject;
|
||||
class QPushButton;
|
||||
class QSlider;
|
||||
class QSpinBox;
|
||||
class QRadioButton;
|
||||
|
||||
namespace Settings {
|
||||
class BasicSetting;
|
||||
@ -38,6 +39,7 @@ enum class RequestType {
|
||||
LineEdit,
|
||||
HexEdit,
|
||||
DateTimeEdit,
|
||||
RadioGroup,
|
||||
MaxEnum,
|
||||
};
|
||||
|
||||
@ -91,6 +93,7 @@ public:
|
||||
QSlider* slider{};
|
||||
QComboBox* combobox{};
|
||||
QDateTimeEdit* date_time_edit{};
|
||||
std::vector<std::pair<u32, QRadioButton*>> radio_buttons{};
|
||||
|
||||
private:
|
||||
void SetupComponent(const QString& label, std::function<void()>& load_func, bool managed,
|
||||
@ -106,6 +109,9 @@ private:
|
||||
QWidget* CreateCombobox(std::function<std::string()>& serializer,
|
||||
std::function<void()>& restore_func,
|
||||
const std::function<void()>& touch);
|
||||
QWidget* CreateRadioGroup(std::function<std::string()>& serializer,
|
||||
std::function<void()>& restore_func,
|
||||
const std::function<void()>& touch);
|
||||
QWidget* CreateLineEdit(std::function<std::string()>& serializer,
|
||||
std::function<void()>& restore_func, const std::function<void()>& touch,
|
||||
bool managed = true);
|
||||
|
@ -1158,9 +1158,9 @@ void GMainWindow::InitializeWidgets() {
|
||||
[this](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
|
||||
for (auto const& docked_mode_pair : Config::use_docked_mode_texts_map) {
|
||||
context_menu.addAction(docked_mode_pair.second, [this, docked_mode_pair] {
|
||||
if (docked_mode_pair.first != Settings::values.use_docked_mode.GetValue()) {
|
||||
for (auto const& pair : Config::use_docked_mode_texts_map) {
|
||||
context_menu.addAction(pair.second, [this, &pair] {
|
||||
if (pair.first != Settings::values.use_docked_mode.GetValue()) {
|
||||
OnToggleDockedMode();
|
||||
}
|
||||
});
|
||||
@ -3674,7 +3674,7 @@ void GMainWindow::OnTasReset() {
|
||||
}
|
||||
|
||||
void GMainWindow::OnToggleDockedMode() {
|
||||
const bool is_docked = Settings::values.use_docked_mode.GetValue();
|
||||
const bool is_docked = Settings::IsDockedMode();
|
||||
auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
|
||||
@ -3688,7 +3688,8 @@ void GMainWindow::OnToggleDockedMode() {
|
||||
controller_dialog->refreshConfiguration();
|
||||
}
|
||||
|
||||
Settings::values.use_docked_mode.SetValue(!is_docked);
|
||||
Settings::values.use_docked_mode.SetValue(is_docked ? Settings::ConsoleMode::Handheld
|
||||
: Settings::ConsoleMode::Docked);
|
||||
UpdateDockedButton();
|
||||
OnDockedModeChanged(is_docked, !is_docked, *system);
|
||||
}
|
||||
@ -4118,10 +4119,10 @@ void GMainWindow::UpdateGPUAccuracyButton() {
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateDockedButton() {
|
||||
const bool is_docked = Settings::values.use_docked_mode.GetValue();
|
||||
dock_status_button->setChecked(is_docked);
|
||||
const auto console_mode = Settings::values.use_docked_mode.GetValue();
|
||||
dock_status_button->setChecked(Settings::IsDockedMode());
|
||||
dock_status_button->setText(
|
||||
Config::use_docked_mode_texts_map.find(is_docked)->second.toUpper());
|
||||
Config::use_docked_mode_texts_map.find(console_mode)->second.toUpper());
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateAPIText() {
|
||||
|
Reference in New Issue
Block a user