summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/common_types.h1
-rw-r--r--src/core/device_memory.h16
-rw-r--r--src/core/device_memory_manager.h97
-rw-r--r--src/core/device_memory_manager.inc304
-rw-r--r--src/video_core/host1x/gpu_device_memory_manager.cpp21
-rw-r--r--src/video_core/host1x/gpu_device_memory_manager.h20
6 files changed, 459 insertions, 0 deletions
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 0fc225aff..ae04c4d60 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -45,6 +45,7 @@ using f32 = float; ///< 32-bit floating point
45using f64 = double; ///< 64-bit floating point 45using f64 = double; ///< 64-bit floating point
46 46
47using VAddr = u64; ///< Represents a pointer in the userspace virtual address space. 47using VAddr = u64; ///< Represents a pointer in the userspace virtual address space.
48using DAddr = u64; ///< Represents a pointer in the device specific virtual address space.
48using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space. 49using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space.
49using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space. 50using GPUVAddr = u64; ///< Represents a pointer in the GPU virtual address space.
50 51
diff --git a/src/core/device_memory.h b/src/core/device_memory.h
index 13388b73e..11bf0e326 100644
--- a/src/core/device_memory.h
+++ b/src/core/device_memory.h
@@ -32,6 +32,12 @@ public:
32 } 32 }
33 33
34 template <typename T> 34 template <typename T>
35 PAddr GetRawPhysicalAddr(const T* ptr) const {
36 return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) -
37 reinterpret_cast<uintptr_t>(buffer.BackingBasePointer()));
38 }
39
40 template <typename T>
35 T* GetPointer(Common::PhysicalAddress addr) { 41 T* GetPointer(Common::PhysicalAddress addr) {
36 return reinterpret_cast<T*>(buffer.BackingBasePointer() + 42 return reinterpret_cast<T*>(buffer.BackingBasePointer() +
37 (GetInteger(addr) - DramMemoryMap::Base)); 43 (GetInteger(addr) - DramMemoryMap::Base));
@@ -43,6 +49,16 @@ public:
43 (GetInteger(addr) - DramMemoryMap::Base)); 49 (GetInteger(addr) - DramMemoryMap::Base));
44 } 50 }
45 51
52 template <typename T>
53 T* GetPointerFromRaw(PAddr addr) {
54 return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
55 }
56
57 template <typename T>
58 const T* GetPointerFromRaw(PAddr addr) const {
59 return reinterpret_cast<T*>(buffer.BackingBasePointer() + addr);
60 }
61
46 Common::HostMemory buffer; 62 Common::HostMemory buffer;
47}; 63};
48 64
diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h
new file mode 100644
index 000000000..0861b792d
--- /dev/null
+++ b/src/core/device_memory_manager.h
@@ -0,0 +1,97 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <deque>
7#include <memory>
8
9#include "common/common_types.h"
10#include "common/virtual_buffer.h"
11
12namespace Core {
13
14class DeviceMemory;
15
16namespace Memory {
17class Memory;
18}
19
20template <typename DTraits>
21struct DeviceMemoryManagerAllocator;
22
23template <typename Traits>
24class DeviceMemoryManager {
25 using DeviceInterface = typename Traits::DeviceInterface;
26
27public:
28 DeviceMemoryManager(const DeviceMemory& device_memory);
29 ~DeviceMemoryManager();
30
31 void BindInterface(DeviceInterface* interface);
32
33 DAddr Allocate(size_t size);
34 void AllocateFixed(DAddr start, size_t size);
35 DAddr AllocatePinned(size_t size);
36 void Free(DAddr start, size_t size);
37
38 void Map(DAddr address, VAddr virtual_address, size_t size, size_t p_id);
39 void Unmap(DAddr address, size_t size);
40
41 // Write / Read
42 template <typename T>
43 T* GetPointer(DAddr address);
44
45 template <typename T>
46 const T* GetPointer(DAddr address) const;
47
48 template <typename T>
49 void Write(DAddr address, T value);
50
51 template <typename T>
52 T Read(DAddr address) const;
53
54 void ReadBlock(DAddr address, void* dest_pointer, size_t size);
55 void WriteBlock(DAddr address, void* src_pointer, size_t size);
56
57 size_t RegisterProcess(Memory::Memory* memory);
58 void UnregisterProcess(size_t id);
59
60private:
61 static constexpr bool supports_pinning = Traits::supports_pinning;
62 static constexpr size_t device_virtual_bits = Traits::device_virtual_bits;
63 static constexpr size_t device_as_size = 1ULL << device_virtual_bits;
64 static constexpr size_t physical_max_bits = 33;
65 static constexpr size_t page_bits = 12;
66 static constexpr u32 physical_address_base = 1U << page_bits;
67
68 template <typename T>
69 T* GetPointerFromRaw(PAddr addr) {
70 return reinterpret_cast<T*>(physical_base + addr);
71 }
72
73 template <typename T>
74 const T* GetPointerFromRaw(PAddr addr) const {
75 return reinterpret_cast<T*>(physical_base + addr);
76 }
77
78 template <typename T>
79 PAddr GetRawPhysicalAddr(const T* ptr) const {
80 return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) - physical_base);
81 }
82
83 void WalkBlock(const DAddr addr, const std::size_t size, auto on_unmapped, auto on_memory,
84 auto increment);
85
86 std::unique_ptr<DeviceMemoryManagerAllocator<Traits>> impl;
87
88 const uintptr_t physical_base;
89 DeviceInterface* interface;
90 Common::VirtualBuffer<u32> compressed_physical_ptr;
91 Common::VirtualBuffer<u32> compressed_device_addr;
92
93 std::deque<size_t> id_pool;
94 std::deque<Memory::Memory*> registered_processes;
95};
96
97} // namespace Core \ No newline at end of file
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
new file mode 100644
index 000000000..1f52b92d5
--- /dev/null
+++ b/src/core/device_memory_manager.inc
@@ -0,0 +1,304 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <atomic>
5#include <memory>
6#include <type_traits>
7
8#include "common/address_space.h"
9#include "common/address_space.inc"
10#include "common/alignment.h"
11#include "common/scope_exit.h"
12#include "core/device_memory.h"
13#include "core/device_memory_manager.h"
14#include "core/memory.h"
15
16namespace Core {
17
18struct EmptyAllocator {
19 EmptyAllocator([[maybe_unused]] DAddr address) {}
20};
21
22template <typename DTraits>
23struct DeviceMemoryManagerAllocator {
24 static constexpr bool supports_pinning = DTraits::supports_pinning;
25 static constexpr size_t device_virtual_bits = DTraits::device_virtual_bits;
26 static constexpr size_t pin_bits = 32;
27 static constexpr DAddr first_address = 1ULL << Memory::YUZU_PAGEBITS;
28 static constexpr DAddr max_pin_area = supports_pinning ? 1ULL << pin_bits : first_address;
29 static constexpr DAddr max_device_area = 1ULL << device_virtual_bits;
30
31 DeviceMemoryManagerAllocator()
32 : pin_allocator(first_address),
33 main_allocator(supports_pinning ? 1ULL << pin_bits : first_address) {}
34
35 std::conditional_t<supports_pinning, Common::FlatAllocator<DAddr, 0, pin_bits>, EmptyAllocator>
36 pin_allocator;
37 Common::FlatAllocator<DAddr, 0, device_virtual_bits> main_allocator;
38
39 /// Returns true when vaddr -> vaddr+size is fully contained in the buffer
40 template <bool pin_area>
41 [[nodiscard]] bool IsInBounds(VAddr addr, u64 size) const noexcept {
42 if constexpr (pin_area) {
43 return addr >= 0 && addr + size <= max_pin_area;
44 } else {
45 return addr >= max_pin_area && addr + size <= max_device_area;
46 }
47 }
48
49 DAddr Allocate(size_t size) {
50 return main_allocator.Allocate(size);
51 }
52
53 DAddr AllocatePinned(size_t size) {
54 return pin_allocator.Allocate(size);
55 }
56
57 void DoInRange(DAddr address, size_t size, auto pin_func, auto main_func) {
58 if (IsInBounds<true>(address, size)) {
59 pin_func(address, size);
60 return;
61 }
62 if (IsInBounds<false>(address, size)) {
63 main_func(address, size);
64 return;
65 }
66 DAddr end_size = address + size - max_pin_area;
67 DAddr end_size2 = max_pin_area - address;
68 pin_func(address, end_size2);
69 main_func(max_pin_area, end_size);
70 }
71
72 void AllocateFixed(DAddr b_address, size_t b_size) {
73 if constexpr (supports_pinning) {
74 DoInRange(
75 b_address, b_size,
76 [this](DAddr address, size_t size) { pin_allocator.AllocateFixed(address, size); },
77 [this](DAddr address, size_t size) {
78 main_allocator.AllocateFixed(address, size);
79 });
80 } else {
81 main_allocator.AllocateFixed(b_address, b_size);
82 }
83 }
84
85 void Free(DAddr b_address, size_t b_size) {
86 if constexpr (supports_pinning) {
87 DoInRange(
88 b_address, b_size,
89 [this](DAddr address, size_t size) { pin_allocator.Free(address, size); },
90 [this](DAddr address, size_t size) { main_allocator.Free(address, size); });
91 } else {
92 main_allocator.Free(b_address, b_size);
93 }
94 }
95};
96
97template <typename Traits>
98DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
99 : physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())},
100 interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS),
101 compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)) {
102 impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
103}
104
105template <typename Traits>
106DeviceMemoryManager<Traits>::~DeviceMemoryManager() = default;
107
108template <typename Traits>
109void DeviceMemoryManager<Traits>::BindInterface(DeviceInterface* interface_) {
110 interface = interface_;
111}
112
113template <typename Traits>
114DAddr DeviceMemoryManager<Traits>::Allocate(size_t size) {
115 return impl->Allocate(size);
116}
117
118template <typename Traits>
119void DeviceMemoryManager<Traits>::AllocateFixed(DAddr start, size_t size) {
120 return impl->AllocateFixed(start, size);
121}
122
123template <typename Traits>
124DAddr DeviceMemoryManager<Traits>::AllocatePinned(size_t size) {
125 return impl->AllocatePinned(size);
126}
127
128template <typename Traits>
129void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) {
130 impl->Free(start, size);
131}
132
133template <typename Traits>
134void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size,
135 size_t p_id) {
136 Core::Memory::Memory* process_memory = registered_processes[p_id];
137 size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
138 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
139 std::atomic_thread_fence(std::memory_order_acquire);
140 for (size_t i = 0; i < num_pages; i++) {
141 auto* ptr = process_memory->GetPointer(
142 Common::ProcessAddress(virtual_address + i * Memory::YUZU_PAGESIZE));
143 if (ptr == nullptr) [[unlikely]] {
144 compressed_physical_ptr[start_page_d + i] = 0;
145 continue;
146 }
147 auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
148 compressed_physical_ptr[start_page_d + i] = phys_addr;
149 compressed_device_addr[phys_addr - 1U] = static_cast<u32>(start_page_d + i);
150 }
151 std::atomic_thread_fence(std::memory_order_release);
152}
153
154template <typename Traits>
155void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
156 size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
157 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
158 std::atomic_thread_fence(std::memory_order_acquire);
159 for (size_t i = 0; i < num_pages; i++) {
160 auto phys_addr = compressed_physical_ptr[start_page_d + i];
161 compressed_physical_ptr[start_page_d + i] = 0;
162 if (phys_addr != 0) {
163 compressed_device_addr[phys_addr - 1] = 0;
164 }
165 }
166 std::atomic_thread_fence(std::memory_order_release);
167}
168
169template <typename Traits>
170template <typename T>
171T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) {
172 const size_t index = address >> Memory::YUZU_PAGEBITS;
173 const size_t offset = address & Memory::YUZU_PAGEMASK;
174 auto phys_addr = compressed_physical_ptr[index];
175 if (phys_addr == 0) [[unlikely]] {
176 return nullptr;
177 }
178 return GetPointerFromRaw<T>(
179 static_cast<PAddr>(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset));
180}
181
182template <typename Traits>
183template <typename T>
184const T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) const {
185 const size_t index = address >> Memory::YUZU_PAGEBITS;
186 const size_t offset = address & Memory::YUZU_PAGEMASK;
187 auto phys_addr = compressed_physical_ptr[index];
188 if (phys_addr == 0) [[unlikely]] {
189 return nullptr;
190 }
191 return GetPointerFromRaw<T>(
192 static_cast<PAddr>(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset));
193}
194
195template <typename Traits>
196template <typename T>
197void DeviceMemoryManager<Traits>::Write(DAddr address, T value) {
198 T* ptr = GetPointer<T>(address);
199 if (!ptr) [[unlikely]] {
200 return;
201 }
202 std::memcpy(ptr, &value, sizeof(T));
203}
204
205template <typename Traits>
206template <typename T>
207T DeviceMemoryManager<Traits>::Read(DAddr address) const {
208 const T* ptr = GetPointer<T>(address);
209 T result{};
210 if (!ptr) [[unlikely]] {
211 return result;
212 }
213 std::memcpy(&result, ptr, sizeof(T));
214 return result;
215}
216
217template <typename Traits>
218void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto on_unmapped,
219 auto on_memory, auto increment) {
220 std::size_t remaining_size = size;
221 std::size_t page_index = addr >> Memory::YUZU_PAGEBITS;
222 std::size_t page_offset = addr & Memory::YUZU_PAGEMASK;
223
224 while (remaining_size) {
225 const std::size_t copy_amount =
226 std::min(static_cast<std::size_t>(Memory::YUZU_PAGESIZE) - page_offset, remaining_size);
227 const auto current_vaddr =
228 static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
229 SCOPE_EXIT({
230 page_index++;
231 page_offset = 0;
232 increment(copy_amount);
233 remaining_size -= copy_amount;
234 });
235
236 auto phys_addr = compressed_physical_ptr[page_index];
237 if (phys_addr == 0) {
238 on_unmapped(copy_amount, current_vaddr);
239 continue;
240 }
241 auto* mem_ptr = GetPointerFromRaw<u8>(
242 static_cast<PAddr>(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset));
243 on_memory(copy_amount, mem_ptr);
244 }
245}
246
247template <typename Traits>
248void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) {
249 WalkBlock(
250 address, size,
251 [&](size_t copy_amount, DAddr current_vaddr) {
252 LOG_ERROR(
253 HW_Memory,
254 "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
255 current_vaddr, address, size);
256 std::memset(dest_pointer, 0, copy_amount);
257 },
258 [&](size_t copy_amount, const u8* const src_ptr) {
259 std::memcpy(dest_pointer, src_ptr, copy_amount);
260 },
261 [&](const std::size_t copy_amount) {
262 dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount;
263 });
264}
265
266template <typename Traits>
267void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, void* src_pointer, size_t size) {
268 WalkBlock(
269 address, size,
270 [&](size_t copy_amount, DAddr current_vaddr) {
271 LOG_ERROR(
272 HW_Memory,
273 "Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
274 current_vaddr, address, size);
275 },
276 [&](size_t copy_amount, u8* const dst_ptr) {
277 std::memcpy(dst_ptr, src_pointer, copy_amount);
278 },
279 [&](const std::size_t copy_amount) {
280 src_pointer = static_cast<u8*>(src_pointer) + copy_amount;
281 });
282}
283
284template <typename Traits>
285size_t DeviceMemoryManager<Traits>::RegisterProcess(Memory::Memory* memory_interface) {
286 size_t new_id;
287 if (!id_pool.empty()) {
288 new_id = id_pool.front();
289 id_pool.pop_front();
290 registered_processes[new_id] = memory_interface;
291 } else {
292 registered_processes.emplace_back(memory_interface);
293 new_id = registered_processes.size() - 1U;
294 }
295 return new_id;
296}
297
298template <typename Traits>
299void DeviceMemoryManager<Traits>::UnregisterProcess(size_t id) {
300 registered_processes[id] = nullptr;
301 id_pool.push_front(id);
302}
303
304} // namespace Core \ No newline at end of file
diff --git a/src/video_core/host1x/gpu_device_memory_manager.cpp b/src/video_core/host1x/gpu_device_memory_manager.cpp
new file mode 100644
index 000000000..2ca445081
--- /dev/null
+++ b/src/video_core/host1x/gpu_device_memory_manager.cpp
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/device_memory_manager.inc"
5#include "video_core/host1x/gpu_device_memory_manager.h"
6#include "video_core/rasterizer_interface.h"
7
8template struct Core::DeviceMemoryManagerAllocator<Tegra::MaxwellDeviceTraits>;
9template class Core::DeviceMemoryManager<Tegra::MaxwellDeviceTraits>;
10
11template const u8* Tegra::MaxwellDeviceMemoryManager::GetPointer<u8>(DAddr addr) const;
12template u8* Tegra::MaxwellDeviceMemoryManager::GetPointer<u8>(DAddr addr);
13
14template u8 Tegra::MaxwellDeviceMemoryManager::Read<u8>(DAddr addr) const;
15template u16 Tegra::MaxwellDeviceMemoryManager::Read<u16>(DAddr addr) const;
16template u32 Tegra::MaxwellDeviceMemoryManager::Read<u32>(DAddr addr) const;
17template u64 Tegra::MaxwellDeviceMemoryManager::Read<u64>(DAddr addr) const;
18template void Tegra::MaxwellDeviceMemoryManager::Write<u8>(DAddr addr, u8 data);
19template void Tegra::MaxwellDeviceMemoryManager::Write<u16>(DAddr addr, u16 data);
20template void Tegra::MaxwellDeviceMemoryManager::Write<u32>(DAddr addr, u32 data);
21template void Tegra::MaxwellDeviceMemoryManager::Write<u64>(DAddr addr, u64 data); \ No newline at end of file
diff --git a/src/video_core/host1x/gpu_device_memory_manager.h b/src/video_core/host1x/gpu_device_memory_manager.h
new file mode 100644
index 000000000..30ad52017
--- /dev/null
+++ b/src/video_core/host1x/gpu_device_memory_manager.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/device_memory_manager.h"
5
6namespace VideoCore {
7class RasterizerInterface;
8}
9
10namespace Tegra {
11
12struct MaxwellDeviceTraits {
13 static constexpr bool supports_pinning = true;
14 static constexpr size_t device_virtual_bits = 34;
15 using DeviceInterface = typename VideoCore::RasterizerInterface;
16};
17
18using MaxwellDeviceMemoryManager = Core::DeviceMemoryManager<MaxwellDeviceTraits>;
19
20} // namespace Tegra \ No newline at end of file