summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-04-24 16:35:54 -0300
committerGravatar ReinUsesLisp2019-06-20 21:36:11 -0300
commit1b4503c571d3b961efe74fa7e35d5fa14941ec09 (patch)
treefb732f50d8bd2855f3fa7657c7c6d36c58134d89 /src
parenttexture_cache: Move staging buffer into a generic implementation (diff)
downloadyuzu-1b4503c571d3b961efe74fa7e35d5fa14941ec09.tar.gz
yuzu-1b4503c571d3b961efe74fa7e35d5fa14941ec09.tar.xz
yuzu-1b4503c571d3b961efe74fa7e35d5fa14941ec09.zip
texture_cache: Split texture cache into different files
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt9
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h2
-rw-r--r--src/video_core/texture_cache.h750
-rw-r--r--src/video_core/texture_cache/surface_base.cpp118
-rw-r--r--src/video_core/texture_cache/surface_base.h172
-rw-r--r--src/video_core/texture_cache/surface_params.cpp (renamed from src/video_core/texture_cache.cpp)126
-rw-r--r--src/video_core/texture_cache/surface_params.h229
-rw-r--r--src/video_core/texture_cache/surface_view.cpp23
-rw-r--r--src/video_core/texture_cache/surface_view.h35
-rw-r--r--src/video_core/texture_cache/texture_cache.h282
-rw-r--r--src/video_core/texture_cache/texture_cache_contextless.h93
12 files changed, 965 insertions, 876 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 64cff27a4..470fbceda 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -109,6 +109,13 @@ add_library(video_core STATIC
109 shader/track.cpp 109 shader/track.cpp
110 surface.cpp 110 surface.cpp
111 surface.h 111 surface.h
112 texture_cache/surface_base.cpp
113 texture_cache/surface_base.h
114 texture_cache/surface_params.cpp
115 texture_cache/surface_params.h
116 texture_cache/surface_view.cpp
117 texture_cache/surface_view.h
118 texture_cache/texture_cache.h
112 textures/astc.cpp 119 textures/astc.cpp
113 textures/astc.h 120 textures/astc.h
114 textures/convert.cpp 121 textures/convert.cpp
@@ -116,8 +123,6 @@ add_library(video_core STATIC
116 textures/decoders.cpp 123 textures/decoders.cpp
117 textures/decoders.h 124 textures/decoders.h
118 textures/texture.h 125 textures/texture.h
119 texture_cache.cpp
120 texture_cache.h
121 video_core.cpp 126 video_core.cpp
122 video_core.h 127 video_core.h
123) 128)
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 3e2a1f53c..ca007b797 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -9,7 +9,7 @@
9#include "video_core/renderer_opengl/gl_resource_manager.h" 9#include "video_core/renderer_opengl/gl_resource_manager.h"
10#include "video_core/renderer_opengl/gl_texture_cache.h" 10#include "video_core/renderer_opengl/gl_texture_cache.h"
11#include "video_core/renderer_opengl/utils.h" 11#include "video_core/renderer_opengl/utils.h"
12#include "video_core/texture_cache.h" 12#include "video_core/texture_cache/texture_cache_contextless.h"
13#include "video_core/textures/convert.h" 13#include "video_core/textures/convert.h"
14#include "video_core/textures/texture.h" 14#include "video_core/textures/texture.h"
15 15
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 0a69be233..3c15b37bd 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -13,7 +13,7 @@
13 13
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "video_core/engines/shader_bytecode.h" 15#include "video_core/engines/shader_bytecode.h"
16#include "video_core/texture_cache.h" 16#include "video_core/texture_cache/texture_cache_contextless.h"
17 17
18namespace OpenGL { 18namespace OpenGL {
19 19
diff --git a/src/video_core/texture_cache.h b/src/video_core/texture_cache.h
deleted file mode 100644
index 90c72cb15..000000000
--- a/src/video_core/texture_cache.h
+++ /dev/null
@@ -1,750 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <list>
8#include <memory>
9#include <set>
10#include <tuple>
11#include <type_traits>
12#include <unordered_map>
13
14#include <boost/icl/interval_map.hpp>
15#include <boost/range/iterator_range.hpp>
16
17#include "common/assert.h"
18#include "common/common_types.h"
19#include "core/memory.h"
20#include "video_core/engines/fermi_2d.h"
21#include "video_core/engines/maxwell_3d.h"
22#include "video_core/gpu.h"
23#include "video_core/memory_manager.h"
24#include "video_core/rasterizer_interface.h"
25#include "video_core/surface.h"
26
27namespace Core {
28class System;
29}
30
31namespace Tegra::Texture {
32struct FullTextureInfo;
33}
34
35namespace VideoCore {
36class RasterizerInterface;
37}
38
39namespace VideoCommon {
40
41class HasheableSurfaceParams {
42public:
43 std::size_t Hash() const;
44
45 bool operator==(const HasheableSurfaceParams& rhs) const;
46
47 bool operator!=(const HasheableSurfaceParams& rhs) const {
48 return !operator==(rhs);
49 }
50
51protected:
52 // Avoid creation outside of a managed environment.
53 HasheableSurfaceParams() = default;
54
55 bool is_tiled;
56 bool srgb_conversion;
57 u32 block_width;
58 u32 block_height;
59 u32 block_depth;
60 u32 tile_width_spacing;
61 u32 width;
62 u32 height;
63 u32 depth;
64 u32 pitch;
65 u32 unaligned_height;
66 u32 num_levels;
67 VideoCore::Surface::PixelFormat pixel_format;
68 VideoCore::Surface::ComponentType component_type;
69 VideoCore::Surface::SurfaceType type;
70 VideoCore::Surface::SurfaceTarget target;
71};
72
73class SurfaceParams final : public HasheableSurfaceParams {
74public:
75 /// Creates SurfaceCachedParams from a texture configuration.
76 static SurfaceParams CreateForTexture(Core::System& system,
77 const Tegra::Texture::FullTextureInfo& config);
78
79 /// Creates SurfaceCachedParams for a depth buffer configuration.
80 static SurfaceParams CreateForDepthBuffer(
81 Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
82 u32 block_width, u32 block_height, u32 block_depth,
83 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type);
84
85 /// Creates SurfaceCachedParams from a framebuffer configuration.
86 static SurfaceParams CreateForFramebuffer(Core::System& system, std::size_t index);
87
88 /// Creates SurfaceCachedParams from a Fermi2D surface configuration.
89 static SurfaceParams CreateForFermiCopySurface(
90 const Tegra::Engines::Fermi2D::Regs::Surface& config);
91
92 bool IsTiled() const {
93 return is_tiled;
94 }
95
96 bool GetSrgbConversion() const {
97 return srgb_conversion;
98 }
99
100 u32 GetBlockWidth() const {
101 return block_width;
102 }
103
104 u32 GetTileWidthSpacing() const {
105 return tile_width_spacing;
106 }
107
108 u32 GetWidth() const {
109 return width;
110 }
111
112 u32 GetHeight() const {
113 return height;
114 }
115
116 u32 GetDepth() const {
117 return depth;
118 }
119
120 u32 GetPitch() const {
121 return pitch;
122 }
123
124 u32 GetNumLevels() const {
125 return num_levels;
126 }
127
128 VideoCore::Surface::PixelFormat GetPixelFormat() const {
129 return pixel_format;
130 }
131
132 VideoCore::Surface::ComponentType GetComponentType() const {
133 return component_type;
134 }
135
136 VideoCore::Surface::SurfaceTarget GetTarget() const {
137 return target;
138 }
139
140 VideoCore::Surface::SurfaceType GetType() const {
141 return type;
142 }
143
144 std::size_t GetGuestSizeInBytes() const {
145 return guest_size_in_bytes;
146 }
147
148 std::size_t GetHostSizeInBytes() const {
149 return host_size_in_bytes;
150 }
151
152 u32 GetNumLayers() const {
153 return num_layers;
154 }
155
156 /// Returns the width of a given mipmap level.
157 u32 GetMipWidth(u32 level) const;
158
159 /// Returns the height of a given mipmap level.
160 u32 GetMipHeight(u32 level) const;
161
162 /// Returns the depth of a given mipmap level.
163 u32 GetMipDepth(u32 level) const;
164
165 /// Returns true if these parameters are from a layered surface.
166 bool IsLayered() const;
167
168 /// Returns the block height of a given mipmap level.
169 u32 GetMipBlockHeight(u32 level) const;
170
171 /// Returns the block depth of a given mipmap level.
172 u32 GetMipBlockDepth(u32 level) const;
173
174 /// Returns the offset in bytes in guest memory of a given mipmap level.
175 std::size_t GetGuestMipmapLevelOffset(u32 level) const;
176
177 /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
178 std::size_t GetHostMipmapLevelOffset(u32 level) const;
179
180 /// Returns the size in bytes in host memory (linear) of a given mipmap level.
181 std::size_t GetHostMipmapSize(u32 level) const;
182
183 /// Returns the size of a layer in bytes in guest memory.
184 std::size_t GetGuestLayerSize() const;
185
186 /// Returns the size of a layer in bytes in host memory for a given mipmap level.
187 std::size_t GetHostLayerSize(u32 level) const;
188
189 /// Returns the default block width.
190 u32 GetDefaultBlockWidth() const;
191
192 /// Returns the default block height.
193 u32 GetDefaultBlockHeight() const;
194
195 /// Returns the bits per pixel.
196 u32 GetBitsPerPixel() const;
197
198 /// Returns the bytes per pixel.
199 u32 GetBytesPerPixel() const;
200
201 /// Returns true if another surface can be familiar with this. This is a loosely defined term
202 /// that reflects the possibility of these two surface parameters potentially being part of a
203 /// bigger superset.
204 bool IsFamiliar(const SurfaceParams& view_params) const;
205
206 /// Returns true if the pixel format is a depth and/or stencil format.
207 bool IsPixelFormatZeta() const;
208
209 /// Creates a map that redirects an address difference to a layer and mipmap level.
210 std::map<u64, std::pair<u32, u32>> CreateViewOffsetMap() const;
211
212 /// Returns true if the passed surface view parameters is equal or a valid subset of this.
213 bool IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const;
214
215private:
216 /// Calculates values that can be deduced from HasheableSurfaceParams.
217 void CalculateCachedValues();
218
219 /// Returns the size of a given mipmap level inside a layer.
220 std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;
221
222 /// Returns the size of all mipmap levels and aligns as needed.
223 std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const;
224
225 /// Returns the size of a layer
226 std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const;
227
228 /// Returns true if the passed view width and height match the size of this params in a given
229 /// mipmap level.
230 bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const;
231
232 /// Returns true if the passed view depth match the size of this params in a given mipmap level.
233 bool IsDepthValid(const SurfaceParams& view_params, u32 level) const;
234
235 /// Returns true if the passed view layers and mipmap levels are in bounds.
236 bool IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const;
237
238 std::size_t guest_size_in_bytes;
239 std::size_t host_size_in_bytes;
240 u32 num_layers;
241};
242
243struct ViewKey {
244 std::size_t Hash() const;
245
246 bool operator==(const ViewKey& rhs) const;
247
248 u32 base_layer{};
249 u32 num_layers{};
250 u32 base_level{};
251 u32 num_levels{};
252};
253
254} // namespace VideoCommon
255
256namespace std {
257
258template <>
259struct hash<VideoCommon::SurfaceParams> {
260 std::size_t operator()(const VideoCommon::SurfaceParams& k) const noexcept {
261 return k.Hash();
262 }
263};
264
265template <>
266struct hash<VideoCommon::ViewKey> {
267 std::size_t operator()(const VideoCommon::ViewKey& k) const noexcept {
268 return k.Hash();
269 }
270};
271
272} // namespace std
273
274namespace VideoCommon {
275
276class SurfaceBaseImpl {
277public:
278 void LoadBuffer();
279
280 void FlushBuffer();
281
282 GPUVAddr GetGpuAddr() const {
283 ASSERT(is_registered);
284 return gpu_addr;
285 }
286
287 VAddr GetCpuAddr() const {
288 ASSERT(is_registered);
289 return cpu_addr;
290 }
291
292 u8* GetHostPtr() const {
293 ASSERT(is_registered);
294 return host_ptr;
295 }
296
297 CacheAddr GetCacheAddr() const {
298 ASSERT(is_registered);
299 return cache_addr;
300 }
301
302 const SurfaceParams& GetSurfaceParams() const {
303 return params;
304 }
305
306 void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) {
307 ASSERT(!is_registered);
308 is_registered = true;
309 gpu_addr = gpu_addr_;
310 cpu_addr = cpu_addr_;
311 host_ptr = host_ptr_;
312 cache_addr = ToCacheAddr(host_ptr_);
313 DecorateSurfaceName();
314 }
315
316 void Unregister() {
317 ASSERT(is_registered);
318 is_registered = false;
319 }
320
321 bool IsRegistered() const {
322 return is_registered;
323 }
324
325 std::size_t GetSizeInBytes() const {
326 return params.GetGuestSizeInBytes();
327 }
328
329 u8* GetStagingBufferLevelData(u32 level) {
330 return staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
331 }
332
333protected:
334 explicit SurfaceBaseImpl(const SurfaceParams& params);
335 ~SurfaceBaseImpl(); // non-virtual is intended
336
337 virtual void DecorateSurfaceName() = 0;
338
339 const SurfaceParams params;
340
341private:
342 GPUVAddr gpu_addr{};
343 VAddr cpu_addr{};
344 u8* host_ptr{};
345 CacheAddr cache_addr{};
346 bool is_registered{};
347
348 std::vector<u8> staging_buffer;
349};
350
351template <typename TTextureCache, typename TView, typename TExecutionContext>
352class SurfaceBase : public SurfaceBaseImpl {
353 static_assert(std::is_trivially_copyable_v<TExecutionContext>);
354
355public:
356 virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
357
358 virtual TExecutionContext DownloadTexture(TExecutionContext exctx) = 0;
359
360 TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
361 if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) {
362 // It can't be a view if it's in a prior address.
363 return {};
364 }
365
366 const auto relative_offset{static_cast<u64>(view_addr - GetGpuAddr())};
367 const auto it{view_offset_map.find(relative_offset)};
368 if (it == view_offset_map.end()) {
369 // Couldn't find an aligned view.
370 return {};
371 }
372 const auto [layer, level] = it->second;
373
374 if (!params.IsViewValid(view_params, layer, level)) {
375 return {};
376 }
377
378 return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
379 }
380
381 void MarkAsModified(bool is_modified_) {
382 is_modified = is_modified_;
383 if (is_modified_) {
384 modification_tick = texture_cache.Tick();
385 }
386 }
387
388 TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
389 TView* view{TryGetView(view_addr, view_params)};
390 ASSERT(view != nullptr);
391 return view;
392 }
393
394 bool IsModified() const {
395 return is_modified;
396 }
397
398 u64 GetModificationTick() const {
399 return modification_tick;
400 }
401
402protected:
403 explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params)
404 : SurfaceBaseImpl{params}, texture_cache{texture_cache},
405 view_offset_map{params.CreateViewOffsetMap()} {}
406
407 ~SurfaceBase() = default;
408
409 virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
410
411private:
412 TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) {
413 const ViewKey key{base_layer, num_layers, base_level, num_levels};
414 const auto [entry, is_cache_miss] = views.try_emplace(key);
415 auto& view{entry->second};
416 if (is_cache_miss) {
417 view = CreateView(key);
418 }
419 return view.get();
420 }
421
422 TTextureCache& texture_cache;
423 const std::map<u64, std::pair<u32, u32>> view_offset_map;
424
425 bool is_modified{};
426 u64 modification_tick{};
427 std::unordered_map<ViewKey, std::unique_ptr<TView>> views;
428};
429
430template <typename TSurface, typename TView, typename TExecutionContext>
431class TextureCache {
432 static_assert(std::is_trivially_copyable_v<TExecutionContext>);
433
434 using ResultType = std::tuple<TView*, TExecutionContext>;
435 using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>;
436 using IntervalType = typename IntervalMap::interval_type;
437
438public:
439 void InvalidateRegion(CacheAddr addr, std::size_t size) {
440 for (const auto& surface : GetSurfacesInRegion(addr, size)) {
441 if (!surface->IsRegistered()) {
442 // Skip duplicates
443 continue;
444 }
445 Unregister(surface);
446 }
447 }
448
449 ResultType GetTextureSurface(TExecutionContext exctx,
450 const Tegra::Texture::FullTextureInfo& config) {
451 const auto gpu_addr{config.tic.Address()};
452 if (!gpu_addr) {
453 return {{}, exctx};
454 }
455 const auto params{SurfaceParams::CreateForTexture(system, config)};
456 return GetSurfaceView(exctx, gpu_addr, params, true);
457 }
458
459 ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) {
460 const auto& regs{system.GPU().Maxwell3D().regs};
461 const auto gpu_addr{regs.zeta.Address()};
462 if (!gpu_addr || !regs.zeta_enable) {
463 return {{}, exctx};
464 }
465 const auto depth_params{SurfaceParams::CreateForDepthBuffer(
466 system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
467 regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
468 regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
469 return GetSurfaceView(exctx, gpu_addr, depth_params, preserve_contents);
470 }
471
472 ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index,
473 bool preserve_contents) {
474 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
475
476 const auto& regs{system.GPU().Maxwell3D().regs};
477 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
478 regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
479 return {{}, exctx};
480 }
481
482 auto& memory_manager{system.GPU().MemoryManager()};
483 const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
484 const auto gpu_addr{config.Address() +
485 config.base_layer * config.layer_stride * sizeof(u32)};
486 if (!gpu_addr) {
487 return {{}, exctx};
488 }
489
490 return GetSurfaceView(exctx, gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
491 preserve_contents);
492 }
493
494 ResultType GetFermiSurface(TExecutionContext exctx,
495 const Tegra::Engines::Fermi2D::Regs::Surface& config) {
496 return GetSurfaceView(exctx, config.Address(),
497 SurfaceParams::CreateForFermiCopySurface(config), true);
498 }
499
500 std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
501 const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
502 return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
503 }
504
505 u64 Tick() {
506 return ++ticks;
507 }
508
509protected:
510 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
511 : system{system}, rasterizer{rasterizer} {}
512
513 ~TextureCache() = default;
514
515 virtual ResultType TryFastGetSurfaceView(
516 TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
517 const SurfaceParams& params, bool preserve_contents,
518 const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
519
520 virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0;
521
522 void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr,
523 u8* host_ptr) {
524 surface->Register(gpu_addr, cpu_addr, host_ptr);
525 registered_surfaces.add({GetSurfaceInterval(surface), {surface}});
526 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1);
527 }
528
529 void Unregister(std::shared_ptr<TSurface> surface) {
530 registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}});
531 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1);
532 surface->Unregister();
533 }
534
535 std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) {
536 if (const auto surface = TryGetReservedSurface(params); surface)
537 return surface;
538 // No reserved surface available, create a new one and reserve it
539 auto new_surface{CreateSurface(params)};
540 ReserveSurface(params, new_surface);
541 return new_surface;
542 }
543
544 Core::System& system;
545
546private:
547 ResultType GetSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr,
548 const SurfaceParams& params, bool preserve_contents) {
549 auto& memory_manager{system.GPU().MemoryManager()};
550 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
551 DEBUG_ASSERT(cpu_addr);
552
553 const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
554 const auto cache_addr{ToCacheAddr(host_ptr)};
555 auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())};
556 if (overlaps.empty()) {
557 return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
558 }
559
560 if (overlaps.size() == 1) {
561 if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) {
562 return {view, exctx};
563 }
564 }
565
566 TView* fast_view;
567 std::tie(fast_view, exctx) = TryFastGetSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr,
568 params, preserve_contents, overlaps);
569
570 if (!fast_view) {
571 std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) {
572 return lhs->GetModificationTick() < rhs->GetModificationTick();
573 });
574 }
575
576 for (const auto& surface : overlaps) {
577 if (!fast_view) {
578 // Flush even when we don't care about the contents, to preserve memory not
579 // written by the new surface.
580 exctx = FlushSurface(exctx, surface);
581 }
582 Unregister(surface);
583 }
584
585 if (fast_view) {
586 return {fast_view, exctx};
587 }
588
589 return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
590 }
591
592 ResultType LoadSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr,
593 u8* host_ptr, const SurfaceParams& params, bool preserve_contents) {
594 const auto new_surface{GetUncachedSurface(params)};
595 Register(new_surface, gpu_addr, cpu_addr, host_ptr);
596 if (preserve_contents) {
597 exctx = LoadSurface(exctx, new_surface);
598 }
599 return {new_surface->GetView(gpu_addr, params), exctx};
600 }
601
602 TExecutionContext LoadSurface(TExecutionContext exctx,
603 const std::shared_ptr<TSurface>& surface) {
604 surface->LoadBuffer();
605 exctx = surface->UploadTexture(exctx);
606 surface->MarkAsModified(false);
607 return exctx;
608 }
609
610 TExecutionContext FlushSurface(TExecutionContext exctx,
611 const std::shared_ptr<TSurface>& surface) {
612 if (!surface->IsModified()) {
613 return exctx;
614 }
615 exctx = surface->DownloadTexture(exctx);
616 surface->FlushBuffer();
617 return exctx;
618 }
619
620 std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,
621 std::size_t size) const {
622 if (size == 0) {
623 return {};
624 }
625 const IntervalType interval{cache_addr, cache_addr + size};
626
627 std::vector<std::shared_ptr<TSurface>> surfaces;
628 for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
629 surfaces.push_back(*pair.second.begin());
630 }
631 return surfaces;
632 }
633
634 void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) {
635 surface_reserve[params].push_back(std::move(surface));
636 }
637
638 std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) {
639 auto search{surface_reserve.find(params)};
640 if (search == surface_reserve.end()) {
641 return {};
642 }
643 for (auto& surface : search->second) {
644 if (!surface->IsRegistered()) {
645 return surface;
646 }
647 }
648 return {};
649 }
650
651 IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const {
652 return IntervalType::right_open(surface->GetCacheAddr(),
653 surface->GetCacheAddr() + surface->GetSizeInBytes());
654 }
655
656 VideoCore::RasterizerInterface& rasterizer;
657
658 u64 ticks{};
659
660 IntervalMap registered_surfaces;
661
662 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
663 /// previously been used. This is to prevent surfaces from being constantly created and
664 /// destroyed when used with different surface parameters.
665 std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve;
666};
667
668struct DummyExecutionContext {};
669
670template <typename TSurface, typename TView>
671class TextureCacheContextless : protected TextureCache<TSurface, TView, DummyExecutionContext> {
672 using Base = TextureCache<TSurface, TView, DummyExecutionContext>;
673
674public:
675 void InvalidateRegion(CacheAddr addr, std::size_t size) {
676 Base::InvalidateRegion(addr, size);
677 }
678
679 TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
680 return RemoveContext(Base::GetTextureSurface({}, config));
681 }
682
683 TView* GetDepthBufferSurface(bool preserve_contents) {
684 return RemoveContext(Base::GetDepthBufferSurface({}, preserve_contents));
685 }
686
687 TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) {
688 return RemoveContext(Base::GetColorBufferSurface({}, index, preserve_contents));
689 }
690
691 TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
692 return RemoveContext(Base::GetFermiSurface({}, config));
693 }
694
695 std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
696 return Base::TryFindFramebufferSurface(host_ptr);
697 }
698
699 u64 Tick() {
700 return Base::Tick();
701 }
702
703protected:
704 explicit TextureCacheContextless(Core::System& system,
705 VideoCore::RasterizerInterface& rasterizer)
706 : TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {}
707
708 virtual TView* TryFastGetSurfaceView(
709 GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
710 bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
711
712private:
713 std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView(
714 DummyExecutionContext, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
715 const SurfaceParams& params, bool preserve_contents,
716 const std::vector<std::shared_ptr<TSurface>>& overlaps) {
717 return {TryFastGetSurfaceView(gpu_addr, cpu_addr, host_ptr, params, preserve_contents,
718 overlaps),
719 {}};
720 }
721
722 TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) {
723 const auto [view, exctx] = return_value;
724 return view;
725 }
726};
727
728template <typename TTextureCache, typename TView>
729class SurfaceBaseContextless : public SurfaceBase<TTextureCache, TView, DummyExecutionContext> {
730public:
731 DummyExecutionContext DownloadTexture(DummyExecutionContext) {
732 DownloadTextureImpl();
733 return {};
734 }
735
736 DummyExecutionContext UploadTexture(DummyExecutionContext) {
737 UploadTextureImpl();
738 return {};
739 }
740
741protected:
742 explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params)
743 : SurfaceBase<TTextureCache, TView, DummyExecutionContext>{texture_cache, params} {}
744
745 virtual void DownloadTextureImpl() = 0;
746
747 virtual void UploadTextureImpl() = 0;
748};
749
750} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp
new file mode 100644
index 000000000..8680485b4
--- /dev/null
+++ b/src/video_core/texture_cache/surface_base.cpp
@@ -0,0 +1,118 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/common_types.h"
7#include "video_core/morton.h"
8#include "video_core/texture_cache/surface_base.h"
9#include "video_core/texture_cache/surface_params.h"
10#include "video_core/textures/convert.h"
11
12namespace VideoCommon {
13
14using Tegra::Texture::ConvertFromGuestToHost;
15using VideoCore::MortonSwizzleMode;
16
17namespace {
18void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
19 u32 level) {
20 const u32 width{params.GetMipWidth(level)};
21 const u32 height{params.GetMipHeight(level)};
22 const u32 block_height{params.GetMipBlockHeight(level)};
23 const u32 block_depth{params.GetMipBlockDepth(level)};
24
25 std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
26 if (params.IsLayered()) {
27 std::size_t host_offset{0};
28 const std::size_t guest_stride = params.GetGuestLayerSize();
29 const std::size_t host_stride = params.GetHostLayerSize(level);
30 for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
31 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
32 1, params.GetTileWidthSpacing(), buffer + host_offset,
33 memory + guest_offset);
34 guest_offset += guest_stride;
35 host_offset += host_stride;
36 }
37 } else {
38 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
39 params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
40 memory + guest_offset);
41 }
42}
43} // Anonymous namespace
44
45SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} {
46 staging_buffer.resize(params.GetHostSizeInBytes());
47}
48
49SurfaceBaseImpl::~SurfaceBaseImpl() = default;
50
51void SurfaceBaseImpl::LoadBuffer() {
52 if (params.IsTiled()) {
53 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
54 params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
55 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
56 u8* const buffer{GetStagingBufferLevelData(level)};
57 SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, buffer, level);
58 }
59 } else {
60 ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
61 const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
62 const u32 block_width{params.GetDefaultBlockWidth()};
63 const u32 block_height{params.GetDefaultBlockHeight()};
64 const u32 width{(params.GetWidth() + block_width - 1) / block_width};
65 const u32 height{(params.GetHeight() + block_height - 1) / block_height};
66 const u32 copy_size{width * bpp};
67 if (params.GetPitch() == copy_size) {
68 std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
69 } else {
70 const u8* start{host_ptr};
71 u8* write_to{staging_buffer.data()};
72 for (u32 h = height; h > 0; --h) {
73 std::memcpy(write_to, start, copy_size);
74 start += params.GetPitch();
75 write_to += copy_size;
76 }
77 }
78 }
79
80 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
81 ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(),
82 params.GetMipWidth(level), params.GetMipHeight(level),
83 params.GetMipDepth(level), true, true);
84 }
85}
86
87void SurfaceBaseImpl::FlushBuffer() {
88 if (params.IsTiled()) {
89 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
90 params.GetBlockWidth());
91 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
92 u8* const buffer = GetStagingBufferLevelData(level);
93 SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
94 }
95 } else {
96 UNIMPLEMENTED();
97 /*
98 ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
99 ASSERT(params.GetNumLevels() == 1);
100
101 const u32 bpp{params.GetFormatBpp() / 8};
102 const u32 copy_size{params.GetWidth() * bpp};
103 if (params.GetPitch() == copy_size) {
104 std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
105 } else {
106 u8* start{host_ptr};
107 const u8* read_to{staging_buffer.data()};
108 for (u32 h = params.GetHeight(); h > 0; --h) {
109 std::memcpy(start, read_to, copy_size);
110 start += params.GetPitch();
111 read_to += copy_size;
112 }
113 }
114 */
115 }
116}
117
118} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h
new file mode 100644
index 000000000..d0142a9e6
--- /dev/null
+++ b/src/video_core/texture_cache/surface_base.h
@@ -0,0 +1,172 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <unordered_map>
8
9#include "common/assert.h"
10#include "common/common_types.h"
11#include "video_core/gpu.h"
12#include "video_core/texture_cache/surface_params.h"
13#include "video_core/texture_cache/surface_view.h"
14
15namespace VideoCommon {
16
17class SurfaceBaseImpl {
18public:
19 void LoadBuffer();
20
21 void FlushBuffer();
22
23 GPUVAddr GetGpuAddr() const {
24 ASSERT(is_registered);
25 return gpu_addr;
26 }
27
28 VAddr GetCpuAddr() const {
29 ASSERT(is_registered);
30 return cpu_addr;
31 }
32
33 u8* GetHostPtr() const {
34 ASSERT(is_registered);
35 return host_ptr;
36 }
37
38 CacheAddr GetCacheAddr() const {
39 ASSERT(is_registered);
40 return cache_addr;
41 }
42
43 const SurfaceParams& GetSurfaceParams() const {
44 return params;
45 }
46
47 void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) {
48 ASSERT(!is_registered);
49 is_registered = true;
50 gpu_addr = gpu_addr_;
51 cpu_addr = cpu_addr_;
52 host_ptr = host_ptr_;
53 cache_addr = ToCacheAddr(host_ptr_);
54 DecorateSurfaceName();
55 }
56
57 void Unregister() {
58 ASSERT(is_registered);
59 is_registered = false;
60 }
61
62 bool IsRegistered() const {
63 return is_registered;
64 }
65
66 std::size_t GetSizeInBytes() const {
67 return params.GetGuestSizeInBytes();
68 }
69
70 u8* GetStagingBufferLevelData(u32 level) {
71 return staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
72 }
73
74protected:
75 explicit SurfaceBaseImpl(const SurfaceParams& params);
76 ~SurfaceBaseImpl(); // non-virtual is intended
77
78 virtual void DecorateSurfaceName() = 0;
79
80 const SurfaceParams params;
81
82private:
83 GPUVAddr gpu_addr{};
84 VAddr cpu_addr{};
85 u8* host_ptr{};
86 CacheAddr cache_addr{};
87 bool is_registered{};
88
89 std::vector<u8> staging_buffer;
90};
91
92template <typename TTextureCache, typename TView, typename TExecutionContext>
93class SurfaceBase : public SurfaceBaseImpl {
94 static_assert(std::is_trivially_copyable_v<TExecutionContext>);
95
96public:
97 virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0;
98
99 virtual TExecutionContext DownloadTexture(TExecutionContext exctx) = 0;
100
101 TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
102 if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) {
103 // It can't be a view if it's in a prior address.
104 return {};
105 }
106
107 const auto relative_offset{static_cast<u64>(view_addr - GetGpuAddr())};
108 const auto it{view_offset_map.find(relative_offset)};
109 if (it == view_offset_map.end()) {
110 // Couldn't find an aligned view.
111 return {};
112 }
113 const auto [layer, level] = it->second;
114
115 if (!params.IsViewValid(view_params, layer, level)) {
116 return {};
117 }
118
119 return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
120 }
121
122 void MarkAsModified(bool is_modified_) {
123 is_modified = is_modified_;
124 if (is_modified_) {
125 modification_tick = texture_cache.Tick();
126 }
127 }
128
129 TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
130 TView* view{TryGetView(view_addr, view_params)};
131 ASSERT(view != nullptr);
132 return view;
133 }
134
135 bool IsModified() const {
136 return is_modified;
137 }
138
139 u64 GetModificationTick() const {
140 return modification_tick;
141 }
142
143protected:
144 explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params)
145 : SurfaceBaseImpl{params}, texture_cache{texture_cache},
146 view_offset_map{params.CreateViewOffsetMap()} {}
147
148 ~SurfaceBase() = default;
149
150 virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
151
152private:
153 TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) {
154 const ViewKey key{base_layer, num_layers, base_level, num_levels};
155 const auto [entry, is_cache_miss] = views.try_emplace(key);
156 auto& view{entry->second};
157 if (is_cache_miss) {
158 view = CreateView(key);
159 }
160 return view.get();
161 }
162
163 TTextureCache& texture_cache;
164 const std::map<u64, std::pair<u32, u32>> view_offset_map;
165
166 std::unordered_map<ViewKey, std::unique_ptr<TView>> views;
167
168 bool is_modified{};
169 u64 modification_tick{};
170};
171
172} // namespace VideoCommon
diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache/surface_params.cpp
index 146e8ed9b..d1f8c53d5 100644
--- a/src/video_core/texture_cache.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -2,22 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/alignment.h" 5#include <map>
6#include "common/assert.h" 6
7#include "common/cityhash.h" 7#include "common/cityhash.h"
8#include "common/common_types.h" 8#include "common/alignment.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "video_core/morton.h"
11#include "video_core/surface.h" 10#include "video_core/surface.h"
12#include "video_core/texture_cache.h" 11#include "video_core/texture_cache/surface_params.h"
13#include "video_core/textures/convert.h"
14#include "video_core/textures/decoders.h" 12#include "video_core/textures/decoders.h"
15#include "video_core/textures/texture.h"
16 13
17namespace VideoCommon { 14namespace VideoCommon {
18 15
19using VideoCore::MortonSwizzleMode;
20
21using VideoCore::Surface::ComponentTypeFromDepthFormat; 16using VideoCore::Surface::ComponentTypeFromDepthFormat;
22using VideoCore::Surface::ComponentTypeFromRenderTarget; 17using VideoCore::Surface::ComponentTypeFromRenderTarget;
23using VideoCore::Surface::ComponentTypeFromTexture; 18using VideoCore::Surface::ComponentTypeFromTexture;
@@ -27,115 +22,12 @@ using VideoCore::Surface::PixelFormatFromTextureFormat;
27using VideoCore::Surface::SurfaceTarget; 22using VideoCore::Surface::SurfaceTarget;
28using VideoCore::Surface::SurfaceTargetFromTextureType; 23using VideoCore::Surface::SurfaceTargetFromTextureType;
29 24
30using Tegra::Texture::ConvertFromGuestToHost;
31
32namespace { 25namespace {
33
34constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { 26constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
35 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile); 27 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
36} 28}
37
38void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
39 u32 level) {
40 const u32 width{params.GetMipWidth(level)};
41 const u32 height{params.GetMipHeight(level)};
42 const u32 block_height{params.GetMipBlockHeight(level)};
43 const u32 block_depth{params.GetMipBlockDepth(level)};
44
45 std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
46 if (params.IsLayered()) {
47 std::size_t host_offset{0};
48 const std::size_t guest_stride = params.GetGuestLayerSize();
49 const std::size_t host_stride = params.GetHostLayerSize(level);
50 for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
51 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
52 1, params.GetTileWidthSpacing(), buffer + host_offset,
53 memory + guest_offset);
54 guest_offset += guest_stride;
55 host_offset += host_stride;
56 }
57 } else {
58 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
59 params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
60 memory + guest_offset);
61 }
62}
63
64} // Anonymous namespace 29} // Anonymous namespace
65 30
66SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} {
67 staging_buffer.resize(params.GetHostSizeInBytes());
68}
69
70SurfaceBaseImpl::~SurfaceBaseImpl() = default;
71
72void SurfaceBaseImpl::LoadBuffer() {
73 if (params.IsTiled()) {
74 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
75 params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
76 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
77 u8* const buffer{GetStagingBufferLevelData(level)};
78 SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, buffer, level);
79 }
80 } else {
81 ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
82 const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
83 const u32 block_width{params.GetDefaultBlockWidth()};
84 const u32 block_height{params.GetDefaultBlockHeight()};
85 const u32 width{(params.GetWidth() + block_width - 1) / block_width};
86 const u32 height{(params.GetHeight() + block_height - 1) / block_height};
87 const u32 copy_size{width * bpp};
88 if (params.GetPitch() == copy_size) {
89 std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
90 } else {
91 const u8* start{host_ptr};
92 u8* write_to{staging_buffer.data()};
93 for (u32 h = height; h > 0; --h) {
94 std::memcpy(write_to, start, copy_size);
95 start += params.GetPitch();
96 write_to += copy_size;
97 }
98 }
99 }
100
101 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
102 ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(),
103 params.GetMipWidth(level), params.GetMipHeight(level),
104 params.GetMipDepth(level), true, true);
105 }
106}
107
108void SurfaceBaseImpl::FlushBuffer() {
109 if (params.IsTiled()) {
110 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
111 params.GetBlockWidth());
112 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
113 u8* const buffer = GetStagingBufferLevelData(level);
114 SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
115 }
116 } else {
117 UNIMPLEMENTED();
118 /*
119 ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
120 ASSERT(params.GetNumLevels() == 1);
121
122 const u32 bpp{params.GetFormatBpp() / 8};
123 const u32 copy_size{params.GetWidth() * bpp};
124 if (params.GetPitch() == copy_size) {
125 std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
126 } else {
127 u8* start{host_ptr};
128 const u8* read_to{staging_buffer.data()};
129 for (u32 h = params.GetHeight(); h > 0; --h) {
130 std::memcpy(start, read_to, copy_size);
131 start += params.GetPitch();
132 read_to += copy_size;
133 }
134 }
135 */
136 }
137}
138
139SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, 31SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
140 const Tegra::Texture::FullTextureInfo& config) { 32 const Tegra::Texture::FullTextureInfo& config) {
141 SurfaceParams params; 33 SurfaceParams params;
@@ -517,14 +409,4 @@ bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const
517 rhs.type, rhs.target); 409 rhs.type, rhs.target);
518} 410}
519 411
520std::size_t ViewKey::Hash() const {
521 return static_cast<std::size_t>(
522 Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
523}
524
525bool ViewKey::operator==(const ViewKey& rhs) const {
526 return std::tie(base_layer, num_layers, base_level, num_levels) ==
527 std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels);
528}
529
530} // namespace VideoCommon 412} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
new file mode 100644
index 000000000..77dc0ba66
--- /dev/null
+++ b/src/video_core/texture_cache/surface_params.h
@@ -0,0 +1,229 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8
9#include "common/common_types.h"
10#include "video_core/engines/fermi_2d.h"
11#include "video_core/engines/maxwell_3d.h"
12#include "video_core/surface.h"
13
14namespace VideoCommon {
15
16class HasheableSurfaceParams {
17public:
18 std::size_t Hash() const;
19
20 bool operator==(const HasheableSurfaceParams& rhs) const;
21
22 bool operator!=(const HasheableSurfaceParams& rhs) const {
23 return !operator==(rhs);
24 }
25
26protected:
27 // Avoid creation outside of a managed environment.
28 HasheableSurfaceParams() = default;
29
30 bool is_tiled;
31 bool srgb_conversion;
32 u32 block_width;
33 u32 block_height;
34 u32 block_depth;
35 u32 tile_width_spacing;
36 u32 width;
37 u32 height;
38 u32 depth;
39 u32 pitch;
40 u32 unaligned_height;
41 u32 num_levels;
42 VideoCore::Surface::PixelFormat pixel_format;
43 VideoCore::Surface::ComponentType component_type;
44 VideoCore::Surface::SurfaceType type;
45 VideoCore::Surface::SurfaceTarget target;
46};
47
48class SurfaceParams final : public HasheableSurfaceParams {
49public:
50 /// Creates SurfaceCachedParams from a texture configuration.
51 static SurfaceParams CreateForTexture(Core::System& system,
52 const Tegra::Texture::FullTextureInfo& config);
53
54 /// Creates SurfaceCachedParams for a depth buffer configuration.
55 static SurfaceParams CreateForDepthBuffer(
56 Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
57 u32 block_width, u32 block_height, u32 block_depth,
58 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type);
59
60 /// Creates SurfaceCachedParams from a framebuffer configuration.
61 static SurfaceParams CreateForFramebuffer(Core::System& system, std::size_t index);
62
63 /// Creates SurfaceCachedParams from a Fermi2D surface configuration.
64 static SurfaceParams CreateForFermiCopySurface(
65 const Tegra::Engines::Fermi2D::Regs::Surface& config);
66
67 bool IsTiled() const {
68 return is_tiled;
69 }
70
71 bool GetSrgbConversion() const {
72 return srgb_conversion;
73 }
74
75 u32 GetBlockWidth() const {
76 return block_width;
77 }
78
79 u32 GetTileWidthSpacing() const {
80 return tile_width_spacing;
81 }
82
83 u32 GetWidth() const {
84 return width;
85 }
86
87 u32 GetHeight() const {
88 return height;
89 }
90
91 u32 GetDepth() const {
92 return depth;
93 }
94
95 u32 GetPitch() const {
96 return pitch;
97 }
98
99 u32 GetNumLevels() const {
100 return num_levels;
101 }
102
103 VideoCore::Surface::PixelFormat GetPixelFormat() const {
104 return pixel_format;
105 }
106
107 VideoCore::Surface::ComponentType GetComponentType() const {
108 return component_type;
109 }
110
111 VideoCore::Surface::SurfaceTarget GetTarget() const {
112 return target;
113 }
114
115 VideoCore::Surface::SurfaceType GetType() const {
116 return type;
117 }
118
119 std::size_t GetGuestSizeInBytes() const {
120 return guest_size_in_bytes;
121 }
122
123 std::size_t GetHostSizeInBytes() const {
124 return host_size_in_bytes;
125 }
126
127 u32 GetNumLayers() const {
128 return num_layers;
129 }
130
131 /// Returns the width of a given mipmap level.
132 u32 GetMipWidth(u32 level) const;
133
134 /// Returns the height of a given mipmap level.
135 u32 GetMipHeight(u32 level) const;
136
137 /// Returns the depth of a given mipmap level.
138 u32 GetMipDepth(u32 level) const;
139
140 /// Returns true if these parameters are from a layered surface.
141 bool IsLayered() const;
142
143 /// Returns the block height of a given mipmap level.
144 u32 GetMipBlockHeight(u32 level) const;
145
146 /// Returns the block depth of a given mipmap level.
147 u32 GetMipBlockDepth(u32 level) const;
148
149 /// Returns the offset in bytes in guest memory of a given mipmap level.
150 std::size_t GetGuestMipmapLevelOffset(u32 level) const;
151
152 /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
153 std::size_t GetHostMipmapLevelOffset(u32 level) const;
154
155 /// Returns the size in bytes in host memory (linear) of a given mipmap level.
156 std::size_t GetHostMipmapSize(u32 level) const;
157
158 /// Returns the size of a layer in bytes in guest memory.
159 std::size_t GetGuestLayerSize() const;
160
161 /// Returns the size of a layer in bytes in host memory for a given mipmap level.
162 std::size_t GetHostLayerSize(u32 level) const;
163
164 /// Returns the default block width.
165 u32 GetDefaultBlockWidth() const;
166
167 /// Returns the default block height.
168 u32 GetDefaultBlockHeight() const;
169
170 /// Returns the bits per pixel.
171 u32 GetBitsPerPixel() const;
172
173 /// Returns the bytes per pixel.
174 u32 GetBytesPerPixel() const;
175
176 /// Returns true if another surface can be familiar with this. This is a loosely defined term
177 /// that reflects the possibility of these two surface parameters potentially being part of a
178 /// bigger superset.
179 bool IsFamiliar(const SurfaceParams& view_params) const;
180
181 /// Returns true if the pixel format is a depth and/or stencil format.
182 bool IsPixelFormatZeta() const;
183
184 /// Creates a map that redirects an address difference to a layer and mipmap level.
185 std::map<u64, std::pair<u32, u32>> CreateViewOffsetMap() const;
186
187 /// Returns true if the passed surface view parameters is equal or a valid subset of this.
188 bool IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const;
189
190private:
191 /// Calculates values that can be deduced from HasheableSurfaceParams.
192 void CalculateCachedValues();
193
194 /// Returns the size of a given mipmap level inside a layer.
195 std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;
196
197 /// Returns the size of all mipmap levels and aligns as needed.
198 std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const;
199
200 /// Returns the size of a layer
201 std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const;
202
203 /// Returns true if the passed view width and height match the size of this params in a given
204 /// mipmap level.
205 bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const;
206
207 /// Returns true if the passed view depth match the size of this params in a given mipmap level.
208 bool IsDepthValid(const SurfaceParams& view_params, u32 level) const;
209
210 /// Returns true if the passed view layers and mipmap levels are in bounds.
211 bool IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const;
212
213 std::size_t guest_size_in_bytes;
214 std::size_t host_size_in_bytes;
215 u32 num_layers;
216};
217
218} // namespace VideoCommon
219
220namespace std {
221
222template <>
223struct hash<VideoCommon::SurfaceParams> {
224 std::size_t operator()(const VideoCommon::SurfaceParams& k) const noexcept {
225 return k.Hash();
226 }
227};
228
229} // namespace std
diff --git a/src/video_core/texture_cache/surface_view.cpp b/src/video_core/texture_cache/surface_view.cpp
new file mode 100644
index 000000000..5f4cdbb1c
--- /dev/null
+++ b/src/video_core/texture_cache/surface_view.cpp
@@ -0,0 +1,23 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <tuple>
6
7#include "common/common_types.h"
8#include "video_core/texture_cache/surface_view.h"
9
10namespace VideoCommon {
11
12std::size_t ViewKey::Hash() const {
13 return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^
14 (static_cast<std::size_t>(base_level) << 32) ^
15 (static_cast<std::size_t>(num_levels) << 48);
16}
17
18bool ViewKey::operator==(const ViewKey& rhs) const {
19 return std::tie(base_layer, num_layers, base_level, num_levels) ==
20 std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels);
21}
22
23} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/surface_view.h b/src/video_core/texture_cache/surface_view.h
new file mode 100644
index 000000000..e73d8f6ae
--- /dev/null
+++ b/src/video_core/texture_cache/surface_view.h
@@ -0,0 +1,35 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8
9#include "common/common_types.h"
10
11namespace VideoCommon {
12
13struct ViewKey {
14 std::size_t Hash() const;
15
16 bool operator==(const ViewKey& rhs) const;
17
18 u32 base_layer{};
19 u32 num_layers{};
20 u32 base_level{};
21 u32 num_levels{};
22};
23
24} // namespace VideoCommon
25
26namespace std {
27
28template <>
29struct hash<VideoCommon::ViewKey> {
30 std::size_t operator()(const VideoCommon::ViewKey& k) const noexcept {
31 return k.Hash();
32 }
33};
34
35} // namespace std
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
new file mode 100644
index 000000000..fb43fa65e
--- /dev/null
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -0,0 +1,282 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <list>
8#include <memory>
9#include <set>
10#include <tuple>
11#include <type_traits>
12#include <unordered_map>
13
14#include <boost/icl/interval_map.hpp>
15#include <boost/range/iterator_range.hpp>
16
17#include "common/assert.h"
18#include "common/common_types.h"
19#include "core/memory.h"
20#include "video_core/engines/fermi_2d.h"
21#include "video_core/engines/maxwell_3d.h"
22#include "video_core/gpu.h"
23#include "video_core/memory_manager.h"
24#include "video_core/rasterizer_interface.h"
25#include "video_core/surface.h"
26#include "video_core/texture_cache/surface_base.h"
27#include "video_core/texture_cache/surface_params.h"
28#include "video_core/texture_cache/surface_view.h"
29
30namespace Core {
31class System;
32}
33
34namespace Tegra::Texture {
35struct FullTextureInfo;
36}
37
38namespace VideoCore {
39class RasterizerInterface;
40}
41
42namespace VideoCommon {
43
44template <typename TSurface, typename TView, typename TExecutionContext>
45class TextureCache {
46 static_assert(std::is_trivially_copyable_v<TExecutionContext>);
47
48 using ResultType = std::tuple<TView*, TExecutionContext>;
49 using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>;
50 using IntervalType = typename IntervalMap::interval_type;
51
52public:
53 void InvalidateRegion(CacheAddr addr, std::size_t size) {
54 for (const auto& surface : GetSurfacesInRegion(addr, size)) {
55 if (!surface->IsRegistered()) {
56 // Skip duplicates
57 continue;
58 }
59 Unregister(surface);
60 }
61 }
62
63 ResultType GetTextureSurface(TExecutionContext exctx,
64 const Tegra::Texture::FullTextureInfo& config) {
65 const auto gpu_addr{config.tic.Address()};
66 if (!gpu_addr) {
67 return {{}, exctx};
68 }
69 const auto params{SurfaceParams::CreateForTexture(system, config)};
70 return GetSurfaceView(exctx, gpu_addr, params, true);
71 }
72
73 ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) {
74 const auto& regs{system.GPU().Maxwell3D().regs};
75 const auto gpu_addr{regs.zeta.Address()};
76 if (!gpu_addr || !regs.zeta_enable) {
77 return {{}, exctx};
78 }
79 const auto depth_params{SurfaceParams::CreateForDepthBuffer(
80 system, regs.zeta_width, regs.zeta_height, regs.zeta.format,
81 regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height,
82 regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)};
83 return GetSurfaceView(exctx, gpu_addr, depth_params, preserve_contents);
84 }
85
86 ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index,
87 bool preserve_contents) {
88 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
89
90 const auto& regs{system.GPU().Maxwell3D().regs};
91 if (index >= regs.rt_control.count || regs.rt[index].Address() == 0 ||
92 regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
93 return {{}, exctx};
94 }
95
96 auto& memory_manager{system.GPU().MemoryManager()};
97 const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
98 const auto gpu_addr{config.Address() +
99 config.base_layer * config.layer_stride * sizeof(u32)};
100 if (!gpu_addr) {
101 return {{}, exctx};
102 }
103
104 return GetSurfaceView(exctx, gpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
105 preserve_contents);
106 }
107
108 ResultType GetFermiSurface(TExecutionContext exctx,
109 const Tegra::Engines::Fermi2D::Regs::Surface& config) {
110 return GetSurfaceView(exctx, config.Address(),
111 SurfaceParams::CreateForFermiCopySurface(config), true);
112 }
113
114 std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
115 const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))};
116 return it != registered_surfaces.end() ? *it->second.begin() : nullptr;
117 }
118
119 u64 Tick() {
120 return ++ticks;
121 }
122
123protected:
124 TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
125 : system{system}, rasterizer{rasterizer} {}
126
127 ~TextureCache() = default;
128
129 virtual ResultType TryFastGetSurfaceView(
130 TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
131 const SurfaceParams& params, bool preserve_contents,
132 const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
133
134 virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0;
135
136 void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr,
137 u8* host_ptr) {
138 surface->Register(gpu_addr, cpu_addr, host_ptr);
139 registered_surfaces.add({GetSurfaceInterval(surface), {surface}});
140 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1);
141 }
142
143 void Unregister(std::shared_ptr<TSurface> surface) {
144 registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}});
145 rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1);
146 surface->Unregister();
147 }
148
149 std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) {
150 if (const auto surface = TryGetReservedSurface(params); surface)
151 return surface;
152 // No reserved surface available, create a new one and reserve it
153 auto new_surface{CreateSurface(params)};
154 ReserveSurface(params, new_surface);
155 return new_surface;
156 }
157
158 Core::System& system;
159
160private:
161 ResultType GetSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr,
162 const SurfaceParams& params, bool preserve_contents) {
163 auto& memory_manager{system.GPU().MemoryManager()};
164 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
165 DEBUG_ASSERT(cpu_addr);
166
167 const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
168 const auto cache_addr{ToCacheAddr(host_ptr)};
169 auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())};
170 if (overlaps.empty()) {
171 return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
172 }
173
174 if (overlaps.size() == 1) {
175 if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) {
176 return {view, exctx};
177 }
178 }
179
180 TView* fast_view;
181 std::tie(fast_view, exctx) = TryFastGetSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr,
182 params, preserve_contents, overlaps);
183
184 if (!fast_view) {
185 std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) {
186 return lhs->GetModificationTick() < rhs->GetModificationTick();
187 });
188 }
189
190 for (const auto& surface : overlaps) {
191 if (!fast_view) {
192 // Flush even when we don't care about the contents, to preserve memory not
193 // written by the new surface.
194 exctx = FlushSurface(exctx, surface);
195 }
196 Unregister(surface);
197 }
198
199 if (fast_view) {
200 return {fast_view, exctx};
201 }
202
203 return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents);
204 }
205
206 ResultType LoadSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr,
207 u8* host_ptr, const SurfaceParams& params, bool preserve_contents) {
208 const auto new_surface{GetUncachedSurface(params)};
209 Register(new_surface, gpu_addr, cpu_addr, host_ptr);
210 if (preserve_contents) {
211 exctx = LoadSurface(exctx, new_surface);
212 }
213 return {new_surface->GetView(gpu_addr, params), exctx};
214 }
215
216 TExecutionContext LoadSurface(TExecutionContext exctx,
217 const std::shared_ptr<TSurface>& surface) {
218 surface->LoadBuffer();
219 exctx = surface->UploadTexture(exctx);
220 surface->MarkAsModified(false);
221 return exctx;
222 }
223
224 TExecutionContext FlushSurface(TExecutionContext exctx,
225 const std::shared_ptr<TSurface>& surface) {
226 if (!surface->IsModified()) {
227 return exctx;
228 }
229 exctx = surface->DownloadTexture(exctx);
230 surface->FlushBuffer();
231 return exctx;
232 }
233
234 std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr,
235 std::size_t size) const {
236 if (size == 0) {
237 return {};
238 }
239 const IntervalType interval{cache_addr, cache_addr + size};
240
241 std::vector<std::shared_ptr<TSurface>> surfaces;
242 for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) {
243 surfaces.push_back(*pair.second.begin());
244 }
245 return surfaces;
246 }
247
248 void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) {
249 surface_reserve[params].push_back(std::move(surface));
250 }
251
252 std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) {
253 auto search{surface_reserve.find(params)};
254 if (search == surface_reserve.end()) {
255 return {};
256 }
257 for (auto& surface : search->second) {
258 if (!surface->IsRegistered()) {
259 return surface;
260 }
261 }
262 return {};
263 }
264
265 IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const {
266 return IntervalType::right_open(surface->GetCacheAddr(),
267 surface->GetCacheAddr() + surface->GetSizeInBytes());
268 }
269
270 VideoCore::RasterizerInterface& rasterizer;
271
272 u64 ticks{};
273
274 IntervalMap registered_surfaces;
275
276 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
277 /// previously been used. This is to prevent surfaces from being constantly created and
278 /// destroyed when used with different surface parameters.
279 std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve;
280};
281
282} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/texture_cache_contextless.h b/src/video_core/texture_cache/texture_cache_contextless.h
new file mode 100644
index 000000000..cd35a9fd4
--- /dev/null
+++ b/src/video_core/texture_cache/texture_cache_contextless.h
@@ -0,0 +1,93 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "video_core/texture_cache/texture_cache.h"
8
9namespace VideoCommon {
10
11struct DummyExecutionContext {};
12
13template <typename TSurface, typename TView>
14class TextureCacheContextless : protected TextureCache<TSurface, TView, DummyExecutionContext> {
15 using Base = TextureCache<TSurface, TView, DummyExecutionContext>;
16
17public:
18 void InvalidateRegion(CacheAddr addr, std::size_t size) {
19 Base::InvalidateRegion(addr, size);
20 }
21
22 TView* GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
23 return RemoveContext(Base::GetTextureSurface({}, config));
24 }
25
26 TView* GetDepthBufferSurface(bool preserve_contents) {
27 return RemoveContext(Base::GetDepthBufferSurface({}, preserve_contents));
28 }
29
30 TView* GetColorBufferSurface(std::size_t index, bool preserve_contents) {
31 return RemoveContext(Base::GetColorBufferSurface({}, index, preserve_contents));
32 }
33
34 TView* GetFermiSurface(const Tegra::Engines::Fermi2D::Regs::Surface& config) {
35 return RemoveContext(Base::GetFermiSurface({}, config));
36 }
37
38 std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const {
39 return Base::TryFindFramebufferSurface(host_ptr);
40 }
41
42 u64 Tick() {
43 return Base::Tick();
44 }
45
46protected:
47 explicit TextureCacheContextless(Core::System& system,
48 VideoCore::RasterizerInterface& rasterizer)
49 : TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {}
50
51 virtual TView* TryFastGetSurfaceView(
52 GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params,
53 bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0;
54
55private:
56 std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView(
57 DummyExecutionContext, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr,
58 const SurfaceParams& params, bool preserve_contents,
59 const std::vector<std::shared_ptr<TSurface>>& overlaps) {
60 return {TryFastGetSurfaceView(gpu_addr, cpu_addr, host_ptr, params, preserve_contents,
61 overlaps),
62 {}};
63 }
64
65 TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) {
66 const auto [view, exctx] = return_value;
67 return view;
68 }
69};
70
71template <typename TTextureCache, typename TView>
72class SurfaceBaseContextless : public SurfaceBase<TTextureCache, TView, DummyExecutionContext> {
73public:
74 DummyExecutionContext DownloadTexture(DummyExecutionContext) {
75 DownloadTextureImpl();
76 return {};
77 }
78
79 DummyExecutionContext UploadTexture(DummyExecutionContext) {
80 UploadTextureImpl();
81 return {};
82 }
83
84protected:
85 explicit SurfaceBaseContextless(TTextureCache& texture_cache, const SurfaceParams& params)
86 : SurfaceBase<TTextureCache, TView, DummyExecutionContext>{texture_cache, params} {}
87
88 virtual void DownloadTextureImpl() = 0;
89
90 virtual void UploadTextureImpl() = 0;
91};
92
93} // namespace VideoCommon