|
|
@@ -18,10 +18,117 @@
|
|
|
|
|
|
namespace Core {
|
|
|
|
|
|
+namespace {
|
|
|
+
|
|
|
+class PhysicalAddressContainer {
|
|
|
+public:
|
|
|
+ PhysicalAddressContainer() = default;
|
|
|
+ ~PhysicalAddressContainer() = default;
|
|
|
+
|
|
|
+ void GatherValues(u32 start_entry, Common::ScratchBuffer<u32>& buffer) {
|
|
|
+ buffer.resize(8);
|
|
|
+ buffer.resize(0);
|
|
|
+ size_t index = 0;
|
|
|
+ const auto add_value = [&](u32 value) {
|
|
|
+ buffer[index] = value;
|
|
|
+ index++;
|
|
|
+ buffer.resize(index);
|
|
|
+ };
|
|
|
+
|
|
|
+ u32 iter_entry = start_entry;
|
|
|
+ Entry* current = &storage[iter_entry - 1];
|
|
|
+ add_value(current->value);
|
|
|
+ while (current->next_entry != 0) {
|
|
|
+ iter_entry = current->next_entry;
|
|
|
+ current = &storage[iter_entry - 1];
|
|
|
+ add_value(current->value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ u32 Register(u32 value) {
|
|
|
+ return RegisterImplementation(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ void Register(u32 value, u32 start_entry) {
|
|
|
+ auto entry_id = RegisterImplementation(value);
|
|
|
+ u32 iter_entry = start_entry;
|
|
|
+ Entry* current = &storage[iter_entry - 1];
|
|
|
+ while (current->next_entry != 0) {
|
|
|
+ iter_entry = current->next_entry;
|
|
|
+ current = &storage[iter_entry - 1];
|
|
|
+ }
|
|
|
+ current->next_entry = entry_id;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::pair<bool, u32> Unregister(u32 value, u32 start_entry) {
|
|
|
+ u32 iter_entry = start_entry;
|
|
|
+ Entry* previous{};
|
|
|
+ Entry* current = &storage[iter_entry - 1];
|
|
|
+ Entry* next{};
|
|
|
+ bool more_than_one_remaining = false;
|
|
|
+ u32 result_start{start_entry};
|
|
|
+ size_t count = 0;
|
|
|
+ while (current->value != value) {
|
|
|
+ count++;
|
|
|
+ previous = current;
|
|
|
+ iter_entry = current->next_entry;
|
|
|
+ current = &storage[iter_entry - 1];
|
|
|
+ }
|
|
|
+ // Find next
|
|
|
+ u32 next_entry = current->next_entry;
|
|
|
+ if (next_entry != 0) {
|
|
|
+ next = &storage[next_entry - 1];
|
|
|
+ more_than_one_remaining = next->next_entry != 0;
|
|
|
+ }
|
|
|
+ if (previous) {
|
|
|
+ previous->next_entry = next_entry;
|
|
|
+ } else {
|
|
|
+ result_start = next_entry;
|
|
|
+ }
|
|
|
+ free_entries.emplace_back(iter_entry);
|
|
|
+ return std::make_pair(more_than_one_remaining || count > 1, result_start);
|
|
|
+ }
|
|
|
+
|
|
|
+ u32 ReleaseEntry(u32 start_entry) {
|
|
|
+ Entry* current = &storage[start_entry - 1];
|
|
|
+ free_entries.emplace_back(start_entry);
|
|
|
+ return current->value;
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ u32 RegisterImplementation(u32 value) {
|
|
|
+ auto entry_id = GetNewEntry();
|
|
|
+ auto& entry = storage[entry_id - 1];
|
|
|
+ entry.next_entry = 0;
|
|
|
+ entry.value = value;
|
|
|
+ return entry_id;
|
|
|
+ }
|
|
|
+ u32 GetNewEntry() {
|
|
|
+ if (!free_entries.empty()) {
|
|
|
+ u32 result = free_entries.front();
|
|
|
+ free_entries.pop_front();
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ storage.emplace_back();
|
|
|
+ u32 new_entry = static_cast<u32>(storage.size());
|
|
|
+ return new_entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ struct Entry {
|
|
|
+ u32 next_entry{};
|
|
|
+ u32 value{};
|
|
|
+ };
|
|
|
+
|
|
|
+ std::deque<Entry> storage;
|
|
|
+ std::deque<u32> free_entries;
|
|
|
+};
|
|
|
+
|
|
|
struct EmptyAllocator {
|
|
|
EmptyAllocator([[maybe_unused]] DAddr address) {}
|
|
|
};
|
|
|
|
|
|
+} // namespace
|
|
|
+
|
|
|
template <typename DTraits>
|
|
|
struct DeviceMemoryManagerAllocator {
|
|
|
static constexpr bool supports_pinning = DTraits::supports_pinning;
|
|
|
@@ -38,6 +145,7 @@ struct DeviceMemoryManagerAllocator {
|
|
|
std::conditional_t<supports_pinning, Common::FlatAllocator<DAddr, 0, pin_bits>, EmptyAllocator>
|
|
|
pin_allocator;
|
|
|
Common::FlatAllocator<DAddr, 0, device_virtual_bits> main_allocator;
|
|
|
+ PhysicalAddressContainer multi_dev_address;
|
|
|
|
|
|
/// Returns true when vaddr -> vaddr+size is fully contained in the buffer
|
|
|
template <bool pin_area>
|
|
|
@@ -109,6 +217,9 @@ DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memo
|
|
|
cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) {
|
|
|
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
|
|
|
cached_pages = std::make_unique<CachedPages>();
|
|
|
+ for (size_t i = 0; i < 1ULL << (33 - 12); i++) {
|
|
|
+ compressed_device_addr[i] = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
template <typename Traits>
|
|
|
@@ -155,8 +266,19 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size
|
|
|
}
|
|
|
auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
|
|
|
compressed_physical_ptr[start_page_d + i] = phys_addr;
|
|
|
- compressed_device_addr[phys_addr - 1U] = static_cast<u32>(start_page_d + i);
|
|
|
InsertCPUBacking(start_page_d + i, new_vaddress, process_id);
|
|
|
+ const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
|
|
+ const u32 new_dev = static_cast<u32>(start_page_d + i);
|
|
|
+ if (base_dev == 0) [[likely]] {
|
|
|
+ compressed_device_addr[phys_addr - 1U] = new_dev;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ u32 start_id = base_dev & MULTI_MASK;
|
|
|
+ if ((base_dev >> MULTI_FLAG_BITS) == 0) {
|
|
|
+ start_id = impl->multi_dev_address.Register(base_dev);
|
|
|
+ compressed_device_addr[phys_addr - 1U] = MULTI_FLAG | start_id;
|
|
|
+ }
|
|
|
+ impl->multi_dev_address.Register(new_dev, start_id);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -170,12 +292,38 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
|
|
|
auto phys_addr = compressed_physical_ptr[start_page_d + i];
|
|
|
compressed_physical_ptr[start_page_d + i] = 0;
|
|
|
cpu_backing_address[start_page_d + i] = 0;
|
|
|
- if (phys_addr != 0) {
|
|
|
- compressed_device_addr[phys_addr - 1] = 0;
|
|
|
+ if (phys_addr != 0) [[likely]] {
|
|
|
+ const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
|
|
+ if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] {
|
|
|
+ compressed_device_addr[phys_addr - 1] = 0;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ const auto [more_entries, new_start] = impl->multi_dev_address.Unregister(
|
|
|
+ static_cast<u32>(start_page_d + i), base_dev & MULTI_MASK);
|
|
|
+ if (!more_entries) {
|
|
|
+ compressed_device_addr[phys_addr - 1] =
|
|
|
+ impl->multi_dev_address.ReleaseEntry(new_start);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ compressed_device_addr[phys_addr - 1] = new_start | MULTI_FLAG;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+template <typename Traits>
|
|
|
+void DeviceMemoryManager<Traits>::InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer,
|
|
|
+ PAddr address) {
|
|
|
+ size_t phys_addr = address >> page_bits;
|
|
|
+ std::scoped_lock lk(mapping_guard);
|
|
|
+ u32 backing = compressed_device_addr[phys_addr];
|
|
|
+ if ((backing >> MULTI_FLAG_BITS) != 0) {
|
|
|
+ impl->multi_dev_address.GatherValues(backing & MULTI_MASK, buffer);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ buffer.resize(1);
|
|
|
+ buffer[0] = backing;
|
|
|
+}
|
|
|
+
|
|
|
template <typename Traits>
|
|
|
template <typename T>
|
|
|
T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) {
|