mirror of
https://github.com/yuzu-mirror/yuzu.git
synced 2024-11-18 08:29:58 +00:00
NVDRV: Refactor HeapMapper to use RangeSets
This commit is contained in:
parent
01ba6cf610
commit
accccc0cbf
1 changed files with 43 additions and 144 deletions
|
@ -3,110 +3,21 @@
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include <boost/container/small_vector.hpp>
|
#include "common/range_sets.h"
|
||||||
#define BOOST_NO_MT
|
#include "common/range_sets.inc"
|
||||||
#include <boost/pool/detail/mutex.hpp>
|
|
||||||
#undef BOOST_NO_MT
|
|
||||||
#include <boost/icl/interval.hpp>
|
|
||||||
#include <boost/icl/interval_base_set.hpp>
|
|
||||||
#include <boost/icl/interval_set.hpp>
|
|
||||||
#include <boost/icl/split_interval_map.hpp>
|
|
||||||
#include <boost/pool/pool.hpp>
|
|
||||||
#include <boost/pool/pool_alloc.hpp>
|
|
||||||
#include <boost/pool/poolfwd.hpp>
|
|
||||||
|
|
||||||
#include "core/hle/service/nvdrv/core/heap_mapper.h"
|
#include "core/hle/service/nvdrv/core/heap_mapper.h"
|
||||||
#include "video_core/host1x/host1x.h"
|
#include "video_core/host1x/host1x.h"
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
template <typename T>
|
|
||||||
class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::Nvidia::NvCore {
|
namespace Service::Nvidia::NvCore {
|
||||||
|
|
||||||
using IntervalCompare = std::less<DAddr>;
|
|
||||||
using IntervalInstance = boost::icl::interval_type_default<DAddr, std::less>;
|
|
||||||
using IntervalAllocator = boost::fast_pool_allocator<DAddr>;
|
|
||||||
using IntervalSet = boost::icl::interval_set<DAddr>;
|
|
||||||
using IntervalType = typename IntervalSet::interval_type;
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct counter_add_functor : public boost::icl::identity_based_inplace_combine<Type> {
|
|
||||||
// types
|
|
||||||
typedef counter_add_functor<Type> type;
|
|
||||||
typedef boost::icl::identity_based_inplace_combine<Type> base_type;
|
|
||||||
|
|
||||||
// public member functions
|
|
||||||
void operator()(Type& current, const Type& added) const {
|
|
||||||
current += added;
|
|
||||||
if (current < base_type::identity_element()) {
|
|
||||||
current = base_type::identity_element();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// public static functions
|
|
||||||
static void version(Type&){};
|
|
||||||
};
|
|
||||||
|
|
||||||
using OverlapCombine = counter_add_functor<int>;
|
|
||||||
using OverlapSection = boost::icl::inter_section<int>;
|
|
||||||
using OverlapCounter = boost::icl::split_interval_map<DAddr, int>;
|
|
||||||
|
|
||||||
struct HeapMapper::HeapMapperInternal {
|
struct HeapMapper::HeapMapperInternal {
|
||||||
HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : device_memory{host1x.MemoryManager()} {}
|
HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : m_device_memory{host1x.MemoryManager()} {}
|
||||||
~HeapMapperInternal() = default;
|
~HeapMapperInternal() = default;
|
||||||
|
|
||||||
template <typename Func>
|
Common::RangeSet<VAddr> m_temporary_set;
|
||||||
void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size,
|
Common::SplitRangeSet<VAddr> m_mapped_ranges;
|
||||||
Func&& func) {
|
Tegra::MaxwellDeviceMemoryManager& m_device_memory;
|
||||||
const DAddr start_address = cpu_addr;
|
std::mutex m_guard;
|
||||||
const DAddr end_address = start_address + size;
|
|
||||||
const IntervalType search_interval{start_address, end_address};
|
|
||||||
auto it = current_range.lower_bound(search_interval);
|
|
||||||
if (it == current_range.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto end_it = current_range.upper_bound(search_interval);
|
|
||||||
for (; it != end_it; it++) {
|
|
||||||
auto& inter = it->first;
|
|
||||||
DAddr inter_addr_end = inter.upper();
|
|
||||||
DAddr inter_addr = inter.lower();
|
|
||||||
if (inter_addr_end > end_address) {
|
|
||||||
inter_addr_end = end_address;
|
|
||||||
}
|
|
||||||
if (inter_addr < start_address) {
|
|
||||||
inter_addr = start_address;
|
|
||||||
}
|
|
||||||
func(inter_addr, inter_addr_end, it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveEachInOverlapCounter(OverlapCounter& current_range,
|
|
||||||
const IntervalType search_interval, int subtract_value) {
|
|
||||||
bool any_removals = false;
|
|
||||||
current_range.add(std::make_pair(search_interval, subtract_value));
|
|
||||||
do {
|
|
||||||
any_removals = false;
|
|
||||||
auto it = current_range.lower_bound(search_interval);
|
|
||||||
if (it == current_range.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto end_it = current_range.upper_bound(search_interval);
|
|
||||||
for (; it != end_it; it++) {
|
|
||||||
if (it->second <= 0) {
|
|
||||||
any_removals = true;
|
|
||||||
current_range.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (any_removals);
|
|
||||||
}
|
|
||||||
|
|
||||||
IntervalSet base_set;
|
|
||||||
OverlapCounter mapping_overlaps;
|
|
||||||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
|
||||||
std::mutex guard;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
|
HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid,
|
||||||
|
@ -116,60 +27,48 @@ HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size,
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapMapper::~HeapMapper() {
|
HeapMapper::~HeapMapper() {
|
||||||
m_internal->device_memory.Unmap(m_daddress, m_size);
|
// Unmap whatever has been mapped.
|
||||||
|
m_internal->m_mapped_ranges.ForEach([this](VAddr start_addr, VAddr end_addr, s32 count) {
|
||||||
|
const size_t sub_size = end_addr - start_addr;
|
||||||
|
const size_t offset = start_addr - m_vaddress;
|
||||||
|
m_internal->m_device_memory.Unmap(m_daddress + offset, sub_size);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DAddr HeapMapper::Map(VAddr start, size_t size) {
|
DAddr HeapMapper::Map(VAddr start, size_t size) {
|
||||||
std::scoped_lock lk(m_internal->guard);
|
std::scoped_lock lk(m_internal->m_guard);
|
||||||
m_internal->base_set.clear();
|
// Add the mapping range to a temporary range set.
|
||||||
const IntervalType interval{start, start + size};
|
m_internal->m_temporary_set.Clear();
|
||||||
m_internal->base_set.insert(interval);
|
m_internal->m_temporary_set.Add(start, size);
|
||||||
m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
|
|
||||||
[this](VAddr start_addr, VAddr end_addr, int) {
|
// Remove anything that's already mapped from the temporary range set.
|
||||||
const IntervalType other{start_addr, end_addr};
|
m_internal->m_mapped_ranges.ForEachInRange(
|
||||||
m_internal->base_set.subtract(other);
|
start, size, [this](VAddr start_addr, VAddr end_addr, s32) {
|
||||||
|
m_internal->m_temporary_set.Subtract(start_addr, end_addr - start_addr);
|
||||||
});
|
});
|
||||||
if (!m_internal->base_set.empty()) {
|
|
||||||
auto it = m_internal->base_set.begin();
|
// Map anything that has not been mapped yet.
|
||||||
auto end_it = m_internal->base_set.end();
|
m_internal->m_temporary_set.ForEach([this](VAddr start_addr, VAddr end_addr) {
|
||||||
for (; it != end_it; it++) {
|
const size_t sub_size = end_addr - start_addr;
|
||||||
const VAddr inter_addr_end = it->upper();
|
const size_t offset = start_addr - m_vaddress;
|
||||||
const VAddr inter_addr = it->lower();
|
m_internal->m_device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, m_asid);
|
||||||
const size_t offset = inter_addr - m_vaddress;
|
});
|
||||||
const size_t sub_size = inter_addr_end - inter_addr;
|
|
||||||
m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size,
|
// Add the mapping range to the split map, to register the map and overlaps.
|
||||||
m_asid);
|
m_internal->m_mapped_ranges.Add(start, size);
|
||||||
}
|
m_internal->m_temporary_set.Clear();
|
||||||
}
|
return m_daddress + static_cast<DAddr>(start - m_vaddress);
|
||||||
m_internal->mapping_overlaps += std::make_pair(interval, 1);
|
|
||||||
m_internal->base_set.clear();
|
|
||||||
return m_daddress + (start - m_vaddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeapMapper::Unmap(VAddr start, size_t size) {
|
void HeapMapper::Unmap(VAddr start, size_t size) {
|
||||||
std::scoped_lock lk(m_internal->guard);
|
std::scoped_lock lk(m_internal->m_guard);
|
||||||
m_internal->base_set.clear();
|
|
||||||
m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size,
|
// Just subtract the range and whatever is deleted, unmap it.
|
||||||
[this](VAddr start_addr, VAddr end_addr, int value) {
|
m_internal->m_mapped_ranges.Subtract(start, size, [this](VAddr start_addr, VAddr end_addr) {
|
||||||
if (value <= 1) {
|
const size_t sub_size = end_addr - start_addr;
|
||||||
const IntervalType other{start_addr, end_addr};
|
const size_t offset = start_addr - m_vaddress;
|
||||||
m_internal->base_set.insert(other);
|
m_internal->m_device_memory.Unmap(m_daddress + offset, sub_size);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (!m_internal->base_set.empty()) {
|
|
||||||
auto it = m_internal->base_set.begin();
|
|
||||||
auto end_it = m_internal->base_set.end();
|
|
||||||
for (; it != end_it; it++) {
|
|
||||||
const VAddr inter_addr_end = it->upper();
|
|
||||||
const VAddr inter_addr = it->lower();
|
|
||||||
const size_t offset = inter_addr - m_vaddress;
|
|
||||||
const size_t sub_size = inter_addr_end - inter_addr;
|
|
||||||
m_internal->device_memory.Unmap(m_daddress + offset, sub_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const IntervalType to_remove{start, start + size};
|
|
||||||
m_internal->RemoveEachInOverlapCounter(m_internal->mapping_overlaps, to_remove, -1);
|
|
||||||
m_internal->base_set.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::NvCore
|
} // namespace Service::Nvidia::NvCore
|
||||||
|
|
Loading…
Reference in a new issue