diff options
Diffstat (limited to 'src/video_core/buffer_cache')
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 63 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/map_interval.h | 62 |
2 files changed, 76 insertions, 49 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index e36f85705..7c1737fe2 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -25,6 +25,8 @@ class RasterizerInterface; | |||
| 25 | 25 | ||
| 26 | namespace VideoCommon { | 26 | namespace VideoCommon { |
| 27 | 27 | ||
| 28 | using MapInterval = std::shared_ptr<MapIntervalBase>; | ||
| 29 | |||
| 28 | template <typename TBuffer, typename TBufferType, typename StreamBuffer> | 30 | template <typename TBuffer, typename TBufferType, typename StreamBuffer> |
| 29 | class BufferCache { | 31 | class BufferCache { |
| 30 | public: | 32 | public: |
| @@ -90,7 +92,9 @@ public: | |||
| 90 | 92 | ||
| 91 | std::vector<MapInterval> objects = GetMapsInRange(addr, size); | 93 | std::vector<MapInterval> objects = GetMapsInRange(addr, size); |
| 92 | for (auto& object : objects) { | 94 | for (auto& object : objects) { |
| 93 | Unregister(object); | 95 | if (object->IsRegistered()) { |
| 96 | Unregister(object); | ||
| 97 | } | ||
| 94 | } | 98 | } |
| 95 | } | 99 | } |
| 96 | 100 | ||
| @@ -120,51 +124,54 @@ protected: | |||
| 120 | std::size_t dst_offset, std::size_t size) = 0; | 124 | std::size_t dst_offset, std::size_t size) = 0; |
| 121 | 125 | ||
| 122 | /// Register an object into the cache | 126 | /// Register an object into the cache |
| 123 | void Register(const MapInterval& new_interval, const GPUVAddr gpu_addr) { | 127 | void Register(const MapInterval& new_map) { |
| 124 | const CacheAddr cache_ptr = new_interval.start; | 128 | const CacheAddr cache_ptr = new_map->GetStart(); |
| 125 | const std::size_t size = new_interval.end - new_interval.start; | ||
| 126 | const std::optional<VAddr> cpu_addr = | 129 | const std::optional<VAddr> cpu_addr = |
| 127 | system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr); | 130 | system.GPU().MemoryManager().GpuToCpuAddress(new_map->GetGpuAddress()); |
| 128 | if (!cache_ptr || !cpu_addr) { | 131 | if (!cache_ptr || !cpu_addr) { |
| 129 | LOG_CRITICAL(HW_GPU, "Failed to register buffer with unmapped gpu_address 0x{:016x}", | 132 | LOG_CRITICAL(HW_GPU, "Failed to register buffer with unmapped gpu_address 0x{:016x}", |
| 130 | gpu_addr); | 133 | new_map->GetGpuAddress()); |
| 131 | return; | 134 | return; |
| 132 | } | 135 | } |
| 133 | const IntervalType interval{new_interval.start, new_interval.end}; | 136 | const std::size_t size = new_map->GetEnd() - new_map->GetStart(); |
| 134 | mapped_addresses.insert(interval); | 137 | new_map->SetCpuAddress(*cpu_addr); |
| 135 | map_storage[new_interval] = MapInfo{gpu_addr, *cpu_addr}; | 138 | new_map->MarkAsRegistered(true); |
| 136 | 139 | const IntervalType interval{new_map->GetStart(), new_map->GetEnd()}; | |
| 140 | mapped_addresses.insert({interval, new_map}); | ||
| 137 | rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1); | 141 | rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1); |
| 138 | } | 142 | } |
| 139 | 143 | ||
| 140 | /// Unregisters an object from the cache | 144 | /// Unregisters an object from the cache |
| 141 | void Unregister(const MapInterval& interval) { | 145 | void Unregister(MapInterval& map) { |
| 142 | const MapInfo info = map_storage[interval]; | 146 | const std::size_t size = map->GetEnd() - map->GetStart(); |
| 143 | const std::size_t size = interval.end - interval.start; | 147 | rasterizer.UpdatePagesCachedCount(map->GetCpuAddress(), size, -1); |
| 144 | rasterizer.UpdatePagesCachedCount(info.cpu_addr, size, -1); | 148 | map->MarkAsRegistered(false); |
| 145 | const IntervalType delete_interval{interval.start, interval.end}; | 149 | const IntervalType delete_interval{map->GetStart(), map->GetEnd()}; |
| 146 | mapped_addresses.erase(delete_interval); | 150 | mapped_addresses.erase(delete_interval); |
| 147 | map_storage.erase(interval); | ||
| 148 | } | 151 | } |
| 149 | 152 | ||
| 150 | private: | 153 | private: |
| 154 | MapInterval CreateMap(const CacheAddr start, const CacheAddr end, const GPUVAddr gpu_addr) { | ||
| 155 | return std::make_shared<MapIntervalBase>(start, end, gpu_addr); | ||
| 156 | } | ||
| 157 | |||
| 151 | void MapAddress(const TBuffer& block, const GPUVAddr gpu_addr, const CacheAddr cache_addr, | 158 | void MapAddress(const TBuffer& block, const GPUVAddr gpu_addr, const CacheAddr cache_addr, |
| 152 | const std::size_t size) { | 159 | const std::size_t size) { |
| 153 | 160 | ||
| 154 | std::vector<MapInterval> overlaps = GetMapsInRange(cache_addr, size); | 161 | std::vector<MapInterval> overlaps = GetMapsInRange(cache_addr, size); |
| 155 | if (overlaps.empty()) { | 162 | if (overlaps.empty()) { |
| 156 | const CacheAddr cache_addr_end = cache_addr + size; | 163 | const CacheAddr cache_addr_end = cache_addr + size; |
| 157 | MapInterval new_interval{cache_addr, cache_addr_end}; | 164 | MapInterval new_map = CreateMap(cache_addr, cache_addr_end, gpu_addr); |
| 158 | u8* host_ptr = FromCacheAddr(cache_addr); | 165 | u8* host_ptr = FromCacheAddr(cache_addr); |
| 159 | UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr); | 166 | UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr); |
| 160 | Register(new_interval, gpu_addr); | 167 | Register(new_map); |
| 161 | return; | 168 | return; |
| 162 | } | 169 | } |
| 163 | 170 | ||
| 164 | const CacheAddr cache_addr_end = cache_addr + size; | 171 | const CacheAddr cache_addr_end = cache_addr + size; |
| 165 | if (overlaps.size() == 1) { | 172 | if (overlaps.size() == 1) { |
| 166 | const MapInterval& current_map = overlaps[0]; | 173 | const MapInterval& current_map = overlaps[0]; |
| 167 | if (current_map.IsInside(cache_addr, cache_addr_end)) { | 174 | if (current_map->IsInside(cache_addr, cache_addr_end)) { |
| 168 | return; | 175 | return; |
| 169 | } | 176 | } |
| 170 | } | 177 | } |
| @@ -172,25 +179,25 @@ private: | |||
| 172 | CacheAddr new_end = cache_addr_end; | 179 | CacheAddr new_end = cache_addr_end; |
| 173 | // Calculate new buffer parameters | 180 | // Calculate new buffer parameters |
| 174 | for (auto& overlap : overlaps) { | 181 | for (auto& overlap : overlaps) { |
| 175 | new_start = std::min(overlap.start, new_start); | 182 | new_start = std::min(overlap->GetStart(), new_start); |
| 176 | new_end = std::max(overlap.end, new_end); | 183 | new_end = std::max(overlap->GetEnd(), new_end); |
| 177 | } | 184 | } |
| 178 | GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr; | 185 | GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr; |
| 179 | for (auto& overlap : overlaps) { | 186 | for (auto& overlap : overlaps) { |
| 180 | Unregister(overlap); | 187 | Unregister(overlap); |
| 181 | } | 188 | } |
| 182 | UpdateBlock(block, new_start, new_end, overlaps); | 189 | UpdateBlock(block, new_start, new_end, overlaps); |
| 183 | MapInterval new_interval{new_start, new_end}; | 190 | MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr); |
| 184 | Register(new_interval, new_gpu_addr); | 191 | Register(new_map); |
| 185 | } | 192 | } |
| 186 | 193 | ||
| 187 | void UpdateBlock(const TBuffer& block, CacheAddr start, CacheAddr end, | 194 | void UpdateBlock(const TBuffer& block, CacheAddr start, CacheAddr end, |
| 188 | std::vector<MapInterval>& overlaps) { | 195 | std::vector<MapInterval>& overlaps) { |
| 189 | const IntervalType base_interval{start, end}; | 196 | const IntervalType base_interval{start, end}; |
| 190 | IntervalCache interval_set{}; | 197 | IntervalSet interval_set{}; |
| 191 | interval_set.add(base_interval); | 198 | interval_set.add(base_interval); |
| 192 | for (auto& overlap : overlaps) { | 199 | for (auto& overlap : overlaps) { |
| 193 | const IntervalType subtract{overlap.start, overlap.end}; | 200 | const IntervalType subtract{overlap->GetStart(), overlap->GetEnd()}; |
| 194 | interval_set.subtract(subtract); | 201 | interval_set.subtract(subtract); |
| 195 | } | 202 | } |
| 196 | for (auto& interval : interval_set) { | 203 | for (auto& interval : interval_set) { |
| @@ -210,7 +217,7 @@ private: | |||
| 210 | std::vector<MapInterval> objects{}; | 217 | std::vector<MapInterval> objects{}; |
| 211 | const IntervalType interval{addr, addr + size}; | 218 | const IntervalType interval{addr, addr + size}; |
| 212 | for (auto& pair : boost::make_iterator_range(mapped_addresses.equal_range(interval))) { | 219 | for (auto& pair : boost::make_iterator_range(mapped_addresses.equal_range(interval))) { |
| 213 | objects.emplace_back(pair.lower(), pair.upper()); | 220 | objects.push_back(pair.second); |
| 214 | } | 221 | } |
| 215 | 222 | ||
| 216 | return objects; | 223 | return objects; |
| @@ -322,10 +329,10 @@ private: | |||
| 322 | u64 buffer_offset = 0; | 329 | u64 buffer_offset = 0; |
| 323 | u64 buffer_offset_base = 0; | 330 | u64 buffer_offset_base = 0; |
| 324 | 331 | ||
| 325 | using IntervalCache = boost::icl::interval_set<CacheAddr>; | 332 | using IntervalSet = boost::icl::interval_set<CacheAddr>; |
| 333 | using IntervalCache = boost::icl::interval_map<CacheAddr, MapInterval>; | ||
| 326 | using IntervalType = typename IntervalCache::interval_type; | 334 | using IntervalType = typename IntervalCache::interval_type; |
| 327 | IntervalCache mapped_addresses{}; | 335 | IntervalCache mapped_addresses{}; |
| 328 | std::unordered_map<MapInterval, MapInfo> map_storage; | ||
| 329 | 336 | ||
| 330 | static constexpr u64 block_page_bits{24}; | 337 | static constexpr u64 block_page_bits{24}; |
| 331 | static constexpr u64 block_page_size{1 << block_page_bits}; | 338 | static constexpr u64 block_page_size{1 << block_page_bits}; |
diff --git a/src/video_core/buffer_cache/map_interval.h b/src/video_core/buffer_cache/map_interval.h index c1cd52ca4..a01eddf49 100644 --- a/src/video_core/buffer_cache/map_interval.h +++ b/src/video_core/buffer_cache/map_interval.h | |||
| @@ -4,45 +4,65 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <boost/functional/hash.hpp> | ||
| 8 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 9 | #include "video_core/gpu.h" | 8 | #include "video_core/gpu.h" |
| 10 | 9 | ||
| 11 | namespace VideoCommon { | 10 | namespace VideoCommon { |
| 12 | 11 | ||
| 13 | struct MapInterval { | 12 | class MapIntervalBase { |
| 14 | MapInterval(const CacheAddr start, const CacheAddr end) : start{start}, end{end} {} | 13 | public: |
| 15 | CacheAddr start; | 14 | MapIntervalBase(const CacheAddr start, const CacheAddr end, const GPUVAddr gpu_addr) |
| 16 | CacheAddr end; | 15 | : start{start}, end{end}, gpu_addr{gpu_addr} {} |
| 16 | |||
| 17 | void SetCpuAddress(VAddr new_cpu_addr) { | ||
| 18 | cpu_addr = new_cpu_addr; | ||
| 19 | } | ||
| 20 | |||
| 21 | VAddr GetCpuAddress() const { | ||
| 22 | return cpu_addr; | ||
| 23 | } | ||
| 24 | |||
| 25 | GPUVAddr GetGpuAddress() const { | ||
| 26 | return gpu_addr; | ||
| 27 | } | ||
| 28 | |||
| 17 | bool IsInside(const CacheAddr other_start, const CacheAddr other_end) const { | 29 | bool IsInside(const CacheAddr other_start, const CacheAddr other_end) const { |
| 18 | return (start <= other_start && other_end <= end); | 30 | return (start <= other_start && other_end <= end); |
| 19 | } | 31 | } |
| 20 | 32 | ||
| 21 | bool operator==(const MapInterval& rhs) const { | 33 | bool operator==(const MapIntervalBase& rhs) const { |
| 22 | return std::tie(start, end) == std::tie(rhs.start, rhs.end); | 34 | return std::tie(start, end) == std::tie(rhs.start, rhs.end); |
| 23 | } | 35 | } |
| 24 | 36 | ||
| 25 | bool operator!=(const MapInterval& rhs) const { | 37 | bool operator!=(const MapIntervalBase& rhs) const { |
| 26 | return !operator==(rhs); | 38 | return !operator==(rhs); |
| 27 | } | 39 | } |
| 28 | }; | ||
| 29 | 40 | ||
| 30 | struct MapInfo { | 41 | void MarkAsRegistered(const bool registered) { |
| 31 | GPUVAddr gpu_addr; | 42 | is_registered = registered; |
| 32 | VAddr cpu_addr; | 43 | } |
| 33 | }; | ||
| 34 | 44 | ||
| 35 | } // namespace VideoCommon | 45 | bool IsRegistered() const { |
| 46 | return is_registered; | ||
| 47 | } | ||
| 36 | 48 | ||
| 37 | namespace std { | 49 | CacheAddr GetStart() const { |
| 50 | return start; | ||
| 51 | } | ||
| 38 | 52 | ||
| 39 | template <> | 53 | CacheAddr GetEnd() const { |
| 40 | struct hash<VideoCommon::MapInterval> { | 54 | return end; |
| 41 | std::size_t operator()(const VideoCommon::MapInterval& k) const noexcept { | ||
| 42 | std::size_t a = std::hash<CacheAddr>()(k.start); | ||
| 43 | boost::hash_combine(a, std::hash<CacheAddr>()(k.end)); | ||
| 44 | return a; | ||
| 45 | } | 55 | } |
| 56 | |||
| 57 | private: | ||
| 58 | CacheAddr start; | ||
| 59 | CacheAddr end; | ||
| 60 | GPUVAddr gpu_addr; | ||
| 61 | VAddr cpu_addr{}; | ||
| 62 | bool is_write{}; | ||
| 63 | bool is_modified{}; | ||
| 64 | bool is_registered{}; | ||
| 65 | u64 ticks{}; | ||
| 46 | }; | 66 | }; |
| 47 | 67 | ||
| 48 | } // namespace std | 68 | } // namespace VideoCommon |