Files
KytyPS5/src/graphics/host_gpu/rangeSet.h
T
nmzikandGitHub f6e01e5403
Build and Release KytyPS5 / Build KytyPS5 (Windows) (push) Canceled after 0s
Build and Release KytyPS5 / Build KytyPS5 (macOS) (push) Canceled after 0s
Build and Release KytyPS5 / Build KytyPS5 (Linux) (push) Canceled after 0s
Build and Release KytyPS5 / Release KytyPS5 (push) Canceled after 0s
Optimize bulk memory invalidation (#124)
* Per page -> per range search (optimization)
2026-07-29 05:09:36 +02:00

104 lines
2.7 KiB
C++

#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_
#include "common/assert.h"
#include <algorithm>
#include <cstdint>
#include <map>
#include <vector>
namespace Libs::Graphics {
class RangeSet final {
public:
struct Range {
uint64_t address = 0;
uint64_t size = 0;
};
void Add(uint64_t address, uint64_t size) {
const auto end = End(address, size);
auto it = m_ranges.lower_bound(address);
if (it != m_ranges.begin() && std::prev(it)->second >= address) {
it = std::prev(it);
}
uint64_t begin = address;
uint64_t last = end;
while (it != m_ranges.end() && it->first <= last) {
begin = std::min(begin, it->first);
last = std::max(last, it->second);
it = m_ranges.erase(it);
}
m_ranges.emplace(begin, last);
}
void Subtract(uint64_t address, uint64_t size) {
const auto end = End(address, size);
auto it = m_ranges.lower_bound(address);
if (it != m_ranges.begin() && std::prev(it)->second > address) {
it = std::prev(it);
}
while (it != m_ranges.end() && it->first < end) {
const auto begin = it->first;
const auto last = it->second;
it = m_ranges.erase(it);
if (begin < address) {
m_ranges.emplace(begin, address);
}
if (last > end) {
m_ranges.emplace(end, last);
break;
}
}
}
[[nodiscard]] std::vector<Range> Intersections(uint64_t address, uint64_t size) const {
std::vector<Range> result;
ForEachIntersection(address, size, [&result](Range range) { result.push_back(range); });
return result;
}
[[nodiscard]] bool Contains(uint64_t address, uint64_t size) const {
const auto end = End(address, size);
auto it = m_ranges.upper_bound(address);
if (it == m_ranges.begin()) {
return false;
}
--it;
return it->first <= address && it->second >= end;
}
template <typename Func>
void ForEachIntersection(uint64_t address, uint64_t size, Func&& func) const {
const auto end = End(address, size);
auto it = m_ranges.upper_bound(address);
if (it != m_ranges.begin()) {
--it;
}
for (; it != m_ranges.end() && it->first < end; ++it) {
const auto begin = std::max(address, it->first);
const auto last = std::min(end, it->second);
if (begin < last) {
func(Range {begin, last - begin});
}
}
}
[[nodiscard]] bool Empty() const { return m_ranges.empty(); }
private:
static uint64_t End(uint64_t address, uint64_t size) {
if (address == 0 || size == 0 || size > UINT64_MAX - address) {
EXIT("invalid range-set address or size\n");
}
return address + size;
}
std::map<uint64_t, uint64_t> m_ranges;
};
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_