diff --git a/src/common/bit_array.h b/src/common/bit_array.h index 7da565804..f211bbf95 100644 --- a/src/common/bit_array.h +++ b/src/common/bit_array.h @@ -65,6 +65,45 @@ public: using pointer = const Range*; using reference = const Range&; + BitArray() = default; + BitArray(const BitArray& other) = default; + BitArray& operator=(const BitArray& other) = default; + BitArray(BitArray&& other) noexcept = default; + BitArray& operator=(BitArray&& other) noexcept = default; + ~BitArray() = default; + + BitArray(const BitArray& other, size_t start, size_t end) { + if (start >= end || end > N) { + return; + } + const size_t first_word = start / BITS_PER_WORD; + const size_t last_word = (end - 1) / BITS_PER_WORD; + const size_t start_bit = start % BITS_PER_WORD; + const size_t end_bit = (end - 1) % BITS_PER_WORD; + const u64 start_mask = ~((1ULL << start_bit) - 1); + const u64 end_mask = end_bit == BITS_PER_WORD - 1 ? ~0ULL : (1ULL << (end_bit + 1)) - 1; + if (first_word == last_word) { + data[first_word] = other.data[first_word] & (start_mask & end_mask); + } else { + data[first_word] = other.data[first_word] & start_mask; + size_t i = first_word + 1; +#ifdef BIT_ARRAY_USE_AVX + for (; i + WORDS_PER_AVX <= last_word; i += WORDS_PER_AVX) { + const __m256i current = + _mm256_loadu_si256(reinterpret_cast(&other.data[i])); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(&data[i]), current); + } +#endif + for (; i < last_word; ++i) { + data[i] = other.data[i]; + } + data[last_word] = other.data[last_word] & end_mask; + } + } + + BitArray(const BitArray& other, const Range& range) + : BitArray(other, range.first, range.second) {} + const_iterator begin() const { return Iterator(*this, 0); } @@ -293,7 +332,7 @@ public: return {0, 0}; } - inline constexpr Range LastRaange() const { + inline constexpr Range LastRange() const { return LastRangeFrom(N); } diff --git a/src/video_core/buffer_cache/region_manager.h b/src/video_core/buffer_cache/region_manager.h index b0e072153..2711bdc38 100644 --- a/src/video_core/buffer_cache/region_manager.h +++ b/src/video_core/buffer_cache/region_manager.h @@ -123,12 +123,7 @@ public: static_assert(type != Type::Writeable); RegionBits& bits = GetRegionBits(); - RegionBits mask{}; - mask.SetRange(start_page, end_page); - if constexpr (type == Type::GPU) { - mask &= ~writeable; - } - mask &= bits; + RegionBits mask(bits, start_page, end_page); for (const auto& [start, end] : mask) { func(cpu_addr + start * BYTES_PER_PAGE, (end - start) * BYTES_PER_PAGE); @@ -160,12 +155,7 @@ public: static_assert(type != Type::Writeable); const RegionBits& bits = GetRegionBits(); - RegionBits test{}; - test.SetRange(start_page, end_page); - if constexpr (type == Type::GPU) { - test &= ~writeable; - } - test &= bits; + RegionBits test(bits, start_page, end_page); return test.Any(); } diff --git a/src/video_core/page_manager.cpp b/src/video_core/page_manager.cpp index d539e0924..322eea7d7 100644 --- a/src/video_core/page_manager.cpp +++ b/src/video_core/page_manager.cpp @@ -259,7 +259,7 @@ struct PageManager::Impl { boost::container::small_vector update_ranges; auto start_range = mask.FirstRange(); - auto end_range = mask.LastRaange(); + auto end_range = mask.LastRange(); if (start_range.second == end_range.second) { // Optimization: if all pages are contiguous, use the regular UpdatePageWatchers