From 2ea7ff6b1480483c9e8161715de6f0c5188e91c5 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 26 May 2025 03:11:08 +0300 Subject: [PATCH] rsx/util: Split address_range into a sized address_range template --- Utilities/address_range.h | 154 ++++++++++++--------- rpcs3/Emu/Memory/vm.h | 4 +- rpcs3/Emu/RSX/Common/texture_cache.h | 8 +- rpcs3/Emu/RSX/Common/texture_cache_utils.h | 8 +- rpcs3/Emu/RSX/rsx_utils.h | 2 +- rpcs3/tests/test_address_range.cpp | 18 +-- 6 files changed, 108 insertions(+), 86 deletions(-) diff --git a/Utilities/address_range.h b/Utilities/address_range.h index 1ac39c26a1..ba07651b4e 100644 --- a/Utilities/address_range.h +++ b/Utilities/address_range.h @@ -8,65 +8,73 @@ namespace utils { + template class address_range_vector; /** * Helpers */ - static inline u32 page_start(u32 addr) + template + T page_start(T addr) { - return addr & ~(get_page_size() - 1); + return addr & ~static_cast(get_page_size() - 1); } - static inline u32 next_page(u32 addr) + template + static inline T next_page(T addr) { - return page_start(addr) + get_page_size(); + return page_start(addr) + static_cast(get_page_size()); } - static inline u32 page_end(u32 addr) + template + static inline T page_end(T addr) { return next_page(addr) - 1; } - static inline u32 is_page_aligned(u32 val) + template + static inline T is_page_aligned(T val) { - return (val & (get_page_size() - 1)) == 0; + return (val & static_cast(get_page_size() - 1)) == 0; } /** * Address Range utility class */ - class address_range32 + template + class address_range { public: - u32 start = umax; // First address in range - u32 end = 0; // Last address + T start = umax; // First address in range + T end = 0; // Last address + + using signed_type_t = std::make_signed::type; private: // Helper constexprs - static constexpr inline bool range_overlaps(u32 start1, u32 end1, u32 start2, u32 end2) + static constexpr inline bool range_overlaps(T start1, T end1, T start2, T end2) { return (start1 <= end2 && start2 <= end1); } - static constexpr inline bool address_overlaps(u32 address, u32 start, u32 end) + static constexpr inline bool address_overlaps(T address, T start, T end) { return (start <= address && address <= end); } - static constexpr inline bool range_inside_range(u32 start1, u32 end1, u32 start2, u32 end2) + static constexpr inline bool range_inside_range(T start1, T end1, T start2, T end2) { return (start1 >= start2 && end1 <= end2); } - constexpr address_range32(u32 _start, u32 _end) : start(_start), end(_end) {} + constexpr address_range(T _start, T _end) : start(_start), end(_end) {} public: // Constructors - constexpr address_range32() = default; + constexpr address_range() = default; - static constexpr address_range32 start_length(u32 _start, u32 _length) + static constexpr address_range start_length(T _start, T _length) { if (!_length) { @@ -76,57 +84,57 @@ namespace utils return {_start, _start + (_length - 1)}; } - static constexpr address_range32 start_end(u32 _start, u32 _end) + static constexpr address_range start_end(T _start, T _end) { return {_start, _end}; } // Length - u32 length() const + T length() const { AUDIT(valid()); return end - start + 1; } - void set_length(const u32 new_length) + void set_length(const T new_length) { end = start + new_length - 1; ensure(valid()); } - u32 next_address() const + T next_address() const { return end + 1; } - u32 prev_address() const + T prev_address() const { return start - 1; } // Overlapping checks - bool overlaps(const address_range32 &other) const + bool overlaps(const address_range& other) const { AUDIT(valid() && other.valid()); return range_overlaps(start, end, other.start, other.end); } - bool overlaps(const u32 addr) const + bool overlaps(const T addr) const { AUDIT(valid()); return address_overlaps(addr, start, end); } - bool inside(const address_range32 &other) const + bool inside(const address_range& other) const { AUDIT(valid() && other.valid()); return range_inside_range(start, end, other.start, other.end); } - inline bool inside(const address_range_vector &vec) const; - inline bool overlaps(const address_range_vector &vec) const; + inline bool inside(const address_range_vector& vec) const; + inline bool overlaps(const address_range_vector& vec) const; - bool touches(const address_range32 &other) const + bool touches(const address_range& other) const { AUDIT(valid() && other.valid()); // returns true if there is overlap, or if sections are side-by-side @@ -134,7 +142,7 @@ namespace utils } // Utilities - s32 signed_distance(const address_range32 &other) const + signed_type_t signed_distance(const address_range& other) const { if (touches(other)) { @@ -144,15 +152,15 @@ namespace utils // other after this if (other.start > end) { - return static_cast(other.start - end - 1); + return static_cast(other.start - end - 1); } // this after other AUDIT(start > other.end); - return -static_cast(start - other.end - 1); + return -static_cast(start - other.end - 1); } - u32 distance(const address_range32 &other) const + T distance(const address_range& other) const { if (touches(other)) { @@ -170,7 +178,7 @@ namespace utils return (start - other.end - 1); } - address_range32 get_min_max(const address_range32 &other) const + address_range get_min_max(const address_range& other) const { return { std::min(valid() ? start : umax, other.valid() ? other.start : umax), @@ -178,7 +186,7 @@ namespace utils }; } - void set_min_max(const address_range32 &other) + void set_min_max(const address_range& other) { *this = get_min_max(other); } @@ -188,7 +196,7 @@ namespace utils return (valid() && is_page_aligned(start) && is_page_aligned(length())); } - address_range32 to_page_range() const + address_range to_page_range() const { AUDIT(valid()); return { page_start(start), page_end(end) }; @@ -202,7 +210,7 @@ namespace utils AUDIT(is_page_range()); } - address_range32 get_intersect(const address_range32 &clamp) const + address_range get_intersect(const address_range& clamp) const { if (!valid() || !clamp.valid()) { @@ -212,7 +220,7 @@ namespace utils return { std::max(start, clamp.start), std::min(end, clamp.end) }; } - void intersect(const address_range32 &clamp) + void intersect(const address_range& clamp) { if (!clamp.valid()) { @@ -238,7 +246,7 @@ namespace utils } // Comparison Operators - bool operator ==(const address_range32& other) const + bool operator ==(const address_range& other) const { return (start == other.start && end == other.end); } @@ -252,21 +260,27 @@ namespace utils } }; - static inline address_range32 page_for(u32 addr) + using address_range16 = address_range; + using address_range32 = address_range; + using address_range64 = address_range; + + template + static inline address_range page_for(T addr) { - return address_range32::start_end(page_start(addr), page_end(addr)); + return address_range::start_end(page_start(addr), page_end(addr)); } /** * Address Range Vector utility class * - * Collection of address_range32 objects. Allows for merging and removing ranges from the set. + * Collection of address_range objects. Allows for merging and removing ranges from the set. */ + template class address_range_vector { public: - using vector_type = std::vector; + using vector_type = std::vector>; using iterator = vector_type::iterator; using const_iterator = vector_type::const_iterator; using size_type = vector_type::size_type; @@ -280,8 +294,8 @@ namespace utils inline void clear() { data.clear(); } inline size_type size() const { return data.size(); } inline bool empty() const { return data.empty(); } - inline address_range32& operator[](size_type n) { return data[n]; } - inline const address_range32& operator[](size_type n) const { return data[n]; } + inline address_range& operator[](size_type n) { return data[n]; } + inline const address_range& operator[](size_type n) const { return data[n]; } inline iterator begin() { return data.begin(); } inline const_iterator begin() const { return data.begin(); } inline iterator end() { return data.end(); } @@ -289,7 +303,7 @@ namespace utils // Search for ranges that touch new_range. If found, merge instead of adding new_range. // When adding a new range, re-use invalid ranges whenever possible - void merge(const address_range32 &new_range) + void merge(const address_range& new_range) { // Note the case where we have // AAAA BBBB @@ -301,8 +315,8 @@ namespace utils return; } - address_range32 *found = nullptr; - address_range32 *invalid = nullptr; + address_range *found = nullptr; + address_range *invalid = nullptr; for (auto &existing : data) { @@ -347,22 +361,22 @@ namespace utils AUDIT(check_consistency()); } - void merge(const address_range_vector &other) + void merge(const address_range_vector& other) { - for (const address_range32 &new_range : other) + for (const address_range& new_range : other) { merge(new_range); } } // Exclude a given range from data - void exclude(const address_range32 &exclusion) + void exclude(const address_range& exclusion) { // Note the case where we have // AAAAAAA // EEE // where data={A} and exclusion=E. - // In this case, we need to reduce A to the head (before E starts), and then create a new address_range32 B for the tail (after E ends), i.e. + // In this case, we need to reduce A to the head (before E starts), and then create a new address_range B for the tail (after E ends), i.e. // AA BB // EEE @@ -371,13 +385,13 @@ namespace utils return; } - address_range32 *invalid = nullptr; // try to re-use an invalid range instead of calling push_back + address_range *invalid = nullptr; // try to re-use an invalid range instead of calling push_back // We use index access because we might have to push_back within the loop, which could invalidate the iterators size_type _size = data.size(); for (size_type n = 0; n < _size; ++n) { - address_range32 &existing = data[n]; + address_range& existing = data[n]; if (!existing.valid()) { @@ -430,7 +444,7 @@ namespace utils else { // IMPORTANT: adding to data invalidates "existing". This must be done last! - data.push_back(address_range32::start_end(exclusion.next_address(), tail_end)); + data.push_back(address_range::start_end(exclusion.next_address(), tail_end)); } } } @@ -438,9 +452,9 @@ namespace utils AUDIT(!overlaps(exclusion)); } - void exclude(const address_range_vector &other) + void exclude(const address_range_vector& other) { - for (const address_range32 &exclusion : other) + for (const address_range& exclusion : other) { exclude(exclusion); } @@ -478,25 +492,25 @@ namespace utils } // Test for overlap with a given range - bool overlaps(const address_range32 &range) const + bool overlaps(const address_range& range) const { - return std::any_of(data.cbegin(), data.cend(), [&range](const address_range32& cur) + return std::any_of(data.cbegin(), data.cend(), [&range](const address_range& cur) { return cur.valid() && cur.overlaps(range); }); } - // Test for overlap with a given address_range32 vector - bool overlaps(const address_range_vector &other) const + // Test for overlap with a given address_range vector + bool overlaps(const address_range_vector& other) const { - for (const address_range32 &rng1 : data) + for (const address_range& rng1 : data) { if (!rng1.valid()) { continue; } - for (const address_range32 &rng2 : other.data) + for (const address_range& rng2 : other.data) { if (!rng2.valid()) { @@ -513,18 +527,18 @@ namespace utils } // Test if a given range is fully contained inside this vector - bool contains(const address_range32 &range) const + bool contains(const address_range& range) const { - return std::any_of(this->begin(), this->end(), [&range](const address_range32& cur) + return std::any_of(this->begin(), this->end(), [&range](const address_range& cur) { return cur.valid() && cur.inside(range); }); } // Test if all ranges in this vector are full contained inside a specific range - bool inside(const address_range32 &range) const + bool inside(const address_range& range) const { - return std::all_of(this->begin(), this->end(), [&range](const address_range32& cur) + return std::all_of(this->begin(), this->end(), [&range](const address_range& cur) { return !cur.valid() || cur.inside(range); }); @@ -547,16 +561,22 @@ namespace utils // These declarations must be done after address_range_vector has been defined - bool address_range32::inside(const address_range_vector &vec) const + template + bool address_range::inside(const address_range_vector& vec) const { return vec.contains(*this); } - bool address_range32::overlaps(const address_range_vector &vec) const + template + bool address_range::overlaps(const address_range_vector& vec) const { return vec.overlaps(*this); } + using address_range_vector16 = address_range_vector; + using address_range_vector32 = address_range_vector; + using address_range_vector64 = address_range_vector; + } // namespace utils diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 98800055a5..3c39d0aa4a 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -22,7 +22,9 @@ void ppubreak(ppu_thread& ppu); namespace utils { class shm; - class address_range32; + + template class address_range; + using address_range32 = address_range; } namespace vm diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 2eeab39ecb..91e41e6179 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -685,7 +685,7 @@ namespace rsx // Merges the protected ranges of the sections in "sections" into "result" - void merge_protected_ranges(address_range_vector &result, const std::vector §ions) + void merge_protected_ranges(address_range_vector32 &result, const std::vector §ions) { result.reserve(result.size() + sections.size()); @@ -704,7 +704,7 @@ namespace rsx // Otherwise the page protections will end up incorrect and things will break! void unprotect_set(thrashed_set& data) { - auto protect_ranges = [](address_range_vector& _set, utils::protection _prot) + auto protect_ranges = [](address_range_vector32& _set, utils::protection _prot) { //u32 count = 0; for (auto &range : _set) @@ -734,8 +734,8 @@ namespace rsx AUDIT(data.is_flushed()); // Merge ranges to unprotect - address_range_vector ranges_to_unprotect; - address_range_vector ranges_to_protect_ro; + address_range_vector32 ranges_to_unprotect; + address_range_vector32 ranges_to_protect_ro; ranges_to_unprotect.reserve(data.sections_to_unprotect.size() + data.sections_to_flush.size() + data.sections_to_exclude.size()); merge_protected_ranges(ranges_to_unprotect, data.sections_to_unprotect); diff --git a/rpcs3/Emu/RSX/Common/texture_cache_utils.h b/rpcs3/Emu/RSX/Common/texture_cache_utils.h index 97b02e8f9d..8c5defdd0b 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache_utils.h +++ b/rpcs3/Emu/RSX/Common/texture_cache_utils.h @@ -928,7 +928,7 @@ namespace rsx return get_bounds(bounds).overlaps(other); } - inline bool overlaps(const address_range_vector& other, section_bounds bounds) const + inline bool overlaps(const address_range_vector32& other, section_bounds bounds) const { return get_bounds(bounds).overlaps(other); } @@ -943,7 +943,7 @@ namespace rsx return get_bounds(bounds).inside(other); } - inline bool inside(const address_range_vector& other, section_bounds bounds) const + inline bool inside(const address_range_vector32& other, section_bounds bounds) const { return get_bounds(bounds).inside(other); } @@ -1088,7 +1088,7 @@ namespace rsx rsx::texture_upload_context context = rsx::texture_upload_context::shader_read; rsx::texture_dimension_extended image_type = rsx::texture_dimension_extended::texture_dimension_2d; - address_range_vector flush_exclusions; // Address ranges that will be skipped during flush + address_range_vector32 flush_exclusions; // Address ranges that will be skipped during flush predictor_type *m_predictor = nullptr; usz m_predictor_key_hash = 0; @@ -1553,7 +1553,7 @@ namespace rsx // Otherwise, we need to filter the memcpy with our flush exclusions // Should be relatively rare - address_range_vector vec; + address_range_vector32 vec; vec.merge(copy_range); vec.exclude(flush_exclusions); diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 5b7c09cf5d..7a0aa3c14f 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -16,7 +16,7 @@ namespace rsx { // Import address_range32 utilities using utils::address_range32; - using utils::address_range_vector; + using utils::address_range_vector32; using utils::page_for; using utils::page_start; using utils::page_end; diff --git a/rpcs3/tests/test_address_range.cpp b/rpcs3/tests/test_address_range.cpp index c75483bcc5..44ad134646 100644 --- a/rpcs3/tests/test_address_range.cpp +++ b/rpcs3/tests/test_address_range.cpp @@ -302,10 +302,10 @@ namespace utils EXPECT_NE(str.find("1fff"), std::string::npos); } - // Tests for address_range_vector + // Tests for address_range_vector32 TEST(AddressRangeVector, BasicOperations) { - address_range_vector vec; + address_range_vector32 vec; EXPECT_TRUE(vec.empty()); EXPECT_EQ(vec.size(), 0); @@ -322,7 +322,7 @@ namespace utils TEST(AddressRangeVector, MergeOperations) { - address_range_vector vec; + address_range_vector32 vec; // Add non-touching ranges vec.merge(address_range32::start_length(0x1000, 0x1000)); // 0x1000-0x1FFF @@ -347,7 +347,7 @@ namespace utils TEST(AddressRangeVector, ExcludeOperations) { - address_range_vector vec; + address_range_vector32 vec; vec.merge(address_range32::start_length(0x1000, 0x4000)); // 0x1000-0x4FFF // Exclude from the middle @@ -378,7 +378,7 @@ namespace utils // Test excluding with another vector vec.merge(address_range32::start_length(0x1000, 0x4000)); // 0x1000-0x4FFF - address_range_vector vec2; + address_range_vector32 vec2; vec2.merge(address_range32::start_length(0x2000, 0x1000)); // 0x2000-0x2FFF vec2.merge(address_range32::start_length(0x4000, 0x1000)); // 0x4000-0x4FFF @@ -391,7 +391,7 @@ namespace utils TEST(AddressRangeVector, ConsistencyCheck) { - address_range_vector vec; + address_range_vector32 vec; vec.merge(address_range32::start_length(0x1000, 0x1000)); // 0x1000-0x1FFF vec.merge(address_range32::start_length(0x3000, 0x1000)); // 0x3000-0x3FFF @@ -405,7 +405,7 @@ namespace utils TEST(AddressRangeVector, OverlapsAndContains) { - address_range_vector vec; + address_range_vector32 vec; vec.merge(address_range32::start_length(0x1000, 0x1000)); // 0x1000-0x1FFF vec.merge(address_range32::start_length(0x3000, 0x1000)); // 0x3000-0x3FFF @@ -420,11 +420,11 @@ namespace utils EXPECT_FALSE(vec.contains(address_range32::start_length(0x1500, 0x1000))); // 0x1500-0x24FF // Test overlaps with another vector - address_range_vector vec2; + address_range_vector32 vec2; vec2.merge(address_range32::start_length(0x1500, 0x1000)); // 0x1500-0x24FF EXPECT_TRUE(vec.overlaps(vec2)); - address_range_vector vec3; + address_range_vector32 vec3; vec3.merge(address_range32::start_length(0x2000, 0x1000)); // 0x2000-0x2FFF EXPECT_FALSE(vec.overlaps(vec3));