summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-05-16 18:07:03 -0300
committerGravatar ReinUsesLisp2020-05-21 16:02:54 -0300
commit3b0baf746ea6863d38d90521abba95303f321bf3 (patch)
tree5c3b648e083919099f15a45f6e592efcd6e7bac3 /src
parentbuffer_cache: Minor style changes (diff)
downloadyuzu-3b0baf746ea6863d38d90521abba95303f321bf3.tar.gz
yuzu-3b0baf746ea6863d38d90521abba95303f321bf3.tar.xz
yuzu-3b0baf746ea6863d38d90521abba95303f321bf3.zip
buffer_cache: Remove shared pointers
Removing shared pointers is a first step to be able to use intrusive objects and keep allocations close to one another in memory.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h114
-rw-r--r--src/video_core/buffer_cache/map_interval.h28
2 files changed, 72 insertions, 70 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 81134eb1f..eb03879c4 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -29,8 +29,6 @@
29 29
30namespace VideoCommon { 30namespace VideoCommon {
31 31
32using MapInterval = std::shared_ptr<MapIntervalBase>;
33
34template <typename OwnerBuffer, typename BufferType, typename StreamBuffer> 32template <typename OwnerBuffer, typename BufferType, typename StreamBuffer>
35class BufferCache { 33class BufferCache {
36public: 34public:
@@ -76,7 +74,10 @@ public:
76 } 74 }
77 75
78 auto block = GetBlock(cpu_addr, size); 76 auto block = GetBlock(cpu_addr, size);
79 auto map = MapAddress(block, gpu_addr, cpu_addr, size); 77 MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size);
78 if (!map) {
79 return {GetEmptyBuffer(size), 0};
80 }
80 if (is_written) { 81 if (is_written) {
81 map->MarkAsModified(true, GetModifiedTicks()); 82 map->MarkAsModified(true, GetModifiedTicks());
82 if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { 83 if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) {
@@ -130,11 +131,10 @@ public:
130 void FlushRegion(VAddr addr, std::size_t size) { 131 void FlushRegion(VAddr addr, std::size_t size) {
131 std::lock_guard lock{mutex}; 132 std::lock_guard lock{mutex};
132 133
133 std::vector<MapInterval> objects = GetMapsInRange(addr, size); 134 std::vector<MapInterval*> objects = GetMapsInRange(addr, size);
134 std::sort( 135 std::sort(objects.begin(), objects.end(),
135 objects.begin(), objects.end(), 136 [](MapInterval* lhs, MapInterval* rhs) { return lhs->ticks < rhs->ticks; });
136 [](const MapInterval& lhs, const MapInterval& rhs) { return lhs->ticks < rhs->ticks; }); 137 for (MapInterval* object : objects) {
137 for (auto& object : objects) {
138 if (object->is_modified && object->is_registered) { 138 if (object->is_modified && object->is_registered) {
139 mutex.unlock(); 139 mutex.unlock();
140 FlushMap(object); 140 FlushMap(object);
@@ -146,8 +146,8 @@ public:
146 bool MustFlushRegion(VAddr addr, std::size_t size) { 146 bool MustFlushRegion(VAddr addr, std::size_t size) {
147 std::lock_guard lock{mutex}; 147 std::lock_guard lock{mutex};
148 148
149 const std::vector<MapInterval> objects = GetMapsInRange(addr, size); 149 const std::vector<MapInterval*> objects = GetMapsInRange(addr, size);
150 return std::any_of(objects.cbegin(), objects.cend(), [](const MapInterval& map) { 150 return std::any_of(objects.cbegin(), objects.cend(), [](const MapInterval* map) {
151 return map->is_modified && map->is_registered; 151 return map->is_modified && map->is_registered;
152 }); 152 });
153 } 153 }
@@ -156,7 +156,7 @@ public:
156 void InvalidateRegion(VAddr addr, u64 size) { 156 void InvalidateRegion(VAddr addr, u64 size) {
157 std::lock_guard lock{mutex}; 157 std::lock_guard lock{mutex};
158 158
159 std::vector<MapInterval> objects = GetMapsInRange(addr, size); 159 std::vector<MapInterval*> objects = GetMapsInRange(addr, size);
160 for (auto& object : objects) { 160 for (auto& object : objects) {
161 if (object->is_registered) { 161 if (object->is_registered) {
162 Unregister(object); 162 Unregister(object);
@@ -167,7 +167,7 @@ public:
167 void OnCPUWrite(VAddr addr, std::size_t size) { 167 void OnCPUWrite(VAddr addr, std::size_t size) {
168 std::lock_guard lock{mutex}; 168 std::lock_guard lock{mutex};
169 169
170 for (const auto& object : GetMapsInRange(addr, size)) { 170 for (MapInterval* object : GetMapsInRange(addr, size)) {
171 if (object->is_memory_marked && object->is_registered) { 171 if (object->is_memory_marked && object->is_registered) {
172 UnmarkMemory(object); 172 UnmarkMemory(object);
173 object->is_sync_pending = true; 173 object->is_sync_pending = true;
@@ -179,7 +179,7 @@ public:
179 void SyncGuestHost() { 179 void SyncGuestHost() {
180 std::lock_guard lock{mutex}; 180 std::lock_guard lock{mutex};
181 181
182 for (const auto& object : marked_for_unregister) { 182 for (auto& object : marked_for_unregister) {
183 if (object->is_registered) { 183 if (object->is_registered) {
184 object->is_sync_pending = false; 184 object->is_sync_pending = false;
185 Unregister(object); 185 Unregister(object);
@@ -190,8 +190,8 @@ public:
190 190
191 void CommitAsyncFlushes() { 191 void CommitAsyncFlushes() {
192 if (uncommitted_flushes) { 192 if (uncommitted_flushes) {
193 auto commit_list = std::make_shared<std::list<MapInterval>>(); 193 auto commit_list = std::make_shared<std::list<MapInterval*>>();
194 for (auto& map : *uncommitted_flushes) { 194 for (MapInterval* map : *uncommitted_flushes) {
195 if (map->is_registered && map->is_modified) { 195 if (map->is_registered && map->is_modified) {
196 // TODO(Blinkhawk): Implement backend asynchronous flushing 196 // TODO(Blinkhawk): Implement backend asynchronous flushing
197 // AsyncFlushMap(map) 197 // AsyncFlushMap(map)
@@ -226,7 +226,7 @@ public:
226 committed_flushes.pop_front(); 226 committed_flushes.pop_front();
227 return; 227 return;
228 } 228 }
229 for (MapInterval& map : *flush_list) { 229 for (MapInterval* map : *flush_list) {
230 if (map->is_registered) { 230 if (map->is_registered) {
231 // TODO(Blinkhawk): Replace this for reading the asynchronous flush 231 // TODO(Blinkhawk): Replace this for reading the asynchronous flush
232 FlushMap(map); 232 FlushMap(map);
@@ -263,26 +263,28 @@ protected:
263 } 263 }
264 264
265 /// Register an object into the cache 265 /// Register an object into the cache
266 void Register(const MapInterval& new_map, bool inherit_written = false) { 266 MapInterval* Register(MapInterval new_map, bool inherit_written = false) {
267 const VAddr cpu_addr = new_map->start; 267 const VAddr cpu_addr = new_map.start;
268 if (!cpu_addr) { 268 if (!cpu_addr) {
269 LOG_CRITICAL(HW_GPU, "Failed to register buffer with unmapped gpu_address 0x{:016x}", 269 LOG_CRITICAL(HW_GPU, "Failed to register buffer with unmapped gpu_address 0x{:016x}",
270 new_map->gpu_addr); 270 new_map.gpu_addr);
271 return; 271 return nullptr;
272 } 272 }
273 const std::size_t size = new_map->end - new_map->start; 273 const std::size_t size = new_map.end - new_map.start;
274 new_map->is_registered = true; 274 new_map.is_registered = true;
275 const IntervalType interval{new_map->start, new_map->end}; 275 const IntervalType interval{new_map.start, new_map.end};
276 mapped_addresses.insert({interval, new_map});
277 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); 276 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
278 new_map->is_memory_marked = true; 277 new_map.is_memory_marked = true;
279 if (inherit_written) { 278 if (inherit_written) {
280 MarkRegionAsWritten(new_map->start, new_map->end - 1); 279 MarkRegionAsWritten(new_map.start, new_map.end - 1);
281 new_map->is_written = true; 280 new_map.is_written = true;
282 } 281 }
282 mapped_addresses.insert({interval, new_map});
283 // Temporary hack until this is replaced with boost::intrusive::rbtree
284 return const_cast<MapInterval*>(&mapped_addresses.find(interval)->second);
283 } 285 }
284 286
285 void UnmarkMemory(const MapInterval& map) { 287 void UnmarkMemory(MapInterval* map) {
286 if (!map->is_memory_marked) { 288 if (!map->is_memory_marked) {
287 return; 289 return;
288 } 290 }
@@ -292,7 +294,7 @@ protected:
292 } 294 }
293 295
294 /// Unregisters an object from the cache 296 /// Unregisters an object from the cache
295 void Unregister(const MapInterval& map) { 297 void Unregister(MapInterval* map) {
296 UnmarkMemory(map); 298 UnmarkMemory(map);
297 map->is_registered = false; 299 map->is_registered = false;
298 if (map->is_sync_pending) { 300 if (map->is_sync_pending) {
@@ -307,17 +309,12 @@ protected:
307 } 309 }
308 310
309private: 311private:
310 MapInterval CreateMap(const VAddr start, const VAddr end, const GPUVAddr gpu_addr) { 312 MapInterval* MapAddress(const OwnerBuffer& block, GPUVAddr gpu_addr, VAddr cpu_addr,
311 return std::make_shared<MapIntervalBase>(start, end, gpu_addr); 313 std::size_t size) {
312 } 314 std::vector<MapInterval*> overlaps = GetMapsInRange(cpu_addr, size);
313
314 MapInterval MapAddress(const OwnerBuffer& block, const GPUVAddr gpu_addr, const VAddr cpu_addr,
315 const std::size_t size) {
316 std::vector<MapInterval> overlaps = GetMapsInRange(cpu_addr, size);
317 if (overlaps.empty()) { 315 if (overlaps.empty()) {
318 auto& memory_manager = system.GPU().MemoryManager(); 316 auto& memory_manager = system.GPU().MemoryManager();
319 const VAddr cpu_addr_end = cpu_addr + size; 317 const VAddr cpu_addr_end = cpu_addr + size;
320 MapInterval new_map = CreateMap(cpu_addr, cpu_addr_end, gpu_addr);
321 if (memory_manager.IsGranularRange(gpu_addr, size)) { 318 if (memory_manager.IsGranularRange(gpu_addr, size)) {
322 u8* host_ptr = memory_manager.GetPointer(gpu_addr); 319 u8* host_ptr = memory_manager.GetPointer(gpu_addr);
323 UploadBlockData(block, block->GetOffset(cpu_addr), size, host_ptr); 320 UploadBlockData(block, block->GetOffset(cpu_addr), size, host_ptr);
@@ -326,13 +323,12 @@ private:
326 memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size); 323 memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size);
327 UploadBlockData(block, block->GetOffset(cpu_addr), size, staging_buffer.data()); 324 UploadBlockData(block, block->GetOffset(cpu_addr), size, staging_buffer.data());
328 } 325 }
329 Register(new_map); 326 return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr));
330 return new_map;
331 } 327 }
332 328
333 const VAddr cpu_addr_end = cpu_addr + size; 329 const VAddr cpu_addr_end = cpu_addr + size;
334 if (overlaps.size() == 1) { 330 if (overlaps.size() == 1) {
335 MapInterval& current_map = overlaps[0]; 331 MapInterval* const current_map = overlaps[0];
336 if (current_map->IsInside(cpu_addr, cpu_addr_end)) { 332 if (current_map->IsInside(cpu_addr, cpu_addr_end)) {
337 return current_map; 333 return current_map;
338 } 334 }
@@ -342,7 +338,7 @@ private:
342 bool write_inheritance = false; 338 bool write_inheritance = false;
343 bool modified_inheritance = false; 339 bool modified_inheritance = false;
344 // Calculate new buffer parameters 340 // Calculate new buffer parameters
345 for (auto& overlap : overlaps) { 341 for (MapInterval* overlap : overlaps) {
346 new_start = std::min(overlap->start, new_start); 342 new_start = std::min(overlap->start, new_start);
347 new_end = std::max(overlap->end, new_end); 343 new_end = std::max(overlap->end, new_end);
348 write_inheritance |= overlap->is_written; 344 write_inheritance |= overlap->is_written;
@@ -353,19 +349,23 @@ private:
353 Unregister(overlap); 349 Unregister(overlap);
354 } 350 }
355 UpdateBlock(block, new_start, new_end, overlaps); 351 UpdateBlock(block, new_start, new_end, overlaps);
356 MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr); 352
353 const MapInterval new_map{new_start, new_end, new_gpu_addr};
354 MapInterval* const map = Register(new_map, write_inheritance);
355 if (!map) {
356 return nullptr;
357 }
357 if (modified_inheritance) { 358 if (modified_inheritance) {
358 new_map->MarkAsModified(true, GetModifiedTicks()); 359 map->MarkAsModified(true, GetModifiedTicks());
359 if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { 360 if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) {
360 MarkForAsyncFlush(new_map); 361 MarkForAsyncFlush(map);
361 } 362 }
362 } 363 }
363 Register(new_map, write_inheritance); 364 return map;
364 return new_map;
365 } 365 }
366 366
367 void UpdateBlock(const OwnerBuffer& block, VAddr start, VAddr end, 367 void UpdateBlock(const OwnerBuffer& block, VAddr start, VAddr end,
368 std::vector<MapInterval>& overlaps) { 368 std::vector<MapInterval*>& overlaps) {
369 const IntervalType base_interval{start, end}; 369 const IntervalType base_interval{start, end};
370 IntervalSet interval_set{}; 370 IntervalSet interval_set{};
371 interval_set.add(base_interval); 371 interval_set.add(base_interval);
@@ -384,15 +384,15 @@ private:
384 } 384 }
385 } 385 }
386 386
387 std::vector<MapInterval> GetMapsInRange(VAddr addr, std::size_t size) { 387 std::vector<MapInterval*> GetMapsInRange(VAddr addr, std::size_t size) {
388 if (size == 0) { 388 if (size == 0) {
389 return {}; 389 return {};
390 } 390 }
391 391
392 std::vector<MapInterval> objects{}; 392 std::vector<MapInterval*> objects;
393 const IntervalType interval{addr, addr + size}; 393 const IntervalType interval{addr, addr + size};
394 for (auto& pair : boost::make_iterator_range(mapped_addresses.equal_range(interval))) { 394 for (auto& pair : boost::make_iterator_range(mapped_addresses.equal_range(interval))) {
395 objects.push_back(pair.second); 395 objects.push_back(&pair.second);
396 } 396 }
397 397
398 return objects; 398 return objects;
@@ -403,8 +403,8 @@ private:
403 return ++modified_ticks; 403 return ++modified_ticks;
404 } 404 }
405 405
406 void FlushMap(MapInterval map) { 406 void FlushMap(MapInterval* map) {
407 std::size_t size = map->end - map->start; 407 const std::size_t size = map->end - map->start;
408 OwnerBuffer block = blocks[map->start >> block_page_bits]; 408 OwnerBuffer block = blocks[map->start >> block_page_bits];
409 staging_buffer.resize(size); 409 staging_buffer.resize(size);
410 DownloadBlockData(block, block->GetOffset(map->start), size, staging_buffer.data()); 410 DownloadBlockData(block, block->GetOffset(map->start), size, staging_buffer.data());
@@ -545,9 +545,9 @@ private:
545 return false; 545 return false;
546 } 546 }
547 547
548 void MarkForAsyncFlush(MapInterval& map) { 548 void MarkForAsyncFlush(MapInterval* map) {
549 if (!uncommitted_flushes) { 549 if (!uncommitted_flushes) {
550 uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval>>(); 550 uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval*>>();
551 } 551 }
552 uncommitted_flushes->insert(map); 552 uncommitted_flushes->insert(map);
553 } 553 }
@@ -581,10 +581,10 @@ private:
581 u64 modified_ticks = 0; 581 u64 modified_ticks = 0;
582 582
583 std::vector<u8> staging_buffer; 583 std::vector<u8> staging_buffer;
584 std::list<MapInterval> marked_for_unregister; 584 std::list<MapInterval*> marked_for_unregister;
585 585
586 std::shared_ptr<std::unordered_set<MapInterval>> uncommitted_flushes; 586 std::shared_ptr<std::unordered_set<MapInterval*>> uncommitted_flushes;
587 std::list<std::shared_ptr<std::list<MapInterval>>> committed_flushes; 587 std::list<std::shared_ptr<std::list<MapInterval*>>> committed_flushes;
588 588
589 std::recursive_mutex mutex; 589 std::recursive_mutex mutex;
590}; 590};
diff --git a/src/video_core/buffer_cache/map_interval.h b/src/video_core/buffer_cache/map_interval.h
index 1e77012d9..ad4db0135 100644
--- a/src/video_core/buffer_cache/map_interval.h
+++ b/src/video_core/buffer_cache/map_interval.h
@@ -9,30 +9,32 @@
9 9
10namespace VideoCommon { 10namespace VideoCommon {
11 11
12struct MapIntervalBase { 12struct MapInterval {
13 constexpr explicit MapIntervalBase(VAddr start, VAddr end, GPUVAddr gpu_addr) noexcept 13 constexpr explicit MapInterval() noexcept = default;
14
15 constexpr explicit MapInterval(VAddr start, VAddr end, GPUVAddr gpu_addr) noexcept
14 : start{start}, end{end}, gpu_addr{gpu_addr} {} 16 : start{start}, end{end}, gpu_addr{gpu_addr} {}
15 17
16 constexpr bool IsInside(const VAddr other_start, const VAddr other_end) const noexcept { 18 constexpr bool IsInside(VAddr other_start, VAddr other_end) const noexcept {
17 return (start <= other_start && other_end <= end); 19 return (start <= other_start && other_end <= end);
18 } 20 }
19 21
20 constexpr void MarkAsModified(bool is_modified_, u64 ticks_) noexcept { 22 constexpr bool operator==(const MapInterval& rhs) const noexcept {
21 is_modified = is_modified_;
22 ticks = ticks_;
23 }
24
25 constexpr bool operator==(const MapIntervalBase& rhs) const noexcept {
26 return start == rhs.start && end == rhs.end; 23 return start == rhs.start && end == rhs.end;
27 } 24 }
28 25
29 constexpr bool operator!=(const MapIntervalBase& rhs) const noexcept { 26 constexpr bool operator!=(const MapInterval& rhs) const noexcept {
30 return !operator==(rhs); 27 return !operator==(rhs);
31 } 28 }
32 29
33 VAddr start; 30 constexpr void MarkAsModified(bool is_modified_, u64 ticks_) noexcept {
34 VAddr end; 31 is_modified = is_modified_;
35 GPUVAddr gpu_addr; 32 ticks = ticks_;
33 }
34
35 VAddr start = 0;
36 VAddr end = 0;
37 GPUVAddr gpu_addr = 0;
36 VAddr cpu_addr = 0; 38 VAddr cpu_addr = 0;
37 u64 ticks = 0; 39 u64 ticks = 0;
38 bool is_written = false; 40 bool is_written = false;