summaryrefslogtreecommitdiff
path: root/src/video_core/texture_cache
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/texture_cache')
-rw-r--r--src/video_core/texture_cache/surface_base.h18
-rw-r--r--src/video_core/texture_cache/texture_cache.h114
2 files changed, 122 insertions, 10 deletions
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h
index c5ab21f56..79e10ffbb 100644
--- a/src/video_core/texture_cache/surface_base.h
+++ b/src/video_core/texture_cache/surface_base.h
@@ -192,6 +192,22 @@ public:
192 index = index_; 192 index = index_;
193 } 193 }
194 194
195 void SetMemoryMarked(bool is_memory_marked_) {
196 is_memory_marked = is_memory_marked_;
197 }
198
199 bool IsMemoryMarked() const {
200 return is_memory_marked;
201 }
202
203 void SetSyncPending(bool is_sync_pending_) {
204 is_sync_pending = is_sync_pending_;
205 }
206
207 bool IsSyncPending() const {
208 return is_sync_pending;
209 }
210
195 void MarkAsPicked(bool is_picked_) { 211 void MarkAsPicked(bool is_picked_) {
196 is_picked = is_picked_; 212 is_picked = is_picked_;
197 } 213 }
@@ -303,6 +319,8 @@ private:
303 bool is_target{}; 319 bool is_target{};
304 bool is_registered{}; 320 bool is_registered{};
305 bool is_picked{}; 321 bool is_picked{};
322 bool is_memory_marked{};
323 bool is_sync_pending{};
306 u32 index{NO_RT}; 324 u32 index{NO_RT};
307 u64 modification_tick{}; 325 u64 modification_tick{};
308}; 326};
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 69ca08fd1..cf6bd005a 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -6,6 +6,7 @@
6 6
7#include <algorithm> 7#include <algorithm>
8#include <array> 8#include <array>
9#include <list>
9#include <memory> 10#include <memory>
10#include <mutex> 11#include <mutex>
11#include <set> 12#include <set>
@@ -62,6 +63,30 @@ public:
62 } 63 }
63 } 64 }
64 65
66 void OnCPUWrite(VAddr addr, std::size_t size) {
67 std::lock_guard lock{mutex};
68
69 for (const auto& surface : GetSurfacesInRegion(addr, size)) {
70 if (surface->IsMemoryMarked()) {
71 UnmarkMemory(surface);
72 surface->SetSyncPending(true);
73 marked_for_unregister.emplace_back(surface);
74 }
75 }
76 }
77
78 void SyncGuestHost() {
79 std::lock_guard lock{mutex};
80
81 for (const auto& surface : marked_for_unregister) {
82 if (surface->IsRegistered()) {
83 surface->SetSyncPending(false);
84 Unregister(surface);
85 }
86 }
87 marked_for_unregister.clear();
88 }
89
65 /** 90 /**
66 * Guarantees that rendertargets don't unregister themselves if the 91 * Guarantees that rendertargets don't unregister themselves if the
67 * collide. Protection is currently only done on 3D slices. 92 * collide. Protection is currently only done on 3D slices.
@@ -85,10 +110,20 @@ public:
85 return a->GetModificationTick() < b->GetModificationTick(); 110 return a->GetModificationTick() < b->GetModificationTick();
86 }); 111 });
87 for (const auto& surface : surfaces) { 112 for (const auto& surface : surfaces) {
113 mutex.unlock();
88 FlushSurface(surface); 114 FlushSurface(surface);
115 mutex.lock();
89 } 116 }
90 } 117 }
91 118
119 bool MustFlushRegion(VAddr addr, std::size_t size) {
120 std::lock_guard lock{mutex};
121
122 const auto surfaces = GetSurfacesInRegion(addr, size);
123 return std::any_of(surfaces.cbegin(), surfaces.cend(),
124 [](const TSurface& surface) { return surface->IsModified(); });
125 }
126
92 TView GetTextureSurface(const Tegra::Texture::TICEntry& tic, 127 TView GetTextureSurface(const Tegra::Texture::TICEntry& tic,
93 const VideoCommon::Shader::Sampler& entry) { 128 const VideoCommon::Shader::Sampler& entry) {
94 std::lock_guard lock{mutex}; 129 std::lock_guard lock{mutex};
@@ -206,8 +241,14 @@ public:
206 241
207 auto surface_view = GetSurface(gpu_addr, *cpu_addr, 242 auto surface_view = GetSurface(gpu_addr, *cpu_addr,
208 SurfaceParams::CreateForFramebuffer(system, index), true); 243 SurfaceParams::CreateForFramebuffer(system, index), true);
209 if (render_targets[index].target) 244 if (render_targets[index].target) {
210 render_targets[index].target->MarkAsRenderTarget(false, NO_RT); 245 auto& surface = render_targets[index].target;
246 surface->MarkAsRenderTarget(false, NO_RT);
247 const auto& cr_params = surface->GetSurfaceParams();
248 if (!cr_params.is_tiled && Settings::values.use_asynchronous_gpu_emulation) {
249 AsyncFlushSurface(surface);
250 }
251 }
211 render_targets[index].target = surface_view.first; 252 render_targets[index].target = surface_view.first;
212 render_targets[index].view = surface_view.second; 253 render_targets[index].view = surface_view.second;
213 if (render_targets[index].target) 254 if (render_targets[index].target)
@@ -284,6 +325,34 @@ public:
284 return ++ticks; 325 return ++ticks;
285 } 326 }
286 327
328 void CommitAsyncFlushes() {
329 committed_flushes.push_back(uncommitted_flushes);
330 uncommitted_flushes.reset();
331 }
332
333 bool HasUncommittedFlushes() const {
334 return uncommitted_flushes != nullptr;
335 }
336
337 bool ShouldWaitAsyncFlushes() const {
338 return !committed_flushes.empty() && committed_flushes.front() != nullptr;
339 }
340
341 void PopAsyncFlushes() {
342 if (committed_flushes.empty()) {
343 return;
344 }
345 auto& flush_list = committed_flushes.front();
346 if (!flush_list) {
347 committed_flushes.pop_front();
348 return;
349 }
350 for (TSurface& surface : *flush_list) {
351 FlushSurface(surface);
352 }
353 committed_flushes.pop_front();
354 }
355
287protected: 356protected:
288 explicit TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 357 explicit TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
289 bool is_astc_supported) 358 bool is_astc_supported)
@@ -345,9 +414,20 @@ protected:
345 surface->SetCpuAddr(*cpu_addr); 414 surface->SetCpuAddr(*cpu_addr);
346 RegisterInnerCache(surface); 415 RegisterInnerCache(surface);
347 surface->MarkAsRegistered(true); 416 surface->MarkAsRegistered(true);
417 surface->SetMemoryMarked(true);
348 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1); 418 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
349 } 419 }
350 420
421 void UnmarkMemory(TSurface surface) {
422 if (!surface->IsMemoryMarked()) {
423 return;
424 }
425 const std::size_t size = surface->GetSizeInBytes();
426 const VAddr cpu_addr = surface->GetCpuAddr();
427 rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
428 surface->SetMemoryMarked(false);
429 }
430
351 void Unregister(TSurface surface) { 431 void Unregister(TSurface surface) {
352 if (guard_render_targets && surface->IsProtected()) { 432 if (guard_render_targets && surface->IsProtected()) {
353 return; 433 return;
@@ -355,9 +435,11 @@ protected:
355 if (!guard_render_targets && surface->IsRenderTarget()) { 435 if (!guard_render_targets && surface->IsRenderTarget()) {
356 ManageRenderTargetUnregister(surface); 436 ManageRenderTargetUnregister(surface);
357 } 437 }
358 const std::size_t size = surface->GetSizeInBytes(); 438 UnmarkMemory(surface);
359 const VAddr cpu_addr = surface->GetCpuAddr(); 439 if (surface->IsSyncPending()) {
360 rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1); 440 marked_for_unregister.remove(surface);
441 surface->SetSyncPending(false);
442 }
361 UnregisterInnerCache(surface); 443 UnregisterInnerCache(surface);
362 surface->MarkAsRegistered(false); 444 surface->MarkAsRegistered(false);
363 ReserveSurface(surface->GetSurfaceParams(), surface); 445 ReserveSurface(surface->GetSurfaceParams(), surface);
@@ -417,7 +499,7 @@ private:
417 **/ 499 **/
418 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params, 500 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
419 const GPUVAddr gpu_addr, const MatchTopologyResult untopological) { 501 const GPUVAddr gpu_addr, const MatchTopologyResult untopological) {
420 if (Settings::values.use_accurate_gpu_emulation) { 502 if (Settings::IsGPULevelExtreme()) {
421 return RecycleStrategy::Flush; 503 return RecycleStrategy::Flush;
422 } 504 }
423 // 3D Textures decision 505 // 3D Textures decision
@@ -461,7 +543,7 @@ private:
461 } 543 }
462 switch (PickStrategy(overlaps, params, gpu_addr, untopological)) { 544 switch (PickStrategy(overlaps, params, gpu_addr, untopological)) {
463 case RecycleStrategy::Ignore: { 545 case RecycleStrategy::Ignore: {
464 return InitializeSurface(gpu_addr, params, Settings::values.use_accurate_gpu_emulation); 546 return InitializeSurface(gpu_addr, params, Settings::IsGPULevelExtreme());
465 } 547 }
466 case RecycleStrategy::Flush: { 548 case RecycleStrategy::Flush: {
467 std::sort(overlaps.begin(), overlaps.end(), 549 std::sort(overlaps.begin(), overlaps.end(),
@@ -509,7 +591,7 @@ private:
509 } 591 }
510 const auto& final_params = new_surface->GetSurfaceParams(); 592 const auto& final_params = new_surface->GetSurfaceParams();
511 if (cr_params.type != final_params.type) { 593 if (cr_params.type != final_params.type) {
512 if (Settings::values.use_accurate_gpu_emulation) { 594 if (Settings::IsGPULevelExtreme()) {
513 BufferCopy(current_surface, new_surface); 595 BufferCopy(current_surface, new_surface);
514 } 596 }
515 } else { 597 } else {
@@ -598,7 +680,7 @@ private:
598 if (passed_tests == 0) { 680 if (passed_tests == 0) {
599 return {}; 681 return {};
600 // In Accurate GPU all tests should pass, else we recycle 682 // In Accurate GPU all tests should pass, else we recycle
601 } else if (Settings::values.use_accurate_gpu_emulation && passed_tests != overlaps.size()) { 683 } else if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) {
602 return {}; 684 return {};
603 } 685 }
604 for (const auto& surface : overlaps) { 686 for (const auto& surface : overlaps) {
@@ -668,7 +750,7 @@ private:
668 for (const auto& surface : overlaps) { 750 for (const auto& surface : overlaps) {
669 if (!surface->MatchTarget(params.target)) { 751 if (!surface->MatchTarget(params.target)) {
670 if (overlaps.size() == 1 && surface->GetCpuAddr() == cpu_addr) { 752 if (overlaps.size() == 1 && surface->GetCpuAddr() == cpu_addr) {
671 if (Settings::values.use_accurate_gpu_emulation) { 753 if (Settings::IsGPULevelExtreme()) {
672 return std::nullopt; 754 return std::nullopt;
673 } 755 }
674 Unregister(surface); 756 Unregister(surface);
@@ -1106,6 +1188,13 @@ private:
1106 TView view; 1188 TView view;
1107 }; 1189 };
1108 1190
1191 void AsyncFlushSurface(TSurface& surface) {
1192 if (!uncommitted_flushes) {
1193 uncommitted_flushes = std::make_shared<std::list<TSurface>>();
1194 }
1195 uncommitted_flushes->push_back(surface);
1196 }
1197
1109 VideoCore::RasterizerInterface& rasterizer; 1198 VideoCore::RasterizerInterface& rasterizer;
1110 1199
1111 FormatLookupTable format_lookup_table; 1200 FormatLookupTable format_lookup_table;
@@ -1150,6 +1239,11 @@ private:
1150 std::unordered_map<u32, TSurface> invalid_cache; 1239 std::unordered_map<u32, TSurface> invalid_cache;
1151 std::vector<u8> invalid_memory; 1240 std::vector<u8> invalid_memory;
1152 1241
1242 std::list<TSurface> marked_for_unregister;
1243
1244 std::shared_ptr<std::list<TSurface>> uncommitted_flushes{};
1245 std::list<std::shared_ptr<std::list<TSurface>>> committed_flushes;
1246
1153 StagingCache staging_cache; 1247 StagingCache staging_cache;
1154 std::recursive_mutex mutex; 1248 std::recursive_mutex mutex;
1155}; 1249};