summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--externals/CMakeLists.txt4
m---------externals/zstd0
-rw-r--r--src/common/CMakeLists.txt5
-rw-r--r--src/common/bit_util.h16
-rw-r--r--src/common/lz4_compression.cpp76
-rw-r--r--src/common/lz4_compression.h55
-rw-r--r--src/common/multi_level_queue.h2
-rw-r--r--src/common/zstd_compression.cpp53
-rw-r--r--src/common/zstd_compression.h42
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp1
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h4
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp5
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h4
-rw-r--r--src/core/file_sys/control_metadata.cpp6
-rw-r--r--src/core/file_sys/control_metadata.h30
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp4
-rw-r--r--src/core/file_sys/nca_metadata.cpp8
-rw-r--r--src/core/file_sys/nca_metadata.h3
-rw-r--r--src/core/file_sys/program_metadata.cpp27
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/savedata_factory.cpp8
-rw-r--r--src/core/file_sys/savedata_factory.h11
-rw-r--r--src/core/gdbstub/gdbstub.cpp2
-rw-r--r--src/core/hle/ipc_helpers.h4
-rw-r--r--src/core/hle/kernel/client_port.cpp10
-rw-r--r--src/core/hle/kernel/object.cpp1
-rw-r--r--src/core/hle/kernel/object.h1
-rw-r--r--src/core/hle/kernel/server_port.cpp7
-rw-r--r--src/core/hle/kernel/server_port.h7
-rw-r--r--src/core/hle/kernel/server_session.cpp2
-rw-r--r--src/core/hle/kernel/server_session.h7
-rw-r--r--src/core/hle/kernel/svc.cpp14
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp22
-rw-r--r--src/core/hle/kernel/transfer_memory.h20
-rw-r--r--src/core/hle/result.h4
-rw-r--r--src/core/hle/service/am/am.cpp19
-rw-r--r--src/core/hle/service/audio/audin_u.cpp4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp4
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp4
-rw-r--r--src/core/hle/service/audio/audren_u.cpp13
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp19
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp89
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h2
-rw-r--r--src/core/hle/service/nvdrv/interface.h2
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.h2
-rw-r--r--src/core/hle/service/service.h2
-rw-r--r--src/core/hle/service/set/set_cal.h2
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp12
-rw-r--r--src/core/hle/service/spl/module.cpp4
-rw-r--r--src/core/hle/service/ssl/ssl.cpp10
-rw-r--r--src/core/hle/service/vi/vi.cpp5
-rw-r--r--src/core/loader/nso.cpp17
-rw-r--r--src/core/loader/xci.h2
-rw-r--r--src/core/memory.h10
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/engines/fermi_2d.cpp3
-rw-r--r--src/video_core/engines/fermi_2d.h8
-rw-r--r--src/video_core/engines/kepler_compute.h10
-rw-r--r--src/video_core/engines/kepler_memory.cpp4
-rw-r--r--src/video_core/engines/kepler_memory.h7
-rw-r--r--src/video_core/engines/maxwell_3d.cpp19
-rw-r--r--src/video_core/engines/maxwell_3d.h24
-rw-r--r--src/video_core/engines/maxwell_dma.cpp4
-rw-r--r--src/video_core/engines/maxwell_dma.h9
-rw-r--r--src/video_core/gpu.cpp2
-rw-r--r--src/video_core/gpu_asynch.cpp2
-rw-r--r--src/video_core/gpu_thread.cpp43
-rw-r--r--src/video_core/gpu_thread.h71
-rw-r--r--src/video_core/macro_interpreter.cpp20
-rw-r--r--src/video_core/memory_manager.cpp138
-rw-r--r--src/video_core/memory_manager.h16
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_global_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_primitive_assembler.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_primitive_assembler.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp36
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp46
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h11
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp1
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp206
-rw-r--r--src/yuzu/game_list.cpp4
-rw-r--r--src/yuzu/game_list.h1
-rw-r--r--src/yuzu/main.cpp48
-rw-r--r--src/yuzu/main.h1
98 files changed, 964 insertions, 517 deletions
diff --git a/.gitmodules b/.gitmodules
index 2558a5ebc..26b4e5272 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -40,3 +40,6 @@
40[submodule "Vulkan-Headers"] 40[submodule "Vulkan-Headers"]
41 path = externals/Vulkan-Headers 41 path = externals/Vulkan-Headers
42 url = https://github.com/KhronosGroup/Vulkan-Headers.git 42 url = https://github.com/KhronosGroup/Vulkan-Headers.git
43[submodule "externals/zstd"]
44 path = externals/zstd
45 url = https://github.com/facebook/zstd
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index e156bbece..aa3319eb1 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -49,6 +49,10 @@ add_subdirectory(open_source_archives EXCLUDE_FROM_ALL)
49add_library(unicorn-headers INTERFACE) 49add_library(unicorn-headers INTERFACE)
50target_include_directories(unicorn-headers INTERFACE ./unicorn/include) 50target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
51 51
52# Zstandard
53add_subdirectory(zstd/build/cmake EXCLUDE_FROM_ALL)
54target_include_directories(libzstd_static INTERFACE ./zstd/lib)
55
52# SoundTouch 56# SoundTouch
53add_subdirectory(soundtouch) 57add_subdirectory(soundtouch)
54 58
diff --git a/externals/zstd b/externals/zstd
new file mode 160000
Subproject 470344d33e1d52a2ada75d278466da8d4ee2faf
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 850ce8006..1e8e1b215 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -91,6 +91,8 @@ add_library(common STATIC
91 logging/log.h 91 logging/log.h
92 logging/text_formatter.cpp 92 logging/text_formatter.cpp
93 logging/text_formatter.h 93 logging/text_formatter.h
94 lz4_compression.cpp
95 lz4_compression.h
94 math_util.h 96 math_util.h
95 memory_hook.cpp 97 memory_hook.cpp
96 memory_hook.h 98 memory_hook.h
@@ -123,6 +125,8 @@ add_library(common STATIC
123 uint128.h 125 uint128.h
124 vector_math.h 126 vector_math.h
125 web_result.h 127 web_result.h
128 zstd_compression.cpp
129 zstd_compression.h
126) 130)
127 131
128if(ARCHITECTURE_x86_64) 132if(ARCHITECTURE_x86_64)
@@ -136,3 +140,4 @@ endif()
136create_target_directory_groups(common) 140create_target_directory_groups(common)
137 141
138target_link_libraries(common PUBLIC Boost::boost fmt microprofile) 142target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
143target_link_libraries(common PRIVATE lz4_static libzstd_static)
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index a4f9ed4aa..d032df413 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
32 return 32; 32 return 32;
33} 33}
34 34
35inline u64 CountLeadingZeroes64(u64 value) { 35inline u32 CountLeadingZeroes64(u64 value) {
36 unsigned long leading_zero = 0; 36 unsigned long leading_zero = 0;
37 37
38 if (_BitScanReverse64(&leading_zero, value) != 0) { 38 if (_BitScanReverse64(&leading_zero, value) != 0) {
@@ -47,15 +47,15 @@ inline u32 CountLeadingZeroes32(u32 value) {
47 return 32; 47 return 32;
48 } 48 }
49 49
50 return __builtin_clz(value); 50 return static_cast<u32>(__builtin_clz(value));
51} 51}
52 52
53inline u64 CountLeadingZeroes64(u64 value) { 53inline u32 CountLeadingZeroes64(u64 value) {
54 if (value == 0) { 54 if (value == 0) {
55 return 64; 55 return 64;
56 } 56 }
57 57
58 return __builtin_clzll(value); 58 return static_cast<u32>(__builtin_clzll(value));
59} 59}
60#endif 60#endif
61 61
@@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
70 return 32; 70 return 32;
71} 71}
72 72
73inline u64 CountTrailingZeroes64(u64 value) { 73inline u32 CountTrailingZeroes64(u64 value) {
74 unsigned long trailing_zero = 0; 74 unsigned long trailing_zero = 0;
75 75
76 if (_BitScanForward64(&trailing_zero, value) != 0) { 76 if (_BitScanForward64(&trailing_zero, value) != 0) {
@@ -85,15 +85,15 @@ inline u32 CountTrailingZeroes32(u32 value) {
85 return 32; 85 return 32;
86 } 86 }
87 87
88 return __builtin_ctz(value); 88 return static_cast<u32>(__builtin_ctz(value));
89} 89}
90 90
91inline u64 CountTrailingZeroes64(u64 value) { 91inline u32 CountTrailingZeroes64(u64 value) {
92 if (value == 0) { 92 if (value == 0) {
93 return 64; 93 return 64;
94 } 94 }
95 95
96 return __builtin_ctzll(value); 96 return static_cast<u32>(__builtin_ctzll(value));
97} 97}
98#endif 98#endif
99 99
diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp
new file mode 100644
index 000000000..ade6759bb
--- /dev/null
+++ b/src/common/lz4_compression.cpp
@@ -0,0 +1,76 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <lz4hc.h>
7
8#include "common/assert.h"
9#include "common/lz4_compression.h"
10
11namespace Common::Compression {
12
13std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) {
14 ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
15
16 const auto source_size_int = static_cast<int>(source_size);
17 const int max_compressed_size = LZ4_compressBound(source_size_int);
18 std::vector<u8> compressed(max_compressed_size);
19
20 const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source),
21 reinterpret_cast<char*>(compressed.data()),
22 source_size_int, max_compressed_size);
23
24 if (compressed_size <= 0) {
25 // Compression failed
26 return {};
27 }
28
29 compressed.resize(compressed_size);
30
31 return compressed;
32}
33
34std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
35 s32 compression_level) {
36 ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
37
38 compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
39
40 const auto source_size_int = static_cast<int>(source_size);
41 const int max_compressed_size = LZ4_compressBound(source_size_int);
42 std::vector<u8> compressed(max_compressed_size);
43
44 const int compressed_size = LZ4_compress_HC(
45 reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
46 source_size_int, max_compressed_size, compression_level);
47
48 if (compressed_size <= 0) {
49 // Compression failed
50 return {};
51 }
52
53 compressed.resize(compressed_size);
54
55 return compressed;
56}
57
58std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) {
59 return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX);
60}
61
62std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
63 std::size_t uncompressed_size) {
64 std::vector<u8> uncompressed(uncompressed_size);
65 const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()),
66 reinterpret_cast<char*>(uncompressed.data()),
67 static_cast<int>(compressed.size()),
68 static_cast<int>(uncompressed.size()));
69 if (static_cast<int>(uncompressed_size) != size_check) {
70 // Decompression failed
71 return {};
72 }
73 return uncompressed;
74}
75
76} // namespace Common::Compression
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h
new file mode 100644
index 000000000..fe2231a6c
--- /dev/null
+++ b/src/common/lz4_compression.h
@@ -0,0 +1,55 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "common/common_types.h"
8
9namespace Common::Compression {
10
11/**
12 * Compresses a source memory region with LZ4 and returns the compressed data in a vector.
13 *
14 * @param source the uncompressed source memory region.
15 * @param source_size the size in bytes of the uncompressed source memory region.
16 *
17 * @return the compressed data.
18 */
19std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
20
21/**
22 * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
23 * levels result in a smaller compressed size, but require more CPU time for compression. The
24 * compression level has almost no impact on decompression speed. Data compressed with LZ4HC can
25 * also be decompressed with the default LZ4 decompression.
26 *
27 * @param source the uncompressed source memory region.
28 * @param source_size the size in bytes of the uncompressed source memory region.
29 * @param compression_level the used compression level. Should be between 3 and 12.
30 *
31 * @return the compressed data.
32 */
33std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level);
34
35/**
36 * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
37 *
38 * @param source the uncompressed source memory region.
39 * @param source_size the size in bytes of the uncompressed source memory region.
40 *
41 * @return the compressed data.
42 */
43std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
44
45/**
46 * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
47 *
48 * @param compressed the compressed source memory region.
49 * @param uncompressed_size the size in bytes of the uncompressed data.
50 *
51 * @return the decompressed data.
52 */
53std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size);
54
55} // namespace Common::Compression \ No newline at end of file
diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h
index 2b61b91e0..9cb448f56 100644
--- a/src/common/multi_level_queue.h
+++ b/src/common/multi_level_queue.h
@@ -72,7 +72,7 @@ public:
72 u64 prios = mlq.used_priorities; 72 u64 prios = mlq.used_priorities;
73 prios &= ~((1ULL << (current_priority + 1)) - 1); 73 prios &= ~((1ULL << (current_priority + 1)) - 1);
74 if (prios == 0) { 74 if (prios == 0) {
75 current_priority = mlq.depth(); 75 current_priority = static_cast<u32>(mlq.depth());
76 } else { 76 } else {
77 current_priority = CountTrailingZeroes64(prios); 77 current_priority = CountTrailingZeroes64(prios);
78 it = GetBeginItForPrio(); 78 it = GetBeginItForPrio();
diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp
new file mode 100644
index 000000000..60a35c67c
--- /dev/null
+++ b/src/common/zstd_compression.cpp
@@ -0,0 +1,53 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <algorithm>
8#include <zstd.h>
9
10#include "common/assert.h"
11#include "common/zstd_compression.h"
12
13namespace Common::Compression {
14
15std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level) {
16 compression_level = std::clamp(compression_level, 1, ZSTD_maxCLevel());
17
18 const std::size_t max_compressed_size = ZSTD_compressBound(source_size);
19 std::vector<u8> compressed(max_compressed_size);
20
21 const std::size_t compressed_size =
22 ZSTD_compress(compressed.data(), compressed.size(), source, source_size, compression_level);
23
24 if (ZSTD_isError(compressed_size)) {
25 // Compression failed
26 return {};
27 }
28
29 compressed.resize(compressed_size);
30
31 return compressed;
32}
33
34std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) {
35 return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT);
36}
37
38std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) {
39 const std::size_t decompressed_size =
40 ZSTD_getDecompressedSize(compressed.data(), compressed.size());
41 std::vector<u8> decompressed(decompressed_size);
42
43 const std::size_t uncompressed_result_size = ZSTD_decompress(
44 decompressed.data(), decompressed.size(), compressed.data(), compressed.size());
45
46 if (decompressed_size != uncompressed_result_size || ZSTD_isError(uncompressed_result_size)) {
47 // Decompression failed
48 return {};
49 }
50 return decompressed;
51}
52
53} // namespace Common::Compression
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h
new file mode 100644
index 000000000..e0a64b035
--- /dev/null
+++ b/src/common/zstd_compression.h
@@ -0,0 +1,42 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "common/common_types.h"
8
9namespace Common::Compression {
10
11/**
12 * Compresses a source memory region with Zstandard and returns the compressed data in a vector.
13 *
14 * @param source the uncompressed source memory region.
15 * @param source_size the size in bytes of the uncompressed source memory region.
16 * @param compression_level the used compression level. Should be between 1 and 22.
17 *
18 * @return the compressed data.
19 */
20std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level);
21
22/**
23 * Compresses a source memory region with Zstandard with the default compression level and returns
24 * the compressed data in a vector.
25 *
26 * @param source the uncompressed source memory region.
27 * @param source_size the size in bytes of the uncompressed source memory region.
28 *
29 * @return the compressed data.
30 */
31std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
32
33/**
34 * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
35 *
36 * @param compressed the compressed source memory region.
37 *
38 * @return the decompressed data.
39 */
40std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
41
42} // namespace Common::Compression \ No newline at end of file
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9e23afe85..c59107102 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -458,7 +458,7 @@ add_library(core STATIC
458create_target_directory_groups(core) 458create_target_directory_groups(core)
459 459
460target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 460target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
461target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives) 461target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt mbedtls opus unicorn open_source_archives)
462if (ENABLE_WEB_SERVICE) 462if (ENABLE_WEB_SERVICE)
463 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) 463 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
464 target_link_libraries(core PRIVATE web_service) 464 target_link_libraries(core PRIVATE web_service)
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 4fdc12f11..f64e4c6a6 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -26,7 +26,6 @@ using Vector = Dynarmic::A64::Vector;
26class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks { 26class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks {
27public: 27public:
28 explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {} 28 explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
29 ~ARM_Dynarmic_Callbacks() = default;
30 29
31 u8 MemoryRead8(u64 vaddr) override { 30 u8 MemoryRead8(u64 vaddr) override {
32 return Memory::Read8(vaddr); 31 return Memory::Read8(vaddr);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index aada1e862..81e0b4ac0 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -29,7 +29,7 @@ class ARM_Dynarmic final : public ARM_Interface {
29public: 29public:
30 ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor, 30 ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
31 std::size_t core_index); 31 std::size_t core_index);
32 ~ARM_Dynarmic(); 32 ~ARM_Dynarmic() override;
33 33
34 void MapBackingMemory(VAddr address, std::size_t size, u8* memory, 34 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
35 Kernel::VMAPermission perms) override; 35 Kernel::VMAPermission perms) override;
@@ -76,7 +76,7 @@ private:
76class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 76class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
77public: 77public:
78 explicit DynarmicExclusiveMonitor(std::size_t core_count); 78 explicit DynarmicExclusiveMonitor(std::size_t core_count);
79 ~DynarmicExclusiveMonitor(); 79 ~DynarmicExclusiveMonitor() override;
80 80
81 void SetExclusive(std::size_t core_index, VAddr addr) override; 81 void SetExclusive(std::size_t core_index, VAddr addr) override;
82 void ClearExclusive() override; 82 void ClearExclusive() override;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index a542a098b..27309280c 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -192,12 +192,13 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
192 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); 192 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
193 core_timing.AddTicks(num_instructions); 193 core_timing.AddTicks(num_instructions);
194 if (GDBStub::IsServerEnabled()) { 194 if (GDBStub::IsServerEnabled()) {
195 if (last_bkpt_hit) { 195 if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
196 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); 196 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
197 } 197 }
198
198 Kernel::Thread* thread = Kernel::GetCurrentThread(); 199 Kernel::Thread* thread = Kernel::GetCurrentThread();
199 SaveContext(thread->GetContext()); 200 SaveContext(thread->GetContext());
200 if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) { 201 if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
201 last_bkpt_hit = false; 202 last_bkpt_hit = false;
202 GDBStub::Break(); 203 GDBStub::Break();
203 GDBStub::SendTrap(thread, 5); 204 GDBStub::SendTrap(thread, 5);
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index dbd6955ea..1e44f0736 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -18,7 +18,7 @@ namespace Core {
18class ARM_Unicorn final : public ARM_Interface { 18class ARM_Unicorn final : public ARM_Interface {
19public: 19public:
20 explicit ARM_Unicorn(Timing::CoreTiming& core_timing); 20 explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
21 ~ARM_Unicorn(); 21 ~ARM_Unicorn() override;
22 22
23 void MapBackingMemory(VAddr address, std::size_t size, u8* memory, 23 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
24 Kernel::VMAPermission perms) override; 24 Kernel::VMAPermission perms) override;
@@ -50,7 +50,7 @@ private:
50 uc_engine* uc{}; 50 uc_engine* uc{};
51 Timing::CoreTiming& core_timing; 51 Timing::CoreTiming& core_timing;
52 GDBStub::BreakpointAddress last_bkpt{}; 52 GDBStub::BreakpointAddress last_bkpt{};
53 bool last_bkpt_hit; 53 bool last_bkpt_hit = false;
54}; 54};
55 55
56} // namespace Core 56} // namespace Core
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 83c184750..60ea9ad12 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -67,7 +67,7 @@ std::string NACP::GetDeveloperName(Language language) const {
67} 67}
68 68
69u64 NACP::GetTitleId() const { 69u64 NACP::GetTitleId() const {
70 return raw.title_id; 70 return raw.save_data_owner_id;
71} 71}
72 72
73u64 NACP::GetDLCBaseTitleId() const { 73u64 NACP::GetDLCBaseTitleId() const {
@@ -80,11 +80,11 @@ std::string NACP::GetVersionString() const {
80} 80}
81 81
82u64 NACP::GetDefaultNormalSaveSize() const { 82u64 NACP::GetDefaultNormalSaveSize() const {
83 return raw.normal_save_data_size; 83 return raw.user_account_save_data_size;
84} 84}
85 85
86u64 NACP::GetDefaultJournalSaveSize() const { 86u64 NACP::GetDefaultJournalSaveSize() const {
87 return raw.journal_sava_data_size; 87 return raw.user_account_save_data_journal_size;
88} 88}
89 89
90std::vector<u8> NACP::GetRawBytes() const { 90std::vector<u8> NACP::GetRawBytes() const {
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 7b9cdc910..280710ddf 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -38,23 +38,35 @@ struct RawNACP {
38 u8 video_capture_mode; 38 u8 video_capture_mode;
39 bool data_loss_confirmation; 39 bool data_loss_confirmation;
40 INSERT_PADDING_BYTES(1); 40 INSERT_PADDING_BYTES(1);
41 u64_le title_id; 41 u64_le presence_group_id;
42 std::array<u8, 0x20> rating_age; 42 std::array<u8, 0x20> rating_age;
43 std::array<char, 0x10> version_string; 43 std::array<char, 0x10> version_string;
44 u64_le dlc_base_title_id; 44 u64_le dlc_base_title_id;
45 u64_le title_id_2; 45 u64_le save_data_owner_id;
46 u64_le normal_save_data_size; 46 u64_le user_account_save_data_size;
47 u64_le journal_sava_data_size; 47 u64_le user_account_save_data_journal_size;
48 INSERT_PADDING_BYTES(0x18); 48 u64_le device_save_data_size;
49 u64_le product_code; 49 u64_le device_save_data_journal_size;
50 u64_le bcat_delivery_cache_storage_size;
51 char application_error_code_category[8];
50 std::array<u64_le, 0x8> local_communication; 52 std::array<u64_le, 0x8> local_communication;
51 u8 logo_type; 53 u8 logo_type;
52 u8 logo_handling; 54 u8 logo_handling;
53 bool runtime_add_on_content_install; 55 bool runtime_add_on_content_install;
54 INSERT_PADDING_BYTES(5); 56 INSERT_PADDING_BYTES(5);
55 u64_le title_id_update; 57 u64_le seed_for_pseudo_device_id;
56 std::array<u8, 0x40> bcat_passphrase; 58 std::array<u8, 0x41> bcat_passphrase;
57 INSERT_PADDING_BYTES(0xEC0); 59 INSERT_PADDING_BYTES(7);
60 u64_le user_account_save_data_max_size;
61 u64_le user_account_save_data_max_journal_size;
62 u64_le device_save_data_max_size;
63 u64_le device_save_data_max_journal_size;
64 u64_le temporary_storage_size;
65 u64_le cache_storage_size;
66 u64_le cache_storage_journal_size;
67 u64_le cache_storage_data_and_journal_max_size;
68 u64_le cache_storage_max_index;
69 INSERT_PADDING_BYTES(0xE70);
58}; 70};
59static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); 71static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size.");
60 72
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 47b7526c7..d126ae8dd 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <cstring> 25#include <cstring>
26#include <string_view>
26#include "common/alignment.h" 27#include "common/alignment.h"
27#include "common/assert.h" 28#include "common/assert.h"
28#include "core/file_sys/fsmitm_romfsbuild.h" 29#include "core/file_sys/fsmitm_romfsbuild.h"
@@ -97,7 +98,8 @@ struct RomFSBuildFileContext {
97 VirtualFile source; 98 VirtualFile source;
98}; 99};
99 100
100static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) { 101static u32 romfs_calc_path_hash(u32 parent, std::string_view path, u32 start,
102 std::size_t path_len) {
101 u32 hash = parent ^ 123456789; 103 u32 hash = parent ^ 123456789;
102 for (u32 i = 0; i < path_len; i++) { 104 for (u32 i = 0; i < path_len; i++) {
103 hash = (hash >> 5) | (hash << 27); 105 hash = (hash >> 5) | (hash << 27);
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 6f34b7836..93d0df6b9 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -10,14 +10,6 @@
10 10
11namespace FileSys { 11namespace FileSys {
12 12
13bool operator>=(TitleType lhs, TitleType rhs) {
14 return static_cast<std::size_t>(lhs) >= static_cast<std::size_t>(rhs);
15}
16
17bool operator<=(TitleType lhs, TitleType rhs) {
18 return static_cast<std::size_t>(lhs) <= static_cast<std::size_t>(rhs);
19}
20
21CNMT::CNMT(VirtualFile file) { 13CNMT::CNMT(VirtualFile file) {
22 if (file->ReadObject(&header) != sizeof(CNMTHeader)) 14 if (file->ReadObject(&header) != sizeof(CNMTHeader))
23 return; 15 return;
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index a05d155f4..50bf38471 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -29,9 +29,6 @@ enum class TitleType : u8 {
29 DeltaTitle = 0x83, 29 DeltaTitle = 0x83,
30}; 30};
31 31
32bool operator>=(TitleType lhs, TitleType rhs);
33bool operator<=(TitleType lhs, TitleType rhs);
34
35enum class ContentRecordType : u8 { 32enum class ContentRecordType : u8 {
36 Meta = 0, 33 Meta = 0,
37 Program = 1, 34 Program = 1,
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index d3e00437f..d863253f8 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstddef> 5#include <cstddef>
6#include <cstring>
7#include <vector> 6#include <vector>
8 7
9#include "common/logging/log.h" 8#include "common/logging/log.h"
@@ -17,28 +16,30 @@ ProgramMetadata::ProgramMetadata() = default;
17ProgramMetadata::~ProgramMetadata() = default; 16ProgramMetadata::~ProgramMetadata() = default;
18 17
19Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { 18Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
20 std::size_t total_size = static_cast<std::size_t>(file->GetSize()); 19 const std::size_t total_size = file->GetSize();
21 if (total_size < sizeof(Header)) 20 if (total_size < sizeof(Header)) {
22 return Loader::ResultStatus::ErrorBadNPDMHeader; 21 return Loader::ResultStatus::ErrorBadNPDMHeader;
22 }
23 23
24 // TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable. 24 if (sizeof(Header) != file->ReadObject(&npdm_header)) {
25 std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
26 if (sizeof(Header) != npdm_header_data.size())
27 return Loader::ResultStatus::ErrorBadNPDMHeader; 25 return Loader::ResultStatus::ErrorBadNPDMHeader;
28 std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header)); 26 }
29 27
30 std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset); 28 if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) {
31 if (sizeof(AcidHeader) != acid_header_data.size())
32 return Loader::ResultStatus::ErrorBadACIDHeader; 29 return Loader::ResultStatus::ErrorBadACIDHeader;
33 std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader)); 30 }
34 31
35 if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) 32 if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) {
36 return Loader::ResultStatus::ErrorBadACIHeader; 33 return Loader::ResultStatus::ErrorBadACIHeader;
34 }
37 35
38 if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) 36 if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) {
39 return Loader::ResultStatus::ErrorBadFileAccessControl; 37 return Loader::ResultStatus::ErrorBadFileAccessControl;
40 if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) 38 }
39
40 if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) {
41 return Loader::ResultStatus::ErrorBadFileAccessHeader; 41 return Loader::ResultStatus::ErrorBadFileAccessHeader;
42 }
42 43
43 aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32)); 44 aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32));
44 const u64 read_size = aci_header.kac_size; 45 const u64 read_size = aci_header.kac_size;
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 0033ba347..7de5b9cf9 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -58,7 +58,6 @@ public:
58 void Print() const; 58 void Print() const;
59 59
60private: 60private:
61 // TODO(DarkLordZach): BitField is not trivially copyable.
62 struct Header { 61 struct Header {
63 std::array<char, 4> magic; 62 std::array<char, 4> magic;
64 std::array<u8, 8> reserved; 63 std::array<u8, 8> reserved;
@@ -85,7 +84,6 @@ private:
85 84
86 static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong"); 85 static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");
87 86
88 // TODO(DarkLordZach): BitField is not trivially copyable.
89 struct AcidHeader { 87 struct AcidHeader {
90 std::array<u8, 0x100> signature; 88 std::array<u8, 0x100> signature;
91 std::array<u8, 0x100> nca_modulus; 89 std::array<u8, 0x100> nca_modulus;
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 1913dc956..7974b031d 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -16,8 +16,10 @@ namespace FileSys {
16constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size"; 16constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
17 17
18std::string SaveDataDescriptor::DebugInfo() const { 18std::string SaveDataDescriptor::DebugInfo() const {
19 return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]", 19 return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, "
20 static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id); 20 "rank={}, index={}]",
21 static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
22 static_cast<u8>(rank), index);
21} 23}
22 24
23SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) { 25SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
@@ -28,7 +30,7 @@ SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save
28 30
29SaveDataFactory::~SaveDataFactory() = default; 31SaveDataFactory::~SaveDataFactory() = default;
30 32
31ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) { 33ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
32 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) { 34 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
33 if (meta.zero_1 != 0) { 35 if (meta.zero_1 != 0) {
34 LOG_WARNING(Service_FS, 36 LOG_WARNING(Service_FS,
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 3a1caf292..b73654571 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -32,12 +32,19 @@ enum class SaveDataType : u8 {
32 CacheStorage = 5, 32 CacheStorage = 5,
33}; 33};
34 34
35enum class SaveDataRank : u8 {
36 Primary,
37 Secondary,
38};
39
35struct SaveDataDescriptor { 40struct SaveDataDescriptor {
36 u64_le title_id; 41 u64_le title_id;
37 u128 user_id; 42 u128 user_id;
38 u64_le save_id; 43 u64_le save_id;
39 SaveDataType type; 44 SaveDataType type;
40 INSERT_PADDING_BYTES(7); 45 SaveDataRank rank;
46 u16_le index;
47 INSERT_PADDING_BYTES(4);
41 u64_le zero_1; 48 u64_le zero_1;
42 u64_le zero_2; 49 u64_le zero_2;
43 u64_le zero_3; 50 u64_le zero_3;
@@ -57,7 +64,7 @@ public:
57 explicit SaveDataFactory(VirtualDir dir); 64 explicit SaveDataFactory(VirtualDir dir);
58 ~SaveDataFactory(); 65 ~SaveDataFactory();
59 66
60 ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); 67 ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta);
61 68
62 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; 69 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
63 70
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index dafb32aae..afa812598 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -1030,7 +1030,7 @@ static void Step() {
1030 1030
1031/// Tell the CPU if we hit a memory breakpoint. 1031/// Tell the CPU if we hit a memory breakpoint.
1032bool IsMemoryBreak() { 1032bool IsMemoryBreak() {
1033 if (IsConnected()) { 1033 if (!IsConnected()) {
1034 return false; 1034 return false;
1035 } 1035 }
1036 1036
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 68406eb63..ac0e1d796 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -139,10 +139,8 @@ public:
139 context->AddDomainObject(std::move(iface)); 139 context->AddDomainObject(std::move(iface));
140 } else { 140 } else {
141 auto& kernel = Core::System::GetInstance().Kernel(); 141 auto& kernel = Core::System::GetInstance().Kernel();
142 auto sessions = 142 auto [server, client] =
143 Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName()); 143 Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName());
144 auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
145 auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
146 iface->ClientConnected(server); 144 iface->ClientConnected(server);
147 context->AddMoveObject(std::move(client)); 145 context->AddMoveObject(std::move(client));
148 } 146 }
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index aa432658e..744b1697d 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -2,8 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <tuple>
6
7#include "core/hle/kernel/client_port.h" 5#include "core/hle/kernel/client_port.h"
8#include "core/hle/kernel/client_session.h" 6#include "core/hle/kernel/client_session.h"
9#include "core/hle/kernel/errors.h" 7#include "core/hle/kernel/errors.h"
@@ -31,18 +29,18 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
31 active_sessions++; 29 active_sessions++;
32 30
33 // Create a new session pair, let the created sessions inherit the parent port's HLE handler. 31 // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
34 auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this); 32 auto [server, client] = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
35 33
36 if (server_port->HasHLEHandler()) { 34 if (server_port->HasHLEHandler()) {
37 server_port->GetHLEHandler()->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); 35 server_port->GetHLEHandler()->ClientConnected(server);
38 } else { 36 } else {
39 server_port->AppendPendingSession(std::get<SharedPtr<ServerSession>>(sessions)); 37 server_port->AppendPendingSession(server);
40 } 38 }
41 39
42 // Wake the threads waiting on the ServerPort 40 // Wake the threads waiting on the ServerPort
43 server_port->WakeupAllWaitingThreads(); 41 server_port->WakeupAllWaitingThreads();
44 42
45 return MakeResult(std::get<SharedPtr<ClientSession>>(sessions)); 43 return MakeResult(client);
46} 44}
47 45
48void ClientPort::ConnectionClosed() { 46void ClientPort::ConnectionClosed() {
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index 217144efc..10431e94c 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -24,7 +24,6 @@ bool Object::IsWaitable() const {
24 case HandleType::WritableEvent: 24 case HandleType::WritableEvent:
25 case HandleType::SharedMemory: 25 case HandleType::SharedMemory:
26 case HandleType::TransferMemory: 26 case HandleType::TransferMemory:
27 case HandleType::AddressArbiter:
28 case HandleType::ResourceLimit: 27 case HandleType::ResourceLimit:
29 case HandleType::ClientPort: 28 case HandleType::ClientPort:
30 case HandleType::ClientSession: 29 case HandleType::ClientSession:
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index 3f6baa094..332876c27 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -25,7 +25,6 @@ enum class HandleType : u32 {
25 TransferMemory, 25 TransferMemory,
26 Thread, 26 Thread,
27 Process, 27 Process,
28 AddressArbiter,
29 ResourceLimit, 28 ResourceLimit,
30 ClientPort, 29 ClientPort,
31 ServerPort, 30 ServerPort,
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 708fdf9e1..02e7c60e6 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -39,9 +39,8 @@ void ServerPort::Acquire(Thread* thread) {
39 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 39 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
40} 40}
41 41
42std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( 42ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
43 KernelCore& kernel, u32 max_sessions, std::string name) { 43 std::string name) {
44
45 SharedPtr<ServerPort> server_port(new ServerPort(kernel)); 44 SharedPtr<ServerPort> server_port(new ServerPort(kernel));
46 SharedPtr<ClientPort> client_port(new ClientPort(kernel)); 45 SharedPtr<ClientPort> client_port(new ClientPort(kernel));
47 46
@@ -51,7 +50,7 @@ std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortP
51 client_port->max_sessions = max_sessions; 50 client_port->max_sessions = max_sessions;
52 client_port->active_sessions = 0; 51 client_port->active_sessions = 0;
53 52
54 return std::make_tuple(std::move(server_port), std::move(client_port)); 53 return std::make_pair(std::move(server_port), std::move(client_port));
55} 54}
56 55
57} // namespace Kernel 56} // namespace Kernel
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 76293cb8b..fef573b71 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -6,7 +6,7 @@
6 6
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include <tuple> 9#include <utility>
10#include <vector> 10#include <vector>
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/hle/kernel/object.h" 12#include "core/hle/kernel/object.h"
@@ -23,6 +23,7 @@ class SessionRequestHandler;
23class ServerPort final : public WaitObject { 23class ServerPort final : public WaitObject {
24public: 24public:
25 using HLEHandler = std::shared_ptr<SessionRequestHandler>; 25 using HLEHandler = std::shared_ptr<SessionRequestHandler>;
26 using PortPair = std::pair<SharedPtr<ServerPort>, SharedPtr<ClientPort>>;
26 27
27 /** 28 /**
28 * Creates a pair of ServerPort and an associated ClientPort. 29 * Creates a pair of ServerPort and an associated ClientPort.
@@ -32,8 +33,8 @@ public:
32 * @param name Optional name of the ports 33 * @param name Optional name of the ports
33 * @return The created port tuple 34 * @return The created port tuple
34 */ 35 */
35 static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( 36 static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions,
36 KernelCore& kernel, u32 max_sessions, std::string name = "UnknownPort"); 37 std::string name = "UnknownPort");
37 38
38 std::string GetTypeName() const override { 39 std::string GetTypeName() const override {
39 return "ServerPort"; 40 return "ServerPort";
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 40cec143e..a6b2cf06a 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -204,6 +204,6 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel,
204 client_session->parent = parent; 204 client_session->parent = parent;
205 server_session->parent = parent; 205 server_session->parent = parent;
206 206
207 return std::make_tuple(std::move(server_session), std::move(client_session)); 207 return std::make_pair(std::move(server_session), std::move(client_session));
208} 208}
209} // namespace Kernel 209} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 79b84bade..09b835ff8 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -6,6 +6,7 @@
6 6
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include <utility>
9#include <vector> 10#include <vector>
10 11
11#include "core/hle/kernel/object.h" 12#include "core/hle/kernel/object.h"
@@ -41,6 +42,10 @@ public:
41 return "ServerSession"; 42 return "ServerSession";
42 } 43 }
43 44
45 std::string GetName() const override {
46 return name;
47 }
48
44 static const HandleType HANDLE_TYPE = HandleType::ServerSession; 49 static const HandleType HANDLE_TYPE = HandleType::ServerSession;
45 HandleType GetHandleType() const override { 50 HandleType GetHandleType() const override {
46 return HANDLE_TYPE; 51 return HANDLE_TYPE;
@@ -54,7 +59,7 @@ public:
54 return parent.get(); 59 return parent.get();
55 } 60 }
56 61
57 using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>; 62 using SessionPair = std::pair<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
58 63
59 /** 64 /**
60 * Creates a pair of ServerSession and an associated ClientSession. 65 * Creates a pair of ServerSession and an associated ClientSession.
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index ab10db3df..2fd07ab34 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1339,6 +1339,20 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
1339 "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", 1339 "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
1340 mutex_addr, condition_variable_addr, thread_handle, nano_seconds); 1340 mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
1341 1341
1342 if (Memory::IsKernelVirtualAddress(mutex_addr)) {
1343 LOG_ERROR(
1344 Kernel_SVC,
1345 "Given mutex address must not be within the kernel address space. address=0x{:016X}",
1346 mutex_addr);
1347 return ERR_INVALID_ADDRESS_STATE;
1348 }
1349
1350 if (!Common::IsWordAligned(mutex_addr)) {
1351 LOG_ERROR(Kernel_SVC, "Given mutex address must be word-aligned. address=0x{:016X}",
1352 mutex_addr);
1353 return ERR_INVALID_ADDRESS;
1354 }
1355
1342 auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess(); 1356 auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
1343 const auto& handle_table = current_process->GetHandleTable(); 1357 const auto& handle_table = current_process->GetHandleTable();
1344 SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1358 SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp
index 23228e1b5..26c4e5e67 100644
--- a/src/core/hle/kernel/transfer_memory.cpp
+++ b/src/core/hle/kernel/transfer_memory.cpp
@@ -14,8 +14,8 @@ namespace Kernel {
14TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} 14TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
15TransferMemory::~TransferMemory() = default; 15TransferMemory::~TransferMemory() = default;
16 16
17SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, 17SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, u64 size,
18 size_t size, MemoryPermission permissions) { 18 MemoryPermission permissions) {
19 SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)}; 19 SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)};
20 20
21 transfer_memory->base_address = base_address; 21 transfer_memory->base_address = base_address;
@@ -26,7 +26,15 @@ SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_
26 return transfer_memory; 26 return transfer_memory;
27} 27}
28 28
29ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermission permissions) { 29const u8* TransferMemory::GetPointer() const {
30 return backing_block.get()->data();
31}
32
33u64 TransferMemory::GetSize() const {
34 return memory_size;
35}
36
37ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission permissions) {
30 if (memory_size != size) { 38 if (memory_size != size) {
31 return ERR_INVALID_SIZE; 39 return ERR_INVALID_SIZE;
32 } 40 }
@@ -39,13 +47,13 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio
39 return ERR_INVALID_STATE; 47 return ERR_INVALID_STATE;
40 } 48 }
41 49
50 backing_block = std::make_shared<std::vector<u8>>(size);
51
42 const auto map_state = owner_permissions == MemoryPermission::None 52 const auto map_state = owner_permissions == MemoryPermission::None
43 ? MemoryState::TransferMemoryIsolated 53 ? MemoryState::TransferMemoryIsolated
44 : MemoryState::TransferMemory; 54 : MemoryState::TransferMemory;
45 auto& vm_manager = owner_process->VMManager(); 55 auto& vm_manager = owner_process->VMManager();
46 const auto map_result = vm_manager.MapMemoryBlock( 56 const auto map_result = vm_manager.MapMemoryBlock(address, backing_block, 0, size, map_state);
47 address, std::make_shared<std::vector<u8>>(size), 0, size, map_state);
48
49 if (map_result.Failed()) { 57 if (map_result.Failed()) {
50 return map_result.Code(); 58 return map_result.Code();
51 } 59 }
@@ -54,7 +62,7 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio
54 return RESULT_SUCCESS; 62 return RESULT_SUCCESS;
55} 63}
56 64
57ResultCode TransferMemory::UnmapMemory(VAddr address, size_t size) { 65ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) {
58 if (memory_size != size) { 66 if (memory_size != size) {
59 return ERR_INVALID_SIZE; 67 return ERR_INVALID_SIZE;
60 } 68 }
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h
index ec294951e..a140b1e2b 100644
--- a/src/core/hle/kernel/transfer_memory.h
+++ b/src/core/hle/kernel/transfer_memory.h
@@ -4,6 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <vector>
9
7#include "core/hle/kernel/object.h" 10#include "core/hle/kernel/object.h"
8 11
9union ResultCode; 12union ResultCode;
@@ -25,7 +28,7 @@ class TransferMemory final : public Object {
25public: 28public:
26 static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; 29 static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
27 30
28 static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, size_t size, 31 static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
29 MemoryPermission permissions); 32 MemoryPermission permissions);
30 33
31 TransferMemory(const TransferMemory&) = delete; 34 TransferMemory(const TransferMemory&) = delete;
@@ -46,6 +49,12 @@ public:
46 return HANDLE_TYPE; 49 return HANDLE_TYPE;
47 } 50 }
48 51
52 /// Gets a pointer to the backing block of this instance.
53 const u8* GetPointer() const;
54
55 /// Gets the size of the memory backing this instance in bytes.
56 u64 GetSize() const;
57
49 /// Attempts to map transfer memory with the given range and memory permissions. 58 /// Attempts to map transfer memory with the given range and memory permissions.
50 /// 59 ///
51 /// @param address The base address to being mapping memory at. 60 /// @param address The base address to being mapping memory at.
@@ -56,7 +65,7 @@ public:
56 /// the same values that were given when creating the transfer memory 65 /// the same values that were given when creating the transfer memory
57 /// instance. 66 /// instance.
58 /// 67 ///
59 ResultCode MapMemory(VAddr address, size_t size, MemoryPermission permissions); 68 ResultCode MapMemory(VAddr address, u64 size, MemoryPermission permissions);
60 69
61 /// Unmaps the transfer memory with the given range 70 /// Unmaps the transfer memory with the given range
62 /// 71 ///
@@ -66,17 +75,20 @@ public:
66 /// @pre The given address and size must be the same as the ones used 75 /// @pre The given address and size must be the same as the ones used
67 /// to create the transfer memory instance. 76 /// to create the transfer memory instance.
68 /// 77 ///
69 ResultCode UnmapMemory(VAddr address, size_t size); 78 ResultCode UnmapMemory(VAddr address, u64 size);
70 79
71private: 80private:
72 explicit TransferMemory(KernelCore& kernel); 81 explicit TransferMemory(KernelCore& kernel);
73 ~TransferMemory() override; 82 ~TransferMemory() override;
74 83
84 /// Memory block backing this instance.
85 std::shared_ptr<std::vector<u8>> backing_block;
86
75 /// The base address for the memory managed by this instance. 87 /// The base address for the memory managed by this instance.
76 VAddr base_address = 0; 88 VAddr base_address = 0;
77 89
78 /// Size of the memory, in bytes, that this instance manages. 90 /// Size of the memory, in bytes, that this instance manages.
79 size_t memory_size = 0; 91 u64 memory_size = 0;
80 92
81 /// The memory permissions that are applied to this instance. 93 /// The memory permissions that are applied to this instance.
82 MemoryPermission owner_permissions{}; 94 MemoryPermission owner_permissions{};
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index ab84f5ddc..8a3701151 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -119,10 +119,6 @@ union ResultCode {
119 BitField<0, 9, ErrorModule> module; 119 BitField<0, 9, ErrorModule> module;
120 BitField<9, 13, u32> description; 120 BitField<9, 13, u32> description;
121 121
122 // The last bit of `level` is checked by apps and the kernel to determine if a result code is an
123 // error
124 BitField<31, 1, u32> is_error;
125
126 constexpr explicit ResultCode(u32 raw) : raw(raw) {} 122 constexpr explicit ResultCode(u32 raw) : raw(raw) {}
127 123
128 constexpr ResultCode(ErrorModule module_, u32 description_) 124 constexpr ResultCode(ErrorModule module_, u32 description_)
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d31ab7970..85271d418 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -13,7 +13,7 @@
13#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/readable_event.h" 15#include "core/hle/kernel/readable_event.h"
16#include "core/hle/kernel/shared_memory.h" 16#include "core/hle/kernel/transfer_memory.h"
17#include "core/hle/kernel/writable_event.h" 17#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/acc/profile_manager.h" 18#include "core/hle/service/acc/profile_manager.h"
19#include "core/hle/service/am/am.h" 19#include "core/hle/service/am/am.h"
@@ -363,8 +363,6 @@ void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestCo
363void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { 363void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
364 // Takes 3 input u8s with each field located immediately after the previous 364 // Takes 3 input u8s with each field located immediately after the previous
365 // u8, these are bool flags. No output. 365 // u8, these are bool flags. No output.
366 LOG_WARNING(Service_AM, "(STUBBED) called");
367
368 IPC::RequestParser rp{ctx}; 366 IPC::RequestParser rp{ctx};
369 367
370 struct FocusHandlingModeParams { 368 struct FocusHandlingModeParams {
@@ -372,7 +370,10 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
372 u8 unknown1; 370 u8 unknown1;
373 u8 unknown2; 371 u8 unknown2;
374 }; 372 };
375 auto flags = rp.PopRaw<FocusHandlingModeParams>(); 373 const auto flags = rp.PopRaw<FocusHandlingModeParams>();
374
375 LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
376 flags.unknown0, flags.unknown1, flags.unknown2);
376 377
377 IPC::ResponseBuilder rb{ctx, 2}; 378 IPC::ResponseBuilder rb{ctx, 2};
378 rb.Push(RESULT_SUCCESS); 379 rb.Push(RESULT_SUCCESS);
@@ -931,19 +932,19 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
931 rp.SetCurrentOffset(3); 932 rp.SetCurrentOffset(3);
932 const auto handle{rp.Pop<Kernel::Handle>()}; 933 const auto handle{rp.Pop<Kernel::Handle>()};
933 934
934 const auto shared_mem = 935 const auto transfer_mem =
935 Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>( 936 Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(
936 handle); 937 handle);
937 938
938 if (shared_mem == nullptr) { 939 if (transfer_mem == nullptr) {
939 LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); 940 LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
940 IPC::ResponseBuilder rb{ctx, 2}; 941 IPC::ResponseBuilder rb{ctx, 2};
941 rb.Push(ResultCode(-1)); 942 rb.Push(ResultCode(-1));
942 return; 943 return;
943 } 944 }
944 945
945 const u8* mem_begin = shared_mem->GetPointer(); 946 const u8* const mem_begin = transfer_mem->GetPointer();
946 const u8* mem_end = mem_begin + shared_mem->GetSize(); 947 const u8* const mem_end = mem_begin + transfer_mem->GetSize();
947 std::vector<u8> memory{mem_begin, mem_end}; 948 std::vector<u8> memory{mem_begin, mem_end};
948 949
949 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 950 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 088410564..e5daefdde 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -2,9 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/audio/audin_u.h" 5#include "core/hle/service/audio/audin_u.h"
9 6
10namespace Service::Audio { 7namespace Service::Audio {
@@ -33,7 +30,6 @@ public:
33 30
34 RegisterHandlers(functions); 31 RegisterHandlers(functions);
35 } 32 }
36 ~IAudioIn() = default;
37}; 33};
38 34
39AudInU::AudInU() : ServiceFramework("audin:u") { 35AudInU::AudInU() : ServiceFramework("audin:u") {
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 21f5e64c7..39acb7b23 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -150,7 +150,6 @@ private:
150 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 150 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
151 LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); 151 LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
152 152
153 IPC::RequestParser rp{ctx};
154 const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; 153 const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
155 const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; 154 const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
156 155
@@ -194,12 +193,9 @@ private:
194void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { 193void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
195 LOG_DEBUG(Service_Audio, "called"); 194 LOG_DEBUG(Service_Audio, "called");
196 195
197 IPC::RequestParser rp{ctx};
198
199 ctx.WriteBuffer(DefaultDevice); 196 ctx.WriteBuffer(DefaultDevice);
200 197
201 IPC::ResponseBuilder rb{ctx, 3}; 198 IPC::ResponseBuilder rb{ctx, 3};
202
203 rb.Push(RESULT_SUCCESS); 199 rb.Push(RESULT_SUCCESS);
204 rb.Push<u32>(1); // Amount of audio devices 200 rb.Push<u32>(1); // Amount of audio devices
205} 201}
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
index 6956a2e64..1a5aed9ed 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -2,9 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/audio/audrec_u.h" 5#include "core/hle/service/audio/audrec_u.h"
9 6
10namespace Service::Audio { 7namespace Service::Audio {
@@ -30,7 +27,6 @@ public:
30 27
31 RegisterHandlers(functions); 28 RegisterHandlers(functions);
32 } 29 }
33 ~IFinalOutputRecorder() = default;
34}; 30};
35 31
36AudRecU::AudRecU() : ServiceFramework("audrec:u") { 32AudRecU::AudRecU() : ServiceFramework("audrec:u") {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index c9de10a24..1dde6edb7 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -10,6 +10,7 @@
10#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/common_funcs.h" 11#include "common/common_funcs.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/string_util.h"
13#include "core/core.h" 14#include "core/core.h"
14#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
@@ -184,7 +185,6 @@ public:
184private: 185private:
185 void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { 186 void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
186 LOG_WARNING(Service_Audio, "(STUBBED) called"); 187 LOG_WARNING(Service_Audio, "(STUBBED) called");
187 IPC::RequestParser rp{ctx};
188 188
189 constexpr std::array<char, 15> audio_interface{{"AudioInterface"}}; 189 constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
190 ctx.WriteBuffer(audio_interface); 190 ctx.WriteBuffer(audio_interface);
@@ -195,13 +195,13 @@ private:
195 } 195 }
196 196
197 void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { 197 void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
198 LOG_WARNING(Service_Audio, "(STUBBED) called");
199
200 IPC::RequestParser rp{ctx}; 198 IPC::RequestParser rp{ctx};
201 f32 volume = static_cast<f32>(rp.Pop<u32>()); 199 const f32 volume = rp.Pop<f32>();
202 200
203 auto file_buffer = ctx.ReadBuffer(); 201 const auto device_name_buffer = ctx.ReadBuffer();
204 auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); 202 const std::string name = Common::StringFromBuffer(device_name_buffer);
203
204 LOG_WARNING(Service_Audio, "(STUBBED) called. name={}, volume={}", name, volume);
205 205
206 IPC::ResponseBuilder rb{ctx, 2}; 206 IPC::ResponseBuilder rb{ctx, 2};
207 rb.Push(RESULT_SUCCESS); 207 rb.Push(RESULT_SUCCESS);
@@ -209,7 +209,6 @@ private:
209 209
210 void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { 210 void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
211 LOG_WARNING(Service_Audio, "(STUBBED) called"); 211 LOG_WARNING(Service_Audio, "(STUBBED) called");
212 IPC::RequestParser rp{ctx};
213 212
214 constexpr std::array<char, 12> audio_interface{{"AudioDevice"}}; 213 constexpr std::array<char, 12> audio_interface{{"AudioDevice"}};
215 ctx.WriteBuffer(audio_interface); 214 ctx.WriteBuffer(audio_interface);
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index c6da2df43..4c2b371c3 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -197,13 +197,16 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa
197 197
198ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_, 198ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
199 FileSys::Mode mode) const { 199 FileSys::Mode mode) const {
200 std::string path(FileUtil::SanitizePath(path_)); 200 const std::string path(FileUtil::SanitizePath(path_));
201 auto npath = path; 201 std::string_view npath = path;
202 while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\')) 202 while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
203 npath = npath.substr(1); 203 npath.remove_prefix(1);
204 }
205
204 auto file = backing->GetFileRelative(npath); 206 auto file = backing->GetFileRelative(npath);
205 if (file == nullptr) 207 if (file == nullptr) {
206 return FileSys::ERROR_PATH_NOT_FOUND; 208 return FileSys::ERROR_PATH_NOT_FOUND;
209 }
207 210
208 if (mode == FileSys::Mode::Append) { 211 if (mode == FileSys::Mode::Append) {
209 return MakeResult<FileSys::VirtualFile>( 212 return MakeResult<FileSys::VirtualFile>(
@@ -319,15 +322,15 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
319} 322}
320 323
321ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, 324ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
322 FileSys::SaveDataDescriptor save_struct) { 325 const FileSys::SaveDataDescriptor& descriptor) {
323 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", 326 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
324 static_cast<u8>(space), save_struct.DebugInfo()); 327 static_cast<u8>(space), descriptor.DebugInfo());
325 328
326 if (save_data_factory == nullptr) { 329 if (save_data_factory == nullptr) {
327 return FileSys::ERROR_ENTITY_NOT_FOUND; 330 return FileSys::ERROR_ENTITY_NOT_FOUND;
328 } 331 }
329 332
330 return save_data_factory->Open(space, save_struct); 333 return save_data_factory->Open(space, descriptor);
331} 334}
332 335
333ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) { 336ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6fd5e7b23..7cfc0d902 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -46,7 +46,7 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
46ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, 46ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
47 FileSys::ContentRecordType type); 47 FileSys::ContentRecordType type);
48ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, 48ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
49 FileSys::SaveDataDescriptor save_struct); 49 const FileSys::SaveDataDescriptor& descriptor);
50ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); 50ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
51ResultVal<FileSys::VirtualDir> OpenSDMC(); 51ResultVal<FileSys::VirtualDir> OpenSDMC();
52 52
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index f03fb629c..657baddb8 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -315,61 +315,53 @@ public:
315 void CreateFile(Kernel::HLERequestContext& ctx) { 315 void CreateFile(Kernel::HLERequestContext& ctx) {
316 IPC::RequestParser rp{ctx}; 316 IPC::RequestParser rp{ctx};
317 317
318 auto file_buffer = ctx.ReadBuffer(); 318 const auto file_buffer = ctx.ReadBuffer();
319 std::string name = Common::StringFromBuffer(file_buffer); 319 const std::string name = Common::StringFromBuffer(file_buffer);
320 320
321 u64 mode = rp.Pop<u64>(); 321 const u64 mode = rp.Pop<u64>();
322 u32 size = rp.Pop<u32>(); 322 const u32 size = rp.Pop<u32>();
323 323
324 LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); 324 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, mode, size);
325 325
326 IPC::ResponseBuilder rb{ctx, 2}; 326 IPC::ResponseBuilder rb{ctx, 2};
327 rb.Push(backend.CreateFile(name, size)); 327 rb.Push(backend.CreateFile(name, size));
328 } 328 }
329 329
330 void DeleteFile(Kernel::HLERequestContext& ctx) { 330 void DeleteFile(Kernel::HLERequestContext& ctx) {
331 IPC::RequestParser rp{ctx}; 331 const auto file_buffer = ctx.ReadBuffer();
332 332 const std::string name = Common::StringFromBuffer(file_buffer);
333 auto file_buffer = ctx.ReadBuffer();
334 std::string name = Common::StringFromBuffer(file_buffer);
335 333
336 LOG_DEBUG(Service_FS, "called file {}", name); 334 LOG_DEBUG(Service_FS, "called. file={}", name);
337 335
338 IPC::ResponseBuilder rb{ctx, 2}; 336 IPC::ResponseBuilder rb{ctx, 2};
339 rb.Push(backend.DeleteFile(name)); 337 rb.Push(backend.DeleteFile(name));
340 } 338 }
341 339
342 void CreateDirectory(Kernel::HLERequestContext& ctx) { 340 void CreateDirectory(Kernel::HLERequestContext& ctx) {
343 IPC::RequestParser rp{ctx}; 341 const auto file_buffer = ctx.ReadBuffer();
344 342 const std::string name = Common::StringFromBuffer(file_buffer);
345 auto file_buffer = ctx.ReadBuffer();
346 std::string name = Common::StringFromBuffer(file_buffer);
347 343
348 LOG_DEBUG(Service_FS, "called directory {}", name); 344 LOG_DEBUG(Service_FS, "called. directory={}", name);
349 345
350 IPC::ResponseBuilder rb{ctx, 2}; 346 IPC::ResponseBuilder rb{ctx, 2};
351 rb.Push(backend.CreateDirectory(name)); 347 rb.Push(backend.CreateDirectory(name));
352 } 348 }
353 349
354 void DeleteDirectory(Kernel::HLERequestContext& ctx) { 350 void DeleteDirectory(Kernel::HLERequestContext& ctx) {
355 const IPC::RequestParser rp{ctx};
356
357 const auto file_buffer = ctx.ReadBuffer(); 351 const auto file_buffer = ctx.ReadBuffer();
358 std::string name = Common::StringFromBuffer(file_buffer); 352 const std::string name = Common::StringFromBuffer(file_buffer);
359 353
360 LOG_DEBUG(Service_FS, "called directory {}", name); 354 LOG_DEBUG(Service_FS, "called. directory={}", name);
361 355
362 IPC::ResponseBuilder rb{ctx, 2}; 356 IPC::ResponseBuilder rb{ctx, 2};
363 rb.Push(backend.DeleteDirectory(name)); 357 rb.Push(backend.DeleteDirectory(name));
364 } 358 }
365 359
366 void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { 360 void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) {
367 const IPC::RequestParser rp{ctx};
368
369 const auto file_buffer = ctx.ReadBuffer(); 361 const auto file_buffer = ctx.ReadBuffer();
370 std::string name = Common::StringFromBuffer(file_buffer); 362 const std::string name = Common::StringFromBuffer(file_buffer);
371 363
372 LOG_DEBUG(Service_FS, "called directory {}", name); 364 LOG_DEBUG(Service_FS, "called. directory={}", name);
373 365
374 IPC::ResponseBuilder rb{ctx, 2}; 366 IPC::ResponseBuilder rb{ctx, 2};
375 rb.Push(backend.DeleteDirectoryRecursively(name)); 367 rb.Push(backend.DeleteDirectoryRecursively(name));
@@ -386,18 +378,16 @@ public:
386 } 378 }
387 379
388 void RenameFile(Kernel::HLERequestContext& ctx) { 380 void RenameFile(Kernel::HLERequestContext& ctx) {
389 IPC::RequestParser rp{ctx};
390
391 std::vector<u8> buffer; 381 std::vector<u8> buffer;
392 buffer.resize(ctx.BufferDescriptorX()[0].Size()); 382 buffer.resize(ctx.BufferDescriptorX()[0].Size());
393 Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size()); 383 Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size());
394 std::string src_name = Common::StringFromBuffer(buffer); 384 const std::string src_name = Common::StringFromBuffer(buffer);
395 385
396 buffer.resize(ctx.BufferDescriptorX()[1].Size()); 386 buffer.resize(ctx.BufferDescriptorX()[1].Size());
397 Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size()); 387 Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size());
398 std::string dst_name = Common::StringFromBuffer(buffer); 388 const std::string dst_name = Common::StringFromBuffer(buffer);
399 389
400 LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); 390 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
401 391
402 IPC::ResponseBuilder rb{ctx, 2}; 392 IPC::ResponseBuilder rb{ctx, 2};
403 rb.Push(backend.RenameFile(src_name, dst_name)); 393 rb.Push(backend.RenameFile(src_name, dst_name));
@@ -406,12 +396,12 @@ public:
406 void OpenFile(Kernel::HLERequestContext& ctx) { 396 void OpenFile(Kernel::HLERequestContext& ctx) {
407 IPC::RequestParser rp{ctx}; 397 IPC::RequestParser rp{ctx};
408 398
409 auto file_buffer = ctx.ReadBuffer(); 399 const auto file_buffer = ctx.ReadBuffer();
410 std::string name = Common::StringFromBuffer(file_buffer); 400 const std::string name = Common::StringFromBuffer(file_buffer);
411 401
412 auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); 402 const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
413 403
414 LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); 404 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, static_cast<u32>(mode));
415 405
416 auto result = backend.OpenFile(name, mode); 406 auto result = backend.OpenFile(name, mode);
417 if (result.Failed()) { 407 if (result.Failed()) {
@@ -430,13 +420,13 @@ public:
430 void OpenDirectory(Kernel::HLERequestContext& ctx) { 420 void OpenDirectory(Kernel::HLERequestContext& ctx) {
431 IPC::RequestParser rp{ctx}; 421 IPC::RequestParser rp{ctx};
432 422
433 auto file_buffer = ctx.ReadBuffer(); 423 const auto file_buffer = ctx.ReadBuffer();
434 std::string name = Common::StringFromBuffer(file_buffer); 424 const std::string name = Common::StringFromBuffer(file_buffer);
435 425
436 // TODO(Subv): Implement this filter. 426 // TODO(Subv): Implement this filter.
437 u32 filter_flags = rp.Pop<u32>(); 427 const u32 filter_flags = rp.Pop<u32>();
438 428
439 LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); 429 LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
440 430
441 auto result = backend.OpenDirectory(name); 431 auto result = backend.OpenDirectory(name);
442 if (result.Failed()) { 432 if (result.Failed()) {
@@ -453,12 +443,10 @@ public:
453 } 443 }
454 444
455 void GetEntryType(Kernel::HLERequestContext& ctx) { 445 void GetEntryType(Kernel::HLERequestContext& ctx) {
456 IPC::RequestParser rp{ctx}; 446 const auto file_buffer = ctx.ReadBuffer();
457 447 const std::string name = Common::StringFromBuffer(file_buffer);
458 auto file_buffer = ctx.ReadBuffer();
459 std::string name = Common::StringFromBuffer(file_buffer);
460 448
461 LOG_DEBUG(Service_FS, "called file {}", name); 449 LOG_DEBUG(Service_FS, "called. file={}", name);
462 450
463 auto result = backend.GetEntryType(name); 451 auto result = backend.GetEntryType(name);
464 if (result.Failed()) { 452 if (result.Failed()) {
@@ -616,7 +604,9 @@ private:
616 u64_le save_id; 604 u64_le save_id;
617 u64_le title_id; 605 u64_le title_id;
618 u64_le save_image_size; 606 u64_le save_image_size;
619 INSERT_PADDING_BYTES(0x28); 607 u16_le index;
608 FileSys::SaveDataRank rank;
609 INSERT_PADDING_BYTES(0x25);
620 }; 610 };
621 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); 611 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
622 612
@@ -779,16 +769,17 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
779} 769}
780 770
781void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) { 771void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
782 IPC::RequestParser rp{ctx}; 772 LOG_INFO(Service_FS, "called.");
783
784 auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
785 auto unk = rp.Pop<u32>();
786 LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
787 773
788 auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); 774 struct Parameters {
775 FileSys::SaveDataSpaceId save_data_space_id;
776 FileSys::SaveDataDescriptor descriptor;
777 };
789 778
790 auto dir = OpenSaveData(space_id, save_struct); 779 IPC::RequestParser rp{ctx};
780 const auto parameters = rp.PopRaw<Parameters>();
791 781
782 auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
792 if (dir.Failed()) { 783 if (dir.Failed()) {
793 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 784 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
794 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 785 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index ace71169f..12f3ef825 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -18,7 +18,7 @@ class nvmap;
18class nvdisp_disp0 final : public nvdevice { 18class nvdisp_disp0 final : public nvdevice {
19public: 19public:
20 explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev); 20 explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev);
21 ~nvdisp_disp0(); 21 ~nvdisp_disp0() override;
22 22
23 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 23 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
24 24
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index fe311b069..5b4889910 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -17,7 +17,7 @@ namespace Service::Nvidia {
17class NVDRV final : public ServiceFramework<NVDRV> { 17class NVDRV final : public ServiceFramework<NVDRV> {
18public: 18public:
19 NVDRV(std::shared_ptr<Module> nvdrv, const char* name); 19 NVDRV(std::shared_ptr<Module> nvdrv, const char* name);
20 ~NVDRV(); 20 ~NVDRV() override;
21 21
22private: 22private:
23 void Open(Kernel::HLERequestContext& ctx); 23 void Open(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h
index 5a4dfc1f9..6eafb1346 100644
--- a/src/core/hle/service/nvdrv/nvmemp.h
+++ b/src/core/hle/service/nvdrv/nvmemp.h
@@ -11,7 +11,7 @@ namespace Service::Nvidia {
11class NVMEMP final : public ServiceFramework<NVMEMP> { 11class NVMEMP final : public ServiceFramework<NVMEMP> {
12public: 12public:
13 NVMEMP(); 13 NVMEMP();
14 ~NVMEMP(); 14 ~NVMEMP() override;
15 15
16private: 16private:
17 void Cmd0(Kernel::HLERequestContext& ctx); 17 void Cmd0(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 830790269..abbfe5524 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -90,7 +90,7 @@ private:
90 Kernel::HLERequestContext& ctx); 90 Kernel::HLERequestContext& ctx);
91 91
92 ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); 92 ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker);
93 ~ServiceFrameworkBase(); 93 ~ServiceFrameworkBase() override;
94 94
95 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); 95 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
96 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); 96 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h
index 583036eac..a0677e815 100644
--- a/src/core/hle/service/set/set_cal.h
+++ b/src/core/hle/service/set/set_cal.h
@@ -11,7 +11,7 @@ namespace Service::Set {
11class SET_CAL final : public ServiceFramework<SET_CAL> { 11class SET_CAL final : public ServiceFramework<SET_CAL> {
12public: 12public:
13 explicit SET_CAL(); 13 explicit SET_CAL();
14 ~SET_CAL(); 14 ~SET_CAL() override;
15}; 15};
16 16
17} // namespace Service::Set 17} // namespace Service::Set
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 13ab1d31e..852e71e4b 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -8,12 +8,20 @@
8namespace Service::Sockets { 8namespace Service::Sockets {
9 9
10void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { 10void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) {
11 struct Parameters {
12 u8 use_nsd_resolve;
13 u32 unknown;
14 u64 process_id;
15 };
16
11 IPC::RequestParser rp{ctx}; 17 IPC::RequestParser rp{ctx};
18 const auto parameters = rp.PopRaw<Parameters>();
12 19
13 LOG_WARNING(Service, "(STUBBED) called"); 20 LOG_WARNING(Service,
21 "(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}",
22 parameters.use_nsd_resolve, parameters.unknown, parameters.process_id);
14 23
15 IPC::ResponseBuilder rb{ctx, 2}; 24 IPC::ResponseBuilder rb{ctx, 2};
16
17 rb.Push(RESULT_SUCCESS); 25 rb.Push(RESULT_SUCCESS);
18} 26}
19 27
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 8db0c2f13..e724d4ab8 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -26,9 +26,7 @@ Module::Interface::~Interface() = default;
26void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { 26void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
27 LOG_DEBUG(Service_SPL, "called"); 27 LOG_DEBUG(Service_SPL, "called");
28 28
29 IPC::RequestParser rp{ctx}; 29 const std::size_t size = ctx.GetWriteBufferSize();
30
31 std::size_t size = ctx.GetWriteBufferSize();
32 30
33 std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max()); 31 std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max());
34 std::vector<u8> data(size); 32 std::vector<u8> data(size);
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index af40a1815..f7f87a958 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -64,13 +64,19 @@ public:
64 }; 64 };
65 RegisterHandlers(functions); 65 RegisterHandlers(functions);
66 } 66 }
67 ~ISslContext() = default;
68 67
69private: 68private:
70 void SetOption(Kernel::HLERequestContext& ctx) { 69 void SetOption(Kernel::HLERequestContext& ctx) {
71 LOG_WARNING(Service_SSL, "(STUBBED) called"); 70 struct Parameters {
71 u8 enable;
72 u32 option;
73 };
72 74
73 IPC::RequestParser rp{ctx}; 75 IPC::RequestParser rp{ctx};
76 const auto parameters = rp.PopRaw<Parameters>();
77
78 LOG_WARNING(Service_SSL, "(STUBBED) called. enable={}, option={}", parameters.enable,
79 parameters.option);
74 80
75 IPC::ResponseBuilder rb{ctx, 2}; 81 IPC::ResponseBuilder rb{ctx, 2};
76 rb.Push(RESULT_SUCCESS); 82 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 566cd6006..4e17249a9 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -498,7 +498,6 @@ public:
498 }; 498 };
499 RegisterHandlers(functions); 499 RegisterHandlers(functions);
500 } 500 }
501 ~IHOSBinderDriver() = default;
502 501
503private: 502private:
504 enum class TransactionId { 503 enum class TransactionId {
@@ -692,7 +691,6 @@ public:
692 }; 691 };
693 RegisterHandlers(functions); 692 RegisterHandlers(functions);
694 } 693 }
695 ~ISystemDisplayService() = default;
696 694
697private: 695private:
698 void SetLayerZ(Kernel::HLERequestContext& ctx) { 696 void SetLayerZ(Kernel::HLERequestContext& ctx) {
@@ -818,7 +816,6 @@ public:
818 }; 816 };
819 RegisterHandlers(functions); 817 RegisterHandlers(functions);
820 } 818 }
821 ~IManagerDisplayService() = default;
822 819
823private: 820private:
824 void CloseDisplay(Kernel::HLERequestContext& ctx) { 821 void CloseDisplay(Kernel::HLERequestContext& ctx) {
@@ -884,7 +881,6 @@ private:
884class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { 881class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
885public: 882public:
886 explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 883 explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
887 ~IApplicationDisplayService() = default;
888 884
889private: 885private:
890 enum class ConvertedScaleMode : u64 { 886 enum class ConvertedScaleMode : u64 {
@@ -1037,7 +1033,6 @@ private:
1037 void ListDisplays(Kernel::HLERequestContext& ctx) { 1033 void ListDisplays(Kernel::HLERequestContext& ctx) {
1038 LOG_WARNING(Service_VI, "(STUBBED) called"); 1034 LOG_WARNING(Service_VI, "(STUBBED) called");
1039 1035
1040 IPC::RequestParser rp{ctx};
1041 DisplayInfo display_info; 1036 DisplayInfo display_info;
1042 display_info.width *= static_cast<u64>(Settings::values.resolution_factor); 1037 display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
1043 display_info.height *= static_cast<u64>(Settings::values.resolution_factor); 1038 display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index babc7e646..ffe2eea8a 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -4,11 +4,12 @@
4 4
5#include <cinttypes> 5#include <cinttypes>
6#include <vector> 6#include <vector>
7#include <lz4.h> 7
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/hex_util.h" 10#include "common/hex_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/lz4_compression.h"
12#include "common/swap.h" 13#include "common/swap.h"
13#include "core/core.h" 14#include "core/core.h"
14#include "core/file_sys/patch_manager.h" 15#include "core/file_sys/patch_manager.h"
@@ -35,15 +36,11 @@ static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size.");
35 36
36std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data, 37std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
37 const NSOSegmentHeader& header) { 38 const NSOSegmentHeader& header) {
38 std::vector<u8> uncompressed_data(header.size); 39 const std::vector<u8> uncompressed_data =
39 const int bytes_uncompressed = 40 Common::Compression::DecompressDataLZ4(compressed_data, header.size);
40 LZ4_decompress_safe(reinterpret_cast<const char*>(compressed_data.data()), 41
41 reinterpret_cast<char*>(uncompressed_data.data()), 42 ASSERT_MSG(uncompressed_data.size() == static_cast<int>(header.size), "{} != {}", header.size,
42 static_cast<int>(compressed_data.size()), header.size); 43 uncompressed_data.size());
43
44 ASSERT_MSG(bytes_uncompressed == static_cast<int>(header.size) &&
45 bytes_uncompressed == static_cast<int>(uncompressed_data.size()),
46 "{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size());
47 44
48 return uncompressed_data; 45 return uncompressed_data;
49} 46}
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index d6995b61e..436f7387c 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -22,7 +22,7 @@ class AppLoader_NCA;
22class AppLoader_XCI final : public AppLoader { 22class AppLoader_XCI final : public AppLoader {
23public: 23public:
24 explicit AppLoader_XCI(FileSys::VirtualFile file); 24 explicit AppLoader_XCI(FileSys::VirtualFile file);
25 ~AppLoader_XCI(); 25 ~AppLoader_XCI() override;
26 26
27 /** 27 /**
28 * Returns the type of the file 28 * Returns the type of the file
diff --git a/src/core/memory.h b/src/core/memory.h
index 1d38cdca8..9153e4954 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -28,16 +28,6 @@ constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
28 28
29/// Virtual user-space memory regions 29/// Virtual user-space memory regions
30enum : VAddr { 30enum : VAddr {
31 /// Read-only page containing kernel and system configuration values.
32 CONFIG_MEMORY_VADDR = 0x1FF80000,
33 CONFIG_MEMORY_SIZE = 0x00001000,
34 CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE,
35
36 /// Usually read-only page containing mostly values read from hardware.
37 SHARED_PAGE_VADDR = 0x1FF81000,
38 SHARED_PAGE_SIZE = 0x00001000,
39 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
40
41 /// TLS (Thread-Local Storage) related. 31 /// TLS (Thread-Local Storage) related.
42 TLS_ENTRY_SIZE = 0x200, 32 TLS_ENTRY_SIZE = 0x200,
43 33
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 44c761d3e..242a0d1cd 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -139,4 +139,4 @@ endif()
139create_target_directory_groups(video_core) 139create_target_directory_groups(video_core)
140 140
141target_link_libraries(video_core PUBLIC common core) 141target_link_libraries(video_core PUBLIC common core)
142target_link_libraries(video_core PRIVATE glad lz4_static) 142target_link_libraries(video_core PRIVATE glad)
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 03b7ee5d8..55966eef1 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -6,12 +6,13 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "common/math_util.h" 7#include "common/math_util.h"
8#include "video_core/engines/fermi_2d.h" 8#include "video_core/engines/fermi_2d.h"
9#include "video_core/memory_manager.h"
9#include "video_core/rasterizer_interface.h" 10#include "video_core/rasterizer_interface.h"
10 11
11namespace Tegra::Engines { 12namespace Tegra::Engines {
12 13
13Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 14Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
14 : memory_manager(memory_manager), rasterizer{rasterizer} {} 15 : rasterizer{rasterizer}, memory_manager{memory_manager} {}
15 16
16void Fermi2D::CallMethod(const GPU::MethodCall& method_call) { 17void Fermi2D::CallMethod(const GPU::MethodCall& method_call) {
17 ASSERT_MSG(method_call.method < Regs::NUM_REGS, 18 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 80523e320..2e51b7f13 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -10,7 +10,10 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/gpu.h" 12#include "video_core/gpu.h"
13#include "video_core/memory_manager.h" 13
14namespace Tegra {
15class MemoryManager;
16}
14 17
15namespace VideoCore { 18namespace VideoCore {
16class RasterizerInterface; 19class RasterizerInterface;
@@ -115,10 +118,9 @@ public:
115 }; 118 };
116 } regs{}; 119 } regs{};
117 120
118 MemoryManager& memory_manager;
119
120private: 121private:
121 VideoCore::RasterizerInterface& rasterizer; 122 VideoCore::RasterizerInterface& rasterizer;
123 MemoryManager& memory_manager;
122 124
123 /// Performs the copy from the source surface to the destination surface as configured in the 125 /// Performs the copy from the source surface to the destination surface as configured in the
124 /// registers. 126 /// registers.
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index 6575afd0f..fb6cdf432 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -9,7 +9,10 @@
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/gpu.h" 11#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 12
13namespace Tegra {
14class MemoryManager;
15}
13 16
14namespace Tegra::Engines { 17namespace Tegra::Engines {
15 18
@@ -40,10 +43,11 @@ public:
40 static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), 43 static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
41 "KeplerCompute Regs has wrong size"); 44 "KeplerCompute Regs has wrong size");
42 45
43 MemoryManager& memory_manager;
44
45 /// Write the value to the register identified by method. 46 /// Write the value to the register identified by method.
46 void CallMethod(const GPU::MethodCall& method_call); 47 void CallMethod(const GPU::MethodCall& method_call);
48
49private:
50 MemoryManager& memory_manager;
47}; 51};
48 52
49#define ASSERT_REG_POSITION(field_name, position) \ 53#define ASSERT_REG_POSITION(field_name, position) \
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
index e259bf46b..cd51a31d7 100644
--- a/src/video_core/engines/kepler_memory.cpp
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -5,9 +5,9 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/memory.h"
9#include "video_core/engines/kepler_memory.h" 8#include "video_core/engines/kepler_memory.h"
10#include "video_core/engines/maxwell_3d.h" 9#include "video_core/engines/maxwell_3d.h"
10#include "video_core/memory_manager.h"
11#include "video_core/rasterizer_interface.h" 11#include "video_core/rasterizer_interface.h"
12#include "video_core/renderer_base.h" 12#include "video_core/renderer_base.h"
13 13
@@ -15,7 +15,7 @@ namespace Tegra::Engines {
15 15
16KeplerMemory::KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 16KeplerMemory::KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
17 MemoryManager& memory_manager) 17 MemoryManager& memory_manager)
18 : system{system}, memory_manager(memory_manager), rasterizer{rasterizer} {} 18 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager} {}
19 19
20KeplerMemory::~KeplerMemory() = default; 20KeplerMemory::~KeplerMemory() = default;
21 21
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index 9181e9d80..78b6c3e45 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -10,12 +10,15 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/gpu.h" 12#include "video_core/gpu.h"
13#include "video_core/memory_manager.h"
14 13
15namespace Core { 14namespace Core {
16class System; 15class System;
17} 16}
18 17
18namespace Tegra {
19class MemoryManager;
20}
21
19namespace VideoCore { 22namespace VideoCore {
20class RasterizerInterface; 23class RasterizerInterface;
21} 24}
@@ -82,8 +85,8 @@ public:
82 85
83private: 86private:
84 Core::System& system; 87 Core::System& system;
85 MemoryManager& memory_manager;
86 VideoCore::RasterizerInterface& rasterizer; 88 VideoCore::RasterizerInterface& rasterizer;
89 MemoryManager& memory_manager;
87 90
88 void ProcessData(u32 data); 91 void ProcessData(u32 data);
89}; 92};
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index defcfbd3f..8194a4b4a 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -7,11 +7,10 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "core/memory.h"
11#include "video_core/debug_utils/debug_utils.h" 10#include "video_core/debug_utils/debug_utils.h"
12#include "video_core/engines/maxwell_3d.h" 11#include "video_core/engines/maxwell_3d.h"
12#include "video_core/memory_manager.h"
13#include "video_core/rasterizer_interface.h" 13#include "video_core/rasterizer_interface.h"
14#include "video_core/renderer_base.h"
15#include "video_core/textures/texture.h" 14#include "video_core/textures/texture.h"
16 15
17namespace Tegra::Engines { 16namespace Tegra::Engines {
@@ -21,8 +20,8 @@ constexpr u32 MacroRegistersStart = 0xE00;
21 20
22Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 21Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
23 MemoryManager& memory_manager) 22 MemoryManager& memory_manager)
24 : memory_manager(memory_manager), system{system}, rasterizer{rasterizer}, 23 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, macro_interpreter{
25 macro_interpreter(*this) { 24 *this} {
26 InitializeRegisterDefaults(); 25 InitializeRegisterDefaults();
27} 26}
28 27
@@ -250,6 +249,10 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
250 ProcessQueryGet(); 249 ProcessQueryGet();
251 break; 250 break;
252 } 251 }
252 case MAXWELL3D_REG_INDEX(sync_info): {
253 ProcessSyncPoint();
254 break;
255 }
253 default: 256 default:
254 break; 257 break;
255 } 258 }
@@ -327,6 +330,14 @@ void Maxwell3D::ProcessQueryGet() {
327 } 330 }
328} 331}
329 332
333void Maxwell3D::ProcessSyncPoint() {
334 const u32 sync_point = regs.sync_info.sync_point.Value();
335 const u32 increment = regs.sync_info.increment.Value();
336 const u32 cache_flush = regs.sync_info.unknown.Value();
337 UNIMPLEMENTED_MSG("Syncpoint Set {}, increment: {}, unk: {}", sync_point, increment,
338 cache_flush);
339}
340
330void Maxwell3D::DrawArrays() { 341void Maxwell3D::DrawArrays() {
331 LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()), 342 LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
332 regs.vertex_buffer.count); 343 regs.vertex_buffer.count);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 7fbf1026e..321af3297 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -16,13 +16,16 @@
16#include "common/math_util.h" 16#include "common/math_util.h"
17#include "video_core/gpu.h" 17#include "video_core/gpu.h"
18#include "video_core/macro_interpreter.h" 18#include "video_core/macro_interpreter.h"
19#include "video_core/memory_manager.h"
20#include "video_core/textures/texture.h" 19#include "video_core/textures/texture.h"
21 20
22namespace Core { 21namespace Core {
23class System; 22class System;
24} 23}
25 24
25namespace Tegra {
26class MemoryManager;
27}
28
26namespace VideoCore { 29namespace VideoCore {
27class RasterizerInterface; 30class RasterizerInterface;
28} 31}
@@ -576,7 +579,17 @@ public:
576 u32 bind; 579 u32 bind;
577 } macros; 580 } macros;
578 581
579 INSERT_PADDING_WORDS(0x188); 582 INSERT_PADDING_WORDS(0x69);
583
584 struct {
585 union {
586 BitField<0, 16, u32> sync_point;
587 BitField<16, 1, u32> unknown;
588 BitField<20, 1, u32> increment;
589 };
590 } sync_info;
591
592 INSERT_PADDING_WORDS(0x11E);
580 593
581 u32 tfb_enabled; 594 u32 tfb_enabled;
582 595
@@ -1093,7 +1106,6 @@ public:
1093 }; 1106 };
1094 1107
1095 State state{}; 1108 State state{};
1096 MemoryManager& memory_manager;
1097 1109
1098 struct DirtyFlags { 1110 struct DirtyFlags {
1099 std::bitset<8> color_buffer{0xFF}; 1111 std::bitset<8> color_buffer{0xFF};
@@ -1141,6 +1153,8 @@ private:
1141 1153
1142 VideoCore::RasterizerInterface& rasterizer; 1154 VideoCore::RasterizerInterface& rasterizer;
1143 1155
1156 MemoryManager& memory_manager;
1157
1144 /// Start offsets of each macro in macro_memory 1158 /// Start offsets of each macro in macro_memory
1145 std::unordered_map<u32, u32> macro_offsets; 1159 std::unordered_map<u32, u32> macro_offsets;
1146 1160
@@ -1180,6 +1194,9 @@ private:
1180 /// Handles a write to the QUERY_GET register. 1194 /// Handles a write to the QUERY_GET register.
1181 void ProcessQueryGet(); 1195 void ProcessQueryGet();
1182 1196
1197 /// Handles writes to syncing register.
1198 void ProcessSyncPoint();
1199
1183 /// Handles a write to the CB_DATA[i] register. 1200 /// Handles a write to the CB_DATA[i] register.
1184 void ProcessCBData(u32 value); 1201 void ProcessCBData(u32 value);
1185 1202
@@ -1195,6 +1212,7 @@ private:
1195 "Field " #field_name " has invalid position") 1212 "Field " #field_name " has invalid position")
1196 1213
1197ASSERT_REG_POSITION(macros, 0x45); 1214ASSERT_REG_POSITION(macros, 0x45);
1215ASSERT_REG_POSITION(sync_info, 0xB2);
1198ASSERT_REG_POSITION(tfb_enabled, 0x1D1); 1216ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
1199ASSERT_REG_POSITION(rt, 0x200); 1217ASSERT_REG_POSITION(rt, 0x200);
1200ASSERT_REG_POSITION(viewport_transform, 0x280); 1218ASSERT_REG_POSITION(viewport_transform, 0x280);
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 5cca5c29a..2426d0067 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -5,9 +5,9 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/memory.h"
9#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
10#include "video_core/engines/maxwell_dma.h" 9#include "video_core/engines/maxwell_dma.h"
10#include "video_core/memory_manager.h"
11#include "video_core/rasterizer_interface.h" 11#include "video_core/rasterizer_interface.h"
12#include "video_core/renderer_base.h" 12#include "video_core/renderer_base.h"
13#include "video_core/textures/decoders.h" 13#include "video_core/textures/decoders.h"
@@ -16,7 +16,7 @@ namespace Tegra::Engines {
16 16
17MaxwellDMA::MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 17MaxwellDMA::MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
18 MemoryManager& memory_manager) 18 MemoryManager& memory_manager)
19 : memory_manager(memory_manager), system{system}, rasterizer{rasterizer} {} 19 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager} {}
20 20
21void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) { 21void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) {
22 ASSERT_MSG(method_call.method < Regs::NUM_REGS, 22 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 34c369320..c6b649842 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -10,12 +10,15 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/gpu.h" 12#include "video_core/gpu.h"
13#include "video_core/memory_manager.h"
14 13
15namespace Core { 14namespace Core {
16class System; 15class System;
17} 16}
18 17
18namespace Tegra {
19class MemoryManager;
20}
21
19namespace VideoCore { 22namespace VideoCore {
20class RasterizerInterface; 23class RasterizerInterface;
21} 24}
@@ -139,13 +142,13 @@ public:
139 }; 142 };
140 } regs{}; 143 } regs{};
141 144
142 MemoryManager& memory_manager;
143
144private: 145private:
145 Core::System& system; 146 Core::System& system;
146 147
147 VideoCore::RasterizerInterface& rasterizer; 148 VideoCore::RasterizerInterface& rasterizer;
148 149
150 MemoryManager& memory_manager;
151
149 /// Performs the copy from the source buffer to the destination buffer as configured in the 152 /// Performs the copy from the source buffer to the destination buffer as configured in the
150 /// registers. 153 /// registers.
151 void HandleCopy(); 154 void HandleCopy();
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 30b29e14d..4461083ff 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -31,7 +31,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
31 31
32GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer) : renderer{renderer} { 32GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer) : renderer{renderer} {
33 auto& rasterizer{renderer.Rasterizer()}; 33 auto& rasterizer{renderer.Rasterizer()};
34 memory_manager = std::make_unique<Tegra::MemoryManager>(); 34 memory_manager = std::make_unique<Tegra::MemoryManager>(rasterizer);
35 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); 35 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
36 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); 36 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
37 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); 37 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp
index 8b355cf7b..db507cf04 100644
--- a/src/video_core/gpu_asynch.cpp
+++ b/src/video_core/gpu_asynch.cpp
@@ -9,7 +9,7 @@
9namespace VideoCommon { 9namespace VideoCommon {
10 10
11GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer) 11GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer)
12 : Tegra::GPU(system, renderer), gpu_thread{renderer, *dma_pusher} {} 12 : Tegra::GPU(system, renderer), gpu_thread{system, renderer, *dma_pusher} {}
13 13
14GPUAsynch::~GPUAsynch() = default; 14GPUAsynch::~GPUAsynch() = default;
15 15
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index c5dc199c5..cc56cf467 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -4,6 +4,9 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "core/core.h"
8#include "core/core_timing.h"
9#include "core/core_timing_util.h"
7#include "core/frontend/scope_acquire_window_context.h" 10#include "core/frontend/scope_acquire_window_context.h"
8#include "video_core/dma_pusher.h" 11#include "video_core/dma_pusher.h"
9#include "video_core/gpu.h" 12#include "video_core/gpu.h"
@@ -36,7 +39,6 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
36 dma_pusher.Push(std::move(submit_list->entries)); 39 dma_pusher.Push(std::move(submit_list->entries));
37 dma_pusher.DispatchCalls(); 40 dma_pusher.DispatchCalls();
38 } else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) { 41 } else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) {
39 state.DecrementFramesCounter();
40 renderer.SwapBuffers(std::move(data->framebuffer)); 42 renderer.SwapBuffers(std::move(data->framebuffer));
41 } else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) { 43 } else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) {
42 renderer.Rasterizer().FlushRegion(data->addr, data->size); 44 renderer.Rasterizer().FlushRegion(data->addr, data->size);
@@ -47,13 +49,18 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
47 } else { 49 } else {
48 UNREACHABLE(); 50 UNREACHABLE();
49 } 51 }
52 state.signaled_fence = next.fence;
53 state.TrySynchronize();
50 } 54 }
51 } 55 }
52} 56}
53 57
54ThreadManager::ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) 58ThreadManager::ThreadManager(Core::System& system, VideoCore::RendererBase& renderer,
55 : renderer{renderer}, thread{RunThread, std::ref(renderer), std::ref(dma_pusher), 59 Tegra::DmaPusher& dma_pusher)
56 std::ref(state)} {} 60 : system{system}, thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)} {
61 synchronization_event = system.CoreTiming().RegisterEvent(
62 "GPUThreadSynch", [this](u64 fence, s64) { state.WaitForSynchronization(fence); });
63}
57 64
58ThreadManager::~ThreadManager() { 65ThreadManager::~ThreadManager() {
59 // Notify GPU thread that a shutdown is pending 66 // Notify GPU thread that a shutdown is pending
@@ -62,14 +69,14 @@ ThreadManager::~ThreadManager() {
62} 69}
63 70
64void ThreadManager::SubmitList(Tegra::CommandList&& entries) { 71void ThreadManager::SubmitList(Tegra::CommandList&& entries) {
65 PushCommand(SubmitListCommand(std::move(entries))); 72 const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))};
73 const s64 synchronization_ticks{Core::Timing::usToCycles(9000)};
74 system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence);
66} 75}
67 76
68void ThreadManager::SwapBuffers( 77void ThreadManager::SwapBuffers(
69 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { 78 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) {
70 state.IncrementFramesCounter();
71 PushCommand(SwapBuffersCommand(std::move(framebuffer))); 79 PushCommand(SwapBuffersCommand(std::move(framebuffer)));
72 state.WaitForFrames();
73} 80}
74 81
75void ThreadManager::FlushRegion(CacheAddr addr, u64 size) { 82void ThreadManager::FlushRegion(CacheAddr addr, u64 size) {
@@ -79,7 +86,7 @@ void ThreadManager::FlushRegion(CacheAddr addr, u64 size) {
79void ThreadManager::InvalidateRegion(CacheAddr addr, u64 size) { 86void ThreadManager::InvalidateRegion(CacheAddr addr, u64 size) {
80 if (state.queue.Empty()) { 87 if (state.queue.Empty()) {
81 // It's quicker to invalidate a single region on the CPU if the queue is already empty 88 // It's quicker to invalidate a single region on the CPU if the queue is already empty
82 renderer.Rasterizer().InvalidateRegion(addr, size); 89 system.Renderer().Rasterizer().InvalidateRegion(addr, size);
83 } else { 90 } else {
84 PushCommand(InvalidateRegionCommand(addr, size)); 91 PushCommand(InvalidateRegionCommand(addr, size));
85 } 92 }
@@ -90,9 +97,25 @@ void ThreadManager::FlushAndInvalidateRegion(CacheAddr addr, u64 size) {
90 InvalidateRegion(addr, size); 97 InvalidateRegion(addr, size);
91} 98}
92 99
93void ThreadManager::PushCommand(CommandData&& command_data) { 100u64 ThreadManager::PushCommand(CommandData&& command_data) {
94 state.queue.Push(CommandDataContainer(std::move(command_data))); 101 const u64 fence{++state.last_fence};
102 state.queue.Push(CommandDataContainer(std::move(command_data), fence));
95 state.SignalCommands(); 103 state.SignalCommands();
104 return fence;
105}
106
107MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
108void SynchState::WaitForSynchronization(u64 fence) {
109 if (signaled_fence >= fence) {
110 return;
111 }
112
113 // Wait for the GPU to be idle (all commands to be executed)
114 {
115 MICROPROFILE_SCOPE(GPU_wait);
116 std::unique_lock<std::mutex> lock{synchronization_mutex};
117 synchronization_condition.wait(lock, [this, fence] { return signaled_fence >= fence; });
118 }
96} 119}
97 120
98} // namespace VideoCommon::GPUThread 121} // namespace VideoCommon::GPUThread
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 70acb2e79..62bcea5bb 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -19,9 +19,12 @@ struct FramebufferConfig;
19class DmaPusher; 19class DmaPusher;
20} // namespace Tegra 20} // namespace Tegra
21 21
22namespace VideoCore { 22namespace Core {
23class RendererBase; 23class System;
24} // namespace VideoCore 24namespace Timing {
25struct EventType;
26} // namespace Timing
27} // namespace Core
25 28
26namespace VideoCommon::GPUThread { 29namespace VideoCommon::GPUThread {
27 30
@@ -75,63 +78,47 @@ using CommandData =
75struct CommandDataContainer { 78struct CommandDataContainer {
76 CommandDataContainer() = default; 79 CommandDataContainer() = default;
77 80
78 CommandDataContainer(CommandData&& data) : data{std::move(data)} {} 81 CommandDataContainer(CommandData&& data, u64 next_fence)
82 : data{std::move(data)}, fence{next_fence} {}
79 83
80 CommandDataContainer& operator=(const CommandDataContainer& t) { 84 CommandDataContainer& operator=(const CommandDataContainer& t) {
81 data = std::move(t.data); 85 data = std::move(t.data);
86 fence = t.fence;
82 return *this; 87 return *this;
83 } 88 }
84 89
85 CommandData data; 90 CommandData data;
91 u64 fence{};
86}; 92};
87 93
88/// Struct used to synchronize the GPU thread 94/// Struct used to synchronize the GPU thread
89struct SynchState final { 95struct SynchState final {
90 std::atomic_bool is_running{true}; 96 std::atomic_bool is_running{true};
91 std::atomic_int queued_frame_count{}; 97 std::atomic_int queued_frame_count{};
92 std::mutex frames_mutex; 98 std::mutex synchronization_mutex;
93 std::mutex commands_mutex; 99 std::mutex commands_mutex;
94 std::condition_variable commands_condition; 100 std::condition_variable commands_condition;
95 std::condition_variable frames_condition; 101 std::condition_variable synchronization_condition;
96 102
97 void IncrementFramesCounter() { 103 /// Returns true if the gap in GPU commands is small enough that we can consider the CPU and GPU
98 std::lock_guard lock{frames_mutex}; 104 /// synchronized. This is entirely empirical.
99 ++queued_frame_count; 105 bool IsSynchronized() const {
106 constexpr std::size_t max_queue_gap{5};
107 return queue.Size() <= max_queue_gap;
100 } 108 }
101 109
102 void DecrementFramesCounter() { 110 void TrySynchronize() {
103 { 111 if (IsSynchronized()) {
104 std::lock_guard lock{frames_mutex}; 112 std::lock_guard<std::mutex> lock{synchronization_mutex};
105 --queued_frame_count; 113 synchronization_condition.notify_one();
106
107 if (queued_frame_count) {
108 return;
109 }
110 } 114 }
111 frames_condition.notify_one();
112 } 115 }
113 116
114 void WaitForFrames() { 117 void WaitForSynchronization(u64 fence);
115 {
116 std::lock_guard lock{frames_mutex};
117 if (!queued_frame_count) {
118 return;
119 }
120 }
121
122 // Wait for the GPU to be idle (all commands to be executed)
123 {
124 std::unique_lock lock{frames_mutex};
125 frames_condition.wait(lock, [this] { return !queued_frame_count; });
126 }
127 }
128 118
129 void SignalCommands() { 119 void SignalCommands() {
130 { 120 if (queue.Empty()) {
131 std::unique_lock lock{commands_mutex}; 121 return;
132 if (queue.Empty()) {
133 return;
134 }
135 } 122 }
136 123
137 commands_condition.notify_one(); 124 commands_condition.notify_one();
@@ -144,12 +131,15 @@ struct SynchState final {
144 131
145 using CommandQueue = Common::SPSCQueue<CommandDataContainer>; 132 using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
146 CommandQueue queue; 133 CommandQueue queue;
134 u64 last_fence{};
135 std::atomic<u64> signaled_fence{};
147}; 136};
148 137
149/// Class used to manage the GPU thread 138/// Class used to manage the GPU thread
150class ThreadManager final { 139class ThreadManager final {
151public: 140public:
152 explicit ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher); 141 explicit ThreadManager(Core::System& system, VideoCore::RendererBase& renderer,
142 Tegra::DmaPusher& dma_pusher);
153 ~ThreadManager(); 143 ~ThreadManager();
154 144
155 /// Push GPU command entries to be processed 145 /// Push GPU command entries to be processed
@@ -170,11 +160,12 @@ public:
170 160
171private: 161private:
172 /// Pushes a command to be executed by the GPU thread 162 /// Pushes a command to be executed by the GPU thread
173 void PushCommand(CommandData&& command_data); 163 u64 PushCommand(CommandData&& command_data);
174 164
175private: 165private:
176 SynchState state; 166 SynchState state;
177 VideoCore::RendererBase& renderer; 167 Core::System& system;
168 Core::Timing::EventType* synchronization_event{};
178 std::thread thread; 169 std::thread thread;
179 std::thread::id thread_id; 170 std::thread::id thread_id;
180}; 171};
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 64f75db43..524d9ea5a 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -223,27 +223,21 @@ void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 res
223} 223}
224 224
225u32 MacroInterpreter::FetchParameter() { 225u32 MacroInterpreter::FetchParameter() {
226 ASSERT(next_parameter_index < parameters.size()); 226 return parameters.at(next_parameter_index++);
227 return parameters[next_parameter_index++];
228} 227}
229 228
230u32 MacroInterpreter::GetRegister(u32 register_id) const { 229u32 MacroInterpreter::GetRegister(u32 register_id) const {
231 // Register 0 is supposed to always return 0. 230 return registers.at(register_id);
232 if (register_id == 0)
233 return 0;
234
235 ASSERT(register_id < registers.size());
236 return registers[register_id];
237} 231}
238 232
239void MacroInterpreter::SetRegister(u32 register_id, u32 value) { 233void MacroInterpreter::SetRegister(u32 register_id, u32 value) {
240 // Register 0 is supposed to always return 0. NOP is implemented as a store to the zero 234 // Register 0 is hardwired as the zero register.
241 // register. 235 // Ensure no writes to it actually occur.
242 if (register_id == 0) 236 if (register_id == 0) {
243 return; 237 return;
238 }
244 239
245 ASSERT(register_id < registers.size()); 240 registers.at(register_id) = value;
246 registers[register_id] = value;
247} 241}
248 242
249void MacroInterpreter::SetMethodAddress(u32 address) { 243void MacroInterpreter::SetMethodAddress(u32 address) {
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index e76b59842..0f4e820aa 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -5,16 +5,13 @@
5#include "common/alignment.h" 5#include "common/alignment.h"
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
9#include "core/memory.h" 8#include "core/memory.h"
10#include "video_core/gpu.h"
11#include "video_core/memory_manager.h" 9#include "video_core/memory_manager.h"
12#include "video_core/rasterizer_interface.h" 10#include "video_core/rasterizer_interface.h"
13#include "video_core/renderer_base.h"
14 11
15namespace Tegra { 12namespace Tegra {
16 13
17MemoryManager::MemoryManager() { 14MemoryManager::MemoryManager(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {
18 std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr); 15 std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
19 std::fill(page_table.attributes.begin(), page_table.attributes.end(), 16 std::fill(page_table.attributes.begin(), page_table.attributes.end(),
20 Common::PageType::Unmapped); 17 Common::PageType::Unmapped);
@@ -70,23 +67,23 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
70 const u64 aligned_size{Common::AlignUp(size, page_size)}; 67 const u64 aligned_size{Common::AlignUp(size, page_size)};
71 const CacheAddr cache_addr{ToCacheAddr(GetPointer(gpu_addr))}; 68 const CacheAddr cache_addr{ToCacheAddr(GetPointer(gpu_addr))};
72 69
73 Core::System::GetInstance().Renderer().Rasterizer().FlushAndInvalidateRegion(cache_addr, 70 rasterizer.FlushAndInvalidateRegion(cache_addr, aligned_size);
74 aligned_size);
75 UnmapRange(gpu_addr, aligned_size); 71 UnmapRange(gpu_addr, aligned_size);
76 72
77 return gpu_addr; 73 return gpu_addr;
78} 74}
79 75
80GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size) { 76GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size) const {
81 // Find the first Free VMA. 77 // Find the first Free VMA.
82 const VMAHandle vma_handle{std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { 78 const VMAHandle vma_handle{
83 if (vma.second.type != VirtualMemoryArea::Type::Unmapped) { 79 std::find_if(vma_map.begin(), vma_map.end(), [region_start, size](const auto& vma) {
84 return false; 80 if (vma.second.type != VirtualMemoryArea::Type::Unmapped) {
85 } 81 return false;
82 }
86 83
87 const VAddr vma_end{vma.second.base + vma.second.size}; 84 const VAddr vma_end{vma.second.base + vma.second.size};
88 return vma_end > region_start && vma_end >= region_start + size; 85 return vma_end > region_start && vma_end >= region_start + size;
89 })}; 86 })};
90 87
91 if (vma_handle == vma_map.end()) { 88 if (vma_handle == vma_map.end()) {
92 return {}; 89 return {};
@@ -99,12 +96,12 @@ bool MemoryManager::IsAddressValid(GPUVAddr addr) const {
99 return (addr >> page_bits) < page_table.pointers.size(); 96 return (addr >> page_bits) < page_table.pointers.size();
100} 97}
101 98
102std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) { 99std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) const {
103 if (!IsAddressValid(addr)) { 100 if (!IsAddressValid(addr)) {
104 return {}; 101 return {};
105 } 102 }
106 103
107 VAddr cpu_addr{page_table.backing_addr[addr >> page_bits]}; 104 const VAddr cpu_addr{page_table.backing_addr[addr >> page_bits]};
108 if (cpu_addr) { 105 if (cpu_addr) {
109 return cpu_addr + (addr & page_mask); 106 return cpu_addr + (addr & page_mask);
110 } 107 }
@@ -113,7 +110,7 @@ std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) {
113} 110}
114 111
115template <typename T> 112template <typename T>
116T MemoryManager::Read(GPUVAddr addr) { 113T MemoryManager::Read(GPUVAddr addr) const {
117 if (!IsAddressValid(addr)) { 114 if (!IsAddressValid(addr)) {
118 return {}; 115 return {};
119 } 116 }
@@ -165,10 +162,10 @@ void MemoryManager::Write(GPUVAddr addr, T data) {
165 } 162 }
166} 163}
167 164
168template u8 MemoryManager::Read<u8>(GPUVAddr addr); 165template u8 MemoryManager::Read<u8>(GPUVAddr addr) const;
169template u16 MemoryManager::Read<u16>(GPUVAddr addr); 166template u16 MemoryManager::Read<u16>(GPUVAddr addr) const;
170template u32 MemoryManager::Read<u32>(GPUVAddr addr); 167template u32 MemoryManager::Read<u32>(GPUVAddr addr) const;
171template u64 MemoryManager::Read<u64>(GPUVAddr addr); 168template u64 MemoryManager::Read<u64>(GPUVAddr addr) const;
172template void MemoryManager::Write<u8>(GPUVAddr addr, u8 data); 169template void MemoryManager::Write<u8>(GPUVAddr addr, u8 data);
173template void MemoryManager::Write<u16>(GPUVAddr addr, u16 data); 170template void MemoryManager::Write<u16>(GPUVAddr addr, u16 data);
174template void MemoryManager::Write<u32>(GPUVAddr addr, u32 data); 171template void MemoryManager::Write<u32>(GPUVAddr addr, u32 data);
@@ -179,8 +176,22 @@ u8* MemoryManager::GetPointer(GPUVAddr addr) {
179 return {}; 176 return {};
180 } 177 }
181 178
182 u8* page_pointer{page_table.pointers[addr >> page_bits]}; 179 u8* const page_pointer{page_table.pointers[addr >> page_bits]};
183 if (page_pointer) { 180 if (page_pointer != nullptr) {
181 return page_pointer + (addr & page_mask);
182 }
183
184 LOG_ERROR(HW_GPU, "Unknown GetPointer @ 0x{:016X}", addr);
185 return {};
186}
187
188const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
189 if (!IsAddressValid(addr)) {
190 return {};
191 }
192
193 const u8* const page_pointer{page_table.pointers[addr >> page_bits]};
194 if (page_pointer != nullptr) {
184 return page_pointer + (addr & page_mask); 195 return page_pointer + (addr & page_mask);
185 } 196 }
186 197
@@ -188,15 +199,86 @@ u8* MemoryManager::GetPointer(GPUVAddr addr) {
188 return {}; 199 return {};
189} 200}
190 201
191void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) { 202void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const {
192 std::memcpy(dest_buffer, GetPointer(src_addr), size); 203 std::size_t remaining_size{size};
204 std::size_t page_index{src_addr >> page_bits};
205 std::size_t page_offset{src_addr & page_mask};
206
207 while (remaining_size > 0) {
208 const std::size_t copy_amount{
209 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
210
211 switch (page_table.attributes[page_index]) {
212 case Common::PageType::Memory: {
213 const u8* src_ptr{page_table.pointers[page_index] + page_offset};
214 rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
215 std::memcpy(dest_buffer, src_ptr, copy_amount);
216 break;
217 }
218 default:
219 UNREACHABLE();
220 }
221
222 page_index++;
223 page_offset = 0;
224 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
225 remaining_size -= copy_amount;
226 }
193} 227}
228
194void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size) { 229void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size) {
195 std::memcpy(GetPointer(dest_addr), src_buffer, size); 230 std::size_t remaining_size{size};
231 std::size_t page_index{dest_addr >> page_bits};
232 std::size_t page_offset{dest_addr & page_mask};
233
234 while (remaining_size > 0) {
235 const std::size_t copy_amount{
236 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
237
238 switch (page_table.attributes[page_index]) {
239 case Common::PageType::Memory: {
240 u8* dest_ptr{page_table.pointers[page_index] + page_offset};
241 rasterizer.InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
242 std::memcpy(dest_ptr, src_buffer, copy_amount);
243 break;
244 }
245 default:
246 UNREACHABLE();
247 }
248
249 page_index++;
250 page_offset = 0;
251 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
252 remaining_size -= copy_amount;
253 }
196} 254}
197 255
198void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size) { 256void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size) {
199 std::memcpy(GetPointer(dest_addr), GetPointer(src_addr), size); 257 std::size_t remaining_size{size};
258 std::size_t page_index{src_addr >> page_bits};
259 std::size_t page_offset{src_addr & page_mask};
260
261 while (remaining_size > 0) {
262 const std::size_t copy_amount{
263 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
264
265 switch (page_table.attributes[page_index]) {
266 case Common::PageType::Memory: {
267 const u8* src_ptr{page_table.pointers[page_index] + page_offset};
268 rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
269 WriteBlock(dest_addr, src_ptr, copy_amount);
270 break;
271 }
272 default:
273 UNREACHABLE();
274 }
275
276 page_index++;
277 page_offset = 0;
278 dest_addr += static_cast<VAddr>(copy_amount);
279 src_addr += static_cast<VAddr>(copy_amount);
280 remaining_size -= copy_amount;
281 }
200} 282}
201 283
202void MemoryManager::MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type, 284void MemoryManager::MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
@@ -336,7 +418,7 @@ MemoryManager::VMAIter MemoryManager::CarveVMA(GPUVAddr base, u64 size) {
336 const VirtualMemoryArea& vma{vma_handle->second}; 418 const VirtualMemoryArea& vma{vma_handle->second};
337 if (vma.type == VirtualMemoryArea::Type::Mapped) { 419 if (vma.type == VirtualMemoryArea::Type::Mapped) {
338 // Region is already allocated 420 // Region is already allocated
339 return {}; 421 return vma_handle;
340 } 422 }
341 423
342 const VAddr start_in_vma{base - vma.base}; 424 const VAddr start_in_vma{base - vma.base};
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 34744bb27..647cbf93a 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -10,6 +10,10 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/page_table.h" 11#include "common/page_table.h"
12 12
13namespace VideoCore {
14class RasterizerInterface;
15}
16
13namespace Tegra { 17namespace Tegra {
14 18
15/** 19/**
@@ -43,24 +47,25 @@ struct VirtualMemoryArea {
43 47
44class MemoryManager final { 48class MemoryManager final {
45public: 49public:
46 MemoryManager(); 50 MemoryManager(VideoCore::RasterizerInterface& rasterizer);
47 51
48 GPUVAddr AllocateSpace(u64 size, u64 align); 52 GPUVAddr AllocateSpace(u64 size, u64 align);
49 GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align); 53 GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
50 GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size); 54 GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
51 GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size); 55 GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size);
52 GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size); 56 GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size);
53 std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr); 57 std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
54 58
55 template <typename T> 59 template <typename T>
56 T Read(GPUVAddr addr); 60 T Read(GPUVAddr addr) const;
57 61
58 template <typename T> 62 template <typename T>
59 void Write(GPUVAddr addr, T data); 63 void Write(GPUVAddr addr, T data);
60 64
61 u8* GetPointer(GPUVAddr addr); 65 u8* GetPointer(GPUVAddr addr);
66 const u8* GetPointer(GPUVAddr addr) const;
62 67
63 void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size); 68 void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
64 void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size); 69 void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
65 void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size); 70 void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
66 71
@@ -127,7 +132,7 @@ private:
127 void UpdatePageTableForVMA(const VirtualMemoryArea& vma); 132 void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
128 133
129 /// Finds a free (unmapped region) of the specified size starting at the specified address. 134 /// Finds a free (unmapped region) of the specified size starting at the specified address.
130 GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size); 135 GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size) const;
131 136
132private: 137private:
133 static constexpr u64 page_bits{16}; 138 static constexpr u64 page_bits{16};
@@ -143,6 +148,7 @@ private:
143 148
144 Common::PageTable page_table{page_bits}; 149 Common::PageTable page_table{page_bits};
145 VMAMap vma_map; 150 VMAMap vma_map;
151 VideoCore::RasterizerInterface& rasterizer;
146}; 152};
147 153
148} // namespace Tegra 154} // namespace Tegra
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index fd091c84c..7989ec11b 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -7,7 +7,6 @@
7 7
8#include "common/alignment.h" 8#include "common/alignment.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/memory.h"
11#include "video_core/renderer_opengl/gl_buffer_cache.h" 10#include "video_core/renderer_opengl/gl_buffer_cache.h"
12#include "video_core/renderer_opengl/gl_rasterizer.h" 11#include "video_core/renderer_opengl/gl_rasterizer.h"
13 12
diff --git a/src/video_core/renderer_opengl/gl_global_cache.cpp b/src/video_core/renderer_opengl/gl_global_cache.cpp
index da9326253..5842d6213 100644
--- a/src/video_core/renderer_opengl/gl_global_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_global_cache.cpp
@@ -4,7 +4,6 @@
4 4
5#include <glad/glad.h> 5#include <glad/glad.h>
6 6
7#include "common/assert.h"
8#include "common/logging/log.h" 7#include "common/logging/log.h"
9#include "core/core.h" 8#include "core/core.h"
10#include "video_core/renderer_opengl/gl_global_cache.h" 9#include "video_core/renderer_opengl/gl_global_cache.h"
diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
index 2bcbd3da2..c3e94d917 100644
--- a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
+++ b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
@@ -7,7 +7,7 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/memory.h" 10#include "video_core/memory_manager.h"
11#include "video_core/renderer_opengl/gl_buffer_cache.h" 11#include "video_core/renderer_opengl/gl_buffer_cache.h"
12#include "video_core/renderer_opengl/gl_primitive_assembler.h" 12#include "video_core/renderer_opengl/gl_primitive_assembler.h"
13 13
diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.h b/src/video_core/renderer_opengl/gl_primitive_assembler.h
index 0e2e7dc36..4e87ce4d6 100644
--- a/src/video_core/renderer_opengl/gl_primitive_assembler.h
+++ b/src/video_core/renderer_opengl/gl_primitive_assembler.h
@@ -4,11 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector>
8#include <glad/glad.h> 7#include <glad/glad.h>
9 8
10#include "common/common_types.h" 9#include "common/common_types.h"
11#include "video_core/memory_manager.h"
12 10
13namespace OpenGL { 11namespace OpenGL {
14 12
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 046fc935b..7ff1e6737 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -17,7 +17,6 @@
17#include "common/microprofile.h" 17#include "common/microprofile.h"
18#include "common/scope_exit.h" 18#include "common/scope_exit.h"
19#include "core/core.h" 19#include "core/core.h"
20#include "core/frontend/emu_window.h"
21#include "core/hle/kernel/process.h" 20#include "core/hle/kernel/process.h"
22#include "core/settings.h" 21#include "core/settings.h"
23#include "video_core/engines/maxwell_3d.h" 22#include "video_core/engines/maxwell_3d.h"
@@ -26,7 +25,6 @@
26#include "video_core/renderer_opengl/gl_shader_gen.h" 25#include "video_core/renderer_opengl/gl_shader_gen.h"
27#include "video_core/renderer_opengl/maxwell_to_gl.h" 26#include "video_core/renderer_opengl/maxwell_to_gl.h"
28#include "video_core/renderer_opengl/renderer_opengl.h" 27#include "video_core/renderer_opengl/renderer_opengl.h"
29#include "video_core/video_core.h"
30 28
31namespace OpenGL { 29namespace OpenGL {
32 30
@@ -318,7 +316,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
318 const std::size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5 316 const std::size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
319 317
320 GLShader::MaxwellUniformData ubo{}; 318 GLShader::MaxwellUniformData ubo{};
321 ubo.SetFromRegs(gpu.state.shader_stages[stage]); 319 ubo.SetFromRegs(gpu, stage);
322 const GLintptr offset = buffer_cache.UploadHostMemory( 320 const GLintptr offset = buffer_cache.UploadHostMemory(
323 &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment)); 321 &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
324 322
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 4de565321..54fbf48aa 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -12,15 +12,12 @@
12#include <optional> 12#include <optional>
13#include <tuple> 13#include <tuple>
14#include <utility> 14#include <utility>
15#include <vector>
16 15
17#include <boost/icl/interval_map.hpp> 16#include <boost/icl/interval_map.hpp>
18#include <boost/range/iterator_range.hpp>
19#include <glad/glad.h> 17#include <glad/glad.h>
20 18
21#include "common/common_types.h" 19#include "common/common_types.h"
22#include "video_core/engines/maxwell_3d.h" 20#include "video_core/engines/maxwell_3d.h"
23#include "video_core/memory_manager.h"
24#include "video_core/rasterizer_cache.h" 21#include "video_core/rasterizer_cache.h"
25#include "video_core/rasterizer_interface.h" 22#include "video_core/rasterizer_interface.h"
26#include "video_core/renderer_opengl/gl_buffer_cache.h" 23#include "video_core/renderer_opengl/gl_buffer_cache.h"
@@ -29,10 +26,8 @@
29#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 26#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
30#include "video_core/renderer_opengl/gl_resource_manager.h" 27#include "video_core/renderer_opengl/gl_resource_manager.h"
31#include "video_core/renderer_opengl/gl_shader_cache.h" 28#include "video_core/renderer_opengl/gl_shader_cache.h"
32#include "video_core/renderer_opengl/gl_shader_gen.h"
33#include "video_core/renderer_opengl/gl_shader_manager.h" 29#include "video_core/renderer_opengl/gl_shader_manager.h"
34#include "video_core/renderer_opengl/gl_state.h" 30#include "video_core/renderer_opengl/gl_state.h"
35#include "video_core/renderer_opengl/gl_stream_buffer.h"
36 31
37namespace Core { 32namespace Core {
38class System; 33class System;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index aba6ce731..7a3280620 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -13,7 +13,6 @@
13#include "common/scope_exit.h" 13#include "common/scope_exit.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
16#include "core/memory.h"
17#include "core/settings.h" 16#include "core/settings.h"
18#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
19#include "video_core/morton.h" 18#include "video_core/morton.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index e8073579f..ad4fd3ad2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -5,10 +5,9 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <map>
9#include <memory> 8#include <memory>
10#include <string> 9#include <string>
11#include <unordered_set> 10#include <tuple>
12#include <vector> 11#include <vector>
13 12
14#include "common/alignment.h" 13#include "common/alignment.h"
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 290e654bc..7030db365 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -6,13 +6,11 @@
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/hash.h" 7#include "common/hash.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/memory.h"
10#include "video_core/engines/maxwell_3d.h" 9#include "video_core/engines/maxwell_3d.h"
11#include "video_core/renderer_opengl/gl_rasterizer.h" 10#include "video_core/renderer_opengl/gl_rasterizer.h"
12#include "video_core/renderer_opengl/gl_shader_cache.h" 11#include "video_core/renderer_opengl/gl_shader_cache.h"
13#include "video_core/renderer_opengl/gl_shader_decompiler.h" 12#include "video_core/renderer_opengl/gl_shader_decompiler.h"
14#include "video_core/renderer_opengl/gl_shader_disk_cache.h" 13#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
15#include "video_core/renderer_opengl/gl_shader_manager.h"
16#include "video_core/renderer_opengl/utils.h" 14#include "video_core/renderer_opengl/utils.h"
17#include "video_core/shader/shader_ir.h" 15#include "video_core/shader/shader_ir.h"
18 16
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index fd1c85115..0cf8e0b3d 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -5,21 +5,20 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
8#include <memory> 9#include <memory>
9#include <set> 10#include <set>
10#include <tuple> 11#include <tuple>
11#include <unordered_map> 12#include <unordered_map>
13#include <vector>
12 14
13#include <glad/glad.h> 15#include <glad/glad.h>
14 16
15#include "common/assert.h"
16#include "common/common_types.h" 17#include "common/common_types.h"
17#include "video_core/rasterizer_cache.h" 18#include "video_core/rasterizer_cache.h"
18#include "video_core/renderer_base.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_decompiler.h" 20#include "video_core/renderer_opengl/gl_shader_decompiler.h"
21#include "video_core/renderer_opengl/gl_shader_disk_cache.h" 21#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
22#include "video_core/renderer_opengl/gl_shader_gen.h"
23 22
24namespace Core { 23namespace Core {
25class System; 24class System;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 11d1169f0..a1a51f226 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -69,10 +69,10 @@ public:
69 shader_source += '\n'; 69 shader_source += '\n';
70 } 70 }
71 71
72 std::string GenerateTemporal() { 72 std::string GenerateTemporary() {
73 std::string temporal = "tmp"; 73 std::string temporary = "tmp";
74 temporal += std::to_string(temporal_index++); 74 temporary += std::to_string(temporary_index++);
75 return temporal; 75 return temporary;
76 } 76 }
77 77
78 std::string GetResult() { 78 std::string GetResult() {
@@ -87,7 +87,7 @@ private:
87 } 87 }
88 88
89 std::string shader_source; 89 std::string shader_source;
90 u32 temporal_index = 1; 90 u32 temporary_index = 1;
91}; 91};
92 92
93/// Generates code to use for a swizzle operation. 93/// Generates code to use for a swizzle operation.
@@ -426,9 +426,14 @@ private:
426 std::string Visit(Node node) { 426 std::string Visit(Node node) {
427 if (const auto operation = std::get_if<OperationNode>(node)) { 427 if (const auto operation = std::get_if<OperationNode>(node)) {
428 const auto operation_index = static_cast<std::size_t>(operation->GetCode()); 428 const auto operation_index = static_cast<std::size_t>(operation->GetCode());
429 if (operation_index >= operation_decompilers.size()) {
430 UNREACHABLE_MSG("Out of bounds operation: {}", operation_index);
431 return {};
432 }
429 const auto decompiler = operation_decompilers[operation_index]; 433 const auto decompiler = operation_decompilers[operation_index];
430 if (decompiler == nullptr) { 434 if (decompiler == nullptr) {
431 UNREACHABLE_MSG("Operation decompiler {} not defined", operation_index); 435 UNREACHABLE_MSG("Undefined operation: {}", operation_index);
436 return {};
432 } 437 }
433 return (this->*decompiler)(*operation); 438 return (this->*decompiler)(*operation);
434 439
@@ -540,7 +545,7 @@ private:
540 545
541 } else if (std::holds_alternative<OperationNode>(*offset)) { 546 } else if (std::holds_alternative<OperationNode>(*offset)) {
542 // Indirect access 547 // Indirect access
543 const std::string final_offset = code.GenerateTemporal(); 548 const std::string final_offset = code.GenerateTemporary();
544 code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4) & " + 549 code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4) & " +
545 std::to_string(MAX_CONSTBUFFER_ELEMENTS - 1) + ';'); 550 std::to_string(MAX_CONSTBUFFER_ELEMENTS - 1) + ';');
546 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), 551 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()),
@@ -587,9 +592,9 @@ private:
587 // There's a bug in NVidia's proprietary drivers that makes precise fail on fragment shaders 592 // There's a bug in NVidia's proprietary drivers that makes precise fail on fragment shaders
588 const std::string precise = stage != ShaderStage::Fragment ? "precise " : ""; 593 const std::string precise = stage != ShaderStage::Fragment ? "precise " : "";
589 594
590 const std::string temporal = code.GenerateTemporal(); 595 const std::string temporary = code.GenerateTemporary();
591 code.AddLine(precise + "float " + temporal + " = " + value + ';'); 596 code.AddLine(precise + "float " + temporary + " = " + value + ';');
592 return temporal; 597 return temporary;
593 } 598 }
594 599
595 std::string VisitOperand(Operation operation, std::size_t operand_index) { 600 std::string VisitOperand(Operation operation, std::size_t operand_index) {
@@ -601,9 +606,9 @@ private:
601 return Visit(operand); 606 return Visit(operand);
602 } 607 }
603 608
604 const std::string temporal = code.GenerateTemporal(); 609 const std::string temporary = code.GenerateTemporary();
605 code.AddLine("float " + temporal + " = " + Visit(operand) + ';'); 610 code.AddLine("float " + temporary + " = " + Visit(operand) + ';');
606 return temporal; 611 return temporary;
607 } 612 }
608 613
609 std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { 614 std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) {
@@ -1196,11 +1201,12 @@ private:
1196 switch (meta->element) { 1201 switch (meta->element) {
1197 case 0: 1202 case 0:
1198 case 1: 1203 case 1:
1199 return "textureSize(" + sampler + ", " + lod + ')' + GetSwizzle(meta->element); 1204 return "itof(int(textureSize(" + sampler + ", " + lod + ')' +
1205 GetSwizzle(meta->element) + "))";
1200 case 2: 1206 case 2:
1201 return "0"; 1207 return "0";
1202 case 3: 1208 case 3:
1203 return "textureQueryLevels(" + sampler + ')'; 1209 return "itof(textureQueryLevels(" + sampler + "))";
1204 } 1210 }
1205 UNREACHABLE(); 1211 UNREACHABLE();
1206 return "0"; 1212 return "0";
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index 72aca4938..4e04ab2f8 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <set>
9#include <string> 8#include <string>
10#include <utility> 9#include <utility>
11#include <vector> 10#include <vector>
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 82fc4d44b..8a43eb157 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -4,7 +4,6 @@
4 4
5#include <cstring> 5#include <cstring>
6#include <fmt/format.h> 6#include <fmt/format.h>
7#include <lz4.h>
8 7
9#include "common/assert.h" 8#include "common/assert.h"
10#include "common/common_paths.h" 9#include "common/common_paths.h"
@@ -12,6 +11,7 @@
12#include "common/file_util.h" 11#include "common/file_util.h"
13#include "common/logging/log.h" 12#include "common/logging/log.h"
14#include "common/scm_rev.h" 13#include "common/scm_rev.h"
14#include "common/zstd_compression.h"
15 15
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
@@ -49,39 +49,6 @@ ShaderCacheVersionHash GetShaderCacheVersionHash() {
49 return hash; 49 return hash;
50} 50}
51 51
52template <typename T>
53std::vector<u8> CompressData(const T* source, std::size_t source_size) {
54 if (source_size > LZ4_MAX_INPUT_SIZE) {
55 // Source size exceeds LZ4 maximum input size
56 return {};
57 }
58 const auto source_size_int = static_cast<int>(source_size);
59 const int max_compressed_size = LZ4_compressBound(source_size_int);
60 std::vector<u8> compressed(max_compressed_size);
61 const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source),
62 reinterpret_cast<char*>(compressed.data()),
63 source_size_int, max_compressed_size);
64 if (compressed_size <= 0) {
65 // Compression failed
66 return {};
67 }
68 compressed.resize(compressed_size);
69 return compressed;
70}
71
72std::vector<u8> DecompressData(const std::vector<u8>& compressed, std::size_t uncompressed_size) {
73 std::vector<u8> uncompressed(uncompressed_size);
74 const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()),
75 reinterpret_cast<char*>(uncompressed.data()),
76 static_cast<int>(compressed.size()),
77 static_cast<int>(uncompressed.size()));
78 if (static_cast<int>(uncompressed_size) != size_check) {
79 // Decompression failed
80 return {};
81 }
82 return uncompressed;
83}
84
85} // namespace 52} // namespace
86 53
87ShaderDiskCacheRaw::ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type, 54ShaderDiskCacheRaw::ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type,
@@ -292,7 +259,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) {
292 return {}; 259 return {};
293 } 260 }
294 261
295 dump.binary = DecompressData(compressed_binary, binary_length); 262 dump.binary = Common::Compression::DecompressDataZSTD(compressed_binary);
296 if (dump.binary.empty()) { 263 if (dump.binary.empty()) {
297 return {}; 264 return {};
298 } 265 }
@@ -321,7 +288,7 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
321 return {}; 288 return {};
322 } 289 }
323 290
324 const std::vector<u8> code = DecompressData(compressed_code, code_size); 291 const std::vector<u8> code = Common::Compression::DecompressDataZSTD(compressed_code);
325 if (code.empty()) { 292 if (code.empty()) {
326 return {}; 293 return {};
327 } 294 }
@@ -507,7 +474,8 @@ void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::str
507 if (!IsUsable()) 474 if (!IsUsable())
508 return; 475 return;
509 476
510 const std::vector<u8> compressed_code{CompressData(code.data(), code.size())}; 477 const std::vector<u8> compressed_code{Common::Compression::CompressDataZSTDDefault(
478 reinterpret_cast<const u8*>(code.data()), code.size())};
511 if (compressed_code.empty()) { 479 if (compressed_code.empty()) {
512 LOG_ERROR(Render_OpenGL, "Failed to compress GLSL code - skipping shader {:016x}", 480 LOG_ERROR(Render_OpenGL, "Failed to compress GLSL code - skipping shader {:016x}",
513 unique_identifier); 481 unique_identifier);
@@ -537,7 +505,9 @@ void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint p
537 std::vector<u8> binary(binary_length); 505 std::vector<u8> binary(binary_length);
538 glGetProgramBinary(program, binary_length, nullptr, &binary_format, binary.data()); 506 glGetProgramBinary(program, binary_length, nullptr, &binary_format, binary.data());
539 507
540 const std::vector<u8> compressed_binary = CompressData(binary.data(), binary.size()); 508 const std::vector<u8> compressed_binary =
509 Common::Compression::CompressDataZSTDDefault(binary.data(), binary.size());
510
541 if (compressed_binary.empty()) { 511 if (compressed_binary.empty()) {
542 LOG_ERROR(Render_OpenGL, "Failed to compress binary program in shader={:016x}", 512 LOG_ERROR(Render_OpenGL, "Failed to compress binary program in shader={:016x}",
543 usage.unique_identifier); 513 usage.unique_identifier);
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 7d96649af..8763d9c71 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <fmt/format.h> 5#include <fmt/format.h>
6#include "common/assert.h"
7#include "video_core/engines/maxwell_3d.h" 6#include "video_core/engines/maxwell_3d.h"
8#include "video_core/renderer_opengl/gl_shader_decompiler.h" 7#include "video_core/renderer_opengl/gl_shader_decompiler.h"
9#include "video_core/renderer_opengl/gl_shader_gen.h" 8#include "video_core/renderer_opengl/gl_shader_gen.h"
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index fba8e681b..fad346b48 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -4,12 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <string>
9#include <vector> 7#include <vector>
10 8
11#include "common/common_types.h" 9#include "common/common_types.h"
12#include "video_core/engines/shader_bytecode.h"
13#include "video_core/renderer_opengl/gl_shader_decompiler.h" 10#include "video_core/renderer_opengl/gl_shader_decompiler.h"
14#include "video_core/shader/shader_ir.h" 11#include "video_core/shader/shader_ir.h"
15 12
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 6a30c28d2..eaf3e03a0 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -2,15 +2,15 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
6#include "video_core/renderer_opengl/gl_shader_manager.h" 5#include "video_core/renderer_opengl/gl_shader_manager.h"
7 6
8namespace OpenGL::GLShader { 7namespace OpenGL::GLShader {
9 8
10void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) { 9using Tegra::Engines::Maxwell3D;
11 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); 10
12 const auto& regs = gpu.regs; 11void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell, std::size_t shader_stage) {
13 const auto& state = gpu.state; 12 const auto& regs = maxwell.regs;
13 const auto& state = maxwell.state;
14 14
15 // TODO(bunnei): Support more than one viewport 15 // TODO(bunnei): Support more than one viewport
16 viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; 16 viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
@@ -18,7 +18,7 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
18 18
19 u32 func = static_cast<u32>(regs.alpha_test_func); 19 u32 func = static_cast<u32>(regs.alpha_test_func);
20 // Normalize the gl variants of opCompare to be the same as the normal variants 20 // Normalize the gl variants of opCompare to be the same as the normal variants
21 u32 op_gl_variant_base = static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never); 21 const u32 op_gl_variant_base = static_cast<u32>(Maxwell3D::Regs::ComparisonOp::Never);
22 if (func >= op_gl_variant_base) { 22 if (func >= op_gl_variant_base) {
23 func = func - op_gl_variant_base + 1U; 23 func = func - op_gl_variant_base + 1U;
24 } 24 }
@@ -31,8 +31,9 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
31 31
32 // Assign in which stage the position has to be flipped 32 // Assign in which stage the position has to be flipped
33 // (the last stage before the fragment shader). 33 // (the last stage before the fragment shader).
34 if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { 34 constexpr u32 geometry_index = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry);
35 flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); 35 if (maxwell.regs.shader_config[geometry_index].enable) {
36 flip_stage = geometry_index;
36 } else { 37 } else {
37 flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); 38 flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB);
38 } 39 }
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 316b47910..37dcfefdb 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -12,14 +12,13 @@
12 12
13namespace OpenGL::GLShader { 13namespace OpenGL::GLShader {
14 14
15using Tegra::Engines::Maxwell3D;
16
17/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned 15/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
18// NOTE: Always keep a vec4 at the end. The GL spec is not clear whether the alignment at 16/// @note Always keep a vec4 at the end. The GL spec is not clear whether the alignment at
19// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. 17/// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.
20// Not following that rule will cause problems on some AMD drivers. 18/// Not following that rule will cause problems on some AMD drivers.
21struct MaxwellUniformData { 19struct MaxwellUniformData {
22 void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); 20 void SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell, std::size_t shader_stage);
21
23 alignas(16) GLvec4 viewport_flip; 22 alignas(16) GLvec4 viewport_flip;
24 struct alignas(16) { 23 struct alignas(16) {
25 GLuint instance_id; 24 GLuint instance_id;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index a01efeb05..d69cba9c3 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -5,7 +5,6 @@
5#include <algorithm> 5#include <algorithm>
6#include <cstddef> 6#include <cstddef>
7#include <cstdlib> 7#include <cstdlib>
8#include <cstring>
9#include <memory> 8#include <memory>
10#include <glad/glad.h> 9#include <glad/glad.h>
11#include "common/assert.h" 10#include "common/assert.h"
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 388b5ffd5..02a9f5ecb 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -10,6 +10,7 @@
10#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/assert.h" 11#include "common/assert.h"
12#include "core/memory.h" 12#include "core/memory.h"
13#include "video_core/memory_manager.h"
13#include "video_core/renderer_vulkan/declarations.h" 14#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_buffer_cache.h" 15#include "video_core/renderer_vulkan/vk_buffer_cache.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h" 16#include "video_core/renderer_vulkan/vk_scheduler.h"
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 11023ed63..f2d14becf 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -7,6 +7,7 @@
7#include <QDebug> 7#include <QDebug>
8#include <QFileDialog> 8#include <QFileDialog>
9#include <QLabel> 9#include <QLabel>
10#include <QMessageBox>
10#include <QMouseEvent> 11#include <QMouseEvent>
11#include <QPushButton> 12#include <QPushButton>
12#include <QScrollArea> 13#include <QScrollArea>
@@ -95,50 +96,91 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext
95 surface_picker_y_control = new QSpinBox; 96 surface_picker_y_control = new QSpinBox;
96 surface_picker_y_control->setRange(0, max_dimension - 1); 97 surface_picker_y_control->setRange(0, max_dimension - 1);
97 98
98 surface_format_control = new QComboBox; 99 // clang-format off
99
100 // Color formats sorted by Maxwell texture format index 100 // Color formats sorted by Maxwell texture format index
101 surface_format_control->addItem(tr("None")); 101 const QStringList surface_formats{
102 surface_format_control->addItem(tr("Unknown")); 102 tr("None"),
103 surface_format_control->addItem(tr("Unknown")); 103 QStringLiteral("R32_G32_B32_A32"),
104 surface_format_control->addItem(tr("Unknown")); 104 QStringLiteral("R32_G32_B32"),
105 surface_format_control->addItem(tr("Unknown")); 105 QStringLiteral("R16_G16_B16_A16"),
106 surface_format_control->addItem(tr("Unknown")); 106 QStringLiteral("R32_G32"),
107 surface_format_control->addItem(tr("Unknown")); 107 QStringLiteral("R32_B24G8"),
108 surface_format_control->addItem(tr("Unknown")); 108 QStringLiteral("ETC2_RGB"),
109 surface_format_control->addItem(tr("A8R8G8B8")); 109 QStringLiteral("X8B8G8R8"),
110 surface_format_control->addItem(tr("Unknown")); 110 QStringLiteral("A8R8G8B8"),
111 surface_format_control->addItem(tr("Unknown")); 111 QStringLiteral("A2B10G10R10"),
112 surface_format_control->addItem(tr("Unknown")); 112 QStringLiteral("ETC2_RGB_PTA"),
113 surface_format_control->addItem(tr("Unknown")); 113 QStringLiteral("ETC2_RGBA"),
114 surface_format_control->addItem(tr("Unknown")); 114 QStringLiteral("R16_G16"),
115 surface_format_control->addItem(tr("Unknown")); 115 QStringLiteral("G8R24"),
116 surface_format_control->addItem(tr("Unknown")); 116 QStringLiteral("G24R8"),
117 surface_format_control->addItem(tr("Unknown")); 117 QStringLiteral("R32"),
118 surface_format_control->addItem(tr("Unknown")); 118 QStringLiteral("BC6H_SF16"),
119 surface_format_control->addItem(tr("Unknown")); 119 QStringLiteral("BC6H_UF16"),
120 surface_format_control->addItem(tr("Unknown")); 120 QStringLiteral("A4B4G4R4"),
121 surface_format_control->addItem(tr("Unknown")); 121 QStringLiteral("A5B5G5R1"),
122 surface_format_control->addItem(tr("Unknown")); 122 QStringLiteral("A1B5G5R5"),
123 surface_format_control->addItem(tr("Unknown")); 123 QStringLiteral("B5G6R5"),
124 surface_format_control->addItem(tr("Unknown")); 124 QStringLiteral("B6G5R5"),
125 surface_format_control->addItem(tr("Unknown")); 125 QStringLiteral("BC7U"),
126 surface_format_control->addItem(tr("Unknown")); 126 QStringLiteral("G8R8"),
127 surface_format_control->addItem(tr("Unknown")); 127 QStringLiteral("EAC"),
128 surface_format_control->addItem(tr("Unknown")); 128 QStringLiteral("EACX2"),
129 surface_format_control->addItem(tr("Unknown")); 129 QStringLiteral("R16"),
130 surface_format_control->addItem(tr("Unknown")); 130 QStringLiteral("Y8_VIDEO"),
131 surface_format_control->addItem(tr("Unknown")); 131 QStringLiteral("R8"),
132 surface_format_control->addItem(tr("Unknown")); 132 QStringLiteral("G4R4"),
133 surface_format_control->addItem(tr("Unknown")); 133 QStringLiteral("R1"),
134 surface_format_control->addItem(tr("Unknown")); 134 QStringLiteral("E5B9G9R9_SHAREDEXP"),
135 surface_format_control->addItem(tr("Unknown")); 135 QStringLiteral("BF10GF11RF11"),
136 surface_format_control->addItem(tr("Unknown")); 136 QStringLiteral("G8B8G8R8"),
137 surface_format_control->addItem(tr("DXT1")); 137 QStringLiteral("B8G8R8G8"),
138 surface_format_control->addItem(tr("DXT23")); 138 QStringLiteral("DXT1"),
139 surface_format_control->addItem(tr("DXT45")); 139 QStringLiteral("DXT23"),
140 surface_format_control->addItem(tr("DXN1")); 140 QStringLiteral("DXT45"),
141 surface_format_control->addItem(tr("DXN2")); 141 QStringLiteral("DXN1"),
142 QStringLiteral("DXN2"),
143 QStringLiteral("Z24S8"),
144 QStringLiteral("X8Z24"),
145 QStringLiteral("S8Z24"),
146 QStringLiteral("X4V4Z24__COV4R4V"),
147 QStringLiteral("X4V4Z24__COV8R8V"),
148 QStringLiteral("V8Z24__COV4R12V"),
149 QStringLiteral("ZF32"),
150 QStringLiteral("ZF32_X24S8"),
151 QStringLiteral("X8Z24_X20V4S8__COV4R4V"),
152 QStringLiteral("X8Z24_X20V4S8__COV8R8V"),
153 QStringLiteral("ZF32_X20V4X8__COV4R4V"),
154 QStringLiteral("ZF32_X20V4X8__COV8R8V"),
155 QStringLiteral("ZF32_X20V4S8__COV4R4V"),
156 QStringLiteral("ZF32_X20V4S8__COV8R8V"),
157 QStringLiteral("X8Z24_X16V8S8__COV4R12V"),
158 QStringLiteral("ZF32_X16V8X8__COV4R12V"),
159 QStringLiteral("ZF32_X16V8S8__COV4R12V"),
160 QStringLiteral("Z16"),
161 QStringLiteral("V8Z24__COV8R24V"),
162 QStringLiteral("X8Z24_X16V8S8__COV8R24V"),
163 QStringLiteral("ZF32_X16V8X8__COV8R24V"),
164 QStringLiteral("ZF32_X16V8S8__COV8R24V"),
165 QStringLiteral("ASTC_2D_4X4"),
166 QStringLiteral("ASTC_2D_5X5"),
167 QStringLiteral("ASTC_2D_6X6"),
168 QStringLiteral("ASTC_2D_8X8"),
169 QStringLiteral("ASTC_2D_10X10"),
170 QStringLiteral("ASTC_2D_12X12"),
171 QStringLiteral("ASTC_2D_5X4"),
172 QStringLiteral("ASTC_2D_6X5"),
173 QStringLiteral("ASTC_2D_8X6"),
174 QStringLiteral("ASTC_2D_10X8"),
175 QStringLiteral("ASTC_2D_12X10"),
176 QStringLiteral("ASTC_2D_8X5"),
177 QStringLiteral("ASTC_2D_10X5"),
178 QStringLiteral("ASTC_2D_10X6"),
179 };
180 // clang-format on
181
182 surface_format_control = new QComboBox;
183 surface_format_control->addItems(surface_formats);
142 184
143 surface_info_label = new QLabel(); 185 surface_info_label = new QLabel();
144 surface_info_label->setWordWrap(true); 186 surface_info_label->setWordWrap(true);
@@ -157,22 +199,20 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext
157 199
158 // Connections 200 // Connections
159 connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate); 201 connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate);
160 connect(surface_source_list, 202 connect(surface_source_list, qOverload<int>(&QComboBox::currentIndexChanged), this,
161 static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
162 &GraphicsSurfaceWidget::OnSurfaceSourceChanged); 203 &GraphicsSurfaceWidget::OnSurfaceSourceChanged);
163 connect(surface_address_control, &CSpinBox::ValueChanged, this, 204 connect(surface_address_control, &CSpinBox::ValueChanged, this,
164 &GraphicsSurfaceWidget::OnSurfaceAddressChanged); 205 &GraphicsSurfaceWidget::OnSurfaceAddressChanged);
165 connect(surface_width_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), 206 connect(surface_width_control, qOverload<int>(&QSpinBox::valueChanged), this,
166 this, &GraphicsSurfaceWidget::OnSurfaceWidthChanged); 207 &GraphicsSurfaceWidget::OnSurfaceWidthChanged);
167 connect(surface_height_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), 208 connect(surface_height_control, qOverload<int>(&QSpinBox::valueChanged), this,
168 this, &GraphicsSurfaceWidget::OnSurfaceHeightChanged); 209 &GraphicsSurfaceWidget::OnSurfaceHeightChanged);
169 connect(surface_format_control, 210 connect(surface_format_control, qOverload<int>(&QComboBox::currentIndexChanged), this,
170 static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
171 &GraphicsSurfaceWidget::OnSurfaceFormatChanged); 211 &GraphicsSurfaceWidget::OnSurfaceFormatChanged);
172 connect(surface_picker_x_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), 212 connect(surface_picker_x_control, qOverload<int>(&QSpinBox::valueChanged), this,
173 this, &GraphicsSurfaceWidget::OnSurfacePickerXChanged); 213 &GraphicsSurfaceWidget::OnSurfacePickerXChanged);
174 connect(surface_picker_y_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), 214 connect(surface_picker_y_control, qOverload<int>(&QSpinBox::valueChanged), this,
175 this, &GraphicsSurfaceWidget::OnSurfacePickerYChanged); 215 &GraphicsSurfaceWidget::OnSurfacePickerYChanged);
176 connect(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface); 216 connect(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface);
177 217
178 auto main_widget = new QWidget; 218 auto main_widget = new QWidget;
@@ -420,40 +460,56 @@ void GraphicsSurfaceWidget::OnUpdate() {
420} 460}
421 461
422void GraphicsSurfaceWidget::SaveSurface() { 462void GraphicsSurfaceWidget::SaveSurface() {
423 QString png_filter = tr("Portable Network Graphic (*.png)"); 463 const QString png_filter = tr("Portable Network Graphic (*.png)");
424 QString bin_filter = tr("Binary data (*.bin)"); 464 const QString bin_filter = tr("Binary data (*.bin)");
425 465
426 QString selectedFilter; 466 QString selected_filter;
427 QString filename = QFileDialog::getSaveFileName( 467 const QString filename = QFileDialog::getSaveFileName(
428 this, tr("Save Surface"), 468 this, tr("Save Surface"),
429 QString("texture-0x%1.png").arg(QString::number(surface_address, 16)), 469 QStringLiteral("texture-0x%1.png").arg(QString::number(surface_address, 16)),
430 QString("%1;;%2").arg(png_filter, bin_filter), &selectedFilter); 470 QStringLiteral("%1;;%2").arg(png_filter, bin_filter), &selected_filter);
431 471
432 if (filename.isEmpty()) { 472 if (filename.isEmpty()) {
433 // If the user canceled the dialog, don't save anything. 473 // If the user canceled the dialog, don't save anything.
434 return; 474 return;
435 } 475 }
436 476
437 if (selectedFilter == png_filter) { 477 if (selected_filter == png_filter) {
438 const QPixmap* pixmap = surface_picture_label->pixmap(); 478 const QPixmap* const pixmap = surface_picture_label->pixmap();
439 ASSERT_MSG(pixmap != nullptr, "No pixmap set"); 479 ASSERT_MSG(pixmap != nullptr, "No pixmap set");
440 480
441 QFile file(filename); 481 QFile file{filename};
442 file.open(QIODevice::WriteOnly); 482 if (!file.open(QIODevice::WriteOnly)) {
443 if (pixmap) 483 QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename));
444 pixmap->save(&file, "PNG"); 484 return;
445 } else if (selectedFilter == bin_filter) { 485 }
486
487 if (!pixmap->save(&file, "PNG")) {
488 QMessageBox::warning(this, tr("Error"),
489 tr("Failed to save surface data to file '%1'").arg(filename));
490 }
491 } else if (selected_filter == bin_filter) {
446 auto& gpu = Core::System::GetInstance().GPU(); 492 auto& gpu = Core::System::GetInstance().GPU();
447 std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address); 493 const std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
448 494
449 const u8* buffer = Memory::GetPointer(*address); 495 const u8* const buffer = Memory::GetPointer(*address);
450 ASSERT_MSG(buffer != nullptr, "Memory not accessible"); 496 ASSERT_MSG(buffer != nullptr, "Memory not accessible");
451 497
452 QFile file(filename); 498 QFile file{filename};
453 file.open(QIODevice::WriteOnly); 499 if (!file.open(QIODevice::WriteOnly)) {
454 int size = surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format); 500 QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename));
455 QByteArray data(reinterpret_cast<const char*>(buffer), size); 501 return;
456 file.write(data); 502 }
503
504 const int size =
505 surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format);
506 const QByteArray data(reinterpret_cast<const char*>(buffer), size);
507 if (file.write(data) != data.size()) {
508 QMessageBox::warning(
509 this, tr("Error"),
510 tr("Failed to completely write surface data to file. The saved data will "
511 "likely be corrupt."));
512 }
457 } else { 513 } else {
458 UNREACHABLE_MSG("Unhandled filter selected"); 514 UNREACHABLE_MSG("Unhandled filter selected");
459 } 515 }
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index c0e3c5fa9..4422a572b 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -329,6 +329,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
329 QMenu context_menu; 329 QMenu context_menu;
330 QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); 330 QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
331 QAction* open_lfs_location = context_menu.addAction(tr("Open Mod Data Location")); 331 QAction* open_lfs_location = context_menu.addAction(tr("Open Mod Data Location"));
332 QAction* open_transferable_shader_cache =
333 context_menu.addAction(tr("Open Transferable Shader Cache"));
332 context_menu.addSeparator(); 334 context_menu.addSeparator();
333 QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS")); 335 QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS"));
334 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); 336 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
@@ -344,6 +346,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
344 [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); }); 346 [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); });
345 connect(open_lfs_location, &QAction::triggered, 347 connect(open_lfs_location, &QAction::triggered,
346 [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); }); 348 [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); });
349 connect(open_transferable_shader_cache, &QAction::triggered,
350 [&]() { emit OpenTransferableShaderCacheRequested(program_id); });
347 connect(dump_romfs, &QAction::triggered, [&]() { emit DumpRomFSRequested(program_id, path); }); 351 connect(dump_romfs, &QAction::triggered, [&]() { emit DumpRomFSRequested(program_id, path); });
348 connect(copy_tid, &QAction::triggered, [&]() { emit CopyTIDRequested(program_id); }); 352 connect(copy_tid, &QAction::triggered, [&]() { emit CopyTIDRequested(program_id); });
349 connect(navigate_to_gamedb_entry, &QAction::triggered, 353 connect(navigate_to_gamedb_entry, &QAction::triggered,
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index b317eb2fc..8ea5cbaaa 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -66,6 +66,7 @@ signals:
66 void GameChosen(QString game_path); 66 void GameChosen(QString game_path);
67 void ShouldCancelWorker(); 67 void ShouldCancelWorker();
68 void OpenFolderRequested(u64 program_id, GameListOpenTarget target); 68 void OpenFolderRequested(u64 program_id, GameListOpenTarget target);
69 void OpenTransferableShaderCacheRequested(u64 program_id);
69 void DumpRomFSRequested(u64 program_id, const std::string& game_path); 70 void DumpRomFSRequested(u64 program_id, const std::string& game_path);
70 void CopyTIDRequested(u64 program_id); 71 void CopyTIDRequested(u64 program_id);
71 void NavigateToGamedbEntryRequested(u64 program_id, 72 void NavigateToGamedbEntryRequested(u64 program_id,
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 41ba3c4c6..2b9db69a3 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -37,14 +37,20 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
37#include <glad/glad.h> 37#include <glad/glad.h>
38 38
39#define QT_NO_OPENGL 39#define QT_NO_OPENGL
40#include <QClipboard>
41#include <QDesktopServices>
40#include <QDesktopWidget> 42#include <QDesktopWidget>
41#include <QDialogButtonBox> 43#include <QDialogButtonBox>
42#include <QFile> 44#include <QFile>
43#include <QFileDialog> 45#include <QFileDialog>
46#include <QInputDialog>
44#include <QMessageBox> 47#include <QMessageBox>
48#include <QProgressBar>
49#include <QProgressDialog>
50#include <QShortcut>
51#include <QStatusBar>
45#include <QtConcurrent/QtConcurrent> 52#include <QtConcurrent/QtConcurrent>
46#include <QtGui> 53
47#include <QtWidgets>
48#include <fmt/format.h> 54#include <fmt/format.h>
49#include "common/common_paths.h" 55#include "common/common_paths.h"
50#include "common/detached_tasks.h" 56#include "common/detached_tasks.h"
@@ -55,11 +61,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
55#include "common/microprofile.h" 61#include "common/microprofile.h"
56#include "common/scm_rev.h" 62#include "common/scm_rev.h"
57#include "common/scope_exit.h" 63#include "common/scope_exit.h"
58#include "common/string_util.h"
59#include "common/telemetry.h" 64#include "common/telemetry.h"
60#include "core/core.h" 65#include "core/core.h"
61#include "core/crypto/key_manager.h" 66#include "core/crypto/key_manager.h"
62#include "core/file_sys/bis_factory.h"
63#include "core/file_sys/card_image.h" 67#include "core/file_sys/card_image.h"
64#include "core/file_sys/content_archive.h" 68#include "core/file_sys/content_archive.h"
65#include "core/file_sys/control_metadata.h" 69#include "core/file_sys/control_metadata.h"
@@ -71,7 +75,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
71#include "core/frontend/applets/software_keyboard.h" 75#include "core/frontend/applets/software_keyboard.h"
72#include "core/hle/kernel/process.h" 76#include "core/hle/kernel/process.h"
73#include "core/hle/service/filesystem/filesystem.h" 77#include "core/hle/service/filesystem/filesystem.h"
74#include "core/hle/service/filesystem/fsp_ldr.h"
75#include "core/hle/service/nfp/nfp.h" 78#include "core/hle/service/nfp/nfp.h"
76#include "core/hle/service/sm/sm.h" 79#include "core/hle/service/sm/sm.h"
77#include "core/loader/loader.h" 80#include "core/loader/loader.h"
@@ -648,6 +651,8 @@ void GMainWindow::RestoreUIState() {
648void GMainWindow::ConnectWidgetEvents() { 651void GMainWindow::ConnectWidgetEvents() {
649 connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); 652 connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
650 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); 653 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
654 connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this,
655 &GMainWindow::OnTransferableShaderCacheOpenFile);
651 connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS); 656 connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
652 connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID); 657 connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
653 connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, 658 connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
@@ -1082,6 +1087,39 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
1082 QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); 1087 QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
1083} 1088}
1084 1089
1090void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
1091 ASSERT(program_id != 0);
1092
1093 const QString tranferable_shader_cache_folder_path =
1094 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) + "opengl" +
1095 DIR_SEP + "transferable";
1096
1097 const QString transferable_shader_cache_file_path =
1098 tranferable_shader_cache_folder_path + DIR_SEP +
1099 QString::fromStdString(fmt::format("{:016X}.bin", program_id));
1100
1101 if (!QFile::exists(transferable_shader_cache_file_path)) {
1102 QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"),
1103 tr("A shader cache for this title does not exist."));
1104 return;
1105 }
1106
1107 // Windows supports opening a folder with selecting a specified file in explorer. On every other
1108 // OS we just open the transferable shader cache folder without preselecting the transferable
1109 // shader cache file for the selected game.
1110#if defined(Q_OS_WIN)
1111 const QString explorer = QStringLiteral("explorer");
1112 QStringList param;
1113 if (!QFileInfo(transferable_shader_cache_file_path).isDir()) {
1114 param << QStringLiteral("/select,");
1115 }
1116 param << QDir::toNativeSeparators(transferable_shader_cache_file_path);
1117 QProcess::startDetached(explorer, param);
1118#else
1119 QDesktopServices::openUrl(QUrl::fromLocalFile(tranferable_shader_cache_folder_path));
1120#endif
1121}
1122
1085static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) { 1123static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) {
1086 std::size_t out = 0; 1124 std::size_t out = 0;
1087 1125
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index e07c892cf..7f3aa998e 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -176,6 +176,7 @@ private slots:
176 /// Called whenever a user selects a game in the game list widget. 176 /// Called whenever a user selects a game in the game list widget.
177 void OnGameListLoadFile(QString game_path); 177 void OnGameListLoadFile(QString game_path);
178 void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); 178 void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target);
179 void OnTransferableShaderCacheOpenFile(u64 program_id);
179 void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); 180 void OnGameListDumpRomFS(u64 program_id, const std::string& game_path);
180 void OnGameListCopyTID(u64 program_id); 181 void OnGameListCopyTID(u64 program_id);
181 void OnGameListNavigateToGamedbEntry(u64 program_id, 182 void OnGameListNavigateToGamedbEntry(u64 program_id,