summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/time_stretch.cpp6
-rw-r--r--src/core/core.cpp28
-rw-r--r--src/core/core.h31
-rw-r--r--src/core/hle/kernel/kernel.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp2
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp243
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h87
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp5
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h27
-rw-r--r--src/video_core/renderer_opengl/utils.cpp38
-rw-r--r--src/video_core/renderer_opengl/utils.h15
-rw-r--r--src/video_core/textures/decoders.h6
-rw-r--r--src/video_core/utils.h26
16 files changed, 373 insertions, 158 deletions
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
index cee8b12dd..2fe0b3aef 100644
--- a/src/audio_core/time_stretch.cpp
+++ b/src/audio_core/time_stretch.cpp
@@ -32,10 +32,10 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
32 // We were given actual_samples number of samples, and num_samples were requested from us. 32 // We were given actual_samples number of samples, and num_samples were requested from us.
33 double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out); 33 double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out);
34 34
35 const double max_latency = 1.0; // seconds 35 const double max_latency = 0.25; // seconds
36 const double max_backlog = m_sample_rate * max_latency; 36 const double max_backlog = m_sample_rate * max_latency;
37 const double backlog_fullness = m_sound_touch.numSamples() / max_backlog; 37 const double backlog_fullness = m_sound_touch.numSamples() / max_backlog;
38 if (backlog_fullness > 5.0) { 38 if (backlog_fullness > 4.0) {
39 // Too many samples in backlog: Don't push anymore on 39 // Too many samples in backlog: Don't push anymore on
40 num_in = 0; 40 num_in = 0;
41 } 41 }
@@ -49,7 +49,7 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
49 49
50 // This low-pass filter smoothes out variance in the calculated stretch ratio. 50 // This low-pass filter smoothes out variance in the calculated stretch ratio.
51 // The time-scale determines how responsive this filter is. 51 // The time-scale determines how responsive this filter is.
52 constexpr double lpf_time_scale = 2.0; // seconds 52 constexpr double lpf_time_scale = 0.712; // seconds
53 const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale); 53 const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale);
54 m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio); 54 m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio);
55 55
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 7cb86ed92..6c32154db 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -312,6 +312,10 @@ Cpu& System::CurrentCpuCore() {
312 return impl->CurrentCpuCore(); 312 return impl->CurrentCpuCore();
313} 313}
314 314
315const Cpu& System::CurrentCpuCore() const {
316 return impl->CurrentCpuCore();
317}
318
315System::ResultStatus System::RunLoop(bool tight_loop) { 319System::ResultStatus System::RunLoop(bool tight_loop) {
316 return impl->RunLoop(tight_loop); 320 return impl->RunLoop(tight_loop);
317} 321}
@@ -342,7 +346,11 @@ PerfStatsResults System::GetAndResetPerfStats() {
342 return impl->GetAndResetPerfStats(); 346 return impl->GetAndResetPerfStats();
343} 347}
344 348
345Core::TelemetrySession& System::TelemetrySession() const { 349TelemetrySession& System::TelemetrySession() {
350 return *impl->telemetry_session;
351}
352
353const TelemetrySession& System::TelemetrySession() const {
346 return *impl->telemetry_session; 354 return *impl->telemetry_session;
347} 355}
348 356
@@ -350,7 +358,11 @@ ARM_Interface& System::CurrentArmInterface() {
350 return CurrentCpuCore().ArmInterface(); 358 return CurrentCpuCore().ArmInterface();
351} 359}
352 360
353std::size_t System::CurrentCoreIndex() { 361const ARM_Interface& System::CurrentArmInterface() const {
362 return CurrentCpuCore().ArmInterface();
363}
364
365std::size_t System::CurrentCoreIndex() const {
354 return CurrentCpuCore().CoreIndex(); 366 return CurrentCpuCore().CoreIndex();
355} 367}
356 368
@@ -358,6 +370,10 @@ Kernel::Scheduler& System::CurrentScheduler() {
358 return CurrentCpuCore().Scheduler(); 370 return CurrentCpuCore().Scheduler();
359} 371}
360 372
373const Kernel::Scheduler& System::CurrentScheduler() const {
374 return CurrentCpuCore().Scheduler();
375}
376
361Kernel::Scheduler& System::Scheduler(std::size_t core_index) { 377Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
362 return CpuCore(core_index).Scheduler(); 378 return CpuCore(core_index).Scheduler();
363} 379}
@@ -378,6 +394,10 @@ ARM_Interface& System::ArmInterface(std::size_t core_index) {
378 return CpuCore(core_index).ArmInterface(); 394 return CpuCore(core_index).ArmInterface();
379} 395}
380 396
397const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
398 return CpuCore(core_index).ArmInterface();
399}
400
381Cpu& System::CpuCore(std::size_t core_index) { 401Cpu& System::CpuCore(std::size_t core_index) {
382 ASSERT(core_index < NUM_CPU_CORES); 402 ASSERT(core_index < NUM_CPU_CORES);
383 return *impl->cpu_cores[core_index]; 403 return *impl->cpu_cores[core_index];
@@ -392,6 +412,10 @@ ExclusiveMonitor& System::Monitor() {
392 return *impl->cpu_exclusive_monitor; 412 return *impl->cpu_exclusive_monitor;
393} 413}
394 414
415const ExclusiveMonitor& System::Monitor() const {
416 return *impl->cpu_exclusive_monitor;
417}
418
395Tegra::GPU& System::GPU() { 419Tegra::GPU& System::GPU() {
396 return *impl->gpu_core; 420 return *impl->gpu_core;
397} 421}
diff --git a/src/core/core.h b/src/core/core.h
index 173be45f8..cfacceb81 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -129,11 +129,11 @@ public:
129 */ 129 */
130 bool IsPoweredOn() const; 130 bool IsPoweredOn() const;
131 131
132 /** 132 /// Gets a reference to the telemetry session for this emulation session.
133 * Returns a reference to the telemetry session for this emulation session. 133 Core::TelemetrySession& TelemetrySession();
134 * @returns Reference to the telemetry session. 134
135 */ 135 /// Gets a reference to the telemetry session for this emulation session.
136 Core::TelemetrySession& TelemetrySession() const; 136 const Core::TelemetrySession& TelemetrySession() const;
137 137
138 /// Prepare the core emulation for a reschedule 138 /// Prepare the core emulation for a reschedule
139 void PrepareReschedule(); 139 void PrepareReschedule();
@@ -144,24 +144,36 @@ public:
144 /// Gets an ARM interface to the CPU core that is currently running 144 /// Gets an ARM interface to the CPU core that is currently running
145 ARM_Interface& CurrentArmInterface(); 145 ARM_Interface& CurrentArmInterface();
146 146
147 /// Gets an ARM interface to the CPU core that is currently running
148 const ARM_Interface& CurrentArmInterface() const;
149
147 /// Gets the index of the currently running CPU core 150 /// Gets the index of the currently running CPU core
148 std::size_t CurrentCoreIndex(); 151 std::size_t CurrentCoreIndex() const;
149 152
150 /// Gets the scheduler for the CPU core that is currently running 153 /// Gets the scheduler for the CPU core that is currently running
151 Kernel::Scheduler& CurrentScheduler(); 154 Kernel::Scheduler& CurrentScheduler();
152 155
153 /// Gets an ARM interface to the CPU core with the specified index 156 /// Gets the scheduler for the CPU core that is currently running
157 const Kernel::Scheduler& CurrentScheduler() const;
158
159 /// Gets a reference to an ARM interface for the CPU core with the specified index
154 ARM_Interface& ArmInterface(std::size_t core_index); 160 ARM_Interface& ArmInterface(std::size_t core_index);
155 161
162 /// Gets a const reference to an ARM interface from the CPU core with the specified index
163 const ARM_Interface& ArmInterface(std::size_t core_index) const;
164
156 /// Gets a CPU interface to the CPU core with the specified index 165 /// Gets a CPU interface to the CPU core with the specified index
157 Cpu& CpuCore(std::size_t core_index); 166 Cpu& CpuCore(std::size_t core_index);
158 167
159 /// Gets a CPU interface to the CPU core with the specified index 168 /// Gets a CPU interface to the CPU core with the specified index
160 const Cpu& CpuCore(std::size_t core_index) const; 169 const Cpu& CpuCore(std::size_t core_index) const;
161 170
162 /// Gets the exclusive monitor 171 /// Gets a reference to the exclusive monitor
163 ExclusiveMonitor& Monitor(); 172 ExclusiveMonitor& Monitor();
164 173
174 /// Gets a constant reference to the exclusive monitor
175 const ExclusiveMonitor& Monitor() const;
176
165 /// Gets a mutable reference to the GPU interface 177 /// Gets a mutable reference to the GPU interface
166 Tegra::GPU& GPU(); 178 Tegra::GPU& GPU();
167 179
@@ -230,6 +242,9 @@ private:
230 /// Returns the currently running CPU core 242 /// Returns the currently running CPU core
231 Cpu& CurrentCpuCore(); 243 Cpu& CurrentCpuCore();
232 244
245 /// Returns the currently running CPU core
246 const Cpu& CurrentCpuCore() const;
247
233 /** 248 /**
234 * Initialize the emulated system. 249 * Initialize the emulated system.
235 * @param emu_window Reference to the host-system window used for video output and keyboard 250 * @param emu_window Reference to the host-system window used for video output and keyboard
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4b6b32dd5..1fd4ba5d2 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -32,7 +32,7 @@ namespace Kernel {
32 */ 32 */
33static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) { 33static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) {
34 const auto proper_handle = static_cast<Handle>(thread_handle); 34 const auto proper_handle = static_cast<Handle>(thread_handle);
35 auto& system = Core::System::GetInstance(); 35 const auto& system = Core::System::GetInstance();
36 36
37 // Lock the global kernel mutex when we enter the kernel HLE. 37 // Lock the global kernel mutex when we enter the kernel HLE.
38 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); 38 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
@@ -90,7 +90,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
90/// The timer callback event, called when a timer is fired 90/// The timer callback event, called when a timer is fired
91static void TimerCallback(u64 timer_handle, int cycles_late) { 91static void TimerCallback(u64 timer_handle, int cycles_late) {
92 const auto proper_handle = static_cast<Handle>(timer_handle); 92 const auto proper_handle = static_cast<Handle>(timer_handle);
93 auto& system = Core::System::GetInstance(); 93 const auto& system = Core::System::GetInstance();
94 SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle); 94 SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle);
95 95
96 if (timer == nullptr) { 96 if (timer == nullptr) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4e490e2b5..c7c579aaf 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -572,7 +572,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
572 return ERR_INVALID_HANDLE; 572 return ERR_INVALID_HANDLE;
573 } 573 }
574 574
575 auto& system = Core::System::GetInstance(); 575 const auto& system = Core::System::GetInstance();
576 const auto& scheduler = system.CurrentScheduler(); 576 const auto& scheduler = system.CurrentScheduler();
577 const auto* const current_thread = scheduler.GetCurrentThread(); 577 const auto* const current_thread = scheduler.GetCurrentThread();
578 const bool same_thread = current_thread == thread; 578 const bool same_thread = current_thread == thread;
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 09ecc5bad..c5f7128ec 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -51,6 +51,8 @@ add_library(video_core STATIC
51 renderer_opengl/maxwell_to_gl.h 51 renderer_opengl/maxwell_to_gl.h
52 renderer_opengl/renderer_opengl.cpp 52 renderer_opengl/renderer_opengl.cpp
53 renderer_opengl/renderer_opengl.h 53 renderer_opengl/renderer_opengl.h
54 renderer_opengl/utils.cpp
55 renderer_opengl/utils.h
54 textures/astc.cpp 56 textures/astc.cpp
55 textures/astc.h 57 textures/astc.h
56 textures/decoders.cpp 58 textures/decoders.cpp
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index cb180b93c..7bb5544fc 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -731,11 +731,15 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
731 731
732 if (mag_filter != config.mag_filter) { 732 if (mag_filter != config.mag_filter) {
733 mag_filter = config.mag_filter; 733 mag_filter = config.mag_filter;
734 glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter)); 734 glSamplerParameteri(
735 s, GL_TEXTURE_MAG_FILTER,
736 MaxwellToGL::TextureFilterMode(mag_filter, Tegra::Texture::TextureMipmapFilter::None));
735 } 737 }
736 if (min_filter != config.min_filter) { 738 if (min_filter != config.min_filter || mip_filter != config.mip_filter) {
737 min_filter = config.min_filter; 739 min_filter = config.min_filter;
738 glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter)); 740 mip_filter = config.mip_filter;
741 glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER,
742 MaxwellToGL::TextureFilterMode(min_filter, mip_filter));
739 } 743 }
740 744
741 if (wrap_u != config.wrap_u) { 745 if (wrap_u != config.wrap_u) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 5020a5392..7b0615125 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -93,6 +93,7 @@ private:
93 private: 93 private:
94 Tegra::Texture::TextureFilter mag_filter; 94 Tegra::Texture::TextureFilter mag_filter;
95 Tegra::Texture::TextureFilter min_filter; 95 Tegra::Texture::TextureFilter min_filter;
96 Tegra::Texture::TextureMipmapFilter mip_filter;
96 Tegra::Texture::WrapMode wrap_u; 97 Tegra::Texture::WrapMode wrap_u;
97 Tegra::Texture::WrapMode wrap_v; 98 Tegra::Texture::WrapMode wrap_v;
98 Tegra::Texture::WrapMode wrap_p; 99 Tegra::Texture::WrapMode wrap_p;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b057e2efa..1d43a419d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -16,6 +16,7 @@
16#include "core/settings.h" 16#include "core/settings.h"
17#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
18#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 18#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
19#include "video_core/renderer_opengl/utils.h"
19#include "video_core/textures/astc.h" 20#include "video_core/textures/astc.h"
20#include "video_core/textures/decoders.h" 21#include "video_core/textures/decoders.h"
21#include "video_core/utils.h" 22#include "video_core/utils.h"
@@ -90,27 +91,36 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
90 } 91 }
91} 92}
92 93
93std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { 94std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only,
95 bool uncompressed) const {
94 const u32 compression_factor{GetCompressionFactor(pixel_format)}; 96 const u32 compression_factor{GetCompressionFactor(pixel_format)};
95 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; 97 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
96 u32 m_depth = (layer_only ? 1U : depth); 98 u32 m_depth = (layer_only ? 1U : depth);
97 u32 m_width = std::max(1U, width / compression_factor); 99 u32 m_width = MipWidth(mip_level);
98 u32 m_height = std::max(1U, height / compression_factor); 100 u32 m_height = MipHeight(mip_level);
99 std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, 101 m_width = uncompressed ? m_width
100 m_depth, block_height, block_depth); 102 : std::max(1U, (m_width + compression_factor - 1) / compression_factor);
101 u32 m_block_height = block_height; 103 m_height = uncompressed
102 u32 m_block_depth = block_depth; 104 ? m_height
103 std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size 105 : std::max(1U, (m_height + compression_factor - 1) / compression_factor);
104 for (u32 i = 1; i < max_mip_level; i++) { 106 m_depth = std::max(1U, m_depth >> mip_level);
105 m_width = std::max(1U, m_width / 2); 107 u32 m_block_height = MipBlockHeight(mip_level);
106 m_height = std::max(1U, m_height / 2); 108 u32 m_block_depth = MipBlockDepth(mip_level);
107 m_depth = std::max(1U, m_depth / 2); 109 return Tegra::Texture::CalculateSize(force_gl ? false : is_tiled, bytes_per_pixel, m_width,
108 m_block_height = std::max(1U, m_block_height / 2); 110 m_height, m_depth, m_block_height, m_block_depth);
109 m_block_depth = std::max(1U, m_block_depth / 2); 111}
110 size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth, 112
111 m_block_height, m_block_depth); 113std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
114 bool uncompressed) const {
115 std::size_t block_size_bytes = Tegra::Texture::GetGOBSize() * block_height * block_depth;
116 std::size_t size = 0;
117 for (u32 i = 0; i < max_mip_level; i++) {
118 size += InnerMipmapMemorySize(i, force_gl, layer_only, uncompressed);
119 }
120 if (!force_gl && is_tiled) {
121 size = Common::AlignUp(size, block_size_bytes);
112 } 122 }
113 return is_tiled ? Common::AlignUp(size, block_size_bytes) : size; 123 return size;
114} 124}
115 125
116/*static*/ SurfaceParams SurfaceParams::CreateForTexture( 126/*static*/ SurfaceParams SurfaceParams::CreateForTexture(
@@ -188,7 +198,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
188 params.unaligned_height = config.height; 198 params.unaligned_height = config.height;
189 params.target = SurfaceTarget::Texture2D; 199 params.target = SurfaceTarget::Texture2D;
190 params.depth = 1; 200 params.depth = 1;
191 params.max_mip_level = 0; 201 params.max_mip_level = 1;
192 params.is_layered = false; 202 params.is_layered = false;
193 203
194 // Render target specific parameters, not used for caching 204 // Render target specific parameters, not used for caching
@@ -222,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
222 params.unaligned_height = zeta_height; 232 params.unaligned_height = zeta_height;
223 params.target = SurfaceTarget::Texture2D; 233 params.target = SurfaceTarget::Texture2D;
224 params.depth = 1; 234 params.depth = 1;
225 params.max_mip_level = 0; 235 params.max_mip_level = 1;
226 params.is_layered = false; 236 params.is_layered = false;
227 params.rt = {}; 237 params.rt = {};
228 238
@@ -249,7 +259,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
249 params.unaligned_height = config.height; 259 params.unaligned_height = config.height;
250 params.target = SurfaceTarget::Texture2D; 260 params.target = SurfaceTarget::Texture2D;
251 params.depth = 1; 261 params.depth = 1;
252 params.max_mip_level = 0; 262 params.max_mip_level = 1;
253 params.rt = {}; 263 params.rt = {};
254 264
255 params.InitCacheParameters(config.Address()); 265 params.InitCacheParameters(config.Address());
@@ -273,7 +283,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
273 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, 283 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
274 false}, // R11FG11FB10F 284 false}, // R11FG11FB10F
275 {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI 285 {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI
276 {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 286 {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
277 true}, // DXT1 287 true}, // DXT1
278 {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 288 {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
279 true}, // DXT23 289 true}, // DXT23
@@ -318,7 +328,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
318 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 328 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4
319 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 329 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8
320 // Compressed sRGB formats 330 // Compressed sRGB formats
321 {GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 331 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
322 true}, // DXT1_SRGB 332 true}, // DXT1_SRGB
323 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 333 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
324 true}, // DXT23_SRGB 334 true}, // DXT23_SRGB
@@ -373,13 +383,13 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType
373 return format; 383 return format;
374} 384}
375 385
376MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { 386MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
377 u32 actual_height{unaligned_height}; 387 u32 actual_height{std::max(1U, unaligned_height >> mip_level)};
378 if (IsPixelFormatASTC(pixel_format)) { 388 if (IsPixelFormatASTC(pixel_format)) {
379 // ASTC formats must stop at the ATSC block size boundary 389 // ASTC formats must stop at the ATSC block size boundary
380 actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second); 390 actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second);
381 } 391 }
382 return {0, actual_height, width, 0}; 392 return {0, actual_height, MipWidth(mip_level), 0};
383} 393}
384 394
385/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN 395/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
@@ -563,28 +573,31 @@ static constexpr GLConversionArray gl_to_morton_fns = {
563}; 573};
564 574
565void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, 575void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
566 std::vector<u8>& gl_buffer) { 576 std::vector<u8>& gl_buffer, u32 mip_level) {
567 u32 depth = params.depth; 577 u32 depth = params.MipDepth(mip_level);
568 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { 578 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
569 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented. 579 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
570 depth = 1U; 580 depth = 1U;
571 } 581 }
572 if (params.is_layered) { 582 if (params.is_layered) {
573 u64 offset = 0; 583 u64 offset = params.GetMipmapLevelOffset(mip_level);
574 u64 offset_gl = 0; 584 u64 offset_gl = 0;
575 u64 layer_size = params.LayerMemorySize(); 585 u64 layer_size = params.LayerMemorySize();
576 u64 gl_size = params.LayerSizeGL(); 586 u64 gl_size = params.LayerSizeGL(mip_level);
577 for (u32 i = 0; i < depth; i++) { 587 for (u32 i = 0; i < params.depth; i++) {
578 functions[static_cast<std::size_t>(params.pixel_format)]( 588 functions[static_cast<std::size_t>(params.pixel_format)](
579 params.width, params.block_height, params.height, params.block_depth, 1, 589 params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
590 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1,
580 gl_buffer.data() + offset_gl, gl_size, params.addr + offset); 591 gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
581 offset += layer_size; 592 offset += layer_size;
582 offset_gl += gl_size; 593 offset_gl += gl_size;
583 } 594 }
584 } else { 595 } else {
596 u64 offset = params.GetMipmapLevelOffset(mip_level);
585 functions[static_cast<std::size_t>(params.pixel_format)]( 597 functions[static_cast<std::size_t>(params.pixel_format)](
586 params.width, params.block_height, params.height, params.block_depth, depth, 598 params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
587 gl_buffer.data(), gl_buffer.size(), params.addr); 599 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(),
600 gl_buffer.size(), params.addr + offset);
588 } 601 }
589} 602}
590 603
@@ -839,34 +852,41 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
839 // Only pre-create the texture for non-compressed textures. 852 // Only pre-create the texture for non-compressed textures.
840 switch (params.target) { 853 switch (params.target) {
841 case SurfaceParams::SurfaceTarget::Texture1D: 854 case SurfaceParams::SurfaceTarget::Texture1D:
842 glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 855 glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
843 rect.GetWidth()); 856 format_tuple.internal_format, rect.GetWidth());
844 break; 857 break;
845 case SurfaceParams::SurfaceTarget::Texture2D: 858 case SurfaceParams::SurfaceTarget::Texture2D:
846 case SurfaceParams::SurfaceTarget::TextureCubemap: 859 case SurfaceParams::SurfaceTarget::TextureCubemap:
847 glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 860 glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
848 rect.GetWidth(), rect.GetHeight()); 861 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
849 break; 862 break;
850 case SurfaceParams::SurfaceTarget::Texture3D: 863 case SurfaceParams::SurfaceTarget::Texture3D:
851 case SurfaceParams::SurfaceTarget::Texture2DArray: 864 case SurfaceParams::SurfaceTarget::Texture2DArray:
852 glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 865 glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
853 rect.GetWidth(), rect.GetHeight(), params.depth); 866 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
867 params.depth);
854 break; 868 break;
855 default: 869 default:
856 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 870 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
857 static_cast<u32>(params.target)); 871 static_cast<u32>(params.target));
858 UNREACHABLE(); 872 UNREACHABLE();
859 glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(), 873 glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format,
860 rect.GetHeight()); 874 rect.GetWidth(), rect.GetHeight());
861 } 875 }
862 } 876 }
863 877
864 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); 878 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
879 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
865 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 880 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
866 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 881 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
882 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL,
883 params.max_mip_level - 1);
884 if (params.max_mip_level == 1) {
885 glTexParameterf(SurfaceTargetToGL(params.target), GL_TEXTURE_LOD_BIAS, 1000.0);
886 }
867 887
868 VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, 888 LabelGLObject(GL_TEXTURE, texture.handle, params.addr,
869 SurfaceParams::SurfaceTargetName(params.target)); 889 SurfaceParams::SurfaceTargetName(params.target));
870 890
871 // Clamp size to mapped GPU memory region 891 // Clamp size to mapped GPU memory region
872 // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000 892 // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000
@@ -992,20 +1012,22 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
992MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 1012MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
993void CachedSurface::LoadGLBuffer() { 1013void CachedSurface::LoadGLBuffer() {
994 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 1014 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
995 1015 gl_buffer.resize(params.max_mip_level);
996 gl_buffer.resize(params.size_in_bytes_gl); 1016 for (u32 i = 0; i < params.max_mip_level; i++)
1017 gl_buffer[i].resize(params.GetMipmapSizeGL(i));
997 if (params.is_tiled) { 1018 if (params.is_tiled) {
998 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 1019 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
999 params.block_width, static_cast<u32>(params.target)); 1020 params.block_width, static_cast<u32>(params.target));
1000 1021 for (u32 i = 0; i < params.max_mip_level; i++)
1001 SwizzleFunc(morton_to_gl_fns, params, gl_buffer); 1022 SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i);
1002 } else { 1023 } else {
1003 const auto texture_src_data{Memory::GetPointer(params.addr)}; 1024 const auto texture_src_data{Memory::GetPointer(params.addr)};
1004 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; 1025 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
1005 gl_buffer.assign(texture_src_data, texture_src_data_end); 1026 gl_buffer[0].assign(texture_src_data, texture_src_data_end);
1006 } 1027 }
1007 1028 for (u32 i = 0; i < params.max_mip_level; i++)
1008 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); 1029 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
1030 params.MipHeight(i));
1009} 1031}
1010 1032
1011MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 1033MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1015,7 +1037,8 @@ void CachedSurface::FlushGLBuffer() {
1015 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented"); 1037 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented");
1016 1038
1017 // OpenGL temporary buffer needs to be big enough to store raw texture size 1039 // OpenGL temporary buffer needs to be big enough to store raw texture size
1018 gl_buffer.resize(GetSizeInBytes()); 1040 gl_buffer.resize(1);
1041 gl_buffer[0].resize(GetSizeInBytes());
1019 1042
1020 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 1043 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
1021 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 1044 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
@@ -1024,9 +1047,9 @@ void CachedSurface::FlushGLBuffer() {
1024 ASSERT(!tuple.compressed); 1047 ASSERT(!tuple.compressed);
1025 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 1048 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
1026 glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, 1049 glGetTextureImage(texture.handle, 0, tuple.format, tuple.type,
1027 static_cast<GLsizei>(gl_buffer.size()), gl_buffer.data()); 1050 static_cast<GLsizei>(gl_buffer[0].size()), gl_buffer[0].data());
1028 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 1051 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1029 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, 1052 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer[0], params.pixel_format, params.width,
1030 params.height); 1053 params.height);
1031 ASSERT(params.type != SurfaceType::Fill); 1054 ASSERT(params.type != SurfaceType::Fill);
1032 const u8* const texture_src_data = Memory::GetPointer(params.addr); 1055 const u8* const texture_src_data = Memory::GetPointer(params.addr);
@@ -1035,26 +1058,21 @@ void CachedSurface::FlushGLBuffer() {
1035 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 1058 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
1036 params.block_width, static_cast<u32>(params.target)); 1059 params.block_width, static_cast<u32>(params.target));
1037 1060
1038 SwizzleFunc(gl_to_morton_fns, params, gl_buffer); 1061 SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0);
1039 } else { 1062 } else {
1040 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes()); 1063 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes());
1041 } 1064 }
1042} 1065}
1043 1066
1044MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 1067void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1045void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { 1068 GLuint draw_fb_handle) {
1046 if (params.type == SurfaceType::Fill) 1069 const auto& rect{params.GetRect(mip_map)};
1047 return;
1048
1049 MICROPROFILE_SCOPE(OpenGL_TextureUL);
1050
1051 const auto& rect{params.GetRect()};
1052 1070
1053 // Load data from memory to the surface 1071 // Load data from memory to the surface
1054 const GLint x0 = static_cast<GLint>(rect.left); 1072 const GLint x0 = static_cast<GLint>(rect.left);
1055 const GLint y0 = static_cast<GLint>(rect.bottom); 1073 const GLint y0 = static_cast<GLint>(rect.bottom);
1056 std::size_t buffer_offset = 1074 std::size_t buffer_offset =
1057 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + 1075 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
1058 static_cast<std::size_t>(x0)) * 1076 static_cast<std::size_t>(x0)) *
1059 SurfaceParams::GetBytesPerPixel(params.pixel_format); 1077 SurfaceParams::GetBytesPerPixel(params.pixel_format);
1060 1078
@@ -1072,88 +1090,117 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
1072 cur_state.Apply(); 1090 cur_state.Apply();
1073 1091
1074 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 1092 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
1075 ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); 1093 ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 ==
1076 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); 1094 0);
1095 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
1077 1096
1097 GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
1078 glActiveTexture(GL_TEXTURE0); 1098 glActiveTexture(GL_TEXTURE0);
1079 if (tuple.compressed) { 1099 if (tuple.compressed) {
1080 switch (params.target) { 1100 switch (params.target) {
1081 case SurfaceParams::SurfaceTarget::Texture2D: 1101 case SurfaceParams::SurfaceTarget::Texture2D:
1082 glCompressedTexImage2D( 1102 glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1083 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 1103 static_cast<GLsizei>(params.MipWidth(mip_map)),
1084 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, 1104 static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
1085 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1105 &gl_buffer[mip_map][buffer_offset]);
1086 break; 1106 break;
1087 case SurfaceParams::SurfaceTarget::Texture3D: 1107 case SurfaceParams::SurfaceTarget::Texture3D:
1108 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1109 static_cast<GLsizei>(params.MipWidth(mip_map)),
1110 static_cast<GLsizei>(params.MipHeight(mip_map)),
1111 static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
1112 &gl_buffer[mip_map][buffer_offset]);
1113 break;
1088 case SurfaceParams::SurfaceTarget::Texture2DArray: 1114 case SurfaceParams::SurfaceTarget::Texture2DArray:
1089 glCompressedTexImage3D( 1115 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1090 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 1116 static_cast<GLsizei>(params.MipWidth(mip_map)),
1091 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 1117 static_cast<GLsizei>(params.MipHeight(mip_map)),
1092 static_cast<GLsizei>(params.depth), 0, 1118 static_cast<GLsizei>(params.depth), 0, image_size,
1093 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1119 &gl_buffer[mip_map][buffer_offset]);
1094 break; 1120 break;
1095 case SurfaceParams::SurfaceTarget::TextureCubemap: 1121 case SurfaceParams::SurfaceTarget::TextureCubemap: {
1122 GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
1096 for (std::size_t face = 0; face < params.depth; ++face) { 1123 for (std::size_t face = 0; face < params.depth; ++face) {
1097 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 1124 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
1098 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1125 mip_map, tuple.internal_format,
1099 static_cast<GLsizei>(params.height), 0, 1126 static_cast<GLsizei>(params.MipWidth(mip_map)),
1100 static_cast<GLsizei>(params.SizeInBytesCubeFaceGL()), 1127 static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
1101 &gl_buffer[buffer_offset]); 1128 layer_size, &gl_buffer[mip_map][buffer_offset]);
1102 buffer_offset += params.SizeInBytesCubeFace(); 1129 buffer_offset += layer_size;
1103 } 1130 }
1104 break; 1131 break;
1132 }
1105 default: 1133 default:
1106 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1134 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1107 static_cast<u32>(params.target)); 1135 static_cast<u32>(params.target));
1108 UNREACHABLE(); 1136 UNREACHABLE();
1109 glCompressedTexImage2D( 1137 glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format,
1110 GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1138 static_cast<GLsizei>(params.MipWidth(mip_map)),
1111 static_cast<GLsizei>(params.height), 0, 1139 static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
1112 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1140 static_cast<GLsizei>(params.size_in_bytes_gl),
1141 &gl_buffer[mip_map][buffer_offset]);
1113 } 1142 }
1114 } else { 1143 } else {
1115 1144
1116 switch (params.target) { 1145 switch (params.target) {
1117 case SurfaceParams::SurfaceTarget::Texture1D: 1146 case SurfaceParams::SurfaceTarget::Texture1D:
1118 glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, 1147 glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
1119 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, 1148 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
1120 &gl_buffer[buffer_offset]); 1149 &gl_buffer[mip_map][buffer_offset]);
1121 break; 1150 break;
1122 case SurfaceParams::SurfaceTarget::Texture2D: 1151 case SurfaceParams::SurfaceTarget::Texture2D:
1123 glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, 1152 glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
1124 static_cast<GLsizei>(rect.GetWidth()), 1153 static_cast<GLsizei>(rect.GetWidth()),
1125 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1154 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1126 &gl_buffer[buffer_offset]); 1155 &gl_buffer[mip_map][buffer_offset]);
1127 break; 1156 break;
1128 case SurfaceParams::SurfaceTarget::Texture3D: 1157 case SurfaceParams::SurfaceTarget::Texture3D:
1158 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1159 static_cast<GLsizei>(rect.GetWidth()),
1160 static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
1161 tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
1162 break;
1129 case SurfaceParams::SurfaceTarget::Texture2DArray: 1163 case SurfaceParams::SurfaceTarget::Texture2DArray:
1130 glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, 1164 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1131 static_cast<GLsizei>(rect.GetWidth()), 1165 static_cast<GLsizei>(rect.GetWidth()),
1132 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, 1166 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
1133 tuple.type, &gl_buffer[buffer_offset]); 1167 tuple.type, &gl_buffer[mip_map][buffer_offset]);
1134 break; 1168 break;
1135 case SurfaceParams::SurfaceTarget::TextureCubemap: 1169 case SurfaceParams::SurfaceTarget::TextureCubemap: {
1170 std::size_t start = buffer_offset;
1136 for (std::size_t face = 0; face < params.depth; ++face) { 1171 for (std::size_t face = 0; face < params.depth; ++face) {
1137 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, x0, 1172 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
1138 y0, static_cast<GLsizei>(rect.GetWidth()), 1173 x0, y0, static_cast<GLsizei>(rect.GetWidth()),
1139 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1174 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1140 &gl_buffer[buffer_offset]); 1175 &gl_buffer[mip_map][buffer_offset]);
1141 buffer_offset += params.SizeInBytesCubeFace(); 1176 buffer_offset += params.LayerSizeGL(mip_map);
1142 } 1177 }
1143 break; 1178 break;
1179 }
1144 default: 1180 default:
1145 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1181 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1146 static_cast<u32>(params.target)); 1182 static_cast<u32>(params.target));
1147 UNREACHABLE(); 1183 UNREACHABLE();
1148 glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), 1184 glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
1149 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1185 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1150 &gl_buffer[buffer_offset]); 1186 &gl_buffer[mip_map][buffer_offset]);
1151 } 1187 }
1152 } 1188 }
1153 1189
1154 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 1190 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1155} 1191}
1156 1192
1193MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
1194void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
1195 if (params.type == SurfaceType::Fill)
1196 return;
1197
1198 MICROPROFILE_SCOPE(OpenGL_TextureUL);
1199
1200 for (u32 i = 0; i < params.max_mip_level; i++)
1201 UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
1202}
1203
1157RasterizerCacheOpenGL::RasterizerCacheOpenGL() { 1204RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
1158 read_framebuffer.Create(); 1205 read_framebuffer.Create();
1159 draw_framebuffer.Create(); 1206 draw_framebuffer.Create();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index be8c00e99..e72f4f2d2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -404,7 +404,7 @@ struct SurfaceParams {
404 128, // BC7U 404 128, // BC7U
405 32, // ASTC_2D_4X4_SRGB 405 32, // ASTC_2D_4X4_SRGB
406 16, // ASTC_2D_8X8_SRGB 406 16, // ASTC_2D_8X8_SRGB
407 32, // ASTC_2D_8X5_SRGB 407 16, // ASTC_2D_8X5_SRGB
408 32, // ASTC_2D_5X4_SRGB 408 32, // ASTC_2D_5X4_SRGB
409 32, // Z32F 409 32, // Z32F
410 16, // Z16 410 16, // Z16
@@ -834,7 +834,7 @@ struct SurfaceParams {
834 } 834 }
835 835
836 /// Returns the rectangle corresponding to this surface 836 /// Returns the rectangle corresponding to this surface
837 MathUtil::Rectangle<u32> GetRect() const; 837 MathUtil::Rectangle<u32> GetRect(u32 mip_level = 0) const;
838 838
839 /// Returns the total size of this surface in bytes, adjusted for compression 839 /// Returns the total size of this surface in bytes, adjusted for compression
840 std::size_t SizeInBytesRaw(bool ignore_tiled = false) const { 840 std::size_t SizeInBytesRaw(bool ignore_tiled = false) const {
@@ -865,7 +865,7 @@ struct SurfaceParams {
865 865
866 /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps. 866 /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps.
867 std::size_t MemorySize() const { 867 std::size_t MemorySize() const {
868 std::size_t size = InnerMemorySize(is_layered); 868 std::size_t size = InnerMemorySize(false, is_layered);
869 if (is_layered) 869 if (is_layered)
870 return size * depth; 870 return size * depth;
871 return size; 871 return size;
@@ -874,12 +874,78 @@ struct SurfaceParams {
874 /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including 874 /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including
875 /// mipmaps. 875 /// mipmaps.
876 std::size_t LayerMemorySize() const { 876 std::size_t LayerMemorySize() const {
877 return InnerMemorySize(true); 877 return InnerMemorySize(false, true);
878 } 878 }
879 879
880 /// Returns the size of a layer of this surface in OpenGL. 880 /// Returns the size of a layer of this surface in OpenGL.
881 std::size_t LayerSizeGL() const { 881 std::size_t LayerSizeGL(u32 mip_level) const {
882 return SizeInBytesRaw(true) / depth; 882 return InnerMipmapMemorySize(mip_level, true, is_layered, false);
883 }
884
885 std::size_t GetMipmapSizeGL(u32 mip_level, bool ignore_compressed = true) const {
886 std::size_t size = InnerMipmapMemorySize(mip_level, true, is_layered, ignore_compressed);
887 if (is_layered)
888 return size * depth;
889 return size;
890 }
891
892 std::size_t GetMipmapLevelOffset(u32 mip_level) const {
893 std::size_t offset = 0;
894 for (u32 i = 0; i < mip_level; i++)
895 offset += InnerMipmapMemorySize(i, false, is_layered);
896 return offset;
897 }
898
899 std::size_t GetMipmapLevelOffsetGL(u32 mip_level) const {
900 std::size_t offset = 0;
901 for (u32 i = 0; i < mip_level; i++)
902 offset += InnerMipmapMemorySize(i, true, is_layered);
903 return offset;
904 }
905
906 u32 MipWidth(u32 mip_level) const {
907 return std::max(1U, width >> mip_level);
908 }
909
910 u32 MipHeight(u32 mip_level) const {
911 return std::max(1U, height >> mip_level);
912 }
913
914 u32 MipDepth(u32 mip_level) const {
915 return std::max(1U, depth >> mip_level);
916 }
917
918 // Auto block resizing algorithm from:
919 // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c
920 u32 MipBlockHeight(u32 mip_level) const {
921 if (mip_level == 0)
922 return block_height;
923 u32 alt_height = MipHeight(mip_level);
924 u32 h = GetDefaultBlockHeight(pixel_format);
925 u32 blocks_in_y = (alt_height + h - 1) / h;
926 u32 bh = 16;
927 while (bh > 1 && blocks_in_y <= bh * 4) {
928 bh >>= 1;
929 }
930 return bh;
931 }
932
933 u32 MipBlockDepth(u32 mip_level) const {
934 if (mip_level == 0)
935 return block_depth;
936 if (is_layered)
937 return 1;
938 u32 depth = MipDepth(mip_level);
939 u32 bd = 32;
940 while (bd > 1 && depth * 2 <= bd) {
941 bd >>= 1;
942 }
943 if (bd == 32) {
944 u32 bh = MipBlockHeight(mip_level);
945 if (bh >= 4)
946 return 16;
947 }
948 return bd;
883 } 949 }
884 950
885 /// Creates SurfaceParams from a texture configuration 951 /// Creates SurfaceParams from a texture configuration
@@ -940,7 +1006,10 @@ struct SurfaceParams {
940 } rt; 1006 } rt;
941 1007
942private: 1008private:
943 std::size_t InnerMemorySize(bool layer_only = false) const; 1009 std::size_t InnerMipmapMemorySize(u32 mip_level, bool force_gl = false, bool layer_only = false,
1010 bool uncompressed = false) const;
1011 std::size_t InnerMemorySize(bool force_gl = false, bool layer_only = false,
1012 bool uncompressed = false) const;
944}; 1013};
945 1014
946}; // namespace OpenGL 1015}; // namespace OpenGL
@@ -1002,8 +1071,10 @@ public:
1002 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); 1071 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
1003 1072
1004private: 1073private:
1074 void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
1075
1005 OGLTexture texture; 1076 OGLTexture texture;
1006 std::vector<u8> gl_buffer; 1077 std::vector<std::vector<u8>> gl_buffer;
1007 SurfaceParams params; 1078 SurfaceParams params;
1008 GLenum gl_target; 1079 GLenum gl_target;
1009 std::size_t cached_size_in_bytes; 1080 std::size_t cached_size_in_bytes;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 1a03a677f..9522fd344 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -8,6 +8,7 @@
8#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/renderer_opengl/gl_shader_cache.h" 9#include "video_core/renderer_opengl/gl_shader_cache.h"
10#include "video_core/renderer_opengl/gl_shader_manager.h" 10#include "video_core/renderer_opengl/gl_shader_manager.h"
11#include "video_core/renderer_opengl/utils.h"
11#include "video_core/utils.h" 12#include "video_core/utils.h"
12 13
13namespace OpenGL { 14namespace OpenGL {
@@ -89,7 +90,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
89 shader.Create(program_result.first.c_str(), gl_type); 90 shader.Create(program_result.first.c_str(), gl_type);
90 program.Create(true, shader.handle); 91 program.Create(true, shader.handle);
91 SetShaderUniformBlockBindings(program.handle); 92 SetShaderUniformBlockBindings(program.handle);
92 VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr); 93 LabelGLObject(GL_PROGRAM, program.handle, addr);
93 } else { 94 } else {
94 // Store shader's code to lazily build it on draw 95 // Store shader's code to lazily build it on draw
95 geometry_programs.code = program_result.first; 96 geometry_programs.code = program_result.first;
@@ -130,7 +131,7 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
130 shader.Create(source.c_str(), GL_GEOMETRY_SHADER); 131 shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
131 target_program.Create(true, shader.handle); 132 target_program.Create(true, shader.handle);
132 SetShaderUniformBlockBindings(target_program.handle); 133 SetShaderUniformBlockBindings(target_program.handle);
133 VideoCore::LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name); 134 LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name);
134 return target_program.handle; 135 return target_program.handle;
135}; 136};
136 137
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 0f6dcab2b..87d511c38 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -135,12 +135,29 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
135 return {}; 135 return {};
136} 136}
137 137
138inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { 138inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode,
139 Tegra::Texture::TextureMipmapFilter mip_filter_mode) {
139 switch (filter_mode) { 140 switch (filter_mode) {
140 case Tegra::Texture::TextureFilter::Linear: 141 case Tegra::Texture::TextureFilter::Linear: {
141 return GL_LINEAR; 142 switch (mip_filter_mode) {
142 case Tegra::Texture::TextureFilter::Nearest: 143 case Tegra::Texture::TextureMipmapFilter::None:
143 return GL_NEAREST; 144 return GL_LINEAR;
145 case Tegra::Texture::TextureMipmapFilter::Nearest:
146 return GL_NEAREST_MIPMAP_LINEAR;
147 case Tegra::Texture::TextureMipmapFilter::Linear:
148 return GL_LINEAR_MIPMAP_LINEAR;
149 }
150 }
151 case Tegra::Texture::TextureFilter::Nearest: {
152 switch (mip_filter_mode) {
153 case Tegra::Texture::TextureMipmapFilter::None:
154 return GL_NEAREST;
155 case Tegra::Texture::TextureMipmapFilter::Nearest:
156 return GL_NEAREST_MIPMAP_NEAREST;
157 case Tegra::Texture::TextureMipmapFilter::Linear:
158 return GL_LINEAR_MIPMAP_NEAREST;
159 }
160 }
144 } 161 }
145 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", 162 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}",
146 static_cast<u32>(filter_mode)); 163 static_cast<u32>(filter_mode));
diff --git a/src/video_core/renderer_opengl/utils.cpp b/src/video_core/renderer_opengl/utils.cpp
new file mode 100644
index 000000000..d84634cb3
--- /dev/null
+++ b/src/video_core/renderer_opengl/utils.cpp
@@ -0,0 +1,38 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6#include <fmt/format.h>
7#include <glad/glad.h>
8#include "common/common_types.h"
9#include "video_core/renderer_opengl/utils.h"
10
11namespace OpenGL {
12
13void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info) {
14 if (!GLAD_GL_KHR_debug) {
15 return; // We don't need to throw an error as this is just for debugging
16 }
17 const std::string nice_addr = fmt::format("0x{:016x}", addr);
18 std::string object_label;
19
20 if (extra_info.empty()) {
21 switch (identifier) {
22 case GL_TEXTURE:
23 object_label = "Texture@" + nice_addr;
24 break;
25 case GL_PROGRAM:
26 object_label = "Shader@" + nice_addr;
27 break;
28 default:
29 object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
30 break;
31 }
32 } else {
33 object_label = extra_info + '@' + nice_addr;
34 }
35 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
36}
37
38} // namespace OpenGL \ No newline at end of file
diff --git a/src/video_core/renderer_opengl/utils.h b/src/video_core/renderer_opengl/utils.h
new file mode 100644
index 000000000..1fcb6fc11
--- /dev/null
+++ b/src/video_core/renderer_opengl/utils.h
@@ -0,0 +1,15 @@
1// Copyright 2014 Citra 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 <string>
8#include <glad/glad.h>
9#include "common/common_types.h"
10
11namespace OpenGL {
12
13void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info = "");
14
15} // namespace OpenGL \ No newline at end of file
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index 4726f54a5..b390219e4 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -10,6 +10,12 @@
10 10
11namespace Tegra::Texture { 11namespace Tegra::Texture {
12 12
13// GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents
14// an small rect of (64/bytes_per_pixel)X8.
15inline std::size_t GetGOBSize() {
16 return 512;
17}
18
13/** 19/**
14 * Unswizzles a swizzled texture without changing its format. 20 * Unswizzles a swizzled texture without changing its format.
15 */ 21 */
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index 237cc1307..e0a14d48f 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -161,30 +161,4 @@ static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixe
161 } 161 }
162} 162}
163 163
164static void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr,
165 std::string extra_info = "") {
166 if (!GLAD_GL_KHR_debug) {
167 return; // We don't need to throw an error as this is just for debugging
168 }
169 const std::string nice_addr = fmt::format("0x{:016x}", addr);
170 std::string object_label;
171
172 if (extra_info.empty()) {
173 switch (identifier) {
174 case GL_TEXTURE:
175 object_label = "Texture@" + nice_addr;
176 break;
177 case GL_PROGRAM:
178 object_label = "Shader@" + nice_addr;
179 break;
180 default:
181 object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
182 break;
183 }
184 } else {
185 object_label = extra_info + '@' + nice_addr;
186 }
187 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
188}
189
190} // namespace VideoCore 164} // namespace VideoCore