diff options
Diffstat (limited to 'src/video_core/buffer_cache')
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 119 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/map_interval.h | 18 |
2 files changed, 135 insertions, 2 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 83e7a1cde..510f11089 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <list> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <mutex> | 10 | #include <mutex> |
| 10 | #include <unordered_map> | 11 | #include <unordered_map> |
| @@ -18,8 +19,10 @@ | |||
| 18 | 19 | ||
| 19 | #include "common/alignment.h" | 20 | #include "common/alignment.h" |
| 20 | #include "common/common_types.h" | 21 | #include "common/common_types.h" |
| 22 | #include "common/logging/log.h" | ||
| 21 | #include "core/core.h" | 23 | #include "core/core.h" |
| 22 | #include "core/memory.h" | 24 | #include "core/memory.h" |
| 25 | #include "core/settings.h" | ||
| 23 | #include "video_core/buffer_cache/buffer_block.h" | 26 | #include "video_core/buffer_cache/buffer_block.h" |
| 24 | #include "video_core/buffer_cache/map_interval.h" | 27 | #include "video_core/buffer_cache/map_interval.h" |
| 25 | #include "video_core/memory_manager.h" | 28 | #include "video_core/memory_manager.h" |
| @@ -79,6 +82,9 @@ public: | |||
| 79 | auto map = MapAddress(block, gpu_addr, cpu_addr, size); | 82 | auto map = MapAddress(block, gpu_addr, cpu_addr, size); |
| 80 | if (is_written) { | 83 | if (is_written) { |
| 81 | map->MarkAsModified(true, GetModifiedTicks()); | 84 | map->MarkAsModified(true, GetModifiedTicks()); |
| 85 | if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { | ||
| 86 | MarkForAsyncFlush(map); | ||
| 87 | } | ||
| 82 | if (!map->IsWritten()) { | 88 | if (!map->IsWritten()) { |
| 83 | map->MarkAsWritten(true); | 89 | map->MarkAsWritten(true); |
| 84 | MarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1); | 90 | MarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1); |
| @@ -137,11 +143,22 @@ public: | |||
| 137 | }); | 143 | }); |
| 138 | for (auto& object : objects) { | 144 | for (auto& object : objects) { |
| 139 | if (object->IsModified() && object->IsRegistered()) { | 145 | if (object->IsModified() && object->IsRegistered()) { |
| 146 | mutex.unlock(); | ||
| 140 | FlushMap(object); | 147 | FlushMap(object); |
| 148 | mutex.lock(); | ||
| 141 | } | 149 | } |
| 142 | } | 150 | } |
| 143 | } | 151 | } |
| 144 | 152 | ||
| 153 | bool MustFlushRegion(VAddr addr, std::size_t size) { | ||
| 154 | std::lock_guard lock{mutex}; | ||
| 155 | |||
| 156 | const std::vector<MapInterval> objects = GetMapsInRange(addr, size); | ||
| 157 | return std::any_of(objects.cbegin(), objects.cend(), [](const MapInterval& map) { | ||
| 158 | return map->IsModified() && map->IsRegistered(); | ||
| 159 | }); | ||
| 160 | } | ||
| 161 | |||
| 145 | /// Mark the specified region as being invalidated | 162 | /// Mark the specified region as being invalidated |
| 146 | void InvalidateRegion(VAddr addr, u64 size) { | 163 | void InvalidateRegion(VAddr addr, u64 size) { |
| 147 | std::lock_guard lock{mutex}; | 164 | std::lock_guard lock{mutex}; |
| @@ -154,6 +171,77 @@ public: | |||
| 154 | } | 171 | } |
| 155 | } | 172 | } |
| 156 | 173 | ||
| 174 | void OnCPUWrite(VAddr addr, std::size_t size) { | ||
| 175 | std::lock_guard lock{mutex}; | ||
| 176 | |||
| 177 | for (const auto& object : GetMapsInRange(addr, size)) { | ||
| 178 | if (object->IsMemoryMarked() && object->IsRegistered()) { | ||
| 179 | UnmarkMemory(object); | ||
| 180 | object->SetSyncPending(true); | ||
| 181 | marked_for_unregister.emplace_back(object); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | void SyncGuestHost() { | ||
| 187 | std::lock_guard lock{mutex}; | ||
| 188 | |||
| 189 | for (const auto& object : marked_for_unregister) { | ||
| 190 | if (object->IsRegistered()) { | ||
| 191 | object->SetSyncPending(false); | ||
| 192 | Unregister(object); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | marked_for_unregister.clear(); | ||
| 196 | } | ||
| 197 | |||
| 198 | void CommitAsyncFlushes() { | ||
| 199 | if (uncommitted_flushes) { | ||
| 200 | auto commit_list = std::make_shared<std::list<MapInterval>>(); | ||
| 201 | for (auto& map : *uncommitted_flushes) { | ||
| 202 | if (map->IsRegistered() && map->IsModified()) { | ||
| 203 | // TODO(Blinkhawk): Implement backend asynchronous flushing | ||
| 204 | // AsyncFlushMap(map) | ||
| 205 | commit_list->push_back(map); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | if (!commit_list->empty()) { | ||
| 209 | committed_flushes.push_back(commit_list); | ||
| 210 | } else { | ||
| 211 | committed_flushes.emplace_back(); | ||
| 212 | } | ||
| 213 | } else { | ||
| 214 | committed_flushes.emplace_back(); | ||
| 215 | } | ||
| 216 | uncommitted_flushes.reset(); | ||
| 217 | } | ||
| 218 | |||
| 219 | bool ShouldWaitAsyncFlushes() const { | ||
| 220 | return !committed_flushes.empty() && committed_flushes.front() != nullptr; | ||
| 221 | } | ||
| 222 | |||
| 223 | bool HasUncommittedFlushes() const { | ||
| 224 | return uncommitted_flushes != nullptr; | ||
| 225 | } | ||
| 226 | |||
| 227 | void PopAsyncFlushes() { | ||
| 228 | if (committed_flushes.empty()) { | ||
| 229 | return; | ||
| 230 | } | ||
| 231 | auto& flush_list = committed_flushes.front(); | ||
| 232 | if (!flush_list) { | ||
| 233 | committed_flushes.pop_front(); | ||
| 234 | return; | ||
| 235 | } | ||
| 236 | for (MapInterval& map : *flush_list) { | ||
| 237 | if (map->IsRegistered()) { | ||
| 238 | // TODO(Blinkhawk): Replace this for reading the asynchronous flush | ||
| 239 | FlushMap(map); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | committed_flushes.pop_front(); | ||
| 243 | } | ||
| 244 | |||
| 157 | virtual BufferType GetEmptyBuffer(std::size_t size) = 0; | 245 | virtual BufferType GetEmptyBuffer(std::size_t size) = 0; |
| 158 | 246 | ||
| 159 | protected: | 247 | protected: |
| @@ -196,17 +284,30 @@ protected: | |||
| 196 | const IntervalType interval{new_map->GetStart(), new_map->GetEnd()}; | 284 | const IntervalType interval{new_map->GetStart(), new_map->GetEnd()}; |
| 197 | mapped_addresses.insert({interval, new_map}); | 285 | mapped_addresses.insert({interval, new_map}); |
| 198 | rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); | 286 | rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); |
| 287 | new_map->SetMemoryMarked(true); | ||
| 199 | if (inherit_written) { | 288 | if (inherit_written) { |
| 200 | MarkRegionAsWritten(new_map->GetStart(), new_map->GetEnd() - 1); | 289 | MarkRegionAsWritten(new_map->GetStart(), new_map->GetEnd() - 1); |
| 201 | new_map->MarkAsWritten(true); | 290 | new_map->MarkAsWritten(true); |
| 202 | } | 291 | } |
| 203 | } | 292 | } |
| 204 | 293 | ||
| 205 | /// Unregisters an object from the cache | 294 | void UnmarkMemory(const MapInterval& map) { |
| 206 | void Unregister(MapInterval& map) { | 295 | if (!map->IsMemoryMarked()) { |
| 296 | return; | ||
| 297 | } | ||
| 207 | const std::size_t size = map->GetEnd() - map->GetStart(); | 298 | const std::size_t size = map->GetEnd() - map->GetStart(); |
| 208 | rasterizer.UpdatePagesCachedCount(map->GetStart(), size, -1); | 299 | rasterizer.UpdatePagesCachedCount(map->GetStart(), size, -1); |
| 300 | map->SetMemoryMarked(false); | ||
| 301 | } | ||
| 302 | |||
| 303 | /// Unregisters an object from the cache | ||
| 304 | void Unregister(const MapInterval& map) { | ||
| 305 | UnmarkMemory(map); | ||
| 209 | map->MarkAsRegistered(false); | 306 | map->MarkAsRegistered(false); |
| 307 | if (map->IsSyncPending()) { | ||
| 308 | marked_for_unregister.remove(map); | ||
| 309 | map->SetSyncPending(false); | ||
| 310 | } | ||
| 210 | if (map->IsWritten()) { | 311 | if (map->IsWritten()) { |
| 211 | UnmarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1); | 312 | UnmarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1); |
| 212 | } | 313 | } |
| @@ -264,6 +365,9 @@ private: | |||
| 264 | MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr); | 365 | MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr); |
| 265 | if (modified_inheritance) { | 366 | if (modified_inheritance) { |
| 266 | new_map->MarkAsModified(true, GetModifiedTicks()); | 367 | new_map->MarkAsModified(true, GetModifiedTicks()); |
| 368 | if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { | ||
| 369 | MarkForAsyncFlush(new_map); | ||
| 370 | } | ||
| 267 | } | 371 | } |
| 268 | Register(new_map, write_inheritance); | 372 | Register(new_map, write_inheritance); |
| 269 | return new_map; | 373 | return new_map; |
| @@ -450,6 +554,13 @@ private: | |||
| 450 | return false; | 554 | return false; |
| 451 | } | 555 | } |
| 452 | 556 | ||
| 557 | void MarkForAsyncFlush(MapInterval& map) { | ||
| 558 | if (!uncommitted_flushes) { | ||
| 559 | uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval>>(); | ||
| 560 | } | ||
| 561 | uncommitted_flushes->insert(map); | ||
| 562 | } | ||
| 563 | |||
| 453 | VideoCore::RasterizerInterface& rasterizer; | 564 | VideoCore::RasterizerInterface& rasterizer; |
| 454 | Core::System& system; | 565 | Core::System& system; |
| 455 | 566 | ||
| @@ -479,6 +590,10 @@ private: | |||
| 479 | u64 modified_ticks = 0; | 590 | u64 modified_ticks = 0; |
| 480 | 591 | ||
| 481 | std::vector<u8> staging_buffer; | 592 | std::vector<u8> staging_buffer; |
| 593 | std::list<MapInterval> marked_for_unregister; | ||
| 594 | |||
| 595 | std::shared_ptr<std::unordered_set<MapInterval>> uncommitted_flushes{}; | ||
| 596 | std::list<std::shared_ptr<std::list<MapInterval>>> committed_flushes; | ||
| 482 | 597 | ||
| 483 | std::recursive_mutex mutex; | 598 | std::recursive_mutex mutex; |
| 484 | }; | 599 | }; |
diff --git a/src/video_core/buffer_cache/map_interval.h b/src/video_core/buffer_cache/map_interval.h index b0956029d..29d8b26f3 100644 --- a/src/video_core/buffer_cache/map_interval.h +++ b/src/video_core/buffer_cache/map_interval.h | |||
| @@ -46,6 +46,22 @@ public: | |||
| 46 | return is_registered; | 46 | return is_registered; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | void SetMemoryMarked(bool is_memory_marked_) { | ||
| 50 | is_memory_marked = is_memory_marked_; | ||
| 51 | } | ||
| 52 | |||
| 53 | bool IsMemoryMarked() const { | ||
| 54 | return is_memory_marked; | ||
| 55 | } | ||
| 56 | |||
| 57 | void SetSyncPending(bool is_sync_pending_) { | ||
| 58 | is_sync_pending = is_sync_pending_; | ||
| 59 | } | ||
| 60 | |||
| 61 | bool IsSyncPending() const { | ||
| 62 | return is_sync_pending; | ||
| 63 | } | ||
| 64 | |||
| 49 | VAddr GetStart() const { | 65 | VAddr GetStart() const { |
| 50 | return start; | 66 | return start; |
| 51 | } | 67 | } |
| @@ -83,6 +99,8 @@ private: | |||
| 83 | bool is_written{}; | 99 | bool is_written{}; |
| 84 | bool is_modified{}; | 100 | bool is_modified{}; |
| 85 | bool is_registered{}; | 101 | bool is_registered{}; |
| 102 | bool is_memory_marked{}; | ||
| 103 | bool is_sync_pending{}; | ||
| 86 | u64 ticks{}; | 104 | u64 ticks{}; |
| 87 | }; | 105 | }; |
| 88 | 106 | ||