From 8775571f5d9765cbc86f2af0af940b30ef630c02 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Tue, 29 Mar 2022 22:45:29 +0200 Subject: [PATCH] early-access version 2620 --- README.md | 2 +- dist/yuzu.ico | Bin 23159 -> 25355 bytes dist/yuzu.svg | 2 +- src/common/atomic_ops.h | 17 ++ src/common/settings.h | 3 + src/common/settings_input.h | 1 + src/common/x64/native_clock.cpp | 4 +- src/core/CMakeLists.txt | 10 + src/core/hid/emulated_devices.cpp | 45 ++++ src/core/hid/emulated_devices.h | 34 +++ src/core/hle/kernel/k_code_memory.cpp | 3 +- src/core/hle/kernel/k_page_linked_list.h | 4 + src/core/hle/kernel/k_page_table.cpp | 242 ++++++++++++++---- src/core/hle/kernel/k_page_table.h | 33 +++ src/core/hle/kernel/kernel.cpp | 18 ++ src/core/hle/kernel/kernel.h | 6 + src/core/hle/kernel/svc.cpp | 13 +- src/core/hle/service/hid/hid.cpp | 27 +- .../hle/service/nvdrv/devices/nvhost_ctrl.cpp | 2 +- .../command_classes/codecs/codec.cpp | 35 ++- src/video_core/memory_manager.cpp | 25 +- src/video_core/memory_manager.h | 1 + src/video_core/renderer_vulkan/blit_image.cpp | 7 +- .../renderer_vulkan/vk_texture_cache.cpp | 3 +- .../vulkan_common/vulkan_device.cpp | 5 + src/yuzu/CMakeLists.txt | 3 + src/yuzu/configuration/config.cpp | 34 +++ src/yuzu/configuration/config.h | 3 + src/yuzu/configuration/configure_input.cpp | 5 + .../configure_input_advanced.cpp | 9 +- .../configuration/configure_input_advanced.h | 1 + .../configuration/configure_input_advanced.ui | 14 + .../configuration/configure_input_player.cpp | 2 +- src/yuzu/discord_impl.cpp | 2 +- 34 files changed, 497 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 4d79655be..685904b23 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2618. +This is the source code for early-access 2620. ## Legal Notice diff --git a/dist/yuzu.ico b/dist/yuzu.ico index df3be8464fcb3c0fb10308472ed527dbcdc10d61..7c998a5c53a3b079b67c526586c269f2efd25447 100755 GIT binary patch literal 25355 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 s8oRK@Tvf05pF literal 23159 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 diff --git a/dist/yuzu.svg b/dist/yuzu.svg index 93171d1bf..98ded2d8f 100755 --- a/dist/yuzu.svg +++ b/dist/yuzu.svg @@ -1 +1 @@ -Artboard 1 \ No newline at end of file +newAsset 7 \ No newline at end of file diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h index b94d73c7a..b963e7b99 100755 --- a/src/common/atomic_ops.h +++ b/src/common/atomic_ops.h @@ -46,6 +46,13 @@ namespace Common { reinterpret_cast<__int64*>(expected.data())) != 0; } +[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) { + u128 result{}; + _InterlockedCompareExchange128(reinterpret_cast(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 +79,16 @@ namespace Common { return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_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..3de4ba1a7 100755 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -589,6 +589,9 @@ struct Values { BasicSetting touch_from_button_map_index{0, "touch_from_button_map"}; std::vector touch_from_button_maps; + BasicSetting enable_ring_controller{true, "enable_ring_controller"}; + RingconRaw ringcon_analogs; + // Data Storage BasicSetting use_virtual_sd{true, "use_virtual_sd"}; BasicSetting gamecard_inserted{false, "gamecard_inserted"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 4ff37e186..6f42346bc 100755 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -357,6 +357,7 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods; using AnalogsRaw = std::array; using ButtonsRaw = std::array; using MotionsRaw = std::array; +using RingconRaw = std::string; constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 347e41efc..2a2664e5d 100755 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -56,7 +56,7 @@ u64 NativeClock::GetRTSC() { TimePoint new_time_point{}; TimePoint current_time_point{}; do { - current_time_point.pack = time_point.pack; + current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); _mm_mfence(); const u64 current_measure = __rdtsc(); u64 diff = current_measure - current_time_point.inner.last_measure; @@ -76,7 +76,7 @@ void NativeClock::Pause(bool is_paused) { TimePoint current_time_point{}; TimePoint new_time_point{}; do { - current_time_point.pack = time_point.pack; + current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); new_time_point.pack = current_time_point.pack; _mm_mfence(); new_time_point.inner.last_measure = __rdtsc(); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6536d0544..6fc10637c 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -432,6 +432,8 @@ add_library(core STATIC hle/service/grc/grc.h hle/service/hid/hid.cpp hle/service/hid/hid.h + hle/service/hid/hidbus.cpp + hle/service/hid/hidbus.h hle/service/hid/irs.cpp hle/service/hid/irs.h hle/service/hid/ring_lifo.h @@ -458,6 +460,14 @@ add_library(core STATIC hle/service/hid/controllers/touchscreen.h hle/service/hid/controllers/xpad.cpp hle/service/hid/controllers/xpad.h + hle/service/hid/hidbus/hidbus_base.cpp + hle/service/hid/hidbus/hidbus_base.h + hle/service/hid/hidbus/ringcon.cpp + hle/service/hid/hidbus/ringcon.h + hle/service/hid/hidbus/starlink.cpp + hle/service/hid/hidbus/starlink.h + hle/service/hid/hidbus/stubbed.cpp + hle/service/hid/hidbus/stubbed.h hle/service/lbl/lbl.cpp hle/service/lbl/lbl.h hle/service/ldn/errors.h diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 708480f2d..6de447361 100755 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -15,6 +15,7 @@ EmulatedDevices::EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default; void EmulatedDevices::ReloadFromSettings() { + ring_params = Common::ParamPackage(Settings::values.ringcon_analogs); ReloadInput(); } @@ -66,6 +67,8 @@ void EmulatedDevices::ReloadInput() { key_index++; } + ring_analog_device = Common::Input::CreateDevice(ring_params); + for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { continue; @@ -120,6 +123,13 @@ void EmulatedDevices::ReloadInput() { }, }); } + + if (ring_analog_device) { + ring_analog_device->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); }, + }); + } } void EmulatedDevices::UnloadInput() { @@ -155,6 +165,7 @@ void EmulatedDevices::SaveCurrentConfig() { if (!is_configuring) { return; } + Settings::values.ringcon_analogs = ring_params.Serialize(); } void EmulatedDevices::RestoreConfig() { @@ -164,6 +175,15 @@ void EmulatedDevices::RestoreConfig() { ReloadFromSettings(); } +Common::ParamPackage EmulatedDevices::GetRingParam() const { + return ring_params; +} + +void EmulatedDevices::SetRingParam(Common::ParamPackage param) { + ring_params = std::move(param); + ReloadInput(); +} + void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { @@ -400,6 +420,23 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac TriggerOnChange(DeviceTriggerType::Mouse); } +void EmulatedDevices::SetRingAnalog(const Common::Input::CallbackStatus& callback) { + std::lock_guard lock{mutex}; + const auto force_value = TransformToStick(callback); + + device_status.ring_analog_value = force_value.x; + + if (is_configuring) { + device_status.ring_analog_value = {}; + TriggerOnChange(DeviceTriggerType::RingController); + return; + } + + device_status.ring_analog_state.force = force_value.x.value; + + TriggerOnChange(DeviceTriggerType::RingController); +} + KeyboardValues EmulatedDevices::GetKeyboardValues() const { return device_status.keyboard_values; } @@ -412,6 +449,10 @@ MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { return device_status.mouse_button_values; } +RingAnalogValue EmulatedDevices::GetRingSensorValues() const { + return device_status.ring_analog_value; +} + KeyboardKey EmulatedDevices::GetKeyboard() const { return device_status.keyboard_state; } @@ -432,6 +473,10 @@ AnalogStickState EmulatedDevices::GetMouseWheel() const { return device_status.mouse_wheel_state; } +RingSensorForce EmulatedDevices::GetRingSensorForce() const { + return device_status.ring_analog_state; +} + void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { for (const auto& poller_pair : callback_list) { const InterfaceUpdateCallback& poller = poller_pair.second; diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 790d3b411..9f739028d 100755 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -26,9 +26,11 @@ using MouseButtonDevices = std::array, Settings::NativeMouseWheel::NumMouseWheels>; using MouseStickDevice = std::unique_ptr; +using RingAnalogDevice = std::unique_ptr; using MouseButtonParams = std::array; +using RingAnalogParams = Common::ParamPackage; using KeyboardValues = std::array; @@ -39,12 +41,17 @@ using MouseButtonValues = using MouseAnalogValues = std::array; using MouseStickValue = Common::Input::TouchStatus; +using RingAnalogValue = Common::Input::AnalogStatus; struct MousePosition { f32 x; f32 y; }; +struct RingSensorForce { + f32 force; +}; + struct DeviceStatus { // Data from input_common KeyboardValues keyboard_values{}; @@ -52,6 +59,7 @@ struct DeviceStatus { MouseButtonValues mouse_button_values{}; MouseAnalogValues mouse_analog_values{}; MouseStickValue mouse_stick_value{}; + RingAnalogValue ring_analog_value{}; // Data for HID serices KeyboardKey keyboard_state{}; @@ -59,12 +67,14 @@ struct DeviceStatus { MouseButton mouse_button_state{}; MousePosition mouse_position_state{}; AnalogStickState mouse_wheel_state{}; + RingSensorForce ring_analog_state{}; }; enum class DeviceTriggerType { Keyboard, KeyboardModdifier, Mouse, + RingController, }; struct InterfaceUpdateCallback { @@ -110,6 +120,15 @@ public: /// Reverts any mapped changes made that weren't saved void RestoreConfig(); + // Returns the current mapped ring device + Common::ParamPackage GetRingParam() const; + + /** + * Updates the current mapped ring device + * @param param ParamPackage with ring sensor data to be mapped + */ + void SetRingParam(Common::ParamPackage param); + /// Returns the latest status of button input from the keyboard with parameters KeyboardValues GetKeyboardValues() const; @@ -119,6 +138,9 @@ public: /// Returns the latest status of button input from the mouse with parameters MouseButtonValues GetMouseButtonsValues() const; + /// Returns the latest status of analog input from the ring sensor with parameters + RingAnalogValue GetRingSensorValues() const; + /// Returns the latest status of button input from the keyboard KeyboardKey GetKeyboard() const; @@ -134,6 +156,9 @@ public: /// Returns the latest mouse wheel change AnalogStickState GetMouseWheel() const; + /// Returns the latest ringcon force sensor value + RingSensorForce GetRingSensorForce() const; + /** * Adds a callback to the list of events * @param update_callback InterfaceUpdateCallback that will be triggered @@ -185,6 +210,12 @@ private: */ void SetMouseStick(const Common::Input::CallbackStatus& callback); + /** + * Updates the ring analog sensor status of the ring controller + * @param callback A CallbackStatus containing the force status + */ + void SetRingAnalog(const Common::Input::CallbackStatus& callback); + /** * Triggers a callback that something has changed on the device status * @param type Input type of the event to trigger @@ -193,11 +224,14 @@ private: bool is_configuring{false}; + RingAnalogParams ring_params; + KeyboardDevices keyboard_devices; KeyboardModifierDevices keyboard_modifier_devices; MouseButtonDevices mouse_button_devices; MouseAnalogDevices mouse_analog_devices; MouseStickDevice mouse_stick_device; + RingAnalogDevice ring_analog_device; mutable std::mutex mutex; std::unordered_map callback_list; diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index b365ce7b7..63bbe02e9 100755 --- 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 100755 --- 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 nodes; }; diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 02d93b12e..599013cf6 100755 --- 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::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(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(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 100755 --- 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/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 34da7c23b..df05f5ddb 100755 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -139,6 +139,7 @@ struct KernelCore::Impl { CleanupObject(font_shared_mem); CleanupObject(irs_shared_mem); CleanupObject(time_shared_mem); + CleanupObject(hidbus_shared_mem); CleanupObject(system_resource_limit); for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { @@ -621,16 +622,20 @@ struct KernelCore::Impl { constexpr std::size_t font_size{0x1100000}; constexpr std::size_t irs_size{0x8000}; constexpr std::size_t time_size{0x1000}; + constexpr std::size_t hidbus_size{0x1000}; const PAddr hid_phys_addr{system_pool.GetAddress()}; const PAddr font_phys_addr{system_pool.GetAddress() + hid_size}; const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size}; const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size}; + const PAddr hidbus_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size + + time_size}; hid_shared_mem = KSharedMemory::Create(system.Kernel()); font_shared_mem = KSharedMemory::Create(system.Kernel()); irs_shared_mem = KSharedMemory::Create(system.Kernel()); time_shared_mem = KSharedMemory::Create(system.Kernel()); + hidbus_shared_mem = KSharedMemory::Create(system.Kernel()); hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize}, @@ -648,6 +653,10 @@ struct KernelCore::Impl { {time_phys_addr, time_size / PageSize}, Svc::MemoryPermission::None, Svc::MemoryPermission::Read, time_phys_addr, time_size, "Time:SharedMemory"); + hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, + {hidbus_phys_addr, hidbus_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + hidbus_phys_addr, hidbus_size, "HidBus:SharedMemory"); } KClientPort* CreateNamedServicePort(std::string name) { @@ -734,6 +743,7 @@ struct KernelCore::Impl { Kernel::KSharedMemory* font_shared_mem{}; Kernel::KSharedMemory* irs_shared_mem{}; Kernel::KSharedMemory* time_shared_mem{}; + Kernel::KSharedMemory* hidbus_shared_mem{}; // Memory layout std::unique_ptr memory_layout; @@ -1024,6 +1034,14 @@ const Kernel::KSharedMemory& KernelCore::GetTimeSharedMem() const { return *impl->time_shared_mem; } +Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() { + return *impl->hidbus_shared_mem; +} + +const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const { + return *impl->hidbus_shared_mem; +} + void KernelCore::Suspend(bool in_suspention) { const bool should_suspend = exception_exited || in_suspention; { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4c68e96df..0757d74a7 100755 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -256,6 +256,12 @@ public: /// Gets the shared memory object for Time services. const Kernel::KSharedMemory& GetTimeSharedMem() const; + /// Gets the shared memory object for HIDBus services. + Kernel::KSharedMemory& GetHidBusSharedMem(); + + /// Gets the shared memory object for HIDBus services. + const Kernel::KSharedMemory& GetHidBusSharedMem() const; + /// Suspend/unsuspend the OS. void Suspend(bool in_suspention); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 839171e85..976d63234 100755 --- 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(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/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index d9202ea6c..8a2635ee4 100755 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid.h" +#include "core/hle/service/hid/hidbus.h" #include "core/hle/service/hid/irs.h" #include "core/hle/service/hid/xcd.h" #include "core/memory.h" @@ -2124,32 +2125,6 @@ public: } }; -class HidBus final : public ServiceFramework { -public: - explicit HidBus(Core::System& system_) : ServiceFramework{system_, "hidbus"} { - // clang-format off - static const FunctionInfo functions[] = { - {1, nullptr, "GetBusHandle"}, - {2, nullptr, "IsExternalDeviceConnected"}, - {3, nullptr, "Initialize"}, - {4, nullptr, "Finalize"}, - {5, nullptr, "EnableExternalDevice"}, - {6, nullptr, "GetExternalDeviceId"}, - {7, nullptr, "SendCommandAsync"}, - {8, nullptr, "GetSendCommandAsynceResult"}, - {9, nullptr, "SetEventForSendCommandAsycResult"}, - {10, nullptr, "GetSharedMemoryHandle"}, - {11, nullptr, "EnableJoyPollingReceiveMode"}, - {12, nullptr, "DisableJoyPollingReceiveMode"}, - {13, nullptr, "GetPollingData"}, - {14, nullptr, "SetStatusManagerType"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { std::make_shared(system)->InstallAsService(service_manager); std::make_shared(system)->InstallAsService(service_manager); 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 100755 --- 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& 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/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 81fac94bf..40f7755e8 100755 --- 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 ListSupportedContexts() { + std::vector 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 ListSupportedContexts() { - std::vector 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/memory_manager.cpp b/src/video_core/memory_manager.cpp index 722ebd9ad..d7011b3b4 100755 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -39,7 +39,22 @@ GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std return gpu_addr; } +void MemoryManager::UnmapSubmappedRanges(GPUVAddr gpu_addr, std::size_t size) { + const auto submapped_ranges = GetSubmappedRange(gpu_addr, size); + for (const auto& [map_addr, map_size] : submapped_ranges) { + // Flush and invalidate through the GPU interface, to be asynchronous if possible. + const std::optional cpu_vaddr = GpuToCpuAddress(map_addr); + if (!cpu_vaddr) { + continue; + } + rasterizer->UnmapMemory(*cpu_vaddr, map_size); + } +} + GPUVAddr MemoryManager::Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size) { + // Unmap any pre-existing rasterizer memory in this range + UnmapSubmappedRanges(gpu_addr, size); + const auto it = std::ranges::lower_bound(map_ranges, gpu_addr, {}, &MapRange::first); if (it != map_ranges.end() && it->first == gpu_addr) { it->second = size; @@ -70,16 +85,8 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) { } else { UNREACHABLE_MSG("Unmapping non-existent GPU address=0x{:x}", gpu_addr); } - const auto submapped_ranges = GetSubmappedRange(gpu_addr, size); - - for (const auto& [map_addr, map_size] : submapped_ranges) { - // Flush and invalidate through the GPU interface, to be asynchronous if possible. - const std::optional cpu_addr = GpuToCpuAddress(map_addr); - ASSERT(cpu_addr); - - rasterizer->UnmapMemory(*cpu_addr, map_size); - } + UnmapSubmappedRanges(gpu_addr, size); UpdateRange(gpu_addr, PageEntry::State::Unmapped, size); } diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 61bfe47c7..ebeea7a40 100755 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -149,6 +149,7 @@ private: [[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const; void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size); GPUVAddr UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size); + void UnmapSubmappedRanges(GPUVAddr gpu_addr, std::size_t size); [[nodiscard]] std::optional FindFreeRange(std::size_t size, std::size_t align, bool start_32bit_address = false) const; diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index ec03cca38..abda1c490 100755 --- 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)), - nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) { - if (device.IsExtShaderStencilExportSupported()) { - blit_depth_stencil_frag = BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV); - } -} + nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO)) {} 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 100755 --- 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(*runtime, nullptr, view_ptr, extent); } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index e142bee35..4a5de9ddf 100755 --- 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) { diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 30902101d..9eb377b57 100755 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -99,6 +99,9 @@ add_executable(yuzu configuration/configure_profile_manager.cpp configuration/configure_profile_manager.h configuration/configure_profile_manager.ui + configuration/configure_ringcon.cpp + configuration/configure_ringcon.h + configuration/configure_ringcon.ui configuration/configure_network.cpp configuration/configure_network.h configuration/configure_network.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index d2e735f48..ac26b885b 100755 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -60,6 +60,11 @@ const std::array Config::default_stick_mod = { 0, }; +const std::array Config::default_ringcon_analogs{{ + Qt::Key_A, + Qt::Key_D, +}}; + // This shouldn't have anything except static initializers (no functions). So // QKeySequence(...).toString() is NOT ALLOWED HERE. // This must be in alphabetical order according to action name as it must have the same order as @@ -346,6 +351,23 @@ void Config::ReadTouchscreenValues() { ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt(); } +void Config::ReadHidbusValues() { + Settings::values.enable_ring_controller = + ReadSetting(QStringLiteral("enable_ring_controller"), true).toBool(); + + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + auto& ringcon_analogs = Settings::values.ringcon_analogs; + + ringcon_analogs = + qt_config->value(QStringLiteral("ring_controller"), QString::fromStdString(default_param)) + .toString() + .toStdString(); + if (ringcon_analogs.empty()) { + ringcon_analogs = default_param; + } +} + void Config::ReadAudioValues() { qt_config->beginGroup(QStringLiteral("Audio")); @@ -369,6 +391,7 @@ void Config::ReadControlValues() { ReadMouseValues(); ReadTouchscreenValues(); ReadMotionTouchValues(); + ReadHidbusValues(); #ifdef _WIN32 ReadBasicSetting(Settings::values.enable_raw_input); @@ -962,6 +985,16 @@ void Config::SaveMotionTouchValues() { qt_config->endArray(); } +void Config::SaveHidbusValues() { + WriteBasicSetting(Settings::values.enable_ring_controller); + + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + WriteSetting(QStringLiteral("ring_controller"), + QString::fromStdString(Settings::values.ringcon_analogs), + QString::fromStdString(default_param)); +} + void Config::SaveValues() { if (global) { SaveControlValues(); @@ -1002,6 +1035,7 @@ void Config::SaveControlValues() { SaveMouseValues(); SaveTouchscreenValues(); SaveMotionTouchValues(); + SaveHidbusValues(); WriteGlobalSetting(Settings::values.use_docked_mode); WriteGlobalSetting(Settings::values.vibration_enabled); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index ae3e36a11..f0ab6bdaa 100755 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -42,6 +42,7 @@ public: static const std::array default_motions; static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; static const std::array default_stick_mod; + static const std::array default_ringcon_analogs; static const std::array default_mouse_buttons; static const std::array default_keyboard_keys; @@ -66,6 +67,7 @@ private: void ReadMouseValues(); void ReadTouchscreenValues(); void ReadMotionTouchValues(); + void ReadHidbusValues(); // Read functions bases off the respective config section names. void ReadAudioValues(); @@ -93,6 +95,7 @@ private: void SaveMouseValues(); void SaveTouchscreenValues(); void SaveMotionTouchValues(); + void SaveHidbusValues(); // Save functions based off the respective config section names. void SaveAudioValues(); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 4ca74a5f7..73d7ba24b 100755 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -20,6 +20,7 @@ #include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_motion_touch.h" +#include "yuzu/configuration/configure_ringcon.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" #include "yuzu/configuration/configure_vibration.h" #include "yuzu/configuration/input_profiles.h" @@ -158,6 +159,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, [this, input_subsystem] { CallConfigureDialog(*this, input_subsystem); }); + connect(advanced, &ConfigureInputAdvanced::CallRingControllerDialog, + [this, input_subsystem, &hid_core] { + CallConfigureDialog(*this, input_subsystem, hid_core); + }); connect(ui->vibrationButton, &QPushButton::clicked, [this, &hid_core] { CallConfigureDialog(*this, hid_core); }); diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index 20fc2599d..8fd1f4a38 100755 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -79,13 +79,17 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) &ConfigureInputAdvanced::UpdateUIEnabled); connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this, &ConfigureInputAdvanced::UpdateUIEnabled); + connect(ui->enable_ring_controller, &QCheckBox::stateChanged, this, + &ConfigureInputAdvanced::UpdateUIEnabled); connect(ui->debug_configure, &QPushButton::clicked, this, [this] { CallDebugControllerDialog(); }); connect(ui->touchscreen_advanced, &QPushButton::clicked, this, [this] { CallTouchscreenConfigDialog(); }); connect(ui->buttonMotionTouch, &QPushButton::clicked, this, - &ConfigureInputAdvanced::CallMotionTouchConfigDialog); + [this] { CallMotionTouchConfigDialog(); }); + connect(ui->ring_controller_configure, &QPushButton::clicked, this, + [this] { CallRingControllerDialog(); }); #ifndef _WIN32 ui->enable_raw_input->setVisible(false); @@ -132,6 +136,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); Settings::values.controller_navigation = ui->controller_navigation->isChecked(); + Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); } void ConfigureInputAdvanced::LoadConfiguration() { @@ -164,6 +169,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); + ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); UpdateUIEnabled(); } @@ -185,4 +191,5 @@ void ConfigureInputAdvanced::UpdateUIEnabled() { ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked()); ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked()); + ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked()); } diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h index 3083d55c1..4472cb846 100755 --- a/src/yuzu/configuration/configure_input_advanced.h +++ b/src/yuzu/configuration/configure_input_advanced.h @@ -29,6 +29,7 @@ signals: void CallMouseConfigDialog(); void CallTouchscreenConfigDialog(); void CallMotionTouchConfigDialog(); + void CallRingControllerDialog(); private: void changeEvent(QEvent* event) override; diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 66f2075f2..14403cb10 100755 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2603,6 +2603,20 @@ + + + + Ring Controller + + + + + + + Configure + + + diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 8ef3596dd..291e37acf 100755 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -1407,10 +1407,10 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { } void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { - event->ignore(); if (!input_setter || !event) { return; } + event->ignore(); if (event->key() != Qt::Key_Escape) { input_subsystem->GetKeyboard()->PressKey(event->key()); } diff --git a/src/yuzu/discord_impl.cpp b/src/yuzu/discord_impl.cpp index 66f928af6..be1c477d8 100755 --- a/src/yuzu/discord_impl.cpp +++ b/src/yuzu/discord_impl.cpp @@ -39,7 +39,7 @@ void DiscordImpl::Update() { system.GetAppLoader().ReadTitle(title); } DiscordRichPresence presence{}; - presence.largeImageKey = "yuzu_logo"; + presence.largeImageKey = "yuzu_logo_ea"; presence.largeImageText = "yuzu is an emulator for the Nintendo Switch"; if (system.IsPoweredOn()) { presence.state = title.c_str();