diff options
| author | 2020-04-23 11:37:12 -0400 | |
|---|---|---|
| committer | 2020-04-23 11:37:12 -0400 | |
| commit | ff0c49e1cee3c1dc21d56f6ca73963da5ceec80c (patch) | |
| tree | f3108877d77c64d4456b7ad27d500aa1e82da33d | |
| parent | Merge pull request #3730 from lioncash/time (diff) | |
| download | yuzu-ff0c49e1cee3c1dc21d56f6ca73963da5ceec80c.tar.gz yuzu-ff0c49e1cee3c1dc21d56f6ca73963da5ceec80c.tar.xz yuzu-ff0c49e1cee3c1dc21d56f6ca73963da5ceec80c.zip | |
kernel: memory: Improve implementation of device shared memory. (#3707)
* kernel: memory: Improve implementation of device shared memory.
* fixup! kernel: memory: Improve implementation of device shared memory.
* fixup! kernel: memory: Improve implementation of device shared memory.
| -rw-r--r-- | src/core/hle/kernel/memory/memory_block.h | 23 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_block_manager.cpp | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_block_manager.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_table.cpp | 44 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_table.h | 2 | ||||
| -rw-r--r-- | src/video_core/memory_manager.cpp | 18 |
6 files changed, 110 insertions, 16 deletions
diff --git a/src/core/hle/kernel/memory/memory_block.h b/src/core/hle/kernel/memory/memory_block.h index e11043b60..9db1f7b39 100644 --- a/src/core/hle/kernel/memory/memory_block.h +++ b/src/core/hle/kernel/memory/memory_block.h | |||
| @@ -17,7 +17,7 @@ namespace Kernel::Memory { | |||
| 17 | 17 | ||
| 18 | enum class MemoryState : u32 { | 18 | enum class MemoryState : u32 { |
| 19 | None = 0, | 19 | None = 0, |
| 20 | Mask = 0xFFFFFFFF, // TODO(bunnei): This should probable be 0xFF | 20 | Mask = 0xFF, |
| 21 | All = ~None, | 21 | All = ~None, |
| 22 | 22 | ||
| 23 | FlagCanReprotect = (1 << 8), | 23 | FlagCanReprotect = (1 << 8), |
| @@ -253,6 +253,23 @@ public: | |||
| 253 | }; | 253 | }; |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | void ShareToDevice(MemoryPermission /*new_perm*/) { | ||
| 257 | ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared || | ||
| 258 | device_use_count == 0); | ||
| 259 | attribute |= MemoryAttribute::DeviceShared; | ||
| 260 | const u16 new_use_count{++device_use_count}; | ||
| 261 | ASSERT(new_use_count > 0); | ||
| 262 | } | ||
| 263 | |||
| 264 | void UnshareToDevice(MemoryPermission /*new_perm*/) { | ||
| 265 | ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared); | ||
| 266 | const u16 prev_use_count{device_use_count--}; | ||
| 267 | ASSERT(prev_use_count > 0); | ||
| 268 | if (prev_use_count == 1) { | ||
| 269 | attribute &= ~MemoryAttribute::DeviceShared; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 256 | private: | 273 | private: |
| 257 | constexpr bool HasProperties(MemoryState s, MemoryPermission p, MemoryAttribute a) const { | 274 | constexpr bool HasProperties(MemoryState s, MemoryPermission p, MemoryAttribute a) const { |
| 258 | constexpr MemoryAttribute AttributeIgnoreMask{MemoryAttribute::DontCareMask | | 275 | constexpr MemoryAttribute AttributeIgnoreMask{MemoryAttribute::DontCareMask | |
| @@ -287,9 +304,9 @@ private: | |||
| 287 | state = new_state; | 304 | state = new_state; |
| 288 | perm = new_perm; | 305 | perm = new_perm; |
| 289 | 306 | ||
| 290 | // TODO(bunnei): Is this right? | ||
| 291 | attribute = static_cast<MemoryAttribute>( | 307 | attribute = static_cast<MemoryAttribute>( |
| 292 | new_attribute /*| (attribute & (MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared))*/); | 308 | new_attribute | |
| 309 | (attribute & (MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared))); | ||
| 293 | } | 310 | } |
| 294 | 311 | ||
| 295 | constexpr MemoryBlock Split(VAddr split_addr) { | 312 | constexpr MemoryBlock Split(VAddr split_addr) { |
diff --git a/src/core/hle/kernel/memory/memory_block_manager.cpp b/src/core/hle/kernel/memory/memory_block_manager.cpp index 1ebc126c0..900395c37 100644 --- a/src/core/hle/kernel/memory/memory_block_manager.cpp +++ b/src/core/hle/kernel/memory/memory_block_manager.cpp | |||
| @@ -143,6 +143,42 @@ void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState s | |||
| 143 | } | 143 | } |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | void MemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, | ||
| 147 | MemoryPermission perm) { | ||
| 148 | const std::size_t prev_count{memory_block_tree.size()}; | ||
| 149 | const VAddr end_addr{addr + num_pages * PageSize}; | ||
| 150 | iterator node{memory_block_tree.begin()}; | ||
| 151 | |||
| 152 | while (node != memory_block_tree.end()) { | ||
| 153 | MemoryBlock* block{&(*node)}; | ||
| 154 | iterator next_node{std::next(node)}; | ||
| 155 | const VAddr cur_addr{block->GetAddress()}; | ||
| 156 | const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; | ||
| 157 | |||
| 158 | if (addr < cur_end_addr && cur_addr < end_addr) { | ||
| 159 | iterator new_node{node}; | ||
| 160 | |||
| 161 | if (addr > cur_addr) { | ||
| 162 | memory_block_tree.insert(node, block->Split(addr)); | ||
| 163 | } | ||
| 164 | |||
| 165 | if (end_addr < cur_end_addr) { | ||
| 166 | new_node = memory_block_tree.insert(node, block->Split(end_addr)); | ||
| 167 | } | ||
| 168 | |||
| 169 | lock_func(new_node, perm); | ||
| 170 | |||
| 171 | MergeAdjacent(new_node, next_node); | ||
| 172 | } | ||
| 173 | |||
| 174 | if (cur_end_addr - 1 >= end_addr - 1) { | ||
| 175 | break; | ||
| 176 | } | ||
| 177 | |||
| 178 | node = next_node; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 146 | void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) { | 182 | void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) { |
| 147 | const_iterator it{FindIterator(start)}; | 183 | const_iterator it{FindIterator(start)}; |
| 148 | MemoryInfo info{}; | 184 | MemoryInfo info{}; |
diff --git a/src/core/hle/kernel/memory/memory_block_manager.h b/src/core/hle/kernel/memory/memory_block_manager.h index 0f2270f0f..9451b5df6 100644 --- a/src/core/hle/kernel/memory/memory_block_manager.h +++ b/src/core/hle/kernel/memory/memory_block_manager.h | |||
| @@ -45,6 +45,9 @@ public: | |||
| 45 | MemoryPermission perm = MemoryPermission::None, | 45 | MemoryPermission perm = MemoryPermission::None, |
| 46 | MemoryAttribute attribute = MemoryAttribute::None); | 46 | MemoryAttribute attribute = MemoryAttribute::None); |
| 47 | 47 | ||
| 48 | using LockFunc = std::function<void(iterator, MemoryPermission)>; | ||
| 49 | void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, MemoryPermission perm); | ||
| 50 | |||
| 48 | using IterateFunc = std::function<void(const MemoryInfo&)>; | 51 | using IterateFunc = std::function<void(const MemoryInfo&)>; |
| 49 | void IterateForRange(VAddr start, VAddr end, IterateFunc&& func); | 52 | void IterateForRange(VAddr start, VAddr end, IterateFunc&& func); |
| 50 | 53 | ||
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 091e52ca4..2c9925f33 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp | |||
| @@ -840,6 +840,50 @@ ResultVal<VAddr> PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s | |||
| 840 | return MakeResult<VAddr>(addr); | 840 | return MakeResult<VAddr>(addr); |
| 841 | } | 841 | } |
| 842 | 842 | ||
| 843 | ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { | ||
| 844 | std::lock_guard lock{page_table_lock}; | ||
| 845 | |||
| 846 | MemoryPermission perm{}; | ||
| 847 | if (const ResultCode result{CheckMemoryState( | ||
| 848 | nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute, | ||
| 849 | MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None, | ||
| 850 | MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None, | ||
| 851 | MemoryAttribute::DeviceSharedAndUncached)}; | ||
| 852 | result.IsError()) { | ||
| 853 | return result; | ||
| 854 | } | ||
| 855 | |||
| 856 | block_manager->UpdateLock(addr, size / PageSize, | ||
| 857 | [perm](MemoryBlockManager::iterator block, MemoryPermission perm) { | ||
| 858 | block->ShareToDevice(perm); | ||
| 859 | }, | ||
| 860 | perm); | ||
| 861 | |||
| 862 | return RESULT_SUCCESS; | ||
| 863 | } | ||
| 864 | |||
| 865 | ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) { | ||
| 866 | std::lock_guard lock{page_table_lock}; | ||
| 867 | |||
| 868 | MemoryPermission perm{}; | ||
| 869 | if (const ResultCode result{CheckMemoryState( | ||
| 870 | nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute, | ||
| 871 | MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None, | ||
| 872 | MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None, | ||
| 873 | MemoryAttribute::DeviceSharedAndUncached)}; | ||
| 874 | result.IsError()) { | ||
| 875 | return result; | ||
| 876 | } | ||
| 877 | |||
| 878 | block_manager->UpdateLock(addr, size / PageSize, | ||
| 879 | [perm](MemoryBlockManager::iterator block, MemoryPermission perm) { | ||
| 880 | block->UnshareToDevice(perm); | ||
| 881 | }, | ||
| 882 | perm); | ||
| 883 | |||
| 884 | return RESULT_SUCCESS; | ||
| 885 | } | ||
| 886 | |||
| 843 | ResultCode PageTable::InitializeMemoryLayout(VAddr start, VAddr end) { | 887 | ResultCode PageTable::InitializeMemoryLayout(VAddr start, VAddr end) { |
| 844 | block_manager = std::make_unique<MemoryBlockManager>(start, end); | 888 | block_manager = std::make_unique<MemoryBlockManager>(start, end); |
| 845 | 889 | ||
diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/memory/page_table.h index 80384ab0f..a867aa050 100644 --- a/src/core/hle/kernel/memory/page_table.h +++ b/src/core/hle/kernel/memory/page_table.h | |||
| @@ -53,6 +53,8 @@ public: | |||
| 53 | bool is_map_only, VAddr region_start, | 53 | bool is_map_only, VAddr region_start, |
| 54 | std::size_t region_num_pages, MemoryState state, | 54 | std::size_t region_num_pages, MemoryState state, |
| 55 | MemoryPermission perm, PAddr map_addr = 0); | 55 | MemoryPermission perm, PAddr map_addr = 0); |
| 56 | ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); | ||
| 57 | ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); | ||
| 56 | 58 | ||
| 57 | Common::PageTable& PageTableImpl() { | 59 | Common::PageTable& PageTableImpl() { |
| 58 | return page_table_impl; | 60 | return page_table_impl; |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index fd49bc2a9..dbee9f634 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -51,11 +51,8 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { | |||
| 51 | const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)}; | 51 | const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)}; |
| 52 | 52 | ||
| 53 | MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr); | 53 | MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr); |
| 54 | ASSERT(system.CurrentProcess() | 54 | ASSERT( |
| 55 | ->PageTable() | 55 | system.CurrentProcess()->PageTable().LockForDeviceAddressSpace(cpu_addr, size).IsSuccess()); |
| 56 | .SetMemoryAttribute(cpu_addr, size, Kernel::Memory::MemoryAttribute::DeviceShared, | ||
| 57 | Kernel::Memory::MemoryAttribute::DeviceShared) | ||
| 58 | .IsSuccess()); | ||
| 59 | 56 | ||
| 60 | return gpu_addr; | 57 | return gpu_addr; |
| 61 | } | 58 | } |
| @@ -66,11 +63,8 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) | |||
| 66 | const u64 aligned_size{Common::AlignUp(size, page_size)}; | 63 | const u64 aligned_size{Common::AlignUp(size, page_size)}; |
| 67 | 64 | ||
| 68 | MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr); | 65 | MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr); |
| 69 | ASSERT(system.CurrentProcess() | 66 | ASSERT( |
| 70 | ->PageTable() | 67 | system.CurrentProcess()->PageTable().LockForDeviceAddressSpace(cpu_addr, size).IsSuccess()); |
| 71 | .SetMemoryAttribute(cpu_addr, size, Kernel::Memory::MemoryAttribute::DeviceShared, | ||
| 72 | Kernel::Memory::MemoryAttribute::DeviceShared) | ||
| 73 | .IsSuccess()); | ||
| 74 | return gpu_addr; | 68 | return gpu_addr; |
| 75 | } | 69 | } |
| 76 | 70 | ||
| @@ -87,9 +81,7 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) { | |||
| 87 | UnmapRange(gpu_addr, aligned_size); | 81 | UnmapRange(gpu_addr, aligned_size); |
| 88 | ASSERT(system.CurrentProcess() | 82 | ASSERT(system.CurrentProcess() |
| 89 | ->PageTable() | 83 | ->PageTable() |
| 90 | .SetMemoryAttribute(cpu_addr.value(), size, | 84 | .UnlockForDeviceAddressSpace(cpu_addr.value(), size) |
| 91 | Kernel::Memory::MemoryAttribute::DeviceShared, | ||
| 92 | Kernel::Memory::MemoryAttribute::None) | ||
| 93 | .IsSuccess()); | 85 | .IsSuccess()); |
| 94 | 86 | ||
| 95 | return gpu_addr; | 87 | return gpu_addr; |