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);
|
return FirstRangeFrom(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Range LastRegionFrom(size_t end) const {
|
Range LastRangeFrom(size_t end) const {
|
||||||
if (end == 0) {
|
if (end == 0) {
|
||||||
return {0, 0};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
@ -289,8 +289,8 @@ public:
|
|||||||
return {0, 0};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr Range LastRegion() const {
|
inline constexpr Range LastRaange() const {
|
||||||
return LastRegionFrom(N);
|
return LastRangeFrom(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr size_t Size() const {
|
inline constexpr size_t Size() const {
|
||||||
|
@ -48,9 +48,11 @@ struct PageManager::Impl {
|
|||||||
u8 AddDelta() {
|
u8 AddDelta() {
|
||||||
if constexpr (delta == 1) {
|
if constexpr (delta == 1) {
|
||||||
return ++num_watchers;
|
return ++num_watchers;
|
||||||
} else {
|
} else if constexpr (delta == -1) {
|
||||||
ASSERT_MSG(num_watchers > 0, "Not enough watchers");
|
ASSERT_MSG(num_watchers > 0, "Not enough watchers");
|
||||||
return --num_watchers;
|
return --num_watchers;
|
||||||
|
} else {
|
||||||
|
return num_watchers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -223,22 +225,21 @@ struct PageManager::Impl {
|
|||||||
PageState& state = cached_pages[page];
|
PageState& state = cached_pages[page];
|
||||||
|
|
||||||
// Apply the change to the page state
|
// 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 (auto new_perms = state.Perm(); new_perms != perms) [[unlikely]] {
|
||||||
|
// If the protection changed add pending (un)protect action
|
||||||
release_pending();
|
release_pending();
|
||||||
perms = new_perms;
|
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
|
// Only start a new range if the page must be (un)protected
|
||||||
if ((new_count == 0 && !track) || (new_count == 1 && track)) {
|
if (range_bytes == 0 && ((new_count == 0 && !track) || (new_count == 1 && track))) {
|
||||||
if (range_bytes == 0) {
|
range_begin = page;
|
||||||
range_begin = page;
|
range_bytes = PAGE_SIZE;
|
||||||
}
|
|
||||||
range_bytes += PAGE_SIZE;
|
|
||||||
} else {
|
|
||||||
release_pending();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,13 +254,70 @@ struct PageManager::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <bool track>
|
template <bool track>
|
||||||
void UpdatePageWatchersMasked(VAddr addr, RegionBits& mask) {
|
void UpdatePageWatchersMasked(VAddr base_addr, RegionBits& mask) {
|
||||||
RENDERER_TRACE;
|
RENDERER_TRACE;
|
||||||
boost::container::small_vector<UpdateProtectRange, 16> update_ranges;
|
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);
|
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
|
// Flush deferred protects
|
||||||
@ -294,7 +352,14 @@ void PageManager::UpdatePageWatchers(VAddr addr, u64 size) const {
|
|||||||
impl->UpdatePageWatchers<track>(addr, size);
|
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<true>(VAddr addr, u64 size) const;
|
||||||
template void PageManager::UpdatePageWatchers<false>(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
|
} // namespace VideoCore
|
||||||
|
@ -35,7 +35,7 @@ public:
|
|||||||
/// Updates watches in the pages touching the specified region
|
/// Updates watches in the pages touching the specified region
|
||||||
/// using a mask.
|
/// using a mask.
|
||||||
template <bool track>
|
template <bool track>
|
||||||
void UpdatePageWatchersMasked(VAddr addr, RegionBits& mask) const;
|
void UpdatePageWatchersMasked(VAddr base_addr, RegionBits& mask) const;
|
||||||
|
|
||||||
/// Returns page aligned address.
|
/// Returns page aligned address.
|
||||||
static constexpr VAddr GetPageAddr(VAddr addr) {
|
static constexpr VAddr GetPageAddr(VAddr addr) {
|
||||||
|
Loading…
Reference in New Issue
Block a user