summaryrefslogtreecommitdiff
path: root/src/video_core/buffer_cache
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/buffer_cache')
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h119
-rw-r--r--src/video_core/buffer_cache/map_interval.h18
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
159protected: 247protected:
@@ -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