diff options
Diffstat (limited to 'src')
41 files changed, 560 insertions, 363 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1bdf70b76..3ad2c0950 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,12 +103,6 @@ else() -Wno-unused-parameter ) - # TODO: Remove when we update to a GCC compiler that enables this - # by default (i.e. GCC 10 or newer). - if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) - add_compile_options(-fconcepts) - endif() - if (ARCHITECTURE_x86_64) add_compile_options("-mcx16") endif() diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 090dd19b1..e553b8203 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -36,8 +36,6 @@ add_library(audio_core STATIC splitter_context.h stream.cpp stream.h - time_stretch.cpp - time_stretch.h voice_context.cpp voice_context.h @@ -63,7 +61,6 @@ if (NOT MSVC) endif() target_link_libraries(audio_core PUBLIC common core) -target_link_libraries(audio_core PRIVATE SoundTouch) if(ENABLE_CUBEB) target_link_libraries(audio_core PRIVATE cubeb) diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp index 93c35e785..13de3087c 100644 --- a/src/audio_core/cubeb_sink.cpp +++ b/src/audio_core/cubeb_sink.cpp @@ -7,7 +7,6 @@ #include <cstring> #include "audio_core/cubeb_sink.h" #include "audio_core/stream.h" -#include "audio_core/time_stretch.h" #include "common/assert.h" #include "common/logging/log.h" #include "common/ring_buffer.h" @@ -23,8 +22,7 @@ class CubebSinkStream final : public SinkStream { public: CubebSinkStream(cubeb* ctx_, u32 sample_rate, u32 num_channels_, cubeb_devid output_device, const std::string& name) - : ctx{ctx_}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, - num_channels} { + : ctx{ctx_}, num_channels{std::min(num_channels_, 6u)} { cubeb_stream_params params{}; params.rate = sample_rate; @@ -131,7 +129,6 @@ private: Common::RingBuffer<s16, 0x10000> queue; std::array<s16, 2> last_frame{}; std::atomic<bool> should_flush{}; - TimeStretcher time_stretch; static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, void* output_buffer, long num_frames); @@ -205,25 +202,7 @@ long CubebSinkStream::DataCallback([[maybe_unused]] cubeb_stream* stream, void* const std::size_t num_channels = impl->GetNumChannels(); const std::size_t samples_to_write = num_channels * num_frames; - std::size_t samples_written; - - /* - if (Settings::values.enable_audio_stretching.GetValue()) { - const std::vector<s16> in{impl->queue.Pop()}; - const std::size_t num_in{in.size() / num_channels}; - s16* const out{reinterpret_cast<s16*>(buffer)}; - const std::size_t out_frames = - impl->time_stretch.Process(in.data(), num_in, out, num_frames); - samples_written = out_frames * num_channels; - - if (impl->should_flush) { - impl->time_stretch.Flush(); - impl->should_flush = false; - } - } else { - samples_written = impl->queue.Pop(buffer, samples_to_write); - }*/ - samples_written = impl->queue.Pop(buffer, samples_to_write); + const std::size_t samples_written = impl->queue.Pop(buffer, samples_to_write); if (samples_written >= num_channels) { std::memcpy(&impl->last_frame[0], buffer + (samples_written - num_channels) * sizeof(s16), diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp index 62d3716a6..2d14ce2cb 100644 --- a/src/audio_core/sdl2_sink.cpp +++ b/src/audio_core/sdl2_sink.cpp @@ -7,7 +7,6 @@ #include <cstring> #include "audio_core/sdl2_sink.h" #include "audio_core/stream.h" -#include "audio_core/time_stretch.h" #include "common/assert.h" #include "common/logging/log.h" //#include "common/settings.h" @@ -27,7 +26,7 @@ namespace AudioCore { class SDLSinkStream final : public SinkStream { public: SDLSinkStream(u32 sample_rate, u32 num_channels_, const std::string& output_device) - : num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, num_channels} { + : num_channels{std::min(num_channels_, 6u)} { SDL_AudioSpec spec; spec.freq = sample_rate; @@ -116,7 +115,6 @@ private: SDL_AudioDeviceID dev = 0; u32 num_channels{}; std::atomic<bool> should_flush{}; - TimeStretcher time_stretch; }; SDLSink::SDLSink(std::string_view target_device_name) { diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp deleted file mode 100644 index 726591fce..000000000 --- a/src/audio_core/time_stretch.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <cmath> -#include <cstddef> -#include "audio_core/time_stretch.h" -#include "common/logging/log.h" - -namespace AudioCore { - -TimeStretcher::TimeStretcher(u32 sample_rate, u32 channel_count) : m_sample_rate{sample_rate} { - m_sound_touch.setChannels(channel_count); - m_sound_touch.setSampleRate(sample_rate); - m_sound_touch.setPitch(1.0); - m_sound_touch.setTempo(1.0); -} - -void TimeStretcher::Clear() { - m_sound_touch.clear(); -} - -void TimeStretcher::Flush() { - m_sound_touch.flush(); -} - -std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out, - std::size_t num_out) { - const double time_delta = static_cast<double>(num_out) / m_sample_rate; // seconds - - // We were given actual_samples number of samples, and num_samples were requested from us. - double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out); - - const double max_latency = 0.25; // seconds - const double max_backlog = m_sample_rate * max_latency; - const double backlog_fullness = m_sound_touch.numSamples() / max_backlog; - if (backlog_fullness > 4.0) { - // Too many samples in backlog: Don't push anymore on - num_in = 0; - } - - // We ideally want the backlog to be about 50% full. - // This gives some headroom both ways to prevent underflow and overflow. - // We tweak current_ratio to encourage this. - constexpr double tweak_time_scale = 0.05; // seconds - const double tweak_correction = (backlog_fullness - 0.5) * (time_delta / tweak_time_scale); - current_ratio *= std::pow(1.0 + 2.0 * tweak_correction, tweak_correction < 0 ? 3.0 : 1.0); - - // This low-pass filter smoothes out variance in the calculated stretch ratio. - // The time-scale determines how responsive this filter is. - constexpr double lpf_time_scale = 0.712; // seconds - const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale); - m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio); - - // Place a lower limit of 5% speed. When a game boots up, there will be - // many silence samples. These do not need to be timestretched. - m_stretch_ratio = std::max(m_stretch_ratio, 0.05); - m_sound_touch.setTempo(m_stretch_ratio); - - LOG_TRACE(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio, - backlog_fullness); - - m_sound_touch.putSamples(in, static_cast<u32>(num_in)); - return m_sound_touch.receiveSamples(out, static_cast<u32>(num_out)); -} - -} // namespace AudioCore diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h deleted file mode 100644 index bb2270b96..000000000 --- a/src/audio_core/time_stretch.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <cstddef> -#include <SoundTouch.h> -#include "common/common_types.h" - -namespace AudioCore { - -class TimeStretcher { -public: - TimeStretcher(u32 sample_rate, u32 channel_count); - - /// @param in Input sample buffer - /// @param num_in Number of input frames in `in` - /// @param out Output sample buffer - /// @param num_out Desired number of output frames in `out` - /// @returns Actual number of frames written to `out` - std::size_t Process(const s16* in, std::size_t num_in, s16* out, std::size_t num_out); - - void Clear(); - - void Flush(); - -private: - u32 m_sample_rate; - soundtouch::SoundTouch m_sound_touch; - double m_stretch_ratio = 1.0; -}; - -} // namespace AudioCore diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h index b94d73c7a..69fde8421 100644 --- a/src/common/atomic_ops.h +++ b/src/common/atomic_ops.h @@ -46,6 +46,50 @@ namespace Common { reinterpret_cast<__int64*>(expected.data())) != 0; } +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected, + u8& actual) { + actual = + _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected, + u16& actual) { + actual = + _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected, + u32& actual) { + actual = + _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected, + u64& actual) { + actual = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), value, + expected); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected, + u128& actual) { + const bool result = + _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1], + value[0], reinterpret_cast<__int64*>(expected.data())) != 0; + actual = expected; + return result; +} + +[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) { + u128 result{}; + _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), result[1], + result[0], reinterpret_cast<__int64*>(result.data())); + return result; +} + #else [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { @@ -72,6 +116,52 @@ namespace Common { return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); } +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected, + u8& actual) { + actual = __sync_val_compare_and_swap(pointer, expected, value); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected, + u16& actual) { + actual = __sync_val_compare_and_swap(pointer, expected, value); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected, + u32& actual) { + actual = __sync_val_compare_and_swap(pointer, expected, value); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected, + u64& actual) { + actual = __sync_val_compare_and_swap(pointer, expected, value); + return actual == expected; +} + +[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected, + u128& actual) { + unsigned __int128 value_a; + unsigned __int128 expected_a; + unsigned __int128 actual_a; + std::memcpy(&value_a, value.data(), sizeof(u128)); + std::memcpy(&expected_a, expected.data(), sizeof(u128)); + actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); + std::memcpy(actual.data(), &actual_a, sizeof(u128)); + return actual_a == expected_a; +} + +[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) { + unsigned __int128 zeros_a = 0; + unsigned __int128 result_a = + __sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a); + + u128 result; + std::memcpy(result.data(), &result_a, sizeof(u128)); + return result; +} + #endif } // namespace Common diff --git a/src/common/settings.h b/src/common/settings.h index a37d83fb3..86e0fa140 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -38,6 +38,7 @@ enum class CPUAccuracy : u32 { Auto = 0, Accurate = 1, Unsafe = 2, + Paranoid = 3, }; enum class FullscreenMode : u32 { @@ -470,7 +471,7 @@ struct Values { // Cpu RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, - CPUAccuracy::Unsafe, "cpu_accuracy"}; + CPUAccuracy::Paranoid, "cpu_accuracy"}; // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021 BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"}; BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"}; diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 347e41efc..7a3f21dcf 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -55,8 +55,9 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen u64 NativeClock::GetRTSC() { TimePoint new_time_point{}; TimePoint current_time_point{}; + + current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); do { - current_time_point.pack = time_point.pack; _mm_mfence(); const u64 current_measure = __rdtsc(); u64 diff = current_measure - current_time_point.inner.last_measure; @@ -66,7 +67,7 @@ u64 NativeClock::GetRTSC() { : current_time_point.inner.last_measure; new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, - current_time_point.pack)); + current_time_point.pack, current_time_point.pack)); /// The clock cannot be more precise than the guest timer, remove the lower bits return new_time_point.inner.accumulated_ticks & inaccuracy_mask; } @@ -75,13 +76,14 @@ void NativeClock::Pause(bool is_paused) { if (!is_paused) { TimePoint current_time_point{}; TimePoint new_time_point{}; + + current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); do { - current_time_point.pack = time_point.pack; new_time_point.pack = current_time_point.pack; _mm_mfence(); new_time_point.inner.last_measure = __rdtsc(); } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, - current_time_point.pack)); + current_time_point.pack, current_time_point.pack)); } } diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 286976623..054572445 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -70,11 +70,13 @@ public: } void InterpreterFallback(u32 pc, std::size_t num_instructions) override { + parent.LogBacktrace(); UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc, MemoryReadCode(pc)); } void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { + parent.LogBacktrace(); LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", exception, pc, MemoryReadCode(pc), parent.IsInThumbMode()); @@ -186,35 +188,41 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* if (!Settings::values.cpuopt_recompile_exclusives) { config.recompile_on_exclusive_fastmem_failure = false; } - } + } else { + // Unsafe optimizations + if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { + config.unsafe_optimizations = true; + if (Settings::values.cpuopt_unsafe_unfuse_fma) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; + } + if (Settings::values.cpuopt_unsafe_reduce_fp_error) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; + } + if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; + } + if (Settings::values.cpuopt_unsafe_inaccurate_nan) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; + } + if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + } + } - // Unsafe optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { - config.unsafe_optimizations = true; - if (Settings::values.cpuopt_unsafe_unfuse_fma) { + // Curated optimizations + if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { + config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; - } - if (Settings::values.cpuopt_unsafe_reduce_fp_error) { - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; - } - if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; - } - if (Settings::values.cpuopt_unsafe_inaccurate_nan) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; - } - if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - } - // 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; - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + // Paranoia mode for debugging optimizations + if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) { + config.unsafe_optimizations = false; + config.optimizations = Dynarmic::no_optimizations; + } } return std::make_unique<Dynarmic::A32::Jit>(config); diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index d96226c41..7ff8f9495 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -81,6 +81,7 @@ public: } void InterpreterFallback(u64 pc, std::size_t num_instructions) override { + parent.LogBacktrace(); LOG_ERROR(Core_ARM, "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, num_instructions, MemoryReadCode(pc)); @@ -93,17 +94,19 @@ public: static constexpr u64 ICACHE_LINE_SIZE = 64; const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); - parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE); + parent.system.InvalidateCpuInstructionCacheRange(cache_line_start, ICACHE_LINE_SIZE); break; } case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: - parent.ClearInstructionCache(); + parent.system.InvalidateCpuInstructionCaches(); break; case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: default: LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op); break; } + + parent.jit->HaltExecution(); } void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { @@ -116,6 +119,7 @@ public: return; case Dynarmic::A64::Exception::Breakpoint: default: + parent.LogBacktrace(); ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); } @@ -246,35 +250,41 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* if (!Settings::values.cpuopt_recompile_exclusives) { config.recompile_on_exclusive_fastmem_failure = false; } - } + } else { + // Unsafe optimizations + if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { + config.unsafe_optimizations = true; + if (Settings::values.cpuopt_unsafe_unfuse_fma) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; + } + if (Settings::values.cpuopt_unsafe_reduce_fp_error) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; + } + if (Settings::values.cpuopt_unsafe_inaccurate_nan) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; + } + if (Settings::values.cpuopt_unsafe_fastmem_check) { + config.fastmem_address_space_bits = 64; + } + if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + } + } - // Unsafe optimizations - if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { - config.unsafe_optimizations = true; - if (Settings::values.cpuopt_unsafe_unfuse_fma) { + // Curated optimizations + if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { + config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; - } - if (Settings::values.cpuopt_unsafe_reduce_fp_error) { - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; - } - if (Settings::values.cpuopt_unsafe_inaccurate_nan) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; - } - if (Settings::values.cpuopt_unsafe_fastmem_check) { config.fastmem_address_space_bits = 64; - } - if (Settings::values.cpuopt_unsafe_ignore_global_monitor) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - } - // 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; - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + // Paranoia mode for debugging optimizations + if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) { + config.unsafe_optimizations = false; + config.optimizations = Dynarmic::no_optimizations; + } } return std::make_shared<Dynarmic::A64::Jit>(config); diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index b365ce7b7..63bbe02e9 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -28,7 +28,8 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr auto& page_table = m_owner->PageTable(); // Construct the page group. - m_page_group = KPageLinkedList(addr, Common::DivideUp(size, PageSize)); + m_page_group = + KPageLinkedList(page_table.GetPhysicalAddr(addr), Common::DivideUp(size, PageSize)); // Lock the memory. R_TRY(page_table.LockForCodeMemory(addr, size)) diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h index 0e2ae582a..869228322 100644 --- a/src/core/hle/kernel/k_page_linked_list.h +++ b/src/core/hle/kernel/k_page_linked_list.h @@ -89,6 +89,10 @@ public: return ResultSuccess; } + bool Empty() const { + return nodes.empty(); + } + private: std::list<Node> nodes; }; diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 02d93b12e..599013cf6 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -486,6 +486,58 @@ VAddr KPageTable::FindFreeArea(VAddr region_start, std::size_t region_num_pages, return address; } +ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages) { + ASSERT(this->IsLockedByCurrentThread()); + + const size_t size = num_pages * PageSize; + + // We're making a new group, not adding to an existing one. + R_UNLESS(pg.Empty(), ResultInvalidCurrentMemory); + + // Begin traversal. + Common::PageTable::TraversalContext context; + Common::PageTable::TraversalEntry next_entry; + R_UNLESS(page_table_impl.BeginTraversal(next_entry, context, addr), ResultInvalidCurrentMemory); + + // Prepare tracking variables. + PAddr cur_addr = next_entry.phys_addr; + size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1)); + size_t tot_size = cur_size; + + // Iterate, adding to group as we go. + const auto& memory_layout = system.Kernel().MemoryLayout(); + while (tot_size < size) { + R_UNLESS(page_table_impl.ContinueTraversal(next_entry, context), + ResultInvalidCurrentMemory); + + if (next_entry.phys_addr != (cur_addr + cur_size)) { + const size_t cur_pages = cur_size / PageSize; + + R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory); + R_TRY(pg.AddBlock(cur_addr, cur_pages)); + + cur_addr = next_entry.phys_addr; + cur_size = next_entry.block_size; + } else { + cur_size += next_entry.block_size; + } + + tot_size += next_entry.block_size; + } + + // Ensure we add the right amount for the last block. + if (tot_size > size) { + cur_size -= (tot_size - size); + } + + // Add the last block. + const size_t cur_pages = cur_size / PageSize; + R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory); + R_TRY(pg.AddBlock(cur_addr, cur_pages)); + + return ResultSuccess; +} + ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, VAddr src_addr) { KScopedLightLock lk(general_lock); @@ -1223,6 +1275,31 @@ ResultCode KPageTable::UnmapPages(VAddr address, std::size_t num_pages, KMemoryS return ResultSuccess; } +ResultCode KPageTable::MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr) { + // Ensure that the page group isn't null. + ASSERT(out != nullptr); + + // Make sure that the region we're mapping is valid for the table. + const size_t size = num_pages * PageSize; + R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory); + + // Lock the table. + KScopedLightLock lk(general_lock); + + // Check if state allows us to create the group. + R_TRY(this->CheckMemoryState(address, size, state_mask | KMemoryState::FlagReferenceCounted, + state | KMemoryState::FlagReferenceCounted, perm_mask, perm, + attr_mask, attr)); + + // Create a new page group for the region. + R_TRY(this->MakePageGroup(*out, address, num_pages)); + + return ResultSuccess; +} + ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission svc_perm) { const size_t num_pages = size / PageSize; @@ -1605,57 +1682,21 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) } ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { - KScopedLightLock lk(general_lock); - - KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite; - - KMemoryPermission old_perm{}; - - if (const ResultCode result{CheckMemoryState( - nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, - KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, - KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; - result.IsError()) { - return result; - } - - new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; - - block_manager->UpdateLock( - addr, size / PageSize, - [](KMemoryBlockManager::iterator block, KMemoryPermission permission) { - block->ShareToDevice(permission); - }, - new_perm); - - return ResultSuccess; + return this->LockMemoryAndOpen( + nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, + KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, KMemoryPermission::UserReadWrite, + KMemoryAttribute::All, KMemoryAttribute::None, + static_cast<KMemoryPermission>(KMemoryPermission::NotMapped | + KMemoryPermission::KernelReadWrite), + KMemoryAttribute::Locked); } ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { - KScopedLightLock lk(general_lock); - - KMemoryPermission new_perm = KMemoryPermission::UserReadWrite; - - KMemoryPermission old_perm{}; - - if (const ResultCode result{CheckMemoryState( - nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, - KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::All, KMemoryAttribute::Locked)}; - result.IsError()) { - return result; - } - - new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; - - block_manager->UpdateLock( - addr, size / PageSize, - [](KMemoryBlockManager::iterator block, KMemoryPermission permission) { - block->UnshareToDevice(permission); - }, - new_perm); - - return ResultSuccess; + return this->UnlockMemory(addr, size, KMemoryState::FlagCanCodeMemory, + KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::All, + KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, + KMemoryAttribute::Locked, nullptr); } ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { @@ -1991,4 +2032,109 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi return ResultSuccess; } +ResultCode KPageTable::LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_paddr, VAddr addr, + size_t size, KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryPermission new_perm, KMemoryAttribute lock_attr) { + // Validate basic preconditions. + ASSERT((lock_attr & attr) == KMemoryAttribute::None); + ASSERT((lock_attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) == + KMemoryAttribute::None); + + // Validate the lock request. + const size_t num_pages = size / PageSize; + R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory); + + // Lock the table. + KScopedLightLock lk(general_lock); + + // Check that the output page group is empty, if it exists. + if (out_pg) { + ASSERT(out_pg->GetNumPages() == 0); + } + + // Check the state. + KMemoryState old_state{}; + KMemoryPermission old_perm{}; + KMemoryAttribute old_attr{}; + size_t num_allocator_blocks{}; + R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), + std::addressof(old_attr), std::addressof(num_allocator_blocks), + addr, size, state_mask | KMemoryState::FlagReferenceCounted, + state | KMemoryState::FlagReferenceCounted, perm_mask, perm, + attr_mask, attr)); + + // Get the physical address, if we're supposed to. + if (out_paddr != nullptr) { + ASSERT(this->GetPhysicalAddressLocked(out_paddr, addr)); + } + + // Make the page group, if we're supposed to. + if (out_pg != nullptr) { + R_TRY(this->MakePageGroup(*out_pg, addr, num_pages)); + } + + // Decide on new perm and attr. + new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; + KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr | lock_attr); + + // Update permission, if we need to. + if (new_perm != old_perm) { + R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions)); + } + + // Apply the memory block updates. + block_manager->Update(addr, num_pages, old_state, new_perm, new_attr); + + return ResultSuccess; +} + +ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, KMemoryAttribute attr_mask, + KMemoryAttribute attr, KMemoryPermission new_perm, + KMemoryAttribute lock_attr, const KPageLinkedList* pg) { + // Validate basic preconditions. + ASSERT((attr_mask & lock_attr) == lock_attr); + ASSERT((attr & lock_attr) == lock_attr); + + // Validate the unlock request. + const size_t num_pages = size / PageSize; + R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory); + + // Lock the table. + KScopedLightLock lk(general_lock); + + // Check the state. + KMemoryState old_state{}; + KMemoryPermission old_perm{}; + KMemoryAttribute old_attr{}; + size_t num_allocator_blocks{}; + R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), + std::addressof(old_attr), std::addressof(num_allocator_blocks), + addr, size, state_mask | KMemoryState::FlagReferenceCounted, + state | KMemoryState::FlagReferenceCounted, perm_mask, perm, + attr_mask, attr)); + + // Check the page group. + if (pg != nullptr) { + UNIMPLEMENTED_MSG("PageGroup support is unimplemented!"); + } + + // Decide on new perm and attr. + new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; + KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr & ~lock_attr); + + // Update permission, if we need to. + if (new_perm != old_perm) { + R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions)); + } + + // Apply the memory block updates. + block_manager->Update(addr, num_pages, old_state, new_perm, new_attr); + + return ResultSuccess; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 54c6adf8d..bfabdf38c 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -12,6 +12,7 @@ #include "core/file_sys/program_metadata.h" #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_memory_block.h" +#include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/result.h" @@ -71,6 +72,10 @@ public: ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); ResultCode LockForCodeMemory(VAddr addr, std::size_t size); ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size); + ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr); Common::PageTable& PageTableImpl() { return page_table_impl; @@ -159,10 +164,37 @@ private: attr_mask, attr, ignore_attr); } + ResultCode LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_paddr, VAddr addr, size_t size, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryPermission new_perm, KMemoryAttribute lock_attr); + ResultCode UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryPermission new_perm, KMemoryAttribute lock_attr, + const KPageLinkedList* pg); + + ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages); + bool IsLockedByCurrentThread() const { return general_lock.IsLockedByCurrentThread(); } + bool IsHeapPhysicalAddress(const KMemoryLayout& layout, PAddr phys_addr) { + ASSERT(this->IsLockedByCurrentThread()); + + return layout.IsHeapPhysicalAddress(cached_physical_heap_region, phys_addr); + } + + bool GetPhysicalAddressLocked(PAddr* out, VAddr virt_addr) const { + ASSERT(this->IsLockedByCurrentThread()); + + *out = GetPhysicalAddr(virt_addr); + + return *out != 0; + } + mutable KLightLock general_lock; mutable KLightLock map_physical_memory_lock; @@ -322,6 +354,7 @@ private: bool is_aslr_enabled{}; u32 heap_fill_value{}; + const KMemoryRegion* cached_physical_heap_region{}; KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; KMemoryManager::Direction allocation_option{KMemoryManager::Direction::FromFront}; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 839171e85..976d63234 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1362,8 +1362,11 @@ static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Hand ResultInvalidMemoryRegion); // Create a new page group. - KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address); - KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); + KPageLinkedList pg; + R_TRY(src_pt.MakeAndOpenPageGroup( + std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess, + KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::All, KMemoryAttribute::None)); // Map the group. R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode, @@ -1408,8 +1411,8 @@ static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Ha } static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) { - LOG_TRACE(Kernel_SVC, "called, handle_out={}, address=0x{:X}, size=0x{:X}", - static_cast<void*>(out), address, size); + LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size); + // Get kernel instance. auto& kernel = system.Kernel(); @@ -1664,7 +1667,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha return ResultInvalidAddress; } - if (size == 0 || Common::Is4KBAligned(size)) { + if (size == 0 || !Common::Is4KBAligned(size)) { LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size); return ResultInvalidSize; } diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index bb5cb61be..a4b3fb187 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -446,6 +446,14 @@ void WebBrowser::ExecuteLogin() { } void WebBrowser::ExecuteOffline() { + // TODO (Morph): This is a hack for WebSession foreground web applets such as those used by + // Super Mario 3D All-Stars. + // TODO (Morph): Implement WebSession. + if (applet_mode == LibraryAppletMode::AllForegroundInitiallyHidden) { + LOG_WARNING(Service_AM, "WebSession is not implemented"); + return; + } + const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document)); if (!Common::FS::Exists(main_url)) { diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 3703ca4c6..4208337db 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -174,7 +174,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found."); ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(), - "Could not write all of the bytes but everything else has succeded."); + "Could not write all of the bytes but everything else has succeeded."); if (!src->GetContainingDirectory()->DeleteFile(Common::FS::GetFilename(src_path))) { // TODO(DarkLordZach): Find a better error code for this diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e5c951e06..aa6cb34b7 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -262,11 +262,6 @@ void Controller_NPad::OnInit() { service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); } - if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) { - // We want to support all controllers - hid_core.SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); - } - supported_npad_id_types.resize(npad_id_list.size()); std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), npad_id_list.size() * sizeof(Core::HID::NpadIdType)); @@ -288,14 +283,6 @@ void Controller_NPad::OnInit() { WriteEmptyEntry(npad); } } - - // Connect controllers - for (auto& controller : controller_data) { - const auto& device = controller.device; - if (device->IsConnected()) { - AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType()); - } - } } void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { @@ -320,6 +307,7 @@ void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { } void Controller_NPad::OnRelease() { + is_controller_initialized = false; for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; service_context.CloseEvent(controller.styleset_changed_event); @@ -651,9 +639,27 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { hid_core.SetSupportedStyleTag(style_set); + + if (is_controller_initialized) { + return; + } + + // Once SetSupportedStyleSet is called controllers are fully initialized + is_controller_initialized = true; + + // Connect all active controllers + for (auto& controller : controller_data) { + const auto& device = controller.device; + if (device->IsConnected()) { + AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType()); + } + } } Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { + if (!is_controller_initialized) { + return {Core::HID::NpadStyleSet::None}; + } return hid_core.GetSupportedStyleTag(); } diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 3287cf435..967379f05 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -191,16 +191,16 @@ private: // This is nn::hid::detail::NpadFullKeyColorState struct NpadFullKeyColorState { - ColorAttribute attribute; - Core::HID::NpadControllerColor fullkey; + ColorAttribute attribute{ColorAttribute::NoController}; + Core::HID::NpadControllerColor fullkey{}; }; static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); // This is nn::hid::detail::NpadJoyColorState struct NpadJoyColorState { - ColorAttribute attribute; - Core::HID::NpadControllerColor left; - Core::HID::NpadControllerColor right; + ColorAttribute attribute{ColorAttribute::NoController}; + Core::HID::NpadControllerColor left{}; + Core::HID::NpadControllerColor right{}; }; static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); @@ -226,11 +226,11 @@ private: // This is nn::hid::NpadPalmaState // This is nn::hid::NpadSystemExtState struct NPadGenericState { - s64_le sampling_number; - Core::HID::NpadButtonState npad_buttons; - Core::HID::AnalogStickState l_stick; - Core::HID::AnalogStickState r_stick; - NpadAttribute connection_status; + s64_le sampling_number{}; + Core::HID::NpadButtonState npad_buttons{}; + Core::HID::AnalogStickState l_stick{}; + Core::HID::AnalogStickState r_stick{}; + NpadAttribute connection_status{}; INSERT_PADDING_BYTES(4); // Reserved }; static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); @@ -253,7 +253,7 @@ private: Common::Vec3f gyro{}; Common::Vec3f rotation{}; std::array<Common::Vec3f, 3> orientation{}; - SixAxisSensorAttribute attribute; + SixAxisSensorAttribute attribute{}; INSERT_PADDING_BYTES(4); // Reserved }; static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size"); @@ -325,11 +325,11 @@ private: // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl struct NfcXcdDeviceHandleStateImpl { - u64 handle; - bool is_available; - bool is_activated; + u64 handle{}; + bool is_available{}; + bool is_activated{}; INSERT_PADDING_BYTES(0x6); // Reserved - u64 sampling_number; + u64 sampling_number{}; }; static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, "NfcXcdDeviceHandleStateImpl is an invalid size"); @@ -366,8 +366,8 @@ private: }; struct AppletFooterUi { - AppletFooterUiAttributes attributes; - AppletFooterUiType type; + AppletFooterUiAttributes attributes{}; + AppletFooterUiType type{AppletFooterUiType::None}; INSERT_PADDING_BYTES(0x5B); // Reserved }; static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size"); @@ -404,41 +404,41 @@ private: // This is nn::hid::detail::NpadInternalState struct NpadInternalState { - Core::HID::NpadStyleTag style_tag; - NpadJoyAssignmentMode assignment_mode; - NpadFullKeyColorState fullkey_color; - NpadJoyColorState joycon_color; - Lifo<NPadGenericState, hid_entry_count> fullkey_lifo; - Lifo<NPadGenericState, hid_entry_count> handheld_lifo; - Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo; - Lifo<NPadGenericState, hid_entry_count> joy_left_lifo; - Lifo<NPadGenericState, hid_entry_count> joy_right_lifo; - Lifo<NPadGenericState, hid_entry_count> palma_lifo; - Lifo<NPadGenericState, hid_entry_count> system_ext_lifo; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_right_lifo; - DeviceType device_type; + Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; + NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual}; + NpadFullKeyColorState fullkey_color{}; + NpadJoyColorState joycon_color{}; + Lifo<NPadGenericState, hid_entry_count> fullkey_lifo{}; + Lifo<NPadGenericState, hid_entry_count> handheld_lifo{}; + Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo{}; + Lifo<NPadGenericState, hid_entry_count> joy_left_lifo{}; + Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{}; + Lifo<NPadGenericState, hid_entry_count> palma_lifo{}; + Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{}; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{}; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{}; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{}; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{}; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{}; + Lifo<SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{}; + DeviceType device_type{}; INSERT_PADDING_BYTES(0x4); // Reserved - NPadSystemProperties system_properties; - NpadSystemButtonProperties button_properties; - Core::HID::NpadBatteryLevel battery_level_dual; - Core::HID::NpadBatteryLevel battery_level_left; - Core::HID::NpadBatteryLevel battery_level_right; + NPadSystemProperties system_properties{}; + NpadSystemButtonProperties button_properties{}; + Core::HID::NpadBatteryLevel battery_level_dual{}; + Core::HID::NpadBatteryLevel battery_level_left{}; + Core::HID::NpadBatteryLevel battery_level_right{}; union { - Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo{}; - AppletFooterUi applet_footer; + AppletFooterUi applet_footer{}; + Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo; }; INSERT_PADDING_BYTES(0x20); // Unknown - Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo; - NpadLarkType lark_type_l_and_main; - NpadLarkType lark_type_r; - NpadLuciaType lucia_type; - NpadLagonType lagon_type; - NpadLagerType lager_type; + Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{}; + NpadLarkType lark_type_l_and_main{}; + NpadLarkType lark_type_r{}; + NpadLuciaType lucia_type{}; + NpadLagonType lagon_type{}; + NpadLagerType lager_type{}; // FW 13.x Investigate there is some sort of bitflag related to joycons INSERT_PADDING_BYTES(0x4); INSERT_PADDING_BYTES(0xc08); // Unknown @@ -511,7 +511,8 @@ private: NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; bool permit_vibration_session_enabled{false}; - bool analog_stick_use_center_clamp{}; + bool analog_stick_use_center_clamp{false}; bool is_in_lr_assignment_mode{false}; + bool is_controller_initialized{false}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index d9202ea6c..92e6bf889 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -63,10 +63,6 @@ IAppletResource::IAppletResource(Core::System& system_, MakeController<Controller_Gesture>(HidController::Gesture); MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor); - // Homebrew doesn't try to activate some controllers, so we activate them by default - GetController<Controller_NPad>(HidController::NPad).ActivateController(); - GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); - GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00); GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00); GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000); @@ -878,6 +874,10 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); + // Games expect this event to be signaled after calling this function + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SignalStyleSetChangedEvent(parameters.npad_id); + IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index f9b82b504..44c54c665 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -134,7 +134,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector } EventState status = events_interface.status[event_id]; - const bool bad_parameter = status != EventState::Free && status != EventState::Registered; + const bool bad_parameter = status == EventState::Busy; if (bad_parameter) { std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::BadParameter; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index c16babe14..1ce2a856b 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -26,7 +26,7 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) { rb.Push<DeviceFD>(0); rb.PushEnum(NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + LOG_ERROR(Service_NVDRV, "NvServices is not initialized!"); return; } @@ -61,7 +61,7 @@ void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) { if (!is_initialized) { ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + LOG_ERROR(Service_NVDRV, "NvServices is not initialized!"); return; } @@ -87,7 +87,7 @@ void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { if (!is_initialized) { ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + LOG_ERROR(Service_NVDRV, "NvServices is not initialized!"); return; } @@ -114,7 +114,7 @@ void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { if (!is_initialized) { ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + LOG_ERROR(Service_NVDRV, "NvServices is not initialized!"); return; } @@ -139,7 +139,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) { if (!is_initialized) { ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + LOG_ERROR(Service_NVDRV, "NvServices is not initialized!"); return; } @@ -170,7 +170,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { if (!is_initialized) { ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + LOG_ERROR(Service_NVDRV, "NvServices is not initialized!"); return; } diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp index 57b4f0eee..60732215b 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp @@ -132,7 +132,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) { multisample = v.X(meta_reg++); } if (tld.clamp != 0) { - throw NotImplementedException("TLD.CL - CLAMP is not implmented"); + throw NotImplementedException("TLD.CL - CLAMP is not implemented"); } IR::TextureInstInfo info{}; info.type.Assign(GetType(tld.type)); diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp index 311a9e763..f89ce1b68 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp @@ -81,7 +81,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) { } const tmml{insn}; if ((tmml.mask & 0b1100) != 0) { - throw NotImplementedException("TMML BA results are not implmented"); + throw NotImplementedException("TMML BA results are not implemented"); } const IR::Value coords{MakeCoords(v, tmml.coord_reg, tmml.type)}; diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 81fac94bf..40f7755e8 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -56,6 +56,18 @@ AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pi av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT; return PREFERRED_CPU_FMT; } + +// List all the currently available hwcontext in ffmpeg +std::vector<AVHWDeviceType> ListSupportedContexts() { + std::vector<AVHWDeviceType> contexts{}; + AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; + do { + current_device_type = av_hwdevice_iterate_types(current_device_type); + contexts.push_back(current_device_type); + } while (current_device_type != AV_HWDEVICE_TYPE_NONE); + return contexts; +} + } // namespace void AVFrameDeleter(AVFrame* ptr) { @@ -76,17 +88,6 @@ Codec::~Codec() { av_buffer_unref(&av_gpu_decoder); } -// List all the currently available hwcontext in ffmpeg -static std::vector<AVHWDeviceType> ListSupportedContexts() { - std::vector<AVHWDeviceType> contexts{}; - AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; - do { - current_device_type = av_hwdevice_iterate_types(current_device_type); - contexts.push_back(current_device_type); - } while (current_device_type != AV_HWDEVICE_TYPE_NONE); - return contexts; -} - bool Codec::CreateGpuAvDevice() { static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX; static const auto supported_contexts = ListSupportedContexts(); @@ -96,6 +97,8 @@ bool Codec::CreateGpuAvDevice() { LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); continue; } + // Avoid memory leak from not cleaning up after av_hwdevice_ctx_create + av_buffer_unref(&av_gpu_decoder); const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0); if (hwdevice_res < 0) { LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}", @@ -127,15 +130,19 @@ bool Codec::CreateGpuAvDevice() { av_codec->name, av_hwdevice_get_type_name(type)); break; } - if (config->methods & HW_CONFIG_METHOD && config->device_type == type) { - av_codec_ctx->pix_fmt = config->pix_fmt; - if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) { + if ((config->methods & HW_CONFIG_METHOD) != 0 && config->device_type == type) { +#if defined(__unix__) + // Some linux decoding backends are reported to crash with this config method + // TODO(ameerj): Properly support this method + if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) != 0) { // skip zero-copy decoders, we don't currently support them LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.", av_hwdevice_get_type_name(type), config->methods); continue; } +#endif LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); + av_codec_ctx->pix_fmt = config->pix_fmt; return true; } } diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 656dd7eb0..597301eeb 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -282,7 +282,7 @@ void main() { u64 Device::GetCurrentDedicatedVideoMemory() const { GLint cur_avail_mem_kb = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &cur_avail_mem_kb); + glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &cur_avail_mem_kb); return static_cast<u64>(cur_avail_mem_kb) * 1_KiB; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 4d632d211..e6f9ece8b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -15,8 +15,9 @@ #include "common/logging/log.h" #include "common/math_util.h" #include "common/microprofile.h" +#include "common/scope_exit.h" #include "common/settings.h" -#include "core/memory.h" + #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -210,6 +211,7 @@ void RasterizerOpenGL::Clear() { void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { MICROPROFILE_SCOPE(OpenGL_Drawing); + SCOPE_EXIT({ gpu.TickWork(); }); query_cache.UpdateCounters(); GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; @@ -265,8 +267,6 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { ++num_queued_commands; has_written_global_memory |= pipeline->WritesGlobalMemory(); - - gpu.TickWork(); } void RasterizerOpenGL::DispatchCompute() { diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index ec03cca38..abda1c490 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -367,17 +367,14 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, PipelineLayoutCreateInfo(two_textures_set_layout.address()))), full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), + blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)), linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)), - nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) { - if (device.IsExtShaderStencilExportSupported()) { - blit_depth_stencil_frag = BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV); - } -} + nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {} BlitImageHelper::~BlitImageHelper() = default; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f2890d263..2c2ccc7c6 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1451,8 +1451,7 @@ bool Image::BlitScaleHelper(bool scale_up) { runtime->blit_image_helper.BlitColor(blit_framebuffer.get(), color_view, dst_region, src_region, operation, BLIT_OPERATION); - } else if (!runtime->device.IsBlitDepthStencilSupported() && - aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (!blit_framebuffer) { blit_framebuffer = std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent); } diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index efc1c4525..8fef74117 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1080,8 +1080,6 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA Image& overlap = slot_images[overlap_id]; if (True(overlap.flags & ImageFlagBits::GpuModified)) { new_image.flags |= ImageFlagBits::GpuModified; - new_image.modification_tick = - std::max(overlap.modification_tick, new_image.modification_tick); } if (overlap.info.num_samples != new_image.info.num_samples) { LOG_WARNING(HW_GPU, "Copying between images with different samples is not implemented"); diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index e142bee35..f3a05ada9 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -621,6 +621,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR khr_push_descriptor = false; break; } + const u32 nv_major_version = (properties.driverVersion >> 22) & 0x3ff; + if (nv_major_version >= 510) { + LOG_WARNING(Render_Vulkan, "NVIDIA Drivers >= 510 do not support MSAA image blits"); + cant_blit_msaa = true; + } } const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV; if (ext_extended_dynamic_state && is_radv) { @@ -731,7 +736,7 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags } void Device::ReportLoss() const { - LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); + LOG_CRITICAL(Render_Vulkan, "Device loss occurred!"); // Wait for the log to flush and for Nsight Aftermath to dump the results std::this_thread::sleep_for(std::chrono::seconds{15}); diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 30902101d..b1467d016 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -293,7 +293,7 @@ if (YUZU_USE_QT_WEB_ENGINE) endif () if(UNIX AND NOT APPLE) - install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") + install(TARGETS yuzu) endif() if (YUZU_USE_BUNDLED_QT) diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui index 5d80a8c91..8ae569ee6 100644 --- a/src/yuzu/configuration/configure_cpu.ui +++ b/src/yuzu/configuration/configure_cpu.ui @@ -52,6 +52,11 @@ <string>Unsafe</string> </property> </item> + <item> + <property name="text"> + <string>Paranoid (disables most optimizations)</string> + </property> + </item> </widget> </item> </layout> diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index edb525e82..c1d90d588 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -214,14 +214,14 @@ <item row="1" column="1"> <widget class="QCheckBox" name="enable_all_controllers"> <property name="text"> - <string>Enable all Controller Types</string> + <string>Enable All Controller Types</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QCheckBox" name="disable_web_applet"> <property name="text"> - <string>Disable Web Applet**</string> + <string>Disable Web Applet</string> </property> </widget> </item> diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 53e629a5e..6679e9c53 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -35,8 +35,9 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent ui->hotkey_list->setContextMenuPolicy(Qt::CustomContextMenu); ui->hotkey_list->setModel(model); - ui->hotkey_list->setColumnWidth(name_column, 200); - ui->hotkey_list->resizeColumnToContents(hotkey_column); + ui->hotkey_list->header()->setStretchLastSection(false); + ui->hotkey_list->header()->setSectionResizeMode(name_column, QHeaderView::ResizeMode::Stretch); + ui->hotkey_list->header()->setMinimumSectionSize(150); connect(ui->button_restore_defaults, &QPushButton::clicked, this, &ConfigureHotkeys::RestoreDefaults); @@ -76,8 +77,8 @@ void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { } ui->hotkey_list->expandAll(); - ui->hotkey_list->resizeColumnToContents(name_column); ui->hotkey_list->resizeColumnToContents(hotkey_column); + ui->hotkey_list->resizeColumnToContents(controller_column); } void ConfigureHotkeys::changeEvent(QEvent* event) { diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 21e51d749..7893a85bb 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -47,6 +47,10 @@ ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* p item_model->setHeaderData(0, Qt::Horizontal, tr("Patch Name")); item_model->setHeaderData(1, Qt::Horizontal, tr("Version")); + tree_view->header()->setStretchLastSection(false); + tree_view->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch); + tree_view->header()->setMinimumSectionSize(150); + // We must register all custom types with the Qt Automoc system so that we are able to use it // with signals/slots. In this case, QList falls under the umbrella of custom types. qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>"); @@ -138,5 +142,5 @@ void ConfigurePerGameAddons::LoadConfiguration() { item_model->appendRow(list_items.back()); } - tree_view->setColumnWidth(0, 5 * tree_view->width() / 16); + tree_view->resizeColumnToContents(1); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 3b7058a2b..62d15f8cd 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -293,8 +293,6 @@ GMainWindow::GMainWindow() MigrateConfigFiles(); - ui->action_Fullscreen->setChecked(false); - #if defined(HAVE_SDL2) && !defined(_WIN32) SDL_InitSubSystem(SDL_INIT_VIDEO); // SDL disables the screen saver by default, and setting the hint @@ -312,17 +310,20 @@ GMainWindow::GMainWindow() } QString game_path; + bool has_gamepath = false; + bool is_fullscreen = false; for (int i = 1; i < args.size(); ++i) { // Preserves drag/drop functionality if (args.size() == 2 && !args[1].startsWith(QChar::fromLatin1('-'))) { game_path = args[1]; + has_gamepath = true; break; } // Launch game in fullscreen mode if (args[i] == QStringLiteral("-f")) { - ui->action_Fullscreen->setChecked(true); + is_fullscreen = true; continue; } @@ -365,9 +366,15 @@ GMainWindow::GMainWindow() } game_path = args[++i]; + has_gamepath = true; } } + // Override fullscreen setting if gamepath or argument is provided + if (has_gamepath || is_fullscreen) { + ui->action_Fullscreen->setChecked(is_fullscreen); + } + if (!game_path.isEmpty()) { BootGame(game_path); } diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 74fc24972..c8901f2df 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -45,7 +45,7 @@ if (YUZU_USE_EXTERNAL_SDL2) endif() if(UNIX AND NOT APPLE) - install(TARGETS yuzu-cmd RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") + install(TARGETS yuzu-cmd) endif() if (MSVC) diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 34782c378..f34d6b728 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -342,12 +342,6 @@ fps_cap = # null: No audio output output_engine = -# Whether or not to enable the audio-stretching post-processing effect. -# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter, -# at the cost of increasing audio latency. -# 0: No, 1 (default): Yes -enable_audio_stretching = - # Which audio device to use. # auto (default): Auto-select output_device = diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 14bf82f39..ab12dd15d 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -74,6 +74,7 @@ static void PrintVersion() { int main(int argc, char** argv) { Common::Log::Initialize(); Common::Log::SetColorConsoleBackendEnabled(true); + Common::Log::Start(); Common::DetachedTasks detached_tasks; int option_index = 0; |