mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-23 10:35:03 +00:00
Page manager: batch protect, masked ranges
This commit is contained in:
parent
14a33d35a2
commit
2fc62b5b5f
@ -227,7 +227,7 @@ public:
|
||||
return FirstRangeFrom(0);
|
||||
}
|
||||
|
||||
Range LastRegionFrom(size_t end) const {
|
||||
Range LastRangeFrom(size_t end) const {
|
||||
if (end == 0) {
|
||||
return {0, 0};
|
||||
}
|
||||
@ -289,8 +289,8 @@ public:
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
inline constexpr Range LastRegion() const {
|
||||
return LastRegionFrom(N);
|
||||
inline constexpr Range LastRaange() const {
|
||||
return LastRangeFrom(N);
|
||||
}
|
||||
|
||||
inline constexpr size_t Size() const {
|
||||
|
@ -48,9 +48,11 @@ struct PageManager::Impl {
|
||||
u8 AddDelta() {
|
||||
if constexpr (delta == 1) {
|
||||
return ++num_watchers;
|
||||
} else {
|
||||
} else if constexpr (delta == -1) {
|
||||
ASSERT_MSG(num_watchers > 0, "Not enough watchers");
|
||||
return --num_watchers;
|
||||
} else {
|
||||
return num_watchers;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -223,22 +225,21 @@ struct PageManager::Impl {
|
||||
PageState& state = cached_pages[page];
|
||||
|
||||
// Apply the change to the page state
|
||||
const u8 new_count = state.AddDelta<track ? 1 : -1>();
|
||||
const u8 new_count = state.AddDelta < track ? 1 : -1 > ();
|
||||
|
||||
// If the protection changed add pending (un)protect action
|
||||
if (auto new_perms = state.Perm(); new_perms != perms) [[unlikely]] {
|
||||
// If the protection changed add pending (un)protect action
|
||||
release_pending();
|
||||
perms = new_perms;
|
||||
} else if (range_bytes != 0) {
|
||||
// If the protection did not change, extend the current range
|
||||
range_bytes += PAGE_SIZE;
|
||||
}
|
||||
|
||||
// If the page must be (un)protected, add it to the pending range
|
||||
if ((new_count == 0 && !track) || (new_count == 1 && track)) {
|
||||
if (range_bytes == 0) {
|
||||
range_begin = page;
|
||||
}
|
||||
range_bytes += PAGE_SIZE;
|
||||
} else {
|
||||
release_pending();
|
||||
// Only start a new range if the page must be (un)protected
|
||||
if (range_bytes == 0 && ((new_count == 0 && !track) || (new_count == 1 && track))) {
|
||||
range_begin = page;
|
||||
range_bytes = PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,13 +254,70 @@ struct PageManager::Impl {
|
||||
}
|
||||
|
||||
template <bool track>
|
||||
void UpdatePageWatchersMasked(VAddr addr, RegionBits& mask) {
|
||||
void UpdatePageWatchersMasked(VAddr base_addr, RegionBits& mask) {
|
||||
RENDERER_TRACE;
|
||||
boost::container::small_vector<UpdateProtectRange, 16> update_ranges;
|
||||
|
||||
auto start_range = mask.FirstRange();
|
||||
auto end_range = mask.LastRaange();
|
||||
|
||||
if (start_range.second == end_range.second) {
|
||||
// Optimization: if all pages are contiguous, use the regular UpdatePageWatchers
|
||||
const VAddr start_addr = base_addr + (start_range.first << PAGE_BITS);
|
||||
const u64 size = (start_range.second - start_range.first) << PAGE_BITS;
|
||||
|
||||
UpdatePageWatchers<track>(start_addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock lk(lock);
|
||||
|
||||
size_t base_page = (base_addr >> PAGE_BITS);
|
||||
auto perms = cached_pages[base_page + start_range.first].Perm();
|
||||
u64 range_begin = 0;
|
||||
u64 range_bytes = 0;
|
||||
|
||||
const auto release_pending = [&] {
|
||||
if (range_bytes > 0) {
|
||||
RENDERER_TRACE;
|
||||
// Add pending (un)protect action
|
||||
update_ranges.push_back({range_begin << PAGE_BITS, range_bytes, perms});
|
||||
range_bytes = 0;
|
||||
}
|
||||
};
|
||||
|
||||
for (size_t page = start_range.first; page <= end_range.second; ++page) {
|
||||
PageState& state = cached_pages[base_page + page];
|
||||
const bool update = mask.Get(page);
|
||||
|
||||
// Apply the change to the page state
|
||||
const u8 new_count =
|
||||
update ? state.AddDelta < track ? 1 : -1 > () : state.AddDelta<0>();
|
||||
|
||||
if (auto new_perms = state.Perm(); new_perms != perms) [[unlikely]] {
|
||||
// If the protection changed add pending (un)protect action
|
||||
release_pending();
|
||||
perms = new_perms;
|
||||
} else if (range_bytes != 0) {
|
||||
// If the protection did not change, extend the current range
|
||||
range_bytes += PAGE_SIZE;
|
||||
}
|
||||
|
||||
// If the page is not being updated, skip it
|
||||
if (!update) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only start a new range if the page must be (un)protected
|
||||
if (range_bytes == 0 && ((new_count == 0 && !track) || (new_count == 1 && track))) {
|
||||
range_begin = base_page + page;
|
||||
range_bytes = PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Add pending (un)protect action
|
||||
release_pending();
|
||||
}
|
||||
|
||||
// Flush deferred protects
|
||||
@ -294,7 +352,14 @@ void PageManager::UpdatePageWatchers(VAddr addr, u64 size) const {
|
||||
impl->UpdatePageWatchers<track>(addr, size);
|
||||
}
|
||||
|
||||
template <bool track>
|
||||
void PageManager::UpdatePageWatchersMasked(VAddr base_addr, RegionBits& mask) const {
|
||||
impl->UpdatePageWatchersMasked<track>(base_addr, mask);
|
||||
}
|
||||
|
||||
template void PageManager::UpdatePageWatchers<true>(VAddr addr, u64 size) const;
|
||||
template void PageManager::UpdatePageWatchers<false>(VAddr addr, u64 size) const;
|
||||
template void PageManager::UpdatePageWatchersMasked<true>(VAddr base_addr, RegionBits& mask) const;
|
||||
template void PageManager::UpdatePageWatchersMasked<false>(VAddr base_addr, RegionBits& mask) const;
|
||||
|
||||
} // namespace VideoCore
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
/// Updates watches in the pages touching the specified region
|
||||
/// using a mask.
|
||||
template <bool track>
|
||||
void UpdatePageWatchersMasked(VAddr addr, RegionBits& mask) const;
|
||||
void UpdatePageWatchersMasked(VAddr base_addr, RegionBits& mask) const;
|
||||
|
||||
/// Returns page aligned address.
|
||||
static constexpr VAddr GetPageAddr(VAddr addr) {
|
||||
|
Loading…
Reference in New Issue
Block a user