diff options
Diffstat (limited to 'src')
21 files changed, 272 insertions, 118 deletions
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 6dbd38ffa..e1033b634 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp | |||
| @@ -45,26 +45,26 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb | |||
| 45 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld | 45 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld |
| 46 | if (parameters.allow_pro_controller) { | 46 | if (parameters.allow_pro_controller) { |
| 47 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | 47 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); |
| 48 | controller->Connect(); | 48 | controller->Connect(true); |
| 49 | } else if (parameters.allow_dual_joycons) { | 49 | } else if (parameters.allow_dual_joycons) { |
| 50 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); | 50 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); |
| 51 | controller->Connect(); | 51 | controller->Connect(true); |
| 52 | } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { | 52 | } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { |
| 53 | // Assign left joycons to even player indices and right joycons to odd player indices. | 53 | // Assign left joycons to even player indices and right joycons to odd player indices. |
| 54 | // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and | 54 | // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and |
| 55 | // a right Joycon for Player 2 in 2 Player Assist mode. | 55 | // a right Joycon for Player 2 in 2 Player Assist mode. |
| 56 | if (index % 2 == 0) { | 56 | if (index % 2 == 0) { |
| 57 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); | 57 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); |
| 58 | controller->Connect(); | 58 | controller->Connect(true); |
| 59 | } else { | 59 | } else { |
| 60 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); | 60 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); |
| 61 | controller->Connect(); | 61 | controller->Connect(true); |
| 62 | } | 62 | } |
| 63 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && | 63 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && |
| 64 | !Settings::values.use_docked_mode.GetValue()) { | 64 | !Settings::values.use_docked_mode.GetValue()) { |
| 65 | // We should *never* reach here under any normal circumstances. | 65 | // We should *never* reach here under any normal circumstances. |
| 66 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | 66 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); |
| 67 | controller->Connect(); | 67 | controller->Connect(true); |
| 68 | } else { | 68 | } else { |
| 69 | UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); | 69 | UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); |
| 70 | } | 70 | } |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index ff9d7a7e3..2d3fce276 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -886,8 +886,9 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) | |||
| 886 | } | 886 | } |
| 887 | } | 887 | } |
| 888 | 888 | ||
| 889 | bool EmulatedController::IsControllerSupported() const { | 889 | bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { |
| 890 | switch (npad_type) { | 890 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; |
| 891 | switch (type) { | ||
| 891 | case NpadStyleIndex::ProController: | 892 | case NpadStyleIndex::ProController: |
| 892 | return supported_style_tag.fullkey; | 893 | return supported_style_tag.fullkey; |
| 893 | case NpadStyleIndex::Handheld: | 894 | case NpadStyleIndex::Handheld: |
| @@ -915,9 +916,10 @@ bool EmulatedController::IsControllerSupported() const { | |||
| 915 | } | 916 | } |
| 916 | } | 917 | } |
| 917 | 918 | ||
| 918 | void EmulatedController::Connect() { | 919 | void EmulatedController::Connect(bool use_temporary_value) { |
| 919 | if (!IsControllerSupported()) { | 920 | if (!IsControllerSupported(use_temporary_value)) { |
| 920 | LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type); | 921 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; |
| 922 | LOG_ERROR(Service_HID, "Controller type {} is not supported", type); | ||
| 921 | return; | 923 | return; |
| 922 | } | 924 | } |
| 923 | { | 925 | { |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index e42aafebc..d887eca87 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -167,8 +167,11 @@ public: | |||
| 167 | */ | 167 | */ |
| 168 | void SetSupportedNpadStyleTag(NpadStyleTag supported_styles); | 168 | void SetSupportedNpadStyleTag(NpadStyleTag supported_styles); |
| 169 | 169 | ||
| 170 | /// Sets the connected status to true | 170 | /** |
| 171 | void Connect(); | 171 | * Sets the connected status to true |
| 172 | * @param use_temporary_value If true tmp_npad_type will be used | ||
| 173 | */ | ||
| 174 | void Connect(bool use_temporary_value = false); | ||
| 172 | 175 | ||
| 173 | /// Sets the connected status to false | 176 | /// Sets the connected status to false |
| 174 | void Disconnect(); | 177 | void Disconnect(); |
| @@ -319,9 +322,10 @@ private: | |||
| 319 | 322 | ||
| 320 | /** | 323 | /** |
| 321 | * Checks the current controller type against the supported_style_tag | 324 | * Checks the current controller type against the supported_style_tag |
| 325 | * @param use_temporary_value If true tmp_npad_type will be used | ||
| 322 | * @return true if the controller is supported | 326 | * @return true if the controller is supported |
| 323 | */ | 327 | */ |
| 324 | bool IsControllerSupported() const; | 328 | bool IsControllerSupported(bool use_temporary_value = false) const; |
| 325 | 329 | ||
| 326 | /** | 330 | /** |
| 327 | * Updates the button status of the controller | 331 | * Updates the button status of the controller |
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index fd491146f..9e51c33ce 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h | |||
| @@ -120,7 +120,7 @@ static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015); | |||
| 120 | 120 | ||
| 121 | enum class KMemoryPermission : u8 { | 121 | enum class KMemoryPermission : u8 { |
| 122 | None = 0, | 122 | None = 0, |
| 123 | Mask = static_cast<u8>(~None), | 123 | All = static_cast<u8>(~None), |
| 124 | 124 | ||
| 125 | Read = 1 << 0, | 125 | Read = 1 << 0, |
| 126 | Write = 1 << 1, | 126 | Write = 1 << 1, |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 99982e5a3..4da509224 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -264,9 +264,9 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_ | |||
| 264 | ASSERT(heap_last < stack_start || stack_last < heap_start); | 264 | ASSERT(heap_last < stack_start || stack_last < heap_start); |
| 265 | ASSERT(heap_last < kmap_start || kmap_last < heap_start); | 265 | ASSERT(heap_last < kmap_start || kmap_last < heap_start); |
| 266 | 266 | ||
| 267 | current_heap_addr = heap_region_start; | 267 | current_heap_end = heap_region_start; |
| 268 | heap_capacity = 0; | 268 | max_heap_size = 0; |
| 269 | physical_memory_usage = 0; | 269 | mapped_physical_memory_size = 0; |
| 270 | memory_pool = pool; | 270 | memory_pool = pool; |
| 271 | 271 | ||
| 272 | page_table_impl.Resize(address_space_width, PageBits); | 272 | page_table_impl.Resize(address_space_width, PageBits); |
| @@ -306,7 +306,7 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std: | |||
| 306 | KMemoryState state{}; | 306 | KMemoryState state{}; |
| 307 | KMemoryPermission perm{}; | 307 | KMemoryPermission perm{}; |
| 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, | 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, |
| 309 | KMemoryState::Normal, KMemoryPermission::Mask, | 309 | KMemoryState::Normal, KMemoryPermission::All, |
| 310 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, | 310 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, |
| 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 312 | 312 | ||
| @@ -465,7 +465,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 465 | 465 | ||
| 466 | MapPhysicalMemory(page_linked_list, addr, end_addr); | 466 | MapPhysicalMemory(page_linked_list, addr, end_addr); |
| 467 | 467 | ||
| 468 | physical_memory_usage += remaining_size; | 468 | mapped_physical_memory_size += remaining_size; |
| 469 | 469 | ||
| 470 | const std::size_t num_pages{size / PageSize}; | 470 | const std::size_t num_pages{size / PageSize}; |
| 471 | block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, | 471 | block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, |
| @@ -507,7 +507,7 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 507 | 507 | ||
| 508 | auto process{system.Kernel().CurrentProcess()}; | 508 | auto process{system.Kernel().CurrentProcess()}; |
| 509 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); | 509 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); |
| 510 | physical_memory_usage -= mapped_size; | 510 | mapped_physical_memory_size -= mapped_size; |
| 511 | 511 | ||
| 512 | return ResultSuccess; | 512 | return ResultSuccess; |
| 513 | } | 513 | } |
| @@ -554,7 +554,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 554 | KMemoryState src_state{}; | 554 | KMemoryState src_state{}; |
| 555 | CASCADE_CODE(CheckMemoryState( | 555 | CASCADE_CODE(CheckMemoryState( |
| 556 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, | 556 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, |
| 557 | KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::ReadAndWrite, | 557 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite, |
| 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 559 | 559 | ||
| 560 | if (IsRegionMapped(dst_addr, size)) { | 560 | if (IsRegionMapped(dst_addr, size)) { |
| @@ -593,7 +593,7 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 593 | KMemoryState src_state{}; | 593 | KMemoryState src_state{}; |
| 594 | CASCADE_CODE(CheckMemoryState( | 594 | CASCADE_CODE(CheckMemoryState( |
| 595 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, | 595 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, |
| 596 | KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::None, | 596 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None, |
| 597 | KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); | 597 | KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); |
| 598 | 598 | ||
| 599 | KMemoryPermission dst_perm{}; | 599 | KMemoryPermission dst_perm{}; |
| @@ -784,7 +784,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo | |||
| 784 | CASCADE_CODE(CheckMemoryState( | 784 | CASCADE_CODE(CheckMemoryState( |
| 785 | &state, nullptr, &attribute, addr, size, | 785 | &state, nullptr, &attribute, addr, size, |
| 786 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, | 786 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, |
| 787 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::Mask, | 787 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All, |
| 788 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, | 788 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, |
| 789 | KMemoryAttribute::IpcAndDeviceMapped)); | 789 | KMemoryAttribute::IpcAndDeviceMapped)); |
| 790 | 790 | ||
| @@ -806,6 +806,33 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) { | |||
| 806 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); | 806 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); |
| 807 | 807 | ||
| 808 | block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); | 808 | block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); |
| 809 | return ResultSuccess; | ||
| 810 | } | ||
| 811 | |||
| 812 | ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size, | ||
| 813 | Svc::MemoryPermission svc_perm) { | ||
| 814 | const size_t num_pages = size / PageSize; | ||
| 815 | |||
| 816 | // Lock the table. | ||
| 817 | std::lock_guard lock{page_table_lock}; | ||
| 818 | |||
| 819 | // Verify we can change the memory permission. | ||
| 820 | KMemoryState old_state; | ||
| 821 | KMemoryPermission old_perm; | ||
| 822 | R_TRY(this->CheckMemoryState( | ||
| 823 | std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size, | ||
| 824 | KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None, | ||
| 825 | KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None)); | ||
| 826 | |||
| 827 | // Determine new perm. | ||
| 828 | const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); | ||
| 829 | R_SUCCEED_IF(old_perm == new_perm); | ||
| 830 | |||
| 831 | // Perform mapping operation. | ||
| 832 | R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions)); | ||
| 833 | |||
| 834 | // Update the blocks. | ||
| 835 | block_manager->Update(addr, num_pages, old_state, new_perm, KMemoryAttribute::None); | ||
| 809 | 836 | ||
| 810 | return ResultSuccess; | 837 | return ResultSuccess; |
| 811 | } | 838 | } |
| @@ -832,61 +859,125 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryA | |||
| 832 | return ResultSuccess; | 859 | return ResultSuccess; |
| 833 | } | 860 | } |
| 834 | 861 | ||
| 835 | ResultCode KPageTable::SetHeapCapacity(std::size_t new_heap_capacity) { | 862 | ResultCode KPageTable::SetMaxHeapSize(std::size_t size) { |
| 863 | // Lock the table. | ||
| 836 | std::lock_guard lock{page_table_lock}; | 864 | std::lock_guard lock{page_table_lock}; |
| 837 | heap_capacity = new_heap_capacity; | ||
| 838 | return ResultSuccess; | ||
| 839 | } | ||
| 840 | 865 | ||
| 841 | ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) { | 866 | // Only process page tables are allowed to set heap size. |
| 867 | ASSERT(!this->IsKernel()); | ||
| 842 | 868 | ||
| 843 | if (size > heap_region_end - heap_region_start) { | 869 | max_heap_size = size; |
| 844 | return ResultOutOfMemory; | ||
| 845 | } | ||
| 846 | 870 | ||
| 847 | const u64 previous_heap_size{GetHeapSize()}; | 871 | return ResultSuccess; |
| 848 | 872 | } | |
| 849 | UNIMPLEMENTED_IF_MSG(previous_heap_size > size, "Heap shrink is unimplemented"); | ||
| 850 | 873 | ||
| 851 | // Increase the heap size | 874 | ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) { |
| 875 | // Try to perform a reduction in heap, instead of an extension. | ||
| 876 | VAddr cur_address{}; | ||
| 877 | std::size_t allocation_size{}; | ||
| 852 | { | 878 | { |
| 853 | std::lock_guard lock{page_table_lock}; | 879 | // Lock the table. |
| 854 | 880 | std::lock_guard lk(page_table_lock); | |
| 855 | const u64 delta{size - previous_heap_size}; | 881 | |
| 856 | 882 | // Validate that setting heap size is possible at all. | |
| 857 | // Reserve memory for the heap extension. | 883 | R_UNLESS(!is_kernel, ResultOutOfMemory); |
| 858 | KScopedResourceReservation memory_reservation( | 884 | R_UNLESS(size <= static_cast<std::size_t>(heap_region_end - heap_region_start), |
| 859 | system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, | 885 | ResultOutOfMemory); |
| 860 | delta); | 886 | R_UNLESS(size <= max_heap_size, ResultOutOfMemory); |
| 861 | 887 | ||
| 862 | if (!memory_reservation.Succeeded()) { | 888 | if (size < GetHeapSize()) { |
| 863 | LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); | 889 | // The size being requested is less than the current size, so we need to free the end of |
| 864 | return ResultLimitReached; | 890 | // the heap. |
| 891 | |||
| 892 | // Validate memory state. | ||
| 893 | std::size_t num_allocator_blocks; | ||
| 894 | R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), | ||
| 895 | heap_region_start + size, GetHeapSize() - size, | ||
| 896 | KMemoryState::All, KMemoryState::Normal, | ||
| 897 | KMemoryPermission::All, KMemoryPermission::ReadAndWrite, | ||
| 898 | KMemoryAttribute::All, KMemoryAttribute::None)); | ||
| 899 | |||
| 900 | // Unmap the end of the heap. | ||
| 901 | const auto num_pages = (GetHeapSize() - size) / PageSize; | ||
| 902 | R_TRY(Operate(heap_region_start + size, num_pages, KMemoryPermission::None, | ||
| 903 | OperationType::Unmap)); | ||
| 904 | |||
| 905 | // Release the memory from the resource limit. | ||
| 906 | system.Kernel().CurrentProcess()->GetResourceLimit()->Release( | ||
| 907 | LimitableResource::PhysicalMemory, num_pages * PageSize); | ||
| 908 | |||
| 909 | // Apply the memory block update. | ||
| 910 | block_manager->Update(heap_region_start + size, num_pages, KMemoryState::Free, | ||
| 911 | KMemoryPermission::None, KMemoryAttribute::None); | ||
| 912 | |||
| 913 | // Update the current heap end. | ||
| 914 | current_heap_end = heap_region_start + size; | ||
| 915 | |||
| 916 | // Set the output. | ||
| 917 | *out = heap_region_start; | ||
| 918 | return ResultSuccess; | ||
| 919 | } else if (size == GetHeapSize()) { | ||
| 920 | // The size requested is exactly the current size. | ||
| 921 | *out = heap_region_start; | ||
| 922 | return ResultSuccess; | ||
| 923 | } else { | ||
| 924 | // We have to allocate memory. Determine how much to allocate and where while the table | ||
| 925 | // is locked. | ||
| 926 | cur_address = current_heap_end; | ||
| 927 | allocation_size = size - GetHeapSize(); | ||
| 865 | } | 928 | } |
| 929 | } | ||
| 866 | 930 | ||
| 867 | KPageLinkedList page_linked_list; | 931 | // Reserve memory for the heap extension. |
| 868 | const std::size_t num_pages{delta / PageSize}; | 932 | KScopedResourceReservation memory_reservation( |
| 933 | system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, | ||
| 934 | allocation_size); | ||
| 935 | R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); | ||
| 869 | 936 | ||
| 870 | CASCADE_CODE( | 937 | // Allocate pages for the heap extension. |
| 871 | system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); | 938 | KPageLinkedList page_linked_list; |
| 939 | R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, allocation_size / PageSize, | ||
| 940 | memory_pool)); | ||
| 872 | 941 | ||
| 873 | if (IsRegionMapped(current_heap_addr, delta)) { | 942 | // Map the pages. |
| 874 | return ResultInvalidCurrentMemory; | 943 | { |
| 944 | // Lock the table. | ||
| 945 | std::lock_guard lk(page_table_lock); | ||
| 946 | |||
| 947 | // Ensure that the heap hasn't changed since we began executing. | ||
| 948 | ASSERT(cur_address == current_heap_end); | ||
| 949 | |||
| 950 | // Check the memory state. | ||
| 951 | std::size_t num_allocator_blocks{}; | ||
| 952 | R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), current_heap_end, | ||
| 953 | allocation_size, KMemoryState::All, KMemoryState::Free, | ||
| 954 | KMemoryPermission::None, KMemoryPermission::None, | ||
| 955 | KMemoryAttribute::None, KMemoryAttribute::None)); | ||
| 956 | |||
| 957 | // Map the pages. | ||
| 958 | const auto num_pages = allocation_size / PageSize; | ||
| 959 | R_TRY(Operate(current_heap_end, num_pages, page_linked_list, OperationType::MapGroup)); | ||
| 960 | |||
| 961 | // Clear all the newly allocated pages. | ||
| 962 | for (std::size_t cur_page = 0; cur_page < num_pages; ++cur_page) { | ||
| 963 | std::memset(system.Memory().GetPointer(current_heap_end + (cur_page * PageSize)), 0, | ||
| 964 | PageSize); | ||
| 875 | } | 965 | } |
| 876 | 966 | ||
| 877 | CASCADE_CODE( | 967 | // We succeeded, so commit our memory reservation. |
| 878 | Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); | ||
| 879 | |||
| 880 | // Succeeded in allocation, commit the resource reservation | ||
| 881 | memory_reservation.Commit(); | 968 | memory_reservation.Commit(); |
| 882 | 969 | ||
| 883 | block_manager->Update(current_heap_addr, num_pages, KMemoryState::Normal, | 970 | // Apply the memory block update. |
| 884 | KMemoryPermission::ReadAndWrite); | 971 | block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal, |
| 972 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); | ||
| 885 | 973 | ||
| 886 | current_heap_addr = heap_region_start + size; | 974 | // Update the current heap end. |
| 887 | } | 975 | current_heap_end = heap_region_start + size; |
| 888 | 976 | ||
| 889 | return heap_region_start; | 977 | // Set the output. |
| 978 | *out = heap_region_start; | ||
| 979 | return ResultSuccess; | ||
| 980 | } | ||
| 890 | } | 981 | } |
| 891 | 982 | ||
| 892 | ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, | 983 | ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, |
| @@ -978,7 +1069,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { | |||
| 978 | 1069 | ||
| 979 | if (const ResultCode result{CheckMemoryState( | 1070 | if (const ResultCode result{CheckMemoryState( |
| 980 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | 1071 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, |
| 981 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask, | 1072 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, |
| 982 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; | 1073 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; |
| 983 | result.IsError()) { | 1074 | result.IsError()) { |
| 984 | return result; | 1075 | return result; |
| @@ -1031,9 +1122,8 @@ ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { | |||
| 1031 | 1122 | ||
| 1032 | bool KPageTable::IsRegionMapped(VAddr address, u64 size) { | 1123 | bool KPageTable::IsRegionMapped(VAddr address, u64 size) { |
| 1033 | return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, | 1124 | return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, |
| 1034 | KMemoryPermission::Mask, KMemoryPermission::None, | 1125 | KMemoryPermission::All, KMemoryPermission::None, KMemoryAttribute::Mask, |
| 1035 | KMemoryAttribute::Mask, KMemoryAttribute::None, | 1126 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped) |
| 1036 | KMemoryAttribute::IpcAndDeviceMapped) | ||
| 1037 | .IsError(); | 1127 | .IsError(); |
| 1038 | } | 1128 | } |
| 1039 | 1129 | ||
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index d784aa67e..564410dca 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -47,10 +47,11 @@ public: | |||
| 47 | KMemoryInfo QueryInfo(VAddr addr); | 47 | KMemoryInfo QueryInfo(VAddr addr); |
| 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); | 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); |
| 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); | 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); |
| 50 | ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm); | ||
| 50 | ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, | 51 | ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, |
| 51 | KMemoryAttribute value); | 52 | KMemoryAttribute value); |
| 52 | ResultCode SetHeapCapacity(std::size_t new_heap_capacity); | 53 | ResultCode SetMaxHeapSize(std::size_t size); |
| 53 | ResultVal<VAddr> SetHeapSize(std::size_t size); | 54 | ResultCode SetHeapSize(VAddr* out, std::size_t size); |
| 54 | ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, | 55 | ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, |
| 55 | bool is_map_only, VAddr region_start, | 56 | bool is_map_only, VAddr region_start, |
| 56 | std::size_t region_num_pages, KMemoryState state, | 57 | std::size_t region_num_pages, KMemoryState state, |
| @@ -182,14 +183,15 @@ public: | |||
| 182 | constexpr VAddr GetAliasCodeRegionSize() const { | 183 | constexpr VAddr GetAliasCodeRegionSize() const { |
| 183 | return alias_code_region_end - alias_code_region_start; | 184 | return alias_code_region_end - alias_code_region_start; |
| 184 | } | 185 | } |
| 186 | size_t GetNormalMemorySize() { | ||
| 187 | std::lock_guard lk(page_table_lock); | ||
| 188 | return GetHeapSize() + mapped_physical_memory_size; | ||
| 189 | } | ||
| 185 | constexpr std::size_t GetAddressSpaceWidth() const { | 190 | constexpr std::size_t GetAddressSpaceWidth() const { |
| 186 | return address_space_width; | 191 | return address_space_width; |
| 187 | } | 192 | } |
| 188 | constexpr std::size_t GetHeapSize() { | 193 | constexpr std::size_t GetHeapSize() const { |
| 189 | return current_heap_addr - heap_region_start; | 194 | return current_heap_end - heap_region_start; |
| 190 | } | ||
| 191 | constexpr std::size_t GetTotalHeapSize() { | ||
| 192 | return GetHeapSize() + physical_memory_usage; | ||
| 193 | } | 195 | } |
| 194 | constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const { | 196 | constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const { |
| 195 | return address_space_start <= address && address + size - 1 <= address_space_end - 1; | 197 | return address_space_start <= address && address + size - 1 <= address_space_end - 1; |
| @@ -269,10 +271,8 @@ private: | |||
| 269 | VAddr code_region_end{}; | 271 | VAddr code_region_end{}; |
| 270 | VAddr alias_code_region_start{}; | 272 | VAddr alias_code_region_start{}; |
| 271 | VAddr alias_code_region_end{}; | 273 | VAddr alias_code_region_end{}; |
| 272 | VAddr current_heap_addr{}; | ||
| 273 | 274 | ||
| 274 | std::size_t heap_capacity{}; | 275 | std::size_t mapped_physical_memory_size{}; |
| 275 | std::size_t physical_memory_usage{}; | ||
| 276 | std::size_t max_heap_size{}; | 276 | std::size_t max_heap_size{}; |
| 277 | std::size_t max_physical_memory_size{}; | 277 | std::size_t max_physical_memory_size{}; |
| 278 | std::size_t address_space_width{}; | 278 | std::size_t address_space_width{}; |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index aee313995..73f8bc4fe 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -172,7 +172,7 @@ void KProcess::DecrementThreadCount() { | |||
| 172 | 172 | ||
| 173 | u64 KProcess::GetTotalPhysicalMemoryAvailable() const { | 173 | u64 KProcess::GetTotalPhysicalMemoryAvailable() const { |
| 174 | const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + | 174 | const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + |
| 175 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + | 175 | page_table->GetNormalMemorySize() + GetSystemResourceSize() + image_size + |
| 176 | main_thread_stack_size}; | 176 | main_thread_stack_size}; |
| 177 | if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); | 177 | if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); |
| 178 | capacity != pool_size) { | 178 | capacity != pool_size) { |
| @@ -189,7 +189,7 @@ u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { | |||
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | u64 KProcess::GetTotalPhysicalMemoryUsed() const { | 191 | u64 KProcess::GetTotalPhysicalMemoryUsed() const { |
| 192 | return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() + | 192 | return image_size + main_thread_stack_size + page_table->GetNormalMemorySize() + |
| 193 | GetSystemResourceSize(); | 193 | GetSystemResourceSize(); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| @@ -410,8 +410,8 @@ void KProcess::Run(s32 main_thread_priority, u64 stack_size) { | |||
| 410 | resource_limit->Reserve(LimitableResource::Threads, 1); | 410 | resource_limit->Reserve(LimitableResource::Threads, 1); |
| 411 | resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); | 411 | resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); |
| 412 | 412 | ||
| 413 | const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size}; | 413 | const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)}; |
| 414 | ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError()); | 414 | ASSERT(!page_table->SetMaxHeapSize(heap_capacity).IsError()); |
| 415 | 415 | ||
| 416 | ChangeStatus(ProcessStatus::Running); | 416 | ChangeStatus(ProcessStatus::Running); |
| 417 | 417 | ||
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 752592e2e..b8c993748 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include "core/hle/kernel/k_resource_limit.h" | 26 | #include "core/hle/kernel/k_resource_limit.h" |
| 27 | #include "core/hle/kernel/k_scheduler.h" | 27 | #include "core/hle/kernel/k_scheduler.h" |
| 28 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 28 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 29 | #include "core/hle/kernel/k_system_control.h" | ||
| 29 | #include "core/hle/kernel/k_thread.h" | 30 | #include "core/hle/kernel/k_thread.h" |
| 30 | #include "core/hle/kernel/k_thread_queue.h" | 31 | #include "core/hle/kernel/k_thread_queue.h" |
| 31 | #include "core/hle/kernel/kernel.h" | 32 | #include "core/hle/kernel/kernel.h" |
| @@ -50,6 +51,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, | |||
| 50 | VAddr entry_point, u64 arg) { | 51 | VAddr entry_point, u64 arg) { |
| 51 | context = {}; | 52 | context = {}; |
| 52 | context.cpu_registers[0] = arg; | 53 | context.cpu_registers[0] = arg; |
| 54 | context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1; | ||
| 53 | context.pc = entry_point; | 55 | context.pc = entry_point; |
| 54 | context.sp = stack_top; | 56 | context.sp = stack_top; |
| 55 | // TODO(merry): Perform a hardware test to determine the below value. | 57 | // TODO(merry): Perform a hardware test to determine the below value. |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 37d67b72e..63e2dff19 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -135,24 +135,15 @@ enum class ResourceLimitValueType { | |||
| 135 | } // Anonymous namespace | 135 | } // Anonymous namespace |
| 136 | 136 | ||
| 137 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 137 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 138 | static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) { | 138 | static ResultCode SetHeapSize(Core::System& system, VAddr* out_address, u64 size) { |
| 139 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); | 139 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); |
| 140 | 140 | ||
| 141 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB. | 141 | // Validate size. |
| 142 | if ((heap_size % 0x200000) != 0) { | 142 | R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); |
| 143 | LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}", | 143 | R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); |
| 144 | heap_size); | ||
| 145 | return ResultInvalidSize; | ||
| 146 | } | ||
| 147 | |||
| 148 | if (heap_size >= 0x200000000) { | ||
| 149 | LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size); | ||
| 150 | return ResultInvalidSize; | ||
| 151 | } | ||
| 152 | |||
| 153 | auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; | ||
| 154 | 144 | ||
| 155 | CASCADE_RESULT(*heap_addr, page_table.SetHeapSize(heap_size)); | 145 | // Set the heap size. |
| 146 | R_TRY(system.Kernel().CurrentProcess()->PageTable().SetHeapSize(out_address, size)); | ||
| 156 | 147 | ||
| 157 | return ResultSuccess; | 148 | return ResultSuccess; |
| 158 | } | 149 | } |
| @@ -164,6 +155,36 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s | |||
| 164 | return result; | 155 | return result; |
| 165 | } | 156 | } |
| 166 | 157 | ||
| 158 | constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) { | ||
| 159 | switch (perm) { | ||
| 160 | case MemoryPermission::None: | ||
| 161 | case MemoryPermission::Read: | ||
| 162 | case MemoryPermission::ReadWrite: | ||
| 163 | return true; | ||
| 164 | default: | ||
| 165 | return false; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size, | ||
| 170 | MemoryPermission perm) { | ||
| 171 | // Validate address / size. | ||
| 172 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | ||
| 173 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 174 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 175 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 176 | |||
| 177 | // Validate the permission. | ||
| 178 | R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||
| 179 | |||
| 180 | // Validate that the region is in range for the current process. | ||
| 181 | auto& page_table = system.Kernel().CurrentProcess()->PageTable(); | ||
| 182 | R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); | ||
| 183 | |||
| 184 | // Set the memory attribute. | ||
| 185 | return page_table.SetMemoryPermission(address, size, perm); | ||
| 186 | } | ||
| 187 | |||
| 167 | static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, | 188 | static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, |
| 168 | u32 attribute) { | 189 | u32 attribute) { |
| 169 | LOG_DEBUG(Kernel_SVC, | 190 | LOG_DEBUG(Kernel_SVC, |
| @@ -2724,7 +2745,7 @@ static const FunctionDef SVC_Table_32[] = { | |||
| 2724 | static const FunctionDef SVC_Table_64[] = { | 2745 | static const FunctionDef SVC_Table_64[] = { |
| 2725 | {0x00, nullptr, "Unknown"}, | 2746 | {0x00, nullptr, "Unknown"}, |
| 2726 | {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"}, | 2747 | {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"}, |
| 2727 | {0x02, nullptr, "SetMemoryPermission"}, | 2748 | {0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"}, |
| 2728 | {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"}, | 2749 | {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"}, |
| 2729 | {0x04, SvcWrap64<MapMemory>, "MapMemory"}, | 2750 | {0x04, SvcWrap64<MapMemory>, "MapMemory"}, |
| 2730 | {0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"}, | 2751 | {0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"}, |
diff --git a/src/core/hle/kernel/svc_common.h b/src/core/hle/kernel/svc_common.h index 60ea2c405..25de6e437 100644 --- a/src/core/hle/kernel/svc_common.h +++ b/src/core/hle/kernel/svc_common.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/literals.h" | ||
| 8 | 9 | ||
| 9 | namespace Kernel { | 10 | namespace Kernel { |
| 10 | using Handle = u32; | 11 | using Handle = u32; |
| @@ -12,9 +13,13 @@ using Handle = u32; | |||
| 12 | 13 | ||
| 13 | namespace Kernel::Svc { | 14 | namespace Kernel::Svc { |
| 14 | 15 | ||
| 16 | using namespace Common::Literals; | ||
| 17 | |||
| 15 | constexpr s32 ArgumentHandleCountMax = 0x40; | 18 | constexpr s32 ArgumentHandleCountMax = 0x40; |
| 16 | constexpr u32 HandleWaitMask{1u << 30}; | 19 | constexpr u32 HandleWaitMask{1u << 30}; |
| 17 | 20 | ||
| 21 | constexpr inline std::size_t HeapSizeAlignment = 2_MiB; | ||
| 22 | |||
| 18 | constexpr inline Handle InvalidHandle = Handle(0); | 23 | constexpr inline Handle InvalidHandle = Handle(0); |
| 19 | 24 | ||
| 20 | enum PseudoHandle : Handle { | 25 | enum PseudoHandle : Handle { |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 86255fe6d..a60adfcab 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -249,6 +249,14 @@ void SvcWrap64(Core::System& system) { | |||
| 249 | func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); | 249 | func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | // Used by SetMemoryPermission | ||
| 253 | template <ResultCode func(Core::System&, u64, u64, Svc::MemoryPermission)> | ||
| 254 | void SvcWrap64(Core::System& system) { | ||
| 255 | FuncReturn(system, func(system, Param(system, 0), Param(system, 1), | ||
| 256 | static_cast<Svc::MemoryPermission>(Param(system, 2))) | ||
| 257 | .raw); | ||
| 258 | } | ||
| 259 | |||
| 252 | // Used by MapSharedMemory | 260 | // Used by MapSharedMemory |
| 253 | template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)> | 261 | template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)> |
| 254 | void SvcWrap64(Core::System& system) { | 262 | void SvcWrap64(Core::System& system) { |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index c0f5fc402..7434a1f92 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp | |||
| @@ -86,7 +86,7 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal | |||
| 86 | } | 86 | } |
| 87 | switch (attr) { | 87 | switch (attr) { |
| 88 | case IR::Attribute::PrimitiveId: | 88 | case IR::Attribute::PrimitiveId: |
| 89 | ctx.Add("MOV.S {}.x,primitive.id;", inst); | 89 | ctx.Add("MOV.F {}.x,primitive.id;", inst); |
| 90 | break; | 90 | break; |
| 91 | case IR::Attribute::PositionX: | 91 | case IR::Attribute::PositionX: |
| 92 | case IR::Attribute::PositionY: | 92 | case IR::Attribute::PositionY: |
| @@ -113,13 +113,13 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal | |||
| 113 | ctx.Add("MOV.F {}.x,vertex.tesscoord.{};", inst, swizzle); | 113 | ctx.Add("MOV.F {}.x,vertex.tesscoord.{};", inst, swizzle); |
| 114 | break; | 114 | break; |
| 115 | case IR::Attribute::InstanceId: | 115 | case IR::Attribute::InstanceId: |
| 116 | ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name); | 116 | ctx.Add("MOV.F {}.x,{}.instance;", inst, ctx.attrib_name); |
| 117 | break; | 117 | break; |
| 118 | case IR::Attribute::VertexId: | 118 | case IR::Attribute::VertexId: |
| 119 | ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name); | 119 | ctx.Add("MOV.F {}.x,{}.id;", inst, ctx.attrib_name); |
| 120 | break; | 120 | break; |
| 121 | case IR::Attribute::FrontFace: | 121 | case IR::Attribute::FrontFace: |
| 122 | ctx.Add("CMP.S {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name); | 122 | ctx.Add("CMP.F {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name); |
| 123 | break; | 123 | break; |
| 124 | default: | 124 | default: |
| 125 | throw NotImplementedException("Get attribute {}", attr); | 125 | throw NotImplementedException("Get attribute {}", attr); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 6ce7ed12a..50918317f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -30,11 +30,20 @@ struct FuncTraits<ReturnType_ (*)(Args...)> { | |||
| 30 | using ArgType = std::tuple_element_t<I, std::tuple<Args...>>; | 30 | using ArgType = std::tuple_element_t<I, std::tuple<Args...>>; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | #ifdef _MSC_VER | ||
| 34 | #pragma warning(push) | ||
| 35 | #pragma warning(disable : 4702) // Ignore unreachable code warning | ||
| 36 | #endif | ||
| 37 | |||
| 33 | template <auto func, typename... Args> | 38 | template <auto func, typename... Args> |
| 34 | void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { | 39 | void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { |
| 35 | inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...)); | 40 | inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...)); |
| 36 | } | 41 | } |
| 37 | 42 | ||
| 43 | #ifdef _MSC_VER | ||
| 44 | #pragma warning(pop) | ||
| 45 | #endif | ||
| 46 | |||
| 38 | template <typename ArgType> | 47 | template <typename ArgType> |
| 39 | ArgType Arg(EmitContext& ctx, const IR::Value& arg) { | 48 | ArgType Arg(EmitContext& ctx, const IR::Value& arg) { |
| 40 | if constexpr (std::is_same_v<ArgType, Id>) { | 49 | if constexpr (std::is_same_v<ArgType, Id>) { |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 14e6522f2..3c1f79a27 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -1047,7 +1047,7 @@ bool Image::ScaleDown(bool ignore) { | |||
| 1047 | } | 1047 | } |
| 1048 | 1048 | ||
| 1049 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | 1049 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, |
| 1050 | ImageId image_id_, Image& image) | 1050 | ImageId image_id_, Image& image, const SlotVector<Image>&) |
| 1051 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} { | 1051 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} { |
| 1052 | const Device& device = runtime.device; | 1052 | const Device& device = runtime.device; |
| 1053 | if (True(image.flags & ImageFlagBits::Converted)) { | 1053 | if (True(image.flags & ImageFlagBits::Converted)) { |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index dbf1df79c..7f425631f 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -36,6 +36,7 @@ using VideoCommon::ImageViewType; | |||
| 36 | using VideoCommon::NUM_RT; | 36 | using VideoCommon::NUM_RT; |
| 37 | using VideoCommon::Region2D; | 37 | using VideoCommon::Region2D; |
| 38 | using VideoCommon::RenderTargets; | 38 | using VideoCommon::RenderTargets; |
| 39 | using VideoCommon::SlotVector; | ||
| 39 | 40 | ||
| 40 | struct ImageBufferMap { | 41 | struct ImageBufferMap { |
| 41 | ~ImageBufferMap(); | 42 | ~ImageBufferMap(); |
| @@ -234,7 +235,8 @@ class ImageView : public VideoCommon::ImageViewBase { | |||
| 234 | friend Image; | 235 | friend Image; |
| 235 | 236 | ||
| 236 | public: | 237 | public: |
| 237 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); | 238 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&, |
| 239 | const SlotVector<Image>&); | ||
| 238 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, | 240 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, |
| 239 | const VideoCommon::ImageViewInfo&, GPUVAddr); | 241 | const VideoCommon::ImageViewInfo&, GPUVAddr); |
| 240 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | 242 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 1941170cb..c3050887c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -1473,8 +1473,7 @@ bool Image::BlitScaleHelper(bool scale_up) { | |||
| 1473 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | 1473 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, |
| 1474 | ImageId image_id_, Image& image) | 1474 | ImageId image_id_, Image& image) |
| 1475 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, | 1475 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, |
| 1476 | src_image{&image}, image_handle{image.Handle()}, | 1476 | image_handle{image.Handle()}, samples(ConvertSampleCount(image.info.num_samples)) { |
| 1477 | samples(ConvertSampleCount(image.info.num_samples)) { | ||
| 1478 | using Shader::TextureType; | 1477 | using Shader::TextureType; |
| 1479 | 1478 | ||
| 1480 | const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); | 1479 | const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); |
| @@ -1557,6 +1556,12 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI | |||
| 1557 | } | 1556 | } |
| 1558 | } | 1557 | } |
| 1559 | 1558 | ||
| 1559 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | ||
| 1560 | ImageId image_id_, Image& image, const SlotVector<Image>& slot_imgs) | ||
| 1561 | : ImageView{runtime, info, image_id_, image} { | ||
| 1562 | slot_images = &slot_imgs; | ||
| 1563 | } | ||
| 1564 | |||
| 1560 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | 1565 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, |
| 1561 | const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) | 1566 | const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) |
| 1562 | : VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_}, | 1567 | : VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_}, |
| @@ -1613,10 +1618,12 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type, | |||
| 1613 | } | 1618 | } |
| 1614 | 1619 | ||
| 1615 | bool ImageView::IsRescaled() const noexcept { | 1620 | bool ImageView::IsRescaled() const noexcept { |
| 1616 | if (!src_image) { | 1621 | if (!slot_images) { |
| 1617 | return false; | 1622 | return false; |
| 1618 | } | 1623 | } |
| 1619 | return src_image->IsRescaled(); | 1624 | const auto& slots = *slot_images; |
| 1625 | const auto& src_image = slots[image_id]; | ||
| 1626 | return src_image.IsRescaled(); | ||
| 1620 | } | 1627 | } |
| 1621 | 1628 | ||
| 1622 | vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) { | 1629 | vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) { |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index c592f2666..2f12be78b 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -23,6 +23,7 @@ using VideoCommon::ImageId; | |||
| 23 | using VideoCommon::NUM_RT; | 23 | using VideoCommon::NUM_RT; |
| 24 | using VideoCommon::Region2D; | 24 | using VideoCommon::Region2D; |
| 25 | using VideoCommon::RenderTargets; | 25 | using VideoCommon::RenderTargets; |
| 26 | using VideoCommon::SlotVector; | ||
| 26 | using VideoCore::Surface::PixelFormat; | 27 | using VideoCore::Surface::PixelFormat; |
| 27 | 28 | ||
| 28 | class ASTCDecoderPass; | 29 | class ASTCDecoderPass; |
| @@ -170,6 +171,8 @@ private: | |||
| 170 | class ImageView : public VideoCommon::ImageViewBase { | 171 | class ImageView : public VideoCommon::ImageViewBase { |
| 171 | public: | 172 | public: |
| 172 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); | 173 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); |
| 174 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&, | ||
| 175 | const SlotVector<Image>&); | ||
| 173 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, | 176 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, |
| 174 | const VideoCommon::ImageViewInfo&, GPUVAddr); | 177 | const VideoCommon::ImageViewInfo&, GPUVAddr); |
| 175 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&); | 178 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&); |
| @@ -226,7 +229,7 @@ private: | |||
| 226 | [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask); | 229 | [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask); |
| 227 | 230 | ||
| 228 | const Device* device = nullptr; | 231 | const Device* device = nullptr; |
| 229 | const Image* src_image{}; | 232 | const SlotVector<Image>* slot_images = nullptr; |
| 230 | 233 | ||
| 231 | std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views; | 234 | std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views; |
| 232 | std::unique_ptr<StorageViews> storage_views; | 235 | std::unique_ptr<StorageViews> storage_views; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 2e19fced2..b494152b8 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -1397,7 +1397,8 @@ ImageViewId TextureCache<P>::FindOrEmplaceImageView(ImageId image_id, const Imag | |||
| 1397 | if (const ImageViewId image_view_id = image.FindView(info); image_view_id) { | 1397 | if (const ImageViewId image_view_id = image.FindView(info); image_view_id) { |
| 1398 | return image_view_id; | 1398 | return image_view_id; |
| 1399 | } | 1399 | } |
| 1400 | const ImageViewId image_view_id = slot_image_views.insert(runtime, info, image_id, image); | 1400 | const ImageViewId image_view_id = |
| 1401 | slot_image_views.insert(runtime, info, image_id, image, slot_images); | ||
| 1401 | image.InsertView(info, image_view_id); | 1402 | image.InsertView(info, image_view_id); |
| 1402 | return image_view_id; | 1403 | return image_view_id; |
| 1403 | } | 1404 | } |
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 7bd31b211..d8e19cb2f 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -364,14 +364,14 @@ template <u32 GOB_EXTENT> | |||
| 364 | 364 | ||
| 365 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress2D( | 365 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress2D( |
| 366 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { | 366 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { |
| 367 | const u32 layer_stride = new_info.layer_stride; | 367 | const u64 layer_stride = new_info.layer_stride; |
| 368 | const s32 new_size = layer_stride * new_info.resources.layers; | 368 | const u64 new_size = layer_stride * new_info.resources.layers; |
| 369 | const s32 diff = static_cast<s32>(overlap.gpu_addr - gpu_addr); | 369 | const u64 diff = overlap.gpu_addr - gpu_addr; |
| 370 | if (diff > new_size) { | 370 | if (diff > new_size) { |
| 371 | return std::nullopt; | 371 | return std::nullopt; |
| 372 | } | 372 | } |
| 373 | const s32 base_layer = diff / layer_stride; | 373 | const s32 base_layer = static_cast<s32>(diff / layer_stride); |
| 374 | const s32 mip_offset = diff % layer_stride; | 374 | const s32 mip_offset = static_cast<s32>(diff % layer_stride); |
| 375 | const std::array offsets = CalculateMipLevelOffsets(new_info); | 375 | const std::array offsets = CalculateMipLevelOffsets(new_info); |
| 376 | const auto end = offsets.begin() + new_info.resources.levels; | 376 | const auto end = offsets.begin() + new_info.resources.levels; |
| 377 | const auto it = std::find(offsets.begin(), end, static_cast<u32>(mip_offset)); | 377 | const auto it = std::find(offsets.begin(), end, static_cast<u32>(mip_offset)); |
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index c6222b571..d63193131 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp | |||
| @@ -33,7 +33,7 @@ void UpdateController(Core::HID::EmulatedController* controller, | |||
| 33 | } | 33 | } |
| 34 | controller->SetNpadStyleIndex(controller_type); | 34 | controller->SetNpadStyleIndex(controller_type); |
| 35 | if (connected) { | 35 | if (connected) { |
| 36 | controller->Connect(); | 36 | controller->Connect(true); |
| 37 | } | 37 | } |
| 38 | } | 38 | } |
| 39 | 39 | ||
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 8a8be8e40..cb6163702 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -599,11 +599,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 599 | if (is_connected) { | 599 | if (is_connected) { |
| 600 | if (type == Core::HID::NpadStyleIndex::Handheld) { | 600 | if (type == Core::HID::NpadStyleIndex::Handheld) { |
| 601 | emulated_controller_p1->Disconnect(); | 601 | emulated_controller_p1->Disconnect(); |
| 602 | emulated_controller_handheld->Connect(); | 602 | emulated_controller_handheld->Connect(true); |
| 603 | emulated_controller = emulated_controller_handheld; | 603 | emulated_controller = emulated_controller_handheld; |
| 604 | } else { | 604 | } else { |
| 605 | emulated_controller_handheld->Disconnect(); | 605 | emulated_controller_handheld->Disconnect(); |
| 606 | emulated_controller_p1->Connect(); | 606 | emulated_controller_p1->Connect(true); |
| 607 | emulated_controller = emulated_controller_p1; | 607 | emulated_controller = emulated_controller_p1; |
| 608 | } | 608 | } |
| 609 | } | 609 | } |
| @@ -718,7 +718,7 @@ void ConfigureInputPlayer::LoadConfiguration() { | |||
| 718 | void ConfigureInputPlayer::ConnectPlayer(bool connected) { | 718 | void ConfigureInputPlayer::ConnectPlayer(bool connected) { |
| 719 | ui->groupConnectedController->setChecked(connected); | 719 | ui->groupConnectedController->setChecked(connected); |
| 720 | if (connected) { | 720 | if (connected) { |
| 721 | emulated_controller->Connect(); | 721 | emulated_controller->Connect(true); |
| 722 | } else { | 722 | } else { |
| 723 | emulated_controller->Disconnect(); | 723 | emulated_controller->Disconnect(); |
| 724 | } | 724 | } |