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/texture_cache.h454
1 files changed, 366 insertions, 88 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index c5c01957a..eb0d9bc10 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -22,6 +22,7 @@
22#include "video_core/memory_manager.h" 22#include "video_core/memory_manager.h"
23#include "video_core/rasterizer_interface.h" 23#include "video_core/rasterizer_interface.h"
24#include "video_core/surface.h" 24#include "video_core/surface.h"
25#include "video_core/texture_cache/copy_params.h"
25#include "video_core/texture_cache/surface_base.h" 26#include "video_core/texture_cache/surface_base.h"
26#include "video_core/texture_cache/surface_params.h" 27#include "video_core/texture_cache/surface_params.h"
27#include "video_core/texture_cache/surface_view.h" 28#include "video_core/texture_cache/surface_view.h"
@@ -40,32 +41,42 @@ class RasterizerInterface;
40 41
41namespace VideoCommon { 42namespace VideoCommon {
42 43
44using VideoCore::Surface::SurfaceTarget;
45using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig;
46
43template <typename TSurface, typename TView> 47template <typename TSurface, typename TView>
44class TextureCache { 48class TextureCache {
45 using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>; 49 using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface>>;
46 using IntervalType = typename IntervalMap::interval_type; 50 using IntervalType = typename IntervalMap::interval_type;
47 51
48public: 52public:
53 void InitMemoryMananger(Tegra::MemoryManager& memory_manager) {
54 this->memory_manager = &memory_manager;
55 }
56
49 void InvalidateRegion(CacheAddr addr, std::size_t size) { 57 void InvalidateRegion(CacheAddr addr, std::size_t size) {
50 for (const auto& surface : GetSurfacesInRegion(addr, size)) { 58 for (const auto& surface : GetSurfacesInRegion(addr, size)) {
51 if (!surface->IsRegistered()) {
52 // Skip duplicates
53 continue;
54 }
55 Unregister(surface); 59 Unregister(surface);
56 } 60 }
57 } 61 }
58 62
59 TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { 63 void InvalidateRegionEx(GPUVAddr addr, std::size_t size) {
64 for (const auto& surface : GetSurfacesInRegionInner(addr, size)) {
65 Unregister(surface);
66 }
67 }
68
69 TView GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
70 const VideoCommon::Shader::Sampler& entry) {
60 const auto gpu_addr{config.tic.Address()}; 71 const auto gpu_addr{config.tic.Address()};
61 if (!gpu_addr) { 72 if (!gpu_addr) {
62 return {}; 73 return {};
63 } 74 }
64 const auto params{SurfaceParams::CreateForTexture(system, config)}; 75 const auto params{SurfaceParams::CreateForTexture(system, config, entry)};
65 return GetSurfaceView(gpu_addr, params, true); 76 return GetSurface(gpu_addr, params, true).second;
66 } 77 }
67 78
68 TView* GetDepthBufferSurface(bool preserve_contents) { 79 TView GetDepthBufferSurface(bool preserve_contents) {
69 const auto& regs{system.GPU().Maxwell3D().regs}; 80 const auto& regs{system.GPU().Maxwell3D().regs};
70 const auto gpu_addr{regs.zeta.Address()}; 81 const auto gpu_addr{regs.zeta.Address()};
71 if (!gpu_addr || !regs.zeta_enable) { 82 if (!gpu_addr || !regs.zeta_enable) {
@@ -75,36 +86,75 @@ public:
75 system, regs.zeta_width, regs.zeta_height, regs.zeta.format, 86 system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
76 regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, 87 regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
77 regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; 88 regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
78 return GetSurfaceView(gpu_addr, depth_params, preserve_contents); 89 auto surface_view = GetSurface(gpu_addr, depth_params, preserve_contents);
90 if (depth_buffer.target)
91 depth_buffer.target->MarkAsProtected(false);
92 if (depth_buffer.target)
93 depth_buffer.target->MarkAsProtected(true);
94 return surface_view.second;
79 } 95 }
80 96
81 TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) { 97 TView GetColorBufferSurface(std::size_t index, bool preserve_contents) {
82 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); 98 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
83 99
84 const auto& regs{system.GPU().Maxwell3D().regs}; 100 const auto& regs{system.GPU().Maxwell3D().regs};
85 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 || 101 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
86 regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { 102 regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
103 SetEmptyColorBuffer(index);
87 return {}; 104 return {};
88 } 105 }
89 106
90 auto& memory_manager{system.GPU().MemoryManager()}; 107 const auto& config{regs.rt[index]};
91 const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; 108 const auto gpu_addr{config.Address()};
92 const auto gpu_addr{config.Address() +
93 config.base_layer * config.layer_stride * sizeof(u32)};
94 if (!gpu_addr) { 109 if (!gpu_addr) {
110 SetEmptyColorBuffer(index);
95 return {}; 111 return {};
96 } 112 }
97 113
98 return GetSurfaceView(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), 114 auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
99 preserve_contents); 115 preserve_contents);
116 if (render_targets[index].target)
117 render_targets[index].target->MarkAsProtected(false);
118 render_targets[index].target = surface_view.first;
119 if (render_targets[index].target)
120 render_targets[index].target->MarkAsProtected(true);
121 return surface_view.second;
122 }
123
124 void MarkColorBufferInUse(std::size_t index) {
125 if (render_targets[index].target)
126 render_targets[index].target->MarkAsModified(true, Tick());
100 } 127 }
101 128
102 TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) { 129 void MarkDepthBufferInUse() {
103 return GetSurfaceView(config.Address(), SurfaceParams::CreateForFermiCopySurface(config), 130 if (depth_buffer.target)
104 true); 131 depth_buffer.target->MarkAsModified(true, Tick());
105 } 132 }
106 133
107 std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const { 134 void SetEmptyDepthBuffer() {
135 if (depth_buffer.target != nullptr) {
136 depth_buffer.target->MarkAsProtected(false);
137 depth_buffer.target = nullptr;
138 depth_buffer.view = nullptr;
139 }
140 }
141
142 void SetEmptyColorBuffer(std::size_t index) {
143 if (render_targets[index].target != nullptr) {
144 render_targets[index].target->MarkAsProtected(false);
145 std::memset(&render_targets[index].config, sizeof(RenderTargetConfig), 0);
146 render_targets[index].target = nullptr;
147 render_targets[index].view = nullptr;
148 }
149 }
150
151 TView GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
152 SurfaceParams params = SurfaceParams::CreateForFermiCopySurface(config);
153 const GPUVAddr gpu_addr = config.Address();
154 return GetSurface(gpu_addr, params, true).second;
155 }
156
157 TSurface TryFindFramebufferSurface(const u8* host_ptr) const {
108 const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))}; 158 const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
109 return it != registered_surfaces.end() ? *it->second.begin() : nullptr; 159 return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
110 } 160 }
@@ -115,126 +165,334 @@ public:
115 165
116protected: 166protected:
117 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer) 167 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
118 : system{system}, rasterizer{rasterizer} {} 168 : system{system}, rasterizer{rasterizer} {
169 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
170 SetEmptyColorBuffer(i);
171 }
172 SetEmptyDepthBuffer();
173 }
119 174
120 ~TextureCache() = default; 175 ~TextureCache() = default;
121 176
122 virtual TView* TryFastGetSurfaceView( 177 virtual TSurface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) = 0;
123 GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
124 bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
125 178
126 virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0; 179 virtual void ImageCopy(TSurface src_surface, TSurface dst_surface,
180 const CopyParams& copy_params) = 0;
127 181
128 void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr, 182 void Register(TSurface surface) {
129 u8* host_ptr) { 183 const GPUVAddr gpu_addr = surface->GetGpuAddr();
130 surface->Register(gpu_addr, cpu_addr, host_ptr); 184 u8* host_ptr = memory_manager->GetPointer(gpu_addr);
131 registered_surfaces.add({GetSurfaceInterval(surface), {surface}}); 185 const std::size_t size = surface->GetSizeInBytes();
132 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1); 186 const std::optional<VAddr> cpu_addr = memory_manager->GpuToCpuAddress(gpu_addr);
187 if (!host_ptr || !cpu_addr) {
188 LOG_CRITICAL(HW_GPU, "Failed to register surface with unmapped gpu_address 0x{:016x}",
189 gpu_addr);
190 return;
191 }
192 surface->SetHostPtr(host_ptr);
193 surface->SetCpuAddr(*cpu_addr);
194 registered_surfaces.add({GetInterval(host_ptr, size), {surface}});
195 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
196 RegisterInnerCache(surface);
197 surface->MarkAsRegistered(true);
133 } 198 }
134 199
135 void Unregister(std::shared_ptr<TSurface> surface) { 200 void Unregister(TSurface surface) {
136 registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}}); 201 if (surface->IsProtected())
137 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1); 202 return;
138 surface->Unregister(); 203 const GPUVAddr gpu_addr = surface->GetGpuAddr();
204 const void* host_ptr = surface->GetHostPtr();
205 const std::size_t size = surface->GetSizeInBytes();
206 const VAddr cpu_addr = surface->GetCpuAddr();
207 registered_surfaces.erase(GetInterval(host_ptr, size));
208 rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
209 UnregisterInnerCache(surface);
210 surface->MarkAsRegistered(false);
211 ReserveSurface(surface->GetSurfaceParams(), surface);
139 } 212 }
140 213
141 std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) { 214 TSurface GetUncachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
142 if (const auto surface = TryGetReservedSurface(params); surface) 215 if (const auto surface = TryGetReservedSurface(params); surface) {
216 surface->SetGpuAddr(gpu_addr);
143 return surface; 217 return surface;
218 }
144 // No reserved surface available, create a new one and reserve it 219 // No reserved surface available, create a new one and reserve it
145 auto new_surface{CreateSurface(params)}; 220 auto new_surface{CreateSurface(gpu_addr, params)};
146 ReserveSurface(params, new_surface);
147 return new_surface; 221 return new_surface;
148 } 222 }
149 223
150 Core::System& system; 224 Core::System& system;
151 225
152private: 226private:
153 TView* GetSurfaceView(GPUVAddr gpu_addr, const SurfaceParams& params, bool preserve_contents) { 227 enum class RecycleStrategy : u32 {
154 auto& memory_manager{system.GPU().MemoryManager()}; 228 Ignore = 0,
155 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; 229 Flush = 1,
156 DEBUG_ASSERT(cpu_addr); 230 BufferCopy = 3,
157 231 };
158 const auto host_ptr{memory_manager.GetPointer(gpu_addr)}; 232
159 const auto cache_addr{ToCacheAddr(host_ptr)}; 233 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
160 auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())}; 234 const GPUVAddr gpu_addr, const bool untopological) {
161 if (overlaps.empty()) { 235 // Untopological decision
162 return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); 236 if (untopological) {
237 return RecycleStrategy::Ignore;
238 }
239 // 3D Textures decision
240 if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) {
241 return RecycleStrategy::Flush;
163 } 242 }
243 for (auto s : overlaps) {
244 const auto& s_params = s->GetSurfaceParams();
245 if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) {
246 return RecycleStrategy::Flush;
247 }
248 }
249 return RecycleStrategy::Ignore;
250 }
164 251
165 if (overlaps.size() == 1) { 252 std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
166 if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) { 253 const SurfaceParams& params, const GPUVAddr gpu_addr,
167 return view; 254 const u8* host_ptr, const bool preserve_contents,
255 const bool untopological) {
256 for (auto surface : overlaps) {
257 Unregister(surface);
258 }
259 RecycleStrategy strategy = !Settings::values.use_accurate_gpu_emulation
260 ? PickStrategy(overlaps, params, gpu_addr, untopological)
261 : RecycleStrategy::Flush;
262 switch (strategy) {
263 case RecycleStrategy::Ignore: {
264 return InitializeSurface(gpu_addr, params, preserve_contents);
265 }
266 case RecycleStrategy::Flush: {
267 std::sort(overlaps.begin(), overlaps.end(),
268 [](const TSurface& a, const TSurface& b) -> bool {
269 return a->GetModificationTick() < b->GetModificationTick();
270 });
271 for (auto surface : overlaps) {
272 FlushSurface(surface);
168 } 273 }
274 return InitializeSurface(gpu_addr, params, preserve_contents);
169 } 275 }
276 default: {
277 UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!");
278 return InitializeSurface(gpu_addr, params, preserve_contents);
279 }
280 }
281 }
170 282
171 const auto fast_view{TryFastGetSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, 283 std::pair<TSurface, TView> RebuildMirage(TSurface current_surface,
172 preserve_contents, overlaps)}; 284 const SurfaceParams& params) {
285 const auto gpu_addr = current_surface->GetGpuAddr();
286 TSurface new_surface = GetUncachedSurface(gpu_addr, params);
287 std::vector<CopyParams> bricks = current_surface->BreakDown();
288 for (auto& brick : bricks) {
289 ImageCopy(current_surface, new_surface, brick);
290 }
291 Unregister(current_surface);
292 Register(new_surface);
293 return {new_surface, new_surface->GetMainView()};
294 }
173 295
174 if (!fast_view) { 296 std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface,
175 std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) { 297 const SurfaceParams& params) {
176 return lhs->GetModificationTick() < rhs->GetModificationTick(); 298 const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
177 }); 299 if (is_mirage) {
300 return RebuildMirage(current_surface, params);
178 } 301 }
302 const bool matches_target = current_surface->MatchTarget(params.target);
303 if (matches_target) {
304 return {current_surface, current_surface->GetMainView()};
305 }
306 return {current_surface, current_surface->EmplaceOverview(params)};
307 }
179 308
180 for (const auto& surface : overlaps) { 309 std::optional<std::pair<TSurface, TView>> ReconstructSurface(std::vector<TSurface>& overlaps,
181 if (!fast_view) { 310 const SurfaceParams& params,
182 // Flush even when we don't care about the contents, to preserve memory not 311 const GPUVAddr gpu_addr,
183 // written by the new surface. 312 const u8* host_ptr) {
184 FlushSurface(surface); 313 if (!params.is_layered || params.target == SurfaceTarget::Texture3D) {
314 return {};
315 }
316 TSurface new_surface = GetUncachedSurface(gpu_addr, params);
317 for (auto surface : overlaps) {
318 const SurfaceParams& src_params = surface->GetSurfaceParams();
319 if (src_params.is_layered || src_params.num_levels > 1) {
320 // We send this cases to recycle as they are more complex to handle
321 return {};
322 }
323 const std::size_t candidate_size = src_params.GetGuestSizeInBytes();
324 auto mipmap_layer = new_surface->GetLayerMipmap(surface->GetGpuAddr());
325 if (!mipmap_layer) {
326 return {};
185 } 327 }
328 const u32 layer = (*mipmap_layer).first;
329 const u32 mipmap = (*mipmap_layer).second;
330 if (new_surface->GetMipmapSize(mipmap) != candidate_size) {
331 return {};
332 }
333 // Now we got all the data set up
334 CopyParams copy_params{};
335 const u32 dst_width = params.GetMipWidth(mipmap);
336 const u32 dst_height = params.GetMipHeight(mipmap);
337 copy_params.width = std::min(src_params.width, dst_width);
338 copy_params.height = std::min(src_params.height, dst_height);
339 copy_params.depth = 1;
340 copy_params.source_level = 0;
341 copy_params.dest_level = mipmap;
342 copy_params.source_z = 0;
343 copy_params.dest_z = layer;
344 ImageCopy(surface, new_surface, copy_params);
345 }
346 for (auto surface : overlaps) {
186 Unregister(surface); 347 Unregister(surface);
187 } 348 }
188 if (fast_view) { 349 Register(new_surface);
189 return fast_view; 350 return {{new_surface, new_surface->GetMainView()}};
351 }
352
353 std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params,
354 bool preserve_contents) {
355
356 const auto host_ptr{memory_manager->GetPointer(gpu_addr)};
357 const auto cache_addr{ToCacheAddr(host_ptr)};
358 const std::size_t candidate_size = params.GetGuestSizeInBytes();
359 auto overlaps{GetSurfacesInRegionInner(gpu_addr, candidate_size)};
360 if (overlaps.empty()) {
361 return InitializeSurface(gpu_addr, params, preserve_contents);
362 }
363
364 for (auto surface : overlaps) {
365 if (!surface->MatchesTopology(params)) {
366 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
367 true);
368 }
190 } 369 }
191 370
192 return LoadSurfaceView(gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); 371 if (overlaps.size() == 1) {
372 TSurface current_surface = overlaps[0];
373 if (current_surface->MatchesStructure(params) &&
374 current_surface->GetGpuAddr() == gpu_addr &&
375 (params.target != SurfaceTarget::Texture3D ||
376 current_surface->MatchTarget(params.target))) {
377 return ManageStructuralMatch(current_surface, params);
378 }
379 if (current_surface->GetSizeInBytes() <= candidate_size) {
380 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
381 false);
382 }
383 std::optional<TView> view = current_surface->EmplaceView(params, gpu_addr);
384 if (view.has_value()) {
385 const bool is_mirage = !current_surface->MatchFormat(params.pixel_format);
386 if (is_mirage) {
387 LOG_CRITICAL(HW_GPU, "Mirage View Unsupported");
388 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,
389 false);
390 }
391 return {current_surface, *view};
392 }
393 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false);
394 } else {
395 std::optional<std::pair<TSurface, TView>> view =
396 ReconstructSurface(overlaps, params, gpu_addr, host_ptr);
397 if (view.has_value()) {
398 return *view;
399 }
400 return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false);
401 }
193 } 402 }
194 403
195 TView* LoadSurfaceView(GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, 404 std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,
196 const SurfaceParams& params, bool preserve_contents) { 405 bool preserve_contents) {
197 const auto new_surface{GetUncachedSurface(params)}; 406 auto new_surface{GetUncachedSurface(gpu_addr, params)};
198 Register(new_surface, gpu_addr, cpu_addr, host_ptr); 407 Register(new_surface);
199 if (preserve_contents) { 408 if (preserve_contents) {
200 LoadSurface(new_surface); 409 LoadSurface(new_surface);
201 } 410 }
202 return new_surface->GetView(gpu_addr, params); 411 return {new_surface, new_surface->GetMainView()};
203 } 412 }
204 413
205 void LoadSurface(const std::shared_ptr<TSurface>& surface) { 414 void LoadSurface(const TSurface& surface) {
206 surface->LoadBuffer(); 415 staging_buffer.resize(surface->GetHostSizeInBytes());
207 surface->UploadTexture(); 416 surface->LoadBuffer(*memory_manager, staging_buffer);
208 surface->MarkAsModified(false); 417 surface->UploadTexture(staging_buffer);
418 surface->MarkAsModified(false, Tick());
209 } 419 }
210 420
211 void FlushSurface(const std::shared_ptr<TSurface>& surface) { 421 void FlushSurface(const TSurface& surface) {
212 if (!surface->IsModified()) { 422 if (!surface->IsModified()) {
213 return; 423 return;
214 } 424 }
215 surface->DownloadTexture(); 425 staging_buffer.resize(surface->GetHostSizeInBytes());
216 surface->FlushBuffer(); 426 surface->DownloadTexture(staging_buffer);
427 surface->FlushBuffer(staging_buffer);
428 surface->MarkAsModified(false, Tick());
217 } 429 }
218 430
219 std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr, 431 std::vector<TSurface> GetSurfacesInRegion(CacheAddr cache_addr, std::size_t size) const {
220 std::size_t size) const {
221 if (size == 0) { 432 if (size == 0) {
222 return {}; 433 return {};
223 } 434 }
224 const IntervalType interval{cache_addr, cache_addr + size}; 435 const IntervalType interval{cache_addr, cache_addr + size};
225 436
226 std::vector<std::shared_ptr<TSurface>> surfaces; 437 std::vector<TSurface> surfaces;
227 for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) { 438 for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
228 surfaces.push_back(*pair.second.begin()); 439 for (auto& s : pair.second) {
440 if (!s || !s->IsRegistered()) {
441 continue;
442 }
443 surfaces.push_back(s);
444 }
229 } 445 }
230 return surfaces; 446 return surfaces;
231 } 447 }
232 448
233 void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) { 449 void RegisterInnerCache(TSurface& surface) {
450 GPUVAddr start = surface->GetGpuAddr() >> inner_cache_page_bits;
451 const GPUVAddr end = (surface->GetGpuAddrEnd() - 1) >> inner_cache_page_bits;
452 while (start <= end) {
453 inner_cache[start].push_back(surface);
454 start++;
455 }
456 }
457
458 void UnregisterInnerCache(TSurface& surface) {
459 GPUVAddr start = surface->GetGpuAddr() >> inner_cache_page_bits;
460 const GPUVAddr end = (surface->GetGpuAddrEnd() - 1) >> inner_cache_page_bits;
461 while (start <= end) {
462 inner_cache[start].remove(surface);
463 start++;
464 }
465 }
466
467 std::vector<TSurface> GetSurfacesInRegionInner(const GPUVAddr gpu_addr, const std::size_t size) {
468 if (size == 0) {
469 return {};
470 }
471 const GPUVAddr gpu_addr_end = gpu_addr + size;
472 GPUVAddr start = gpu_addr >> inner_cache_page_bits;
473 const GPUVAddr end = (gpu_addr_end - 1) >> inner_cache_page_bits;
474 std::vector<TSurface> surfaces;
475 while (start <= end) {
476 std::list<TSurface>& list = inner_cache[start];
477 for (auto& s : list) {
478 if (!s->IsPicked() && s->Overlaps(gpu_addr, gpu_addr_end)) {
479 s->MarkAsPicked(true);
480 surfaces.push_back(s);
481 }
482 }
483 start++;
484 }
485 for (auto& s : surfaces) {
486 s->MarkAsPicked(false);
487 }
488 return surfaces;
489 }
490
491 void ReserveSurface(const SurfaceParams& params, TSurface surface) {
234 surface_reserve[params].push_back(std::move(surface)); 492 surface_reserve[params].push_back(std::move(surface));
235 } 493 }
236 494
237 std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) { 495 TSurface TryGetReservedSurface(const SurfaceParams& params) {
238 auto search{surface_reserve.find(params)}; 496 auto search{surface_reserve.find(params)};
239 if (search == surface_reserve.end()) { 497 if (search == surface_reserve.end()) {
240 return {}; 498 return {};
@@ -247,21 +505,41 @@ private:
247 return {}; 505 return {};
248 } 506 }
249 507
250 IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const { 508 IntervalType GetInterval(const void* host_ptr, const std::size_t size) const {
251 return IntervalType::right_open(surface->GetCacheAddr(), 509 const CacheAddr addr = ToCacheAddr(host_ptr);
252 surface->GetCacheAddr() + surface->GetSizeInBytes()); 510 return IntervalType::right_open(addr, addr + size);
253 } 511 }
254 512
513 struct RenderInfo {
514 RenderTargetConfig config;
515 TSurface target;
516 TView view;
517 };
518
519 struct DepthBufferInfo {
520 TSurface target;
521 TView view;
522 };
523
255 VideoCore::RasterizerInterface& rasterizer; 524 VideoCore::RasterizerInterface& rasterizer;
525 Tegra::MemoryManager* memory_manager;
256 526
257 u64 ticks{}; 527 u64 ticks{};
258 528
259 IntervalMap registered_surfaces; 529 IntervalMap registered_surfaces;
260 530
531 static constexpr u64 inner_cache_page_bits{20};
532 static constexpr u64 inner_cache_page_size{1 << inner_cache_page_bits};
533 std::unordered_map<GPUVAddr, std::list<TSurface>> inner_cache;
534
261 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have 535 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
262 /// previously been used. This is to prevent surfaces from being constantly created and 536 /// previously been used. This is to prevent surfaces from being constantly created and
263 /// destroyed when used with different surface parameters. 537 /// destroyed when used with different surface parameters.
264 std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve; 538 std::unordered_map<SurfaceParams, std::list<TSurface>> surface_reserve;
539 std::array<RenderInfo, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> render_targets;
540 DepthBufferInfo depth_buffer;
541
542 std::vector<u8> staging_buffer;
265}; 543};
266 544
267} // namespace VideoCommon 545} // namespace VideoCommon