summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/settings.h2
-rw-r--r--src/core/telemetry_session.cpp4
-rw-r--r--src/video_core/memory_manager.cpp10
-rw-r--r--src/video_core/memory_manager.h1
-rw-r--r--src/video_core/rasterizer_cache.h127
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h9
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp28
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp322
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h81
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h11
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp4
-rw-r--r--src/yuzu/configuration/configure_graphics.ui4
-rw-r--r--src/yuzu_cmd/config.cpp4
-rw-r--r--src/yuzu_cmd/default_ini.h4
15 files changed, 429 insertions, 188 deletions
diff --git a/src/core/settings.h b/src/core/settings.h
index 83b9a04c8..8f2da01c8 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -136,7 +136,7 @@ struct Values {
136 float resolution_factor; 136 float resolution_factor;
137 bool use_frame_limit; 137 bool use_frame_limit;
138 u16 frame_limit; 138 u16 frame_limit;
139 bool use_accurate_framebuffers; 139 bool use_accurate_gpu_emulation;
140 140
141 float bg_red; 141 float bg_red;
142 float bg_green; 142 float bg_green;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 7b04792b5..0de13edd3 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -163,8 +163,8 @@ TelemetrySession::TelemetrySession() {
163 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseFrameLimit", 163 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseFrameLimit",
164 Settings::values.use_frame_limit); 164 Settings::values.use_frame_limit);
165 AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit", Settings::values.frame_limit); 165 AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit", Settings::values.frame_limit);
166 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateFramebuffers", 166 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateGpuEmulation",
167 Settings::values.use_accurate_framebuffers); 167 Settings::values.use_accurate_gpu_emulation);
168 AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode", 168 AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode",
169 Settings::values.use_docked_mode); 169 Settings::values.use_docked_mode);
170} 170}
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index ca923d17d..022d4ab74 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -87,6 +87,16 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
87 return gpu_addr; 87 return gpu_addr;
88} 88}
89 89
90GPUVAddr MemoryManager::GetRegionEnd(GPUVAddr region_start) const {
91 for (const auto& region : mapped_regions) {
92 const GPUVAddr region_end{region.gpu_addr + region.size};
93 if (region_start >= region.gpu_addr && region_start < region_end) {
94 return region_end;
95 }
96 }
97 return {};
98}
99
90boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) { 100boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
91 GPUVAddr gpu_addr = 0; 101 GPUVAddr gpu_addr = 0;
92 u64 free_space = 0; 102 u64 free_space = 0;
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 86765e72a..caf80093f 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -26,6 +26,7 @@ public:
26 GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size); 26 GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
27 GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size); 27 GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size);
28 GPUVAddr UnmapBuffer(GPUVAddr gpu_addr, u64 size); 28 GPUVAddr UnmapBuffer(GPUVAddr gpu_addr, u64 size);
29 GPUVAddr GetRegionEnd(GPUVAddr region_start) const;
29 boost::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr); 30 boost::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr);
30 std::vector<GPUVAddr> CpuToGpuAddress(VAddr cpu_addr) const; 31 std::vector<GPUVAddr> CpuToGpuAddress(VAddr cpu_addr) const;
31 32
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 083b283b0..0a3b3951e 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -11,32 +11,77 @@
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/settings.h"
14#include "video_core/rasterizer_interface.h" 15#include "video_core/rasterizer_interface.h"
15#include "video_core/renderer_base.h" 16#include "video_core/renderer_base.h"
16 17
18class RasterizerCacheObject {
19public:
20 /// Gets the address of the shader in guest memory, required for cache management
21 virtual VAddr GetAddr() const = 0;
22
23 /// Gets the size of the shader in guest memory, required for cache management
24 virtual std::size_t GetSizeInBytes() const = 0;
25
26 /// Wriets any cached resources back to memory
27 virtual void Flush() = 0;
28
29 /// Sets whether the cached object should be considered registered
30 void SetIsRegistered(bool registered) {
31 is_registered = registered;
32 }
33
34 /// Returns true if the cached object is registered
35 bool IsRegistered() const {
36 return is_registered;
37 }
38
39 /// Returns true if the cached object is dirty
40 bool IsDirty() const {
41 return is_dirty;
42 }
43
44 /// Returns ticks from when this cached object was last modified
45 u64 GetLastModifiedTicks() const {
46 return last_modified_ticks;
47 }
48
49 /// Marks an object as recently modified, used to specify whether it is clean or dirty
50 template <class T>
51 void MarkAsModified(bool dirty, T& cache) {
52 is_dirty = dirty;
53 last_modified_ticks = cache.GetModifiedTicks();
54 }
55
56private:
57 bool is_registered{}; ///< Whether the object is currently registered with the cache
58 bool is_dirty{}; ///< Whether the object is dirty (out of sync with guest memory)
59 u64 last_modified_ticks{}; ///< When the object was last modified, used for in-order flushing
60};
61
17template <class T> 62template <class T>
18class RasterizerCache : NonCopyable { 63class RasterizerCache : NonCopyable {
64 friend class RasterizerCacheObject;
65
19public: 66public:
67 /// Write any cached resources overlapping the specified region back to memory
68 void FlushRegion(Tegra::GPUVAddr addr, size_t size) {
69 const auto& objects{GetSortedObjectsFromRegion(addr, size)};
70 for (auto& object : objects) {
71 FlushObject(object);
72 }
73 }
74
20 /// Mark the specified region as being invalidated 75 /// Mark the specified region as being invalidated
21 void InvalidateRegion(VAddr addr, u64 size) { 76 void InvalidateRegion(VAddr addr, u64 size) {
22 if (size == 0) 77 const auto& objects{GetSortedObjectsFromRegion(addr, size)};
23 return; 78 for (auto& object : objects) {
24 79 if (!object->IsRegistered()) {
25 const ObjectInterval interval{addr, addr + size}; 80 // Skip duplicates
26 for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) { 81 continue;
27 for (auto& cached_object : pair.second) {
28 if (!cached_object)
29 continue;
30
31 remove_objects.emplace(cached_object);
32 } 82 }
83 Unregister(object);
33 } 84 }
34
35 for (auto& remove_object : remove_objects) {
36 Unregister(remove_object);
37 }
38
39 remove_objects.clear();
40 } 85 }
41 86
42 /// Invalidates everything in the cache 87 /// Invalidates everything in the cache
@@ -62,6 +107,7 @@ protected:
62 107
63 /// Register an object into the cache 108 /// Register an object into the cache
64 void Register(const T& object) { 109 void Register(const T& object) {
110 object->SetIsRegistered(true);
65 object_cache.add({GetInterval(object), ObjectSet{object}}); 111 object_cache.add({GetInterval(object), ObjectSet{object}});
66 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer(); 112 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
67 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1); 113 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1);
@@ -69,12 +115,57 @@ protected:
69 115
70 /// Unregisters an object from the cache 116 /// Unregisters an object from the cache
71 void Unregister(const T& object) { 117 void Unregister(const T& object) {
118 object->SetIsRegistered(false);
72 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer(); 119 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
73 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); 120 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1);
121
122 // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit
123 if (Settings::values.use_accurate_gpu_emulation) {
124 FlushObject(object);
125 }
126
74 object_cache.subtract({GetInterval(object), ObjectSet{object}}); 127 object_cache.subtract({GetInterval(object), ObjectSet{object}});
75 } 128 }
76 129
130 /// Returns a ticks counter used for tracking when cached objects were last modified
131 u64 GetModifiedTicks() {
132 return ++modified_ticks;
133 }
134
77private: 135private:
136 /// Returns a list of cached objects from the specified memory region, ordered by access time
137 std::vector<T> GetSortedObjectsFromRegion(VAddr addr, u64 size) {
138 if (size == 0) {
139 return {};
140 }
141
142 std::vector<T> objects;
143 const ObjectInterval interval{addr, addr + size};
144 for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
145 for (auto& cached_object : pair.second) {
146 if (!cached_object) {
147 continue;
148 }
149 objects.push_back(cached_object);
150 }
151 }
152
153 std::sort(objects.begin(), objects.end(), [](const T& a, const T& b) -> bool {
154 return a->GetLastModifiedTicks() < b->GetLastModifiedTicks();
155 });
156
157 return objects;
158 }
159
160 /// Flushes the specified object, updating appropriate cache state as needed
161 void FlushObject(const T& object) {
162 if (!object->IsDirty()) {
163 return;
164 }
165 object->Flush();
166 object->MarkAsModified(false, *this);
167 }
168
78 using ObjectSet = std::set<T>; 169 using ObjectSet = std::set<T>;
79 using ObjectCache = boost::icl::interval_map<VAddr, ObjectSet>; 170 using ObjectCache = boost::icl::interval_map<VAddr, ObjectSet>;
80 using ObjectInterval = typename ObjectCache::interval_type; 171 using ObjectInterval = typename ObjectCache::interval_type;
@@ -84,6 +175,6 @@ private:
84 object->GetAddr() + object->GetSizeInBytes()); 175 object->GetAddr() + object->GetSizeInBytes());
85 } 176 }
86 177
87 ObjectCache object_cache; 178 ObjectCache object_cache; ///< Cache of objects
88 ObjectSet remove_objects; 179 u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing
89}; 180};
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 965976334..be29dc8be 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -15,15 +15,18 @@
15 15
16namespace OpenGL { 16namespace OpenGL {
17 17
18struct CachedBufferEntry final { 18struct CachedBufferEntry final : public RasterizerCacheObject {
19 VAddr GetAddr() const { 19 VAddr GetAddr() const override {
20 return addr; 20 return addr;
21 } 21 }
22 22
23 std::size_t GetSizeInBytes() const { 23 std::size_t GetSizeInBytes() const override {
24 return size; 24 return size;
25 } 25 }
26 26
27 // We do not have to flush this cache as things in it are never modified by us.
28 void Flush() override {}
29
27 VAddr addr; 30 VAddr addr;
28 std::size_t size; 31 std::size_t size;
29 GLintptr offset; 32 GLintptr offset;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 8d5f277e2..468253033 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -424,6 +424,13 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
424 // Used when just a single color attachment is enabled, e.g. for clearing a color buffer 424 // Used when just a single color attachment is enabled, e.g. for clearing a color buffer
425 Surface color_surface = 425 Surface color_surface =
426 res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); 426 res_cache.GetColorBufferSurface(*single_color_target, preserve_contents);
427
428 if (color_surface) {
429 // Assume that a surface will be written to if it is used as a framebuffer, even if
430 // the shader doesn't actually write to it.
431 color_surface->MarkAsModified(true, res_cache);
432 }
433
427 glFramebufferTexture2D( 434 glFramebufferTexture2D(
428 GL_DRAW_FRAMEBUFFER, 435 GL_DRAW_FRAMEBUFFER,
429 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D, 436 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D,
@@ -434,6 +441,13 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
434 std::array<GLenum, Maxwell::NumRenderTargets> buffers; 441 std::array<GLenum, Maxwell::NumRenderTargets> buffers;
435 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { 442 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
436 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); 443 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
444
445 if (color_surface) {
446 // Assume that a surface will be written to if it is used as a framebuffer, even
447 // if the shader doesn't actually write to it.
448 color_surface->MarkAsModified(true, res_cache);
449 }
450
437 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); 451 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
438 glFramebufferTexture2D( 452 glFramebufferTexture2D(
439 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), 453 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
@@ -453,6 +467,10 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
453 } 467 }
454 468
455 if (depth_surface) { 469 if (depth_surface) {
470 // Assume that a surface will be written to if it is used as a framebuffer, even if
471 // the shader doesn't actually write to it.
472 depth_surface->MarkAsModified(true, res_cache);
473
456 if (regs.stencil_enable) { 474 if (regs.stencil_enable) {
457 // Attach both depth and stencil 475 // Attach both depth and stencil
458 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 476 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
@@ -617,7 +635,14 @@ void RasterizerOpenGL::DrawArrays() {
617 635
618void RasterizerOpenGL::FlushAll() {} 636void RasterizerOpenGL::FlushAll() {}
619 637
620void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {} 638void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
639 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
640
641 if (Settings::values.use_accurate_gpu_emulation) {
642 // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit
643 res_cache.FlushRegion(addr, size);
644 }
645}
621 646
622void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) { 647void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
623 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 648 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
@@ -627,6 +652,7 @@ void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
627} 652}
628 653
629void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) { 654void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
655 FlushRegion(addr, size);
630 InvalidateRegion(addr, size); 656 InvalidateRegion(addr, size);
631} 657}
632 658
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 801d45144..1cb77aaf2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -34,16 +34,53 @@ struct FormatTuple {
34 bool compressed; 34 bool compressed;
35}; 35};
36 36
37static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { 37static bool IsPixelFormatASTC(PixelFormat format) {
38 auto& gpu{Core::System::GetInstance().GPU()}; 38 switch (format) {
39 const auto cpu_addr{gpu.MemoryManager().GpuToCpuAddress(gpu_addr)}; 39 case PixelFormat::ASTC_2D_4X4:
40 return cpu_addr ? *cpu_addr : 0; 40 case PixelFormat::ASTC_2D_5X4:
41 case PixelFormat::ASTC_2D_8X8:
42 case PixelFormat::ASTC_2D_8X5:
43 return true;
44 default:
45 return false;
46 }
47}
48
49static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
50 switch (format) {
51 case PixelFormat::ASTC_2D_4X4:
52 return {4, 4};
53 case PixelFormat::ASTC_2D_5X4:
54 return {5, 4};
55 case PixelFormat::ASTC_2D_8X8:
56 return {8, 8};
57 case PixelFormat::ASTC_2D_8X5:
58 return {8, 5};
59 default:
60 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
61 UNREACHABLE();
62 }
63}
64
65void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
66 auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
67 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)};
68
69 addr = cpu_addr ? *cpu_addr : 0;
70 gpu_addr = gpu_addr_;
71 size_in_bytes = SizeInBytesRaw();
72
73 if (IsPixelFormatASTC(pixel_format)) {
74 // ASTC is uncompressed in software, in emulated as RGBA8
75 size_in_bytes_gl = width * height * depth * 4;
76 } else {
77 size_in_bytes_gl = SizeInBytesGL();
78 }
41} 79}
42 80
43/*static*/ SurfaceParams SurfaceParams::CreateForTexture( 81/*static*/ SurfaceParams SurfaceParams::CreateForTexture(
44 const Tegra::Texture::FullTextureInfo& config, const GLShader::SamplerEntry& entry) { 82 const Tegra::Texture::FullTextureInfo& config, const GLShader::SamplerEntry& entry) {
45 SurfaceParams params{}; 83 SurfaceParams params{};
46 params.addr = TryGetCpuAddr(config.tic.Address());
47 params.is_tiled = config.tic.IsTiled(); 84 params.is_tiled = config.tic.IsTiled();
48 params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, 85 params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0,
49 params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, 86 params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0,
@@ -87,18 +124,18 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
87 break; 124 break;
88 } 125 }
89 126
90 params.size_in_bytes_total = params.SizeInBytesTotal();
91 params.size_in_bytes_2d = params.SizeInBytes2D();
92 params.max_mip_level = config.tic.max_mip_level + 1; 127 params.max_mip_level = config.tic.max_mip_level + 1;
93 params.rt = {}; 128 params.rt = {};
94 129
130 params.InitCacheParameters(config.tic.Address());
131
95 return params; 132 return params;
96} 133}
97 134
98/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(std::size_t index) { 135/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(std::size_t index) {
99 const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]}; 136 const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]};
100 SurfaceParams params{}; 137 SurfaceParams params{};
101 params.addr = TryGetCpuAddr(config.Address()); 138
102 params.is_tiled = 139 params.is_tiled =
103 config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; 140 config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
104 params.block_width = 1 << config.memory_layout.block_width; 141 params.block_width = 1 << config.memory_layout.block_width;
@@ -112,8 +149,6 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
112 params.unaligned_height = config.height; 149 params.unaligned_height = config.height;
113 params.target = SurfaceTarget::Texture2D; 150 params.target = SurfaceTarget::Texture2D;
114 params.depth = 1; 151 params.depth = 1;
115 params.size_in_bytes_total = params.SizeInBytesTotal();
116 params.size_in_bytes_2d = params.SizeInBytes2D();
117 params.max_mip_level = 0; 152 params.max_mip_level = 0;
118 153
119 // Render target specific parameters, not used for caching 154 // Render target specific parameters, not used for caching
@@ -122,6 +157,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
122 params.rt.layer_stride = config.layer_stride; 157 params.rt.layer_stride = config.layer_stride;
123 params.rt.base_layer = config.base_layer; 158 params.rt.base_layer = config.base_layer;
124 159
160 params.InitCacheParameters(config.Address());
161
125 return params; 162 return params;
126} 163}
127 164
@@ -130,7 +167,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
130 u32 block_width, u32 block_height, u32 block_depth, 167 u32 block_width, u32 block_height, u32 block_depth,
131 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) { 168 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) {
132 SurfaceParams params{}; 169 SurfaceParams params{};
133 params.addr = TryGetCpuAddr(zeta_address); 170
134 params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; 171 params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
135 params.block_width = 1 << std::min(block_width, 5U); 172 params.block_width = 1 << std::min(block_width, 5U);
136 params.block_height = 1 << std::min(block_height, 5U); 173 params.block_height = 1 << std::min(block_height, 5U);
@@ -143,18 +180,18 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
143 params.unaligned_height = zeta_height; 180 params.unaligned_height = zeta_height;
144 params.target = SurfaceTarget::Texture2D; 181 params.target = SurfaceTarget::Texture2D;
145 params.depth = 1; 182 params.depth = 1;
146 params.size_in_bytes_total = params.SizeInBytesTotal();
147 params.size_in_bytes_2d = params.SizeInBytes2D();
148 params.max_mip_level = 0; 183 params.max_mip_level = 0;
149 params.rt = {}; 184 params.rt = {};
150 185
186 params.InitCacheParameters(zeta_address);
187
151 return params; 188 return params;
152} 189}
153 190
154/*static*/ SurfaceParams SurfaceParams::CreateForFermiCopySurface( 191/*static*/ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
155 const Tegra::Engines::Fermi2D::Regs::Surface& config) { 192 const Tegra::Engines::Fermi2D::Regs::Surface& config) {
156 SurfaceParams params{}; 193 SurfaceParams params{};
157 params.addr = TryGetCpuAddr(config.Address()); 194
158 params.is_tiled = !config.linear; 195 params.is_tiled = !config.linear;
159 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, 196 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0,
160 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, 197 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0,
@@ -167,11 +204,11 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
167 params.unaligned_height = config.height; 204 params.unaligned_height = config.height;
168 params.target = SurfaceTarget::Texture2D; 205 params.target = SurfaceTarget::Texture2D;
169 params.depth = 1; 206 params.depth = 1;
170 params.size_in_bytes_total = params.SizeInBytesTotal();
171 params.size_in_bytes_2d = params.SizeInBytes2D();
172 params.max_mip_level = 0; 207 params.max_mip_level = 0;
173 params.rt = {}; 208 params.rt = {};
174 209
210 params.InitCacheParameters(config.Address());
211
175 return params; 212 return params;
176} 213}
177 214
@@ -276,34 +313,6 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType
276 return format; 313 return format;
277} 314}
278 315
279static bool IsPixelFormatASTC(PixelFormat format) {
280 switch (format) {
281 case PixelFormat::ASTC_2D_4X4:
282 case PixelFormat::ASTC_2D_5X4:
283 case PixelFormat::ASTC_2D_8X8:
284 case PixelFormat::ASTC_2D_8X5:
285 return true;
286 default:
287 return false;
288 }
289}
290
291static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
292 switch (format) {
293 case PixelFormat::ASTC_2D_4X4:
294 return {4, 4};
295 case PixelFormat::ASTC_2D_5X4:
296 return {5, 4};
297 case PixelFormat::ASTC_2D_8X8:
298 return {8, 8};
299 case PixelFormat::ASTC_2D_8X5:
300 return {8, 5};
301 default:
302 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
303 UNREACHABLE();
304 }
305}
306
307MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { 316MathUtil::Rectangle<u32> SurfaceParams::GetRect() const {
308 u32 actual_height{unaligned_height}; 317 u32 actual_height{unaligned_height};
309 if (IsPixelFormatASTC(pixel_format)) { 318 if (IsPixelFormatASTC(pixel_format)) {
@@ -333,23 +342,21 @@ static bool IsFormatBCn(PixelFormat format) {
333template <bool morton_to_gl, PixelFormat format> 342template <bool morton_to_gl, PixelFormat format>
334void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer, 343void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
335 std::size_t gl_buffer_size, VAddr addr) { 344 std::size_t gl_buffer_size, VAddr addr) {
336 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; 345 constexpr u32 bytes_per_pixel = SurfaceParams::GetBytesPerPixel(format);
337 constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); 346
347 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
348 // pixel values.
349 const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
338 350
339 if (morton_to_gl) { 351 if (morton_to_gl) {
340 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
341 // pixel values.
342 const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
343 const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( 352 const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
344 addr, tile_size, bytes_per_pixel, stride, height, depth, block_height, block_depth); 353 addr, tile_size, bytes_per_pixel, stride, height, depth, block_height, block_depth);
345 const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())}; 354 const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())};
346 memcpy(gl_buffer, data.data(), size_to_copy); 355 memcpy(gl_buffer, data.data(), size_to_copy);
347 } else { 356 } else {
348 // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should 357 Tegra::Texture::CopySwizzledData(stride / tile_size, height / tile_size, depth,
349 // check the configuration for this and perform more generic un/swizzle 358 bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr),
350 LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); 359 gl_buffer, false, block_height, block_depth);
351 VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
352 Memory::GetPointer(addr), gl_buffer, morton_to_gl);
353 } 360 }
354} 361}
355 362
@@ -430,17 +437,16 @@ static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t,
430 MortonCopy<false, PixelFormat::RGBA16UI>, 437 MortonCopy<false, PixelFormat::RGBA16UI>,
431 MortonCopy<false, PixelFormat::R11FG11FB10F>, 438 MortonCopy<false, PixelFormat::R11FG11FB10F>,
432 MortonCopy<false, PixelFormat::RGBA32UI>, 439 MortonCopy<false, PixelFormat::RGBA32UI>,
433 // TODO(Subv): Swizzling DXT1/DXT23/DXT45/DXN1/DXN2/BC7U/BC6H_UF16/BC6H_SF16/ASTC_2D_4X4 440 MortonCopy<false, PixelFormat::DXT1>,
434 // formats are not supported 441 MortonCopy<false, PixelFormat::DXT23>,
435 nullptr, 442 MortonCopy<false, PixelFormat::DXT45>,
436 nullptr, 443 MortonCopy<false, PixelFormat::DXN1>,
437 nullptr, 444 MortonCopy<false, PixelFormat::DXN2UNORM>,
438 nullptr, 445 MortonCopy<false, PixelFormat::DXN2SNORM>,
439 nullptr, 446 MortonCopy<false, PixelFormat::BC7U>,
440 nullptr, 447 MortonCopy<false, PixelFormat::BC6H_UF16>,
441 nullptr, 448 MortonCopy<false, PixelFormat::BC6H_SF16>,
442 nullptr, 449 // TODO(Subv): Swizzling ASTC formats are not supported
443 nullptr,
444 nullptr, 450 nullptr,
445 MortonCopy<false, PixelFormat::G8R8U>, 451 MortonCopy<false, PixelFormat::G8R8U>,
446 MortonCopy<false, PixelFormat::G8R8S>, 452 MortonCopy<false, PixelFormat::G8R8S>,
@@ -626,22 +632,21 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
626 auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type); 632 auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type);
627 auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type); 633 auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type);
628 634
629 std::size_t buffer_size = 635 std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
630 std::max(src_params.size_in_bytes_total, dst_params.size_in_bytes_total);
631 636
632 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); 637 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
633 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); 638 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
634 if (source_format.compressed) { 639 if (source_format.compressed) {
635 glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment, 640 glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment,
636 static_cast<GLsizei>(src_params.size_in_bytes_total), nullptr); 641 static_cast<GLsizei>(src_params.size_in_bytes), nullptr);
637 } else { 642 } else {
638 glGetTextureImage(src_surface->Texture().handle, src_attachment, source_format.format, 643 glGetTextureImage(src_surface->Texture().handle, src_attachment, source_format.format,
639 source_format.type, static_cast<GLsizei>(src_params.size_in_bytes_total), 644 source_format.type, static_cast<GLsizei>(src_params.size_in_bytes),
640 nullptr); 645 nullptr);
641 } 646 }
642 // If the new texture is bigger than the previous one, we need to fill in the rest with data 647 // If the new texture is bigger than the previous one, we need to fill in the rest with data
643 // from the CPU. 648 // from the CPU.
644 if (src_params.size_in_bytes_total < dst_params.size_in_bytes_total) { 649 if (src_params.size_in_bytes < dst_params.size_in_bytes) {
645 // Upload the rest of the memory. 650 // Upload the rest of the memory.
646 if (dst_params.is_tiled) { 651 if (dst_params.is_tiled) {
647 // TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest 652 // TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest
@@ -651,12 +656,12 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
651 LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " 656 LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
652 "reinterpretation but the texture is tiled."); 657 "reinterpretation but the texture is tiled.");
653 } 658 }
654 std::size_t remaining_size = 659 std::size_t remaining_size = dst_params.size_in_bytes - src_params.size_in_bytes;
655 dst_params.size_in_bytes_total - src_params.size_in_bytes_total;
656 std::vector<u8> data(remaining_size); 660 std::vector<u8> data(remaining_size);
657 Memory::ReadBlock(dst_params.addr + src_params.size_in_bytes_total, data.data(), 661 std::memcpy(data.data(), Memory::GetPointer(dst_params.addr + src_params.size_in_bytes),
658 data.size()); 662 data.size());
659 glBufferSubData(GL_PIXEL_PACK_BUFFER, src_params.size_in_bytes_total, remaining_size, 663
664 glBufferSubData(GL_PIXEL_PACK_BUFFER, src_params.size_in_bytes, remaining_size,
660 data.data()); 665 data.data());
661 } 666 }
662 667
@@ -702,7 +707,8 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
702} 707}
703 708
704CachedSurface::CachedSurface(const SurfaceParams& params) 709CachedSurface::CachedSurface(const SurfaceParams& params)
705 : params(params), gl_target(SurfaceTargetToGL(params.target)) { 710 : params(params), gl_target(SurfaceTargetToGL(params.target)),
711 cached_size_in_bytes(params.size_in_bytes) {
706 texture.Create(); 712 texture.Create();
707 const auto& rect{params.GetRect()}; 713 const auto& rect{params.GetRect()};
708 714
@@ -752,9 +758,21 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
752 758
753 VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, 759 VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr,
754 SurfaceParams::SurfaceTargetName(params.target)); 760 SurfaceParams::SurfaceTargetName(params.target));
761
762 // Clamp size to mapped GPU memory region
763 // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000
764 // R32F render buffer. We do not yet know if this is a game bug or something else, but this
765 // check is necessary to prevent flushing from overwriting unmapped memory.
766
767 auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
768 const u64 max_size{memory_manager.GetRegionEnd(params.gpu_addr) - params.gpu_addr};
769 if (cached_size_in_bytes > max_size) {
770 LOG_ERROR(HW_GPU, "Surface size {} exceeds region size {}", params.size_in_bytes, max_size);
771 cached_size_in_bytes = max_size;
772 }
755} 773}
756 774
757static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { 775static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bool reverse) {
758 union S8Z24 { 776 union S8Z24 {
759 BitField<0, 24, u32> z24; 777 BitField<0, 24, u32> z24;
760 BitField<24, 8, u32> s8; 778 BitField<24, 8, u32> s8;
@@ -767,22 +785,29 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
767 }; 785 };
768 static_assert(sizeof(Z24S8) == 4, "Z24S8 is incorrect size"); 786 static_assert(sizeof(Z24S8) == 4, "Z24S8 is incorrect size");
769 787
770 S8Z24 input_pixel{}; 788 S8Z24 s8z24_pixel{};
771 Z24S8 output_pixel{}; 789 Z24S8 z24s8_pixel{};
772 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)}; 790 constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::S8Z24)};
773 for (std::size_t y = 0; y < height; ++y) { 791 for (std::size_t y = 0; y < height; ++y) {
774 for (std::size_t x = 0; x < width; ++x) { 792 for (std::size_t x = 0; x < width; ++x) {
775 const std::size_t offset{bpp * (y * width + x)}; 793 const std::size_t offset{bpp * (y * width + x)};
776 std::memcpy(&input_pixel, &data[offset], sizeof(S8Z24)); 794 if (reverse) {
777 output_pixel.s8.Assign(input_pixel.s8); 795 std::memcpy(&z24s8_pixel, &data[offset], sizeof(Z24S8));
778 output_pixel.z24.Assign(input_pixel.z24); 796 s8z24_pixel.s8.Assign(z24s8_pixel.s8);
779 std::memcpy(&data[offset], &output_pixel, sizeof(Z24S8)); 797 s8z24_pixel.z24.Assign(z24s8_pixel.z24);
798 std::memcpy(&data[offset], &s8z24_pixel, sizeof(S8Z24));
799 } else {
800 std::memcpy(&s8z24_pixel, &data[offset], sizeof(S8Z24));
801 z24s8_pixel.s8.Assign(s8z24_pixel.s8);
802 z24s8_pixel.z24.Assign(s8z24_pixel.z24);
803 std::memcpy(&data[offset], &z24s8_pixel, sizeof(Z24S8));
804 }
780 } 805 }
781 } 806 }
782} 807}
783 808
784static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { 809static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
785 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)}; 810 constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::G8R8U)};
786 for (std::size_t y = 0; y < height; ++y) { 811 for (std::size_t y = 0; y < height; ++y) {
787 for (std::size_t x = 0; x < width; ++x) { 812 for (std::size_t x = 0; x < width; ++x) {
788 const std::size_t offset{bpp * (y * width + x)}; 813 const std::size_t offset{bpp * (y * width + x)};
@@ -814,7 +839,7 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
814 } 839 }
815 case PixelFormat::S8Z24: 840 case PixelFormat::S8Z24:
816 // Convert the S8Z24 depth format to Z24S8, as OpenGL does not support S8Z24. 841 // Convert the S8Z24 depth format to Z24S8, as OpenGL does not support S8Z24.
817 ConvertS8Z24ToZ24S8(data, width, height); 842 ConvertS8Z24ToZ24S8(data, width, height, false);
818 break; 843 break;
819 844
820 case PixelFormat::G8R8U: 845 case PixelFormat::G8R8U:
@@ -825,22 +850,36 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
825 } 850 }
826} 851}
827 852
853/**
854 * Helper function to perform software conversion (as needed) when flushing a buffer from OpenGL to
855 * Switch memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or
856 * with typical desktop GPUs.
857 */
858static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
859 u32 width, u32 height) {
860 switch (pixel_format) {
861 case PixelFormat::G8R8U:
862 case PixelFormat::G8R8S:
863 case PixelFormat::ASTC_2D_4X4:
864 case PixelFormat::ASTC_2D_8X8: {
865 LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented",
866 static_cast<u32>(pixel_format));
867 UNREACHABLE();
868 break;
869 }
870 case PixelFormat::S8Z24:
871 // Convert the Z24S8 depth format to S8Z24, as OpenGL does not support S8Z24.
872 ConvertS8Z24ToZ24S8(data, width, height, true);
873 break;
874 }
875}
876
828MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 877MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
829void CachedSurface::LoadGLBuffer() { 878void CachedSurface::LoadGLBuffer() {
830 ASSERT(params.type != SurfaceType::Fill);
831
832 const u8* const texture_src_data = Memory::GetPointer(params.addr);
833
834 ASSERT(texture_src_data);
835
836 const u32 bytes_per_pixel = GetGLBytesPerPixel(params.pixel_format);
837 const u32 copy_size = params.width * params.height * bytes_per_pixel;
838 const std::size_t total_size = copy_size * params.depth;
839
840 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 879 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
841 880
881 gl_buffer.resize(params.size_in_bytes_gl);
842 if (params.is_tiled) { 882 if (params.is_tiled) {
843 gl_buffer.resize(total_size);
844 u32 depth = params.depth; 883 u32 depth = params.depth;
845 u32 block_depth = params.block_depth; 884 u32 block_depth = params.block_depth;
846 885
@@ -853,13 +892,12 @@ void CachedSurface::LoadGLBuffer() {
853 block_depth = 1U; 892 block_depth = 1U;
854 } 893 }
855 894
856 const std::size_t size = copy_size * depth;
857
858 morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)]( 895 morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)](
859 params.width, params.block_height, params.height, block_depth, depth, gl_buffer.data(), 896 params.width, params.block_height, params.height, block_depth, depth, gl_buffer.data(),
860 size, params.addr); 897 gl_buffer.size(), params.addr);
861 } else { 898 } else {
862 const u8* const texture_src_data_end{texture_src_data + total_size}; 899 const auto texture_src_data{Memory::GetPointer(params.addr)};
900 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
863 gl_buffer.assign(texture_src_data, texture_src_data_end); 901 gl_buffer.assign(texture_src_data, texture_src_data_end);
864 } 902 }
865 903
@@ -868,7 +906,44 @@ void CachedSurface::LoadGLBuffer() {
868 906
869MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 907MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
870void CachedSurface::FlushGLBuffer() { 908void CachedSurface::FlushGLBuffer() {
871 ASSERT_MSG(false, "Unimplemented"); 909 MICROPROFILE_SCOPE(OpenGL_SurfaceFlush);
910
911 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented");
912
913 // OpenGL temporary buffer needs to be big enough to store raw texture size
914 gl_buffer.resize(GetSizeInBytes());
915
916 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
917 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
918 ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0);
919 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
920 ASSERT(!tuple.compressed);
921 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
922 glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, gl_buffer.size(),
923 gl_buffer.data());
924 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
925 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width,
926 params.height);
927 ASSERT(params.type != SurfaceType::Fill);
928 const u8* const texture_src_data = Memory::GetPointer(params.addr);
929 ASSERT(texture_src_data);
930 if (params.is_tiled) {
931 u32 depth = params.depth;
932 u32 block_depth = params.block_depth;
933
934 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
935 params.block_width, static_cast<u32>(params.target));
936
937 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
938 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
939 depth = 1U;
940 }
941 gl_to_morton_fns[static_cast<size_t>(params.pixel_format)](
942 params.width, params.block_height, params.height, block_depth, depth, gl_buffer.data(),
943 gl_buffer.size(), GetAddr());
944 } else {
945 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes());
946 }
872} 947}
873 948
874MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 949MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
@@ -878,9 +953,6 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
878 953
879 MICROPROFILE_SCOPE(OpenGL_TextureUL); 954 MICROPROFILE_SCOPE(OpenGL_TextureUL);
880 955
881 ASSERT(gl_buffer.size() == static_cast<std::size_t>(params.width) * params.height *
882 GetGLBytesPerPixel(params.pixel_format) * params.depth);
883
884 const auto& rect{params.GetRect()}; 956 const auto& rect{params.GetRect()};
885 957
886 // Load data from memory to the surface 958 // Load data from memory to the surface
@@ -889,7 +961,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
889 std::size_t buffer_offset = 961 std::size_t buffer_offset =
890 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + 962 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width +
891 static_cast<std::size_t>(x0)) * 963 static_cast<std::size_t>(x0)) *
892 GetGLBytesPerPixel(params.pixel_format); 964 SurfaceParams::GetBytesPerPixel(params.pixel_format);
893 965
894 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 966 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
895 const GLuint target_tex = texture.handle; 967 const GLuint target_tex = texture.handle;
@@ -905,7 +977,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
905 cur_state.Apply(); 977 cur_state.Apply();
906 978
907 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 979 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
908 ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0); 980 ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0);
909 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); 981 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width));
910 982
911 glActiveTexture(GL_TEXTURE0); 983 glActiveTexture(GL_TEXTURE0);
@@ -915,7 +987,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
915 glCompressedTexImage2D( 987 glCompressedTexImage2D(
916 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 988 SurfaceTargetToGL(params.target), 0, tuple.internal_format,
917 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, 989 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0,
918 static_cast<GLsizei>(params.size_in_bytes_2d), &gl_buffer[buffer_offset]); 990 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]);
919 break; 991 break;
920 case SurfaceParams::SurfaceTarget::Texture3D: 992 case SurfaceParams::SurfaceTarget::Texture3D:
921 case SurfaceParams::SurfaceTarget::Texture2DArray: 993 case SurfaceParams::SurfaceTarget::Texture2DArray:
@@ -923,16 +995,16 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
923 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 995 SurfaceTargetToGL(params.target), 0, tuple.internal_format,
924 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 996 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height),
925 static_cast<GLsizei>(params.depth), 0, 997 static_cast<GLsizei>(params.depth), 0,
926 static_cast<GLsizei>(params.size_in_bytes_total), &gl_buffer[buffer_offset]); 998 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]);
927 break; 999 break;
928 case SurfaceParams::SurfaceTarget::TextureCubemap: 1000 case SurfaceParams::SurfaceTarget::TextureCubemap:
929 for (std::size_t face = 0; face < params.depth; ++face) { 1001 for (std::size_t face = 0; face < params.depth; ++face) {
930 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 1002 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
931 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1003 0, tuple.internal_format, static_cast<GLsizei>(params.width),
932 static_cast<GLsizei>(params.height), 0, 1004 static_cast<GLsizei>(params.height), 0,
933 static_cast<GLsizei>(params.size_in_bytes_2d), 1005 static_cast<GLsizei>(params.SizeInBytesCubeFaceGL()),
934 &gl_buffer[buffer_offset]); 1006 &gl_buffer[buffer_offset]);
935 buffer_offset += params.size_in_bytes_2d; 1007 buffer_offset += params.SizeInBytesCubeFace();
936 } 1008 }
937 break; 1009 break;
938 default: 1010 default:
@@ -942,7 +1014,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
942 glCompressedTexImage2D( 1014 glCompressedTexImage2D(
943 GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1015 GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width),
944 static_cast<GLsizei>(params.height), 0, 1016 static_cast<GLsizei>(params.height), 0,
945 static_cast<GLsizei>(params.size_in_bytes_2d), &gl_buffer[buffer_offset]); 1017 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]);
946 } 1018 }
947 } else { 1019 } else {
948 1020
@@ -971,7 +1043,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
971 y0, static_cast<GLsizei>(rect.GetWidth()), 1043 y0, static_cast<GLsizei>(rect.GetWidth()),
972 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1044 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
973 &gl_buffer[buffer_offset]); 1045 &gl_buffer[buffer_offset]);
974 buffer_offset += params.size_in_bytes_2d; 1046 buffer_offset += params.SizeInBytesCubeFace();
975 } 1047 }
976 break; 1048 break;
977 default: 1049 default:
@@ -1033,10 +1105,7 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre
1033void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { 1105void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
1034 surface->LoadGLBuffer(); 1106 surface->LoadGLBuffer();
1035 surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); 1107 surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle);
1036} 1108 surface->MarkAsModified(false, *this);
1037
1038void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) {
1039 surface->FlushGLBuffer();
1040} 1109}
1041 1110
1042Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) { 1111Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) {
@@ -1105,6 +1174,14 @@ void RasterizerCacheOpenGL::FermiCopySurface(
1105 FastCopySurface(GetSurface(src_params, true), GetSurface(dst_params, false)); 1174 FastCopySurface(GetSurface(src_params, true), GetSurface(dst_params, false));
1106} 1175}
1107 1176
1177void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface,
1178 const Surface& dst_surface) {
1179 const auto& src_params{src_surface->GetSurfaceParams()};
1180 const auto& dst_params{dst_surface->GetSurfaceParams()};
1181 FlushRegion(src_params.addr, dst_params.size_in_bytes);
1182 LoadSurface(dst_surface);
1183}
1184
1108Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, 1185Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1109 const SurfaceParams& new_params) { 1186 const SurfaceParams& new_params) {
1110 // Verify surface is compatible for blitting 1187 // Verify surface is compatible for blitting
@@ -1113,6 +1190,12 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1113 // Get a new surface with the new parameters, and blit the previous surface to it 1190 // Get a new surface with the new parameters, and blit the previous surface to it
1114 Surface new_surface{GetUncachedSurface(new_params)}; 1191 Surface new_surface{GetUncachedSurface(new_params)};
1115 1192
1193 // With use_accurate_gpu_emulation enabled, do an accurate surface copy
1194 if (Settings::values.use_accurate_gpu_emulation) {
1195 AccurateCopySurface(old_surface, new_surface);
1196 return new_surface;
1197 }
1198
1116 // For compatible surfaces, we can just do fast glCopyImageSubData based copy 1199 // For compatible surfaces, we can just do fast glCopyImageSubData based copy
1117 if (old_params.target == new_params.target && old_params.type == new_params.type && 1200 if (old_params.target == new_params.target && old_params.type == new_params.type &&
1118 old_params.depth == new_params.depth && old_params.depth == 1 && 1201 old_params.depth == new_params.depth && old_params.depth == 1 &&
@@ -1124,11 +1207,10 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1124 1207
1125 // If the format is the same, just do a framebuffer blit. This is significantly faster than 1208 // If the format is the same, just do a framebuffer blit. This is significantly faster than
1126 // using PBOs. The is also likely less accurate, as textures will be converted rather than 1209 // using PBOs. The is also likely less accurate, as textures will be converted rather than
1127 // reinterpreted. When use_accurate_framebuffers setting is enabled, perform a more accurate 1210 // reinterpreted. When use_accurate_gpu_emulation setting is enabled, perform a more accurate
1128 // surface copy, where pixels are reinterpreted as a new format (without conversion). This 1211 // surface copy, where pixels are reinterpreted as a new format (without conversion). This
1129 // code path uses OpenGL PBOs and is quite slow. 1212 // code path uses OpenGL PBOs and is quite slow.
1130 const bool is_blit{old_params.pixel_format == new_params.pixel_format || 1213 const bool is_blit{old_params.pixel_format == new_params.pixel_format};
1131 !Settings::values.use_accurate_framebuffers};
1132 1214
1133 switch (new_params.target) { 1215 switch (new_params.target) {
1134 case SurfaceParams::SurfaceTarget::Texture2D: 1216 case SurfaceParams::SurfaceTarget::Texture2D:
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 0b8ae3eb4..7c1cb72d0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -18,6 +18,7 @@
18#include "video_core/rasterizer_cache.h" 18#include "video_core/rasterizer_cache.h"
19#include "video_core/renderer_opengl/gl_resource_manager.h" 19#include "video_core/renderer_opengl/gl_resource_manager.h"
20#include "video_core/renderer_opengl/gl_shader_gen.h" 20#include "video_core/renderer_opengl/gl_shader_gen.h"
21#include "video_core/textures/decoders.h"
21#include "video_core/textures/texture.h" 22#include "video_core/textures/texture.h"
22 23
23namespace OpenGL { 24namespace OpenGL {
@@ -701,21 +702,42 @@ struct SurfaceParams {
701 return SurfaceType::Invalid; 702 return SurfaceType::Invalid;
702 } 703 }
703 704
705 /// Returns the sizer in bytes of the specified pixel format
706 static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
707 if (pixel_format == SurfaceParams::PixelFormat::Invalid) {
708 return 0;
709 }
710 return GetFormatBpp(pixel_format) / CHAR_BIT;
711 }
712
704 /// Returns the rectangle corresponding to this surface 713 /// Returns the rectangle corresponding to this surface
705 MathUtil::Rectangle<u32> GetRect() const; 714 MathUtil::Rectangle<u32> GetRect() const;
706 715
707 /// Returns the size of this surface as a 2D texture in bytes, adjusted for compression 716 /// Returns the total size of this surface in bytes, adjusted for compression
708 std::size_t SizeInBytes2D() const { 717 std::size_t SizeInBytesRaw(bool ignore_tiled = false) const {
709 const u32 compression_factor{GetCompressionFactor(pixel_format)}; 718 const u32 compression_factor{GetCompressionFactor(pixel_format)};
710 ASSERT(width % compression_factor == 0); 719 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
711 ASSERT(height % compression_factor == 0); 720 const size_t uncompressed_size{
712 return (width / compression_factor) * (height / compression_factor) * 721 Tegra::Texture::CalculateSize((ignore_tiled ? false : is_tiled), bytes_per_pixel, width,
713 GetFormatBpp(pixel_format) / CHAR_BIT; 722 height, depth, block_height, block_depth)};
723
724 // Divide by compression_factor^2, as height and width are factored by this
725 return uncompressed_size / (compression_factor * compression_factor);
714 } 726 }
715 727
716 /// Returns the total size of this surface in bytes, adjusted for compression 728 /// Returns the size of this surface as an OpenGL texture in bytes
717 std::size_t SizeInBytesTotal() const { 729 std::size_t SizeInBytesGL() const {
718 return SizeInBytes2D() * depth; 730 return SizeInBytesRaw(true);
731 }
732
733 /// Returns the size of this surface as a cube face in bytes
734 std::size_t SizeInBytesCubeFace() const {
735 return size_in_bytes / 6;
736 }
737
738 /// Returns the size of this surface as an OpenGL cube face in bytes
739 std::size_t SizeInBytesCubeFaceGL() const {
740 return size_in_bytes_gl / 6;
719 } 741 }
720 742
721 /// Creates SurfaceParams from a texture configuration 743 /// Creates SurfaceParams from a texture configuration
@@ -742,7 +764,9 @@ struct SurfaceParams {
742 other.depth); 764 other.depth);
743 } 765 }
744 766
745 VAddr addr; 767 /// Initializes parameters for caching, should be called after everything has been initialized
768 void InitCacheParameters(Tegra::GPUVAddr gpu_addr);
769
746 bool is_tiled; 770 bool is_tiled;
747 u32 block_width; 771 u32 block_width;
748 u32 block_height; 772 u32 block_height;
@@ -754,11 +778,15 @@ struct SurfaceParams {
754 u32 height; 778 u32 height;
755 u32 depth; 779 u32 depth;
756 u32 unaligned_height; 780 u32 unaligned_height;
757 std::size_t size_in_bytes_total;
758 std::size_t size_in_bytes_2d;
759 SurfaceTarget target; 781 SurfaceTarget target;
760 u32 max_mip_level; 782 u32 max_mip_level;
761 783
784 // Parameters used for caching
785 VAddr addr;
786 Tegra::GPUVAddr gpu_addr;
787 std::size_t size_in_bytes;
788 std::size_t size_in_bytes_gl;
789
762 // Render target specific parameters, not used in caching 790 // Render target specific parameters, not used in caching
763 struct { 791 struct {
764 u32 index; 792 u32 index;
@@ -775,7 +803,8 @@ struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> {
775 static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) { 803 static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) {
776 SurfaceReserveKey res; 804 SurfaceReserveKey res;
777 res.state = params; 805 res.state = params;
778 res.state.rt = {}; // Ignore rt config in caching 806 res.state.gpu_addr = {}; // Ignore GPU vaddr in caching
807 res.state.rt = {}; // Ignore rt config in caching
779 return res; 808 return res;
780 } 809 }
781}; 810};
@@ -790,16 +819,20 @@ struct hash<SurfaceReserveKey> {
790 819
791namespace OpenGL { 820namespace OpenGL {
792 821
793class CachedSurface final { 822class CachedSurface final : public RasterizerCacheObject {
794public: 823public:
795 CachedSurface(const SurfaceParams& params); 824 CachedSurface(const SurfaceParams& params);
796 825
797 VAddr GetAddr() const { 826 VAddr GetAddr() const override {
798 return params.addr; 827 return params.addr;
799 } 828 }
800 829
801 std::size_t GetSizeInBytes() const { 830 std::size_t GetSizeInBytes() const override {
802 return params.size_in_bytes_total; 831 return cached_size_in_bytes;
832 }
833
834 void Flush() override {
835 FlushGLBuffer();
803 } 836 }
804 837
805 const OGLTexture& Texture() const { 838 const OGLTexture& Texture() const {
@@ -810,13 +843,6 @@ public:
810 return gl_target; 843 return gl_target;
811 } 844 }
812 845
813 static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) {
814 if (format == SurfaceParams::PixelFormat::Invalid)
815 return 0;
816
817 return SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
818 }
819
820 const SurfaceParams& GetSurfaceParams() const { 846 const SurfaceParams& GetSurfaceParams() const {
821 return params; 847 return params;
822 } 848 }
@@ -833,6 +859,7 @@ private:
833 std::vector<u8> gl_buffer; 859 std::vector<u8> gl_buffer;
834 SurfaceParams params; 860 SurfaceParams params;
835 GLenum gl_target; 861 GLenum gl_target;
862 std::size_t cached_size_in_bytes;
836}; 863};
837 864
838class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { 865class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
@@ -849,9 +876,6 @@ public:
849 /// Get the color surface based on the framebuffer configuration and the specified render target 876 /// Get the color surface based on the framebuffer configuration and the specified render target
850 Surface GetColorBufferSurface(std::size_t index, bool preserve_contents); 877 Surface GetColorBufferSurface(std::size_t index, bool preserve_contents);
851 878
852 /// Flushes the surface to Switch memory
853 void FlushSurface(const Surface& surface);
854
855 /// Tries to find a framebuffer using on the provided CPU address 879 /// Tries to find a framebuffer using on the provided CPU address
856 Surface TryFindFramebufferSurface(VAddr addr) const; 880 Surface TryFindFramebufferSurface(VAddr addr) const;
857 881
@@ -875,6 +899,9 @@ private:
875 /// Tries to get a reserved surface for the specified parameters 899 /// Tries to get a reserved surface for the specified parameters
876 Surface TryGetReservedSurface(const SurfaceParams& params); 900 Surface TryGetReservedSurface(const SurfaceParams& params);
877 901
902 /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data
903 void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
904
878 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have 905 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
879 /// previously been used. This is to prevent surfaces from being constantly created and 906 /// previously been used. This is to prevent surfaces from being constantly created and
880 /// destroyed when used with different surface parameters. 907 /// destroyed when used with different surface parameters.
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 7bb287f56..a210f1731 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -19,20 +19,21 @@ class CachedShader;
19using Shader = std::shared_ptr<CachedShader>; 19using Shader = std::shared_ptr<CachedShader>;
20using Maxwell = Tegra::Engines::Maxwell3D::Regs; 20using Maxwell = Tegra::Engines::Maxwell3D::Regs;
21 21
22class CachedShader final { 22class CachedShader final : public RasterizerCacheObject {
23public: 23public:
24 CachedShader(VAddr addr, Maxwell::ShaderProgram program_type); 24 CachedShader(VAddr addr, Maxwell::ShaderProgram program_type);
25 25
26 /// Gets the address of the shader in guest memory, required for cache management 26 VAddr GetAddr() const override {
27 VAddr GetAddr() const {
28 return addr; 27 return addr;
29 } 28 }
30 29
31 /// Gets the size of the shader in guest memory, required for cache management 30 std::size_t GetSizeInBytes() const override {
32 std::size_t GetSizeInBytes() const {
33 return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64); 31 return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
34 } 32 }
35 33
34 // We do not have to flush this cache as things in it are never modified by us.
35 void Flush() override {}
36
36 /// Gets the shader entries for the shader 37 /// Gets the shader entries for the shader
37 const GLShader::ShaderEntries& GetShaderEntries() const { 38 const GLShader::ShaderEntries& GetShaderEntries() const {
38 return entries; 39 return entries;
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 7fec15991..71c6ebb41 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -85,8 +85,8 @@ void Config::ReadValues() {
85 Settings::values.resolution_factor = qt_config->value("resolution_factor", 1.0).toFloat(); 85 Settings::values.resolution_factor = qt_config->value("resolution_factor", 1.0).toFloat();
86 Settings::values.use_frame_limit = qt_config->value("use_frame_limit", true).toBool(); 86 Settings::values.use_frame_limit = qt_config->value("use_frame_limit", true).toBool();
87 Settings::values.frame_limit = qt_config->value("frame_limit", 100).toInt(); 87 Settings::values.frame_limit = qt_config->value("frame_limit", 100).toInt();
88 Settings::values.use_accurate_framebuffers = 88 Settings::values.use_accurate_gpu_emulation =
89 qt_config->value("use_accurate_framebuffers", false).toBool(); 89 qt_config->value("use_accurate_gpu_emulation", false).toBool();
90 90
91 Settings::values.bg_red = qt_config->value("bg_red", 0.0).toFloat(); 91 Settings::values.bg_red = qt_config->value("bg_red", 0.0).toFloat();
92 Settings::values.bg_green = qt_config->value("bg_green", 0.0).toFloat(); 92 Settings::values.bg_green = qt_config->value("bg_green", 0.0).toFloat();
@@ -233,7 +233,7 @@ void Config::SaveValues() {
233 qt_config->setValue("resolution_factor", (double)Settings::values.resolution_factor); 233 qt_config->setValue("resolution_factor", (double)Settings::values.resolution_factor);
234 qt_config->setValue("use_frame_limit", Settings::values.use_frame_limit); 234 qt_config->setValue("use_frame_limit", Settings::values.use_frame_limit);
235 qt_config->setValue("frame_limit", Settings::values.frame_limit); 235 qt_config->setValue("frame_limit", Settings::values.frame_limit);
236 qt_config->setValue("use_accurate_framebuffers", Settings::values.use_accurate_framebuffers); 236 qt_config->setValue("use_accurate_gpu_emulation", Settings::values.use_accurate_gpu_emulation);
237 237
238 // Cast to double because Qt's written float values are not human-readable 238 // Cast to double because Qt's written float values are not human-readable
239 qt_config->setValue("bg_red", (double)Settings::values.bg_red); 239 qt_config->setValue("bg_red", (double)Settings::values.bg_red);
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index cd1549462..8290b4384 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -75,7 +75,7 @@ void ConfigureGraphics::setConfiguration() {
75 static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor))); 75 static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor)));
76 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); 76 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
77 ui->frame_limit->setValue(Settings::values.frame_limit); 77 ui->frame_limit->setValue(Settings::values.frame_limit);
78 ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers); 78 ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation);
79 bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green, 79 bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
80 Settings::values.bg_blue); 80 Settings::values.bg_blue);
81 ui->bg_button->setStyleSheet( 81 ui->bg_button->setStyleSheet(
@@ -87,7 +87,7 @@ void ConfigureGraphics::applyConfiguration() {
87 ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); 87 ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex()));
88 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); 88 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
89 Settings::values.frame_limit = ui->frame_limit->value(); 89 Settings::values.frame_limit = ui->frame_limit->value();
90 Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); 90 Settings::values.use_accurate_gpu_emulation = ui->use_accurate_gpu_emulation->isChecked();
91 Settings::values.bg_red = static_cast<float>(bg_color.redF()); 91 Settings::values.bg_red = static_cast<float>(bg_color.redF());
92 Settings::values.bg_green = static_cast<float>(bg_color.greenF()); 92 Settings::values.bg_green = static_cast<float>(bg_color.greenF());
93 Settings::values.bg_blue = static_cast<float>(bg_color.blueF()); 93 Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 8fc00af1b..91fcad994 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -50,9 +50,9 @@
50 </layout> 50 </layout>
51 </item> 51 </item>
52 <item> 52 <item>
53 <widget class="QCheckBox" name="use_accurate_framebuffers"> 53 <widget class="QCheckBox" name="use_accurate_gpu_emulation">
54 <property name="text"> 54 <property name="text">
55 <string>Use accurate framebuffers (slow)</string> 55 <string>Use accurate GPU emulation (slow)</string>
56 </property> 56 </property>
57 </widget> 57 </widget>
58 </item> 58 </item>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 2470f4640..5e42e48b2 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -99,8 +99,8 @@ void Config::ReadValues() {
99 Settings::values.use_frame_limit = sdl2_config->GetBoolean("Renderer", "use_frame_limit", true); 99 Settings::values.use_frame_limit = sdl2_config->GetBoolean("Renderer", "use_frame_limit", true);
100 Settings::values.frame_limit = 100 Settings::values.frame_limit =
101 static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)); 101 static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100));
102 Settings::values.use_accurate_framebuffers = 102 Settings::values.use_accurate_gpu_emulation =
103 sdl2_config->GetBoolean("Renderer", "use_accurate_framebuffers", false); 103 sdl2_config->GetBoolean("Renderer", "use_accurate_gpu_emulation", false);
104 104
105 Settings::values.bg_red = (float)sdl2_config->GetReal("Renderer", "bg_red", 0.0); 105 Settings::values.bg_red = (float)sdl2_config->GetReal("Renderer", "bg_red", 0.0);
106 Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0); 106 Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 762396e3b..a97b75f7b 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -110,9 +110,9 @@ use_frame_limit =
110# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) 110# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
111frame_limit = 111frame_limit =
112 112
113# Whether to use accurate framebuffers 113# Whether to use accurate GPU emulation
114# 0 (default): Off (fast), 1 : On (slow) 114# 0 (default): Off (fast), 1 : On (slow)
115use_accurate_framebuffers = 115use_accurate_gpu_emulation =
116 116
117# The clear color for the renderer. What shows up on the sides of the bottom screen. 117# The clear color for the renderer. What shows up on the sides of the bottom screen.
118# Must be in range of 0.0-1.0. Defaults to 1.0 for all. 118# Must be in range of 0.0-1.0. Defaults to 1.0 for all.