summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt3
-rw-r--r--externals/CMakeLists.txt3
m---------externals/soundtouch0
-rw-r--r--src/audio_core/CMakeLists.txt3
-rw-r--r--src/audio_core/algorithm/filter.cpp12
-rw-r--r--src/audio_core/algorithm/filter.h4
-rw-r--r--src/audio_core/algorithm/interpolate.cpp12
-rw-r--r--src/audio_core/algorithm/interpolate.h4
-rw-r--r--src/audio_core/audio_out.cpp3
-rw-r--r--src/audio_core/audio_out.h2
-rw-r--r--src/audio_core/audio_renderer.cpp24
-rw-r--r--src/audio_core/audio_renderer.h8
-rw-r--r--src/audio_core/codec.cpp20
-rw-r--r--src/audio_core/codec.h2
-rw-r--r--src/audio_core/cubeb_sink.cpp129
-rw-r--r--src/audio_core/null_sink.h6
-rw-r--r--src/audio_core/sink_details.cpp2
-rw-r--r--src/audio_core/sink_details.h4
-rw-r--r--src/audio_core/sink_stream.h4
-rw-r--r--src/audio_core/stream.cpp11
-rw-r--r--src/audio_core/stream.h4
-rw-r--r--src/audio_core/time_stretch.cpp69
-rw-r--r--src/audio_core/time_stretch.h36
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/alignment.h4
-rw-r--r--src/common/bit_field.h4
-rw-r--r--src/common/bit_set.h6
-rw-r--r--src/common/cityhash.cpp22
-rw-r--r--src/common/cityhash.h12
-rw-r--r--src/common/file_util.cpp16
-rw-r--r--src/common/file_util.h25
-rw-r--r--src/common/hash.h4
-rw-r--r--src/common/hex_util.cpp4
-rw-r--r--src/common/hex_util.h12
-rw-r--r--src/common/logging/backend.cpp2
-rw-r--r--src/common/logging/backend.h2
-rw-r--r--src/common/logging/filter.cpp5
-rw-r--r--src/common/logging/filter.h2
-rw-r--r--src/common/memory_util.cpp12
-rw-r--r--src/common/memory_util.h12
-rw-r--r--src/common/misc.cpp2
-rw-r--r--src/common/ring_buffer.h111
-rw-r--r--src/common/string_util.cpp42
-rw-r--r--src/common/string_util.h4
-rw-r--r--src/common/thread.h10
-rw-r--r--src/common/x64/xbyak_abi.h21
-rw-r--r--src/common/x64/xbyak_util.h2
-rw-r--r--src/core/arm/arm_interface.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp27
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h22
-rw-r--r--src/core/arm/exclusive_monitor.h12
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp4
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h4
-rw-r--r--src/core/core.cpp14
-rw-r--r--src/core/core.h8
-rw-r--r--src/core/core_cpu.cpp4
-rw-r--r--src/core/core_cpu.h8
-rw-r--r--src/core/crypto/aes_util.cpp37
-rw-r--r--src/core/crypto/aes_util.h14
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp11
-rw-r--r--src/core/crypto/ctr_encryption_layer.h8
-rw-r--r--src/core/crypto/encryption_layer.cpp6
-rw-r--r--src/core/crypto/encryption_layer.h8
-rw-r--r--src/core/crypto/key_manager.cpp6
-rw-r--r--src/core/crypto/key_manager.h2
-rw-r--r--src/core/crypto/xts_encryption_layer.cpp4
-rw-r--r--src/core/crypto/xts_encryption_layer.h2
-rw-r--r--src/core/file_sys/card_image.cpp15
-rw-r--r--src/core/file_sys/content_archive.cpp6
-rw-r--r--src/core/file_sys/directory.h2
-rw-r--r--src/core/file_sys/nca_metadata.cpp4
-rw-r--r--src/core/file_sys/nca_patch.cpp34
-rw-r--r--src/core/file_sys/nca_patch.h12
-rw-r--r--src/core/file_sys/partition_filesystem.cpp10
-rw-r--r--src/core/file_sys/partition_filesystem.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp4
-rw-r--r--src/core/file_sys/program_metadata.cpp2
-rw-r--r--src/core/file_sys/registered_cache.cpp10
-rw-r--r--src/core/file_sys/romfs.cpp11
-rw-r--r--src/core/file_sys/vfs.cpp22
-rw-r--r--src/core/file_sys/vfs.h32
-rw-r--r--src/core/file_sys/vfs_concat.cpp10
-rw-r--r--src/core/file_sys/vfs_concat.h8
-rw-r--r--src/core/file_sys/vfs_offset.cpp24
-rw-r--r--src/core/file_sys/vfs_offset.h26
-rw-r--r--src/core/file_sys/vfs_real.cpp8
-rw-r--r--src/core/file_sys/vfs_real.h8
-rw-r--r--src/core/file_sys/xts_archive.cpp8
-rw-r--r--src/core/gdbstub/gdbstub.cpp14
-rw-r--r--src/core/hle/ipc.h4
-rw-r--r--src/core/hle/ipc_helpers.h12
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp25
-rw-r--r--src/core/hle/kernel/errors.h13
-rw-r--r--src/core/hle/kernel/handle_table.cpp2
-rw-r--r--src/core/hle/kernel/handle_table.h2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp27
-rw-r--r--src/core/hle/kernel/hle_ipc.h20
-rw-r--r--src/core/hle/kernel/process.cpp6
-rw-r--r--src/core/hle/kernel/process.h4
-rw-r--r--src/core/hle/kernel/shared_memory.h2
-rw-r--r--src/core/hle/kernel/svc.cpp134
-rw-r--r--src/core/hle/kernel/svc_wrap.h4
-rw-r--r--src/core/hle/kernel/thread.cpp6
-rw-r--r--src/core/hle/kernel/thread.h14
-rw-r--r--src/core/hle/kernel/vm_manager.cpp2
-rw-r--r--src/core/hle/kernel/vm_manager.h4
-rw-r--r--src/core/hle/kernel/wait_object.cpp2
-rw-r--r--src/core/hle/service/acc/acc_su.h6
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp21
-rw-r--r--src/core/hle/service/acc/profile_manager.h22
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/audio/audio.cpp1
-rw-r--r--src/core/hle/service/audio/audio.h4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp17
-rw-r--r--src/core/hle/service/audio/audout_u.h17
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.h1
-rw-r--r--src/core/hle/service/audio/hwopus.cpp11
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/lm/lm.cpp2
-rw-r--r--src/core/hle/service/ns/pl_u.cpp156
-rw-r--r--src/core/hle/service/ns/pl_u.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp6
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp2
-rw-r--r--src/core/hle/service/prepo/prepo.cpp63
-rw-r--r--src/core/hle/service/prepo/prepo.h16
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/service.h6
-rw-r--r--src/core/hle/service/set/set.cpp10
-rw-r--r--src/core/hle/service/set/set.h2
-rw-r--r--src/core/hle/service/sm/sm.cpp8
-rw-r--r--src/core/hle/service/sm/sm.h6
-rw-r--r--src/core/hle/service/spl/module.cpp2
-rw-r--r--src/core/hle/service/vi/vi.cpp19
-rw-r--r--src/core/hle/service/vi/vi.h5
-rw-r--r--src/core/loader/elf.cpp2
-rw-r--r--src/core/loader/loader.cpp2
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nso.cpp3
-rw-r--r--src/core/memory.cpp55
-rw-r--r--src/core/memory.h18
-rw-r--r--src/core/memory_hook.h4
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/telemetry_session.cpp3
-rw-r--r--src/core/tracer/recorder.cpp2
-rw-r--r--src/tests/CMakeLists.txt3
-rw-r--r--src/tests/common/ring_buffer.cpp130
-rw-r--r--src/tests/core/arm/arm_test_common.cpp9
-rw-r--r--src/tests/core/arm/arm_test_common.h8
-rw-r--r--src/tests/glad.cpp14
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/command_processor.cpp4
-rw-r--r--src/video_core/engines/fermi_2d.h2
-rw-r--r--src/video_core/engines/kepler_memory.cpp45
-rw-r--r--src/video_core/engines/kepler_memory.h90
-rw-r--r--src/video_core/engines/maxwell_3d.cpp13
-rw-r--r--src/video_core/engines/maxwell_3d.h28
-rw-r--r--src/video_core/engines/maxwell_dma.cpp2
-rw-r--r--src/video_core/engines/maxwell_dma.h2
-rw-r--r--src/video_core/engines/shader_bytecode.h102
-rw-r--r--src/video_core/gpu.cpp2
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/macro_interpreter.h2
-rw-r--r--src/video_core/renderer_base.cpp1
-rw-r--r--src/video_core/renderer_base.h1
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h16
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp55
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h9
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp95
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h58
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp206
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h18
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp6
-rw-r--r--src/video_core/textures/decoders.cpp53
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/configure_audio.cpp3
-rw-r--r--src/yuzu/configuration/configure_audio.ui10
-rw-r--r--src/yuzu/configuration/configure_gamelist.cpp103
-rw-r--r--src/yuzu/configuration/configure_gamelist.h7
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp16
-rw-r--r--src/yuzu/configuration/configure_graphics.h1
-rw-r--r--src/yuzu/configuration/configure_graphics.ui21
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints.cpp3
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp4
-rw-r--r--src/yuzu/debugger/wait_tree.cpp60
-rw-r--r--src/yuzu/game_list.cpp8
-rw-r--r--src/yuzu/game_list_p.h10
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu/util/util.cpp3
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/default_ini.h6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp4
201 files changed, 2181 insertions, 1090 deletions
diff --git a/.gitmodules b/.gitmodules
index 4f4e8690b..e73ca99e3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -31,3 +31,6 @@
31[submodule "opus"] 31[submodule "opus"]
32 path = externals/opus 32 path = externals/opus
33 url = https://github.com/ogniK5377/opus.git 33 url = https://github.com/ogniK5377/opus.git
34[submodule "soundtouch"]
35 path = externals/soundtouch
36 url = https://github.com/citra-emu/ext-soundtouch.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0f32ecfba..500d099fc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -431,6 +431,9 @@ enable_testing()
431add_subdirectory(externals) 431add_subdirectory(externals)
432add_subdirectory(src) 432add_subdirectory(src)
433 433
434# Set yuzu project as default StartUp Project in Visual Studio
435set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
436
434 437
435# Installation instructions 438# Installation instructions
436# ========================= 439# =========================
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 3d8e10c2b..53dcf1f1a 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -50,6 +50,9 @@ add_subdirectory(open_source_archives EXCLUDE_FROM_ALL)
50add_library(unicorn-headers INTERFACE) 50add_library(unicorn-headers INTERFACE)
51target_include_directories(unicorn-headers INTERFACE ./unicorn/include) 51target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
52 52
53# SoundTouch
54add_subdirectory(soundtouch)
55
53# Xbyak 56# Xbyak
54if (ARCHITECTURE_x86_64) 57if (ARCHITECTURE_x86_64)
55 # Defined before "dynarmic" above 58 # Defined before "dynarmic" above
diff --git a/externals/soundtouch b/externals/soundtouch
new file mode 160000
Subproject 060181eaf273180d3a7e87349895bd0cb6ccbf4
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 82e4850f7..c381dbe1d 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -17,6 +17,8 @@ add_library(audio_core STATIC
17 sink_stream.h 17 sink_stream.h
18 stream.cpp 18 stream.cpp
19 stream.h 19 stream.h
20 time_stretch.cpp
21 time_stretch.h
20 22
21 $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h> 23 $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h>
22) 24)
@@ -24,6 +26,7 @@ add_library(audio_core STATIC
24create_target_directory_groups(audio_core) 26create_target_directory_groups(audio_core)
25 27
26target_link_libraries(audio_core PUBLIC common core) 28target_link_libraries(audio_core PUBLIC common core)
29target_link_libraries(audio_core PRIVATE SoundTouch)
27 30
28if(ENABLE_CUBEB) 31if(ENABLE_CUBEB)
29 target_link_libraries(audio_core PRIVATE cubeb) 32 target_link_libraries(audio_core PRIVATE cubeb)
diff --git a/src/audio_core/algorithm/filter.cpp b/src/audio_core/algorithm/filter.cpp
index 9fcd0614d..f65bf64f7 100644
--- a/src/audio_core/algorithm/filter.cpp
+++ b/src/audio_core/algorithm/filter.cpp
@@ -35,12 +35,12 @@ Filter::Filter(double a0, double a1, double a2, double b0, double b1, double b2)
35 : a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {} 35 : a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {}
36 36
37void Filter::Process(std::vector<s16>& signal) { 37void Filter::Process(std::vector<s16>& signal) {
38 const size_t num_frames = signal.size() / 2; 38 const std::size_t num_frames = signal.size() / 2;
39 for (size_t i = 0; i < num_frames; i++) { 39 for (std::size_t i = 0; i < num_frames; i++) {
40 std::rotate(in.begin(), in.end() - 1, in.end()); 40 std::rotate(in.begin(), in.end() - 1, in.end());
41 std::rotate(out.begin(), out.end() - 1, out.end()); 41 std::rotate(out.begin(), out.end() - 1, out.end());
42 42
43 for (size_t ch = 0; ch < channel_count; ch++) { 43 for (std::size_t ch = 0; ch < channel_count; ch++) {
44 in[0][ch] = signal[i * channel_count + ch]; 44 in[0][ch] = signal[i * channel_count + ch];
45 45
46 out[0][ch] = b0 * in[0][ch] + b1 * in[1][ch] + b2 * in[2][ch] - a1 * out[1][ch] - 46 out[0][ch] = b0 * in[0][ch] + b1 * in[1][ch] + b2 * in[2][ch] - a1 * out[1][ch] -
@@ -54,14 +54,14 @@ void Filter::Process(std::vector<s16>& signal) {
54/// Calculates the appropriate Q for each biquad in a cascading filter. 54/// Calculates the appropriate Q for each biquad in a cascading filter.
55/// @param total_count The total number of biquads to be cascaded. 55/// @param total_count The total number of biquads to be cascaded.
56/// @param index 0-index of the biquad to calculate the Q value for. 56/// @param index 0-index of the biquad to calculate the Q value for.
57static double CascadingBiquadQ(size_t total_count, size_t index) { 57static double CascadingBiquadQ(std::size_t total_count, std::size_t index) {
58 const double pole = M_PI * (2 * index + 1) / (4.0 * total_count); 58 const double pole = M_PI * (2 * index + 1) / (4.0 * total_count);
59 return 1.0 / (2.0 * std::cos(pole)); 59 return 1.0 / (2.0 * std::cos(pole));
60} 60}
61 61
62CascadingFilter CascadingFilter::LowPass(double cutoff, size_t cascade_size) { 62CascadingFilter CascadingFilter::LowPass(double cutoff, std::size_t cascade_size) {
63 std::vector<Filter> cascade(cascade_size); 63 std::vector<Filter> cascade(cascade_size);
64 for (size_t i = 0; i < cascade_size; i++) { 64 for (std::size_t i = 0; i < cascade_size; i++) {
65 cascade[i] = Filter::LowPass(cutoff, CascadingBiquadQ(cascade_size, i)); 65 cascade[i] = Filter::LowPass(cutoff, CascadingBiquadQ(cascade_size, i));
66 } 66 }
67 return CascadingFilter{std::move(cascade)}; 67 return CascadingFilter{std::move(cascade)};
diff --git a/src/audio_core/algorithm/filter.h b/src/audio_core/algorithm/filter.h
index a41beef98..3546d149b 100644
--- a/src/audio_core/algorithm/filter.h
+++ b/src/audio_core/algorithm/filter.h
@@ -30,7 +30,7 @@ public:
30 void Process(std::vector<s16>& signal); 30 void Process(std::vector<s16>& signal);
31 31
32private: 32private:
33 static constexpr size_t channel_count = 2; 33 static constexpr std::size_t channel_count = 2;
34 34
35 /// Coefficients are in normalized form (a0 = 1.0). 35 /// Coefficients are in normalized form (a0 = 1.0).
36 double a1, a2, b0, b1, b2; 36 double a1, a2, b0, b1, b2;
@@ -46,7 +46,7 @@ public:
46 /// Creates a cascading low-pass filter. 46 /// Creates a cascading low-pass filter.
47 /// @param cutoff Determines the cutoff frequency. A value from 0.0 to 1.0. 47 /// @param cutoff Determines the cutoff frequency. A value from 0.0 to 1.0.
48 /// @param cascade_size Number of biquads in cascade. 48 /// @param cascade_size Number of biquads in cascade.
49 static CascadingFilter LowPass(double cutoff, size_t cascade_size); 49 static CascadingFilter LowPass(double cutoff, std::size_t cascade_size);
50 50
51 /// Passthrough. 51 /// Passthrough.
52 CascadingFilter(); 52 CascadingFilter();
diff --git a/src/audio_core/algorithm/interpolate.cpp b/src/audio_core/algorithm/interpolate.cpp
index 11459821f..3aea9b0f2 100644
--- a/src/audio_core/algorithm/interpolate.cpp
+++ b/src/audio_core/algorithm/interpolate.cpp
@@ -14,7 +14,7 @@
14namespace AudioCore { 14namespace AudioCore {
15 15
16/// The Lanczos kernel 16/// The Lanczos kernel
17static double Lanczos(size_t a, double x) { 17static double Lanczos(std::size_t a, double x) {
18 if (x == 0.0) 18 if (x == 0.0)
19 return 1.0; 19 return 1.0;
20 const double px = M_PI * x; 20 const double px = M_PI * x;
@@ -37,15 +37,15 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
37 } 37 }
38 state.nyquist.Process(input); 38 state.nyquist.Process(input);
39 39
40 constexpr size_t taps = InterpolationState::lanczos_taps; 40 constexpr std::size_t taps = InterpolationState::lanczos_taps;
41 const size_t num_frames = input.size() / 2; 41 const std::size_t num_frames = input.size() / 2;
42 42
43 std::vector<s16> output; 43 std::vector<s16> output;
44 output.reserve(static_cast<size_t>(input.size() / ratio + 4)); 44 output.reserve(static_cast<std::size_t>(input.size() / ratio + 4));
45 45
46 double& pos = state.position; 46 double& pos = state.position;
47 auto& h = state.history; 47 auto& h = state.history;
48 for (size_t i = 0; i < num_frames; ++i) { 48 for (std::size_t i = 0; i < num_frames; ++i) {
49 std::rotate(h.begin(), h.end() - 1, h.end()); 49 std::rotate(h.begin(), h.end() - 1, h.end());
50 h[0][0] = input[i * 2 + 0]; 50 h[0][0] = input[i * 2 + 0];
51 h[0][1] = input[i * 2 + 1]; 51 h[0][1] = input[i * 2 + 1];
@@ -53,7 +53,7 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
53 while (pos <= 1.0) { 53 while (pos <= 1.0) {
54 double l = 0.0; 54 double l = 0.0;
55 double r = 0.0; 55 double r = 0.0;
56 for (size_t j = 0; j < h.size(); j++) { 56 for (std::size_t j = 0; j < h.size(); j++) {
57 l += Lanczos(taps, pos + j - taps + 1) * h[j][0]; 57 l += Lanczos(taps, pos + j - taps + 1) * h[j][0];
58 r += Lanczos(taps, pos + j - taps + 1) * h[j][1]; 58 r += Lanczos(taps, pos + j - taps + 1) * h[j][1];
59 } 59 }
diff --git a/src/audio_core/algorithm/interpolate.h b/src/audio_core/algorithm/interpolate.h
index c79c2eef4..edbd6460f 100644
--- a/src/audio_core/algorithm/interpolate.h
+++ b/src/audio_core/algorithm/interpolate.h
@@ -12,8 +12,8 @@
12namespace AudioCore { 12namespace AudioCore {
13 13
14struct InterpolationState { 14struct InterpolationState {
15 static constexpr size_t lanczos_taps = 4; 15 static constexpr std::size_t lanczos_taps = 4;
16 static constexpr size_t history_size = lanczos_taps * 2 - 1; 16 static constexpr std::size_t history_size = lanczos_taps * 2 - 1;
17 17
18 double current_ratio = 0.0; 18 double current_ratio = 0.0;
19 CascadingFilter nyquist; 19 CascadingFilter nyquist;
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
index 12632a95c..0c8f5b18e 100644
--- a/src/audio_core/audio_out.cpp
+++ b/src/audio_core/audio_out.cpp
@@ -39,7 +39,8 @@ StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&&
39 sink->AcquireSinkStream(sample_rate, num_channels, name), std::move(name)); 39 sink->AcquireSinkStream(sample_rate, num_channels, name), std::move(name));
40} 40}
41 41
42std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count) { 42std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream,
43 std::size_t max_count) {
43 return stream->GetTagsAndReleaseBuffers(max_count); 44 return stream->GetTagsAndReleaseBuffers(max_count);
44} 45}
45 46
diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h
index 39b7e656b..df9607ac7 100644
--- a/src/audio_core/audio_out.h
+++ b/src/audio_core/audio_out.h
@@ -25,7 +25,7 @@ public:
25 Stream::ReleaseCallback&& release_callback); 25 Stream::ReleaseCallback&& release_callback);
26 26
27 /// Returns a vector of recently released buffers specified by tag for the specified stream 27 /// Returns a vector of recently released buffers specified by tag for the specified stream
28 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count); 28 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count);
29 29
30 /// Starts an audio stream for playback 30 /// Starts an audio stream for playback
31 void StartStream(StreamPtr stream); 31 void StartStream(StreamPtr stream);
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index a75cd3be5..ed3b7defc 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -52,8 +52,8 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
52 memory_pool_count * sizeof(MemoryPoolInfo)); 52 memory_pool_count * sizeof(MemoryPoolInfo));
53 53
54 // Copy VoiceInfo structs 54 // Copy VoiceInfo structs
55 size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size + 55 std::size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size +
56 config.voice_resource_size}; 56 config.voice_resource_size};
57 for (auto& voice : voices) { 57 for (auto& voice : voices) {
58 std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo)); 58 std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo));
59 offset += sizeof(VoiceInfo); 59 offset += sizeof(VoiceInfo);
@@ -72,7 +72,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
72 72
73 // Update memory pool state 73 // Update memory pool state
74 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count); 74 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
75 for (size_t index = 0; index < memory_pool.size(); ++index) { 75 for (std::size_t index = 0; index < memory_pool.size(); ++index) {
76 if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) { 76 if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
77 memory_pool[index].state = MemoryPoolStates::Attached; 77 memory_pool[index].state = MemoryPoolStates::Attached;
78 } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) { 78 } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
@@ -93,7 +93,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
93 response_data.memory_pools_size); 93 response_data.memory_pools_size);
94 94
95 // Copy output voice status 95 // Copy output voice status
96 size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size}; 96 std::size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size};
97 for (const auto& voice : voices) { 97 for (const auto& voice : voices) {
98 std::memcpy(output_params.data() + voice_out_status_offset, &voice.GetOutStatus(), 98 std::memcpy(output_params.data() + voice_out_status_offset, &voice.GetOutStatus(),
99 sizeof(VoiceOutStatus)); 99 sizeof(VoiceOutStatus));
@@ -103,12 +103,12 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
103 return output_params; 103 return output_params;
104} 104}
105 105
106void AudioRenderer::VoiceState::SetWaveIndex(size_t index) { 106void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
107 wave_index = index & 3; 107 wave_index = index & 3;
108 is_refresh_pending = true; 108 is_refresh_pending = true;
109} 109}
110 110
111std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(size_t sample_count) { 111std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count) {
112 if (!IsPlaying()) { 112 if (!IsPlaying()) {
113 return {}; 113 return {};
114 } 114 }
@@ -117,9 +117,9 @@ std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(size_t sample_count)
117 RefreshBuffer(); 117 RefreshBuffer();
118 } 118 }
119 119
120 const size_t max_size{samples.size() - offset}; 120 const std::size_t max_size{samples.size() - offset};
121 const size_t dequeue_offset{offset}; 121 const std::size_t dequeue_offset{offset};
122 size_t size{sample_count * STREAM_NUM_CHANNELS}; 122 std::size_t size{sample_count * STREAM_NUM_CHANNELS};
123 if (size > max_size) { 123 if (size > max_size) {
124 size = max_size; 124 size = max_size;
125 } 125 }
@@ -184,7 +184,7 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
184 case 1: 184 case 1:
185 // 1 channel is upsampled to 2 channel 185 // 1 channel is upsampled to 2 channel
186 samples.resize(new_samples.size() * 2); 186 samples.resize(new_samples.size() * 2);
187 for (size_t index = 0; index < new_samples.size(); ++index) { 187 for (std::size_t index = 0; index < new_samples.size(); ++index) {
188 samples[index * 2] = new_samples[index]; 188 samples[index * 2] = new_samples[index];
189 samples[index * 2 + 1] = new_samples[index]; 189 samples[index * 2 + 1] = new_samples[index];
190 } 190 }
@@ -210,7 +210,7 @@ static constexpr s16 ClampToS16(s32 value) {
210} 210}
211 211
212void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { 212void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
213 constexpr size_t BUFFER_SIZE{512}; 213 constexpr std::size_t BUFFER_SIZE{512};
214 std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels()); 214 std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels());
215 215
216 for (auto& voice : voices) { 216 for (auto& voice : voices) {
@@ -218,7 +218,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
218 continue; 218 continue;
219 } 219 }
220 220
221 size_t offset{}; 221 std::size_t offset{};
222 s64 samples_remaining{BUFFER_SIZE}; 222 s64 samples_remaining{BUFFER_SIZE};
223 while (samples_remaining > 0) { 223 while (samples_remaining > 0) {
224 const std::vector<s16> samples{voice.DequeueSamples(samples_remaining)}; 224 const std::vector<s16> samples{voice.DequeueSamples(samples_remaining)};
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 6d069d693..c8d2cd188 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -184,16 +184,16 @@ private:
184 return info; 184 return info;
185 } 185 }
186 186
187 void SetWaveIndex(size_t index); 187 void SetWaveIndex(std::size_t index);
188 std::vector<s16> DequeueSamples(size_t sample_count); 188 std::vector<s16> DequeueSamples(std::size_t sample_count);
189 void UpdateState(); 189 void UpdateState();
190 void RefreshBuffer(); 190 void RefreshBuffer();
191 191
192 private: 192 private:
193 bool is_in_use{}; 193 bool is_in_use{};
194 bool is_refresh_pending{}; 194 bool is_refresh_pending{};
195 size_t wave_index{}; 195 std::size_t wave_index{};
196 size_t offset{}; 196 std::size_t offset{};
197 Codec::ADPCMState adpcm_state{}; 197 Codec::ADPCMState adpcm_state{};
198 InterpolationState interp_state{}; 198 InterpolationState interp_state{};
199 std::vector<s16> samples; 199 std::vector<s16> samples;
diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp
index c3021403f..454de798b 100644
--- a/src/audio_core/codec.cpp
+++ b/src/audio_core/codec.cpp
@@ -8,27 +8,27 @@
8 8
9namespace AudioCore::Codec { 9namespace AudioCore::Codec {
10 10
11std::vector<s16> DecodeADPCM(const u8* const data, size_t size, const ADPCM_Coeff& coeff, 11std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM_Coeff& coeff,
12 ADPCMState& state) { 12 ADPCMState& state) {
13 // GC-ADPCM with scale factor and variable coefficients. 13 // GC-ADPCM with scale factor and variable coefficients.
14 // Frames are 8 bytes long containing 14 samples each. 14 // Frames are 8 bytes long containing 14 samples each.
15 // Samples are 4 bits (one nibble) long. 15 // Samples are 4 bits (one nibble) long.
16 16
17 constexpr size_t FRAME_LEN = 8; 17 constexpr std::size_t FRAME_LEN = 8;
18 constexpr size_t SAMPLES_PER_FRAME = 14; 18 constexpr std::size_t SAMPLES_PER_FRAME = 14;
19 constexpr std::array<int, 16> SIGNED_NIBBLES = { 19 constexpr std::array<int, 16> SIGNED_NIBBLES = {
20 {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}}; 20 {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}};
21 21
22 const size_t sample_count = (size / FRAME_LEN) * SAMPLES_PER_FRAME; 22 const std::size_t sample_count = (size / FRAME_LEN) * SAMPLES_PER_FRAME;
23 const size_t ret_size = 23 const std::size_t ret_size =
24 sample_count % 2 == 0 ? sample_count : sample_count + 1; // Ensure multiple of two. 24 sample_count % 2 == 0 ? sample_count : sample_count + 1; // Ensure multiple of two.
25 std::vector<s16> ret(ret_size); 25 std::vector<s16> ret(ret_size);
26 26
27 int yn1 = state.yn1, yn2 = state.yn2; 27 int yn1 = state.yn1, yn2 = state.yn2;
28 28
29 const size_t NUM_FRAMES = 29 const std::size_t NUM_FRAMES =
30 (sample_count + (SAMPLES_PER_FRAME - 1)) / SAMPLES_PER_FRAME; // Round up. 30 (sample_count + (SAMPLES_PER_FRAME - 1)) / SAMPLES_PER_FRAME; // Round up.
31 for (size_t framei = 0; framei < NUM_FRAMES; framei++) { 31 for (std::size_t framei = 0; framei < NUM_FRAMES; framei++) {
32 const int frame_header = data[framei * FRAME_LEN]; 32 const int frame_header = data[framei * FRAME_LEN];
33 const int scale = 1 << (frame_header & 0xF); 33 const int scale = 1 << (frame_header & 0xF);
34 const int idx = (frame_header >> 4) & 0x7; 34 const int idx = (frame_header >> 4) & 0x7;
@@ -53,9 +53,9 @@ std::vector<s16> DecodeADPCM(const u8* const data, size_t size, const ADPCM_Coef
53 return static_cast<s16>(val); 53 return static_cast<s16>(val);
54 }; 54 };
55 55
56 size_t outputi = framei * SAMPLES_PER_FRAME; 56 std::size_t outputi = framei * SAMPLES_PER_FRAME;
57 size_t datai = framei * FRAME_LEN + 1; 57 std::size_t datai = framei * FRAME_LEN + 1;
58 for (size_t i = 0; i < SAMPLES_PER_FRAME && outputi < sample_count; i += 2) { 58 for (std::size_t i = 0; i < SAMPLES_PER_FRAME && outputi < sample_count; i += 2) {
59 const s16 sample1 = decode_sample(SIGNED_NIBBLES[data[datai] >> 4]); 59 const s16 sample1 = decode_sample(SIGNED_NIBBLES[data[datai] >> 4]);
60 ret[outputi] = sample1; 60 ret[outputi] = sample1;
61 outputi++; 61 outputi++;
diff --git a/src/audio_core/codec.h b/src/audio_core/codec.h
index 3f845c42c..ef2ce01a8 100644
--- a/src/audio_core/codec.h
+++ b/src/audio_core/codec.h
@@ -38,7 +38,7 @@ using ADPCM_Coeff = std::array<s16, 16>;
38 * @param state ADPCM state, this is updated with new state 38 * @param state ADPCM state, this is updated with new state
39 * @return Decoded stereo signed PCM16 data, sample_count in length 39 * @return Decoded stereo signed PCM16 data, sample_count in length
40 */ 40 */
41std::vector<s16> DecodeADPCM(const u8* const data, size_t size, const ADPCM_Coeff& coeff, 41std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM_Coeff& coeff,
42 ADPCMState& state); 42 ADPCMState& state);
43 43
44}; // namespace AudioCore::Codec 44}; // namespace AudioCore::Codec
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 5a1177d0c..392039688 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -3,27 +3,23 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <atomic>
6#include <cstring> 7#include <cstring>
7#include <mutex>
8
9#include "audio_core/cubeb_sink.h" 8#include "audio_core/cubeb_sink.h"
10#include "audio_core/stream.h" 9#include "audio_core/stream.h"
10#include "audio_core/time_stretch.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/ring_buffer.h"
13#include "core/settings.h"
12 14
13namespace AudioCore { 15namespace AudioCore {
14 16
15class SinkStreamImpl final : public SinkStream { 17class CubebSinkStream final : public SinkStream {
16public: 18public:
17 SinkStreamImpl(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device, 19 CubebSinkStream(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
18 const std::string& name) 20 const std::string& name)
19 : ctx{ctx}, num_channels{num_channels_} { 21 : ctx{ctx}, num_channels{std::min(num_channels_, 2u)}, time_stretch{sample_rate,
20 22 num_channels} {
21 if (num_channels == 6) {
22 // 6-channel audio does not seem to work with cubeb + SDL, so we downsample this to 2
23 // channel for now
24 is_6_channel = true;
25 num_channels = 2;
26 }
27 23
28 cubeb_stream_params params{}; 24 cubeb_stream_params params{};
29 params.rate = sample_rate; 25 params.rate = sample_rate;
@@ -38,7 +34,7 @@ public:
38 34
39 if (cubeb_stream_init(ctx, &stream_backend, name.c_str(), nullptr, nullptr, output_device, 35 if (cubeb_stream_init(ctx, &stream_backend, name.c_str(), nullptr, nullptr, output_device,
40 &params, std::max(512u, minimum_latency), 36 &params, std::max(512u, minimum_latency),
41 &SinkStreamImpl::DataCallback, &SinkStreamImpl::StateCallback, 37 &CubebSinkStream::DataCallback, &CubebSinkStream::StateCallback,
42 this) != CUBEB_OK) { 38 this) != CUBEB_OK) {
43 LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream"); 39 LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream");
44 return; 40 return;
@@ -50,7 +46,7 @@ public:
50 } 46 }
51 } 47 }
52 48
53 ~SinkStreamImpl() { 49 ~CubebSinkStream() {
54 if (!ctx) { 50 if (!ctx) {
55 return; 51 return;
56 } 52 }
@@ -62,27 +58,32 @@ public:
62 cubeb_stream_destroy(stream_backend); 58 cubeb_stream_destroy(stream_backend);
63 } 59 }
64 60
65 void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) override { 61 void EnqueueSamples(u32 source_num_channels, const std::vector<s16>& samples) override {
66 if (!ctx) { 62 if (source_num_channels > num_channels) {
63 // Downsample 6 channels to 2
64 std::vector<s16> buf;
65 buf.reserve(samples.size() * num_channels / source_num_channels);
66 for (std::size_t i = 0; i < samples.size(); i += source_num_channels) {
67 for (std::size_t ch = 0; ch < num_channels; ch++) {
68 buf.push_back(samples[i + ch]);
69 }
70 }
71 queue.Push(buf);
67 return; 72 return;
68 } 73 }
69 74
70 std::lock_guard lock{queue_mutex}; 75 queue.Push(samples);
76 }
71 77
72 queue.reserve(queue.size() + samples.size() * GetNumChannels()); 78 std::size_t SamplesInQueue(u32 num_channels) const override {
79 if (!ctx)
80 return 0;
73 81
74 if (is_6_channel) { 82 return queue.Size() / num_channels;
75 // Downsample 6 channels to 2 83 }
76 const size_t sample_count_copy_size = samples.size() * 2; 84
77 queue.reserve(sample_count_copy_size); 85 void Flush() override {
78 for (size_t i = 0; i < samples.size(); i += num_channels) { 86 should_flush = true;
79 queue.push_back(samples[i]);
80 queue.push_back(samples[i + 1]);
81 }
82 } else {
83 // Copy as-is
84 std::copy(samples.begin(), samples.end(), std::back_inserter(queue));
85 }
86 } 87 }
87 88
88 u32 GetNumChannels() const { 89 u32 GetNumChannels() const {
@@ -95,10 +96,11 @@ private:
95 cubeb* ctx{}; 96 cubeb* ctx{};
96 cubeb_stream* stream_backend{}; 97 cubeb_stream* stream_backend{};
97 u32 num_channels{}; 98 u32 num_channels{};
98 bool is_6_channel{};
99 99
100 std::mutex queue_mutex; 100 Common::RingBuffer<s16, 0x10000> queue;
101 std::vector<s16> queue; 101 std::array<s16, 2> last_frame;
102 std::atomic<bool> should_flush{};
103 TimeStretcher time_stretch;
102 104
103 static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, 105 static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
104 void* output_buffer, long num_frames); 106 void* output_buffer, long num_frames);
@@ -117,10 +119,10 @@ CubebSink::CubebSink(std::string target_device_name) {
117 LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported"); 119 LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
118 } else { 120 } else {
119 const auto collection_end{collection.device + collection.count}; 121 const auto collection_end{collection.device + collection.count};
120 const auto device{std::find_if(collection.device, collection_end, 122 const auto device{
121 [&](const cubeb_device_info& device) { 123 std::find_if(collection.device, collection_end, [&](const cubeb_device_info& info) {
122 return target_device_name == device.friendly_name; 124 return target_device_name == info.friendly_name;
123 })}; 125 })};
124 if (device != collection_end) { 126 if (device != collection_end) {
125 output_device = device->devid; 127 output_device = device->devid;
126 } 128 }
@@ -144,44 +146,59 @@ CubebSink::~CubebSink() {
144SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels, 146SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
145 const std::string& name) { 147 const std::string& name) {
146 sink_streams.push_back( 148 sink_streams.push_back(
147 std::make_unique<SinkStreamImpl>(ctx, sample_rate, num_channels, output_device, name)); 149 std::make_unique<CubebSinkStream>(ctx, sample_rate, num_channels, output_device, name));
148 return *sink_streams.back(); 150 return *sink_streams.back();
149} 151}
150 152
151long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, 153long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
152 void* output_buffer, long num_frames) { 154 void* output_buffer, long num_frames) {
153 SinkStreamImpl* impl = static_cast<SinkStreamImpl*>(user_data); 155 CubebSinkStream* impl = static_cast<CubebSinkStream*>(user_data);
154 u8* buffer = reinterpret_cast<u8*>(output_buffer); 156 u8* buffer = reinterpret_cast<u8*>(output_buffer);
155 157
156 if (!impl) { 158 if (!impl) {
157 return {}; 159 return {};
158 } 160 }
159 161
160 std::lock_guard lock{impl->queue_mutex}; 162 const std::size_t num_channels = impl->GetNumChannels();
161 163 const std::size_t samples_to_write = num_channels * num_frames;
162 const size_t frames_to_write{ 164 std::size_t samples_written;
163 std::min(impl->queue.size() / impl->GetNumChannels(), static_cast<size_t>(num_frames))}; 165
166 if (Settings::values.enable_audio_stretching) {
167 const std::vector<s16> in{impl->queue.Pop()};
168 const std::size_t num_in{in.size() / num_channels};
169 s16* const out{reinterpret_cast<s16*>(buffer)};
170 const std::size_t out_frames =
171 impl->time_stretch.Process(in.data(), num_in, out, num_frames);
172 samples_written = out_frames * num_channels;
173
174 if (impl->should_flush) {
175 impl->time_stretch.Flush();
176 impl->should_flush = false;
177 }
178 } else {
179 samples_written = impl->queue.Pop(buffer, samples_to_write);
180 }
164 181
165 memcpy(buffer, impl->queue.data(), frames_to_write * sizeof(s16) * impl->GetNumChannels()); 182 if (samples_written >= num_channels) {
166 impl->queue.erase(impl->queue.begin(), 183 std::memcpy(&impl->last_frame[0], buffer + (samples_written - num_channels) * sizeof(s16),
167 impl->queue.begin() + frames_to_write * impl->GetNumChannels()); 184 num_channels * sizeof(s16));
185 }
168 186
169 if (frames_to_write < num_frames) { 187 // Fill the rest of the frames with last_frame
170 // Fill the rest of the frames with silence 188 for (std::size_t i = samples_written; i < samples_to_write; i += num_channels) {
171 memset(buffer + frames_to_write * sizeof(s16) * impl->GetNumChannels(), 0, 189 std::memcpy(buffer + i * sizeof(s16), &impl->last_frame[0], num_channels * sizeof(s16));
172 (num_frames - frames_to_write) * sizeof(s16) * impl->GetNumChannels());
173 } 190 }
174 191
175 return num_frames; 192 return num_frames;
176} 193}
177 194
178void SinkStreamImpl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} 195void CubebSinkStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
179 196
180std::vector<std::string> ListCubebSinkDevices() { 197std::vector<std::string> ListCubebSinkDevices() {
181 std::vector<std::string> device_list; 198 std::vector<std::string> device_list;
182 cubeb* ctx; 199 cubeb* ctx;
183 200
184 if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) { 201 if (cubeb_init(&ctx, "yuzu Device Enumerator", nullptr) != CUBEB_OK) {
185 LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); 202 LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
186 return {}; 203 return {};
187 } 204 }
@@ -190,7 +207,7 @@ std::vector<std::string> ListCubebSinkDevices() {
190 if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) { 207 if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
191 LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported"); 208 LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
192 } else { 209 } else {
193 for (size_t i = 0; i < collection.count; i++) { 210 for (std::size_t i = 0; i < collection.count; i++) {
194 const cubeb_device_info& device = collection.device[i]; 211 const cubeb_device_info& device = collection.device[i];
195 if (device.friendly_name) { 212 if (device.friendly_name) {
196 device_list.emplace_back(device.friendly_name); 213 device_list.emplace_back(device.friendly_name);
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
index f235d93e5..a78d78893 100644
--- a/src/audio_core/null_sink.h
+++ b/src/audio_core/null_sink.h
@@ -21,6 +21,12 @@ public:
21private: 21private:
22 struct NullSinkStreamImpl final : SinkStream { 22 struct NullSinkStreamImpl final : SinkStream {
23 void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {} 23 void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {}
24
25 std::size_t SamplesInQueue(u32 /*num_channels*/) const override {
26 return 0;
27 }
28
29 void Flush() override {}
24 } null_sink_stream; 30 } null_sink_stream;
25}; 31};
26 32
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
index 955ba20fb..67cf1f3b2 100644
--- a/src/audio_core/sink_details.cpp
+++ b/src/audio_core/sink_details.cpp
@@ -24,7 +24,7 @@ const std::vector<SinkDetails> g_sink_details = {
24 [] { return std::vector<std::string>{"null"}; }}, 24 [] { return std::vector<std::string>{"null"}; }},
25}; 25};
26 26
27const SinkDetails& GetSinkDetails(std::string sink_id) { 27const SinkDetails& GetSinkDetails(std::string_view sink_id) {
28 auto iter = 28 auto iter =
29 std::find_if(g_sink_details.begin(), g_sink_details.end(), 29 std::find_if(g_sink_details.begin(), g_sink_details.end(),
30 [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; }); 30 [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
index ea666c554..03534b187 100644
--- a/src/audio_core/sink_details.h
+++ b/src/audio_core/sink_details.h
@@ -6,6 +6,8 @@
6 6
7#include <functional> 7#include <functional>
8#include <memory> 8#include <memory>
9#include <string>
10#include <string_view>
9#include <utility> 11#include <utility>
10#include <vector> 12#include <vector>
11 13
@@ -30,6 +32,6 @@ struct SinkDetails {
30 32
31extern const std::vector<SinkDetails> g_sink_details; 33extern const std::vector<SinkDetails> g_sink_details;
32 34
33const SinkDetails& GetSinkDetails(std::string sink_id); 35const SinkDetails& GetSinkDetails(std::string_view sink_id);
34 36
35} // namespace AudioCore 37} // namespace AudioCore
diff --git a/src/audio_core/sink_stream.h b/src/audio_core/sink_stream.h
index 41b6736d8..4309ad094 100644
--- a/src/audio_core/sink_stream.h
+++ b/src/audio_core/sink_stream.h
@@ -25,6 +25,10 @@ public:
25 * @param samples Samples in interleaved stereo PCM16 format. 25 * @param samples Samples in interleaved stereo PCM16 format.
26 */ 26 */
27 virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0; 27 virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0;
28
29 virtual std::size_t SamplesInQueue(u32 num_channels) const = 0;
30
31 virtual void Flush() = 0;
28}; 32};
29 33
30using SinkStreamPtr = std::unique_ptr<SinkStream>; 34using SinkStreamPtr = std::unique_ptr<SinkStream>;
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index dbae75d8c..386f2ec66 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -17,7 +17,7 @@
17 17
18namespace AudioCore { 18namespace AudioCore {
19 19
20constexpr size_t MaxAudioBufferCount{32}; 20constexpr std::size_t MaxAudioBufferCount{32};
21 21
22u32 Stream::GetNumChannels() const { 22u32 Stream::GetNumChannels() const {
23 switch (format) { 23 switch (format) {
@@ -52,7 +52,7 @@ void Stream::Stop() {
52} 52}
53 53
54s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { 54s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
55 const size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; 55 const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
56 return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); 56 return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
57} 57}
58 58
@@ -73,6 +73,7 @@ static void VolumeAdjustSamples(std::vector<s16>& samples) {
73void Stream::PlayNextBuffer() { 73void Stream::PlayNextBuffer() {
74 if (!IsPlaying()) { 74 if (!IsPlaying()) {
75 // Ensure we are in playing state before playing the next buffer 75 // Ensure we are in playing state before playing the next buffer
76 sink_stream.Flush();
76 return; 77 return;
77 } 78 }
78 79
@@ -83,6 +84,7 @@ void Stream::PlayNextBuffer() {
83 84
84 if (queued_buffers.empty()) { 85 if (queued_buffers.empty()) {
85 // No queued buffers - we are effectively paused 86 // No queued buffers - we are effectively paused
87 sink_stream.Flush();
86 return; 88 return;
87 } 89 }
88 90
@@ -90,6 +92,7 @@ void Stream::PlayNextBuffer() {
90 queued_buffers.pop(); 92 queued_buffers.pop();
91 93
92 VolumeAdjustSamples(active_buffer->Samples()); 94 VolumeAdjustSamples(active_buffer->Samples());
95
93 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); 96 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
94 97
95 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); 98 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
@@ -119,9 +122,9 @@ bool Stream::ContainsBuffer(Buffer::Tag tag) const {
119 return {}; 122 return {};
120} 123}
121 124
122std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(size_t max_count) { 125std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count) {
123 std::vector<Buffer::Tag> tags; 126 std::vector<Buffer::Tag> tags;
124 for (size_t count = 0; count < max_count && !released_buffers.empty(); ++count) { 127 for (std::size_t count = 0; count < max_count && !released_buffers.empty(); ++count) {
125 tags.push_back(released_buffers.front()->GetTag()); 128 tags.push_back(released_buffers.front()->GetTag());
126 released_buffers.pop(); 129 released_buffers.pop();
127 } 130 }
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 049b92ca9..3a435982d 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -49,7 +49,7 @@ public:
49 bool ContainsBuffer(Buffer::Tag tag) const; 49 bool ContainsBuffer(Buffer::Tag tag) const;
50 50
51 /// Returns a vector of recently released buffers specified by tag 51 /// Returns a vector of recently released buffers specified by tag
52 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(size_t max_count); 52 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count);
53 53
54 /// Returns true if the stream is currently playing 54 /// Returns true if the stream is currently playing
55 bool IsPlaying() const { 55 bool IsPlaying() const {
@@ -57,7 +57,7 @@ public:
57 } 57 }
58 58
59 /// Returns the number of queued buffers 59 /// Returns the number of queued buffers
60 size_t GetQueueSize() const { 60 std::size_t GetQueueSize() const {
61 return queued_buffers.size(); 61 return queued_buffers.size();
62 } 62 }
63 63
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
new file mode 100644
index 000000000..fc14151da
--- /dev/null
+++ b/src/audio_core/time_stretch.cpp
@@ -0,0 +1,69 @@
1// Copyright 2018 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 <cmath>
7#include <cstddef>
8#include "audio_core/time_stretch.h"
9#include "common/logging/log.h"
10
11namespace AudioCore {
12
13TimeStretcher::TimeStretcher(u32 sample_rate, u32 channel_count)
14 : m_sample_rate(sample_rate), m_channel_count(channel_count) {
15 m_sound_touch.setChannels(channel_count);
16 m_sound_touch.setSampleRate(sample_rate);
17 m_sound_touch.setPitch(1.0);
18 m_sound_touch.setTempo(1.0);
19}
20
21void TimeStretcher::Clear() {
22 m_sound_touch.clear();
23}
24
25void TimeStretcher::Flush() {
26 m_sound_touch.flush();
27}
28
29std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
30 std::size_t num_out) {
31 const double time_delta = static_cast<double>(num_out) / m_sample_rate; // seconds
32
33 // We were given actual_samples number of samples, and num_samples were requested from us.
34 double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out);
35
36 const double max_latency = 1.0; // seconds
37 const double max_backlog = m_sample_rate * max_latency;
38 const double backlog_fullness = m_sound_touch.numSamples() / max_backlog;
39 if (backlog_fullness > 5.0) {
40 // Too many samples in backlog: Don't push anymore on
41 num_in = 0;
42 }
43
44 // We ideally want the backlog to be about 50% full.
45 // This gives some headroom both ways to prevent underflow and overflow.
46 // We tweak current_ratio to encourage this.
47 constexpr double tweak_time_scale = 0.05; // seconds
48 const double tweak_correction = (backlog_fullness - 0.5) * (time_delta / tweak_time_scale);
49 current_ratio *= std::pow(1.0 + 2.0 * tweak_correction, tweak_correction < 0 ? 3.0 : 1.0);
50
51 // This low-pass filter smoothes out variance in the calculated stretch ratio.
52 // The time-scale determines how responsive this filter is.
53 constexpr double lpf_time_scale = 2.0; // seconds
54 const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale);
55 m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio);
56
57 // Place a lower limit of 5% speed. When a game boots up, there will be
58 // many silence samples. These do not need to be timestretched.
59 m_stretch_ratio = std::max(m_stretch_ratio, 0.05);
60 m_sound_touch.setTempo(m_stretch_ratio);
61
62 LOG_DEBUG(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio,
63 backlog_fullness);
64
65 m_sound_touch.putSamples(in, static_cast<u32>(num_in));
66 return m_sound_touch.receiveSamples(out, static_cast<u32>(num_out));
67}
68
69} // namespace AudioCore
diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h
new file mode 100644
index 000000000..c2286fba1
--- /dev/null
+++ b/src/audio_core/time_stretch.h
@@ -0,0 +1,36 @@
1// Copyright 2018 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 <array>
8#include <cstddef>
9#include <SoundTouch.h>
10#include "common/common_types.h"
11
12namespace AudioCore {
13
14class TimeStretcher {
15public:
16 TimeStretcher(u32 sample_rate, u32 channel_count);
17
18 /// @param in Input sample buffer
19 /// @param num_in Number of input frames in `in`
20 /// @param out Output sample buffer
21 /// @param num_out Desired number of output frames in `out`
22 /// @returns Actual number of frames written to `out`
23 std::size_t Process(const s16* in, std::size_t num_in, s16* out, std::size_t num_out);
24
25 void Clear();
26
27 void Flush();
28
29private:
30 u32 m_sample_rate;
31 u32 m_channel_count;
32 soundtouch::SoundTouch m_sound_touch;
33 double m_stretch_ratio = 1.0;
34};
35
36} // namespace AudioCore
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index f41946cc6..6a3f1fe08 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -71,6 +71,7 @@ add_library(common STATIC
71 param_package.cpp 71 param_package.cpp
72 param_package.h 72 param_package.h
73 quaternion.h 73 quaternion.h
74 ring_buffer.h
74 scm_rev.cpp 75 scm_rev.cpp
75 scm_rev.h 76 scm_rev.h
76 scope_exit.h 77 scope_exit.h
diff --git a/src/common/alignment.h b/src/common/alignment.h
index b9dd38746..225770fab 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -8,13 +8,13 @@
8namespace Common { 8namespace Common {
9 9
10template <typename T> 10template <typename T>
11constexpr T AlignUp(T value, size_t size) { 11constexpr T AlignUp(T value, std::size_t size) {
12 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 12 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
13 return static_cast<T>(value + (size - value % size) % size); 13 return static_cast<T>(value + (size - value % size) % size);
14} 14}
15 15
16template <typename T> 16template <typename T>
17constexpr T AlignDown(T value, size_t size) { 17constexpr T AlignDown(T value, std::size_t size) {
18 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 18 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
19 return static_cast<T>(value - value % size); 19 return static_cast<T>(value - value % size);
20} 20}
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 732201de7..bf803da8d 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -129,8 +129,8 @@ private:
129 129
130public: 130public:
131 /// Constants to allow limited introspection of fields if needed 131 /// Constants to allow limited introspection of fields if needed
132 static constexpr size_t position = Position; 132 static constexpr std::size_t position = Position;
133 static constexpr size_t bits = Bits; 133 static constexpr std::size_t bits = Bits;
134 static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; 134 static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position;
135 135
136 /** 136 /**
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
index 5a197d8c1..5cd1352b2 100644
--- a/src/common/bit_set.h
+++ b/src/common/bit_set.h
@@ -170,14 +170,14 @@ public:
170 m_val |= (IntTy)1 << bit; 170 m_val |= (IntTy)1 << bit;
171 } 171 }
172 172
173 static BitSet AllTrue(size_t count) { 173 static BitSet AllTrue(std::size_t count) {
174 return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); 174 return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
175 } 175 }
176 176
177 Ref operator[](size_t bit) { 177 Ref operator[](std::size_t bit) {
178 return Ref(this, (IntTy)1 << bit); 178 return Ref(this, (IntTy)1 << bit);
179 } 179 }
180 const Ref operator[](size_t bit) const { 180 const Ref operator[](std::size_t bit) const {
181 return (*const_cast<BitSet*>(this))[bit]; 181 return (*const_cast<BitSet*>(this))[bit];
182 } 182 }
183 bool operator==(BitSet other) const { 183 bool operator==(BitSet other) const {
diff --git a/src/common/cityhash.cpp b/src/common/cityhash.cpp
index de31ffbd8..4e1d874b5 100644
--- a/src/common/cityhash.cpp
+++ b/src/common/cityhash.cpp
@@ -114,7 +114,7 @@ static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
114 return b; 114 return b;
115} 115}
116 116
117static uint64 HashLen0to16(const char* s, size_t len) { 117static uint64 HashLen0to16(const char* s, std::size_t len) {
118 if (len >= 8) { 118 if (len >= 8) {
119 uint64 mul = k2 + len * 2; 119 uint64 mul = k2 + len * 2;
120 uint64 a = Fetch64(s) + k2; 120 uint64 a = Fetch64(s) + k2;
@@ -141,7 +141,7 @@ static uint64 HashLen0to16(const char* s, size_t len) {
141 141
142// This probably works well for 16-byte strings as well, but it may be overkill 142// This probably works well for 16-byte strings as well, but it may be overkill
143// in that case. 143// in that case.
144static uint64 HashLen17to32(const char* s, size_t len) { 144static uint64 HashLen17to32(const char* s, std::size_t len) {
145 uint64 mul = k2 + len * 2; 145 uint64 mul = k2 + len * 2;
146 uint64 a = Fetch64(s) * k1; 146 uint64 a = Fetch64(s) * k1;
147 uint64 b = Fetch64(s + 8); 147 uint64 b = Fetch64(s + 8);
@@ -170,7 +170,7 @@ static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint
170} 170}
171 171
172// Return an 8-byte hash for 33 to 64 bytes. 172// Return an 8-byte hash for 33 to 64 bytes.
173static uint64 HashLen33to64(const char* s, size_t len) { 173static uint64 HashLen33to64(const char* s, std::size_t len) {
174 uint64 mul = k2 + len * 2; 174 uint64 mul = k2 + len * 2;
175 uint64 a = Fetch64(s) * k2; 175 uint64 a = Fetch64(s) * k2;
176 uint64 b = Fetch64(s + 8); 176 uint64 b = Fetch64(s + 8);
@@ -191,7 +191,7 @@ static uint64 HashLen33to64(const char* s, size_t len) {
191 return b + x; 191 return b + x;
192} 192}
193 193
194uint64 CityHash64(const char* s, size_t len) { 194uint64 CityHash64(const char* s, std::size_t len) {
195 if (len <= 32) { 195 if (len <= 32) {
196 if (len <= 16) { 196 if (len <= 16) {
197 return HashLen0to16(s, len); 197 return HashLen0to16(s, len);
@@ -212,7 +212,7 @@ uint64 CityHash64(const char* s, size_t len) {
212 x = x * k1 + Fetch64(s); 212 x = x * k1 + Fetch64(s);
213 213
214 // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. 214 // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
215 len = (len - 1) & ~static_cast<size_t>(63); 215 len = (len - 1) & ~static_cast<std::size_t>(63);
216 do { 216 do {
217 x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; 217 x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
218 y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; 218 y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
@@ -229,17 +229,17 @@ uint64 CityHash64(const char* s, size_t len) {
229 HashLen16(v.second, w.second) + x); 229 HashLen16(v.second, w.second) + x);
230} 230}
231 231
232uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) { 232uint64 CityHash64WithSeed(const char* s, std::size_t len, uint64 seed) {
233 return CityHash64WithSeeds(s, len, k2, seed); 233 return CityHash64WithSeeds(s, len, k2, seed);
234} 234}
235 235
236uint64 CityHash64WithSeeds(const char* s, size_t len, uint64 seed0, uint64 seed1) { 236uint64 CityHash64WithSeeds(const char* s, std::size_t len, uint64 seed0, uint64 seed1) {
237 return HashLen16(CityHash64(s, len) - seed0, seed1); 237 return HashLen16(CityHash64(s, len) - seed0, seed1);
238} 238}
239 239
240// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings 240// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
241// of any length representable in signed long. Based on City and Murmur. 241// of any length representable in signed long. Based on City and Murmur.
242static uint128 CityMurmur(const char* s, size_t len, uint128 seed) { 242static uint128 CityMurmur(const char* s, std::size_t len, uint128 seed) {
243 uint64 a = Uint128Low64(seed); 243 uint64 a = Uint128Low64(seed);
244 uint64 b = Uint128High64(seed); 244 uint64 b = Uint128High64(seed);
245 uint64 c = 0; 245 uint64 c = 0;
@@ -269,7 +269,7 @@ static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
269 return uint128(a ^ b, HashLen16(b, a)); 269 return uint128(a ^ b, HashLen16(b, a));
270} 270}
271 271
272uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) { 272uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
273 if (len < 128) { 273 if (len < 128) {
274 return CityMurmur(s, len, seed); 274 return CityMurmur(s, len, seed);
275 } 275 }
@@ -313,7 +313,7 @@ uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
313 w.first *= 9; 313 w.first *= 9;
314 v.first *= k0; 314 v.first *= k0;
315 // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. 315 // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
316 for (size_t tail_done = 0; tail_done < len;) { 316 for (std::size_t tail_done = 0; tail_done < len;) {
317 tail_done += 32; 317 tail_done += 32;
318 y = Rotate(x + y, 42) * k0 + v.second; 318 y = Rotate(x + y, 42) * k0 + v.second;
319 w.first += Fetch64(s + len - tail_done + 16); 319 w.first += Fetch64(s + len - tail_done + 16);
@@ -331,7 +331,7 @@ uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
331 return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second)); 331 return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second));
332} 332}
333 333
334uint128 CityHash128(const char* s, size_t len) { 334uint128 CityHash128(const char* s, std::size_t len) {
335 return len >= 16 335 return len >= 16
336 ? CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s), Fetch64(s + 8) + k0)) 336 ? CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s), Fetch64(s + 8) + k0))
337 : CityHash128WithSeed(s, len, uint128(k0, k1)); 337 : CityHash128WithSeed(s, len, uint128(k0, k1));
diff --git a/src/common/cityhash.h b/src/common/cityhash.h
index bcebdb150..4b94f8e18 100644
--- a/src/common/cityhash.h
+++ b/src/common/cityhash.h
@@ -63,7 +63,7 @@
63 63
64#include <utility> 64#include <utility>
65#include <stdint.h> 65#include <stdint.h>
66#include <stdlib.h> // for size_t. 66#include <stdlib.h> // for std::size_t.
67 67
68namespace Common { 68namespace Common {
69 69
@@ -77,22 +77,22 @@ inline uint64_t Uint128High64(const uint128& x) {
77} 77}
78 78
79// Hash function for a byte array. 79// Hash function for a byte array.
80uint64_t CityHash64(const char* buf, size_t len); 80uint64_t CityHash64(const char* buf, std::size_t len);
81 81
82// Hash function for a byte array. For convenience, a 64-bit seed is also 82// Hash function for a byte array. For convenience, a 64-bit seed is also
83// hashed into the result. 83// hashed into the result.
84uint64_t CityHash64WithSeed(const char* buf, size_t len, uint64_t seed); 84uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
85 85
86// Hash function for a byte array. For convenience, two seeds are also 86// Hash function for a byte array. For convenience, two seeds are also
87// hashed into the result. 87// hashed into the result.
88uint64_t CityHash64WithSeeds(const char* buf, size_t len, uint64_t seed0, uint64_t seed1); 88uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0, uint64_t seed1);
89 89
90// Hash function for a byte array. 90// Hash function for a byte array.
91uint128 CityHash128(const char* s, size_t len); 91uint128 CityHash128(const char* s, std::size_t len);
92 92
93// Hash function for a byte array. For convenience, a 128-bit seed is also 93// Hash function for a byte array. For convenience, a 128-bit seed is also
94// hashed into the result. 94// hashed into the result.
95uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed); 95uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
96 96
97// Hash 128 input bits down to 64 bits of output. 97// Hash 128 input bits down to 64 bits of output.
98// This is intended to be a reasonably good hash function. 98// This is intended to be a reasonably good hash function.
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index baa721481..21a0b9738 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -76,7 +76,7 @@ namespace FileUtil {
76// Modifies argument. 76// Modifies argument.
77static void StripTailDirSlashes(std::string& fname) { 77static void StripTailDirSlashes(std::string& fname) {
78 if (fname.length() > 1) { 78 if (fname.length() > 1) {
79 size_t i = fname.length(); 79 std::size_t i = fname.length();
80 while (i > 0 && fname[i - 1] == DIR_SEP_CHR) 80 while (i > 0 && fname[i - 1] == DIR_SEP_CHR)
81 --i; 81 --i;
82 fname.resize(i); 82 fname.resize(i);
@@ -201,7 +201,7 @@ bool CreateFullPath(const std::string& fullPath) {
201 return true; 201 return true;
202 } 202 }
203 203
204 size_t position = 0; 204 std::size_t position = 0;
205 while (true) { 205 while (true) {
206 // Find next sub path 206 // Find next sub path
207 position = fullPath.find(DIR_SEP_CHR, position); 207 position = fullPath.find(DIR_SEP_CHR, position);
@@ -299,7 +299,7 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
299 std::array<char, 1024> buffer; 299 std::array<char, 1024> buffer;
300 while (!feof(input.get())) { 300 while (!feof(input.get())) {
301 // read input 301 // read input
302 size_t rnum = fread(buffer.data(), sizeof(char), buffer.size(), input.get()); 302 std::size_t rnum = fread(buffer.data(), sizeof(char), buffer.size(), input.get());
303 if (rnum != buffer.size()) { 303 if (rnum != buffer.size()) {
304 if (ferror(input.get()) != 0) { 304 if (ferror(input.get()) != 0) {
305 LOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}", 305 LOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}",
@@ -309,7 +309,7 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
309 } 309 }
310 310
311 // write output 311 // write output
312 size_t wnum = fwrite(buffer.data(), sizeof(char), rnum, output.get()); 312 std::size_t wnum = fwrite(buffer.data(), sizeof(char), rnum, output.get());
313 if (wnum != rnum) { 313 if (wnum != rnum) {
314 LOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename, 314 LOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename,
315 destFilename, GetLastErrorMsg()); 315 destFilename, GetLastErrorMsg());
@@ -756,11 +756,11 @@ std::string GetNANDRegistrationDir(bool system) {
756 return GetUserPath(UserPath::NANDDir) + "user/Contents/registered/"; 756 return GetUserPath(UserPath::NANDDir) + "user/Contents/registered/";
757} 757}
758 758
759size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) { 759std::size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
760 return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); 760 return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
761} 761}
762 762
763size_t ReadFileToString(bool text_file, const char* filename, std::string& str) { 763std::size_t ReadFileToString(bool text_file, const char* filename, std::string& str) {
764 IOFile file(filename, text_file ? "r" : "rb"); 764 IOFile file(filename, text_file ? "r" : "rb");
765 765
766 if (!file.IsOpen()) 766 if (!file.IsOpen())
@@ -829,7 +829,7 @@ std::vector<std::string> SplitPathComponents(std::string_view filename) {
829std::string_view GetParentPath(std::string_view path) { 829std::string_view GetParentPath(std::string_view path) {
830 const auto name_bck_index = path.rfind('\\'); 830 const auto name_bck_index = path.rfind('\\');
831 const auto name_fwd_index = path.rfind('/'); 831 const auto name_fwd_index = path.rfind('/');
832 size_t name_index; 832 std::size_t name_index;
833 833
834 if (name_bck_index == std::string_view::npos || name_fwd_index == std::string_view::npos) { 834 if (name_bck_index == std::string_view::npos || name_fwd_index == std::string_view::npos) {
835 name_index = std::min(name_bck_index, name_fwd_index); 835 name_index = std::min(name_bck_index, name_fwd_index);
@@ -868,7 +868,7 @@ std::string_view GetFilename(std::string_view path) {
868} 868}
869 869
870std::string_view GetExtensionFromFilename(std::string_view name) { 870std::string_view GetExtensionFromFilename(std::string_view name) {
871 const size_t index = name.rfind('.'); 871 const std::size_t index = name.rfind('.');
872 872
873 if (index == std::string_view::npos) { 873 if (index == std::string_view::npos) {
874 return {}; 874 return {};
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 2f13d0b6b..24c1e413c 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -143,8 +143,9 @@ const std::string& GetExeDirectory();
143std::string AppDataRoamingDirectory(); 143std::string AppDataRoamingDirectory();
144#endif 144#endif
145 145
146size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename); 146std::size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
147size_t ReadFileToString(bool text_file, const char* filename, std::string& str); 147
148std::size_t ReadFileToString(bool text_file, const char* filename, std::string& str);
148 149
149/** 150/**
150 * Splits the filename into 8.3 format 151 * Splits the filename into 8.3 format
@@ -177,10 +178,10 @@ std::string_view RemoveTrailingSlash(std::string_view path);
177 178
178// Creates a new vector containing indices [first, last) from the original. 179// Creates a new vector containing indices [first, last) from the original.
179template <typename T> 180template <typename T>
180std::vector<T> SliceVector(const std::vector<T>& vector, size_t first, size_t last) { 181std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first, std::size_t last) {
181 if (first >= last) 182 if (first >= last)
182 return {}; 183 return {};
183 last = std::min<size_t>(last, vector.size()); 184 last = std::min<std::size_t>(last, vector.size());
184 return std::vector<T>(vector.begin() + first, vector.begin() + first + last); 185 return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
185} 186}
186 187
@@ -213,47 +214,47 @@ public:
213 bool Close(); 214 bool Close();
214 215
215 template <typename T> 216 template <typename T>
216 size_t ReadArray(T* data, size_t length) const { 217 std::size_t ReadArray(T* data, std::size_t length) const {
217 static_assert(std::is_trivially_copyable_v<T>, 218 static_assert(std::is_trivially_copyable_v<T>,
218 "Given array does not consist of trivially copyable objects"); 219 "Given array does not consist of trivially copyable objects");
219 220
220 if (!IsOpen()) { 221 if (!IsOpen()) {
221 return std::numeric_limits<size_t>::max(); 222 return std::numeric_limits<std::size_t>::max();
222 } 223 }
223 224
224 return std::fread(data, sizeof(T), length, m_file); 225 return std::fread(data, sizeof(T), length, m_file);
225 } 226 }
226 227
227 template <typename T> 228 template <typename T>
228 size_t WriteArray(const T* data, size_t length) { 229 std::size_t WriteArray(const T* data, std::size_t length) {
229 static_assert(std::is_trivially_copyable_v<T>, 230 static_assert(std::is_trivially_copyable_v<T>,
230 "Given array does not consist of trivially copyable objects"); 231 "Given array does not consist of trivially copyable objects");
231 if (!IsOpen()) { 232 if (!IsOpen()) {
232 return std::numeric_limits<size_t>::max(); 233 return std::numeric_limits<std::size_t>::max();
233 } 234 }
234 235
235 return std::fwrite(data, sizeof(T), length, m_file); 236 return std::fwrite(data, sizeof(T), length, m_file);
236 } 237 }
237 238
238 template <typename T> 239 template <typename T>
239 size_t ReadBytes(T* data, size_t length) const { 240 std::size_t ReadBytes(T* data, std::size_t length) const {
240 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); 241 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
241 return ReadArray(reinterpret_cast<char*>(data), length); 242 return ReadArray(reinterpret_cast<char*>(data), length);
242 } 243 }
243 244
244 template <typename T> 245 template <typename T>
245 size_t WriteBytes(const T* data, size_t length) { 246 std::size_t WriteBytes(const T* data, std::size_t length) {
246 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); 247 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
247 return WriteArray(reinterpret_cast<const char*>(data), length); 248 return WriteArray(reinterpret_cast<const char*>(data), length);
248 } 249 }
249 250
250 template <typename T> 251 template <typename T>
251 size_t WriteObject(const T& object) { 252 std::size_t WriteObject(const T& object) {
252 static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer"); 253 static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer");
253 return WriteArray(&object, 1); 254 return WriteArray(&object, 1);
254 } 255 }
255 256
256 size_t WriteString(const std::string& str) { 257 std::size_t WriteString(const std::string& str) {
257 return WriteArray(str.c_str(), str.length()); 258 return WriteArray(str.c_str(), str.length());
258 } 259 }
259 260
diff --git a/src/common/hash.h b/src/common/hash.h
index 2c761e545..40194d1ee 100644
--- a/src/common/hash.h
+++ b/src/common/hash.h
@@ -17,7 +17,7 @@ namespace Common {
17 * @param len Length of data (in bytes) to compute hash over 17 * @param len Length of data (in bytes) to compute hash over
18 * @returns 64-bit hash value that was computed over the data block 18 * @returns 64-bit hash value that was computed over the data block
19 */ 19 */
20static inline u64 ComputeHash64(const void* data, size_t len) { 20static inline u64 ComputeHash64(const void* data, std::size_t len) {
21 return CityHash64(static_cast<const char*>(data), len); 21 return CityHash64(static_cast<const char*>(data), len);
22} 22}
23 23
@@ -63,7 +63,7 @@ struct HashableStruct {
63 return !(*this == o); 63 return !(*this == o);
64 }; 64 };
65 65
66 size_t Hash() const { 66 std::size_t Hash() const {
67 return Common::ComputeStructHash64(state); 67 return Common::ComputeStructHash64(state);
68 } 68 }
69}; 69};
diff --git a/src/common/hex_util.cpp b/src/common/hex_util.cpp
index 8e0a9e46f..589ae5cbf 100644
--- a/src/common/hex_util.cpp
+++ b/src/common/hex_util.cpp
@@ -18,7 +18,7 @@ u8 ToHexNibble(char c1) {
18 return 0; 18 return 0;
19} 19}
20 20
21std::array<u8, 16> operator""_array16(const char* str, size_t len) { 21std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
22 if (len != 32) { 22 if (len != 32) {
23 LOG_ERROR(Common, 23 LOG_ERROR(Common,
24 "Attempting to parse string to array that is not of correct size (expected=32, " 24 "Attempting to parse string to array that is not of correct size (expected=32, "
@@ -29,7 +29,7 @@ std::array<u8, 16> operator""_array16(const char* str, size_t len) {
29 return HexStringToArray<16>(str); 29 return HexStringToArray<16>(str);
30} 30}
31 31
32std::array<u8, 32> operator""_array32(const char* str, size_t len) { 32std::array<u8, 32> operator""_array32(const char* str, std::size_t len) {
33 if (len != 64) { 33 if (len != 64) {
34 LOG_ERROR(Common, 34 LOG_ERROR(Common,
35 "Attempting to parse string to array that is not of correct size (expected=64, " 35 "Attempting to parse string to array that is not of correct size (expected=64, "
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
index 5fb79bb72..863a5ccd9 100644
--- a/src/common/hex_util.h
+++ b/src/common/hex_util.h
@@ -14,20 +14,20 @@ namespace Common {
14 14
15u8 ToHexNibble(char c1); 15u8 ToHexNibble(char c1);
16 16
17template <size_t Size, bool le = false> 17template <std::size_t Size, bool le = false>
18std::array<u8, Size> HexStringToArray(std::string_view str) { 18std::array<u8, Size> HexStringToArray(std::string_view str) {
19 std::array<u8, Size> out{}; 19 std::array<u8, Size> out{};
20 if constexpr (le) { 20 if constexpr (le) {
21 for (size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) 21 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
22 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 22 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
23 } else { 23 } else {
24 for (size_t i = 0; i < 2 * Size; i += 2) 24 for (std::size_t i = 0; i < 2 * Size; i += 2)
25 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 25 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
26 } 26 }
27 return out; 27 return out;
28} 28}
29 29
30template <size_t Size> 30template <std::size_t Size>
31std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) { 31std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) {
32 std::string out; 32 std::string out;
33 for (u8 c : array) 33 for (u8 c : array)
@@ -35,7 +35,7 @@ std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) {
35 return out; 35 return out;
36} 36}
37 37
38std::array<u8, 0x10> operator"" _array16(const char* str, size_t len); 38std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len);
39std::array<u8, 0x20> operator"" _array32(const char* str, size_t len); 39std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len);
40 40
41} // namespace Common 41} // namespace Common
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 1323f8d0f..efd776db6 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -135,7 +135,7 @@ FileBackend::FileBackend(const std::string& filename)
135void FileBackend::Write(const Entry& entry) { 135void FileBackend::Write(const Entry& entry) {
136 // prevent logs from going over the maximum size (in case its spamming and the user doesn't 136 // prevent logs from going over the maximum size (in case its spamming and the user doesn't
137 // know) 137 // know)
138 constexpr size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L; 138 constexpr std::size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L;
139 if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { 139 if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) {
140 return; 140 return;
141 } 141 }
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index b3f4b9cef..11edbf1b6 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -100,7 +100,7 @@ public:
100 100
101private: 101private:
102 FileUtil::IOFile file; 102 FileUtil::IOFile file;
103 size_t bytes_written; 103 std::size_t bytes_written;
104}; 104};
105 105
106void AddBackend(std::unique_ptr<Backend> backend); 106void AddBackend(std::unique_ptr<Backend> backend);
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 2dd331152..2eccbcd8d 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -71,7 +71,7 @@ void Filter::ResetAll(Level level) {
71} 71}
72 72
73void Filter::SetClassLevel(Class log_class, Level level) { 73void Filter::SetClassLevel(Class log_class, Level level) {
74 class_levels[static_cast<size_t>(log_class)] = level; 74 class_levels[static_cast<std::size_t>(log_class)] = level;
75} 75}
76 76
77void Filter::ParseFilterString(std::string_view filter_view) { 77void Filter::ParseFilterString(std::string_view filter_view) {
@@ -93,7 +93,8 @@ void Filter::ParseFilterString(std::string_view filter_view) {
93} 93}
94 94
95bool Filter::CheckMessage(Class log_class, Level level) const { 95bool Filter::CheckMessage(Class log_class, Level level) const {
96 return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]); 96 return static_cast<u8>(level) >=
97 static_cast<u8>(class_levels[static_cast<std::size_t>(log_class)]);
97} 98}
98 99
99bool Filter::IsDebug() const { 100bool Filter::IsDebug() const {
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index f7e3b87c9..773df6f2c 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -49,6 +49,6 @@ public:
49 bool IsDebug() const; 49 bool IsDebug() const;
50 50
51private: 51private:
52 std::array<Level, static_cast<size_t>(Class::Count)> class_levels; 52 std::array<Level, static_cast<std::size_t>(Class::Count)> class_levels;
53}; 53};
54} // namespace Log 54} // namespace Log
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index 09462ccee..9736fb12a 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -25,7 +25,7 @@
25// This is purposely not a full wrapper for virtualalloc/mmap, but it 25// This is purposely not a full wrapper for virtualalloc/mmap, but it
26// provides exactly the primitive operations that Dolphin needs. 26// provides exactly the primitive operations that Dolphin needs.
27 27
28void* AllocateExecutableMemory(size_t size, bool low) { 28void* AllocateExecutableMemory(std::size_t size, bool low) {
29#if defined(_WIN32) 29#if defined(_WIN32)
30 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 30 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
31#else 31#else
@@ -74,7 +74,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
74 return ptr; 74 return ptr;
75} 75}
76 76
77void* AllocateMemoryPages(size_t size) { 77void* AllocateMemoryPages(std::size_t size) {
78#ifdef _WIN32 78#ifdef _WIN32
79 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); 79 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
80#else 80#else
@@ -90,7 +90,7 @@ void* AllocateMemoryPages(size_t size) {
90 return ptr; 90 return ptr;
91} 91}
92 92
93void* AllocateAlignedMemory(size_t size, size_t alignment) { 93void* AllocateAlignedMemory(std::size_t size, std::size_t alignment) {
94#ifdef _WIN32 94#ifdef _WIN32
95 void* ptr = _aligned_malloc(size, alignment); 95 void* ptr = _aligned_malloc(size, alignment);
96#else 96#else
@@ -109,7 +109,7 @@ void* AllocateAlignedMemory(size_t size, size_t alignment) {
109 return ptr; 109 return ptr;
110} 110}
111 111
112void FreeMemoryPages(void* ptr, size_t size) { 112void FreeMemoryPages(void* ptr, std::size_t size) {
113 if (ptr) { 113 if (ptr) {
114#ifdef _WIN32 114#ifdef _WIN32
115 if (!VirtualFree(ptr, 0, MEM_RELEASE)) 115 if (!VirtualFree(ptr, 0, MEM_RELEASE))
@@ -130,7 +130,7 @@ void FreeAlignedMemory(void* ptr) {
130 } 130 }
131} 131}
132 132
133void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) { 133void WriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
134#ifdef _WIN32 134#ifdef _WIN32
135 DWORD oldValue; 135 DWORD oldValue;
136 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) 136 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
@@ -140,7 +140,7 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
140#endif 140#endif
141} 141}
142 142
143void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) { 143void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
144#ifdef _WIN32 144#ifdef _WIN32
145 DWORD oldValue; 145 DWORD oldValue;
146 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, 146 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
diff --git a/src/common/memory_util.h b/src/common/memory_util.h
index 76ca5a30c..aad071979 100644
--- a/src/common/memory_util.h
+++ b/src/common/memory_util.h
@@ -7,13 +7,13 @@
7#include <cstddef> 7#include <cstddef>
8#include <string> 8#include <string>
9 9
10void* AllocateExecutableMemory(size_t size, bool low = true); 10void* AllocateExecutableMemory(std::size_t size, bool low = true);
11void* AllocateMemoryPages(size_t size); 11void* AllocateMemoryPages(std::size_t size);
12void FreeMemoryPages(void* ptr, size_t size); 12void FreeMemoryPages(void* ptr, std::size_t size);
13void* AllocateAlignedMemory(size_t size, size_t alignment); 13void* AllocateAlignedMemory(std::size_t size, std::size_t alignment);
14void FreeAlignedMemory(void* ptr); 14void FreeAlignedMemory(void* ptr);
15void WriteProtectMemory(void* ptr, size_t size, bool executable = false); 15void WriteProtectMemory(void* ptr, std::size_t size, bool executable = false);
16void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); 16void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute = false);
17std::string MemUsage(); 17std::string MemUsage();
18 18
19inline int GetPageSize() { 19inline int GetPageSize() {
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 3fa8a3bc4..68cb86cd1 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -16,7 +16,7 @@
16// Call directly after the command or use the error num. 16// Call directly after the command or use the error num.
17// This function might change the error code. 17// This function might change the error code.
18std::string GetLastErrorMsg() { 18std::string GetLastErrorMsg() {
19 static const size_t buff_size = 255; 19 static const std::size_t buff_size = 255;
20 char err_str[buff_size]; 20 char err_str[buff_size];
21 21
22#ifdef _WIN32 22#ifdef _WIN32
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h
new file mode 100644
index 000000000..45926c9ec
--- /dev/null
+++ b/src/common/ring_buffer.h
@@ -0,0 +1,111 @@
1// Copyright 2018 yuzu emulator team
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 <array>
9#include <atomic>
10#include <cstddef>
11#include <cstring>
12#include <type_traits>
13#include <vector>
14#include "common/common_types.h"
15
16namespace Common {
17
18/// SPSC ring buffer
19/// @tparam T Element type
20/// @tparam capacity Number of slots in ring buffer
21/// @tparam granularity Slot size in terms of number of elements
22template <typename T, std::size_t capacity, std::size_t granularity = 1>
23class RingBuffer {
24 /// A "slot" is made of `granularity` elements of `T`.
25 static constexpr std::size_t slot_size = granularity * sizeof(T);
26 // T must be safely memcpy-able and have a trivial default constructor.
27 static_assert(std::is_trivial_v<T>);
28 // Ensure capacity is sensible.
29 static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2 / granularity);
30 static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two");
31 // Ensure lock-free.
32 static_assert(std::atomic<std::size_t>::is_always_lock_free);
33
34public:
35 /// Pushes slots into the ring buffer
36 /// @param new_slots Pointer to the slots to push
37 /// @param slot_count Number of slots to push
38 /// @returns The number of slots actually pushed
39 std::size_t Push(const void* new_slots, std::size_t slot_count) {
40 const std::size_t write_index = m_write_index.load();
41 const std::size_t slots_free = capacity + m_read_index.load() - write_index;
42 const std::size_t push_count = std::min(slot_count, slots_free);
43
44 const std::size_t pos = write_index % capacity;
45 const std::size_t first_copy = std::min(capacity - pos, push_count);
46 const std::size_t second_copy = push_count - first_copy;
47
48 const char* in = static_cast<const char*>(new_slots);
49 std::memcpy(m_data.data() + pos * granularity, in, first_copy * slot_size);
50 in += first_copy * slot_size;
51 std::memcpy(m_data.data(), in, second_copy * slot_size);
52
53 m_write_index.store(write_index + push_count);
54
55 return push_count;
56 }
57
58 std::size_t Push(const std::vector<T>& input) {
59 return Push(input.data(), input.size());
60 }
61
62 /// Pops slots from the ring buffer
63 /// @param output Where to store the popped slots
64 /// @param max_slots Maximum number of slots to pop
65 /// @returns The number of slots actually popped
66 std::size_t Pop(void* output, std::size_t max_slots = ~std::size_t(0)) {
67 const std::size_t read_index = m_read_index.load();
68 const std::size_t slots_filled = m_write_index.load() - read_index;
69 const std::size_t pop_count = std::min(slots_filled, max_slots);
70
71 const std::size_t pos = read_index % capacity;
72 const std::size_t first_copy = std::min(capacity - pos, pop_count);
73 const std::size_t second_copy = pop_count - first_copy;
74
75 char* out = static_cast<char*>(output);
76 std::memcpy(out, m_data.data() + pos * granularity, first_copy * slot_size);
77 out += first_copy * slot_size;
78 std::memcpy(out, m_data.data(), second_copy * slot_size);
79
80 m_read_index.store(read_index + pop_count);
81
82 return pop_count;
83 }
84
85 std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) {
86 std::vector<T> out(std::min(max_slots, capacity) * granularity);
87 const std::size_t count = Pop(out.data(), out.size() / granularity);
88 out.resize(count * granularity);
89 return out;
90 }
91
92 /// @returns Number of slots used
93 std::size_t Size() const {
94 return m_write_index.load() - m_read_index.load();
95 }
96
97 /// @returns Maximum size of ring buffer
98 constexpr std::size_t Capacity() const {
99 return capacity;
100 }
101
102private:
103 // It is important to align the below variables for performance reasons:
104 // Having them on the same cache-line would result in false-sharing between them.
105 alignas(128) std::atomic<std::size_t> m_read_index{0};
106 alignas(128) std::atomic<std::size_t> m_write_index{0};
107
108 std::array<T, granularity * capacity> m_data;
109};
110
111} // namespace Common
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 0ca663032..c9a5425a7 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -37,7 +37,7 @@ std::string ToUpper(std::string str) {
37} 37}
38 38
39// For Debugging. Read out an u8 array. 39// For Debugging. Read out an u8 array.
40std::string ArrayToString(const u8* data, size_t size, int line_len, bool spaces) { 40std::string ArrayToString(const u8* data, std::size_t size, int line_len, bool spaces) {
41 std::ostringstream oss; 41 std::ostringstream oss;
42 oss << std::setfill('0') << std::hex; 42 oss << std::setfill('0') << std::hex;
43 43
@@ -60,7 +60,7 @@ std::string StringFromBuffer(const std::vector<u8>& data) {
60 60
61// Turns " hej " into "hej". Also handles tabs. 61// Turns " hej " into "hej". Also handles tabs.
62std::string StripSpaces(const std::string& str) { 62std::string StripSpaces(const std::string& str) {
63 const size_t s = str.find_first_not_of(" \t\r\n"); 63 const std::size_t s = str.find_first_not_of(" \t\r\n");
64 64
65 if (str.npos != s) 65 if (str.npos != s)
66 return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); 66 return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1);
@@ -121,10 +121,10 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
121 if (full_path.empty()) 121 if (full_path.empty())
122 return false; 122 return false;
123 123
124 size_t dir_end = full_path.find_last_of("/" 124 std::size_t dir_end = full_path.find_last_of("/"
125// windows needs the : included for something like just "C:" to be considered a directory 125// windows needs the : included for something like just "C:" to be considered a directory
126#ifdef _WIN32 126#ifdef _WIN32
127 "\\:" 127 "\\:"
128#endif 128#endif
129 ); 129 );
130 if (std::string::npos == dir_end) 130 if (std::string::npos == dir_end)
@@ -132,7 +132,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
132 else 132 else
133 dir_end += 1; 133 dir_end += 1;
134 134
135 size_t fname_end = full_path.rfind('.'); 135 std::size_t fname_end = full_path.rfind('.');
136 if (fname_end < dir_end || std::string::npos == fname_end) 136 if (fname_end < dir_end || std::string::npos == fname_end)
137 fname_end = full_path.size(); 137 fname_end = full_path.size();
138 138
@@ -172,7 +172,7 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri
172} 172}
173 173
174std::string TabsToSpaces(int tab_size, std::string in) { 174std::string TabsToSpaces(int tab_size, std::string in) {
175 size_t i = 0; 175 std::size_t i = 0;
176 176
177 while ((i = in.find('\t')) != std::string::npos) { 177 while ((i = in.find('\t')) != std::string::npos) {
178 in.replace(i, 1, tab_size, ' '); 178 in.replace(i, 1, tab_size, ' ');
@@ -182,7 +182,7 @@ std::string TabsToSpaces(int tab_size, std::string in) {
182} 182}
183 183
184std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) { 184std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
185 size_t pos = 0; 185 std::size_t pos = 0;
186 186
187 if (src == dest) 187 if (src == dest)
188 return result; 188 return result;
@@ -280,22 +280,22 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
280 return {}; 280 return {};
281 } 281 }
282 282
283 const size_t in_bytes = sizeof(T) * input.size(); 283 const std::size_t in_bytes = sizeof(T) * input.size();
284 // Multiply by 4, which is the max number of bytes to encode a codepoint 284 // Multiply by 4, which is the max number of bytes to encode a codepoint
285 const size_t out_buffer_size = 4 * in_bytes; 285 const std::size_t out_buffer_size = 4 * in_bytes;
286 286
287 std::string out_buffer(out_buffer_size, '\0'); 287 std::string out_buffer(out_buffer_size, '\0');
288 288
289 auto src_buffer = &input[0]; 289 auto src_buffer = &input[0];
290 size_t src_bytes = in_bytes; 290 std::size_t src_bytes = in_bytes;
291 auto dst_buffer = &out_buffer[0]; 291 auto dst_buffer = &out_buffer[0];
292 size_t dst_bytes = out_buffer.size(); 292 std::size_t dst_bytes = out_buffer.size();
293 293
294 while (0 != src_bytes) { 294 while (0 != src_bytes) {
295 size_t const iconv_result = 295 std::size_t const iconv_result =
296 iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes); 296 iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes);
297 297
298 if (static_cast<size_t>(-1) == iconv_result) { 298 if (static_cast<std::size_t>(-1) == iconv_result) {
299 if (EILSEQ == errno || EINVAL == errno) { 299 if (EILSEQ == errno || EINVAL == errno) {
300 // Try to skip the bad character 300 // Try to skip the bad character
301 if (0 != src_bytes) { 301 if (0 != src_bytes) {
@@ -326,22 +326,22 @@ std::u16string UTF8ToUTF16(const std::string& input) {
326 return {}; 326 return {};
327 } 327 }
328 328
329 const size_t in_bytes = sizeof(char) * input.size(); 329 const std::size_t in_bytes = sizeof(char) * input.size();
330 // Multiply by 4, which is the max number of bytes to encode a codepoint 330 // Multiply by 4, which is the max number of bytes to encode a codepoint
331 const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes; 331 const std::size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
332 332
333 std::u16string out_buffer(out_buffer_size, char16_t{}); 333 std::u16string out_buffer(out_buffer_size, char16_t{});
334 334
335 char* src_buffer = const_cast<char*>(&input[0]); 335 char* src_buffer = const_cast<char*>(&input[0]);
336 size_t src_bytes = in_bytes; 336 std::size_t src_bytes = in_bytes;
337 char* dst_buffer = (char*)(&out_buffer[0]); 337 char* dst_buffer = (char*)(&out_buffer[0]);
338 size_t dst_bytes = out_buffer.size(); 338 std::size_t dst_bytes = out_buffer.size();
339 339
340 while (0 != src_bytes) { 340 while (0 != src_bytes) {
341 size_t const iconv_result = 341 std::size_t const iconv_result =
342 iconv(conv_desc, &src_buffer, &src_bytes, &dst_buffer, &dst_bytes); 342 iconv(conv_desc, &src_buffer, &src_bytes, &dst_buffer, &dst_bytes);
343 343
344 if (static_cast<size_t>(-1) == iconv_result) { 344 if (static_cast<std::size_t>(-1) == iconv_result) {
345 if (EILSEQ == errno || EINVAL == errno) { 345 if (EILSEQ == errno || EINVAL == errno) {
346 // Try to skip the bad character 346 // Try to skip the bad character
347 if (0 != src_bytes) { 347 if (0 != src_bytes) {
@@ -381,8 +381,8 @@ std::string SHIFTJISToUTF8(const std::string& input) {
381 381
382#endif 382#endif
383 383
384std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len) { 384std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len) {
385 size_t len = 0; 385 std::size_t len = 0;
386 while (len < max_len && buffer[len] != '\0') 386 while (len < max_len && buffer[len] != '\0')
387 ++len; 387 ++len;
388 388
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 4a2143b59..dcca6bc38 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -19,7 +19,7 @@ std::string ToLower(std::string str);
19/// Make a string uppercase 19/// Make a string uppercase
20std::string ToUpper(std::string str); 20std::string ToUpper(std::string str);
21 21
22std::string ArrayToString(const u8* data, size_t size, int line_len = 20, bool spaces = true); 22std::string ArrayToString(const u8* data, std::size_t size, int line_len = 20, bool spaces = true);
23 23
24std::string StringFromBuffer(const std::vector<u8>& data); 24std::string StringFromBuffer(const std::vector<u8>& data);
25 25
@@ -118,7 +118,7 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
118 * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't 118 * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
119 * NUL-terminated then the string ends at max_len characters. 119 * NUL-terminated then the string ends at max_len characters.
120 */ 120 */
121std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len); 121std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
122 122
123/** 123/**
124 * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's 124 * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
diff --git a/src/common/thread.h b/src/common/thread.h
index 9465e1de7..12a1c095c 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -60,12 +60,12 @@ private:
60 60
61class Barrier { 61class Barrier {
62public: 62public:
63 explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) {} 63 explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {}
64 64
65 /// Blocks until all "count" threads have called Sync() 65 /// Blocks until all "count" threads have called Sync()
66 void Sync() { 66 void Sync() {
67 std::unique_lock<std::mutex> lk(mutex); 67 std::unique_lock<std::mutex> lk(mutex);
68 const size_t current_generation = generation; 68 const std::size_t current_generation = generation;
69 69
70 if (++waiting == count) { 70 if (++waiting == count) {
71 generation++; 71 generation++;
@@ -80,9 +80,9 @@ public:
80private: 80private:
81 std::condition_variable condvar; 81 std::condition_variable condvar;
82 std::mutex mutex; 82 std::mutex mutex;
83 const size_t count; 83 const std::size_t count;
84 size_t waiting; 84 std::size_t waiting;
85 size_t generation; // Incremented once each time the barrier is used 85 std::size_t generation; // Incremented once each time the barrier is used
86}; 86};
87 87
88void SleepCurrentThread(int ms); 88void SleepCurrentThread(int ms);
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
index 927da9187..636a5c0f9 100644
--- a/src/common/x64/xbyak_abi.h
+++ b/src/common/x64/xbyak_abi.h
@@ -97,7 +97,7 @@ const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
97 Xbyak::util::xmm15, 97 Xbyak::util::xmm15,
98}); 98});
99 99
100constexpr size_t ABI_SHADOW_SPACE = 0x20; 100constexpr std::size_t ABI_SHADOW_SPACE = 0x20;
101 101
102#else 102#else
103 103
@@ -147,22 +147,23 @@ const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
147 Xbyak::util::r15, 147 Xbyak::util::r15,
148}); 148});
149 149
150constexpr size_t ABI_SHADOW_SPACE = 0; 150constexpr std::size_t ABI_SHADOW_SPACE = 0;
151 151
152#endif 152#endif
153 153
154inline void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size, 154inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment,
155 s32* out_subtraction, s32* out_xmm_offset) { 155 std::size_t needed_frame_size, s32* out_subtraction,
156 s32* out_xmm_offset) {
156 int count = (regs & ABI_ALL_GPRS).Count(); 157 int count = (regs & ABI_ALL_GPRS).Count();
157 rsp_alignment -= count * 8; 158 rsp_alignment -= count * 8;
158 size_t subtraction = 0; 159 std::size_t subtraction = 0;
159 int xmm_count = (regs & ABI_ALL_XMMS).Count(); 160 int xmm_count = (regs & ABI_ALL_XMMS).Count();
160 if (xmm_count) { 161 if (xmm_count) {
161 // If we have any XMMs to save, we must align the stack here. 162 // If we have any XMMs to save, we must align the stack here.
162 subtraction = rsp_alignment & 0xF; 163 subtraction = rsp_alignment & 0xF;
163 } 164 }
164 subtraction += 0x10 * xmm_count; 165 subtraction += 0x10 * xmm_count;
165 size_t xmm_base_subtraction = subtraction; 166 std::size_t xmm_base_subtraction = subtraction;
166 subtraction += needed_frame_size; 167 subtraction += needed_frame_size;
167 subtraction += ABI_SHADOW_SPACE; 168 subtraction += ABI_SHADOW_SPACE;
168 // Final alignment. 169 // Final alignment.
@@ -173,8 +174,9 @@ inline void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t n
173 *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction); 174 *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
174} 175}
175 176
176inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, 177inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
177 size_t rsp_alignment, size_t needed_frame_size = 0) { 178 std::size_t rsp_alignment,
179 std::size_t needed_frame_size = 0) {
178 s32 subtraction, xmm_offset; 180 s32 subtraction, xmm_offset;
179 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset); 181 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
180 182
@@ -195,7 +197,8 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet
195} 197}
196 198
197inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, 199inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
198 size_t rsp_alignment, size_t needed_frame_size = 0) { 200 std::size_t rsp_alignment,
201 std::size_t needed_frame_size = 0) {
199 s32 subtraction, xmm_offset; 202 s32 subtraction, xmm_offset;
200 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset); 203 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
201 204
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h
index 02323a017..5cc8a8c76 100644
--- a/src/common/x64/xbyak_util.h
+++ b/src/common/x64/xbyak_util.h
@@ -34,7 +34,7 @@ inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
34template <typename T> 34template <typename T>
35inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { 35inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
36 static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer."); 36 static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
37 size_t addr = reinterpret_cast<size_t>(f); 37 std::size_t addr = reinterpret_cast<std::size_t>(f);
38 if (IsWithin2G(code, addr)) { 38 if (IsWithin2G(code, addr)) {
39 code.call(f); 39 code.call(f);
40 } else { 40 } else {
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index c368745b1..0b2af2a9b 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -31,11 +31,11 @@ public:
31 virtual void Step() = 0; 31 virtual void Step() = 0;
32 32
33 /// Maps a backing memory region for the CPU 33 /// Maps a backing memory region for the CPU
34 virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, 34 virtual void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
35 Kernel::VMAPermission perms) = 0; 35 Kernel::VMAPermission perms) = 0;
36 36
37 /// Unmaps a region of memory that was previously mapped using MapBackingMemory 37 /// Unmaps a region of memory that was previously mapped using MapBackingMemory
38 virtual void UnmapMemory(VAddr address, size_t size) = 0; 38 virtual void UnmapMemory(VAddr address, std::size_t size) = 0;
39 39
40 /// Clear all instruction cache 40 /// Clear all instruction cache
41 virtual void ClearInstructionCache() = 0; 41 virtual void ClearInstructionCache() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index b47f04988..0c175d872 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -58,7 +58,7 @@ public:
58 Memory::Write64(vaddr + 8, value[1]); 58 Memory::Write64(vaddr + 8, value[1]);
59 } 59 }
60 60
61 void InterpreterFallback(u64 pc, size_t num_instructions) override { 61 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
62 LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, 62 LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
63 num_instructions, MemoryReadCode(pc)); 63 num_instructions, MemoryReadCode(pc));
64 64
@@ -81,7 +81,7 @@ public:
81 return; 81 return;
82 default: 82 default:
83 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})", 83 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
84 static_cast<size_t>(exception), pc); 84 static_cast<std::size_t>(exception), pc);
85 } 85 }
86 } 86 }
87 87
@@ -110,7 +110,7 @@ public:
110 } 110 }
111 111
112 ARM_Dynarmic& parent; 112 ARM_Dynarmic& parent;
113 size_t num_interpreted_instructions = 0; 113 std::size_t num_interpreted_instructions = 0;
114 u64 tpidrro_el0 = 0; 114 u64 tpidrro_el0 = 0;
115 u64 tpidr_el0 = 0; 115 u64 tpidr_el0 = 0;
116}; 116};
@@ -157,7 +157,8 @@ void ARM_Dynarmic::Step() {
157 cb->InterpreterFallback(jit->GetPC(), 1); 157 cb->InterpreterFallback(jit->GetPC(), 1);
158} 158}
159 159
160ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index) 160ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
161 std::size_t core_index)
161 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, 162 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
162 exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { 163 exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} {
163 ThreadContext ctx; 164 ThreadContext ctx;
@@ -168,12 +169,12 @@ ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
168 169
169ARM_Dynarmic::~ARM_Dynarmic() = default; 170ARM_Dynarmic::~ARM_Dynarmic() = default;
170 171
171void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory, 172void ARM_Dynarmic::MapBackingMemory(u64 address, std::size_t size, u8* memory,
172 Kernel::VMAPermission perms) { 173 Kernel::VMAPermission perms) {
173 inner_unicorn.MapBackingMemory(address, size, memory, perms); 174 inner_unicorn.MapBackingMemory(address, size, memory, perms);
174} 175}
175 176
176void ARM_Dynarmic::UnmapMemory(u64 address, size_t size) { 177void ARM_Dynarmic::UnmapMemory(u64 address, std::size_t size) {
177 inner_unicorn.UnmapMemory(address, size); 178 inner_unicorn.UnmapMemory(address, size);
178} 179}
179 180
@@ -269,10 +270,10 @@ void ARM_Dynarmic::PageTableChanged() {
269 current_page_table = Memory::GetCurrentPageTable(); 270 current_page_table = Memory::GetCurrentPageTable();
270} 271}
271 272
272DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(size_t core_count) : monitor(core_count) {} 273DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
273DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; 274DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
274 275
275void DynarmicExclusiveMonitor::SetExclusive(size_t core_index, VAddr addr) { 276void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) {
276 // Size doesn't actually matter. 277 // Size doesn't actually matter.
277 monitor.Mark(core_index, addr, 16); 278 monitor.Mark(core_index, addr, 16);
278} 279}
@@ -281,27 +282,27 @@ void DynarmicExclusiveMonitor::ClearExclusive() {
281 monitor.Clear(); 282 monitor.Clear();
282} 283}
283 284
284bool DynarmicExclusiveMonitor::ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) { 285bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
285 return monitor.DoExclusiveOperation(core_index, vaddr, 1, 286 return monitor.DoExclusiveOperation(core_index, vaddr, 1,
286 [&] { Memory::Write8(vaddr, value); }); 287 [&] { Memory::Write8(vaddr, value); });
287} 288}
288 289
289bool DynarmicExclusiveMonitor::ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) { 290bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
290 return monitor.DoExclusiveOperation(core_index, vaddr, 2, 291 return monitor.DoExclusiveOperation(core_index, vaddr, 2,
291 [&] { Memory::Write16(vaddr, value); }); 292 [&] { Memory::Write16(vaddr, value); });
292} 293}
293 294
294bool DynarmicExclusiveMonitor::ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) { 295bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
295 return monitor.DoExclusiveOperation(core_index, vaddr, 4, 296 return monitor.DoExclusiveOperation(core_index, vaddr, 4,
296 [&] { Memory::Write32(vaddr, value); }); 297 [&] { Memory::Write32(vaddr, value); });
297} 298}
298 299
299bool DynarmicExclusiveMonitor::ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) { 300bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
300 return monitor.DoExclusiveOperation(core_index, vaddr, 8, 301 return monitor.DoExclusiveOperation(core_index, vaddr, 8,
301 [&] { Memory::Write64(vaddr, value); }); 302 [&] { Memory::Write64(vaddr, value); });
302} 303}
303 304
304bool DynarmicExclusiveMonitor::ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) { 305bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) {
305 return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { 306 return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] {
306 Memory::Write64(vaddr, value[0]); 307 Memory::Write64(vaddr, value[0]);
307 Memory::Write64(vaddr, value[1]); 308 Memory::Write64(vaddr, value[1]);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 3bdfd8cd9..56c60c853 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -19,12 +19,12 @@ class DynarmicExclusiveMonitor;
19 19
20class ARM_Dynarmic final : public ARM_Interface { 20class ARM_Dynarmic final : public ARM_Interface {
21public: 21public:
22 ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index); 22 ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, std::size_t core_index);
23 ~ARM_Dynarmic(); 23 ~ARM_Dynarmic();
24 24
25 void MapBackingMemory(VAddr address, size_t size, u8* memory, 25 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
26 Kernel::VMAPermission perms) override; 26 Kernel::VMAPermission perms) override;
27 void UnmapMemory(u64 address, size_t size) override; 27 void UnmapMemory(u64 address, std::size_t size) override;
28 void SetPC(u64 pc) override; 28 void SetPC(u64 pc) override;
29 u64 GetPC() const override; 29 u64 GetPC() const override;
30 u64 GetReg(int index) const override; 30 u64 GetReg(int index) const override;
@@ -59,7 +59,7 @@ private:
59 std::unique_ptr<Dynarmic::A64::Jit> jit; 59 std::unique_ptr<Dynarmic::A64::Jit> jit;
60 ARM_Unicorn inner_unicorn; 60 ARM_Unicorn inner_unicorn;
61 61
62 size_t core_index; 62 std::size_t core_index;
63 std::shared_ptr<DynarmicExclusiveMonitor> exclusive_monitor; 63 std::shared_ptr<DynarmicExclusiveMonitor> exclusive_monitor;
64 64
65 Memory::PageTable* current_page_table = nullptr; 65 Memory::PageTable* current_page_table = nullptr;
@@ -67,17 +67,17 @@ private:
67 67
68class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 68class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
69public: 69public:
70 explicit DynarmicExclusiveMonitor(size_t core_count); 70 explicit DynarmicExclusiveMonitor(std::size_t core_count);
71 ~DynarmicExclusiveMonitor(); 71 ~DynarmicExclusiveMonitor();
72 72
73 void SetExclusive(size_t core_index, VAddr addr) override; 73 void SetExclusive(std::size_t core_index, VAddr addr) override;
74 void ClearExclusive() override; 74 void ClearExclusive() override;
75 75
76 bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) override; 76 bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override;
77 bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) override; 77 bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override;
78 bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) override; 78 bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) override;
79 bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) override; 79 bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) override;
80 bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) override; 80 bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override;
81 81
82private: 82private:
83 friend class ARM_Dynarmic; 83 friend class ARM_Dynarmic;
diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h
index 6f9b51573..f59aca667 100644
--- a/src/core/arm/exclusive_monitor.h
+++ b/src/core/arm/exclusive_monitor.h
@@ -12,14 +12,14 @@ class ExclusiveMonitor {
12public: 12public:
13 virtual ~ExclusiveMonitor(); 13 virtual ~ExclusiveMonitor();
14 14
15 virtual void SetExclusive(size_t core_index, VAddr addr) = 0; 15 virtual void SetExclusive(std::size_t core_index, VAddr addr) = 0;
16 virtual void ClearExclusive() = 0; 16 virtual void ClearExclusive() = 0;
17 17
18 virtual bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) = 0; 18 virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0;
19 virtual bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) = 0; 19 virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0;
20 virtual bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) = 0; 20 virtual bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) = 0;
21 virtual bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) = 0; 21 virtual bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) = 0;
22 virtual bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) = 0; 22 virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0;
23}; 23};
24 24
25} // namespace Core 25} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 4c4de2623..4e02b7cd4 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -90,12 +90,12 @@ ARM_Unicorn::~ARM_Unicorn() {
90 CHECKED(uc_close(uc)); 90 CHECKED(uc_close(uc));
91} 91}
92 92
93void ARM_Unicorn::MapBackingMemory(VAddr address, size_t size, u8* memory, 93void ARM_Unicorn::MapBackingMemory(VAddr address, std::size_t size, u8* memory,
94 Kernel::VMAPermission perms) { 94 Kernel::VMAPermission perms) {
95 CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory)); 95 CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory));
96} 96}
97 97
98void ARM_Unicorn::UnmapMemory(VAddr address, size_t size) { 98void ARM_Unicorn::UnmapMemory(VAddr address, std::size_t size) {
99 CHECKED(uc_mem_unmap(uc, address, size)); 99 CHECKED(uc_mem_unmap(uc, address, size));
100} 100}
101 101
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index bd6b2f723..d6f7cf4ab 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -15,9 +15,9 @@ class ARM_Unicorn final : public ARM_Interface {
15public: 15public:
16 ARM_Unicorn(); 16 ARM_Unicorn();
17 ~ARM_Unicorn(); 17 ~ARM_Unicorn();
18 void MapBackingMemory(VAddr address, size_t size, u8* memory, 18 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
19 Kernel::VMAPermission perms) override; 19 Kernel::VMAPermission perms) override;
20 void UnmapMemory(VAddr address, size_t size) override; 20 void UnmapMemory(VAddr address, std::size_t size) override;
21 void SetPC(u64 pc) override; 21 void SetPC(u64 pc) override;
22 u64 GetPC() const override; 22 u64 GetPC() const override;
23 u64 GetReg(int index) const override; 23 u64 GetReg(int index) const override;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 713ee17c1..50f0a42fb 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -140,7 +140,7 @@ struct System::Impl {
140 140
141 cpu_barrier = std::make_shared<CpuBarrier>(); 141 cpu_barrier = std::make_shared<CpuBarrier>();
142 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); 142 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
143 for (size_t index = 0; index < cpu_cores.size(); ++index) { 143 for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
144 cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index); 144 cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index);
145 } 145 }
146 146
@@ -161,7 +161,7 @@ struct System::Impl {
161 // CPU core 0 is run on the main thread 161 // CPU core 0 is run on the main thread
162 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; 162 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
163 if (Settings::values.use_multi_core) { 163 if (Settings::values.use_multi_core) {
164 for (size_t index = 0; index < cpu_core_threads.size(); ++index) { 164 for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
165 cpu_core_threads[index] = 165 cpu_core_threads[index] =
166 std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]); 166 std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]);
167 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1]; 167 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1];
@@ -285,7 +285,7 @@ struct System::Impl {
285 std::shared_ptr<CpuBarrier> cpu_barrier; 285 std::shared_ptr<CpuBarrier> cpu_barrier;
286 std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; 286 std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
287 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; 287 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
288 size_t active_core{}; ///< Active core, only used in single thread mode 288 std::size_t active_core{}; ///< Active core, only used in single thread mode
289 289
290 /// Service manager 290 /// Service manager
291 std::shared_ptr<Service::SM::ServiceManager> service_manager; 291 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -348,7 +348,7 @@ ARM_Interface& System::CurrentArmInterface() {
348 return CurrentCpuCore().ArmInterface(); 348 return CurrentCpuCore().ArmInterface();
349} 349}
350 350
351size_t System::CurrentCoreIndex() { 351std::size_t System::CurrentCoreIndex() {
352 return CurrentCpuCore().CoreIndex(); 352 return CurrentCpuCore().CoreIndex();
353} 353}
354 354
@@ -356,7 +356,7 @@ Kernel::Scheduler& System::CurrentScheduler() {
356 return *CurrentCpuCore().Scheduler(); 356 return *CurrentCpuCore().Scheduler();
357} 357}
358 358
359const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) { 359const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(std::size_t core_index) {
360 ASSERT(core_index < NUM_CPU_CORES); 360 ASSERT(core_index < NUM_CPU_CORES);
361 return impl->cpu_cores[core_index]->Scheduler(); 361 return impl->cpu_cores[core_index]->Scheduler();
362} 362}
@@ -369,12 +369,12 @@ const Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() const {
369 return impl->kernel.CurrentProcess(); 369 return impl->kernel.CurrentProcess();
370} 370}
371 371
372ARM_Interface& System::ArmInterface(size_t core_index) { 372ARM_Interface& System::ArmInterface(std::size_t core_index) {
373 ASSERT(core_index < NUM_CPU_CORES); 373 ASSERT(core_index < NUM_CPU_CORES);
374 return impl->cpu_cores[core_index]->ArmInterface(); 374 return impl->cpu_cores[core_index]->ArmInterface();
375} 375}
376 376
377Cpu& System::CpuCore(size_t core_index) { 377Cpu& System::CpuCore(std::size_t core_index) {
378 ASSERT(core_index < NUM_CPU_CORES); 378 ASSERT(core_index < NUM_CPU_CORES);
379 return *impl->cpu_cores[core_index]; 379 return *impl->cpu_cores[core_index];
380} 380}
diff --git a/src/core/core.h b/src/core/core.h
index ab3663427..f9a3e97e3 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -145,16 +145,16 @@ public:
145 ARM_Interface& CurrentArmInterface(); 145 ARM_Interface& CurrentArmInterface();
146 146
147 /// Gets the index of the currently running CPU core 147 /// Gets the index of the currently running CPU core
148 size_t CurrentCoreIndex(); 148 std::size_t CurrentCoreIndex();
149 149
150 /// Gets the scheduler for the CPU core that is currently running 150 /// Gets the scheduler for the CPU core that is currently running
151 Kernel::Scheduler& CurrentScheduler(); 151 Kernel::Scheduler& CurrentScheduler();
152 152
153 /// Gets an ARM interface to the CPU core with the specified index 153 /// Gets an ARM interface to the CPU core with the specified index
154 ARM_Interface& ArmInterface(size_t core_index); 154 ARM_Interface& ArmInterface(std::size_t core_index);
155 155
156 /// Gets a CPU interface to the CPU core with the specified index 156 /// Gets a CPU interface to the CPU core with the specified index
157 Cpu& CpuCore(size_t core_index); 157 Cpu& CpuCore(std::size_t core_index);
158 158
159 /// Gets the exclusive monitor 159 /// Gets the exclusive monitor
160 ExclusiveMonitor& Monitor(); 160 ExclusiveMonitor& Monitor();
@@ -172,7 +172,7 @@ public:
172 const VideoCore::RendererBase& Renderer() const; 172 const VideoCore::RendererBase& Renderer() const;
173 173
174 /// Gets the scheduler for the CPU core with the specified index 174 /// Gets the scheduler for the CPU core with the specified index
175 const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index); 175 const std::shared_ptr<Kernel::Scheduler>& Scheduler(std::size_t core_index);
176 176
177 /// Provides a reference to the current process 177 /// Provides a reference to the current process
178 Kernel::SharedPtr<Kernel::Process>& CurrentProcess(); 178 Kernel::SharedPtr<Kernel::Process>& CurrentProcess();
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index b042ee02b..15d60cc8a 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -49,7 +49,7 @@ bool CpuBarrier::Rendezvous() {
49} 49}
50 50
51Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, 51Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
52 std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index) 52 std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index)
53 : cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} { 53 : cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} {
54 54
55 if (Settings::values.use_cpu_jit) { 55 if (Settings::values.use_cpu_jit) {
@@ -66,7 +66,7 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
66 scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get()); 66 scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
67} 67}
68 68
69std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(size_t num_cores) { 69std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
70 if (Settings::values.use_cpu_jit) { 70 if (Settings::values.use_cpu_jit) {
71#ifdef ARCHITECTURE_x86_64 71#ifdef ARCHITECTURE_x86_64
72 return std::make_shared<DynarmicExclusiveMonitor>(num_cores); 72 return std::make_shared<DynarmicExclusiveMonitor>(num_cores);
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 40ed34b47..1d229b42f 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -42,7 +42,7 @@ private:
42class Cpu { 42class Cpu {
43public: 43public:
44 Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, 44 Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
45 std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index); 45 std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index);
46 46
47 void RunLoop(bool tight_loop = true); 47 void RunLoop(bool tight_loop = true);
48 48
@@ -66,11 +66,11 @@ public:
66 return core_index == 0; 66 return core_index == 0;
67 } 67 }
68 68
69 size_t CoreIndex() const { 69 std::size_t CoreIndex() const {
70 return core_index; 70 return core_index;
71 } 71 }
72 72
73 static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(size_t num_cores); 73 static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores);
74 74
75private: 75private:
76 void Reschedule(); 76 void Reschedule();
@@ -80,7 +80,7 @@ private:
80 std::shared_ptr<Kernel::Scheduler> scheduler; 80 std::shared_ptr<Kernel::Scheduler> scheduler;
81 81
82 std::atomic<bool> reschedule_pending = false; 82 std::atomic<bool> reschedule_pending = false;
83 size_t core_index; 83 std::size_t core_index;
84}; 84};
85 85
86} // namespace Core 86} // namespace Core
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp
index 89ade5000..4be76bb43 100644
--- a/src/core/crypto/aes_util.cpp
+++ b/src/core/crypto/aes_util.cpp
@@ -10,9 +10,9 @@
10 10
11namespace Core::Crypto { 11namespace Core::Crypto {
12namespace { 12namespace {
13std::vector<u8> CalculateNintendoTweak(size_t sector_id) { 13std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) {
14 std::vector<u8> out(0x10); 14 std::vector<u8> out(0x10);
15 for (size_t i = 0xF; i <= 0xF; --i) { 15 for (std::size_t i = 0xF; i <= 0xF; --i) {
16 out[i] = sector_id & 0xFF; 16 out[i] = sector_id & 0xFF;
17 sector_id >>= 8; 17 sector_id >>= 8;
18 } 18 }
@@ -20,11 +20,14 @@ std::vector<u8> CalculateNintendoTweak(size_t sector_id) {
20} 20}
21} // Anonymous namespace 21} // Anonymous namespace
22 22
23static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), 23static_assert(static_cast<std::size_t>(Mode::CTR) ==
24 static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_CTR),
24 "CTR has incorrect value."); 25 "CTR has incorrect value.");
25static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), 26static_assert(static_cast<std::size_t>(Mode::ECB) ==
27 static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_ECB),
26 "ECB has incorrect value."); 28 "ECB has incorrect value.");
27static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), 29static_assert(static_cast<std::size_t>(Mode::XTS) ==
30 static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_XTS),
28 "XTS has incorrect value."); 31 "XTS has incorrect value.");
29 32
30// Structure to hide mbedtls types from header file 33// Structure to hide mbedtls types from header file
@@ -33,7 +36,7 @@ struct CipherContext {
33 mbedtls_cipher_context_t decryption_context; 36 mbedtls_cipher_context_t decryption_context;
34}; 37};
35 38
36template <typename Key, size_t KeySize> 39template <typename Key, std::size_t KeySize>
37Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) 40Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
38 : ctx(std::make_unique<CipherContext>()) { 41 : ctx(std::make_unique<CipherContext>()) {
39 mbedtls_cipher_init(&ctx->encryption_context); 42 mbedtls_cipher_init(&ctx->encryption_context);
@@ -54,26 +57,26 @@ Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
54 //"Failed to set key on mbedtls ciphers."); 57 //"Failed to set key on mbedtls ciphers.");
55} 58}
56 59
57template <typename Key, size_t KeySize> 60template <typename Key, std::size_t KeySize>
58AESCipher<Key, KeySize>::~AESCipher() { 61AESCipher<Key, KeySize>::~AESCipher() {
59 mbedtls_cipher_free(&ctx->encryption_context); 62 mbedtls_cipher_free(&ctx->encryption_context);
60 mbedtls_cipher_free(&ctx->decryption_context); 63 mbedtls_cipher_free(&ctx->decryption_context);
61} 64}
62 65
63template <typename Key, size_t KeySize> 66template <typename Key, std::size_t KeySize>
64void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) { 67void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
65 ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) || 68 ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
66 mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0, 69 mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
67 "Failed to set IV on mbedtls ciphers."); 70 "Failed to set IV on mbedtls ciphers.");
68} 71}
69 72
70template <typename Key, size_t KeySize> 73template <typename Key, std::size_t KeySize>
71void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) const { 74void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
72 auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context; 75 auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
73 76
74 mbedtls_cipher_reset(context); 77 mbedtls_cipher_reset(context);
75 78
76 size_t written = 0; 79 std::size_t written = 0;
77 if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) { 80 if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) {
78 mbedtls_cipher_update(context, src, size, dest, &written); 81 mbedtls_cipher_update(context, src, size, dest, &written);
79 if (written != size) { 82 if (written != size) {
@@ -90,8 +93,8 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op
90 return; 93 return;
91 } 94 }
92 95
93 for (size_t offset = 0; offset < size; offset += block_size) { 96 for (std::size_t offset = 0; offset < size; offset += block_size) {
94 auto length = std::min<size_t>(block_size, size - offset); 97 auto length = std::min<std::size_t>(block_size, size - offset);
95 mbedtls_cipher_update(context, src + offset, length, dest + offset, &written); 98 mbedtls_cipher_update(context, src + offset, length, dest + offset, &written);
96 if (written != length) { 99 if (written != length) {
97 if (length < block_size) { 100 if (length < block_size) {
@@ -110,12 +113,12 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op
110 mbedtls_cipher_finish(context, nullptr, nullptr); 113 mbedtls_cipher_finish(context, nullptr, nullptr);
111} 114}
112 115
113template <typename Key, size_t KeySize> 116template <typename Key, std::size_t KeySize>
114void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, 117void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8* dest,
115 size_t sector_size, Op op) { 118 std::size_t sector_id, std::size_t sector_size, Op op) {
116 ASSERT_MSG(size % sector_size == 0, "XTS decryption size must be a multiple of sector size."); 119 ASSERT_MSG(size % sector_size == 0, "XTS decryption size must be a multiple of sector size.");
117 120
118 for (size_t i = 0; i < size; i += sector_size) { 121 for (std::size_t i = 0; i < size; i += sector_size) {
119 SetIV(CalculateNintendoTweak(sector_id++)); 122 SetIV(CalculateNintendoTweak(sector_id++));
120 Transcode<u8, u8>(src + i, sector_size, dest + i, op); 123 Transcode<u8, u8>(src + i, sector_size, dest + i, op);
121 } 124 }
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h
index 8ce9d6612..edc4ab910 100644
--- a/src/core/crypto/aes_util.h
+++ b/src/core/crypto/aes_util.h
@@ -25,7 +25,7 @@ enum class Op {
25 Decrypt, 25 Decrypt,
26}; 26};
27 27
28template <typename Key, size_t KeySize = sizeof(Key)> 28template <typename Key, std::size_t KeySize = sizeof(Key)>
29class AESCipher { 29class AESCipher {
30 static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8."); 30 static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8.");
31 static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256."); 31 static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256.");
@@ -38,25 +38,25 @@ public:
38 void SetIV(std::vector<u8> iv); 38 void SetIV(std::vector<u8> iv);
39 39
40 template <typename Source, typename Dest> 40 template <typename Source, typename Dest>
41 void Transcode(const Source* src, size_t size, Dest* dest, Op op) const { 41 void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
42 static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>, 42 static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
43 "Transcode source and destination types must be trivially copyable."); 43 "Transcode source and destination types must be trivially copyable.");
44 Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op); 44 Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op);
45 } 45 }
46 46
47 void Transcode(const u8* src, size_t size, u8* dest, Op op) const; 47 void Transcode(const u8* src, std::size_t size, u8* dest, Op op) const;
48 48
49 template <typename Source, typename Dest> 49 template <typename Source, typename Dest>
50 void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id, 50 void XTSTranscode(const Source* src, std::size_t size, Dest* dest, std::size_t sector_id,
51 size_t sector_size, Op op) { 51 std::size_t sector_size, Op op) {
52 static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>, 52 static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
53 "XTSTranscode source and destination types must be trivially copyable."); 53 "XTSTranscode source and destination types must be trivially copyable.");
54 XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id, 54 XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id,
55 sector_size, op); 55 sector_size, op);
56 } 56 }
57 57
58 void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, 58 void XTSTranscode(const u8* src, std::size_t size, u8* dest, std::size_t sector_id,
59 Op op); 59 std::size_t sector_size, Op op);
60 60
61private: 61private:
62 std::unique_ptr<CipherContext> ctx; 62 std::unique_ptr<CipherContext> ctx;
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp
index 296fad419..902841c77 100644
--- a/src/core/crypto/ctr_encryption_layer.cpp
+++ b/src/core/crypto/ctr_encryption_layer.cpp
@@ -8,11 +8,12 @@
8 8
9namespace Core::Crypto { 9namespace Core::Crypto {
10 10
11CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) 11CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
12 std::size_t base_offset)
12 : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), 13 : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
13 iv(16, 0) {} 14 iv(16, 0) {}
14 15
15size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { 16std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
16 if (length == 0) 17 if (length == 0)
17 return 0; 18 return 0;
18 19
@@ -28,7 +29,7 @@ size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const {
28 std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset); 29 std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset);
29 UpdateIV(base_offset + offset - sector_offset); 30 UpdateIV(base_offset + offset - sector_offset);
30 cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt); 31 cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt);
31 size_t read = 0x10 - sector_offset; 32 std::size_t read = 0x10 - sector_offset;
32 33
33 if (length + sector_offset < 0x10) { 34 if (length + sector_offset < 0x10) {
34 std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); 35 std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read));
@@ -43,9 +44,9 @@ void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
43 iv.assign(iv_.cbegin(), iv_.cbegin() + length); 44 iv.assign(iv_.cbegin(), iv_.cbegin() + length);
44} 45}
45 46
46void CTREncryptionLayer::UpdateIV(size_t offset) const { 47void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
47 offset >>= 4; 48 offset >>= 4;
48 for (size_t i = 0; i < 8; ++i) { 49 for (std::size_t i = 0; i < 8; ++i) {
49 iv[16 - i - 1] = offset & 0xFF; 50 iv[16 - i - 1] = offset & 0xFF;
50 offset >>= 8; 51 offset >>= 8;
51 } 52 }
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h
index 11b8683c7..a7bf810f4 100644
--- a/src/core/crypto/ctr_encryption_layer.h
+++ b/src/core/crypto/ctr_encryption_layer.h
@@ -14,20 +14,20 @@ namespace Core::Crypto {
14// Sits on top of a VirtualFile and provides CTR-mode AES decription. 14// Sits on top of a VirtualFile and provides CTR-mode AES decription.
15class CTREncryptionLayer : public EncryptionLayer { 15class CTREncryptionLayer : public EncryptionLayer {
16public: 16public:
17 CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset); 17 CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
18 18
19 size_t Read(u8* data, size_t length, size_t offset) const override; 19 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
20 20
21 void SetIV(const std::vector<u8>& iv); 21 void SetIV(const std::vector<u8>& iv);
22 22
23private: 23private:
24 size_t base_offset; 24 std::size_t base_offset;
25 25
26 // Must be mutable as operations modify cipher contexts. 26 // Must be mutable as operations modify cipher contexts.
27 mutable AESCipher<Key128> cipher; 27 mutable AESCipher<Key128> cipher;
28 mutable std::vector<u8> iv; 28 mutable std::vector<u8> iv;
29 29
30 void UpdateIV(size_t offset) const; 30 void UpdateIV(std::size_t offset) const;
31}; 31};
32 32
33} // namespace Core::Crypto 33} // namespace Core::Crypto
diff --git a/src/core/crypto/encryption_layer.cpp b/src/core/crypto/encryption_layer.cpp
index 4204527e3..4c377d7d4 100644
--- a/src/core/crypto/encryption_layer.cpp
+++ b/src/core/crypto/encryption_layer.cpp
@@ -12,11 +12,11 @@ std::string EncryptionLayer::GetName() const {
12 return base->GetName(); 12 return base->GetName();
13} 13}
14 14
15size_t EncryptionLayer::GetSize() const { 15std::size_t EncryptionLayer::GetSize() const {
16 return base->GetSize(); 16 return base->GetSize();
17} 17}
18 18
19bool EncryptionLayer::Resize(size_t new_size) { 19bool EncryptionLayer::Resize(std::size_t new_size) {
20 return false; 20 return false;
21} 21}
22 22
@@ -32,7 +32,7 @@ bool EncryptionLayer::IsReadable() const {
32 return true; 32 return true;
33} 33}
34 34
35size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) { 35std::size_t EncryptionLayer::Write(const u8* data, std::size_t length, std::size_t offset) {
36 return 0; 36 return 0;
37} 37}
38 38
diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h
index 7f05af9b4..53619cb38 100644
--- a/src/core/crypto/encryption_layer.h
+++ b/src/core/crypto/encryption_layer.h
@@ -15,15 +15,15 @@ class EncryptionLayer : public FileSys::VfsFile {
15public: 15public:
16 explicit EncryptionLayer(FileSys::VirtualFile base); 16 explicit EncryptionLayer(FileSys::VirtualFile base);
17 17
18 size_t Read(u8* data, size_t length, size_t offset) const override = 0; 18 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override = 0;
19 19
20 std::string GetName() const override; 20 std::string GetName() const override;
21 size_t GetSize() const override; 21 std::size_t GetSize() const override;
22 bool Resize(size_t new_size) override; 22 bool Resize(std::size_t new_size) override;
23 std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override; 23 std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override;
24 bool IsWritable() const override; 24 bool IsWritable() const override;
25 bool IsReadable() const override; 25 bool IsReadable() const override;
26 size_t Write(const u8* data, size_t length, size_t offset) override; 26 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
27 bool Rename(std::string_view name) override; 27 bool Rename(std::string_view name) override;
28 28
29protected: 29protected:
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 6f27f990b..bf3a70944 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -54,7 +54,7 @@ boost::optional<Key128> DeriveSDSeed() {
54 return boost::none; 54 return boost::none;
55 55
56 std::array<u8, 0x10> buffer{}; 56 std::array<u8, 0x10> buffer{};
57 size_t offset = 0; 57 std::size_t offset = 0;
58 for (; offset + 0x10 < save_43.GetSize(); ++offset) { 58 for (; offset + 0x10 < save_43.GetSize(); ++offset) {
59 save_43.Seek(offset, SEEK_SET); 59 save_43.Seek(offset, SEEK_SET);
60 save_43.ReadBytes(buffer.data(), buffer.size()); 60 save_43.ReadBytes(buffer.data(), buffer.size());
@@ -105,7 +105,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManag
105 105
106 // Combine sources and seed 106 // Combine sources and seed
107 for (auto& source : sd_key_sources) { 107 for (auto& source : sd_key_sources) {
108 for (size_t i = 0; i < source.size(); ++i) 108 for (std::size_t i = 0; i < source.size(); ++i)
109 source[i] ^= sd_seed[i & 0xF]; 109 source[i] ^= sd_seed[i & 0xF];
110 } 110 }
111 111
@@ -207,7 +207,7 @@ Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
207 return s256_keys.at({id, field1, field2}); 207 return s256_keys.at({id, field1, field2});
208} 208}
209 209
210template <size_t Size> 210template <std::size_t Size>
211void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, 211void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname,
212 const std::array<u8, Size>& key) { 212 const std::array<u8, Size>& key) {
213 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); 213 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index ce67913bb..978eec8dc 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -108,7 +108,7 @@ private:
108 void LoadFromFile(const std::string& filename, bool is_title_keys); 108 void LoadFromFile(const std::string& filename, bool is_title_keys);
109 void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, 109 void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
110 const std::string& filename, bool title); 110 const std::string& filename, bool title);
111 template <size_t Size> 111 template <std::size_t Size>
112 void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key); 112 void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key);
113 113
114 static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id; 114 static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
diff --git a/src/core/crypto/xts_encryption_layer.cpp b/src/core/crypto/xts_encryption_layer.cpp
index c10832cfe..8f0ba4ee7 100644
--- a/src/core/crypto/xts_encryption_layer.cpp
+++ b/src/core/crypto/xts_encryption_layer.cpp
@@ -14,7 +14,7 @@ constexpr u64 XTS_SECTOR_SIZE = 0x4000;
14XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_) 14XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_)
15 : EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {} 15 : EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {}
16 16
17size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const { 17std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
18 if (length == 0) 18 if (length == 0)
19 return 0; 19 return 0;
20 20
@@ -46,7 +46,7 @@ size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const {
46 block.resize(XTS_SECTOR_SIZE); 46 block.resize(XTS_SECTOR_SIZE);
47 cipher.XTSTranscode(block.data(), block.size(), block.data(), 47 cipher.XTSTranscode(block.data(), block.size(), block.data(),
48 (offset - sector_offset) / XTS_SECTOR_SIZE, XTS_SECTOR_SIZE, Op::Decrypt); 48 (offset - sector_offset) / XTS_SECTOR_SIZE, XTS_SECTOR_SIZE, Op::Decrypt);
49 const size_t read = XTS_SECTOR_SIZE - sector_offset; 49 const std::size_t read = XTS_SECTOR_SIZE - sector_offset;
50 50
51 if (length + sector_offset < XTS_SECTOR_SIZE) { 51 if (length + sector_offset < XTS_SECTOR_SIZE) {
52 std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); 52 std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read));
diff --git a/src/core/crypto/xts_encryption_layer.h b/src/core/crypto/xts_encryption_layer.h
index 7a1f1dc64..5f8f00fe7 100644
--- a/src/core/crypto/xts_encryption_layer.h
+++ b/src/core/crypto/xts_encryption_layer.h
@@ -15,7 +15,7 @@ class XTSEncryptionLayer : public EncryptionLayer {
15public: 15public:
16 XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key); 16 XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key);
17 17
18 size_t Read(u8* data, size_t length, size_t offset) const override; 18 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
19 19
20private: 20private:
21 // Must be mutable as operations modify cipher contexts. 21 // Must be mutable as operations modify cipher contexts.
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 8218893b2..edfc1bbd4 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -41,13 +41,14 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
41 41
42 for (XCIPartition partition : 42 for (XCIPartition partition :
43 {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) { 43 {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
44 auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]); 44 auto raw = main_hfs.GetFile(partition_names[static_cast<std::size_t>(partition)]);
45 if (raw != nullptr) 45 if (raw != nullptr)
46 partitions[static_cast<size_t>(partition)] = std::make_shared<PartitionFilesystem>(raw); 46 partitions[static_cast<std::size_t>(partition)] =
47 std::make_shared<PartitionFilesystem>(raw);
47 } 48 }
48 49
49 secure_partition = std::make_shared<NSP>( 50 secure_partition = std::make_shared<NSP>(
50 main_hfs.GetFile(partition_names[static_cast<size_t>(XCIPartition::Secure)])); 51 main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]));
51 52
52 const auto secure_ncas = secure_partition->GetNCAsCollapsed(); 53 const auto secure_ncas = secure_partition->GetNCAsCollapsed();
53 std::copy(secure_ncas.begin(), secure_ncas.end(), std::back_inserter(ncas)); 54 std::copy(secure_ncas.begin(), secure_ncas.end(), std::back_inserter(ncas));
@@ -92,7 +93,7 @@ Loader::ResultStatus XCI::GetProgramNCAStatus() const {
92} 93}
93 94
94VirtualDir XCI::GetPartition(XCIPartition partition) const { 95VirtualDir XCI::GetPartition(XCIPartition partition) const {
95 return partitions[static_cast<size_t>(partition)]; 96 return partitions[static_cast<std::size_t>(partition)];
96} 97}
97 98
98std::shared_ptr<NSP> XCI::GetSecurePartitionNSP() const { 99std::shared_ptr<NSP> XCI::GetSecurePartitionNSP() const {
@@ -168,11 +169,11 @@ bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
168} 169}
169 170
170Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { 171Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
171 if (partitions[static_cast<size_t>(part)] == nullptr) { 172 if (partitions[static_cast<std::size_t>(part)] == nullptr) {
172 return Loader::ResultStatus::ErrorXCIMissingPartition; 173 return Loader::ResultStatus::ErrorXCIMissingPartition;
173 } 174 }
174 175
175 for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) { 176 for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) {
176 if (file->GetExtension() != "nca") 177 if (file->GetExtension() != "nca")
177 continue; 178 continue;
178 auto nca = std::make_shared<NCA>(file); 179 auto nca = std::make_shared<NCA>(file);
@@ -187,7 +188,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
187 } else { 188 } else {
188 const u16 error_id = static_cast<u16>(nca->GetStatus()); 189 const u16 error_id = static_cast<u16>(nca->GetStatus());
189 LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})", 190 LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})",
190 partition_names[static_cast<size_t>(part)], nca->GetName(), error_id, 191 partition_names[static_cast<std::size_t>(part)], nca->GetName(), error_id,
191 nca->GetStatus()); 192 nca->GetStatus());
192 } 193 }
193 } 194 }
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 79bfb6fec..45fc0b574 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -298,11 +298,11 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
298 auto section = sections[i]; 298 auto section = sections[i];
299 299
300 if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) { 300 if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
301 const size_t base_offset = 301 const std::size_t base_offset =
302 header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER; 302 header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER;
303 ivfc_offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; 303 ivfc_offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset;
304 const size_t romfs_offset = base_offset + ivfc_offset; 304 const std::size_t romfs_offset = base_offset + ivfc_offset;
305 const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size; 305 const std::size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size;
306 auto raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset); 306 auto raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset);
307 auto dec = Decrypt(section, raw, romfs_offset); 307 auto dec = Decrypt(section, raw, romfs_offset);
308 308
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
index 3759e743a..12bb90ec8 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory.h
@@ -25,7 +25,7 @@ enum EntryType : u8 {
25struct Entry { 25struct Entry {
26 Entry(std::string_view view, EntryType entry_type, u64 entry_size) 26 Entry(std::string_view view, EntryType entry_type, u64 entry_size)
27 : type{entry_type}, file_size{entry_size} { 27 : type{entry_type}, file_size{entry_size} {
28 const size_t copy_size = view.copy(filename, std::size(filename) - 1); 28 const std::size_t copy_size = view.copy(filename, std::size(filename) - 1);
29 filename[copy_size] = '\0'; 29 filename[copy_size] = '\0';
30 } 30 }
31 31
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index cdfbc5aaf..479916b69 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -11,11 +11,11 @@
11namespace FileSys { 11namespace FileSys {
12 12
13bool operator>=(TitleType lhs, TitleType rhs) { 13bool operator>=(TitleType lhs, TitleType rhs) {
14 return static_cast<size_t>(lhs) >= static_cast<size_t>(rhs); 14 return static_cast<std::size_t>(lhs) >= static_cast<std::size_t>(rhs);
15} 15}
16 16
17bool operator<=(TitleType lhs, TitleType rhs) { 17bool operator<=(TitleType lhs, TitleType rhs) {
18 return static_cast<size_t>(lhs) <= static_cast<size_t>(rhs); 18 return static_cast<std::size_t>(lhs) <= static_cast<std::size_t>(rhs);
19} 19}
20 20
21CNMT::CNMT(VirtualFile file) { 21CNMT::CNMT(VirtualFile file) {
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp
index 6fc5bd7d8..0090cc6c4 100644
--- a/src/core/file_sys/nca_patch.cpp
+++ b/src/core/file_sys/nca_patch.cpp
@@ -22,11 +22,11 @@ BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock rel
22 base_romfs(std::move(base_romfs_)), bktr_romfs(std::move(bktr_romfs_)), 22 base_romfs(std::move(base_romfs_)), bktr_romfs(std::move(bktr_romfs_)),
23 encrypted(is_encrypted_), key(key_), base_offset(base_offset_), ivfc_offset(ivfc_offset_), 23 encrypted(is_encrypted_), key(key_), base_offset(base_offset_), ivfc_offset(ivfc_offset_),
24 section_ctr(section_ctr_) { 24 section_ctr(section_ctr_) {
25 for (size_t i = 0; i < relocation.number_buckets - 1; ++i) { 25 for (std::size_t i = 0; i < relocation.number_buckets - 1; ++i) {
26 relocation_buckets[i].entries.push_back({relocation.base_offsets[i + 1], 0, 0}); 26 relocation_buckets[i].entries.push_back({relocation.base_offsets[i + 1], 0, 0});
27 } 27 }
28 28
29 for (size_t i = 0; i < subsection.number_buckets - 1; ++i) { 29 for (std::size_t i = 0; i < subsection.number_buckets - 1; ++i) {
30 subsection_buckets[i].entries.push_back({subsection_buckets[i + 1].entries[0].address_patch, 30 subsection_buckets[i].entries.push_back({subsection_buckets[i + 1].entries[0].address_patch,
31 {0}, 31 {0},
32 subsection_buckets[i + 1].entries[0].ctr}); 32 subsection_buckets[i + 1].entries[0].ctr});
@@ -37,7 +37,7 @@ BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock rel
37 37
38BKTR::~BKTR() = default; 38BKTR::~BKTR() = default;
39 39
40size_t BKTR::Read(u8* data, size_t length, size_t offset) const { 40std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
41 // Read out of bounds. 41 // Read out of bounds.
42 if (offset >= relocation.size) 42 if (offset >= relocation.size)
43 return 0; 43 return 0;
@@ -69,14 +69,14 @@ size_t BKTR::Read(u8* data, size_t length, size_t offset) const {
69 std::vector<u8> iv(16); 69 std::vector<u8> iv(16);
70 auto subsection_ctr = subsection.ctr; 70 auto subsection_ctr = subsection.ctr;
71 auto offset_iv = section_offset + base_offset; 71 auto offset_iv = section_offset + base_offset;
72 for (size_t i = 0; i < section_ctr.size(); ++i) 72 for (std::size_t i = 0; i < section_ctr.size(); ++i)
73 iv[i] = section_ctr[0x8 - i - 1]; 73 iv[i] = section_ctr[0x8 - i - 1];
74 offset_iv >>= 4; 74 offset_iv >>= 4;
75 for (size_t i = 0; i < sizeof(u64); ++i) { 75 for (std::size_t i = 0; i < sizeof(u64); ++i) {
76 iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF); 76 iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF);
77 offset_iv >>= 8; 77 offset_iv >>= 8;
78 } 78 }
79 for (size_t i = 0; i < sizeof(u32); ++i) { 79 for (std::size_t i = 0; i < sizeof(u32); ++i) {
80 iv[0x7 - i] = static_cast<u8>(subsection_ctr & 0xFF); 80 iv[0x7 - i] = static_cast<u8>(subsection_ctr & 0xFF);
81 subsection_ctr >>= 8; 81 subsection_ctr >>= 8;
82 } 82 }
@@ -110,8 +110,8 @@ size_t BKTR::Read(u8* data, size_t length, size_t offset) const {
110} 110}
111 111
112template <bool Subsection, typename BlockType, typename BucketType> 112template <bool Subsection, typename BlockType, typename BucketType>
113std::pair<size_t, size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block, 113std::pair<std::size_t, std::size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block,
114 BucketType buckets) const { 114 BucketType buckets) const {
115 if constexpr (Subsection) { 115 if constexpr (Subsection) {
116 const auto last_bucket = buckets[block.number_buckets - 1]; 116 const auto last_bucket = buckets[block.number_buckets - 1];
117 if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch) 117 if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch)
@@ -120,18 +120,18 @@ std::pair<size_t, size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block,
120 ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block."); 120 ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block.");
121 } 121 }
122 122
123 size_t bucket_id = std::count_if(block.base_offsets.begin() + 1, 123 std::size_t bucket_id = std::count_if(
124 block.base_offsets.begin() + block.number_buckets, 124 block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets,
125 [&offset](u64 base_offset) { return base_offset <= offset; }); 125 [&offset](u64 base_offset) { return base_offset <= offset; });
126 126
127 const auto bucket = buckets[bucket_id]; 127 const auto bucket = buckets[bucket_id];
128 128
129 if (bucket.number_entries == 1) 129 if (bucket.number_entries == 1)
130 return {bucket_id, 0}; 130 return {bucket_id, 0};
131 131
132 size_t low = 0; 132 std::size_t low = 0;
133 size_t mid = 0; 133 std::size_t mid = 0;
134 size_t high = bucket.number_entries - 1; 134 std::size_t high = bucket.number_entries - 1;
135 while (low <= high) { 135 while (low <= high) {
136 mid = (low + high) / 2; 136 mid = (low + high) / 2;
137 if (bucket.entries[mid].address_patch > offset) { 137 if (bucket.entries[mid].address_patch > offset) {
@@ -179,11 +179,11 @@ std::string BKTR::GetName() const {
179 return base_romfs->GetName(); 179 return base_romfs->GetName();
180} 180}
181 181
182size_t BKTR::GetSize() const { 182std::size_t BKTR::GetSize() const {
183 return relocation.size; 183 return relocation.size;
184} 184}
185 185
186bool BKTR::Resize(size_t new_size) { 186bool BKTR::Resize(std::size_t new_size) {
187 return false; 187 return false;
188} 188}
189 189
@@ -199,7 +199,7 @@ bool BKTR::IsReadable() const {
199 return true; 199 return true;
200} 200}
201 201
202size_t BKTR::Write(const u8* data, size_t length, size_t offset) { 202std::size_t BKTR::Write(const u8* data, std::size_t length, std::size_t offset) {
203 return 0; 203 return 0;
204} 204}
205 205
diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h
index 381f3504f..8e64e8378 100644
--- a/src/core/file_sys/nca_patch.h
+++ b/src/core/file_sys/nca_patch.h
@@ -98,13 +98,13 @@ public:
98 Core::Crypto::Key128 key, u64 base_offset, u64 ivfc_offset, std::array<u8, 8> section_ctr); 98 Core::Crypto::Key128 key, u64 base_offset, u64 ivfc_offset, std::array<u8, 8> section_ctr);
99 ~BKTR() override; 99 ~BKTR() override;
100 100
101 size_t Read(u8* data, size_t length, size_t offset) const override; 101 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
102 102
103 std::string GetName() const override; 103 std::string GetName() const override;
104 104
105 size_t GetSize() const override; 105 std::size_t GetSize() const override;
106 106
107 bool Resize(size_t new_size) override; 107 bool Resize(std::size_t new_size) override;
108 108
109 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 109 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
110 110
@@ -112,14 +112,14 @@ public:
112 112
113 bool IsReadable() const override; 113 bool IsReadable() const override;
114 114
115 size_t Write(const u8* data, size_t length, size_t offset) override; 115 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
116 116
117 bool Rename(std::string_view name) override; 117 bool Rename(std::string_view name) override;
118 118
119private: 119private:
120 template <bool Subsection, typename BlockType, typename BucketType> 120 template <bool Subsection, typename BlockType, typename BucketType>
121 std::pair<size_t, size_t> SearchBucketEntry(u64 offset, BlockType block, 121 std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, BlockType block,
122 BucketType buckets) const; 122 BucketType buckets) const;
123 123
124 RelocationEntry GetRelocationEntry(u64 offset) const; 124 RelocationEntry GetRelocationEntry(u64 offset) const;
125 RelocationEntry GetNextRelocationEntry(u64 offset) const; 125 RelocationEntry GetNextRelocationEntry(u64 offset) const;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index c377edc9c..f5b3b0175 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -42,21 +42,21 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
42 42
43 is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0'); 43 is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
44 44
45 size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); 45 std::size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
46 size_t metadata_size = 46 std::size_t metadata_size =
47 sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size; 47 sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size;
48 48
49 // Actually read in now... 49 // Actually read in now...
50 std::vector<u8> file_data = file->ReadBytes(metadata_size); 50 std::vector<u8> file_data = file->ReadBytes(metadata_size);
51 const size_t total_size = file_data.size(); 51 const std::size_t total_size = file_data.size();
52 52
53 if (total_size != metadata_size) { 53 if (total_size != metadata_size) {
54 status = Loader::ResultStatus::ErrorIncorrectPFSFileSize; 54 status = Loader::ResultStatus::ErrorIncorrectPFSFileSize;
55 return; 55 return;
56 } 56 }
57 57
58 size_t entries_offset = sizeof(Header); 58 std::size_t entries_offset = sizeof(Header);
59 size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size); 59 std::size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size);
60 content_offset = strtab_offset + pfs_header.strtab_size; 60 content_offset = strtab_offset + pfs_header.strtab_size;
61 for (u16 i = 0; i < pfs_header.num_entries; i++) { 61 for (u16 i = 0; i < pfs_header.num_entries; i++) {
62 FSEntry entry; 62 FSEntry entry;
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index be7bc32a8..e80d2456b 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -79,7 +79,7 @@ private:
79 79
80 Header pfs_header{}; 80 Header pfs_header{};
81 bool is_hfs = false; 81 bool is_hfs = false;
82 size_t content_offset = 0; 82 std::size_t content_offset = 0;
83 83
84 std::vector<VirtualFile> pfs_files; 84 std::vector<VirtualFile> pfs_files;
85 std::vector<VirtualDir> pfs_dirs; 85 std::vector<VirtualDir> pfs_dirs;
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 6cecab336..b37b4c68b 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -21,7 +21,7 @@ constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
21std::string FormatTitleVersion(u32 version, TitleVersionFormat format) { 21std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
22 std::array<u8, sizeof(u32)> bytes{}; 22 std::array<u8, sizeof(u32)> bytes{};
23 bytes[0] = version % SINGLE_BYTE_MODULUS; 23 bytes[0] = version % SINGLE_BYTE_MODULUS;
24 for (size_t i = 1; i < bytes.size(); ++i) { 24 for (std::size_t i = 1; i < bytes.size(); ++i) {
25 version /= SINGLE_BYTE_MODULUS; 25 version /= SINGLE_BYTE_MODULUS;
26 bytes[i] = version % SINGLE_BYTE_MODULUS; 26 bytes[i] = version % SINGLE_BYTE_MODULUS;
27 } 27 }
@@ -36,7 +36,7 @@ constexpr std::array<const char*, 1> PATCH_TYPE_NAMES{
36}; 36};
37 37
38std::string FormatPatchTypeName(PatchType type) { 38std::string FormatPatchTypeName(PatchType type) {
39 return PATCH_TYPE_NAMES.at(static_cast<size_t>(type)); 39 return PATCH_TYPE_NAMES.at(static_cast<std::size_t>(type));
40} 40}
41 41
42PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} 42PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index ccb685526..9d19aaa6d 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -13,7 +13,7 @@
13namespace FileSys { 13namespace FileSys {
14 14
15Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { 15Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
16 size_t total_size = static_cast<size_t>(file->GetSize()); 16 std::size_t total_size = static_cast<std::size_t>(file->GetSize());
17 if (total_size < sizeof(Header)) 17 if (total_size < sizeof(Header))
18 return Loader::ResultStatus::ErrorBadNPDMHeader; 18 return Loader::ResultStatus::ErrorBadNPDMHeader;
19 19
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 7361a67be..dad7ae10b 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -62,11 +62,11 @@ static std::string GetCNMTName(TitleType type, u64 title_id) {
62 "" ///< Currently unknown 'DeltaTitle' 62 "" ///< Currently unknown 'DeltaTitle'
63 }; 63 };
64 64
65 auto index = static_cast<size_t>(type); 65 auto index = static_cast<std::size_t>(type);
66 // If the index is after the jump in TitleType, subtract it out. 66 // If the index is after the jump in TitleType, subtract it out.
67 if (index >= static_cast<size_t>(TitleType::Application)) { 67 if (index >= static_cast<std::size_t>(TitleType::Application)) {
68 index -= static_cast<size_t>(TitleType::Application) - 68 index -= static_cast<std::size_t>(TitleType::Application) -
69 static_cast<size_t>(TitleType::FirmwarePackageB); 69 static_cast<std::size_t>(TitleType::FirmwarePackageB);
70 } 70 }
71 return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); 71 return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id);
72} 72}
@@ -105,7 +105,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
105 } else { 105 } else {
106 std::vector<VirtualFile> concat; 106 std::vector<VirtualFile> concat;
107 // Since the files are a two-digit hex number, max is FF. 107 // Since the files are a two-digit hex number, max is FF.
108 for (size_t i = 0; i < 0x100; ++i) { 108 for (std::size_t i = 0; i < 0x100; ++i) {
109 auto next = nca_dir->GetFile(fmt::format("{:02X}", i)); 109 auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
110 if (next != nullptr) { 110 if (next != nullptr) {
111 concat.push_back(std::move(next)); 111 concat.push_back(std::move(next));
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index e490c8ace..9f6e41cdf 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -49,7 +49,7 @@ struct FileEntry {
49static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); 49static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
50 50
51template <typename Entry> 51template <typename Entry>
52static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t offset) { 52static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) {
53 Entry entry{}; 53 Entry entry{};
54 if (file->ReadObject(&entry, offset) != sizeof(Entry)) 54 if (file->ReadObject(&entry, offset) != sizeof(Entry))
55 return {}; 55 return {};
@@ -59,8 +59,8 @@ static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t of
59 return {entry, string}; 59 return {entry, string};
60} 60}
61 61
62void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 this_file_offset, 62void ProcessFile(VirtualFile file, std::size_t file_offset, std::size_t data_offset,
63 std::shared_ptr<VectorVfsDirectory> parent) { 63 u32 this_file_offset, std::shared_ptr<VectorVfsDirectory> parent) {
64 while (true) { 64 while (true) {
65 auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); 65 auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset);
66 66
@@ -74,8 +74,9 @@ void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 t
74 } 74 }
75} 75}
76 76
77void ProcessDirectory(VirtualFile file, size_t dir_offset, size_t file_offset, size_t data_offset, 77void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file_offset,
78 u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory> parent) { 78 std::size_t data_offset, u32 this_dir_offset,
79 std::shared_ptr<VectorVfsDirectory> parent) {
79 while (true) { 80 while (true) {
80 auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); 81 auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset);
81 auto current = std::make_shared<VectorVfsDirectory>( 82 auto current = std::make_shared<VectorVfsDirectory>(
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 146c839f4..d7b52abfd 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -167,18 +167,18 @@ std::string VfsFile::GetExtension() const {
167 167
168VfsDirectory::~VfsDirectory() = default; 168VfsDirectory::~VfsDirectory() = default;
169 169
170boost::optional<u8> VfsFile::ReadByte(size_t offset) const { 170boost::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
171 u8 out{}; 171 u8 out{};
172 size_t size = Read(&out, 1, offset); 172 std::size_t size = Read(&out, 1, offset);
173 if (size == 1) 173 if (size == 1)
174 return out; 174 return out;
175 175
176 return boost::none; 176 return boost::none;
177} 177}
178 178
179std::vector<u8> VfsFile::ReadBytes(size_t size, size_t offset) const { 179std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const {
180 std::vector<u8> out(size); 180 std::vector<u8> out(size);
181 size_t read_size = Read(out.data(), size, offset); 181 std::size_t read_size = Read(out.data(), size, offset);
182 out.resize(read_size); 182 out.resize(read_size);
183 return out; 183 return out;
184} 184}
@@ -187,11 +187,11 @@ std::vector<u8> VfsFile::ReadAllBytes() const {
187 return ReadBytes(GetSize()); 187 return ReadBytes(GetSize());
188} 188}
189 189
190bool VfsFile::WriteByte(u8 data, size_t offset) { 190bool VfsFile::WriteByte(u8 data, std::size_t offset) {
191 return Write(&data, 1, offset) == 1; 191 return Write(&data, 1, offset) == 1;
192} 192}
193 193
194size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) { 194std::size_t VfsFile::WriteBytes(const std::vector<u8>& data, std::size_t offset) {
195 return Write(data.data(), data.size(), offset); 195 return Write(data.data(), data.size(), offset);
196} 196}
197 197
@@ -215,7 +215,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) co
215 } 215 }
216 216
217 auto dir = GetSubdirectory(vec[0]); 217 auto dir = GetSubdirectory(vec[0]);
218 for (size_t component = 1; component < vec.size() - 1; ++component) { 218 for (std::size_t component = 1; component < vec.size() - 1; ++component) {
219 if (dir == nullptr) { 219 if (dir == nullptr) {
220 return nullptr; 220 return nullptr;
221 } 221 }
@@ -249,7 +249,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_vie
249 } 249 }
250 250
251 auto dir = GetSubdirectory(vec[0]); 251 auto dir = GetSubdirectory(vec[0]);
252 for (size_t component = 1; component < vec.size(); ++component) { 252 for (std::size_t component = 1; component < vec.size(); ++component) {
253 if (dir == nullptr) { 253 if (dir == nullptr) {
254 return nullptr; 254 return nullptr;
255 } 255 }
@@ -286,7 +286,7 @@ bool VfsDirectory::IsRoot() const {
286 return GetParentDirectory() == nullptr; 286 return GetParentDirectory() == nullptr;
287} 287}
288 288
289size_t VfsDirectory::GetSize() const { 289std::size_t VfsDirectory::GetSize() const {
290 const auto& files = GetFiles(); 290 const auto& files = GetFiles();
291 const auto sum_sizes = [](const auto& range) { 291 const auto sum_sizes = [](const auto& range) {
292 return std::accumulate(range.begin(), range.end(), 0ULL, 292 return std::accumulate(range.begin(), range.end(), 0ULL,
@@ -434,13 +434,13 @@ bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
434 return false; 434 return false;
435} 435}
436 436
437bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size) { 437bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t block_size) {
438 if (file1->GetSize() != file2->GetSize()) 438 if (file1->GetSize() != file2->GetSize())
439 return false; 439 return false;
440 440
441 std::vector<u8> f1_v(block_size); 441 std::vector<u8> f1_v(block_size);
442 std::vector<u8> f2_v(block_size); 442 std::vector<u8> f2_v(block_size);
443 for (size_t i = 0; i < file1->GetSize(); i += block_size) { 443 for (std::size_t i = 0; i < file1->GetSize(); i += block_size) {
444 auto f1_vs = file1->Read(f1_v.data(), block_size, i); 444 auto f1_vs = file1->Read(f1_v.data(), block_size, i);
445 auto f2_vs = file2->Read(f2_v.data(), block_size, i); 445 auto f2_vs = file2->Read(f2_v.data(), block_size, i);
446 446
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 5142a3e86..74489b452 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -92,9 +92,9 @@ public:
92 // Retrieves the extension of the file name. 92 // Retrieves the extension of the file name.
93 virtual std::string GetExtension() const; 93 virtual std::string GetExtension() const;
94 // Retrieves the size of the file. 94 // Retrieves the size of the file.
95 virtual size_t GetSize() const = 0; 95 virtual std::size_t GetSize() const = 0;
96 // Resizes the file to new_size. Returns whether or not the operation was successful. 96 // Resizes the file to new_size. Returns whether or not the operation was successful.
97 virtual bool Resize(size_t new_size) = 0; 97 virtual bool Resize(std::size_t new_size) = 0;
98 // Gets a pointer to the directory containing this file, returning nullptr if there is none. 98 // Gets a pointer to the directory containing this file, returning nullptr if there is none.
99 virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0; 99 virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0;
100 100
@@ -105,15 +105,15 @@ public:
105 105
106 // The primary method of reading from the file. Reads length bytes into data starting at offset 106 // The primary method of reading from the file. Reads length bytes into data starting at offset
107 // into file. Returns number of bytes successfully read. 107 // into file. Returns number of bytes successfully read.
108 virtual size_t Read(u8* data, size_t length, size_t offset = 0) const = 0; 108 virtual std::size_t Read(u8* data, std::size_t length, std::size_t offset = 0) const = 0;
109 // The primary method of writing to the file. Writes length bytes from data starting at offset 109 // The primary method of writing to the file. Writes length bytes from data starting at offset
110 // into file. Returns number of bytes successfully written. 110 // into file. Returns number of bytes successfully written.
111 virtual size_t Write(const u8* data, size_t length, size_t offset = 0) = 0; 111 virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0;
112 112
113 // Reads exactly one byte at the offset provided, returning boost::none on error. 113 // Reads exactly one byte at the offset provided, returning boost::none on error.
114 virtual boost::optional<u8> ReadByte(size_t offset = 0) const; 114 virtual boost::optional<u8> ReadByte(std::size_t offset = 0) const;
115 // Reads size bytes starting at offset in file into a vector. 115 // Reads size bytes starting at offset in file into a vector.
116 virtual std::vector<u8> ReadBytes(size_t size, size_t offset = 0) const; 116 virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const;
117 // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(), 117 // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(),
118 // 0)' 118 // 0)'
119 virtual std::vector<u8> ReadAllBytes() const; 119 virtual std::vector<u8> ReadAllBytes() const;
@@ -121,7 +121,7 @@ public:
121 // Reads an array of type T, size number_elements starting at offset. 121 // Reads an array of type T, size number_elements starting at offset.
122 // Returns the number of bytes (sizeof(T)*number_elements) read successfully. 122 // Returns the number of bytes (sizeof(T)*number_elements) read successfully.
123 template <typename T> 123 template <typename T>
124 size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const { 124 std::size_t ReadArray(T* data, std::size_t number_elements, std::size_t offset = 0) const {
125 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); 125 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
126 126
127 return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset); 127 return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset);
@@ -130,7 +130,7 @@ public:
130 // Reads size bytes into the memory starting at data starting at offset into the file. 130 // Reads size bytes into the memory starting at data starting at offset into the file.
131 // Returns the number of bytes read successfully. 131 // Returns the number of bytes read successfully.
132 template <typename T> 132 template <typename T>
133 size_t ReadBytes(T* data, size_t size, size_t offset = 0) const { 133 std::size_t ReadBytes(T* data, std::size_t size, std::size_t offset = 0) const {
134 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); 134 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
135 return Read(reinterpret_cast<u8*>(data), size, offset); 135 return Read(reinterpret_cast<u8*>(data), size, offset);
136 } 136 }
@@ -138,22 +138,22 @@ public:
138 // Reads one object of type T starting at offset in file. 138 // Reads one object of type T starting at offset in file.
139 // Returns the number of bytes read successfully (sizeof(T)). 139 // Returns the number of bytes read successfully (sizeof(T)).
140 template <typename T> 140 template <typename T>
141 size_t ReadObject(T* data, size_t offset = 0) const { 141 std::size_t ReadObject(T* data, std::size_t offset = 0) const {
142 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); 142 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
143 return Read(reinterpret_cast<u8*>(data), sizeof(T), offset); 143 return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);
144 } 144 }
145 145
146 // Writes exactly one byte to offset in file and retuns whether or not the byte was written 146 // Writes exactly one byte to offset in file and retuns whether or not the byte was written
147 // successfully. 147 // successfully.
148 virtual bool WriteByte(u8 data, size_t offset = 0); 148 virtual bool WriteByte(u8 data, std::size_t offset = 0);
149 // Writes a vector of bytes to offset in file and returns the number of bytes successfully 149 // Writes a vector of bytes to offset in file and returns the number of bytes successfully
150 // written. 150 // written.
151 virtual size_t WriteBytes(const std::vector<u8>& data, size_t offset = 0); 151 virtual std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset = 0);
152 152
153 // Writes an array of type T, size number_elements to offset in file. 153 // Writes an array of type T, size number_elements to offset in file.
154 // Returns the number of bytes (sizeof(T)*number_elements) written successfully. 154 // Returns the number of bytes (sizeof(T)*number_elements) written successfully.
155 template <typename T> 155 template <typename T>
156 size_t WriteArray(const T* data, size_t number_elements, size_t offset = 0) { 156 std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) {
157 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); 157 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
158 return Write(data, number_elements * sizeof(T), offset); 158 return Write(data, number_elements * sizeof(T), offset);
159 } 159 }
@@ -161,7 +161,7 @@ public:
161 // Writes size bytes starting at memory location data to offset in file. 161 // Writes size bytes starting at memory location data to offset in file.
162 // Returns the number of bytes written successfully. 162 // Returns the number of bytes written successfully.
163 template <typename T> 163 template <typename T>
164 size_t WriteBytes(const T* data, size_t size, size_t offset = 0) { 164 std::size_t WriteBytes(const T* data, std::size_t size, std::size_t offset = 0) {
165 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); 165 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
166 return Write(reinterpret_cast<const u8*>(data), size, offset); 166 return Write(reinterpret_cast<const u8*>(data), size, offset);
167 } 167 }
@@ -169,7 +169,7 @@ public:
169 // Writes one object of type T to offset in file. 169 // Writes one object of type T to offset in file.
170 // Returns the number of bytes written successfully (sizeof(T)). 170 // Returns the number of bytes written successfully (sizeof(T)).
171 template <typename T> 171 template <typename T>
172 size_t WriteObject(const T& data, size_t offset = 0) { 172 std::size_t WriteObject(const T& data, std::size_t offset = 0) {
173 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); 173 static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
174 return Write(&data, sizeof(T), offset); 174 return Write(&data, sizeof(T), offset);
175 } 175 }
@@ -221,7 +221,7 @@ public:
221 // Returns the name of the directory. 221 // Returns the name of the directory.
222 virtual std::string GetName() const = 0; 222 virtual std::string GetName() const = 0;
223 // Returns the total size of all files and subdirectories in this directory. 223 // Returns the total size of all files and subdirectories in this directory.
224 virtual size_t GetSize() const; 224 virtual std::size_t GetSize() const;
225 // Returns the parent directory of this directory. Returns nullptr if this directory is root or 225 // Returns the parent directory of this directory. Returns nullptr if this directory is root or
226 // has no parent. 226 // has no parent.
227 virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0; 227 virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0;
@@ -311,7 +311,7 @@ public:
311}; 311};
312 312
313// Compare the two files, byte-for-byte, in increments specificed by block_size 313// Compare the two files, byte-for-byte, in increments specificed by block_size
314bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x200); 314bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t block_size = 0x200);
315 315
316// A method that copies the raw data between two different implementations of VirtualFile. If you 316// A method that copies the raw data between two different implementations of VirtualFile. If you
317// are using the same implementation, it is probably better to use the Copy method in the parent 317// are using the same implementation, it is probably better to use the Copy method in the parent
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index e6bf586a3..25a980cbb 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -20,7 +20,7 @@ VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) {
20 20
21ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) 21ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name)
22 : name(std::move(name)) { 22 : name(std::move(name)) {
23 size_t next_offset = 0; 23 std::size_t next_offset = 0;
24 for (const auto& file : files_) { 24 for (const auto& file : files_) {
25 files[next_offset] = file; 25 files[next_offset] = file;
26 next_offset += file->GetSize(); 26 next_offset += file->GetSize();
@@ -35,13 +35,13 @@ std::string ConcatenatedVfsFile::GetName() const {
35 return files.begin()->second->GetName(); 35 return files.begin()->second->GetName();
36} 36}
37 37
38size_t ConcatenatedVfsFile::GetSize() const { 38std::size_t ConcatenatedVfsFile::GetSize() const {
39 if (files.empty()) 39 if (files.empty())
40 return 0; 40 return 0;
41 return files.rbegin()->first + files.rbegin()->second->GetSize(); 41 return files.rbegin()->first + files.rbegin()->second->GetSize();
42} 42}
43 43
44bool ConcatenatedVfsFile::Resize(size_t new_size) { 44bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
45 return false; 45 return false;
46} 46}
47 47
@@ -59,7 +59,7 @@ bool ConcatenatedVfsFile::IsReadable() const {
59 return true; 59 return true;
60} 60}
61 61
62size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const { 62std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
63 auto entry = files.end(); 63 auto entry = files.end();
64 for (auto iter = files.begin(); iter != files.end(); ++iter) { 64 for (auto iter = files.begin(); iter != files.end(); ++iter) {
65 if (iter->first > offset) { 65 if (iter->first > offset) {
@@ -84,7 +84,7 @@ size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const {
84 return entry->second->Read(data, length, offset - entry->first); 84 return entry->second->Read(data, length, offset - entry->first);
85} 85}
86 86
87size_t ConcatenatedVfsFile::Write(const u8* data, size_t length, size_t offset) { 87std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
88 return 0; 88 return 0;
89} 89}
90 90
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 686d32515..31775db7e 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -23,13 +23,13 @@ class ConcatenatedVfsFile : public VfsFile {
23 23
24public: 24public:
25 std::string GetName() const override; 25 std::string GetName() const override;
26 size_t GetSize() const override; 26 std::size_t GetSize() const override;
27 bool Resize(size_t new_size) override; 27 bool Resize(std::size_t new_size) override;
28 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 28 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
29 bool IsWritable() const override; 29 bool IsWritable() const override;
30 bool IsReadable() const override; 30 bool IsReadable() const override;
31 size_t Read(u8* data, size_t length, size_t offset) const override; 31 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
32 size_t Write(const u8* data, size_t length, size_t offset) override; 32 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
33 bool Rename(std::string_view name) override; 33 bool Rename(std::string_view name) override;
34 34
35private: 35private:
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index 847cde2f5..f5ed291ea 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -9,7 +9,7 @@
9 9
10namespace FileSys { 10namespace FileSys {
11 11
12OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_, 12OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_, std::size_t offset_,
13 std::string name_, VirtualDir parent_) 13 std::string name_, VirtualDir parent_)
14 : file(file_), offset(offset_), size(size_), name(std::move(name_)), 14 : file(file_), offset(offset_), size(size_), name(std::move(name_)),
15 parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {} 15 parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
@@ -18,11 +18,11 @@ std::string OffsetVfsFile::GetName() const {
18 return name.empty() ? file->GetName() : name; 18 return name.empty() ? file->GetName() : name;
19} 19}
20 20
21size_t OffsetVfsFile::GetSize() const { 21std::size_t OffsetVfsFile::GetSize() const {
22 return size; 22 return size;
23} 23}
24 24
25bool OffsetVfsFile::Resize(size_t new_size) { 25bool OffsetVfsFile::Resize(std::size_t new_size) {
26 if (offset + new_size < file->GetSize()) { 26 if (offset + new_size < file->GetSize()) {
27 size = new_size; 27 size = new_size;
28 } else { 28 } else {
@@ -47,22 +47,22 @@ bool OffsetVfsFile::IsReadable() const {
47 return file->IsReadable(); 47 return file->IsReadable();
48} 48}
49 49
50size_t OffsetVfsFile::Read(u8* data, size_t length, size_t r_offset) const { 50std::size_t OffsetVfsFile::Read(u8* data, std::size_t length, std::size_t r_offset) const {
51 return file->Read(data, TrimToFit(length, r_offset), offset + r_offset); 51 return file->Read(data, TrimToFit(length, r_offset), offset + r_offset);
52} 52}
53 53
54size_t OffsetVfsFile::Write(const u8* data, size_t length, size_t r_offset) { 54std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t r_offset) {
55 return file->Write(data, TrimToFit(length, r_offset), offset + r_offset); 55 return file->Write(data, TrimToFit(length, r_offset), offset + r_offset);
56} 56}
57 57
58boost::optional<u8> OffsetVfsFile::ReadByte(size_t r_offset) const { 58boost::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
59 if (r_offset < size) 59 if (r_offset < size)
60 return file->ReadByte(offset + r_offset); 60 return file->ReadByte(offset + r_offset);
61 61
62 return boost::none; 62 return boost::none;
63} 63}
64 64
65std::vector<u8> OffsetVfsFile::ReadBytes(size_t r_size, size_t r_offset) const { 65std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const {
66 return file->ReadBytes(TrimToFit(r_size, r_offset), offset + r_offset); 66 return file->ReadBytes(TrimToFit(r_size, r_offset), offset + r_offset);
67} 67}
68 68
@@ -70,14 +70,14 @@ std::vector<u8> OffsetVfsFile::ReadAllBytes() const {
70 return file->ReadBytes(size, offset); 70 return file->ReadBytes(size, offset);
71} 71}
72 72
73bool OffsetVfsFile::WriteByte(u8 data, size_t r_offset) { 73bool OffsetVfsFile::WriteByte(u8 data, std::size_t r_offset) {
74 if (r_offset < size) 74 if (r_offset < size)
75 return file->WriteByte(data, offset + r_offset); 75 return file->WriteByte(data, offset + r_offset);
76 76
77 return false; 77 return false;
78} 78}
79 79
80size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, size_t r_offset) { 80std::size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, std::size_t r_offset) {
81 return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset); 81 return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
82} 82}
83 83
@@ -85,12 +85,12 @@ bool OffsetVfsFile::Rename(std::string_view name) {
85 return file->Rename(name); 85 return file->Rename(name);
86} 86}
87 87
88size_t OffsetVfsFile::GetOffset() const { 88std::size_t OffsetVfsFile::GetOffset() const {
89 return offset; 89 return offset;
90} 90}
91 91
92size_t OffsetVfsFile::TrimToFit(size_t r_size, size_t r_offset) const { 92std::size_t OffsetVfsFile::TrimToFit(std::size_t r_size, std::size_t r_offset) const {
93 return std::clamp(r_size, size_t{0}, size - r_offset); 93 return std::clamp(r_size, std::size_t{0}, size - r_offset);
94} 94}
95 95
96} // namespace FileSys 96} // namespace FileSys
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index cb92d1570..34cb180b3 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -17,33 +17,33 @@ namespace FileSys {
17// the size of this wrapper. 17// the size of this wrapper.
18class OffsetVfsFile : public VfsFile { 18class OffsetVfsFile : public VfsFile {
19public: 19public:
20 OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0, 20 OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::size_t offset = 0,
21 std::string new_name = "", VirtualDir new_parent = nullptr); 21 std::string new_name = "", VirtualDir new_parent = nullptr);
22 22
23 std::string GetName() const override; 23 std::string GetName() const override;
24 size_t GetSize() const override; 24 std::size_t GetSize() const override;
25 bool Resize(size_t new_size) override; 25 bool Resize(std::size_t new_size) override;
26 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 26 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
27 bool IsWritable() const override; 27 bool IsWritable() const override;
28 bool IsReadable() const override; 28 bool IsReadable() const override;
29 size_t Read(u8* data, size_t length, size_t offset) const override; 29 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
30 size_t Write(const u8* data, size_t length, size_t offset) override; 30 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
31 boost::optional<u8> ReadByte(size_t offset) const override; 31 boost::optional<u8> ReadByte(std::size_t offset) const override;
32 std::vector<u8> ReadBytes(size_t size, size_t offset) const override; 32 std::vector<u8> ReadBytes(std::size_t size, std::size_t offset) const override;
33 std::vector<u8> ReadAllBytes() const override; 33 std::vector<u8> ReadAllBytes() const override;
34 bool WriteByte(u8 data, size_t offset) override; 34 bool WriteByte(u8 data, std::size_t offset) override;
35 size_t WriteBytes(const std::vector<u8>& data, size_t offset) override; 35 std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset) override;
36 36
37 bool Rename(std::string_view name) override; 37 bool Rename(std::string_view name) override;
38 38
39 size_t GetOffset() const; 39 std::size_t GetOffset() const;
40 40
41private: 41private:
42 size_t TrimToFit(size_t r_size, size_t r_offset) const; 42 std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const;
43 43
44 std::shared_ptr<VfsFile> file; 44 std::shared_ptr<VfsFile> file;
45 size_t offset; 45 std::size_t offset;
46 size_t size; 46 std::size_t size;
47 std::string name; 47 std::string name;
48 VirtualDir parent; 48 VirtualDir parent;
49}; 49};
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 89b101145..5e242e20f 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -227,11 +227,11 @@ std::string RealVfsFile::GetName() const {
227 return path_components.back(); 227 return path_components.back();
228} 228}
229 229
230size_t RealVfsFile::GetSize() const { 230std::size_t RealVfsFile::GetSize() const {
231 return backing->GetSize(); 231 return backing->GetSize();
232} 232}
233 233
234bool RealVfsFile::Resize(size_t new_size) { 234bool RealVfsFile::Resize(std::size_t new_size) {
235 return backing->Resize(new_size); 235 return backing->Resize(new_size);
236} 236}
237 237
@@ -247,13 +247,13 @@ bool RealVfsFile::IsReadable() const {
247 return (perms & Mode::ReadWrite) != 0; 247 return (perms & Mode::ReadWrite) != 0;
248} 248}
249 249
250size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { 250std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
251 if (!backing->Seek(offset, SEEK_SET)) 251 if (!backing->Seek(offset, SEEK_SET))
252 return 0; 252 return 0;
253 return backing->ReadBytes(data, length); 253 return backing->ReadBytes(data, length);
254} 254}
255 255
256size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { 256std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
257 if (!backing->Seek(offset, SEEK_SET)) 257 if (!backing->Seek(offset, SEEK_SET))
258 return 0; 258 return 0;
259 return backing->WriteBytes(data, length); 259 return backing->WriteBytes(data, length);
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 7db86691f..681c43e82 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -48,13 +48,13 @@ public:
48 ~RealVfsFile() override; 48 ~RealVfsFile() override;
49 49
50 std::string GetName() const override; 50 std::string GetName() const override;
51 size_t GetSize() const override; 51 std::size_t GetSize() const override;
52 bool Resize(size_t new_size) override; 52 bool Resize(std::size_t new_size) override;
53 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 53 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
54 bool IsWritable() const override; 54 bool IsWritable() const override;
55 bool IsReadable() const override; 55 bool IsReadable() const override;
56 size_t Read(u8* data, size_t length, size_t offset) const override; 56 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
57 size_t Write(const u8* data, size_t length, size_t offset) override; 57 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
58 bool Rename(std::string_view name) override; 58 bool Rename(std::string_view name) override;
59 59
60private: 60private:
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index 4dbc25c55..0173f71c1 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -25,8 +25,8 @@ namespace FileSys {
25constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000; 25constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000;
26 26
27template <typename SourceData, typename SourceKey, typename Destination> 27template <typename SourceData, typename SourceKey, typename Destination>
28static bool CalculateHMAC256(Destination* out, const SourceKey* key, size_t key_length, 28static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t key_length,
29 const SourceData* data, size_t data_length) { 29 const SourceData* data, std::size_t data_length) {
30 mbedtls_md_context_t context; 30 mbedtls_md_context_t context;
31 mbedtls_md_init(&context); 31 mbedtls_md_init(&context);
32 32
@@ -91,7 +91,7 @@ Loader::ResultStatus NAX::Parse(std::string_view path) {
91 91
92 const auto enc_keys = header->key_area; 92 const auto enc_keys = header->key_area;
93 93
94 size_t i = 0; 94 std::size_t i = 0;
95 for (; i < sd_keys.size(); ++i) { 95 for (; i < sd_keys.size(); ++i) {
96 std::array<Core::Crypto::Key128, 2> nax_keys{}; 96 std::array<Core::Crypto::Key128, 2> nax_keys{};
97 if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, std::string(path).c_str(), 97 if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, std::string(path).c_str(),
@@ -99,7 +99,7 @@ Loader::ResultStatus NAX::Parse(std::string_view path) {
99 return Loader::ResultStatus::ErrorNAXKeyHMACFailed; 99 return Loader::ResultStatus::ErrorNAXKeyHMACFailed;
100 } 100 }
101 101
102 for (size_t j = 0; j < nax_keys.size(); ++j) { 102 for (std::size_t j = 0; j < nax_keys.size(); ++j) {
103 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(nax_keys[j], 103 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(nax_keys[j],
104 Core::Crypto::Mode::ECB); 104 Core::Crypto::Mode::ECB);
105 cipher.Transcode(enc_keys[j].data(), 0x10, header->key_area[j].data(), 105 cipher.Transcode(enc_keys[j].data(), 0x10, header->key_area[j].data(),
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 332e5c3d0..cfaf20a88 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -292,7 +292,7 @@ static u8 NibbleToHex(u8 n) {
292 * @param src Pointer to array of output hex string characters. 292 * @param src Pointer to array of output hex string characters.
293 * @param len Length of src array. 293 * @param len Length of src array.
294 */ 294 */
295static u32 HexToInt(const u8* src, size_t len) { 295static u32 HexToInt(const u8* src, std::size_t len) {
296 u32 output = 0; 296 u32 output = 0;
297 while (len-- > 0) { 297 while (len-- > 0) {
298 output = (output << 4) | HexCharToValue(src[0]); 298 output = (output << 4) | HexCharToValue(src[0]);
@@ -307,7 +307,7 @@ static u32 HexToInt(const u8* src, size_t len) {
307 * @param src Pointer to array of output hex string characters. 307 * @param src Pointer to array of output hex string characters.
308 * @param len Length of src array. 308 * @param len Length of src array.
309 */ 309 */
310static u64 HexToLong(const u8* src, size_t len) { 310static u64 HexToLong(const u8* src, std::size_t len) {
311 u64 output = 0; 311 u64 output = 0;
312 while (len-- > 0) { 312 while (len-- > 0) {
313 output = (output << 4) | HexCharToValue(src[0]); 313 output = (output << 4) | HexCharToValue(src[0]);
@@ -323,7 +323,7 @@ static u64 HexToLong(const u8* src, size_t len) {
323 * @param src Pointer to array of u8 bytes. 323 * @param src Pointer to array of u8 bytes.
324 * @param len Length of src array. 324 * @param len Length of src array.
325 */ 325 */
326static void MemToGdbHex(u8* dest, const u8* src, size_t len) { 326static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
327 while (len-- > 0) { 327 while (len-- > 0) {
328 u8 tmp = *src++; 328 u8 tmp = *src++;
329 *dest++ = NibbleToHex(tmp >> 4); 329 *dest++ = NibbleToHex(tmp >> 4);
@@ -338,7 +338,7 @@ static void MemToGdbHex(u8* dest, const u8* src, size_t len) {
338 * @param src Pointer to array of output hex string characters. 338 * @param src Pointer to array of output hex string characters.
339 * @param len Length of src array. 339 * @param len Length of src array.
340 */ 340 */
341static void GdbHexToMem(u8* dest, const u8* src, size_t len) { 341static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) {
342 while (len-- > 0) { 342 while (len-- > 0) {
343 *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]); 343 *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]);
344 src += 2; 344 src += 2;
@@ -406,7 +406,7 @@ static u64 GdbHexToLong(const u8* src) {
406/// Read a byte from the gdb client. 406/// Read a byte from the gdb client.
407static u8 ReadByte() { 407static u8 ReadByte() {
408 u8 c; 408 u8 c;
409 size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); 409 std::size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL);
410 if (received_size != 1) { 410 if (received_size != 1) {
411 LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); 411 LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size);
412 Shutdown(); 412 Shutdown();
@@ -416,7 +416,7 @@ static u8 ReadByte() {
416} 416}
417 417
418/// Calculate the checksum of the current command buffer. 418/// Calculate the checksum of the current command buffer.
419static u8 CalculateChecksum(const u8* buffer, size_t length) { 419static u8 CalculateChecksum(const u8* buffer, std::size_t length) {
420 return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>())); 420 return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>()));
421} 421}
422 422
@@ -518,7 +518,7 @@ bool CheckBreakpoint(VAddr addr, BreakpointType type) {
518 * @param packet Packet to be sent to client. 518 * @param packet Packet to be sent to client.
519 */ 519 */
520static void SendPacket(const char packet) { 520static void SendPacket(const char packet) {
521 size_t sent_size = send(gdbserver_socket, &packet, 1, 0); 521 std::size_t sent_size = send(gdbserver_socket, &packet, 1, 0);
522 if (sent_size != 1) { 522 if (sent_size != 1) {
523 LOG_ERROR(Debug_GDBStub, "send failed"); 523 LOG_ERROR(Debug_GDBStub, "send failed");
524 } 524 }
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index eaa5395ac..419f45896 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -12,7 +12,7 @@
12namespace IPC { 12namespace IPC {
13 13
14/// Size of the command buffer area, in 32-bit words. 14/// Size of the command buffer area, in 32-bit words.
15constexpr size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32); 15constexpr std::size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32);
16 16
17// These errors are commonly returned by invalid IPC translations, so alias them here for 17// These errors are commonly returned by invalid IPC translations, so alias them here for
18// convenience. 18// convenience.
@@ -153,7 +153,7 @@ struct DataPayloadHeader {
153 u32_le magic; 153 u32_le magic;
154 INSERT_PADDING_WORDS(1); 154 INSERT_PADDING_WORDS(1);
155}; 155};
156static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadRequest size is incorrect"); 156static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadHeader size is incorrect");
157 157
158struct DomainMessageHeader { 158struct DomainMessageHeader {
159 enum class CommandType : u32_le { 159 enum class CommandType : u32_le {
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 0f3ffdb60..7545ecf2a 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -152,8 +152,8 @@ public:
152 } 152 }
153 153
154 void ValidateHeader() { 154 void ValidateHeader() {
155 const size_t num_domain_objects = context->NumDomainObjects(); 155 const std::size_t num_domain_objects = context->NumDomainObjects();
156 const size_t num_move_objects = context->NumMoveObjects(); 156 const std::size_t num_move_objects = context->NumMoveObjects();
157 ASSERT_MSG(!num_domain_objects || !num_move_objects, 157 ASSERT_MSG(!num_domain_objects || !num_move_objects,
158 "cannot move normal handles and domain objects"); 158 "cannot move normal handles and domain objects");
159 ASSERT_MSG((index - datapayload_index) == normal_params_size, 159 ASSERT_MSG((index - datapayload_index) == normal_params_size,
@@ -329,10 +329,10 @@ public:
329 T PopRaw(); 329 T PopRaw();
330 330
331 template <typename T> 331 template <typename T>
332 Kernel::SharedPtr<T> GetMoveObject(size_t index); 332 Kernel::SharedPtr<T> GetMoveObject(std::size_t index);
333 333
334 template <typename T> 334 template <typename T>
335 Kernel::SharedPtr<T> GetCopyObject(size_t index); 335 Kernel::SharedPtr<T> GetCopyObject(std::size_t index);
336 336
337 template <class T> 337 template <class T>
338 std::shared_ptr<T> PopIpcInterface() { 338 std::shared_ptr<T> PopIpcInterface() {
@@ -406,12 +406,12 @@ void RequestParser::Pop(First& first_value, Other&... other_values) {
406} 406}
407 407
408template <typename T> 408template <typename T>
409Kernel::SharedPtr<T> RequestParser::GetMoveObject(size_t index) { 409Kernel::SharedPtr<T> RequestParser::GetMoveObject(std::size_t index) {
410 return context->GetMoveObject<T>(index); 410 return context->GetMoveObject<T>(index);
411} 411}
412 412
413template <typename T> 413template <typename T>
414Kernel::SharedPtr<T> RequestParser::GetCopyObject(size_t index) { 414Kernel::SharedPtr<T> RequestParser::GetCopyObject(std::size_t index) {
415 return context->GetCopyObject<T>(index); 415 return context->GetCopyObject<T>(index);
416} 416}
417 417
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 6657accd5..93577591f 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -35,16 +35,17 @@ static ResultCode WaitForAddress(VAddr address, s64 timeout) {
35 35
36// Gets the threads waiting on an address. 36// Gets the threads waiting on an address.
37static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) { 37static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) {
38 const auto RetrieveWaitingThreads = 38 const auto RetrieveWaitingThreads = [](std::size_t core_index,
39 [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) { 39 std::vector<SharedPtr<Thread>>& waiting_threads,
40 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); 40 VAddr arb_addr) {
41 auto& thread_list = scheduler->GetThreadList(); 41 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
42 42 auto& thread_list = scheduler->GetThreadList();
43 for (auto& thread : thread_list) { 43
44 if (thread->arb_wait_address == arb_addr) 44 for (auto& thread : thread_list) {
45 waiting_threads.push_back(thread); 45 if (thread->arb_wait_address == arb_addr)
46 } 46 waiting_threads.push_back(thread);
47 }; 47 }
48 };
48 49
49 // Retrieve all threads that are waiting for this address. 50 // Retrieve all threads that are waiting for this address.
50 std::vector<SharedPtr<Thread>> threads; 51 std::vector<SharedPtr<Thread>> threads;
@@ -66,12 +67,12 @@ static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address)
66static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { 67static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {
67 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process 68 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
68 // them all. 69 // them all.
69 size_t last = waiting_threads.size(); 70 std::size_t last = waiting_threads.size();
70 if (num_to_wake > 0) 71 if (num_to_wake > 0)
71 last = num_to_wake; 72 last = num_to_wake;
72 73
73 // Signal the waiting threads. 74 // Signal the waiting threads.
74 for (size_t i = 0; i < last; i++) { 75 for (std::size_t i = 0; i < last; i++) {
75 ASSERT(waiting_threads[i]->status == ThreadStatus::WaitArb); 76 ASSERT(waiting_threads[i]->status == ThreadStatus::WaitArb);
76 waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); 77 waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
77 waiting_threads[i]->arb_wait_address = 0; 78 waiting_threads[i]->arb_wait_address = 0;
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 4054d5db6..8c2be2681 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -17,10 +17,12 @@ enum {
17 17
18 // Confirmed Switch OS error codes 18 // Confirmed Switch OS error codes
19 MaxConnectionsReached = 7, 19 MaxConnectionsReached = 7,
20 InvalidSize = 101,
20 InvalidAddress = 102, 21 InvalidAddress = 102,
21 HandleTableFull = 105, 22 HandleTableFull = 105,
22 InvalidMemoryState = 106, 23 InvalidMemoryState = 106,
23 InvalidMemoryPermissions = 108, 24 InvalidMemoryPermissions = 108,
25 InvalidThreadPriority = 112,
24 InvalidProcessorId = 113, 26 InvalidProcessorId = 113,
25 InvalidHandle = 114, 27 InvalidHandle = 114,
26 InvalidCombination = 116, 28 InvalidCombination = 116,
@@ -28,6 +30,7 @@ enum {
28 SynchronizationCanceled = 118, 30 SynchronizationCanceled = 118,
29 TooLarge = 119, 31 TooLarge = 119,
30 InvalidEnumValue = 120, 32 InvalidEnumValue = 120,
33 NoSuchEntry = 121,
31 InvalidState = 125, 34 InvalidState = 125,
32 ResourceLimitExceeded = 132, 35 ResourceLimitExceeded = 132,
33}; 36};
@@ -36,7 +39,7 @@ enum {
36// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always 39// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always
37// double check that the code matches before re-using the constant. 40// double check that the code matches before re-using the constant.
38 41
39// TODO(bunnei): Replace these with correct errors for Switch OS 42// TODO(bunnei): Replace -1 with correct errors for Switch OS
40constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); 43constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull);
41constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); 44constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1);
42constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); 45constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge);
@@ -53,15 +56,17 @@ constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::In
53constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, 56constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
54 ErrCodes::InvalidMemoryPermissions); 57 ErrCodes::InvalidMemoryPermissions);
55constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 58constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
59constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
60constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
56constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); 61constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
62constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
63 ErrCodes::InvalidThreadPriority);
57constexpr ResultCode ERR_INVALID_POINTER(-1); 64constexpr ResultCode ERR_INVALID_POINTER(-1);
58constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); 65constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
59constexpr ResultCode ERR_NOT_AUTHORIZED(-1); 66constexpr ResultCode ERR_NOT_AUTHORIZED(-1);
60/// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths. 67/// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths.
61constexpr ResultCode ERR_INVALID_HANDLE_OS(-1); 68constexpr ResultCode ERR_INVALID_HANDLE_OS(-1);
62constexpr ResultCode ERR_NOT_FOUND(-1); 69constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry);
63constexpr ResultCode ERR_OUT_OF_RANGE(-1);
64constexpr ResultCode ERR_OUT_OF_RANGE_KERNEL(-1);
65constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout); 70constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout);
66/// Returned when Accept() is called on a port with no sessions to be accepted. 71/// Returned when Accept() is called on a port with no sessions to be accepted.
67constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1); 72constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1);
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 3a079b9a9..5ee5c05e3 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -65,7 +65,7 @@ ResultCode HandleTable::Close(Handle handle) {
65} 65}
66 66
67bool HandleTable::IsValid(Handle handle) const { 67bool HandleTable::IsValid(Handle handle) const {
68 size_t slot = GetSlot(handle); 68 std::size_t slot = GetSlot(handle);
69 u16 generation = GetGeneration(handle); 69 u16 generation = GetGeneration(handle);
70 70
71 return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; 71 return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index cac928adb..9e2f33e8a 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -93,7 +93,7 @@ private:
93 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further 93 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
94 * reduced by ExHeader values, but this is not emulated here. 94 * reduced by ExHeader values, but this is not emulated here.
95 */ 95 */
96 static const size_t MAX_COUNT = 4096; 96 static const std::size_t MAX_COUNT = 4096;
97 97
98 static u16 GetSlot(Handle handle) { 98 static u16 GetSlot(Handle handle) {
99 return handle >> 15; 99 return handle >> 15;
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 7264be906..72fb9d250 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -42,9 +42,9 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
42 Kernel::SharedPtr<Kernel::Event> event) { 42 Kernel::SharedPtr<Kernel::Event> event) {
43 43
44 // Put the client thread to sleep until the wait event is signaled or the timeout expires. 44 // Put the client thread to sleep until the wait event is signaled or the timeout expires.
45 thread->wakeup_callback = 45 thread->wakeup_callback = [context = *this, callback](
46 [context = *this, callback](ThreadWakeupReason reason, SharedPtr<Thread> thread, 46 ThreadWakeupReason reason, SharedPtr<Thread> thread,
47 SharedPtr<WaitObject> object, size_t index) mutable -> bool { 47 SharedPtr<WaitObject> object, std::size_t index) mutable -> bool {
48 ASSERT(thread->status == ThreadStatus::WaitHLEEvent); 48 ASSERT(thread->status == ThreadStatus::WaitHLEEvent);
49 callback(thread, context, reason); 49 callback(thread, context, reason);
50 context.WriteToOutgoingCommandBuffer(*thread); 50 context.WriteToOutgoingCommandBuffer(*thread);
@@ -199,8 +199,8 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb
199 } 199 }
200 200
201 // The data_size already includes the payload header, the padding and the domain header. 201 // The data_size already includes the payload header, the padding and the domain header.
202 size_t size = data_payload_offset + command_header->data_size - 202 std::size_t size = data_payload_offset + command_header->data_size -
203 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; 203 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
204 if (domain_message_header) 204 if (domain_message_header)
205 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); 205 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
206 std::copy_n(src_cmdbuf, size, cmd_buf.begin()); 206 std::copy_n(src_cmdbuf, size, cmd_buf.begin());
@@ -217,8 +217,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
217 ParseCommandBuffer(cmd_buf.data(), false); 217 ParseCommandBuffer(cmd_buf.data(), false);
218 218
219 // The data_size already includes the payload header, the padding and the domain header. 219 // The data_size already includes the payload header, the padding and the domain header.
220 size_t size = data_payload_offset + command_header->data_size - 220 std::size_t size = data_payload_offset + command_header->data_size -
221 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; 221 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
222 if (domain_message_header) 222 if (domain_message_header)
223 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); 223 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
224 224
@@ -229,7 +229,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
229 "Handle descriptor bit set but no handles to translate"); 229 "Handle descriptor bit set but no handles to translate");
230 // We write the translated handles at a specific offset in the command buffer, this space 230 // We write the translated handles at a specific offset in the command buffer, this space
231 // was already reserved when writing the header. 231 // was already reserved when writing the header.
232 size_t current_offset = 232 std::size_t current_offset =
233 (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32); 233 (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32);
234 ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented"); 234 ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented");
235 235
@@ -258,7 +258,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
258 ASSERT(domain_message_header->num_objects == domain_objects.size()); 258 ASSERT(domain_message_header->num_objects == domain_objects.size());
259 // Write the domain objects to the command buffer, these go after the raw untranslated data. 259 // Write the domain objects to the command buffer, these go after the raw untranslated data.
260 // TODO(Subv): This completely ignores C buffers. 260 // TODO(Subv): This completely ignores C buffers.
261 size_t domain_offset = size - domain_message_header->num_objects; 261 std::size_t domain_offset = size - domain_message_header->num_objects;
262 auto& request_handlers = server_session->domain_request_handlers; 262 auto& request_handlers = server_session->domain_request_handlers;
263 263
264 for (auto& object : domain_objects) { 264 for (auto& object : domain_objects) {
@@ -291,14 +291,15 @@ std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const {
291 return buffer; 291 return buffer;
292} 292}
293 293
294size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const { 294std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
295 int buffer_index) const {
295 if (size == 0) { 296 if (size == 0) {
296 LOG_WARNING(Core, "skip empty buffer write"); 297 LOG_WARNING(Core, "skip empty buffer write");
297 return 0; 298 return 0;
298 } 299 }
299 300
300 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; 301 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
301 const size_t buffer_size{GetWriteBufferSize(buffer_index)}; 302 const std::size_t buffer_size{GetWriteBufferSize(buffer_index)};
302 if (size > buffer_size) { 303 if (size > buffer_size) {
303 LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, 304 LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
304 buffer_size); 305 buffer_size);
@@ -314,13 +315,13 @@ size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffe
314 return size; 315 return size;
315} 316}
316 317
317size_t HLERequestContext::GetReadBufferSize(int buffer_index) const { 318std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const {
318 const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; 319 const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()};
319 return is_buffer_a ? BufferDescriptorA()[buffer_index].Size() 320 return is_buffer_a ? BufferDescriptorA()[buffer_index].Size()
320 : BufferDescriptorX()[buffer_index].Size(); 321 : BufferDescriptorX()[buffer_index].Size();
321} 322}
322 323
323size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const { 324std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const {
324 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; 325 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()};
325 return is_buffer_b ? BufferDescriptorB()[buffer_index].Size() 326 return is_buffer_b ? BufferDescriptorB()[buffer_index].Size()
326 : BufferDescriptorC()[buffer_index].Size(); 327 : BufferDescriptorC()[buffer_index].Size();
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index f0d07f1b6..894479ee0 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -170,7 +170,7 @@ public:
170 std::vector<u8> ReadBuffer(int buffer_index = 0) const; 170 std::vector<u8> ReadBuffer(int buffer_index = 0) const;
171 171
172 /// Helper function to write a buffer using the appropriate buffer descriptor 172 /// Helper function to write a buffer using the appropriate buffer descriptor
173 size_t WriteBuffer(const void* buffer, size_t size, int buffer_index = 0) const; 173 std::size_t WriteBuffer(const void* buffer, std::size_t size, int buffer_index = 0) const;
174 174
175 /* Helper function to write a buffer using the appropriate buffer descriptor 175 /* Helper function to write a buffer using the appropriate buffer descriptor
176 * 176 *
@@ -182,7 +182,7 @@ public:
182 */ 182 */
183 template <typename ContiguousContainer, 183 template <typename ContiguousContainer,
184 typename = std::enable_if_t<!std::is_pointer_v<ContiguousContainer>>> 184 typename = std::enable_if_t<!std::is_pointer_v<ContiguousContainer>>>
185 size_t WriteBuffer(const ContiguousContainer& container, int buffer_index = 0) const { 185 std::size_t WriteBuffer(const ContiguousContainer& container, int buffer_index = 0) const {
186 using ContiguousType = typename ContiguousContainer::value_type; 186 using ContiguousType = typename ContiguousContainer::value_type;
187 187
188 static_assert(std::is_trivially_copyable_v<ContiguousType>, 188 static_assert(std::is_trivially_copyable_v<ContiguousType>,
@@ -193,19 +193,19 @@ public:
193 } 193 }
194 194
195 /// Helper function to get the size of the input buffer 195 /// Helper function to get the size of the input buffer
196 size_t GetReadBufferSize(int buffer_index = 0) const; 196 std::size_t GetReadBufferSize(int buffer_index = 0) const;
197 197
198 /// Helper function to get the size of the output buffer 198 /// Helper function to get the size of the output buffer
199 size_t GetWriteBufferSize(int buffer_index = 0) const; 199 std::size_t GetWriteBufferSize(int buffer_index = 0) const;
200 200
201 template <typename T> 201 template <typename T>
202 SharedPtr<T> GetCopyObject(size_t index) { 202 SharedPtr<T> GetCopyObject(std::size_t index) {
203 ASSERT(index < copy_objects.size()); 203 ASSERT(index < copy_objects.size());
204 return DynamicObjectCast<T>(copy_objects[index]); 204 return DynamicObjectCast<T>(copy_objects[index]);
205 } 205 }
206 206
207 template <typename T> 207 template <typename T>
208 SharedPtr<T> GetMoveObject(size_t index) { 208 SharedPtr<T> GetMoveObject(std::size_t index) {
209 ASSERT(index < move_objects.size()); 209 ASSERT(index < move_objects.size());
210 return DynamicObjectCast<T>(move_objects[index]); 210 return DynamicObjectCast<T>(move_objects[index]);
211 } 211 }
@@ -223,7 +223,7 @@ public:
223 } 223 }
224 224
225 template <typename T> 225 template <typename T>
226 std::shared_ptr<T> GetDomainRequestHandler(size_t index) const { 226 std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const {
227 return std::static_pointer_cast<T>(domain_request_handlers[index]); 227 return std::static_pointer_cast<T>(domain_request_handlers[index]);
228 } 228 }
229 229
@@ -240,15 +240,15 @@ public:
240 domain_objects.clear(); 240 domain_objects.clear();
241 } 241 }
242 242
243 size_t NumMoveObjects() const { 243 std::size_t NumMoveObjects() const {
244 return move_objects.size(); 244 return move_objects.size();
245 } 245 }
246 246
247 size_t NumCopyObjects() const { 247 std::size_t NumCopyObjects() const {
248 return copy_objects.size(); 248 return copy_objects.size();
249 } 249 }
250 250
251 size_t NumDomainObjects() const { 251 std::size_t NumDomainObjects() const {
252 return domain_objects.size(); 252 return domain_objects.size();
253 } 253 }
254 254
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index b025e323f..7a272d031 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -40,8 +40,8 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
40 return process; 40 return process;
41} 41}
42 42
43void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { 43void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
44 for (size_t i = 0; i < len; ++i) { 44 for (std::size_t i = 0; i < len; ++i) {
45 u32 descriptor = kernel_caps[i]; 45 u32 descriptor = kernel_caps[i];
46 u32 type = descriptor >> 20; 46 u32 type = descriptor >> 20;
47 47
@@ -211,7 +211,7 @@ ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
211 "Shared memory exceeds bounds of mapped block"); 211 "Shared memory exceeds bounds of mapped block");
212 212
213 const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; 213 const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
214 size_t backing_block_offset = vma->second.offset + vma_offset; 214 std::size_t backing_block_offset = vma->second.offset + vma_offset;
215 215
216 CASCADE_RESULT(auto new_vma, 216 CASCADE_RESULT(auto new_vma,
217 vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, 217 vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 1587d40c1..81538f70c 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -59,7 +59,7 @@ class ResourceLimit;
59 59
60struct CodeSet final : public Object { 60struct CodeSet final : public Object {
61 struct Segment { 61 struct Segment {
62 size_t offset = 0; 62 std::size_t offset = 0;
63 VAddr addr = 0; 63 VAddr addr = 0;
64 u32 size = 0; 64 u32 size = 0;
65 }; 65 };
@@ -164,7 +164,7 @@ public:
164 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them 164 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
165 * to this process. 165 * to this process.
166 */ 166 */
167 void ParseKernelCaps(const u32* kernel_caps, size_t len); 167 void ParseKernelCaps(const u32* kernel_caps, std::size_t len);
168 168
169 /** 169 /**
170 * Applies address space changes and launches the process main thread. 170 * Applies address space changes and launches the process main thread.
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 2c729afe3..2c06bb7ce 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -119,7 +119,7 @@ public:
119 /// Backing memory for this shared memory block. 119 /// Backing memory for this shared memory block.
120 std::shared_ptr<std::vector<u8>> backing_block; 120 std::shared_ptr<std::vector<u8>> backing_block;
121 /// Offset into the backing block for this shared memory. 121 /// Offset into the backing block for this shared memory.
122 size_t backing_block_offset; 122 std::size_t backing_block_offset;
123 /// Size of the memory block. Page-aligned. 123 /// Size of the memory block. Page-aligned.
124 u64 size; 124 u64 size;
125 /// Permission restrictions applied to the process which created the block. 125 /// Permission restrictions applied to the process which created the block.
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1c9373ed8..c5c1697ee 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -35,10 +35,21 @@
35#include "core/hle/service/service.h" 35#include "core/hle/service/service.h"
36 36
37namespace Kernel { 37namespace Kernel {
38namespace {
39constexpr bool Is4KBAligned(VAddr address) {
40 return (address & 0xFFF) == 0;
41}
42} // Anonymous namespace
38 43
39/// Set the process heap to a given Size. It can both extend and shrink the heap. 44/// Set the process heap to a given Size. It can both extend and shrink the heap.
40static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { 45static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
41 LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); 46 LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
47
48 // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB.
49 if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) {
50 return ERR_INVALID_SIZE;
51 }
52
42 auto& process = *Core::CurrentProcess(); 53 auto& process = *Core::CurrentProcess();
43 CASCADE_RESULT(*heap_addr, 54 CASCADE_RESULT(*heap_addr,
44 process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); 55 process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
@@ -56,6 +67,15 @@ static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state
56static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 67static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
57 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, 68 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
58 src_addr, size); 69 src_addr, size);
70
71 if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
72 return ERR_INVALID_ADDRESS;
73 }
74
75 if (size == 0 || !Is4KBAligned(size)) {
76 return ERR_INVALID_SIZE;
77 }
78
59 return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); 79 return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
60} 80}
61 81
@@ -63,6 +83,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
63static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 83static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
64 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, 84 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
65 src_addr, size); 85 src_addr, size);
86
87 if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
88 return ERR_INVALID_ADDRESS;
89 }
90
91 if (size == 0 || !Is4KBAligned(size)) {
92 return ERR_INVALID_SIZE;
93 }
94
66 return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); 95 return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
67} 96}
68 97
@@ -146,7 +175,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
146 175
147/// Default thread wakeup callback for WaitSynchronization 176/// Default thread wakeup callback for WaitSynchronization
148static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, 177static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
149 SharedPtr<WaitObject> object, size_t index) { 178 SharedPtr<WaitObject> object, std::size_t index) {
150 ASSERT(thread->status == ThreadStatus::WaitSynchAny); 179 ASSERT(thread->status == ThreadStatus::WaitSynchAny);
151 180
152 if (reason == ThreadWakeupReason::Timeout) { 181 if (reason == ThreadWakeupReason::Timeout) {
@@ -273,7 +302,11 @@ static void Break(u64 reason, u64 info1, u64 info2) {
273} 302}
274 303
275/// Used to output a message on a debug hardware unit - does nothing on a retail unit 304/// Used to output a message on a debug hardware unit - does nothing on a retail unit
276static void OutputDebugString(VAddr address, s32 len) { 305static void OutputDebugString(VAddr address, u64 len) {
306 if (len == 0) {
307 return;
308 }
309
277 std::string str(len, '\0'); 310 std::string str(len, '\0');
278 Memory::ReadBlock(address, str.data(), str.size()); 311 Memory::ReadBlock(address, str.data(), str.size());
279 LOG_DEBUG(Debug_Emulated, "{}", str); 312 LOG_DEBUG(Debug_Emulated, "{}", str);
@@ -378,7 +411,7 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) {
378/// Sets the priority for the specified thread 411/// Sets the priority for the specified thread
379static ResultCode SetThreadPriority(Handle handle, u32 priority) { 412static ResultCode SetThreadPriority(Handle handle, u32 priority) {
380 if (priority > THREADPRIO_LOWEST) { 413 if (priority > THREADPRIO_LOWEST) {
381 return ERR_OUT_OF_RANGE; 414 return ERR_INVALID_THREAD_PRIORITY;
382 } 415 }
383 416
384 auto& kernel = Core::System::GetInstance().Kernel(); 417 auto& kernel = Core::System::GetInstance().Kernel();
@@ -411,35 +444,43 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
411 "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", 444 "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
412 shared_memory_handle, addr, size, permissions); 445 shared_memory_handle, addr, size, permissions);
413 446
447 if (!Is4KBAligned(addr)) {
448 return ERR_INVALID_ADDRESS;
449 }
450
451 if (size == 0 || !Is4KBAligned(size)) {
452 return ERR_INVALID_SIZE;
453 }
454
455 const auto permissions_type = static_cast<MemoryPermission>(permissions);
456 if (permissions_type != MemoryPermission::Read &&
457 permissions_type != MemoryPermission::ReadWrite) {
458 LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions);
459 return ERR_INVALID_MEMORY_PERMISSIONS;
460 }
461
414 auto& kernel = Core::System::GetInstance().Kernel(); 462 auto& kernel = Core::System::GetInstance().Kernel();
415 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); 463 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
416 if (!shared_memory) { 464 if (!shared_memory) {
417 return ERR_INVALID_HANDLE; 465 return ERR_INVALID_HANDLE;
418 } 466 }
419 467
420 MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); 468 return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type,
421 switch (permissions_type) { 469 MemoryPermission::DontCare);
422 case MemoryPermission::Read:
423 case MemoryPermission::Write:
424 case MemoryPermission::ReadWrite:
425 case MemoryPermission::Execute:
426 case MemoryPermission::ReadExecute:
427 case MemoryPermission::WriteExecute:
428 case MemoryPermission::ReadWriteExecute:
429 case MemoryPermission::DontCare:
430 return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type,
431 MemoryPermission::DontCare);
432 default:
433 LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions);
434 }
435
436 return RESULT_SUCCESS;
437} 470}
438 471
439static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { 472static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
440 LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", 473 LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
441 shared_memory_handle, addr, size); 474 shared_memory_handle, addr, size);
442 475
476 if (!Is4KBAligned(addr)) {
477 return ERR_INVALID_ADDRESS;
478 }
479
480 if (size == 0 || !Is4KBAligned(size)) {
481 return ERR_INVALID_SIZE;
482 }
483
443 auto& kernel = Core::System::GetInstance().Kernel(); 484 auto& kernel = Core::System::GetInstance().Kernel();
444 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); 485 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
445 486
@@ -520,10 +561,10 @@ static void ExitProcess() {
520/// Creates a new thread 561/// Creates a new thread
521static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, 562static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
522 u32 priority, s32 processor_id) { 563 u32 priority, s32 processor_id) {
523 std::string name = fmt::format("unknown-{:X}", entry_point); 564 std::string name = fmt::format("thread-{:X}", entry_point);
524 565
525 if (priority > THREADPRIO_LOWEST) { 566 if (priority > THREADPRIO_LOWEST) {
526 return ERR_OUT_OF_RANGE; 567 return ERR_INVALID_THREAD_PRIORITY;
527 } 568 }
528 569
529 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; 570 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
@@ -544,8 +585,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
544 case THREADPROCESSORID_3: 585 case THREADPROCESSORID_3:
545 break; 586 break;
546 default: 587 default:
547 ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); 588 LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
548 break; 589 return ERR_INVALID_PROCESSOR_ID;
549 } 590 }
550 591
551 auto& kernel = Core::System::GetInstance().Kernel(); 592 auto& kernel = Core::System::GetInstance().Kernel();
@@ -643,16 +684,17 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
643 LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", 684 LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
644 condition_variable_addr, target); 685 condition_variable_addr, target);
645 686
646 auto RetrieveWaitingThreads = 687 auto RetrieveWaitingThreads = [](std::size_t core_index,
647 [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) { 688 std::vector<SharedPtr<Thread>>& waiting_threads,
648 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); 689 VAddr condvar_addr) {
649 auto& thread_list = scheduler->GetThreadList(); 690 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
691 auto& thread_list = scheduler->GetThreadList();
650 692
651 for (auto& thread : thread_list) { 693 for (auto& thread : thread_list) {
652 if (thread->condvar_wait_address == condvar_addr) 694 if (thread->condvar_wait_address == condvar_addr)
653 waiting_threads.push_back(thread); 695 waiting_threads.push_back(thread);
654 } 696 }
655 }; 697 };
656 698
657 // Retrieve a list of all threads that are waiting for this condition variable. 699 // Retrieve a list of all threads that are waiting for this condition variable.
658 std::vector<SharedPtr<Thread>> waiting_threads; 700 std::vector<SharedPtr<Thread>> waiting_threads;
@@ -668,7 +710,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
668 710
669 // Only process up to 'target' threads, unless 'target' is -1, in which case process 711 // Only process up to 'target' threads, unless 'target' is -1, in which case process
670 // them all. 712 // them all.
671 size_t last = waiting_threads.size(); 713 std::size_t last = waiting_threads.size();
672 if (target != -1) 714 if (target != -1)
673 last = target; 715 last = target;
674 716
@@ -676,12 +718,12 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
676 if (last > waiting_threads.size()) 718 if (last > waiting_threads.size())
677 return RESULT_SUCCESS; 719 return RESULT_SUCCESS;
678 720
679 for (size_t index = 0; index < last; ++index) { 721 for (std::size_t index = 0; index < last; ++index) {
680 auto& thread = waiting_threads[index]; 722 auto& thread = waiting_threads[index];
681 723
682 ASSERT(thread->condvar_wait_address == condition_variable_addr); 724 ASSERT(thread->condvar_wait_address == condition_variable_addr);
683 725
684 size_t current_core = Core::System::GetInstance().CurrentCoreIndex(); 726 std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex();
685 727
686 auto& monitor = Core::System::GetInstance().Monitor(); 728 auto& monitor = Core::System::GetInstance().Monitor();
687 729
@@ -894,12 +936,28 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
894 LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, 936 LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
895 local_permissions, remote_permissions); 937 local_permissions, remote_permissions);
896 938
939 // Size must be a multiple of 4KB and be less than or equal to
940 // approx. 8 GB (actually (1GB - 512B) * 8)
941 if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) {
942 return ERR_INVALID_SIZE;
943 }
944
945 const auto local_perms = static_cast<MemoryPermission>(local_permissions);
946 if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) {
947 return ERR_INVALID_MEMORY_PERMISSIONS;
948 }
949
950 const auto remote_perms = static_cast<MemoryPermission>(remote_permissions);
951 if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite &&
952 remote_perms != MemoryPermission::DontCare) {
953 return ERR_INVALID_MEMORY_PERMISSIONS;
954 }
955
897 auto& kernel = Core::System::GetInstance().Kernel(); 956 auto& kernel = Core::System::GetInstance().Kernel();
898 auto& handle_table = kernel.HandleTable(); 957 auto& handle_table = kernel.HandleTable();
899 auto shared_mem_handle = 958 auto shared_mem_handle =
900 SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size, 959 SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
901 static_cast<MemoryPermission>(local_permissions), 960 local_perms, remote_perms);
902 static_cast<MemoryPermission>(remote_permissions));
903 961
904 CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); 962 CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
905 return RESULT_SUCCESS; 963 return RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 79c3fe31b..1eda5f879 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -222,9 +222,9 @@ void SvcWrap() {
222 func((s64)PARAM(0)); 222 func((s64)PARAM(0));
223} 223}
224 224
225template <void func(u64, s32 len)> 225template <void func(u64, u64 len)>
226void SvcWrap() { 226void SvcWrap() {
227 func(PARAM(0), (s32)(PARAM(1) & 0xFFFFFFFF)); 227 func(PARAM(0), PARAM(1));
228} 228}
229 229
230template <void func(u64, u64, u64)> 230template <void func(u64, u64, u64)>
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 3d10d9af2..89cd5f401 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -227,12 +227,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
227 // Check if priority is in ranged. Lowest priority -> highest priority id. 227 // Check if priority is in ranged. Lowest priority -> highest priority id.
228 if (priority > THREADPRIO_LOWEST) { 228 if (priority > THREADPRIO_LOWEST) {
229 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); 229 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
230 return ERR_OUT_OF_RANGE; 230 return ERR_INVALID_THREAD_PRIORITY;
231 } 231 }
232 232
233 if (processor_id > THREADPROCESSORID_MAX) { 233 if (processor_id > THREADPROCESSORID_MAX) {
234 LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); 234 LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
235 return ERR_OUT_OF_RANGE_KERNEL; 235 return ERR_INVALID_PROCESSOR_ID;
236 } 236 }
237 237
238 // TODO(yuriks): Other checks, returning 0xD9001BEA 238 // TODO(yuriks): Other checks, returning 0xD9001BEA
@@ -275,7 +275,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
275 available_slot = 0; // Use the first slot in the new page 275 available_slot = 0; // Use the first slot in the new page
276 276
277 // Allocate some memory from the end of the linear heap for this region. 277 // Allocate some memory from the end of the linear heap for this region.
278 const size_t offset = thread->tls_memory->size(); 278 const std::size_t offset = thread->tls_memory->size();
279 thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0); 279 thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0);
280 280
281 auto& vm_manager = owner_process->vm_manager; 281 auto& vm_manager = owner_process->vm_manager;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 20f50458b..df4748942 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -15,6 +15,12 @@
15#include "core/hle/kernel/wait_object.h" 15#include "core/hle/kernel/wait_object.h"
16#include "core/hle/result.h" 16#include "core/hle/result.h"
17 17
18namespace Kernel {
19
20class KernelCore;
21class Process;
22class Scheduler;
23
18enum ThreadPriority : u32 { 24enum ThreadPriority : u32 {
19 THREADPRIO_HIGHEST = 0, ///< Highest thread priority 25 THREADPRIO_HIGHEST = 0, ///< Highest thread priority
20 THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps 26 THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
@@ -54,12 +60,6 @@ enum class ThreadWakeupReason {
54 Timeout // The thread was woken up due to a wait timeout. 60 Timeout // The thread was woken up due to a wait timeout.
55}; 61};
56 62
57namespace Kernel {
58
59class KernelCore;
60class Process;
61class Scheduler;
62
63class Thread final : public WaitObject { 63class Thread final : public WaitObject {
64public: 64public:
65 /** 65 /**
@@ -254,7 +254,7 @@ public:
254 Handle callback_handle; 254 Handle callback_handle;
255 255
256 using WakeupCallback = bool(ThreadWakeupReason reason, SharedPtr<Thread> thread, 256 using WakeupCallback = bool(ThreadWakeupReason reason, SharedPtr<Thread> thread,
257 SharedPtr<WaitObject> object, size_t index); 257 SharedPtr<WaitObject> object, std::size_t index);
258 // Callback that will be invoked when the thread is resumed from a waiting state. If the thread 258 // Callback that will be invoked when the thread is resumed from a waiting state. If the thread
259 // was waiting via WaitSynchronizationN then the object will be the last object that became 259 // was waiting via WaitSynchronizationN then the object will be the last object that became
260 // available. In case of a timeout, the object will be nullptr. 260 // available. In case of a timeout, the object will be nullptr.
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 479cacb62..608cbd57b 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -86,7 +86,7 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
86 86
87ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, 87ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
88 std::shared_ptr<std::vector<u8>> block, 88 std::shared_ptr<std::vector<u8>> block,
89 size_t offset, u64 size, 89 std::size_t offset, u64 size,
90 MemoryState state) { 90 MemoryState state) {
91 ASSERT(block != nullptr); 91 ASSERT(block != nullptr);
92 ASSERT(offset + size <= block->size()); 92 ASSERT(offset + size <= block->size());
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 98bd04bea..de75036c0 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -81,7 +81,7 @@ struct VirtualMemoryArea {
81 /// Memory block backing this VMA. 81 /// Memory block backing this VMA.
82 std::shared_ptr<std::vector<u8>> backing_block = nullptr; 82 std::shared_ptr<std::vector<u8>> backing_block = nullptr;
83 /// Offset into the backing_memory the mapping starts from. 83 /// Offset into the backing_memory the mapping starts from.
84 size_t offset = 0; 84 std::size_t offset = 0;
85 85
86 // Settings for type = BackingMemory 86 // Settings for type = BackingMemory
87 /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed. 87 /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
@@ -147,7 +147,7 @@ public:
147 * @param state MemoryState tag to attach to the VMA. 147 * @param state MemoryState tag to attach to the VMA.
148 */ 148 */
149 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, 149 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
150 size_t offset, u64 size, MemoryState state); 150 std::size_t offset, u64 size, MemoryState state);
151 151
152 /** 152 /**
153 * Maps an unmanaged host memory pointer at a given address. 153 * Maps an unmanaged host memory pointer at a given address.
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index eef00b729..b190ceb98 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -81,7 +81,7 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
81 } 81 }
82 } 82 }
83 83
84 size_t index = thread->GetWaitObjectIndex(this); 84 std::size_t index = thread->GetWaitObjectIndex(this);
85 85
86 for (auto& object : thread->wait_objects) 86 for (auto& object : thread->wait_objects)
87 object->RemoveWaitingThread(thread.get()); 87 object->RemoveWaitingThread(thread.get());
diff --git a/src/core/hle/service/acc/acc_su.h b/src/core/hle/service/acc/acc_su.h
index a3eb885bf..fcced063a 100644
--- a/src/core/hle/service/acc/acc_su.h
+++ b/src/core/hle/service/acc/acc_su.h
@@ -6,8 +6,7 @@
6 6
7#include "core/hle/service/acc/acc.h" 7#include "core/hle/service/acc/acc.h"
8 8
9namespace Service { 9namespace Service::Account {
10namespace Account {
11 10
12class ACC_SU final : public Module::Interface { 11class ACC_SU final : public Module::Interface {
13public: 12public:
@@ -16,5 +15,4 @@ public:
16 ~ACC_SU() override; 15 ~ACC_SU() override;
17}; 16};
18 17
19} // namespace Account 18} // namespace Service::Account
20} // namespace Service
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 4ccebef23..0071ca613 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -33,7 +33,7 @@ ProfileManager::~ProfileManager() = default;
33 33
34/// After a users creation it needs to be "registered" to the system. AddToProfiles handles the 34/// After a users creation it needs to be "registered" to the system. AddToProfiles handles the
35/// internal management of the users profiles 35/// internal management of the users profiles
36boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { 36boost::optional<std::size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) {
37 if (user_count >= MAX_USERS) { 37 if (user_count >= MAX_USERS) {
38 return boost::none; 38 return boost::none;
39 } 39 }
@@ -42,7 +42,7 @@ boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) {
42} 42}
43 43
44/// Deletes a specific profile based on it's profile index 44/// Deletes a specific profile based on it's profile index
45bool ProfileManager::RemoveProfileAtIndex(size_t index) { 45bool ProfileManager::RemoveProfileAtIndex(std::size_t index) {
46 if (index >= MAX_USERS || index >= user_count) { 46 if (index >= MAX_USERS || index >= user_count) {
47 return false; 47 return false;
48 } 48 }
@@ -101,7 +101,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username)
101} 101}
102 102
103/// Returns a users profile index based on their user id. 103/// Returns a users profile index based on their user id.
104boost::optional<size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { 104boost::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const {
105 if (!uuid) { 105 if (!uuid) {
106 return boost::none; 106 return boost::none;
107 } 107 }
@@ -110,16 +110,17 @@ boost::optional<size_t> ProfileManager::GetUserIndex(const UUID& uuid) const {
110 if (iter == profiles.end()) { 110 if (iter == profiles.end()) {
111 return boost::none; 111 return boost::none;
112 } 112 }
113 return static_cast<size_t>(std::distance(profiles.begin(), iter)); 113 return static_cast<std::size_t>(std::distance(profiles.begin(), iter));
114} 114}
115 115
116/// Returns a users profile index based on their profile 116/// Returns a users profile index based on their profile
117boost::optional<size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const { 117boost::optional<std::size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const {
118 return GetUserIndex(user.user_uuid); 118 return GetUserIndex(user.user_uuid);
119} 119}
120 120
121/// Returns the data structure used by the switch when GetProfileBase is called on acc:* 121/// Returns the data structure used by the switch when GetProfileBase is called on acc:*
122bool ProfileManager::GetProfileBase(boost::optional<size_t> index, ProfileBase& profile) const { 122bool ProfileManager::GetProfileBase(boost::optional<std::size_t> index,
123 ProfileBase& profile) const {
123 if (index == boost::none || index >= MAX_USERS) { 124 if (index == boost::none || index >= MAX_USERS) {
124 return false; 125 return false;
125 } 126 }
@@ -143,14 +144,16 @@ bool ProfileManager::GetProfileBase(const ProfileInfo& user, ProfileBase& profil
143 144
144/// Returns the current user count on the system. We keep a variable which tracks the count so we 145/// Returns the current user count on the system. We keep a variable which tracks the count so we
145/// don't have to loop the internal profile array every call. 146/// don't have to loop the internal profile array every call.
146size_t ProfileManager::GetUserCount() const { 147
148std::size_t ProfileManager::GetUserCount() const {
147 return user_count; 149 return user_count;
148} 150}
149 151
150/// Lists the current "opened" users on the system. Users are typically not open until they sign 152/// Lists the current "opened" users on the system. Users are typically not open until they sign
151/// into something or pick a profile. As of right now users should all be open until qlaunch is 153/// into something or pick a profile. As of right now users should all be open until qlaunch is
152/// booting 154/// booting
153size_t ProfileManager::GetOpenUserCount() const { 155
156std::size_t ProfileManager::GetOpenUserCount() const {
154 return std::count_if(profiles.begin(), profiles.end(), 157 return std::count_if(profiles.begin(), profiles.end(),
155 [](const ProfileInfo& p) { return p.is_open; }); 158 [](const ProfileInfo& p) { return p.is_open; });
156} 159}
@@ -206,7 +209,7 @@ UUID ProfileManager::GetLastOpenedUser() const {
206} 209}
207 210
208/// Return the users profile base and the unknown arbitary data. 211/// Return the users profile base and the unknown arbitary data.
209bool ProfileManager::GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile, 212bool ProfileManager::GetProfileBaseAndData(boost::optional<std::size_t> index, ProfileBase& profile,
210 ProfileData& data) const { 213 ProfileData& data) const {
211 if (GetProfileBase(index, profile)) { 214 if (GetProfileBase(index, profile)) {
212 data = profiles[index.get()].data; 215 data = profiles[index.get()].data;
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index cd8df93a5..bffd4cf4d 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -12,8 +12,8 @@
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13 13
14namespace Service::Account { 14namespace Service::Account {
15constexpr size_t MAX_USERS = 8; 15constexpr std::size_t MAX_USERS = 8;
16constexpr size_t MAX_DATA = 128; 16constexpr std::size_t MAX_DATA = 128;
17constexpr u128 INVALID_UUID{{0, 0}}; 17constexpr u128 INVALID_UUID{{0, 0}};
18 18
19struct UUID { 19struct UUID {
@@ -87,18 +87,18 @@ public:
87 ResultCode AddUser(const ProfileInfo& user); 87 ResultCode AddUser(const ProfileInfo& user);
88 ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username); 88 ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username);
89 ResultCode CreateNewUser(UUID uuid, const std::string& username); 89 ResultCode CreateNewUser(UUID uuid, const std::string& username);
90 boost::optional<size_t> GetUserIndex(const UUID& uuid) const; 90 boost::optional<std::size_t> GetUserIndex(const UUID& uuid) const;
91 boost::optional<size_t> GetUserIndex(const ProfileInfo& user) const; 91 boost::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const;
92 bool GetProfileBase(boost::optional<size_t> index, ProfileBase& profile) const; 92 bool GetProfileBase(boost::optional<std::size_t> index, ProfileBase& profile) const;
93 bool GetProfileBase(UUID uuid, ProfileBase& profile) const; 93 bool GetProfileBase(UUID uuid, ProfileBase& profile) const;
94 bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; 94 bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const;
95 bool GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile, 95 bool GetProfileBaseAndData(boost::optional<std::size_t> index, ProfileBase& profile,
96 ProfileData& data) const; 96 ProfileData& data) const;
97 bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const; 97 bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const;
98 bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, 98 bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile,
99 ProfileData& data) const; 99 ProfileData& data) const;
100 size_t GetUserCount() const; 100 std::size_t GetUserCount() const;
101 size_t GetOpenUserCount() const; 101 std::size_t GetOpenUserCount() const;
102 bool UserExists(UUID uuid) const; 102 bool UserExists(UUID uuid) const;
103 void OpenUser(UUID uuid); 103 void OpenUser(UUID uuid);
104 void CloseUser(UUID uuid); 104 void CloseUser(UUID uuid);
@@ -110,9 +110,9 @@ public:
110 110
111private: 111private:
112 std::array<ProfileInfo, MAX_USERS> profiles{}; 112 std::array<ProfileInfo, MAX_USERS> profiles{};
113 size_t user_count = 0; 113 std::size_t user_count = 0;
114 boost::optional<size_t> AddToProfiles(const ProfileInfo& profile); 114 boost::optional<std::size_t> AddToProfiles(const ProfileInfo& profile);
115 bool RemoveProfileAtIndex(size_t index); 115 bool RemoveProfileAtIndex(std::size_t index);
116 UUID last_opened_user{INVALID_UUID}; 116 UUID last_opened_user{INVALID_UUID};
117}; 117};
118 118
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index a57ed3042..d1f7007ec 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -456,7 +456,7 @@ private:
456 IPC::RequestParser rp{ctx}; 456 IPC::RequestParser rp{ctx};
457 457
458 const u64 offset{rp.Pop<u64>()}; 458 const u64 offset{rp.Pop<u64>()};
459 const size_t size{ctx.GetWriteBufferSize()}; 459 const std::size_t size{ctx.GetWriteBufferSize()};
460 460
461 ASSERT(offset + size <= buffer.size()); 461 ASSERT(offset + size <= buffer.size());
462 462
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 6b5e15633..128df7db5 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -15,6 +15,7 @@
15#include "core/hle/service/audio/audren_u.h" 15#include "core/hle/service/audio/audren_u.h"
16#include "core/hle/service/audio/codecctl.h" 16#include "core/hle/service/audio/codecctl.h"
17#include "core/hle/service/audio/hwopus.h" 17#include "core/hle/service/audio/hwopus.h"
18#include "core/hle/service/service.h"
18 19
19namespace Service::Audio { 20namespace Service::Audio {
20 21
diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h
index 95e5691f7..f5bd3bf5f 100644
--- a/src/core/hle/service/audio/audio.h
+++ b/src/core/hle/service/audio/audio.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h" 7namespace Service::SM {
8class ServiceManager;
9}
8 10
9namespace Service::Audio { 11namespace Service::Audio {
10 12
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 05100ca8f..80a002322 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -3,15 +3,20 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array> 5#include <array>
6#include <cstring>
6#include <vector> 7#include <vector>
7 8
9#include "audio_core/audio_out.h"
8#include "audio_core/codec.h" 10#include "audio_core/codec.h"
11#include "common/common_funcs.h"
9#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/swap.h"
10#include "core/core.h" 14#include "core/core.h"
11#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/hle_ipc.h" 17#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/service/audio/audout_u.h" 18#include "core/hle/service/audio/audout_u.h"
19#include "core/memory.h"
15 20
16namespace Service::Audio { 21namespace Service::Audio {
17 22
@@ -25,6 +30,18 @@ enum {
25constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}}; 30constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
26constexpr int DefaultSampleRate{48000}; 31constexpr int DefaultSampleRate{48000};
27 32
33struct AudoutParams {
34 s32_le sample_rate;
35 u16_le channel_count;
36 INSERT_PADDING_BYTES(2);
37};
38static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
39
40enum class AudioState : u32 {
41 Started,
42 Stopped,
43};
44
28class IAudioOut final : public ServiceFramework<IAudioOut> { 45class IAudioOut final : public ServiceFramework<IAudioOut> {
29public: 46public:
30 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) 47 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index aa52d3855..dcaf64708 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,27 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_out.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
9namespace AudioCore {
10class AudioOut;
11}
12
10namespace Kernel { 13namespace Kernel {
11class HLERequestContext; 14class HLERequestContext;
12} 15}
13 16
14namespace Service::Audio { 17namespace Service::Audio {
15 18
16struct AudoutParams {
17 s32_le sample_rate;
18 u16_le channel_count;
19 INSERT_PADDING_BYTES(2);
20};
21static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
22
23enum class AudioState : u32 {
24 Started,
25 Stopped,
26};
27
28class IAudioOut; 19class IAudioOut;
29 20
30class AudOutU final : public ServiceFramework<AudOutU> { 21class AudOutU final : public ServiceFramework<AudOutU> {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 3870bec65..e84c4fa2b 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -2,12 +2,14 @@
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 <algorithm>
5#include <array> 6#include <array>
7#include <memory>
6 8
9#include "audio_core/audio_renderer.h"
7#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/common_funcs.h"
8#include "common/logging/log.h" 12#include "common/logging/log.h"
9#include "core/core_timing.h"
10#include "core/core_timing_util.h"
11#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 14#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/hle_ipc.h" 15#include "core/hle/kernel/hle_ipc.h"
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 85a995a2f..c6bc3a90a 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_renderer.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
10namespace Kernel { 9namespace Kernel {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 341bfda42..fc6067e59 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -3,7 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <memory>
7#include <vector>
8
6#include <opus.h> 9#include <opus.h>
10
11#include "common/common_funcs.h"
7#include "common/logging/log.h" 12#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 14#include "core/hle/kernel/hle_ipc.h"
@@ -56,7 +61,7 @@ private:
56 61
57 bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input, 62 bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input,
58 std::vector<opus_int16>& output) { 63 std::vector<opus_int16>& output) {
59 size_t raw_output_sz = output.size() * sizeof(opus_int16); 64 std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
60 if (sizeof(OpusHeader) > input.size()) 65 if (sizeof(OpusHeader) > input.size())
61 return false; 66 return false;
62 OpusHeader hdr{}; 67 OpusHeader hdr{};
@@ -91,7 +96,7 @@ private:
91 u32 channel_count; 96 u32 channel_count;
92}; 97};
93 98
94static size_t WorkerBufferSize(u32 channel_count) { 99static std::size_t WorkerBufferSize(u32 channel_count) {
95 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); 100 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
96 return opus_decoder_get_size(static_cast<int>(channel_count)); 101 return opus_decoder_get_size(static_cast<int>(channel_count));
97} 102}
@@ -124,7 +129,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
124 "Invalid sample rate"); 129 "Invalid sample rate");
125 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); 130 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
126 131
127 size_t worker_sz = WorkerBufferSize(channel_count); 132 std::size_t worker_sz = WorkerBufferSize(channel_count);
128 ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large"); 133 ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large");
129 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ 134 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
130 static_cast<OpusDecoder*>(operator new(worker_sz))}; 135 static_cast<OpusDecoder*>(operator new(worker_sz))};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a8e0c869f..ab2f17db9 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -89,7 +89,7 @@ private:
89 controller_header.left_color_body = JOYCON_BODY_NEON_BLUE; 89 controller_header.left_color_body = JOYCON_BODY_NEON_BLUE;
90 controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE; 90 controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE;
91 91
92 for (size_t controller = 0; controller < mem.controllers.size(); controller++) { 92 for (std::size_t controller = 0; controller < mem.controllers.size(); controller++) {
93 for (auto& layout : mem.controllers[controller].layouts) { 93 for (auto& layout : mem.controllers[controller].layouts) {
94 layout.header.num_entries = HID_NUM_ENTRIES; 94 layout.header.num_entries = HID_NUM_ENTRIES;
95 layout.header.max_entry_index = HID_NUM_ENTRIES - 1; 95 layout.header.max_entry_index = HID_NUM_ENTRIES - 1;
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index 098da2a41..c89157a4d 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -99,7 +99,7 @@ private:
99 std::string thread; 99 std::string thread;
100 while (addr < end_addr) { 100 while (addr < end_addr) {
101 const Field field{static_cast<Field>(Memory::Read8(addr++))}; 101 const Field field{static_cast<Field>(Memory::Read8(addr++))};
102 const size_t length{Memory::Read8(addr++)}; 102 const std::size_t length{Memory::Read8(addr++)};
103 103
104 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { 104 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
105 ++addr; 105 ++addr;
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index da1c46d59..1069d103f 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -2,6 +2,10 @@
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 <algorithm>
6#include <cstring>
7#include <vector>
8
5#include <FontChineseSimplified.h> 9#include <FontChineseSimplified.h>
6#include <FontChineseTraditional.h> 10#include <FontChineseTraditional.h>
7#include <FontExtendedChineseSimplified.h> 11#include <FontExtendedChineseSimplified.h>
@@ -9,14 +13,19 @@
9#include <FontNintendoExtended.h> 13#include <FontNintendoExtended.h>
10#include <FontStandard.h> 14#include <FontStandard.h>
11 15
16#include "common/assert.h"
12#include "common/common_paths.h" 17#include "common/common_paths.h"
18#include "common/common_types.h"
13#include "common/file_util.h" 19#include "common/file_util.h"
20#include "common/logging/log.h"
21#include "common/swap.h"
14#include "core/core.h" 22#include "core/core.h"
15#include "core/file_sys/content_archive.h" 23#include "core/file_sys/content_archive.h"
16#include "core/file_sys/nca_metadata.h" 24#include "core/file_sys/nca_metadata.h"
17#include "core/file_sys/registered_cache.h" 25#include "core/file_sys/registered_cache.h"
18#include "core/file_sys/romfs.h" 26#include "core/file_sys/romfs.h"
19#include "core/hle/ipc_helpers.h" 27#include "core/hle/ipc_helpers.h"
28#include "core/hle/kernel/shared_memory.h"
20#include "core/hle/service/filesystem/filesystem.h" 29#include "core/hle/service/filesystem/filesystem.h"
21#include "core/hle/service/ns/pl_u.h" 30#include "core/hle/service/ns/pl_u.h"
22 31
@@ -35,49 +44,41 @@ struct FontRegion {
35 u32 size; 44 u32 size;
36}; 45};
37 46
38static constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ 47constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
39 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), 48 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"),
40 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), 49 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"),
41 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), 50 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"),
42 std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), 51 std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"),
43 std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), 52 std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"),
44 std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), 53 std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"),
45 std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf")}; 54 std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"),
55};
46 56
47static constexpr std::array<const char*, 7> SHARED_FONTS_TTF{"FontStandard.ttf", 57constexpr std::array<const char*, 7> SHARED_FONTS_TTF{
48 "FontChineseSimplified.ttf", 58 "FontStandard.ttf",
49 "FontExtendedChineseSimplified.ttf", 59 "FontChineseSimplified.ttf",
50 "FontChineseTraditional.ttf", 60 "FontExtendedChineseSimplified.ttf",
51 "FontKorean.ttf", 61 "FontChineseTraditional.ttf",
52 "FontNintendoExtended.ttf", 62 "FontKorean.ttf",
53 "FontNintendoExtended2.ttf"}; 63 "FontNintendoExtended.ttf",
64 "FontNintendoExtended2.ttf",
65};
54 66
55// The below data is specific to shared font data dumped from Switch on f/w 2.2 67// The below data is specific to shared font data dumped from Switch on f/w 2.2
56// Virtual address and offsets/sizes likely will vary by dump 68// Virtual address and offsets/sizes likely will vary by dump
57static constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; 69constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
58static constexpr u32 EXPECTED_RESULT{ 70constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be
59 0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be 71constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be
60static constexpr u32 EXPECTED_MAGIC{ 72constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
61 0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be 73constexpr FontRegion EMPTY_REGION{0, 0};
62static constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
63static constexpr FontRegion EMPTY_REGION{0, 0};
64std::vector<FontRegion>
65 SHARED_FONT_REGIONS{}; // Automatically populated based on shared_fonts dump or system archives
66
67const FontRegion& GetSharedFontRegion(size_t index) {
68 if (index >= SHARED_FONT_REGIONS.size() || SHARED_FONT_REGIONS.empty()) {
69 // No font fallback
70 return EMPTY_REGION;
71 }
72 return SHARED_FONT_REGIONS.at(index);
73}
74 74
75enum class LoadState : u32 { 75enum class LoadState : u32 {
76 Loading = 0, 76 Loading = 0,
77 Done = 1, 77 Done = 1,
78}; 78};
79 79
80void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, size_t& offset) { 80static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output,
81 std::size_t& offset) {
81 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, 82 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE,
82 "Shared fonts exceeds 17mb!"); 83 "Shared fonts exceeds 17mb!");
83 ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); 84 ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
@@ -94,7 +95,7 @@ void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, s
94} 95}
95 96
96static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& output, 97static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& output,
97 size_t& offset) { 98 std::size_t& offset) {
98 ASSERT_MSG(offset + input.size() + 8 < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!"); 99 ASSERT_MSG(offset + input.size() + 8 < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!");
99 const u32 KEY = EXPECTED_MAGIC ^ EXPECTED_RESULT; 100 const u32 KEY = EXPECTED_MAGIC ^ EXPECTED_RESULT;
100 std::memcpy(output.data() + offset, &EXPECTED_RESULT, sizeof(u32)); // Magic header 101 std::memcpy(output.data() + offset, &EXPECTED_RESULT, sizeof(u32)); // Magic header
@@ -104,28 +105,52 @@ static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& out
104 offset += input.size() + (sizeof(u32) * 2); 105 offset += input.size() + (sizeof(u32) * 2);
105} 106}
106 107
108// Helper function to make BuildSharedFontsRawRegions a bit nicer
107static u32 GetU32Swapped(const u8* data) { 109static u32 GetU32Swapped(const u8* data) {
108 u32 value; 110 u32 value;
109 std::memcpy(&value, data, sizeof(value)); 111 std::memcpy(&value, data, sizeof(value));
110 return Common::swap32(value); // Helper function to make BuildSharedFontsRawRegions a bit nicer 112 return Common::swap32(value);
111} 113}
112 114
113void BuildSharedFontsRawRegions(const std::vector<u8>& input) { 115struct PL_U::Impl {
114 unsigned cur_offset = 0; // As we can derive the xor key we can just populate the offsets based 116 const FontRegion& GetSharedFontRegion(std::size_t index) const {
115 // on the shared memory dump 117 if (index >= shared_font_regions.size() || shared_font_regions.empty()) {
116 for (size_t i = 0; i < SHARED_FONTS.size(); i++) { 118 // No font fallback
117 // Out of shared fonts/Invalid font 119 return EMPTY_REGION;
118 if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) 120 }
119 break; 121 return shared_font_regions.at(index);
120 const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^
121 EXPECTED_MAGIC; // Derive key withing inverse xor
122 const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY;
123 SHARED_FONT_REGIONS.push_back(FontRegion{cur_offset + 8, SIZE});
124 cur_offset += SIZE + 8;
125 } 122 }
126}
127 123
128PL_U::PL_U() : ServiceFramework("pl:u") { 124 void BuildSharedFontsRawRegions(const std::vector<u8>& input) {
125 // As we can derive the xor key we can just populate the offsets
126 // based on the shared memory dump
127 unsigned cur_offset = 0;
128
129 for (std::size_t i = 0; i < SHARED_FONTS.size(); i++) {
130 // Out of shared fonts/invalid font
131 if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) {
132 break;
133 }
134
135 // Derive key withing inverse xor
136 const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^ EXPECTED_MAGIC;
137 const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY;
138 shared_font_regions.push_back(FontRegion{cur_offset + 8, SIZE});
139 cur_offset += SIZE + 8;
140 }
141 }
142
143 /// Handle to shared memory region designated for a shared font
144 Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
145
146 /// Backing memory for the shared font data
147 std::shared_ptr<std::vector<u8>> shared_font;
148
149 // Automatically populated based on shared_fonts dump or system archives.
150 std::vector<FontRegion> shared_font_regions;
151};
152
153PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
129 static const FunctionInfo functions[] = { 154 static const FunctionInfo functions[] = {
130 {0, &PL_U::RequestLoad, "RequestLoad"}, 155 {0, &PL_U::RequestLoad, "RequestLoad"},
131 {1, &PL_U::GetLoadState, "GetLoadState"}, 156 {1, &PL_U::GetLoadState, "GetLoadState"},
@@ -137,11 +162,11 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
137 RegisterHandlers(functions); 162 RegisterHandlers(functions);
138 // Attempt to load shared font data from disk 163 // Attempt to load shared font data from disk
139 const auto nand = FileSystem::GetSystemNANDContents(); 164 const auto nand = FileSystem::GetSystemNANDContents();
140 size_t offset = 0; 165 std::size_t offset = 0;
141 // Rebuild shared fonts from data ncas 166 // Rebuild shared fonts from data ncas
142 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), 167 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard),
143 FileSys::ContentRecordType::Data)) { 168 FileSys::ContentRecordType::Data)) {
144 shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); 169 impl->shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE);
145 for (auto font : SHARED_FONTS) { 170 for (auto font : SHARED_FONTS) {
146 const auto nca = 171 const auto nca =
147 nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); 172 nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data);
@@ -177,12 +202,12 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
177 static_cast<u32>(offset + 8), 202 static_cast<u32>(offset + 8),
178 static_cast<u32>((font_data_u32.size() * sizeof(u32)) - 203 static_cast<u32>((font_data_u32.size() * sizeof(u32)) -
179 8)}; // Font offset and size do not account for the header 204 8)}; // Font offset and size do not account for the header
180 DecryptSharedFont(font_data_u32, *shared_font, offset); 205 DecryptSharedFont(font_data_u32, *impl->shared_font, offset);
181 SHARED_FONT_REGIONS.push_back(region); 206 impl->shared_font_regions.push_back(region);
182 } 207 }
183 208
184 } else { 209 } else {
185 shared_font = std::make_shared<std::vector<u8>>( 210 impl->shared_font = std::make_shared<std::vector<u8>>(
186 SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size 211 SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size
187 212
188 const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); 213 const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir);
@@ -206,8 +231,8 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
206 static_cast<u32>(offset + 8), 231 static_cast<u32>(offset + 8),
207 static_cast<u32>(ttf_bytes.size())}; // Font offset and size do not account 232 static_cast<u32>(ttf_bytes.size())}; // Font offset and size do not account
208 // for the header 233 // for the header
209 EncryptSharedFont(ttf_bytes, *shared_font, offset); 234 EncryptSharedFont(ttf_bytes, *impl->shared_font, offset);
210 SHARED_FONT_REGIONS.push_back(region); 235 impl->shared_font_regions.push_back(region);
211 } else { 236 } else {
212 LOG_WARNING(Service_NS, "Unable to load font: {}", font_ttf); 237 LOG_WARNING(Service_NS, "Unable to load font: {}", font_ttf);
213 } 238 }
@@ -222,26 +247,28 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
222 if (file.IsOpen()) { 247 if (file.IsOpen()) {
223 // Read shared font data 248 // Read shared font data
224 ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); 249 ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE);
225 file.ReadBytes(shared_font->data(), shared_font->size()); 250 file.ReadBytes(impl->shared_font->data(), impl->shared_font->size());
226 BuildSharedFontsRawRegions(*shared_font); 251 impl->BuildSharedFontsRawRegions(*impl->shared_font);
227 } else { 252 } else {
228 LOG_WARNING(Service_NS, 253 LOG_WARNING(Service_NS,
229 "Shared Font file missing. Loading open source replacement from memory"); 254 "Shared Font file missing. Loading open source replacement from memory");
230 255
256 // clang-format off
231 const std::vector<std::vector<u8>> open_source_shared_fonts_ttf = { 257 const std::vector<std::vector<u8>> open_source_shared_fonts_ttf = {
232 {std::begin(FontChineseSimplified), std::end(FontChineseSimplified)}, 258 {std::begin(FontChineseSimplified), std::end(FontChineseSimplified)},
233 {std::begin(FontChineseTraditional), std::end(FontChineseTraditional)}, 259 {std::begin(FontChineseTraditional), std::end(FontChineseTraditional)},
234 {std::begin(FontExtendedChineseSimplified), 260 {std::begin(FontExtendedChineseSimplified), std::end(FontExtendedChineseSimplified)},
235 std::end(FontExtendedChineseSimplified)}, 261 {std::begin(FontKorean), std::end(FontKorean)},
236 {std::begin(FontNintendoExtended), std::end(FontNintendoExtended)}, 262 {std::begin(FontNintendoExtended), std::end(FontNintendoExtended)},
237 {std::begin(FontStandard), std::end(FontStandard)}, 263 {std::begin(FontStandard), std::end(FontStandard)},
238 }; 264 };
265 // clang-format on
239 266
240 for (const std::vector<u8>& font_ttf : open_source_shared_fonts_ttf) { 267 for (const std::vector<u8>& font_ttf : open_source_shared_fonts_ttf) {
241 const FontRegion region{static_cast<u32>(offset + 8), 268 const FontRegion region{static_cast<u32>(offset + 8),
242 static_cast<u32>(font_ttf.size())}; 269 static_cast<u32>(font_ttf.size())};
243 EncryptSharedFont(font_ttf, *shared_font, offset); 270 EncryptSharedFont(font_ttf, *impl->shared_font, offset);
244 SHARED_FONT_REGIONS.push_back(region); 271 impl->shared_font_regions.push_back(region);
245 } 272 }
246 } 273 }
247 } 274 }
@@ -275,7 +302,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
275 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 302 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
276 IPC::ResponseBuilder rb{ctx, 3}; 303 IPC::ResponseBuilder rb{ctx, 3};
277 rb.Push(RESULT_SUCCESS); 304 rb.Push(RESULT_SUCCESS);
278 rb.Push<u32>(GetSharedFontRegion(font_id).size); 305 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
279} 306}
280 307
281void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { 308void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
@@ -285,17 +312,18 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
285 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 312 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
286 IPC::ResponseBuilder rb{ctx, 3}; 313 IPC::ResponseBuilder rb{ctx, 3};
287 rb.Push(RESULT_SUCCESS); 314 rb.Push(RESULT_SUCCESS);
288 rb.Push<u32>(GetSharedFontRegion(font_id).offset); 315 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
289} 316}
290 317
291void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 318void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
292 // Map backing memory for the font data 319 // Map backing memory for the font data
293 Core::CurrentProcess()->vm_manager.MapMemoryBlock( 320 Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
294 SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared); 321 SHARED_FONT_MEM_SIZE,
322 Kernel::MemoryState::Shared);
295 323
296 // Create shared font memory object 324 // Create shared font memory object
297 auto& kernel = Core::System::GetInstance().Kernel(); 325 auto& kernel = Core::System::GetInstance().Kernel();
298 shared_font_mem = Kernel::SharedMemory::Create( 326 impl->shared_font_mem = Kernel::SharedMemory::Create(
299 kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, 327 kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
300 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, 328 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
301 "PL_U:shared_font_mem"); 329 "PL_U:shared_font_mem");
@@ -303,7 +331,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
303 LOG_DEBUG(Service_NS, "called"); 331 LOG_DEBUG(Service_NS, "called");
304 IPC::ResponseBuilder rb{ctx, 2, 1}; 332 IPC::ResponseBuilder rb{ctx, 2, 1};
305 rb.Push(RESULT_SUCCESS); 333 rb.Push(RESULT_SUCCESS);
306 rb.PushCopyObjects(shared_font_mem); 334 rb.PushCopyObjects(impl->shared_font_mem);
307} 335}
308 336
309void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { 337void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
@@ -316,9 +344,9 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
316 std::vector<u32> font_sizes; 344 std::vector<u32> font_sizes;
317 345
318 // TODO(ogniK): Have actual priority order 346 // TODO(ogniK): Have actual priority order
319 for (size_t i = 0; i < SHARED_FONT_REGIONS.size(); i++) { 347 for (std::size_t i = 0; i < impl->shared_font_regions.size(); i++) {
320 font_codes.push_back(static_cast<u32>(i)); 348 font_codes.push_back(static_cast<u32>(i));
321 auto region = GetSharedFontRegion(i); 349 auto region = impl->GetSharedFontRegion(i);
322 font_offsets.push_back(region.offset); 350 font_offsets.push_back(region.offset);
323 font_sizes.push_back(region.size); 351 font_sizes.push_back(region.size);
324 } 352 }
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h
index 296c3db05..253f26a2a 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/pl_u.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/hle/kernel/shared_memory.h"
9#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
10 9
11namespace Service::NS { 10namespace Service::NS {
@@ -23,11 +22,8 @@ private:
23 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); 22 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
24 void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx); 23 void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx);
25 24
26 /// Handle to shared memory region designated for a shared font 25 struct Impl;
27 Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; 26 std::unique_ptr<Impl> impl;
28
29 /// Backing memory for the shared font data
30 std::shared_ptr<std::vector<u8>> shared_font;
31}; 27};
32 28
33} // namespace Service::NS 29} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 25d5a93fa..d8b8037a8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -71,7 +71,7 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
71} 71}
72 72
73u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 73u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
74 size_t num_entries = input.size() / sizeof(IoctlRemapEntry); 74 std::size_t num_entries = input.size() / sizeof(IoctlRemapEntry);
75 75
76 LOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries); 76 LOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries);
77 77
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 34f98fe5a..fd98d541d 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -9,8 +9,7 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/service/nvflinger/buffer_queue.h" 10#include "core/hle/service/nvflinger/buffer_queue.h"
11 11
12namespace Service { 12namespace Service::NVFlinger {
13namespace NVFlinger {
14 13
15BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { 14BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
16 auto& kernel = Core::System::GetInstance().Kernel(); 15 auto& kernel = Core::System::GetInstance().Kernel();
@@ -104,5 +103,4 @@ u32 BufferQueue::Query(QueryType type) {
104 return 0; 103 return 0;
105} 104}
106 105
107} // namespace NVFlinger 106} // namespace Service::NVFlinger
108} // namespace Service
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 17c81928a..50b767732 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -15,8 +15,7 @@ namespace CoreTiming {
15struct EventType; 15struct EventType;
16} 16}
17 17
18namespace Service { 18namespace Service::NVFlinger {
19namespace NVFlinger {
20 19
21struct IGBPBuffer { 20struct IGBPBuffer {
22 u32_le magic; 21 u32_le magic;
@@ -98,5 +97,4 @@ private:
98 Kernel::SharedPtr<Kernel::Event> buffer_wait_event; 97 Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
99}; 98};
100 99
101} // namespace NVFlinger 100} // namespace Service::NVFlinger
102} // namespace Service
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 7455ddd19..d47b6f659 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -23,7 +23,7 @@
23 23
24namespace Service::NVFlinger { 24namespace Service::NVFlinger {
25 25
26constexpr size_t SCREEN_REFRESH_RATE = 60; 26constexpr std::size_t SCREEN_REFRESH_RATE = 60;
27constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); 27constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
28 28
29NVFlinger::NVFlinger() { 29NVFlinger::NVFlinger() {
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 3c43b8d8c..6a9eccfb5 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -1,36 +1,47 @@
1#include <cinttypes> 1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
2#include "common/logging/log.h" 5#include "common/logging/log.h"
3#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
4#include "core/hle/kernel/event.h"
5#include "core/hle/service/prepo/prepo.h" 7#include "core/hle/service/prepo/prepo.h"
8#include "core/hle/service/service.h"
6 9
7namespace Service::PlayReport { 10namespace Service::PlayReport {
8PlayReport::PlayReport(const char* name) : ServiceFramework(name) {
9 static const FunctionInfo functions[] = {
10 {10100, nullptr, "SaveReport"},
11 {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
12 {10200, nullptr, "RequestImmediateTransmission"},
13 {10300, nullptr, "GetTransmissionStatus"},
14 {20100, nullptr, "SaveSystemReport"},
15 {20200, nullptr, "SetOperationMode"},
16 {20101, nullptr, "SaveSystemReportWithUser"},
17 {30100, nullptr, "ClearStorage"},
18 {40100, nullptr, "IsUserAgreementCheckEnabled"},
19 {40101, nullptr, "SetUserAgreementCheckEnabled"},
20 {90100, nullptr, "GetStorageUsage"},
21 {90200, nullptr, "GetStatistics"},
22 {90201, nullptr, "GetThroughputHistory"},
23 {90300, nullptr, "GetLastUploadError"},
24 };
25 RegisterHandlers(functions);
26};
27 11
28void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { 12class PlayReport final : public ServiceFramework<PlayReport> {
29 // TODO(ogniK): Do we want to add play report? 13public:
30 LOG_WARNING(Service_PREPO, "(STUBBED) called"); 14 explicit PlayReport(const char* name) : ServiceFramework{name} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {10100, nullptr, "SaveReport"},
18 {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
19 {10200, nullptr, "RequestImmediateTransmission"},
20 {10300, nullptr, "GetTransmissionStatus"},
21 {20100, nullptr, "SaveSystemReport"},
22 {20200, nullptr, "SetOperationMode"},
23 {20101, nullptr, "SaveSystemReportWithUser"},
24 {30100, nullptr, "ClearStorage"},
25 {40100, nullptr, "IsUserAgreementCheckEnabled"},
26 {40101, nullptr, "SetUserAgreementCheckEnabled"},
27 {90100, nullptr, "GetStorageUsage"},
28 {90200, nullptr, "GetStatistics"},
29 {90201, nullptr, "GetThroughputHistory"},
30 {90300, nullptr, "GetLastUploadError"},
31 };
32 // clang-format on
33
34 RegisterHandlers(functions);
35 }
36
37private:
38 void SaveReportWithUser(Kernel::HLERequestContext& ctx) {
39 // TODO(ogniK): Do we want to add play report?
40 LOG_WARNING(Service_PREPO, "(STUBBED) called");
31 41
32 IPC::ResponseBuilder rb{ctx, 2}; 42 IPC::ResponseBuilder rb{ctx, 2};
33 rb.Push(RESULT_SUCCESS); 43 rb.Push(RESULT_SUCCESS);
44 }
34}; 45};
35 46
36void InstallInterfaces(SM::ServiceManager& service_manager) { 47void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h
index f5a6aba6d..0e7b01331 100644
--- a/src/core/hle/service/prepo/prepo.h
+++ b/src/core/hle/service/prepo/prepo.h
@@ -4,22 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory> 7namespace Service::SM {
8#include <string> 8class ServiceManager;
9#include "core/hle/kernel/event.h" 9}
10#include "core/hle/service/service.h"
11 10
12namespace Service::PlayReport { 11namespace Service::PlayReport {
13 12
14class PlayReport final : public ServiceFramework<PlayReport> {
15public:
16 explicit PlayReport(const char* name);
17 ~PlayReport() = default;
18
19private:
20 void SaveReportWithUser(Kernel::HLERequestContext& ctx);
21};
22
23void InstallInterfaces(SM::ServiceManager& service_manager); 13void InstallInterfaces(SM::ServiceManager& service_manager);
24 14
25} // namespace Service::PlayReport 15} // namespace Service::PlayReport
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 9bb7c7b26..62f049660 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -50,6 +50,7 @@
50#include "core/hle/service/nim/nim.h" 50#include "core/hle/service/nim/nim.h"
51#include "core/hle/service/ns/ns.h" 51#include "core/hle/service/ns/ns.h"
52#include "core/hle/service/nvdrv/nvdrv.h" 52#include "core/hle/service/nvdrv/nvdrv.h"
53#include "core/hle/service/nvflinger/nvflinger.h"
53#include "core/hle/service/pcie/pcie.h" 54#include "core/hle/service/pcie/pcie.h"
54#include "core/hle/service/pctl/pctl.h" 55#include "core/hle/service/pctl/pctl.h"
55#include "core/hle/service/pcv/pcv.h" 56#include "core/hle/service/pcv/pcv.h"
@@ -58,7 +59,6 @@
58#include "core/hle/service/psc/psc.h" 59#include "core/hle/service/psc/psc.h"
59#include "core/hle/service/service.h" 60#include "core/hle/service/service.h"
60#include "core/hle/service/set/settings.h" 61#include "core/hle/service/set/settings.h"
61#include "core/hle/service/sm/controller.h"
62#include "core/hle/service/sm/sm.h" 62#include "core/hle/service/sm/sm.h"
63#include "core/hle/service/sockets/sockets.h" 63#include "core/hle/service/sockets/sockets.h"
64#include "core/hle/service/spl/module.h" 64#include "core/hle/service/spl/module.h"
@@ -129,9 +129,9 @@ Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() {
129 return client_port; 129 return client_port;
130} 130}
131 131
132void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, size_t n) { 132void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
133 handlers.reserve(handlers.size() + n); 133 handlers.reserve(handlers.size() + n);
134 for (size_t i = 0; i < n; ++i) { 134 for (std::size_t i = 0; i < n; ++i) {
135 // Usually this array is sorted by id already, so hint to insert at the end 135 // Usually this array is sorted by id already, so hint to insert at the end
136 handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]); 136 handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]);
137 } 137 }
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 7a051523e..2fc57a82e 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -88,7 +88,7 @@ private:
88 ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); 88 ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker);
89 ~ServiceFrameworkBase(); 89 ~ServiceFrameworkBase();
90 90
91 void RegisterHandlersBase(const FunctionInfoBase* functions, size_t n); 91 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
92 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); 92 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
93 93
94 /// Identifier string used to connect to the service. 94 /// Identifier string used to connect to the service.
@@ -152,7 +152,7 @@ protected:
152 : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} 152 : ServiceFrameworkBase(service_name, max_sessions, Invoker) {}
153 153
154 /// Registers handlers in the service. 154 /// Registers handlers in the service.
155 template <size_t N> 155 template <std::size_t N>
156 void RegisterHandlers(const FunctionInfo (&functions)[N]) { 156 void RegisterHandlers(const FunctionInfo (&functions)[N]) {
157 RegisterHandlers(functions, N); 157 RegisterHandlers(functions, N);
158 } 158 }
@@ -161,7 +161,7 @@ protected:
161 * Registers handlers in the service. Usually prefer using the other RegisterHandlers 161 * Registers handlers in the service. Usually prefer using the other RegisterHandlers
162 * overload in order to avoid needing to specify the array size. 162 * overload in order to avoid needing to specify the array size.
163 */ 163 */
164 void RegisterHandlers(const FunctionInfo* functions, size_t n) { 164 void RegisterHandlers(const FunctionInfo* functions, std::size_t n) {
165 RegisterHandlersBase(functions, n); 165 RegisterHandlersBase(functions, n);
166 } 166 }
167 167
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 59eb20155..9e5af7839 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -32,21 +32,21 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
32 LanguageCode::ZH_HANT, 32 LanguageCode::ZH_HANT,
33}}; 33}};
34 34
35constexpr size_t pre4_0_0_max_entries = 0xF; 35constexpr std::size_t pre4_0_0_max_entries = 0xF;
36constexpr size_t post4_0_0_max_entries = 0x40; 36constexpr std::size_t post4_0_0_max_entries = 0x40;
37 37
38LanguageCode GetLanguageCodeFromIndex(size_t index) { 38LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
39 return available_language_codes.at(index); 39 return available_language_codes.at(index);
40} 40}
41 41
42template <size_t size> 42template <std::size_t size>
43static std::array<LanguageCode, size> MakeLanguageCodeSubset() { 43static std::array<LanguageCode, size> MakeLanguageCodeSubset() {
44 std::array<LanguageCode, size> arr; 44 std::array<LanguageCode, size> arr;
45 std::copy_n(available_language_codes.begin(), size, arr.begin()); 45 std::copy_n(available_language_codes.begin(), size, arr.begin());
46 return arr; 46 return arr;
47} 47}
48 48
49static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, size_t max_size) { 49static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) {
50 IPC::ResponseBuilder rb{ctx, 3}; 50 IPC::ResponseBuilder rb{ctx, 3};
51 rb.Push(RESULT_SUCCESS); 51 rb.Push(RESULT_SUCCESS);
52 if (available_language_codes.size() > max_size) 52 if (available_language_codes.size() > max_size)
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 5f0214359..266f13e46 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -28,7 +28,7 @@ enum class LanguageCode : u64 {
28 ZH_HANS = 0x00736E61482D687A, 28 ZH_HANS = 0x00736E61482D687A,
29 ZH_HANT = 0x00746E61482D687A, 29 ZH_HANT = 0x00746E61482D687A,
30}; 30};
31LanguageCode GetLanguageCodeFromIndex(size_t idx); 31LanguageCode GetLanguageCodeFromIndex(std::size_t idx);
32 32
33class SET final : public ServiceFramework<SET> { 33class SET final : public ServiceFramework<SET> {
34public: 34public:
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 18d1641b8..096f0fd52 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -15,6 +15,10 @@
15 15
16namespace Service::SM { 16namespace Service::SM {
17 17
18constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
19constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
20constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
21
18ServiceManager::ServiceManager() = default; 22ServiceManager::ServiceManager() = default;
19ServiceManager::~ServiceManager() = default; 23ServiceManager::~ServiceManager() = default;
20 24
@@ -24,10 +28,10 @@ void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
24 28
25static ResultCode ValidateServiceName(const std::string& name) { 29static ResultCode ValidateServiceName(const std::string& name) {
26 if (name.size() <= 0 || name.size() > 8) { 30 if (name.size() <= 0 || name.size() > 8) {
27 return ERR_INVALID_NAME_SIZE; 31 return ERR_INVALID_NAME;
28 } 32 }
29 if (name.find('\0') != std::string::npos) { 33 if (name.find('\0') != std::string::npos) {
30 return ERR_NAME_CONTAINS_NUL; 34 return ERR_INVALID_NAME;
31 } 35 }
32 return RESULT_SUCCESS; 36 return RESULT_SUCCESS;
33} 37}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index a58d922a0..da2c51082 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -36,12 +36,6 @@ private:
36 std::shared_ptr<ServiceManager> service_manager; 36 std::shared_ptr<ServiceManager> service_manager;
37}; 37};
38 38
39constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(-1);
40constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1);
41constexpr ResultCode ERR_INVALID_NAME_SIZE(-1);
42constexpr ResultCode ERR_NAME_CONTAINS_NUL(-1);
43constexpr ResultCode ERR_ALREADY_REGISTERED(-1);
44
45class ServiceManager { 39class ServiceManager {
46public: 40public:
47 static void InstallInterfaces(std::shared_ptr<ServiceManager> self); 41 static void InstallInterfaces(std::shared_ptr<ServiceManager> self);
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 0d8441fb1..44a6717d0 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -21,7 +21,7 @@ Module::Interface::~Interface() = default;
21void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { 21void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
22 IPC::RequestParser rp{ctx}; 22 IPC::RequestParser rp{ctx};
23 23
24 size_t size = ctx.GetWriteBufferSize(); 24 std::size_t size = ctx.GetWriteBufferSize();
25 25
26 std::vector<u8> data(size); 26 std::vector<u8> data(size);
27 std::generate(data.begin(), data.end(), std::rand); 27 std::generate(data.begin(), data.end(), std::rand);
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 85244ac3b..d0cde5ede 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -4,25 +4,28 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7#include <cstring>
7#include <memory> 8#include <memory>
8#include <type_traits> 9#include <type_traits>
9#include <utility> 10#include <utility>
10#include <boost/optional.hpp> 11#include <boost/optional.hpp>
11#include "common/alignment.h" 12#include "common/alignment.h"
13#include "common/assert.h"
14#include "common/common_funcs.h"
15#include "common/logging/log.h"
12#include "common/math_util.h" 16#include "common/math_util.h"
13#include "common/scope_exit.h" 17#include "common/swap.h"
14#include "core/core_timing.h" 18#include "core/core_timing.h"
15#include "core/hle/ipc_helpers.h" 19#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/event.h" 20#include "core/hle/kernel/event.h"
17#include "core/hle/service/nvdrv/nvdrv.h" 21#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvflinger/buffer_queue.h" 22#include "core/hle/service/nvflinger/buffer_queue.h"
23#include "core/hle/service/nvflinger/nvflinger.h"
19#include "core/hle/service/vi/vi.h" 24#include "core/hle/service/vi/vi.h"
20#include "core/hle/service/vi/vi_m.h" 25#include "core/hle/service/vi/vi_m.h"
21#include "core/hle/service/vi/vi_s.h" 26#include "core/hle/service/vi/vi_s.h"
22#include "core/hle/service/vi/vi_u.h" 27#include "core/hle/service/vi/vi_u.h"
23#include "core/settings.h" 28#include "core/settings.h"
24#include "video_core/renderer_base.h"
25#include "video_core/video_core.h"
26 29
27namespace Service::VI { 30namespace Service::VI {
28 31
@@ -38,7 +41,7 @@ static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
38class Parcel { 41class Parcel {
39public: 42public:
40 // This default size was chosen arbitrarily. 43 // This default size was chosen arbitrarily.
41 static constexpr size_t DefaultBufferSize = 0x40; 44 static constexpr std::size_t DefaultBufferSize = 0x40;
42 Parcel() : buffer(DefaultBufferSize) {} 45 Parcel() : buffer(DefaultBufferSize) {}
43 explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {} 46 explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {}
44 virtual ~Parcel() = default; 47 virtual ~Parcel() = default;
@@ -66,7 +69,7 @@ public:
66 return val; 69 return val;
67 } 70 }
68 71
69 std::vector<u8> ReadBlock(size_t length) { 72 std::vector<u8> ReadBlock(std::size_t length) {
70 ASSERT(read_index + length <= buffer.size()); 73 ASSERT(read_index + length <= buffer.size());
71 const u8* const begin = buffer.data() + read_index; 74 const u8* const begin = buffer.data() + read_index;
72 const u8* const end = begin + length; 75 const u8* const end = begin + length;
@@ -156,8 +159,8 @@ private:
156 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size"); 159 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
157 160
158 std::vector<u8> buffer; 161 std::vector<u8> buffer;
159 size_t read_index = 0; 162 std::size_t read_index = 0;
160 size_t write_index = 0; 163 std::size_t write_index = 0;
161}; 164};
162 165
163class NativeWindow : public Parcel { 166class NativeWindow : public Parcel {
@@ -514,7 +517,7 @@ private:
514 ctx.SleepClientThread( 517 ctx.SleepClientThread(
515 Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1, 518 Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1,
516 [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, 519 [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
517 ThreadWakeupReason reason) { 520 Kernel::ThreadWakeupReason reason) {
518 // Repeat TransactParcel DequeueBuffer when a buffer is available 521 // Repeat TransactParcel DequeueBuffer when a buffer is available
519 auto buffer_queue = nv_flinger->GetBufferQueue(id); 522 auto buffer_queue = nv_flinger->GetBufferQueue(id);
520 boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); 523 boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index c2dc83605..e3963502a 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -4,11 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/nvflinger/nvflinger.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
10namespace CoreTiming { 9namespace Service::NVFlinger {
11struct EventType; 10class NVFlinger;
12} 11}
13 12
14namespace Service::VI { 13namespace Service::VI {
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 120e1e133..0e2af20b4 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -300,7 +300,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
300 } 300 }
301 301
302 std::vector<u8> program_image(total_image_size); 302 std::vector<u8> program_image(total_image_size);
303 size_t current_image_position = 0; 303 std::size_t current_image_position = 0;
304 304
305 auto& kernel = Core::System::GetInstance().Kernel(); 305 auto& kernel = Core::System::GetInstance().Kernel();
306 SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, ""); 306 SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index fa43a2650..f2a183ba1 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -155,7 +155,7 @@ constexpr std::array<const char*, 58> RESULT_MESSAGES{
155}; 155};
156 156
157std::ostream& operator<<(std::ostream& os, ResultStatus status) { 157std::ostream& operator<<(std::ostream& os, ResultStatus status) {
158 os << RESULT_MESSAGES.at(static_cast<size_t>(status)); 158 os << RESULT_MESSAGES.at(static_cast<std::size_t>(status));
159 return os; 159 return os;
160} 160}
161 161
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index bb89a9da3..c49ec34ab 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -191,7 +191,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
191 process->svc_access_mask.set(); 191 process->svc_access_mask.set();
192 process->resource_limit = 192 process->resource_limit =
193 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); 193 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
194 process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); 194 process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
195 195
196 is_loaded = true; 196 is_loaded = true;
197 return ResultStatus::Success; 197 return ResultStatus::Success;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 082a95d40..3c6306818 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -157,7 +157,8 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
157 process->svc_access_mask.set(); 157 process->svc_access_mask.set();
158 process->resource_limit = 158 process->resource_limit =
159 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); 159 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
160 process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); 160 process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT,
161 Memory::DEFAULT_STACK_SIZE);
161 162
162 is_loaded = true; 163 is_loaded = true;
163 return ResultStatus::Success; 164 return ResultStatus::Success;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 0e4e0157c..316b46820 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -370,16 +370,16 @@ u64 Read64(const VAddr addr) {
370} 370}
371 371
372void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 372void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
373 const size_t size) { 373 const std::size_t size) {
374 auto& page_table = process.vm_manager.page_table; 374 auto& page_table = process.vm_manager.page_table;
375 375
376 size_t remaining_size = size; 376 std::size_t remaining_size = size;
377 size_t page_index = src_addr >> PAGE_BITS; 377 std::size_t page_index = src_addr >> PAGE_BITS;
378 size_t page_offset = src_addr & PAGE_MASK; 378 std::size_t page_offset = src_addr & PAGE_MASK;
379 379
380 while (remaining_size > 0) { 380 while (remaining_size > 0) {
381 const size_t copy_amount = 381 const std::size_t copy_amount =
382 std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); 382 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
383 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 383 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
384 384
385 switch (page_table.attributes[page_index]) { 385 switch (page_table.attributes[page_index]) {
@@ -414,7 +414,7 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_
414 } 414 }
415} 415}
416 416
417void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { 417void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
418 ReadBlock(*Core::CurrentProcess(), src_addr, dest_buffer, size); 418 ReadBlock(*Core::CurrentProcess(), src_addr, dest_buffer, size);
419} 419}
420 420
@@ -435,15 +435,15 @@ void Write64(const VAddr addr, const u64 data) {
435} 435}
436 436
437void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, 437void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
438 const size_t size) { 438 const std::size_t size) {
439 auto& page_table = process.vm_manager.page_table; 439 auto& page_table = process.vm_manager.page_table;
440 size_t remaining_size = size; 440 std::size_t remaining_size = size;
441 size_t page_index = dest_addr >> PAGE_BITS; 441 std::size_t page_index = dest_addr >> PAGE_BITS;
442 size_t page_offset = dest_addr & PAGE_MASK; 442 std::size_t page_offset = dest_addr & PAGE_MASK;
443 443
444 while (remaining_size > 0) { 444 while (remaining_size > 0) {
445 const size_t copy_amount = 445 const std::size_t copy_amount =
446 std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); 446 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
447 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 447 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
448 448
449 switch (page_table.attributes[page_index]) { 449 switch (page_table.attributes[page_index]) {
@@ -477,19 +477,19 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi
477 } 477 }
478} 478}
479 479
480void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { 480void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
481 WriteBlock(*Core::CurrentProcess(), dest_addr, src_buffer, size); 481 WriteBlock(*Core::CurrentProcess(), dest_addr, src_buffer, size);
482} 482}
483 483
484void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size_t size) { 484void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
485 auto& page_table = process.vm_manager.page_table; 485 auto& page_table = process.vm_manager.page_table;
486 size_t remaining_size = size; 486 std::size_t remaining_size = size;
487 size_t page_index = dest_addr >> PAGE_BITS; 487 std::size_t page_index = dest_addr >> PAGE_BITS;
488 size_t page_offset = dest_addr & PAGE_MASK; 488 std::size_t page_offset = dest_addr & PAGE_MASK;
489 489
490 while (remaining_size > 0) { 490 while (remaining_size > 0) {
491 const size_t copy_amount = 491 const std::size_t copy_amount =
492 std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); 492 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
493 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 493 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
494 494
495 switch (page_table.attributes[page_index]) { 495 switch (page_table.attributes[page_index]) {
@@ -522,15 +522,16 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size
522 } 522 }
523} 523}
524 524
525void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, const size_t size) { 525void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
526 const std::size_t size) {
526 auto& page_table = process.vm_manager.page_table; 527 auto& page_table = process.vm_manager.page_table;
527 size_t remaining_size = size; 528 std::size_t remaining_size = size;
528 size_t page_index = src_addr >> PAGE_BITS; 529 std::size_t page_index = src_addr >> PAGE_BITS;
529 size_t page_offset = src_addr & PAGE_MASK; 530 std::size_t page_offset = src_addr & PAGE_MASK;
530 531
531 while (remaining_size > 0) { 532 while (remaining_size > 0) {
532 const size_t copy_amount = 533 const std::size_t copy_amount =
533 std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); 534 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
534 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 535 const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
535 536
536 switch (page_table.attributes[page_index]) { 537 switch (page_table.attributes[page_index]) {
@@ -565,7 +566,7 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
565 } 566 }
566} 567}
567 568
568void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size) { 569void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) {
569 CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size); 570 CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size);
570} 571}
571 572
diff --git a/src/core/memory.h b/src/core/memory.h
index f06e04a75..2a27c0251 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -22,11 +22,11 @@ namespace Memory {
22 * Page size used by the ARM architecture. This is the smallest granularity with which memory can 22 * Page size used by the ARM architecture. This is the smallest granularity with which memory can
23 * be mapped. 23 * be mapped.
24 */ 24 */
25constexpr size_t PAGE_BITS = 12; 25constexpr std::size_t PAGE_BITS = 12;
26constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; 26constexpr u64 PAGE_SIZE = 1 << PAGE_BITS;
27constexpr u64 PAGE_MASK = PAGE_SIZE - 1; 27constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
28constexpr size_t ADDRESS_SPACE_BITS = 36; 28constexpr std::size_t ADDRESS_SPACE_BITS = 36;
29constexpr size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS); 29constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS);
30 30
31enum class PageType : u8 { 31enum class PageType : u8 {
32 /// Page is unmapped and should cause an access error. 32 /// Page is unmapped and should cause an access error.
@@ -154,13 +154,13 @@ void Write16(VAddr addr, u16 data);
154void Write32(VAddr addr, u32 data); 154void Write32(VAddr addr, u32 data);
155void Write64(VAddr addr, u64 data); 155void Write64(VAddr addr, u64 data);
156 156
157void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, size_t size); 157void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size);
158void ReadBlock(VAddr src_addr, void* dest_buffer, size_t size); 158void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
159void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, 159void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
160 size_t size); 160 std::size_t size);
161void WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size); 161void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
162void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, size_t size); 162void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
163void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size); 163void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
164 164
165u8* GetPointer(VAddr vaddr); 165u8* GetPointer(VAddr vaddr);
166 166
diff --git a/src/core/memory_hook.h b/src/core/memory_hook.h
index e8ea19333..0269c7ff1 100644
--- a/src/core/memory_hook.h
+++ b/src/core/memory_hook.h
@@ -32,14 +32,14 @@ public:
32 virtual boost::optional<u32> Read32(VAddr addr) = 0; 32 virtual boost::optional<u32> Read32(VAddr addr) = 0;
33 virtual boost::optional<u64> Read64(VAddr addr) = 0; 33 virtual boost::optional<u64> Read64(VAddr addr) = 0;
34 34
35 virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, size_t size) = 0; 35 virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
36 36
37 virtual bool Write8(VAddr addr, u8 data) = 0; 37 virtual bool Write8(VAddr addr, u8 data) = 0;
38 virtual bool Write16(VAddr addr, u16 data) = 0; 38 virtual bool Write16(VAddr addr, u16 data) = 0;
39 virtual bool Write32(VAddr addr, u32 data) = 0; 39 virtual bool Write32(VAddr addr, u32 data) = 0;
40 virtual bool Write64(VAddr addr, u64 data) = 0; 40 virtual bool Write64(VAddr addr, u64 data) = 0;
41 41
42 virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size) = 0; 42 virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0;
43}; 43};
44 44
45using MemoryHookPointer = std::shared_ptr<MemoryHook>; 45using MemoryHookPointer = std::shared_ptr<MemoryHook>;
diff --git a/src/core/settings.h b/src/core/settings.h
index 08a16ef2c..0318d019c 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -148,6 +148,7 @@ struct Values {
148 148
149 // Audio 149 // Audio
150 std::string sink_id; 150 std::string sink_id;
151 bool enable_audio_stretching;
151 std::string audio_device_id; 152 std::string audio_device_id;
152 float volume; 153 float volume;
153 154
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 3730e85b8..b0df154ca 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -120,6 +120,9 @@ TelemetrySession::TelemetrySession() {
120 Telemetry::AppendOSInfo(field_collection); 120 Telemetry::AppendOSInfo(field_collection);
121 121
122 // Log user configuration information 122 // Log user configuration information
123 AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id);
124 AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",
125 Settings::values.enable_audio_stretching);
123 AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit); 126 AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit);
124 AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore", 127 AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore",
125 Settings::values.use_multi_core); 128 Settings::values.use_multi_core);
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp
index af032f0c9..73cacb47f 100644
--- a/src/core/tracer/recorder.cpp
+++ b/src/core/tracer/recorder.cpp
@@ -76,7 +76,7 @@ void Recorder::Finish(const std::string& filename) {
76 try { 76 try {
77 // Open file and write header 77 // Open file and write header
78 FileUtil::IOFile file(filename, "wb"); 78 FileUtil::IOFile file(filename, "wb");
79 size_t written = file.WriteObject(header); 79 std::size_t written = file.WriteObject(header);
80 if (written != 1 || file.Tell() != initial.gpu_registers) 80 if (written != 1 || file.Tell() != initial.gpu_registers)
81 throw "Failed to write header"; 81 throw "Failed to write header";
82 82
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 4d74bb395..37f09ce5f 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,16 +1,15 @@
1add_executable(tests 1add_executable(tests
2 common/param_package.cpp 2 common/param_package.cpp
3 common/ring_buffer.cpp
3 core/arm/arm_test_common.cpp 4 core/arm/arm_test_common.cpp
4 core/arm/arm_test_common.h 5 core/arm/arm_test_common.h
5 core/core_timing.cpp 6 core/core_timing.cpp
6 glad.cpp
7 tests.cpp 7 tests.cpp
8) 8)
9 9
10create_target_directory_groups(tests) 10create_target_directory_groups(tests)
11 11
12target_link_libraries(tests PRIVATE common core) 12target_link_libraries(tests PRIVATE common core)
13target_link_libraries(tests PRIVATE glad) # To support linker work-around
14target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads) 13target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads)
15 14
16add_test(NAME tests COMMAND tests) 15add_test(NAME tests COMMAND tests)
diff --git a/src/tests/common/ring_buffer.cpp b/src/tests/common/ring_buffer.cpp
new file mode 100644
index 000000000..c883c4d56
--- /dev/null
+++ b/src/tests/common/ring_buffer.cpp
@@ -0,0 +1,130 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <array>
7#include <cstddef>
8#include <numeric>
9#include <thread>
10#include <vector>
11#include <catch2/catch.hpp>
12#include "common/ring_buffer.h"
13
14namespace Common {
15
16TEST_CASE("RingBuffer: Basic Tests", "[common]") {
17 RingBuffer<char, 4, 1> buf;
18
19 // Pushing values into a ring buffer with space should succeed.
20 for (std::size_t i = 0; i < 4; i++) {
21 const char elem = static_cast<char>(i);
22 const std::size_t count = buf.Push(&elem, 1);
23 REQUIRE(count == 1);
24 }
25
26 REQUIRE(buf.Size() == 4);
27
28 // Pushing values into a full ring buffer should fail.
29 {
30 const char elem = static_cast<char>(42);
31 const std::size_t count = buf.Push(&elem, 1);
32 REQUIRE(count == 0);
33 }
34
35 REQUIRE(buf.Size() == 4);
36
37 // Popping multiple values from a ring buffer with values should succeed.
38 {
39 const std::vector<char> popped = buf.Pop(2);
40 REQUIRE(popped.size() == 2);
41 REQUIRE(popped[0] == 0);
42 REQUIRE(popped[1] == 1);
43 }
44
45 REQUIRE(buf.Size() == 2);
46
47 // Popping a single value from a ring buffer with values should succeed.
48 {
49 const std::vector<char> popped = buf.Pop(1);
50 REQUIRE(popped.size() == 1);
51 REQUIRE(popped[0] == 2);
52 }
53
54 REQUIRE(buf.Size() == 1);
55
56 // Pushing more values than space available should partially suceed.
57 {
58 std::vector<char> to_push(6);
59 std::iota(to_push.begin(), to_push.end(), 88);
60 const std::size_t count = buf.Push(to_push);
61 REQUIRE(count == 3);
62 }
63
64 REQUIRE(buf.Size() == 4);
65
66 // Doing an unlimited pop should pop all values.
67 {
68 const std::vector<char> popped = buf.Pop();
69 REQUIRE(popped.size() == 4);
70 REQUIRE(popped[0] == 3);
71 REQUIRE(popped[1] == 88);
72 REQUIRE(popped[2] == 89);
73 REQUIRE(popped[3] == 90);
74 }
75
76 REQUIRE(buf.Size() == 0);
77}
78
79TEST_CASE("RingBuffer: Threaded Test", "[common]") {
80 RingBuffer<char, 4, 2> buf;
81 const char seed = 42;
82 const std::size_t count = 1000000;
83 std::size_t full = 0;
84 std::size_t empty = 0;
85
86 const auto next_value = [](std::array<char, 2>& value) {
87 value[0] += 1;
88 value[1] += 2;
89 };
90
91 std::thread producer{[&] {
92 std::array<char, 2> value = {seed, seed};
93 std::size_t i = 0;
94 while (i < count) {
95 if (const std::size_t c = buf.Push(&value[0], 1); c > 0) {
96 REQUIRE(c == 1);
97 i++;
98 next_value(value);
99 } else {
100 full++;
101 std::this_thread::yield();
102 }
103 }
104 }};
105
106 std::thread consumer{[&] {
107 std::array<char, 2> value = {seed, seed};
108 std::size_t i = 0;
109 while (i < count) {
110 if (const std::vector<char> v = buf.Pop(1); v.size() > 0) {
111 REQUIRE(v.size() == 2);
112 REQUIRE(v[0] == value[0]);
113 REQUIRE(v[1] == value[1]);
114 i++;
115 next_value(value);
116 } else {
117 empty++;
118 std::this_thread::yield();
119 }
120 }
121 }};
122
123 producer.join();
124 consumer.join();
125
126 REQUIRE(buf.Size() == 0);
127 printf("RingBuffer: Threaded Test: full: %zu, empty: %zu\n", full, empty);
128}
129
130} // namespace Common
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 038d57b3a..7c69fc26e 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -87,11 +87,11 @@ boost::optional<u64> TestEnvironment::TestMemory::Read64(VAddr addr) {
87 return *Read32(addr) | static_cast<u64>(*Read32(addr + 4)) << 32; 87 return *Read32(addr) | static_cast<u64>(*Read32(addr + 4)) << 32;
88} 88}
89 89
90bool TestEnvironment::TestMemory::ReadBlock(VAddr src_addr, void* dest_buffer, size_t size) { 90bool TestEnvironment::TestMemory::ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) {
91 VAddr addr = src_addr; 91 VAddr addr = src_addr;
92 u8* data = static_cast<u8*>(dest_buffer); 92 u8* data = static_cast<u8*>(dest_buffer);
93 93
94 for (size_t i = 0; i < size; i++, addr++, data++) { 94 for (std::size_t i = 0; i < size; i++, addr++, data++) {
95 *data = *Read8(addr); 95 *data = *Read8(addr);
96 } 96 }
97 97
@@ -126,11 +126,12 @@ bool TestEnvironment::TestMemory::Write64(VAddr addr, u64 data) {
126 return true; 126 return true;
127} 127}
128 128
129bool TestEnvironment::TestMemory::WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size) { 129bool TestEnvironment::TestMemory::WriteBlock(VAddr dest_addr, const void* src_buffer,
130 std::size_t size) {
130 VAddr addr = dest_addr; 131 VAddr addr = dest_addr;
131 const u8* data = static_cast<const u8*>(src_buffer); 132 const u8* data = static_cast<const u8*>(src_buffer);
132 133
133 for (size_t i = 0; i < size; i++, addr++, data++) { 134 for (std::size_t i = 0; i < size; i++, addr++, data++) {
134 env->write_records.emplace_back(8, addr, *data); 135 env->write_records.emplace_back(8, addr, *data);
135 if (env->mutable_memory) 136 if (env->mutable_memory)
136 env->SetMemory8(addr, *data); 137 env->SetMemory8(addr, *data);
diff --git a/src/tests/core/arm/arm_test_common.h b/src/tests/core/arm/arm_test_common.h
index e4b6df194..5de8dab4e 100644
--- a/src/tests/core/arm/arm_test_common.h
+++ b/src/tests/core/arm/arm_test_common.h
@@ -19,8 +19,8 @@ struct PageTable;
19namespace ArmTests { 19namespace ArmTests {
20 20
21struct WriteRecord { 21struct WriteRecord {
22 WriteRecord(size_t size, VAddr addr, u64 data) : size(size), addr(addr), data(data) {} 22 WriteRecord(std::size_t size, VAddr addr, u64 data) : size(size), addr(addr), data(data) {}
23 size_t size; 23 std::size_t size;
24 VAddr addr; 24 VAddr addr;
25 u64 data; 25 u64 data;
26 bool operator==(const WriteRecord& o) const { 26 bool operator==(const WriteRecord& o) const {
@@ -71,14 +71,14 @@ private:
71 boost::optional<u32> Read32(VAddr addr) override; 71 boost::optional<u32> Read32(VAddr addr) override;
72 boost::optional<u64> Read64(VAddr addr) override; 72 boost::optional<u64> Read64(VAddr addr) override;
73 73
74 bool ReadBlock(VAddr src_addr, void* dest_buffer, size_t size) override; 74 bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) override;
75 75
76 bool Write8(VAddr addr, u8 data) override; 76 bool Write8(VAddr addr, u8 data) override;
77 bool Write16(VAddr addr, u16 data) override; 77 bool Write16(VAddr addr, u16 data) override;
78 bool Write32(VAddr addr, u32 data) override; 78 bool Write32(VAddr addr, u32 data) override;
79 bool Write64(VAddr addr, u64 data) override; 79 bool Write64(VAddr addr, u64 data) override;
80 80
81 bool WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size) override; 81 bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) override;
82 82
83 std::unordered_map<VAddr, u8> data; 83 std::unordered_map<VAddr, u8> data;
84 }; 84 };
diff --git a/src/tests/glad.cpp b/src/tests/glad.cpp
deleted file mode 100644
index 1797c0e3d..000000000
--- a/src/tests/glad.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <catch2/catch.hpp>
6#include <glad/glad.h>
7
8// This is not an actual test, but a work-around for issue #2183.
9// If tests uses functions in core but doesn't explicitly use functions in glad, the linker of macOS
10// will error about undefined references from video_core to glad. So we explicitly use a glad
11// function here to shut up the linker.
12TEST_CASE("glad fake test", "[dummy]") {
13 REQUIRE(&gladLoadGL != nullptr);
14}
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index ac4ec36de..f5ae57039 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -5,6 +5,8 @@ add_library(video_core STATIC
5 debug_utils/debug_utils.h 5 debug_utils/debug_utils.h
6 engines/fermi_2d.cpp 6 engines/fermi_2d.cpp
7 engines/fermi_2d.h 7 engines/fermi_2d.h
8 engines/kepler_memory.cpp
9 engines/kepler_memory.h
8 engines/maxwell_3d.cpp 10 engines/maxwell_3d.cpp
9 engines/maxwell_3d.h 11 engines/maxwell_3d.h
10 engines/maxwell_compute.cpp 12 engines/maxwell_compute.cpp
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 2625ddfdc..f1aa6091b 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -14,6 +14,7 @@
14#include "core/tracer/recorder.h" 14#include "core/tracer/recorder.h"
15#include "video_core/command_processor.h" 15#include "video_core/command_processor.h"
16#include "video_core/engines/fermi_2d.h" 16#include "video_core/engines/fermi_2d.h"
17#include "video_core/engines/kepler_memory.h"
17#include "video_core/engines/maxwell_3d.h" 18#include "video_core/engines/maxwell_3d.h"
18#include "video_core/engines/maxwell_compute.h" 19#include "video_core/engines/maxwell_compute.h"
19#include "video_core/engines/maxwell_dma.h" 20#include "video_core/engines/maxwell_dma.h"
@@ -69,6 +70,9 @@ void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
69 case EngineID::MAXWELL_DMA_COPY_A: 70 case EngineID::MAXWELL_DMA_COPY_A:
70 maxwell_dma->WriteReg(method, value); 71 maxwell_dma->WriteReg(method, value);
71 break; 72 break;
73 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
74 kepler_memory->WriteReg(method, value);
75 break;
72 default: 76 default:
73 UNIMPLEMENTED_MSG("Unimplemented engine"); 77 UNIMPLEMENTED_MSG("Unimplemented engine");
74 } 78 }
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index dcf9ef8b9..021b83eaa 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -26,7 +26,7 @@ public:
26 void WriteReg(u32 method, u32 value); 26 void WriteReg(u32 method, u32 value);
27 27
28 struct Regs { 28 struct Regs {
29 static constexpr size_t NUM_REGS = 0x258; 29 static constexpr std::size_t NUM_REGS = 0x258;
30 30
31 struct Surface { 31 struct Surface {
32 RenderTargetFormat format; 32 RenderTargetFormat format;
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
new file mode 100644
index 000000000..66ae6332d
--- /dev/null
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -0,0 +1,45 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/memory.h"
7#include "video_core/engines/kepler_memory.h"
8
9namespace Tegra::Engines {
10
11KeplerMemory::KeplerMemory(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
12KeplerMemory::~KeplerMemory() = default;
13
14void KeplerMemory::WriteReg(u32 method, u32 value) {
15 ASSERT_MSG(method < Regs::NUM_REGS,
16 "Invalid KeplerMemory register, increase the size of the Regs structure");
17
18 regs.reg_array[method] = value;
19
20 switch (method) {
21 case KEPLERMEMORY_REG_INDEX(exec): {
22 state.write_offset = 0;
23 break;
24 }
25 case KEPLERMEMORY_REG_INDEX(data): {
26 ProcessData(value);
27 break;
28 }
29 }
30}
31
32void KeplerMemory::ProcessData(u32 data) {
33 ASSERT_MSG(regs.exec.linear, "Non-linear uploads are not supported");
34 ASSERT(regs.dest.x == 0 && regs.dest.y == 0 && regs.dest.z == 0);
35
36 GPUVAddr address = regs.dest.Address();
37 VAddr dest_address =
38 *memory_manager.GpuToCpuAddress(address + state.write_offset * sizeof(u32));
39
40 Memory::Write32(dest_address, data);
41
42 state.write_offset++;
43}
44
45} // namespace Tegra::Engines
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
new file mode 100644
index 000000000..b0d0078cf
--- /dev/null
+++ b/src/video_core/engines/kepler_memory.h
@@ -0,0 +1,90 @@
1// Copyright 2018 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 <array>
8#include "common/assert.h"
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "video_core/memory_manager.h"
13
14namespace Tegra::Engines {
15
16#define KEPLERMEMORY_REG_INDEX(field_name) \
17 (offsetof(Tegra::Engines::KeplerMemory::Regs, field_name) / sizeof(u32))
18
19class KeplerMemory final {
20public:
21 KeplerMemory(MemoryManager& memory_manager);
22 ~KeplerMemory();
23
24 /// Write the value to the register identified by method.
25 void WriteReg(u32 method, u32 value);
26
27 struct Regs {
28 static constexpr size_t NUM_REGS = 0x7F;
29
30 union {
31 struct {
32 INSERT_PADDING_WORDS(0x60);
33
34 u32 line_length_in;
35 u32 line_count;
36
37 struct {
38 u32 address_high;
39 u32 address_low;
40 u32 pitch;
41 u32 block_dimensions;
42 u32 width;
43 u32 height;
44 u32 depth;
45 u32 z;
46 u32 x;
47 u32 y;
48
49 GPUVAddr Address() const {
50 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
51 address_low);
52 }
53 } dest;
54
55 struct {
56 union {
57 BitField<0, 1, u32> linear;
58 };
59 } exec;
60
61 u32 data;
62
63 INSERT_PADDING_WORDS(0x11);
64 };
65 std::array<u32, NUM_REGS> reg_array;
66 };
67 } regs{};
68
69 struct {
70 u32 write_offset = 0;
71 } state{};
72
73private:
74 MemoryManager& memory_manager;
75
76 void ProcessData(u32 data);
77};
78
79#define ASSERT_REG_POSITION(field_name, position) \
80 static_assert(offsetof(KeplerMemory::Regs, field_name) == position * 4, \
81 "Field " #field_name " has invalid position")
82
83ASSERT_REG_POSITION(line_length_in, 0x60);
84ASSERT_REG_POSITION(line_count, 0x61);
85ASSERT_REG_POSITION(dest, 0x62);
86ASSERT_REG_POSITION(exec, 0x6C);
87ASSERT_REG_POSITION(data, 0x6D);
88#undef ASSERT_REG_POSITION
89
90} // namespace Tegra::Engines
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 329079ddd..8afd26fe9 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -248,8 +248,8 @@ void Maxwell3D::DrawArrays() {
248 248
249void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) { 249void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
250 // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage. 250 // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage.
251 auto& shader = state.shader_stages[static_cast<size_t>(stage)]; 251 auto& shader = state.shader_stages[static_cast<std::size_t>(stage)];
252 auto& bind_data = regs.cb_bind[static_cast<size_t>(stage)]; 252 auto& bind_data = regs.cb_bind[static_cast<std::size_t>(stage)];
253 253
254 auto& buffer = shader.const_buffers[bind_data.index]; 254 auto& buffer = shader.const_buffers[bind_data.index];
255 255
@@ -316,14 +316,14 @@ Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const {
316std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderStage stage) const { 316std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderStage stage) const {
317 std::vector<Texture::FullTextureInfo> textures; 317 std::vector<Texture::FullTextureInfo> textures;
318 318
319 auto& fragment_shader = state.shader_stages[static_cast<size_t>(stage)]; 319 auto& fragment_shader = state.shader_stages[static_cast<std::size_t>(stage)];
320 auto& tex_info_buffer = fragment_shader.const_buffers[regs.tex_cb_index]; 320 auto& tex_info_buffer = fragment_shader.const_buffers[regs.tex_cb_index];
321 ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0); 321 ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0);
322 322
323 GPUVAddr tex_info_buffer_end = tex_info_buffer.address + tex_info_buffer.size; 323 GPUVAddr tex_info_buffer_end = tex_info_buffer.address + tex_info_buffer.size;
324 324
325 // Offset into the texture constbuffer where the texture info begins. 325 // Offset into the texture constbuffer where the texture info begins.
326 static constexpr size_t TextureInfoOffset = 0x20; 326 static constexpr std::size_t TextureInfoOffset = 0x20;
327 327
328 for (GPUVAddr current_texture = tex_info_buffer.address + TextureInfoOffset; 328 for (GPUVAddr current_texture = tex_info_buffer.address + TextureInfoOffset;
329 current_texture < tex_info_buffer_end; current_texture += sizeof(Texture::TextureHandle)) { 329 current_texture < tex_info_buffer_end; current_texture += sizeof(Texture::TextureHandle)) {
@@ -360,8 +360,9 @@ std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderSt
360 return textures; 360 return textures;
361} 361}
362 362
363Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage, size_t offset) const { 363Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage,
364 auto& shader = state.shader_stages[static_cast<size_t>(stage)]; 364 std::size_t offset) const {
365 auto& shader = state.shader_stages[static_cast<std::size_t>(stage)];
365 auto& tex_info_buffer = shader.const_buffers[regs.tex_cb_index]; 366 auto& tex_info_buffer = shader.const_buffers[regs.tex_cb_index];
366 ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0); 367 ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0);
367 368
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index d3be900a4..b81b0723d 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -34,17 +34,17 @@ public:
34 /// Register structure of the Maxwell3D engine. 34 /// Register structure of the Maxwell3D engine.
35 /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. 35 /// TODO(Subv): This structure will need to be made bigger as more registers are discovered.
36 struct Regs { 36 struct Regs {
37 static constexpr size_t NUM_REGS = 0xE00; 37 static constexpr std::size_t NUM_REGS = 0xE00;
38 38
39 static constexpr size_t NumRenderTargets = 8; 39 static constexpr std::size_t NumRenderTargets = 8;
40 static constexpr size_t NumViewports = 16; 40 static constexpr std::size_t NumViewports = 16;
41 static constexpr size_t NumCBData = 16; 41 static constexpr std::size_t NumCBData = 16;
42 static constexpr size_t NumVertexArrays = 32; 42 static constexpr std::size_t NumVertexArrays = 32;
43 static constexpr size_t NumVertexAttributes = 32; 43 static constexpr std::size_t NumVertexAttributes = 32;
44 static constexpr size_t MaxShaderProgram = 6; 44 static constexpr std::size_t MaxShaderProgram = 6;
45 static constexpr size_t MaxShaderStage = 5; 45 static constexpr std::size_t MaxShaderStage = 5;
46 // Maximum number of const buffers per shader stage. 46 // Maximum number of const buffers per shader stage.
47 static constexpr size_t MaxConstBuffers = 18; 47 static constexpr std::size_t MaxConstBuffers = 18;
48 48
49 enum class QueryMode : u32 { 49 enum class QueryMode : u32 {
50 Write = 0, 50 Write = 0,
@@ -443,9 +443,9 @@ public:
443 } 443 }
444 }; 444 };
445 445
446 bool IsShaderConfigEnabled(size_t index) const { 446 bool IsShaderConfigEnabled(std::size_t index) const {
447 // The VertexB is always enabled. 447 // The VertexB is always enabled.
448 if (index == static_cast<size_t>(Regs::ShaderProgram::VertexB)) { 448 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
449 return true; 449 return true;
450 } 450 }
451 return shader_config[index].enable != 0; 451 return shader_config[index].enable != 0;
@@ -571,7 +571,7 @@ public:
571 BitField<25, 3, u32> map_7; 571 BitField<25, 3, u32> map_7;
572 }; 572 };
573 573
574 u32 GetMap(size_t index) const { 574 u32 GetMap(std::size_t index) const {
575 const std::array<u32, NumRenderTargets> maps{map_0, map_1, map_2, map_3, 575 const std::array<u32, NumRenderTargets> maps{map_0, map_1, map_2, map_3,
576 map_4, map_5, map_6, map_7}; 576 map_4, map_5, map_6, map_7};
577 ASSERT(index < maps.size()); 577 ASSERT(index < maps.size());
@@ -925,7 +925,7 @@ public:
925 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; 925 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const;
926 926
927 /// Returns the texture information for a specific texture in a specific shader stage. 927 /// Returns the texture information for a specific texture in a specific shader stage.
928 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, size_t offset) const; 928 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
929 929
930private: 930private:
931 VideoCore::RasterizerInterface& rasterizer; 931 VideoCore::RasterizerInterface& rasterizer;
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index c24d33d5c..aa7481b8c 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -50,7 +50,7 @@ void MaxwellDMA::HandleCopy() {
50 ASSERT(regs.dst_params.pos_y == 0); 50 ASSERT(regs.dst_params.pos_y == 0);
51 51
52 if (regs.exec.is_dst_linear == regs.exec.is_src_linear) { 52 if (regs.exec.is_dst_linear == regs.exec.is_src_linear) {
53 size_t copy_size = regs.x_count; 53 std::size_t copy_size = regs.x_count;
54 54
55 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D 55 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
56 // buffer of length `x_count`, otherwise we copy a 2D buffer of size (x_count, y_count). 56 // buffer of length `x_count`, otherwise we copy a 2D buffer of size (x_count, y_count).
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 7882f16e0..311ccb616 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -23,7 +23,7 @@ public:
23 void WriteReg(u32 method, u32 value); 23 void WriteReg(u32 method, u32 value);
24 24
25 struct Regs { 25 struct Regs {
26 static constexpr size_t NUM_REGS = 0x1D6; 26 static constexpr std::size_t NUM_REGS = 0x1D6;
27 27
28 struct Parameters { 28 struct Parameters {
29 union { 29 union {
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 9176a8dbc..6e555ea03 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -20,10 +20,10 @@ namespace Tegra::Shader {
20 20
21struct Register { 21struct Register {
22 /// Number of registers 22 /// Number of registers
23 static constexpr size_t NumRegisters = 256; 23 static constexpr std::size_t NumRegisters = 256;
24 24
25 /// Register 255 is special cased to always be 0 25 /// Register 255 is special cased to always be 0
26 static constexpr size_t ZeroIndex = 255; 26 static constexpr std::size_t ZeroIndex = 255;
27 27
28 enum class Size : u64 { 28 enum class Size : u64 {
29 Byte = 0, 29 Byte = 0,
@@ -67,6 +67,13 @@ private:
67 u64 value{}; 67 u64 value{};
68}; 68};
69 69
70enum class AttributeSize : u64 {
71 Word = 0,
72 DoubleWord = 1,
73 TripleWord = 2,
74 QuadWord = 3,
75};
76
70union Attribute { 77union Attribute {
71 Attribute() = default; 78 Attribute() = default;
72 79
@@ -87,9 +94,10 @@ union Attribute {
87 }; 94 };
88 95
89 union { 96 union {
97 BitField<20, 10, u64> immediate;
90 BitField<22, 2, u64> element; 98 BitField<22, 2, u64> element;
91 BitField<24, 6, Index> index; 99 BitField<24, 6, Index> index;
92 BitField<47, 3, u64> size; 100 BitField<47, 3, AttributeSize> size;
93 } fmt20; 101 } fmt20;
94 102
95 union { 103 union {
@@ -254,6 +262,15 @@ enum class TextureQueryType : u64 {
254 BorderColor = 22, 262 BorderColor = 22,
255}; 263};
256 264
265enum class TextureProcessMode : u64 {
266 None = 0,
267 LZ = 1, // Unknown, appears to be the same as none.
268 LB = 2, // Load Bias.
269 LL = 3, // Load LOD (LevelOfDetail)
270 LBA = 6, // Load Bias. The A is unknown, does not appear to differ with LB
271 LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL
272};
273
257enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; 274enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 };
258enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; 275enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 };
259 276
@@ -424,6 +441,45 @@ union Instruction {
424 } bfe; 441 } bfe;
425 442
426 union { 443 union {
444 BitField<48, 3, u64> pred48;
445
446 union {
447 BitField<20, 20, u64> entry_a;
448 BitField<39, 5, u64> entry_b;
449 BitField<45, 1, u64> neg;
450 BitField<46, 1, u64> uses_cc;
451 } imm;
452
453 union {
454 BitField<20, 14, u64> cb_index;
455 BitField<34, 5, u64> cb_offset;
456 BitField<56, 1, u64> neg;
457 BitField<57, 1, u64> uses_cc;
458 } hi;
459
460 union {
461 BitField<20, 14, u64> cb_index;
462 BitField<34, 5, u64> cb_offset;
463 BitField<39, 5, u64> entry_a;
464 BitField<45, 1, u64> neg;
465 BitField<46, 1, u64> uses_cc;
466 } rz;
467
468 union {
469 BitField<39, 5, u64> entry_a;
470 BitField<45, 1, u64> neg;
471 BitField<46, 1, u64> uses_cc;
472 } r1;
473
474 union {
475 BitField<28, 8, u64> entry_a;
476 BitField<37, 1, u64> neg;
477 BitField<38, 1, u64> uses_cc;
478 } r2;
479
480 } lea;
481
482 union {
427 BitField<0, 5, FlowCondition> cond; 483 BitField<0, 5, FlowCondition> cond;
428 } flow; 484 } flow;
429 485
@@ -478,6 +534,18 @@ union Instruction {
478 } psetp; 534 } psetp;
479 535
480 union { 536 union {
537 BitField<12, 3, u64> pred12;
538 BitField<15, 1, u64> neg_pred12;
539 BitField<24, 2, PredOperation> cond;
540 BitField<29, 3, u64> pred29;
541 BitField<32, 1, u64> neg_pred29;
542 BitField<39, 3, u64> pred39;
543 BitField<42, 1, u64> neg_pred39;
544 BitField<44, 1, u64> bf;
545 BitField<45, 2, PredOperation> op;
546 } pset;
547
548 union {
481 BitField<39, 3, u64> pred39; 549 BitField<39, 3, u64> pred39;
482 BitField<42, 1, u64> neg_pred; 550 BitField<42, 1, u64> neg_pred;
483 BitField<43, 1, u64> neg_a; 551 BitField<43, 1, u64> neg_a;
@@ -522,8 +590,9 @@ union Instruction {
522 BitField<28, 1, u64> array; 590 BitField<28, 1, u64> array;
523 BitField<29, 2, TextureType> texture_type; 591 BitField<29, 2, TextureType> texture_type;
524 BitField<31, 4, u64> component_mask; 592 BitField<31, 4, u64> component_mask;
593 BitField<55, 3, TextureProcessMode> process_mode;
525 594
526 bool IsComponentEnabled(size_t component) const { 595 bool IsComponentEnabled(std::size_t component) const {
527 return ((1ull << component) & component_mask) != 0; 596 return ((1ull << component) & component_mask) != 0;
528 } 597 }
529 } tex; 598 } tex;
@@ -538,7 +607,7 @@ union Instruction {
538 BitField<29, 2, TextureType> texture_type; 607 BitField<29, 2, TextureType> texture_type;
539 BitField<31, 4, u64> component_mask; 608 BitField<31, 4, u64> component_mask;
540 609
541 bool IsComponentEnabled(size_t component) const { 610 bool IsComponentEnabled(std::size_t component) const {
542 return ((1ull << component) & component_mask) != 0; 611 return ((1ull << component) & component_mask) != 0;
543 } 612 }
544 } tmml; 613 } tmml;
@@ -585,7 +654,7 @@ union Instruction {
585 return gpr28.Value() != Register::ZeroIndex; 654 return gpr28.Value() != Register::ZeroIndex;
586 } 655 }
587 656
588 bool IsComponentEnabled(size_t component) const { 657 bool IsComponentEnabled(std::size_t component) const {
589 static constexpr std::array<std::array<u32, 8>, 4> mask_lut{{ 658 static constexpr std::array<std::array<u32, 8>, 4> mask_lut{{
590 {}, 659 {},
591 {0x1, 0x2, 0x4, 0x8, 0x3, 0x9, 0xa, 0xc}, 660 {0x1, 0x2, 0x4, 0x8, 0x3, 0x9, 0xa, 0xc},
@@ -593,7 +662,7 @@ union Instruction {
593 {0x7, 0xb, 0xd, 0xe, 0xf}, 662 {0x7, 0xb, 0xd, 0xe, 0xf},
594 }}; 663 }};
595 664
596 size_t index{gpr0.Value() != Register::ZeroIndex ? 1U : 0U}; 665 std::size_t index{gpr0.Value() != Register::ZeroIndex ? 1U : 0U};
597 index |= gpr28.Value() != Register::ZeroIndex ? 2 : 0; 666 index |= gpr28.Value() != Register::ZeroIndex ? 2 : 0;
598 667
599 u32 mask = mask_lut[index][component_mask_selector]; 668 u32 mask = mask_lut[index][component_mask_selector];
@@ -726,6 +795,11 @@ public:
726 ISCADD_C, // Scale and Add 795 ISCADD_C, // Scale and Add
727 ISCADD_R, 796 ISCADD_R,
728 ISCADD_IMM, 797 ISCADD_IMM,
798 LEA_R1,
799 LEA_R2,
800 LEA_RZ,
801 LEA_IMM,
802 LEA_HI,
729 POPC_C, 803 POPC_C,
730 POPC_R, 804 POPC_R,
731 POPC_IMM, 805 POPC_IMM,
@@ -784,6 +858,7 @@ public:
784 ISET_C, 858 ISET_C,
785 ISET_IMM, 859 ISET_IMM,
786 PSETP, 860 PSETP,
861 PSET,
787 XMAD_IMM, 862 XMAD_IMM,
788 XMAD_CR, 863 XMAD_CR,
789 XMAD_RC, 864 XMAD_RC,
@@ -807,6 +882,7 @@ public:
807 IntegerSet, 882 IntegerSet,
808 IntegerSetPredicate, 883 IntegerSetPredicate,
809 PredicateSetPredicate, 884 PredicateSetPredicate,
885 PredicateSetRegister,
810 Conversion, 886 Conversion,
811 Xmad, 887 Xmad,
812 Unknown, 888 Unknown,
@@ -871,7 +947,7 @@ public:
871private: 947private:
872 struct Detail { 948 struct Detail {
873 private: 949 private:
874 static constexpr size_t opcode_bitsize = 16; 950 static constexpr std::size_t opcode_bitsize = 16;
875 951
876 /** 952 /**
877 * Generates the mask and the expected value after masking from a given bitstring. 953 * Generates the mask and the expected value after masking from a given bitstring.
@@ -880,8 +956,8 @@ private:
880 */ 956 */
881 static auto GetMaskAndExpect(const char* const bitstring) { 957 static auto GetMaskAndExpect(const char* const bitstring) {
882 u16 mask = 0, expect = 0; 958 u16 mask = 0, expect = 0;
883 for (size_t i = 0; i < opcode_bitsize; i++) { 959 for (std::size_t i = 0; i < opcode_bitsize; i++) {
884 const size_t bit_position = opcode_bitsize - i - 1; 960 const std::size_t bit_position = opcode_bitsize - i - 1;
885 switch (bitstring[i]) { 961 switch (bitstring[i]) {
886 case '0': 962 case '0':
887 mask |= 1 << bit_position; 963 mask |= 1 << bit_position;
@@ -958,6 +1034,11 @@ private:
958 INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"), 1034 INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"),
959 INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"), 1035 INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"),
960 INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"), 1036 INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"),
1037 INST("0101101111011---", Id::LEA_R2, Type::ArithmeticInteger, "LEA_R2"),
1038 INST("0101101111010---", Id::LEA_R1, Type::ArithmeticInteger, "LEA_R1"),
1039 INST("001101101101----", Id::LEA_IMM, Type::ArithmeticInteger, "LEA_IMM"),
1040 INST("010010111101----", Id::LEA_RZ, Type::ArithmeticInteger, "LEA_RZ"),
1041 INST("00011000--------", Id::LEA_HI, Type::ArithmeticInteger, "LEA_HI"),
961 INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"), 1042 INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
962 INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"), 1043 INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"),
963 INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"), 1044 INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"),
@@ -1012,6 +1093,7 @@ private:
1012 INST("010110110101----", Id::ISET_R, Type::IntegerSet, "ISET_R"), 1093 INST("010110110101----", Id::ISET_R, Type::IntegerSet, "ISET_R"),
1013 INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"), 1094 INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"),
1014 INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), 1095 INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
1096 INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
1015 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), 1097 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
1016 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), 1098 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
1017 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), 1099 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 86a809f86..baa8b63b7 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "video_core/engines/fermi_2d.h" 6#include "video_core/engines/fermi_2d.h"
7#include "video_core/engines/kepler_memory.h"
7#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
8#include "video_core/engines/maxwell_compute.h" 9#include "video_core/engines/maxwell_compute.h"
9#include "video_core/engines/maxwell_dma.h" 10#include "video_core/engines/maxwell_dma.h"
@@ -27,6 +28,7 @@ GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
27 fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager); 28 fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager);
28 maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); 29 maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
29 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(*memory_manager); 30 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(*memory_manager);
31 kepler_memory = std::make_unique<Engines::KeplerMemory>(*memory_manager);
30} 32}
31 33
32GPU::~GPU() = default; 34GPU::~GPU() = default;
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 589a59b4f..5cc1e19ca 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -42,6 +42,7 @@ enum class RenderTargetFormat : u32 {
42 R32_UINT = 0xE4, 42 R32_UINT = 0xE4,
43 R32_FLOAT = 0xE5, 43 R32_FLOAT = 0xE5,
44 B5G6R5_UNORM = 0xE8, 44 B5G6R5_UNORM = 0xE8,
45 BGR5A1_UNORM = 0xE9,
45 RG8_UNORM = 0xEA, 46 RG8_UNORM = 0xEA,
46 RG8_SNORM = 0xEB, 47 RG8_SNORM = 0xEB,
47 R16_UNORM = 0xEE, 48 R16_UNORM = 0xEE,
@@ -102,6 +103,7 @@ class Fermi2D;
102class Maxwell3D; 103class Maxwell3D;
103class MaxwellCompute; 104class MaxwellCompute;
104class MaxwellDMA; 105class MaxwellDMA;
106class KeplerMemory;
105} // namespace Engines 107} // namespace Engines
106 108
107enum class EngineID { 109enum class EngineID {
@@ -146,6 +148,8 @@ private:
146 std::unique_ptr<Engines::MaxwellCompute> maxwell_compute; 148 std::unique_ptr<Engines::MaxwellCompute> maxwell_compute;
147 /// DMA engine 149 /// DMA engine
148 std::unique_ptr<Engines::MaxwellDMA> maxwell_dma; 150 std::unique_ptr<Engines::MaxwellDMA> maxwell_dma;
151 /// Inline memory engine
152 std::unique_ptr<Engines::KeplerMemory> kepler_memory;
149}; 153};
150 154
151} // namespace Tegra 155} // namespace Tegra
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index 7d836b816..cee0baaf3 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -152,7 +152,7 @@ private:
152 boost::optional<u32> 152 boost::optional<u32>
153 delayed_pc; ///< Program counter to execute at after the delay slot is executed. 153 delayed_pc; ///< Program counter to execute at after the delay slot is executed.
154 154
155 static constexpr size_t NumMacroRegisters = 8; 155 static constexpr std::size_t NumMacroRegisters = 8;
156 156
157 /// General purpose macro registers. 157 /// General purpose macro registers.
158 std::array<u32, NumMacroRegisters> registers = {}; 158 std::array<u32, NumMacroRegisters> registers = {};
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index be17a2b9c..0df3725c2 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -19,6 +19,7 @@ void RendererBase::RefreshBaseSettings() {
19 UpdateCurrentFramebufferLayout(); 19 UpdateCurrentFramebufferLayout();
20 20
21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit; 21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit;
22 renderer_settings.set_background_color = true;
22} 23}
23 24
24void RendererBase::UpdateCurrentFramebufferLayout() { 25void RendererBase::UpdateCurrentFramebufferLayout() {
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 2a357f9d0..2cd0738ff 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -19,6 +19,7 @@ namespace VideoCore {
19 19
20struct RendererSettings { 20struct RendererSettings {
21 std::atomic_bool use_framelimiter{false}; 21 std::atomic_bool use_framelimiter{false};
22 std::atomic_bool set_background_color{false};
22}; 23};
23 24
24class RendererBase : NonCopyable { 25class RendererBase : NonCopyable {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index 0b5d18bcb..578aca789 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -12,10 +12,10 @@
12 12
13namespace OpenGL { 13namespace OpenGL {
14 14
15OGLBufferCache::OGLBufferCache(size_t size) : stream_buffer(GL_ARRAY_BUFFER, size) {} 15OGLBufferCache::OGLBufferCache(std::size_t size) : stream_buffer(GL_ARRAY_BUFFER, size) {}
16 16
17GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, size_t size, size_t alignment, 17GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size,
18 bool cache) { 18 std::size_t alignment, bool cache) {
19 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager(); 19 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
20 const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; 20 const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
21 21
@@ -53,7 +53,8 @@ GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, size_t size, siz
53 return uploaded_offset; 53 return uploaded_offset;
54} 54}
55 55
56GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, size_t size, size_t alignment) { 56GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, std::size_t size,
57 std::size_t alignment) {
57 AlignBuffer(alignment); 58 AlignBuffer(alignment);
58 std::memcpy(buffer_ptr, raw_pointer, size); 59 std::memcpy(buffer_ptr, raw_pointer, size);
59 GLintptr uploaded_offset = buffer_offset; 60 GLintptr uploaded_offset = buffer_offset;
@@ -63,7 +64,7 @@ GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, size_t size,
63 return uploaded_offset; 64 return uploaded_offset;
64} 65}
65 66
66void OGLBufferCache::Map(size_t max_size) { 67void OGLBufferCache::Map(std::size_t max_size) {
67 bool invalidate; 68 bool invalidate;
68 std::tie(buffer_ptr, buffer_offset_base, invalidate) = 69 std::tie(buffer_ptr, buffer_offset_base, invalidate) =
69 stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); 70 stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4);
@@ -81,10 +82,10 @@ GLuint OGLBufferCache::GetHandle() const {
81 return stream_buffer.GetHandle(); 82 return stream_buffer.GetHandle();
82} 83}
83 84
84void OGLBufferCache::AlignBuffer(size_t alignment) { 85void OGLBufferCache::AlignBuffer(std::size_t alignment) {
85 // Align the offset, not the mapped pointer 86 // Align the offset, not the mapped pointer
86 GLintptr offset_aligned = 87 GLintptr offset_aligned =
87 static_cast<GLintptr>(Common::AlignUp(static_cast<size_t>(buffer_offset), alignment)); 88 static_cast<GLintptr>(Common::AlignUp(static_cast<std::size_t>(buffer_offset), alignment));
88 buffer_ptr += offset_aligned - buffer_offset; 89 buffer_ptr += offset_aligned - buffer_offset;
89 buffer_offset = offset_aligned; 90 buffer_offset = offset_aligned;
90} 91}
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 6da862902..6c18461f4 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -19,32 +19,32 @@ struct CachedBufferEntry final {
19 return addr; 19 return addr;
20 } 20 }
21 21
22 size_t GetSizeInBytes() const { 22 std::size_t GetSizeInBytes() const {
23 return size; 23 return size;
24 } 24 }
25 25
26 VAddr addr; 26 VAddr addr;
27 size_t size; 27 std::size_t size;
28 GLintptr offset; 28 GLintptr offset;
29 size_t alignment; 29 std::size_t alignment;
30}; 30};
31 31
32class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { 32class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
33public: 33public:
34 explicit OGLBufferCache(size_t size); 34 explicit OGLBufferCache(std::size_t size);
35 35
36 GLintptr UploadMemory(Tegra::GPUVAddr gpu_addr, size_t size, size_t alignment = 4, 36 GLintptr UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4,
37 bool cache = true); 37 bool cache = true);
38 38
39 GLintptr UploadHostMemory(const void* raw_pointer, size_t size, size_t alignment = 4); 39 GLintptr UploadHostMemory(const void* raw_pointer, std::size_t size, std::size_t alignment = 4);
40 40
41 void Map(size_t max_size); 41 void Map(std::size_t max_size);
42 void Unmap(); 42 void Unmap();
43 43
44 GLuint GetHandle() const; 44 GLuint GetHandle() const;
45 45
46protected: 46protected:
47 void AlignBuffer(size_t alignment); 47 void AlignBuffer(std::size_t alignment);
48 48
49private: 49private:
50 OGLStreamBuffer stream_buffer; 50 OGLStreamBuffer stream_buffer;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index c59f3af1b..274c2dbcf 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array>
6#include <memory> 7#include <memory>
7#include <string> 8#include <string>
8#include <string_view> 9#include <string_view>
@@ -45,7 +46,7 @@ MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100,
45RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) 46RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info)
46 : emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) { 47 : emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) {
47 // Create sampler objects 48 // Create sampler objects
48 for (size_t i = 0; i < texture_samplers.size(); ++i) { 49 for (std::size_t i = 0; i < texture_samplers.size(); ++i) {
49 texture_samplers[i].Create(); 50 texture_samplers[i].Create();
50 state.texture_units[i].sampler = texture_samplers[i].sampler.handle; 51 state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
51 } 52 }
@@ -58,6 +59,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
58 59
59 if (extension == "GL_ARB_direct_state_access") { 60 if (extension == "GL_ARB_direct_state_access") {
60 has_ARB_direct_state_access = true; 61 has_ARB_direct_state_access = true;
62 } else if (extension == "GL_ARB_multi_bind") {
63 has_ARB_multi_bind = true;
61 } else if (extension == "GL_ARB_separate_shader_objects") { 64 } else if (extension == "GL_ARB_separate_shader_objects") {
62 has_ARB_separate_shader_objects = true; 65 has_ARB_separate_shader_objects = true;
63 } else if (extension == "GL_ARB_vertex_attrib_binding") { 66 } else if (extension == "GL_ARB_vertex_attrib_binding") {
@@ -178,7 +181,7 @@ void RasterizerOpenGL::SetupShaders() {
178 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 181 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
179 u32 current_texture_bindpoint = 0; 182 u32 current_texture_bindpoint = 0;
180 183
181 for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 184 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
182 const auto& shader_config = gpu.regs.shader_config[index]; 185 const auto& shader_config = gpu.regs.shader_config[index];
183 const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)}; 186 const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
184 187
@@ -187,12 +190,12 @@ void RasterizerOpenGL::SetupShaders() {
187 continue; 190 continue;
188 } 191 }
189 192
190 const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5 193 const std::size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
191 194
192 GLShader::MaxwellUniformData ubo{}; 195 GLShader::MaxwellUniformData ubo{};
193 ubo.SetFromRegs(gpu.state.shader_stages[stage]); 196 ubo.SetFromRegs(gpu.state.shader_stages[stage]);
194 const GLintptr offset = buffer_cache.UploadHostMemory( 197 const GLintptr offset = buffer_cache.UploadHostMemory(
195 &ubo, sizeof(ubo), static_cast<size_t>(uniform_buffer_alignment)); 198 &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
196 199
197 // Bind the buffer 200 // Bind the buffer
198 glBindBufferRange(GL_UNIFORM_BUFFER, stage, buffer_cache.GetHandle(), offset, sizeof(ubo)); 201 glBindBufferRange(GL_UNIFORM_BUFFER, stage, buffer_cache.GetHandle(), offset, sizeof(ubo));
@@ -235,10 +238,10 @@ void RasterizerOpenGL::SetupShaders() {
235 shader_program_manager->UseTrivialGeometryShader(); 238 shader_program_manager->UseTrivialGeometryShader();
236} 239}
237 240
238size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 241std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
239 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 242 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
240 243
241 size_t size = 0; 244 std::size_t size = 0;
242 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 245 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
243 if (!regs.vertex_array[index].IsEnabled()) 246 if (!regs.vertex_array[index].IsEnabled())
244 continue; 247 continue;
@@ -296,7 +299,7 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
296 299
297void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, 300void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
298 bool preserve_contents, 301 bool preserve_contents,
299 boost::optional<size_t> single_color_target) { 302 boost::optional<std::size_t> single_color_target) {
300 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 303 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
301 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 304 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
302 305
@@ -327,7 +330,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
327 } else { 330 } else {
328 // Multiple color attachments are enabled 331 // Multiple color attachments are enabled
329 std::array<GLenum, Maxwell::NumRenderTargets> buffers; 332 std::array<GLenum, Maxwell::NumRenderTargets> buffers;
330 for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { 333 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
331 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); 334 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
332 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); 335 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
333 glFramebufferTexture2D( 336 glFramebufferTexture2D(
@@ -339,7 +342,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
339 } 342 }
340 } else { 343 } else {
341 // No color attachments are enabled - zero out all of them 344 // No color attachments are enabled - zero out all of them
342 for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { 345 for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
343 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, 346 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
344 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, 347 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D,
345 0, 0); 348 0, 0);
@@ -459,15 +462,15 @@ void RasterizerOpenGL::DrawArrays() {
459 state.draw.vertex_buffer = buffer_cache.GetHandle(); 462 state.draw.vertex_buffer = buffer_cache.GetHandle();
460 state.Apply(); 463 state.Apply();
461 464
462 size_t buffer_size = CalculateVertexArraysSize(); 465 std::size_t buffer_size = CalculateVertexArraysSize();
463 466
464 if (is_indexed) { 467 if (is_indexed) {
465 buffer_size = Common::AlignUp<size_t>(buffer_size, 4) + index_buffer_size; 468 buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + index_buffer_size;
466 } 469 }
467 470
468 // Uniform space for the 5 shader stages 471 // Uniform space for the 5 shader stages
469 buffer_size = 472 buffer_size =
470 Common::AlignUp<size_t>(buffer_size, 4) + 473 Common::AlignUp<std::size_t>(buffer_size, 4) +
471 (sizeof(GLShader::MaxwellUniformData) + uniform_buffer_alignment) * Maxwell::MaxShaderStage; 474 (sizeof(GLShader::MaxwellUniformData) + uniform_buffer_alignment) * Maxwell::MaxShaderStage;
472 475
473 // Add space for at least 18 constant buffers 476 // Add space for at least 18 constant buffers
@@ -641,19 +644,30 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
641 MICROPROFILE_SCOPE(OpenGL_UBO); 644 MICROPROFILE_SCOPE(OpenGL_UBO);
642 const auto& gpu = Core::System::GetInstance().GPU(); 645 const auto& gpu = Core::System::GetInstance().GPU();
643 const auto& maxwell3d = gpu.Maxwell3D(); 646 const auto& maxwell3d = gpu.Maxwell3D();
644 const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)]; 647 const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<std::size_t>(stage)];
645 const auto& entries = shader->GetShaderEntries().const_buffer_entries; 648 const auto& entries = shader->GetShaderEntries().const_buffer_entries;
646 649
650 constexpr u64 max_binds = Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers;
651 std::array<GLuint, max_binds> bind_buffers;
652 std::array<GLintptr, max_binds> bind_offsets;
653 std::array<GLsizeiptr, max_binds> bind_sizes;
654
655 ASSERT_MSG(entries.size() <= max_binds, "Exceeded expected number of binding points.");
656
647 // Upload only the enabled buffers from the 16 constbuffers of each shader stage 657 // Upload only the enabled buffers from the 16 constbuffers of each shader stage
648 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 658 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
649 const auto& used_buffer = entries[bindpoint]; 659 const auto& used_buffer = entries[bindpoint];
650 const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()]; 660 const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()];
651 661
652 if (!buffer.enabled) { 662 if (!buffer.enabled) {
663 // With disabled buffers set values as zero to unbind them
664 bind_buffers[bindpoint] = 0;
665 bind_offsets[bindpoint] = 0;
666 bind_sizes[bindpoint] = 0;
653 continue; 667 continue;
654 } 668 }
655 669
656 size_t size = 0; 670 std::size_t size = 0;
657 671
658 if (used_buffer.IsIndirect()) { 672 if (used_buffer.IsIndirect()) {
659 // Buffer is accessed indirectly, so upload the entire thing 673 // Buffer is accessed indirectly, so upload the entire thing
@@ -675,17 +689,22 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
675 ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); 689 ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
676 690
677 GLintptr const_buffer_offset = buffer_cache.UploadMemory( 691 GLintptr const_buffer_offset = buffer_cache.UploadMemory(
678 buffer.address, size, static_cast<size_t>(uniform_buffer_alignment)); 692 buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
679
680 glBindBufferRange(GL_UNIFORM_BUFFER, current_bindpoint + bindpoint,
681 buffer_cache.GetHandle(), const_buffer_offset, size);
682 693
683 // Now configure the bindpoint of the buffer inside the shader 694 // Now configure the bindpoint of the buffer inside the shader
684 glUniformBlockBinding(shader->GetProgramHandle(), 695 glUniformBlockBinding(shader->GetProgramHandle(),
685 shader->GetProgramResourceIndex(used_buffer), 696 shader->GetProgramResourceIndex(used_buffer),
686 current_bindpoint + bindpoint); 697 current_bindpoint + bindpoint);
698
699 // Prepare values for multibind
700 bind_buffers[bindpoint] = buffer_cache.GetHandle();
701 bind_offsets[bindpoint] = const_buffer_offset;
702 bind_sizes[bindpoint] = size;
687 } 703 }
688 704
705 glBindBuffersRange(GL_UNIFORM_BUFFER, current_bindpoint, static_cast<GLsizei>(entries.size()),
706 bind_buffers.data(), bind_offsets.data(), bind_sizes.data());
707
689 return current_bindpoint + static_cast<u32>(entries.size()); 708 return current_bindpoint + static_cast<u32>(entries.size());
690} 709}
691 710
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 745c3dc0c..bf9560bdc 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -73,7 +73,7 @@ public:
73 }; 73 };
74 74
75 /// Maximum supported size that a constbuffer can have in bytes. 75 /// Maximum supported size that a constbuffer can have in bytes.
76 static constexpr size_t MaxConstbufferSize = 0x10000; 76 static constexpr std::size_t MaxConstbufferSize = 0x10000;
77 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, 77 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0,
78 "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); 78 "The maximum size of a constbuffer must be a multiple of the size of GLvec4");
79 79
@@ -106,7 +106,7 @@ private:
106 */ 106 */
107 void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, 107 void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true,
108 bool preserve_contents = true, 108 bool preserve_contents = true,
109 boost::optional<size_t> single_color_target = {}); 109 boost::optional<std::size_t> single_color_target = {});
110 110
111 /* 111 /*
112 * Configures the current constbuffers to use for the draw command. 112 * Configures the current constbuffers to use for the draw command.
@@ -159,6 +159,7 @@ private:
159 void SyncLogicOpState(); 159 void SyncLogicOpState();
160 160
161 bool has_ARB_direct_state_access = false; 161 bool has_ARB_direct_state_access = false;
162 bool has_ARB_multi_bind = false;
162 bool has_ARB_separate_shader_objects = false; 163 bool has_ARB_separate_shader_objects = false;
163 bool has_ARB_vertex_attrib_binding = false; 164 bool has_ARB_vertex_attrib_binding = false;
164 165
@@ -179,12 +180,12 @@ private:
179 180
180 std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers; 181 std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
181 182
182 static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 183 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
183 OGLBufferCache buffer_cache; 184 OGLBufferCache buffer_cache;
184 OGLFramebuffer framebuffer; 185 OGLFramebuffer framebuffer;
185 GLint uniform_buffer_alignment; 186 GLint uniform_buffer_alignment;
186 187
187 size_t CalculateVertexArraysSize() const; 188 std::size_t CalculateVertexArraysSize() const;
188 189
189 void SetupVertexArrays(); 190 void SetupVertexArrays();
190 191
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 29d61eccd..86682d7cb 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -53,8 +53,6 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
53 params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); 53 params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
54 params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); 54 params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
55 params.unaligned_height = config.tic.Height(); 55 params.unaligned_height = config.tic.Height();
56 params.cache_width = Common::AlignUp(params.width, 8);
57 params.cache_height = Common::AlignUp(params.height, 8);
58 params.target = SurfaceTargetFromTextureType(config.tic.texture_type); 56 params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
59 57
60 switch (params.target) { 58 switch (params.target) {
@@ -77,7 +75,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
77 return params; 75 return params;
78} 76}
79 77
80/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(size_t index) { 78/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(std::size_t index) {
81 const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]}; 79 const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]};
82 SurfaceParams params{}; 80 SurfaceParams params{};
83 params.addr = TryGetCpuAddr(config.Address()); 81 params.addr = TryGetCpuAddr(config.Address());
@@ -89,8 +87,6 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
89 params.width = config.width; 87 params.width = config.width;
90 params.height = config.height; 88 params.height = config.height;
91 params.unaligned_height = config.height; 89 params.unaligned_height = config.height;
92 params.cache_width = Common::AlignUp(params.width, 8);
93 params.cache_height = Common::AlignUp(params.height, 8);
94 params.target = SurfaceTarget::Texture2D; 90 params.target = SurfaceTarget::Texture2D;
95 params.depth = 1; 91 params.depth = 1;
96 params.size_in_bytes = params.SizeInBytes(); 92 params.size_in_bytes = params.SizeInBytes();
@@ -110,8 +106,6 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
110 params.width = zeta_width; 106 params.width = zeta_width;
111 params.height = zeta_height; 107 params.height = zeta_height;
112 params.unaligned_height = zeta_height; 108 params.unaligned_height = zeta_height;
113 params.cache_width = Common::AlignUp(params.width, 8);
114 params.cache_height = Common::AlignUp(params.height, 8);
115 params.target = SurfaceTarget::Texture2D; 109 params.target = SurfaceTarget::Texture2D;
116 params.depth = 1; 110 params.depth = 1;
117 params.size_in_bytes = params.SizeInBytes(); 111 params.size_in_bytes = params.SizeInBytes();
@@ -122,7 +116,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
122 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U 116 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
123 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S 117 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
124 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI 118 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
125 {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U 119 {GL_RGB8, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U
126 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, 120 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm,
127 false}, // A2B10G10R10U 121 false}, // A2B10G10R10U
128 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U 122 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U
@@ -173,6 +167,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
173 {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S 167 {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
174 {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI 168 {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI
175 {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI 169 {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI
170 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8
176 171
177 // Depth formats 172 // Depth formats
178 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F 173 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
@@ -209,7 +204,7 @@ static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) {
209} 204}
210 205
211static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { 206static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
212 ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); 207 ASSERT(static_cast<std::size_t>(pixel_format) < tex_format_tuples.size());
213 auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)]; 208 auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)];
214 ASSERT(component_type == format.component_type); 209 ASSERT(component_type == format.component_type);
215 210
@@ -219,6 +214,7 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType
219static bool IsPixelFormatASTC(PixelFormat format) { 214static bool IsPixelFormatASTC(PixelFormat format) {
220 switch (format) { 215 switch (format) {
221 case PixelFormat::ASTC_2D_4X4: 216 case PixelFormat::ASTC_2D_4X4:
217 case PixelFormat::ASTC_2D_8X8:
222 return true; 218 return true;
223 default: 219 default:
224 return false; 220 return false;
@@ -229,6 +225,8 @@ static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
229 switch (format) { 225 switch (format) {
230 case PixelFormat::ASTC_2D_4X4: 226 case PixelFormat::ASTC_2D_4X4:
231 return {4, 4}; 227 return {4, 4};
228 case PixelFormat::ASTC_2D_8X8:
229 return {8, 8};
232 default: 230 default:
233 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format)); 231 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
234 UNREACHABLE(); 232 UNREACHABLE();
@@ -262,7 +260,7 @@ static bool IsFormatBCn(PixelFormat format) {
262} 260}
263 261
264template <bool morton_to_gl, PixelFormat format> 262template <bool morton_to_gl, PixelFormat format>
265void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t gl_buffer_size, 263void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, std::size_t gl_buffer_size,
266 VAddr addr) { 264 VAddr addr) {
267 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; 265 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
268 constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); 266 constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
@@ -273,7 +271,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t
273 const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; 271 const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
274 const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( 272 const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
275 addr, tile_size, bytes_per_pixel, stride, height, block_height); 273 addr, tile_size, bytes_per_pixel, stride, height, block_height);
276 const size_t size_to_copy{std::min(gl_buffer_size, data.size())}; 274 const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())};
277 memcpy(gl_buffer, data.data(), size_to_copy); 275 memcpy(gl_buffer, data.data(), size_to_copy);
278 } else { 276 } else {
279 // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should 277 // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should
@@ -284,7 +282,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t
284 } 282 }
285} 283}
286 284
287static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), 285static constexpr std::array<void (*)(u32, u32, u32, u8*, std::size_t, VAddr),
288 SurfaceParams::MaxPixelFormat> 286 SurfaceParams::MaxPixelFormat>
289 morton_to_gl_fns = { 287 morton_to_gl_fns = {
290 // clang-format off 288 // clang-format off
@@ -333,6 +331,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
333 MortonCopy<true, PixelFormat::RG8S>, 331 MortonCopy<true, PixelFormat::RG8S>,
334 MortonCopy<true, PixelFormat::RG32UI>, 332 MortonCopy<true, PixelFormat::RG32UI>,
335 MortonCopy<true, PixelFormat::R32UI>, 333 MortonCopy<true, PixelFormat::R32UI>,
334 MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
336 MortonCopy<true, PixelFormat::Z32F>, 335 MortonCopy<true, PixelFormat::Z32F>,
337 MortonCopy<true, PixelFormat::Z16>, 336 MortonCopy<true, PixelFormat::Z16>,
338 MortonCopy<true, PixelFormat::Z24S8>, 337 MortonCopy<true, PixelFormat::Z24S8>,
@@ -341,7 +340,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
341 // clang-format on 340 // clang-format on
342}; 341};
343 342
344static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), 343static constexpr std::array<void (*)(u32, u32, u32, u8*, std::size_t, VAddr),
345 SurfaceParams::MaxPixelFormat> 344 SurfaceParams::MaxPixelFormat>
346 gl_to_morton_fns = { 345 gl_to_morton_fns = {
347 // clang-format off 346 // clang-format off
@@ -392,6 +391,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
392 MortonCopy<false, PixelFormat::RG8S>, 391 MortonCopy<false, PixelFormat::RG8S>,
393 MortonCopy<false, PixelFormat::RG32UI>, 392 MortonCopy<false, PixelFormat::RG32UI>,
394 MortonCopy<false, PixelFormat::R32UI>, 393 MortonCopy<false, PixelFormat::R32UI>,
394 nullptr,
395 MortonCopy<false, PixelFormat::Z32F>, 395 MortonCopy<false, PixelFormat::Z32F>,
396 MortonCopy<false, PixelFormat::Z16>, 396 MortonCopy<false, PixelFormat::Z16>,
397 MortonCopy<false, PixelFormat::Z24S8>, 397 MortonCopy<false, PixelFormat::Z24S8>,
@@ -477,30 +477,27 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
477 // Only pre-create the texture for non-compressed textures. 477 // Only pre-create the texture for non-compressed textures.
478 switch (params.target) { 478 switch (params.target) {
479 case SurfaceParams::SurfaceTarget::Texture1D: 479 case SurfaceParams::SurfaceTarget::Texture1D:
480 glTexImage1D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, 480 glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
481 rect.GetWidth(), 0, format_tuple.format, format_tuple.type, nullptr); 481 rect.GetWidth());
482 break; 482 break;
483 case SurfaceParams::SurfaceTarget::Texture2D: 483 case SurfaceParams::SurfaceTarget::Texture2D:
484 glTexImage2D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, 484 glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
485 rect.GetWidth(), rect.GetHeight(), 0, format_tuple.format, 485 rect.GetWidth(), rect.GetHeight());
486 format_tuple.type, nullptr);
487 break; 486 break;
488 case SurfaceParams::SurfaceTarget::Texture3D: 487 case SurfaceParams::SurfaceTarget::Texture3D:
489 case SurfaceParams::SurfaceTarget::Texture2DArray: 488 case SurfaceParams::SurfaceTarget::Texture2DArray:
490 glTexImage3D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, 489 glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
491 rect.GetWidth(), rect.GetHeight(), params.depth, 0, format_tuple.format, 490 rect.GetWidth(), rect.GetHeight(), params.depth);
492 format_tuple.type, nullptr);
493 break; 491 break;
494 default: 492 default:
495 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 493 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
496 static_cast<u32>(params.target)); 494 static_cast<u32>(params.target));
497 UNREACHABLE(); 495 UNREACHABLE();
498 glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, rect.GetWidth(), 496 glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(),
499 rect.GetHeight(), 0, format_tuple.format, format_tuple.type, nullptr); 497 rect.GetHeight());
500 } 498 }
501 } 499 }
502 500
503 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, 0);
504 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); 501 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
505 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 502 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
506 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 503 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@@ -522,9 +519,9 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
522 S8Z24 input_pixel{}; 519 S8Z24 input_pixel{};
523 Z24S8 output_pixel{}; 520 Z24S8 output_pixel{};
524 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)}; 521 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)};
525 for (size_t y = 0; y < height; ++y) { 522 for (std::size_t y = 0; y < height; ++y) {
526 for (size_t x = 0; x < width; ++x) { 523 for (std::size_t x = 0; x < width; ++x) {
527 const size_t offset{bpp * (y * width + x)}; 524 const std::size_t offset{bpp * (y * width + x)};
528 std::memcpy(&input_pixel, &data[offset], sizeof(S8Z24)); 525 std::memcpy(&input_pixel, &data[offset], sizeof(S8Z24));
529 output_pixel.s8.Assign(input_pixel.s8); 526 output_pixel.s8.Assign(input_pixel.s8);
530 output_pixel.z24.Assign(input_pixel.z24); 527 output_pixel.z24.Assign(input_pixel.z24);
@@ -535,9 +532,9 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
535 532
536static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { 533static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
537 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)}; 534 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)};
538 for (size_t y = 0; y < height; ++y) { 535 for (std::size_t y = 0; y < height; ++y) {
539 for (size_t x = 0; x < width; ++x) { 536 for (std::size_t x = 0; x < width; ++x) {
540 const size_t offset{bpp * (y * width + x)}; 537 const std::size_t offset{bpp * (y * width + x)};
541 const u8 temp{data[offset]}; 538 const u8 temp{data[offset]};
542 data[offset] = data[offset + 1]; 539 data[offset] = data[offset + 1];
543 data[offset + 1] = temp; 540 data[offset + 1] = temp;
@@ -553,7 +550,8 @@ static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
553static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format, 550static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
554 u32 width, u32 height) { 551 u32 width, u32 height) {
555 switch (pixel_format) { 552 switch (pixel_format) {
556 case PixelFormat::ASTC_2D_4X4: { 553 case PixelFormat::ASTC_2D_4X4:
554 case PixelFormat::ASTC_2D_8X8: {
557 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. 555 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
558 u32 block_width{}; 556 u32 block_width{};
559 u32 block_height{}; 557 u32 block_height{};
@@ -600,13 +598,13 @@ void CachedSurface::LoadGLBuffer() {
600 UNREACHABLE(); 598 UNREACHABLE();
601 } 599 }
602 600
603 gl_buffer.resize(static_cast<size_t>(params.depth) * copy_size); 601 gl_buffer.resize(static_cast<std::size_t>(params.depth) * copy_size);
604 morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( 602 morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)](
605 params.width, params.block_height, params.height, gl_buffer.data(), copy_size, 603 params.width, params.block_height, params.height, gl_buffer.data(), copy_size,
606 params.addr); 604 params.addr);
607 } else { 605 } else {
608 const u8* const texture_src_data_end{texture_src_data + 606 const u8* const texture_src_data_end{texture_src_data +
609 (static_cast<size_t>(params.depth) * copy_size)}; 607 (static_cast<std::size_t>(params.depth) * copy_size)};
610 gl_buffer.assign(texture_src_data, texture_src_data_end); 608 gl_buffer.assign(texture_src_data, texture_src_data_end);
611 } 609 }
612 610
@@ -625,7 +623,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
625 623
626 MICROPROFILE_SCOPE(OpenGL_TextureUL); 624 MICROPROFILE_SCOPE(OpenGL_TextureUL);
627 625
628 ASSERT(gl_buffer.size() == static_cast<size_t>(params.width) * params.height * 626 ASSERT(gl_buffer.size() == static_cast<std::size_t>(params.width) * params.height *
629 GetGLBytesPerPixel(params.pixel_format) * params.depth); 627 GetGLBytesPerPixel(params.pixel_format) * params.depth);
630 628
631 const auto& rect{params.GetRect()}; 629 const auto& rect{params.GetRect()};
@@ -633,8 +631,9 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
633 // Load data from memory to the surface 631 // Load data from memory to the surface
634 const GLint x0 = static_cast<GLint>(rect.left); 632 const GLint x0 = static_cast<GLint>(rect.left);
635 const GLint y0 = static_cast<GLint>(rect.bottom); 633 const GLint y0 = static_cast<GLint>(rect.bottom);
636 const size_t buffer_offset = 634 const std::size_t buffer_offset =
637 static_cast<size_t>(static_cast<size_t>(y0) * params.width + static_cast<size_t>(x0)) * 635 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width +
636 static_cast<std::size_t>(x0)) *
638 GetGLBytesPerPixel(params.pixel_format); 637 GetGLBytesPerPixel(params.pixel_format);
639 638
640 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 639 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
@@ -736,7 +735,7 @@ Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) {
736 return GetSurface(depth_params, preserve_contents); 735 return GetSurface(depth_params, preserve_contents);
737} 736}
738 737
739Surface RasterizerCacheOpenGL::GetColorBufferSurface(size_t index, bool preserve_contents) { 738Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool preserve_contents) {
740 const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs}; 739 const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs};
741 740
742 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); 741 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
@@ -817,20 +816,24 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
817 // Get a new surface with the new parameters, and blit the previous surface to it 816 // Get a new surface with the new parameters, and blit the previous surface to it
818 Surface new_surface{GetUncachedSurface(new_params)}; 817 Surface new_surface{GetUncachedSurface(new_params)};
819 818
820 // If format is unchanged, we can do a faster blit without reinterpreting pixel data 819 if (params.pixel_format == new_params.pixel_format ||
821 if (params.pixel_format == new_params.pixel_format) { 820 !Settings::values.use_accurate_framebuffers) {
821 // If the format is the same, just do a framebuffer blit. This is significantly faster than
822 // using PBOs. The is also likely less accurate, as textures will be converted rather than
823 // reinterpreted.
824
822 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, 825 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
823 params.GetRect(), params.type, read_framebuffer.handle, 826 params.GetRect(), params.type, read_framebuffer.handle,
824 draw_framebuffer.handle); 827 draw_framebuffer.handle);
825 return new_surface; 828 } else {
826 } 829 // When use_accurate_framebuffers setting is enabled, perform a more accurate surface copy,
830 // where pixels are reinterpreted as a new format (without conversion). This code path uses
831 // OpenGL PBOs and is quite slow.
827 832
828 // When using accurate framebuffers, always copy old data to new surface, regardless of format
829 if (Settings::values.use_accurate_framebuffers) {
830 auto source_format = GetFormatTuple(params.pixel_format, params.component_type); 833 auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
831 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); 834 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
832 835
833 size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); 836 std::size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
834 837
835 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle); 838 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle);
836 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); 839 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
@@ -854,7 +857,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
854 LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " 857 LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
855 "reinterpretation but the texture is tiled."); 858 "reinterpretation but the texture is tiled.");
856 } 859 }
857 size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); 860 std::size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
858 std::vector<u8> data(remaining_size); 861 std::vector<u8> data(remaining_size);
859 Memory::ReadBlock(new_params.addr + params.SizeInBytes(), data.data(), data.size()); 862 Memory::ReadBlock(new_params.addr + params.SizeInBytes(), data.data(), data.size());
860 glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size, 863 glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index e660998d0..d7a4bc37f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -70,19 +70,20 @@ struct SurfaceParams {
70 RG8S = 42, 70 RG8S = 42,
71 RG32UI = 43, 71 RG32UI = 43,
72 R32UI = 44, 72 R32UI = 44,
73 ASTC_2D_8X8 = 45,
73 74
74 MaxColorFormat, 75 MaxColorFormat,
75 76
76 // Depth formats 77 // Depth formats
77 Z32F = 45, 78 Z32F = 46,
78 Z16 = 46, 79 Z16 = 47,
79 80
80 MaxDepthFormat, 81 MaxDepthFormat,
81 82
82 // DepthStencil formats 83 // DepthStencil formats
83 Z24S8 = 47, 84 Z24S8 = 48,
84 S8Z24 = 48, 85 S8Z24 = 49,
85 Z32FS8 = 49, 86 Z32FS8 = 50,
86 87
87 MaxDepthStencilFormat, 88 MaxDepthStencilFormat,
88 89
@@ -90,7 +91,7 @@ struct SurfaceParams {
90 Invalid = 255, 91 Invalid = 255,
91 }; 92 };
92 93
93 static constexpr size_t MaxPixelFormat = static_cast<size_t>(PixelFormat::Max); 94 static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
94 95
95 enum class ComponentType { 96 enum class ComponentType {
96 Invalid = 0, 97 Invalid = 0,
@@ -192,6 +193,7 @@ struct SurfaceParams {
192 1, // RG8S 193 1, // RG8S
193 1, // RG32UI 194 1, // RG32UI
194 1, // R32UI 195 1, // R32UI
196 4, // ASTC_2D_8X8
195 1, // Z32F 197 1, // Z32F
196 1, // Z16 198 1, // Z16
197 1, // Z24S8 199 1, // Z24S8
@@ -199,8 +201,8 @@ struct SurfaceParams {
199 1, // Z32FS8 201 1, // Z32FS8
200 }}; 202 }};
201 203
202 ASSERT(static_cast<size_t>(format) < compression_factor_table.size()); 204 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
203 return compression_factor_table[static_cast<size_t>(format)]; 205 return compression_factor_table[static_cast<std::size_t>(format)];
204 } 206 }
205 207
206 static constexpr u32 GetFormatBpp(PixelFormat format) { 208 static constexpr u32 GetFormatBpp(PixelFormat format) {
@@ -253,6 +255,7 @@ struct SurfaceParams {
253 16, // RG8S 255 16, // RG8S
254 64, // RG32UI 256 64, // RG32UI
255 32, // R32UI 257 32, // R32UI
258 16, // ASTC_2D_8X8
256 32, // Z32F 259 32, // Z32F
257 16, // Z16 260 16, // Z16
258 32, // Z24S8 261 32, // Z24S8
@@ -260,8 +263,8 @@ struct SurfaceParams {
260 64, // Z32FS8 263 64, // Z32FS8
261 }}; 264 }};
262 265
263 ASSERT(static_cast<size_t>(format) < bpp_table.size()); 266 ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
264 return bpp_table[static_cast<size_t>(format)]; 267 return bpp_table[static_cast<std::size_t>(format)];
265 } 268 }
266 269
267 u32 GetFormatBpp() const { 270 u32 GetFormatBpp() const {
@@ -316,6 +319,8 @@ struct SurfaceParams {
316 return PixelFormat::R11FG11FB10F; 319 return PixelFormat::R11FG11FB10F;
317 case Tegra::RenderTargetFormat::B5G6R5_UNORM: 320 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
318 return PixelFormat::B5G6R5U; 321 return PixelFormat::B5G6R5U;
322 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
323 return PixelFormat::A1B5G5R5U;
319 case Tegra::RenderTargetFormat::RGBA32_UINT: 324 case Tegra::RenderTargetFormat::RGBA32_UINT:
320 return PixelFormat::RGBA32UI; 325 return PixelFormat::RGBA32UI;
321 case Tegra::RenderTargetFormat::R8_UNORM: 326 case Tegra::RenderTargetFormat::R8_UNORM:
@@ -522,6 +527,8 @@ struct SurfaceParams {
522 return PixelFormat::BC6H_SF16; 527 return PixelFormat::BC6H_SF16;
523 case Tegra::Texture::TextureFormat::ASTC_2D_4X4: 528 case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
524 return PixelFormat::ASTC_2D_4X4; 529 return PixelFormat::ASTC_2D_4X4;
530 case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
531 return PixelFormat::ASTC_2D_8X8;
525 case Tegra::Texture::TextureFormat::R16_G16: 532 case Tegra::Texture::TextureFormat::R16_G16:
526 switch (component_type) { 533 switch (component_type) {
527 case Tegra::Texture::ComponentType::FLOAT: 534 case Tegra::Texture::ComponentType::FLOAT:
@@ -576,6 +583,7 @@ struct SurfaceParams {
576 case Tegra::RenderTargetFormat::RG16_UNORM: 583 case Tegra::RenderTargetFormat::RG16_UNORM:
577 case Tegra::RenderTargetFormat::R16_UNORM: 584 case Tegra::RenderTargetFormat::R16_UNORM:
578 case Tegra::RenderTargetFormat::B5G6R5_UNORM: 585 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
586 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
579 case Tegra::RenderTargetFormat::RG8_UNORM: 587 case Tegra::RenderTargetFormat::RG8_UNORM:
580 case Tegra::RenderTargetFormat::RGBA16_UNORM: 588 case Tegra::RenderTargetFormat::RGBA16_UNORM:
581 return ComponentType::UNorm; 589 return ComponentType::UNorm;
@@ -636,16 +644,18 @@ struct SurfaceParams {
636 } 644 }
637 645
638 static SurfaceType GetFormatType(PixelFormat pixel_format) { 646 static SurfaceType GetFormatType(PixelFormat pixel_format) {
639 if (static_cast<size_t>(pixel_format) < static_cast<size_t>(PixelFormat::MaxColorFormat)) { 647 if (static_cast<std::size_t>(pixel_format) <
648 static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
640 return SurfaceType::ColorTexture; 649 return SurfaceType::ColorTexture;
641 } 650 }
642 651
643 if (static_cast<size_t>(pixel_format) < static_cast<size_t>(PixelFormat::MaxDepthFormat)) { 652 if (static_cast<std::size_t>(pixel_format) <
653 static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
644 return SurfaceType::Depth; 654 return SurfaceType::Depth;
645 } 655 }
646 656
647 if (static_cast<size_t>(pixel_format) < 657 if (static_cast<std::size_t>(pixel_format) <
648 static_cast<size_t>(PixelFormat::MaxDepthStencilFormat)) { 658 static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
649 return SurfaceType::DepthStencil; 659 return SurfaceType::DepthStencil;
650 } 660 }
651 661
@@ -659,7 +669,7 @@ struct SurfaceParams {
659 MathUtil::Rectangle<u32> GetRect() const; 669 MathUtil::Rectangle<u32> GetRect() const;
660 670
661 /// Returns the size of this surface in bytes, adjusted for compression 671 /// Returns the size of this surface in bytes, adjusted for compression
662 size_t SizeInBytes() const { 672 std::size_t SizeInBytes() const {
663 const u32 compression_factor{GetCompressionFactor(pixel_format)}; 673 const u32 compression_factor{GetCompressionFactor(pixel_format)};
664 ASSERT(width % compression_factor == 0); 674 ASSERT(width % compression_factor == 0);
665 ASSERT(height % compression_factor == 0); 675 ASSERT(height % compression_factor == 0);
@@ -671,7 +681,7 @@ struct SurfaceParams {
671 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config); 681 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config);
672 682
673 /// Creates SurfaceParams from a framebuffer configuration 683 /// Creates SurfaceParams from a framebuffer configuration
674 static SurfaceParams CreateForFramebuffer(size_t index); 684 static SurfaceParams CreateForFramebuffer(std::size_t index);
675 685
676 /// Creates SurfaceParams for a depth buffer configuration 686 /// Creates SurfaceParams for a depth buffer configuration
677 static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height, 687 static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height,
@@ -680,8 +690,8 @@ struct SurfaceParams {
680 690
681 /// Checks if surfaces are compatible for caching 691 /// Checks if surfaces are compatible for caching
682 bool IsCompatibleSurface(const SurfaceParams& other) const { 692 bool IsCompatibleSurface(const SurfaceParams& other) const {
683 return std::tie(pixel_format, type, cache_width, cache_height) == 693 return std::tie(pixel_format, type, width, height) ==
684 std::tie(other.pixel_format, other.type, other.cache_width, other.cache_height); 694 std::tie(other.pixel_format, other.type, other.width, other.height);
685 } 695 }
686 696
687 VAddr addr; 697 VAddr addr;
@@ -694,12 +704,8 @@ struct SurfaceParams {
694 u32 height; 704 u32 height;
695 u32 depth; 705 u32 depth;
696 u32 unaligned_height; 706 u32 unaligned_height;
697 size_t size_in_bytes; 707 std::size_t size_in_bytes;
698 SurfaceTarget target; 708 SurfaceTarget target;
699
700 // Parameters used for caching only
701 u32 cache_width;
702 u32 cache_height;
703}; 709};
704 710
705}; // namespace OpenGL 711}; // namespace OpenGL
@@ -715,7 +721,7 @@ struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> {
715namespace std { 721namespace std {
716template <> 722template <>
717struct hash<SurfaceReserveKey> { 723struct hash<SurfaceReserveKey> {
718 size_t operator()(const SurfaceReserveKey& k) const { 724 std::size_t operator()(const SurfaceReserveKey& k) const {
719 return k.Hash(); 725 return k.Hash();
720 } 726 }
721}; 727};
@@ -731,7 +737,7 @@ public:
731 return params.addr; 737 return params.addr;
732 } 738 }
733 739
734 size_t GetSizeInBytes() const { 740 std::size_t GetSizeInBytes() const {
735 return params.size_in_bytes; 741 return params.size_in_bytes;
736 } 742 }
737 743
@@ -779,7 +785,7 @@ public:
779 Surface GetDepthBufferSurface(bool preserve_contents); 785 Surface GetDepthBufferSurface(bool preserve_contents);
780 786
781 /// Get the color surface based on the framebuffer configuration and the specified render target 787 /// Get the color surface based on the framebuffer configuration and the specified render target
782 Surface GetColorBufferSurface(size_t index, bool preserve_contents); 788 Surface GetColorBufferSurface(std::size_t index, bool preserve_contents);
783 789
784 /// Flushes the surface to Switch memory 790 /// Flushes the surface to Switch memory
785 void FlushSurface(const Surface& surface); 791 void FlushSurface(const Surface& surface);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 61080f5cc..894fe6eae 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -14,7 +14,7 @@ namespace OpenGL {
14/// Gets the address for the specified shader stage program 14/// Gets the address for the specified shader stage program
15static VAddr GetShaderAddress(Maxwell::ShaderProgram program) { 15static VAddr GetShaderAddress(Maxwell::ShaderProgram program) {
16 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); 16 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
17 const auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)]; 17 const auto& shader_config = gpu.regs.shader_config[static_cast<std::size_t>(program)];
18 return *gpu.memory_manager.GpuToCpuAddress(gpu.regs.code_address.CodeAddress() + 18 return *gpu.memory_manager.GpuToCpuAddress(gpu.regs.code_address.CodeAddress() +
19 shader_config.offset); 19 shader_config.offset);
20} 20}
@@ -28,7 +28,7 @@ static GLShader::ProgramCode GetShaderCode(VAddr addr) {
28 28
29/// Helper function to set shader uniform block bindings for a single shader stage 29/// Helper function to set shader uniform block bindings for a single shader stage
30static void SetShaderUniformBlockBinding(GLuint shader, const char* name, 30static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
31 Maxwell::ShaderStage binding, size_t expected_size) { 31 Maxwell::ShaderStage binding, std::size_t expected_size) {
32 const GLuint ub_index = glGetUniformBlockIndex(shader, name); 32 const GLuint ub_index = glGetUniformBlockIndex(shader, name);
33 if (ub_index == GL_INVALID_INDEX) { 33 if (ub_index == GL_INVALID_INDEX) {
34 return; 34 return;
@@ -36,7 +36,7 @@ static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
36 36
37 GLint ub_size = 0; 37 GLint ub_size = 0;
38 glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size); 38 glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
39 ASSERT_MSG(static_cast<size_t>(ub_size) == expected_size, 39 ASSERT_MSG(static_cast<std::size_t>(ub_size) == expected_size,
40 "Uniform block size did not match! Got {}, expected {}", ub_size, expected_size); 40 "Uniform block size did not match! Got {}, expected {}", ub_size, expected_size);
41 glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding)); 41 glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
42} 42}
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 6e6febcbc..9bafe43a9 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -28,7 +28,7 @@ public:
28 } 28 }
29 29
30 /// Gets the size of the shader in guest memory, required for cache management 30 /// Gets the size of the shader in guest memory, required for cache management
31 size_t GetSizeInBytes() const { 31 std::size_t GetSizeInBytes() const {
32 return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64); 32 return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
33 } 33 }
34 34
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 434faf9d4..a1638c12e 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -190,7 +190,7 @@ public:
190 190
191private: 191private:
192 void AppendIndentation() { 192 void AppendIndentation() {
193 shader_source.append(static_cast<size_t>(scope) * 4, ' '); 193 shader_source.append(static_cast<std::size_t>(scope) * 4, ' ');
194 } 194 }
195 195
196 std::string shader_source; 196 std::string shader_source;
@@ -209,7 +209,7 @@ public:
209 UnsignedInteger, 209 UnsignedInteger,
210 }; 210 };
211 211
212 GLSLRegister(size_t index, const std::string& suffix) : index{index}, suffix{suffix} {} 212 GLSLRegister(std::size_t index, const std::string& suffix) : index{index}, suffix{suffix} {}
213 213
214 /// Gets the GLSL type string for a register 214 /// Gets the GLSL type string for a register
215 static std::string GetTypeString() { 215 static std::string GetTypeString() {
@@ -227,12 +227,12 @@ public:
227 } 227 }
228 228
229 /// Returns the index of the register 229 /// Returns the index of the register
230 size_t GetIndex() const { 230 std::size_t GetIndex() const {
231 return index; 231 return index;
232 } 232 }
233 233
234private: 234private:
235 const size_t index; 235 const std::size_t index;
236 const std::string& suffix; 236 const std::string& suffix;
237}; 237};
238 238
@@ -469,7 +469,7 @@ public:
469 /// necessary. 469 /// necessary.
470 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, 470 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
471 bool is_array) { 471 bool is_array) {
472 const size_t offset = static_cast<size_t>(sampler.index.Value()); 472 const std::size_t offset = static_cast<std::size_t>(sampler.index.Value());
473 473
474 // If this sampler has already been used, return the existing mapping. 474 // If this sampler has already been used, return the existing mapping.
475 const auto itr = 475 const auto itr =
@@ -482,7 +482,7 @@ public:
482 } 482 }
483 483
484 // Otherwise create a new mapping for this sampler 484 // Otherwise create a new mapping for this sampler
485 const size_t next_index = used_samplers.size(); 485 const std::size_t next_index = used_samplers.size();
486 const SamplerEntry entry{stage, offset, next_index, type, is_array}; 486 const SamplerEntry entry{stage, offset, next_index, type, is_array};
487 used_samplers.emplace_back(entry); 487 used_samplers.emplace_back(entry);
488 return entry.GetName(); 488 return entry.GetName();
@@ -532,7 +532,7 @@ private:
532 void BuildRegisterList() { 532 void BuildRegisterList() {
533 regs.reserve(Register::NumRegisters); 533 regs.reserve(Register::NumRegisters);
534 534
535 for (size_t index = 0; index < Register::NumRegisters; ++index) { 535 for (std::size_t index = 0; index < Register::NumRegisters; ++index) {
536 regs.emplace_back(index, suffix); 536 regs.emplace_back(index, suffix);
537 } 537 }
538 } 538 }
@@ -846,7 +846,7 @@ private:
846 */ 846 */
847 bool IsSchedInstruction(u32 offset) const { 847 bool IsSchedInstruction(u32 offset) const {
848 // sched instructions appear once every 4 instructions. 848 // sched instructions appear once every 4 instructions.
849 static constexpr size_t SchedPeriod = 4; 849 static constexpr std::size_t SchedPeriod = 4;
850 u32 absolute_offset = offset - main_offset; 850 u32 absolute_offset = offset - main_offset;
851 851
852 return (absolute_offset % SchedPeriod) == 0; 852 return (absolute_offset % SchedPeriod) == 0;
@@ -914,7 +914,7 @@ private:
914 std::string result; 914 std::string result;
915 result += '('; 915 result += '(';
916 916
917 for (size_t i = 0; i < shift_amounts.size(); ++i) { 917 for (std::size_t i = 0; i < shift_amounts.size(); ++i) {
918 if (i) 918 if (i)
919 result += '|'; 919 result += '|';
920 result += "(((" + imm_lut + " >> (((" + op_c + " >> " + shift_amounts[i] + 920 result += "(((" + imm_lut + " >> (((" + op_c + " >> " + shift_amounts[i] +
@@ -940,7 +940,7 @@ private:
940 940
941 ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented"); 941 ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented");
942 942
943 size_t written_components = 0; 943 std::size_t written_components = 0;
944 for (u32 component = 0; component < 4; ++component) { 944 for (u32 component = 0; component < 4; ++component) {
945 if (!instr.texs.IsComponentEnabled(component)) { 945 if (!instr.texs.IsComponentEnabled(component)) {
946 continue; 946 continue;
@@ -1487,6 +1487,71 @@ private:
1487 1, 1); 1487 1, 1);
1488 break; 1488 break;
1489 } 1489 }
1490 case OpCode::Id::LEA_R2:
1491 case OpCode::Id::LEA_R1:
1492 case OpCode::Id::LEA_IMM:
1493 case OpCode::Id::LEA_RZ:
1494 case OpCode::Id::LEA_HI: {
1495 std::string op_c;
1496
1497 switch (opcode->GetId()) {
1498 case OpCode::Id::LEA_R2: {
1499 op_a = regs.GetRegisterAsInteger(instr.gpr20);
1500 op_b = regs.GetRegisterAsInteger(instr.gpr39);
1501 op_c = std::to_string(instr.lea.r2.entry_a);
1502 break;
1503 }
1504
1505 case OpCode::Id::LEA_R1: {
1506 const bool neg = instr.lea.r1.neg != 0;
1507 op_a = regs.GetRegisterAsInteger(instr.gpr8);
1508 if (neg)
1509 op_a = "-(" + op_a + ')';
1510 op_b = regs.GetRegisterAsInteger(instr.gpr20);
1511 op_c = std::to_string(instr.lea.r1.entry_a);
1512 break;
1513 }
1514
1515 case OpCode::Id::LEA_IMM: {
1516 const bool neg = instr.lea.imm.neg != 0;
1517 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1518 if (neg)
1519 op_b = "-(" + op_b + ')';
1520 op_a = std::to_string(instr.lea.imm.entry_a);
1521 op_c = std::to_string(instr.lea.imm.entry_b);
1522 break;
1523 }
1524
1525 case OpCode::Id::LEA_RZ: {
1526 const bool neg = instr.lea.rz.neg != 0;
1527 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1528 if (neg)
1529 op_b = "-(" + op_b + ')';
1530 op_a = regs.GetUniform(instr.lea.rz.cb_index, instr.lea.rz.cb_offset,
1531 GLSLRegister::Type::Integer);
1532 op_c = std::to_string(instr.lea.rz.entry_a);
1533
1534 break;
1535 }
1536
1537 case OpCode::Id::LEA_HI:
1538 default: {
1539 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1540 op_a = std::to_string(instr.lea.imm.entry_a);
1541 op_c = std::to_string(instr.lea.imm.entry_b);
1542 LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", opcode->GetName());
1543 UNREACHABLE();
1544 }
1545 }
1546 if (instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex)) {
1547 LOG_ERROR(HW_GPU, "Unhandled LEA Predicate");
1548 UNREACHABLE();
1549 }
1550 const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))";
1551 regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1);
1552
1553 break;
1554 }
1490 default: { 1555 default: {
1491 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", 1556 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}",
1492 opcode->GetName()); 1557 opcode->GetName());
@@ -1687,13 +1752,34 @@ private:
1687 case OpCode::Type::Memory: { 1752 case OpCode::Type::Memory: {
1688 switch (opcode->GetId()) { 1753 switch (opcode->GetId()) {
1689 case OpCode::Id::LD_A: { 1754 case OpCode::Id::LD_A: {
1690 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
1691 // Note: Shouldn't this be interp mode flat? As in no interpolation made. 1755 // Note: Shouldn't this be interp mode flat? As in no interpolation made.
1756 ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex,
1757 "Indirect attribute loads are not supported");
1758 ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0,
1759 "Unaligned attribute loads are not supported");
1692 1760
1693 Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective, 1761 Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective,
1694 Tegra::Shader::IpaSampleMode::Default}; 1762 Tegra::Shader::IpaSampleMode::Default};
1695 regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element, 1763
1696 instr.attribute.fmt20.index, input_mode); 1764 u32 next_element = instr.attribute.fmt20.element;
1765 u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
1766
1767 const auto LoadNextElement = [&](u32 reg_offset) {
1768 regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element,
1769 static_cast<Attribute::Index>(next_index),
1770 input_mode);
1771
1772 // Load the next attribute element into the following register. If the element
1773 // to load goes beyond the vec4 size, load the first element of the next
1774 // attribute.
1775 next_element = (next_element + 1) % 4;
1776 next_index = next_index + (next_element == 0 ? 1 : 0);
1777 };
1778
1779 const u32 num_words = static_cast<u32>(instr.attribute.fmt20.size.Value()) + 1;
1780 for (u32 reg_offset = 0; reg_offset < num_words; ++reg_offset) {
1781 LoadNextElement(reg_offset);
1782 }
1697 break; 1783 break;
1698 } 1784 }
1699 case OpCode::Id::LD_C: { 1785 case OpCode::Id::LD_C: {
@@ -1735,9 +1821,31 @@ private:
1735 break; 1821 break;
1736 } 1822 }
1737 case OpCode::Id::ST_A: { 1823 case OpCode::Id::ST_A: {
1738 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); 1824 ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex,
1739 regs.SetOutputAttributeToRegister(instr.attribute.fmt20.index, 1825 "Indirect attribute loads are not supported");
1740 instr.attribute.fmt20.element, instr.gpr0); 1826 ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0,
1827 "Unaligned attribute loads are not supported");
1828
1829 u32 next_element = instr.attribute.fmt20.element;
1830 u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
1831
1832 const auto StoreNextElement = [&](u32 reg_offset) {
1833 regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index),
1834 next_element,
1835 instr.gpr0.Value() + reg_offset);
1836
1837 // Load the next attribute element into the following register. If the element
1838 // to load goes beyond the vec4 size, load the first element of the next
1839 // attribute.
1840 next_element = (next_element + 1) % 4;
1841 next_index = next_index + (next_element == 0 ? 1 : 0);
1842 };
1843
1844 const u32 num_words = static_cast<u32>(instr.attribute.fmt20.size.Value()) + 1;
1845 for (u32 reg_offset = 0; reg_offset < num_words; ++reg_offset) {
1846 StoreNextElement(reg_offset);
1847 }
1848
1741 break; 1849 break;
1742 } 1850 }
1743 case OpCode::Id::TEX: { 1851 case OpCode::Id::TEX: {
@@ -1768,17 +1876,49 @@ private:
1768 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 1876 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1769 texture_type = Tegra::Shader::TextureType::Texture2D; 1877 texture_type = Tegra::Shader::TextureType::Texture2D;
1770 } 1878 }
1879 // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias
1880 // or lod.
1881 const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20);
1771 1882
1772 const std::string sampler = GetSampler(instr.sampler, texture_type, false); 1883 const std::string sampler = GetSampler(instr.sampler, texture_type, false);
1773 // Add an extra scope and declare the texture coords inside to prevent 1884 // Add an extra scope and declare the texture coords inside to prevent
1774 // overwriting them in case they are used as outputs of the texs instruction. 1885 // overwriting them in case they are used as outputs of the texs instruction.
1886
1775 shader.AddLine("{"); 1887 shader.AddLine("{");
1776 ++shader.scope; 1888 ++shader.scope;
1777 shader.AddLine(coord); 1889 shader.AddLine(coord);
1778 const std::string texture = "texture(" + sampler + ", coords)"; 1890 std::string texture;
1779 1891
1780 size_t dest_elem{}; 1892 switch (instr.tex.process_mode) {
1781 for (size_t elem = 0; elem < 4; ++elem) { 1893 case Tegra::Shader::TextureProcessMode::None: {
1894 texture = "texture(" + sampler + ", coords)";
1895 break;
1896 }
1897 case Tegra::Shader::TextureProcessMode::LZ: {
1898 texture = "textureLod(" + sampler + ", coords, 0.0)";
1899 break;
1900 }
1901 case Tegra::Shader::TextureProcessMode::LB:
1902 case Tegra::Shader::TextureProcessMode::LBA: {
1903 // TODO: Figure if A suffix changes the equation at all.
1904 texture = "texture(" + sampler + ", coords, " + op_c + ')';
1905 break;
1906 }
1907 case Tegra::Shader::TextureProcessMode::LL:
1908 case Tegra::Shader::TextureProcessMode::LLA: {
1909 // TODO: Figure if A suffix changes the equation at all.
1910 texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
1911 break;
1912 }
1913 default: {
1914 texture = "texture(" + sampler + ", coords)";
1915 LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}",
1916 static_cast<u32>(instr.tex.process_mode.Value()));
1917 UNREACHABLE();
1918 }
1919 }
1920 std::size_t dest_elem{};
1921 for (std::size_t elem = 0; elem < 4; ++elem) {
1782 if (!instr.tex.IsComponentEnabled(elem)) { 1922 if (!instr.tex.IsComponentEnabled(elem)) {
1783 // Skip disabled components 1923 // Skip disabled components
1784 continue; 1924 continue;
@@ -1882,8 +2022,8 @@ private:
1882 const std::string texture = "textureGather(" + sampler + ", coords, " + 2022 const std::string texture = "textureGather(" + sampler + ", coords, " +
1883 std::to_string(instr.tld4.component) + ')'; 2023 std::to_string(instr.tld4.component) + ')';
1884 2024
1885 size_t dest_elem{}; 2025 std::size_t dest_elem{};
1886 for (size_t elem = 0; elem < 4; ++elem) { 2026 for (std::size_t elem = 0; elem < 4; ++elem) {
1887 if (!instr.tex.IsComponentEnabled(elem)) { 2027 if (!instr.tex.IsComponentEnabled(elem)) {
1888 // Skip disabled components 2028 // Skip disabled components
1889 continue; 2029 continue;
@@ -2069,6 +2209,30 @@ private:
2069 } 2209 }
2070 break; 2210 break;
2071 } 2211 }
2212 case OpCode::Type::PredicateSetRegister: {
2213 const std::string op_a =
2214 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
2215 const std::string op_b =
2216 GetPredicateCondition(instr.pset.pred29, instr.pset.neg_pred29 != 0);
2217
2218 const std::string second_pred =
2219 GetPredicateCondition(instr.pset.pred39, instr.pset.neg_pred39 != 0);
2220
2221 const std::string combiner = GetPredicateCombiner(instr.pset.op);
2222
2223 const std::string predicate =
2224 '(' + op_a + ") " + GetPredicateCombiner(instr.pset.cond) + " (" + op_b + ')';
2225 const std::string result = '(' + predicate + ") " + combiner + " (" + second_pred + ')';
2226 if (instr.pset.bf == 0) {
2227 const std::string value = '(' + result + ") ? 0xFFFFFFFF : 0";
2228 regs.SetRegisterToInteger(instr.gpr0, false, 0, value, 1, 1);
2229 } else {
2230 const std::string value = '(' + result + ") ? 1.0 : 0.0";
2231 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
2232 }
2233
2234 break;
2235 }
2072 case OpCode::Type::PredicateSetPredicate: { 2236 case OpCode::Type::PredicateSetPredicate: {
2073 const std::string op_a = 2237 const std::string op_a =
2074 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); 2238 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index a43e2997b..d53b93ad5 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -13,7 +13,7 @@
13 13
14namespace OpenGL::GLShader { 14namespace OpenGL::GLShader {
15 15
16constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x1000}; 16constexpr std::size_t MAX_PROGRAM_CODE_LENGTH{0x1000};
17using ProgramCode = std::vector<u64>; 17using ProgramCode = std::vector<u64>;
18 18
19class ConstBufferEntry { 19class ConstBufferEntry {
@@ -51,7 +51,7 @@ public:
51 } 51 }
52 52
53 std::string GetName() const { 53 std::string GetName() const {
54 return BufferBaseNames[static_cast<size_t>(stage)] + std::to_string(index); 54 return BufferBaseNames[static_cast<std::size_t>(stage)] + std::to_string(index);
55 } 55 }
56 56
57 u32 GetHash() const { 57 u32 GetHash() const {
@@ -74,15 +74,15 @@ class SamplerEntry {
74 using Maxwell = Tegra::Engines::Maxwell3D::Regs; 74 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
75 75
76public: 76public:
77 SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index, 77 SamplerEntry(Maxwell::ShaderStage stage, std::size_t offset, std::size_t index,
78 Tegra::Shader::TextureType type, bool is_array) 78 Tegra::Shader::TextureType type, bool is_array)
79 : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {} 79 : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {}
80 80
81 size_t GetOffset() const { 81 std::size_t GetOffset() const {
82 return offset; 82 return offset;
83 } 83 }
84 84
85 size_t GetIndex() const { 85 std::size_t GetIndex() const {
86 return sampler_index; 86 return sampler_index;
87 } 87 }
88 88
@@ -91,7 +91,7 @@ public:
91 } 91 }
92 92
93 std::string GetName() const { 93 std::string GetName() const {
94 return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' + 94 return std::string(TextureSamplerNames[static_cast<std::size_t>(stage)]) + '_' +
95 std::to_string(sampler_index); 95 std::to_string(sampler_index);
96 } 96 }
97 97
@@ -133,7 +133,7 @@ public:
133 } 133 }
134 134
135 static std::string GetArrayName(Maxwell::ShaderStage stage) { 135 static std::string GetArrayName(Maxwell::ShaderStage stage) {
136 return TextureSamplerNames[static_cast<size_t>(stage)]; 136 return TextureSamplerNames[static_cast<std::size_t>(stage)];
137 } 137 }
138 138
139private: 139private:
@@ -143,9 +143,9 @@ private:
143 143
144 /// Offset in TSC memory from which to read the sampler object, as specified by the sampling 144 /// Offset in TSC memory from which to read the sampler object, as specified by the sampling
145 /// instruction. 145 /// instruction.
146 size_t offset; 146 std::size_t offset;
147 Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. 147 Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
148 size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. 148 std::size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
149 Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc) 149 Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc)
150 bool is_array; ///< Whether the texture is being sampled as an array texture or not. 150 bool is_array; ///< Whether the texture is being sampled as an array texture or not.
151}; 151};
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 533e42caa..b86cd96e8 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -12,7 +12,7 @@
12namespace OpenGL::GLShader { 12namespace OpenGL::GLShader {
13 13
14/// Number of OpenGL texture samplers that can be used in the fragment shader 14/// Number of OpenGL texture samplers that can be used in the fragment shader
15static constexpr size_t NumTextureSamplers = 32; 15static constexpr std::size_t NumTextureSamplers = 32;
16 16
17using Tegra::Engines::Maxwell3D; 17using Tegra::Engines::Maxwell3D;
18 18
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 6f70deb96..af99132ba 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -272,7 +272,7 @@ void OpenGLState::Apply() const {
272 } 272 }
273 273
274 // Clip distance 274 // Clip distance
275 for (size_t i = 0; i < clip_distance.size(); ++i) { 275 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
276 if (clip_distance[i] != cur_state.clip_distance[i]) { 276 if (clip_distance[i] != cur_state.clip_distance[i]) {
277 if (clip_distance[i]) { 277 if (clip_distance[i]) {
278 glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i)); 278 glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index aadf68f16..664f3ca20 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -61,7 +61,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
61 mapped_size = size; 61 mapped_size = size;
62 62
63 if (alignment > 0) { 63 if (alignment > 0) {
64 buffer_pos = Common::AlignUp<size_t>(buffer_pos, alignment); 64 buffer_pos = Common::AlignUp<std::size_t>(buffer_pos, alignment);
65 } 65 }
66 66
67 bool invalidate = false; 67 bool invalidate = false;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index ccff3e342..96d916b07 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -369,6 +369,12 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
369 * Draws the emulated screens to the emulator window. 369 * Draws the emulated screens to the emulator window.
370 */ 370 */
371void RendererOpenGL::DrawScreen() { 371void RendererOpenGL::DrawScreen() {
372 if (renderer_settings.set_background_color) {
373 // Update background color before drawing
374 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
375 0.0f);
376 }
377
372 const auto& layout = render_window.GetFramebufferLayout(); 378 const auto& layout = render_window.GetFramebufferLayout();
373 const auto& screen = layout.screen; 379 const auto& screen = layout.screen;
374 380
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 272294c62..20ba6d4f6 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -46,6 +46,48 @@ void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_
46 } 46 }
47} 47}
48 48
49template <std::size_t N, std::size_t M>
50struct alignas(64) SwizzleTable {
51 constexpr SwizzleTable() {
52 for (u32 y = 0; y < N; ++y) {
53 for (u32 x = 0; x < M; ++x) {
54 const u32 x2 = x * 16;
55 values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 +
56 ((x2 % 32) / 16) * 32 + (y % 2) * 16);
57 }
58 }
59 }
60 const std::array<u16, M>& operator[](std::size_t index) const {
61 return values[index];
62 }
63 std::array<std::array<u16, M>, N> values{};
64};
65
66constexpr auto swizzle_table = SwizzleTable<8, 4>();
67
68void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_data,
69 u8* unswizzled_data, bool unswizzle, u32 block_height) {
70 std::array<u8*, 2> data_ptrs;
71 const std::size_t stride{width * bytes_per_pixel};
72 const std::size_t image_width_in_gobs{(stride + 63) / 64};
73 const std::size_t copy_size{16};
74 for (std::size_t y = 0; y < height; ++y) {
75 const std::size_t initial_gob =
76 (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs +
77 (y % (8 * block_height) / 8) * 512;
78 const std::size_t pixel_base{y * width * bytes_per_pixel};
79 const auto& table = swizzle_table[y % 8];
80 for (std::size_t xb = 0; xb < stride; xb += copy_size) {
81 const std::size_t gob_address{initial_gob + (xb / 64) * 512 * block_height};
82 const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]};
83 const std::size_t pixel_index{xb + pixel_base};
84 data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
85 data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
86 std::memcpy(data_ptrs[0], data_ptrs[1], copy_size);
87 }
88 }
89}
90
49u32 BytesPerPixel(TextureFormat format) { 91u32 BytesPerPixel(TextureFormat format) {
50 switch (format) { 92 switch (format) {
51 case TextureFormat::DXT1: 93 case TextureFormat::DXT1:
@@ -63,6 +105,7 @@ u32 BytesPerPixel(TextureFormat format) {
63 case TextureFormat::R32_G32_B32: 105 case TextureFormat::R32_G32_B32:
64 return 12; 106 return 12;
65 case TextureFormat::ASTC_2D_4X4: 107 case TextureFormat::ASTC_2D_4X4:
108 case TextureFormat::ASTC_2D_8X8:
66 case TextureFormat::A8R8G8B8: 109 case TextureFormat::A8R8G8B8:
67 case TextureFormat::A2B10G10R10: 110 case TextureFormat::A2B10G10R10:
68 case TextureFormat::BF10GF11RF11: 111 case TextureFormat::BF10GF11RF11:
@@ -91,8 +134,13 @@ u32 BytesPerPixel(TextureFormat format) {
91std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, 134std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
92 u32 height, u32 block_height) { 135 u32 height, u32 block_height) {
93 std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); 136 std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
94 CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel, 137 if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) {
95 Memory::GetPointer(address), unswizzled_data.data(), true, block_height); 138 FastSwizzleData(width / tile_size, height / tile_size, bytes_per_pixel,
139 Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
140 } else {
141 CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
142 Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
143 }
96 return unswizzled_data; 144 return unswizzled_data;
97} 145}
98 146
@@ -111,6 +159,7 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
111 case TextureFormat::BC6H_UF16: 159 case TextureFormat::BC6H_UF16:
112 case TextureFormat::BC6H_SF16: 160 case TextureFormat::BC6H_SF16:
113 case TextureFormat::ASTC_2D_4X4: 161 case TextureFormat::ASTC_2D_4X4:
162 case TextureFormat::ASTC_2D_8X8:
114 case TextureFormat::A8R8G8B8: 163 case TextureFormat::A8R8G8B8:
115 case TextureFormat::A2B10G10R10: 164 case TextureFormat::A2B10G10R10:
116 case TextureFormat::A1B5G5R5: 165 case TextureFormat::A1B5G5R5:
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index c43e79e78..d229225b4 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -95,6 +95,8 @@ void Config::ReadValues() {
95 95
96 qt_config->beginGroup("Audio"); 96 qt_config->beginGroup("Audio");
97 Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); 97 Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
98 Settings::values.enable_audio_stretching =
99 qt_config->value("enable_audio_stretching", true).toBool();
98 Settings::values.audio_device_id = 100 Settings::values.audio_device_id =
99 qt_config->value("output_device", "auto").toString().toStdString(); 101 qt_config->value("output_device", "auto").toString().toStdString();
100 Settings::values.volume = qt_config->value("volume", 1).toFloat(); 102 Settings::values.volume = qt_config->value("volume", 1).toFloat();
@@ -230,6 +232,7 @@ void Config::SaveValues() {
230 232
231 qt_config->beginGroup("Audio"); 233 qt_config->beginGroup("Audio");
232 qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); 234 qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
235 qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching);
233 qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id)); 236 qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
234 qt_config->setValue("volume", Settings::values.volume); 237 qt_config->setValue("volume", Settings::values.volume);
235 qt_config->endGroup(); 238 qt_config->endGroup();
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index fbb813f6c..6ea59f2a3 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -46,6 +46,8 @@ void ConfigureAudio::setConfiguration() {
46 } 46 }
47 ui->output_sink_combo_box->setCurrentIndex(new_sink_index); 47 ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
48 48
49 ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
50
49 // The device list cannot be pre-populated (nor listed) until the output sink is known. 51 // The device list cannot be pre-populated (nor listed) until the output sink is known.
50 updateAudioDevices(new_sink_index); 52 updateAudioDevices(new_sink_index);
51 53
@@ -67,6 +69,7 @@ void ConfigureAudio::applyConfiguration() {
67 Settings::values.sink_id = 69 Settings::values.sink_id =
68 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) 70 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
69 .toStdString(); 71 .toStdString();
72 Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
70 Settings::values.audio_device_id = 73 Settings::values.audio_device_id =
71 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex()) 74 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
72 .toStdString(); 75 .toStdString();
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index ef67890dc..a29a0e265 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -31,6 +31,16 @@
31 </item> 31 </item>
32 </layout> 32 </layout>
33 </item> 33 </item>
34 <item>
35 <widget class="QCheckBox" name="toggle_audio_stretching">
36 <property name="toolTip">
37 <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
38 </property>
39 <property name="text">
40 <string>Enable audio stretching</string>
41 </property>
42 </widget>
43 </item>
34 <item> 44 <item>
35 <layout class="QHBoxLayout"> 45 <layout class="QHBoxLayout">
36 <item> 46 <item>
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp
index 1ae3423cf..8743ce982 100644
--- a/src/yuzu/configuration/configure_gamelist.cpp
+++ b/src/yuzu/configuration/configure_gamelist.cpp
@@ -2,47 +2,51 @@
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" 5#include <array>
6#include <utility>
7
8#include "common/common_types.h"
6#include "core/settings.h" 9#include "core/settings.h"
7#include "ui_configure_gamelist.h" 10#include "ui_configure_gamelist.h"
8#include "ui_settings.h"
9#include "yuzu/configuration/configure_gamelist.h" 11#include "yuzu/configuration/configure_gamelist.h"
12#include "yuzu/ui_settings.h"
13
14namespace {
15constexpr std::array<std::pair<u32, const char*>, 5> default_icon_sizes{{
16 std::make_pair(0, QT_TR_NOOP("None")),
17 std::make_pair(32, QT_TR_NOOP("Small (32x32)")),
18 std::make_pair(64, QT_TR_NOOP("Standard (64x64)")),
19 std::make_pair(128, QT_TR_NOOP("Large (128x128)")),
20 std::make_pair(256, QT_TR_NOOP("Full Size (256x256)")),
21}};
22
23constexpr std::array<const char*, 4> row_text_names{{
24 QT_TR_NOOP("Filename"),
25 QT_TR_NOOP("Filetype"),
26 QT_TR_NOOP("Title ID"),
27 QT_TR_NOOP("Title Name"),
28}};
29} // Anonymous namespace
10 30
11ConfigureGameList::ConfigureGameList(QWidget* parent) 31ConfigureGameList::ConfigureGameList(QWidget* parent)
12 : QWidget(parent), ui(new Ui::ConfigureGameList) { 32 : QWidget(parent), ui(new Ui::ConfigureGameList) {
13 ui->setupUi(this); 33 ui->setupUi(this);
14 34
15 static const std::vector<std::pair<u32, std::string>> default_icon_sizes{ 35 InitializeIconSizeComboBox();
16 std::make_pair(0, "None"), std::make_pair(32, "Small"), 36 InitializeRowComboBoxes();
17 std::make_pair(64, "Standard"), std::make_pair(128, "Large"),
18 std::make_pair(256, "Full Size"),
19 };
20
21 for (const auto& size : default_icon_sizes) {
22 ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" +
23 std::to_string(size.first) + "x" +
24 std::to_string(size.first) + ")"),
25 size.first);
26 }
27
28 static const std::vector<std::string> row_text_names{
29 "Filename",
30 "Filetype",
31 "Title ID",
32 "Title Name",
33 };
34
35 for (size_t i = 0; i < row_text_names.size(); ++i) {
36 ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]),
37 QVariant::fromValue(i));
38 ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]),
39 QVariant::fromValue(i));
40 }
41 37
42 this->setConfiguration(); 38 this->setConfiguration();
43} 39}
44 40
45ConfigureGameList::~ConfigureGameList() {} 41ConfigureGameList::~ConfigureGameList() = default;
42
43void ConfigureGameList::applyConfiguration() {
44 UISettings::values.show_unknown = ui->show_unknown->isChecked();
45 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
46 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
47 UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
48 Settings::Apply();
49}
46 50
47void ConfigureGameList::setConfiguration() { 51void ConfigureGameList::setConfiguration() {
48 ui->show_unknown->setChecked(UISettings::values.show_unknown); 52 ui->show_unknown->setChecked(UISettings::values.show_unknown);
@@ -54,10 +58,39 @@ void ConfigureGameList::setConfiguration() {
54 ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id)); 58 ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id));
55} 59}
56 60
57void ConfigureGameList::applyConfiguration() { 61void ConfigureGameList::changeEvent(QEvent* event) {
58 UISettings::values.show_unknown = ui->show_unknown->isChecked(); 62 if (event->type() == QEvent::LanguageChange) {
59 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); 63 RetranslateUI();
60 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); 64 return;
61 UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); 65 }
62 Settings::Apply(); 66
67 QWidget::changeEvent(event);
68}
69
70void ConfigureGameList::RetranslateUI() {
71 ui->retranslateUi(this);
72
73 for (int i = 0; i < ui->icon_size_combobox->count(); i++) {
74 ui->icon_size_combobox->setItemText(i, tr(default_icon_sizes[i].second));
75 }
76
77 for (int i = 0; i < ui->row_1_text_combobox->count(); i++) {
78 const QString name = tr(row_text_names[i]);
79
80 ui->row_1_text_combobox->setItemText(i, name);
81 ui->row_2_text_combobox->setItemText(i, name);
82 }
83}
84
85void ConfigureGameList::InitializeIconSizeComboBox() {
86 for (const auto& size : default_icon_sizes) {
87 ui->icon_size_combobox->addItem(size.second, size.first);
88 }
89}
90
91void ConfigureGameList::InitializeRowComboBoxes() {
92 for (std::size_t i = 0; i < row_text_names.size(); ++i) {
93 ui->row_1_text_combobox->addItem(row_text_names[i], QVariant::fromValue(i));
94 ui->row_2_text_combobox->addItem(row_text_names[i], QVariant::fromValue(i));
95 }
63} 96}
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h
index 94fba6373..ff7406c60 100644
--- a/src/yuzu/configuration/configure_gamelist.h
+++ b/src/yuzu/configuration/configure_gamelist.h
@@ -23,6 +23,11 @@ public:
23private: 23private:
24 void setConfiguration(); 24 void setConfiguration();
25 25
26private: 26 void changeEvent(QEvent*) override;
27 void RetranslateUI();
28
29 void InitializeIconSizeComboBox();
30 void InitializeRowComboBoxes();
31
27 std::unique_ptr<Ui::ConfigureGameList> ui; 32 std::unique_ptr<Ui::ConfigureGameList> ui;
28}; 33};
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index ee1287028..839d58f59 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -2,6 +2,7 @@
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 <QColorDialog>
5#include "core/core.h" 6#include "core/core.h"
6#include "core/settings.h" 7#include "core/settings.h"
7#include "ui_configure_graphics.h" 8#include "ui_configure_graphics.h"
@@ -16,6 +17,14 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
16 ui->frame_limit->setEnabled(Settings::values.use_frame_limit); 17 ui->frame_limit->setEnabled(Settings::values.use_frame_limit);
17 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, 18 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit,
18 &QSpinBox::setEnabled); 19 &QSpinBox::setEnabled);
20 connect(ui->bg_button, &QPushButton::clicked, this, [this] {
21 const QColor new_bg_color = QColorDialog::getColor(bg_color);
22 if (!new_bg_color.isValid())
23 return;
24 bg_color = new_bg_color;
25 ui->bg_button->setStyleSheet(
26 QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
27 });
19} 28}
20 29
21ConfigureGraphics::~ConfigureGraphics() = default; 30ConfigureGraphics::~ConfigureGraphics() = default;
@@ -65,6 +74,10 @@ void ConfigureGraphics::setConfiguration() {
65 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); 74 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
66 ui->frame_limit->setValue(Settings::values.frame_limit); 75 ui->frame_limit->setValue(Settings::values.frame_limit);
67 ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers); 76 ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers);
77 bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
78 Settings::values.bg_blue);
79 ui->bg_button->setStyleSheet(
80 QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
68} 81}
69 82
70void ConfigureGraphics::applyConfiguration() { 83void ConfigureGraphics::applyConfiguration() {
@@ -73,4 +86,7 @@ void ConfigureGraphics::applyConfiguration() {
73 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); 86 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
74 Settings::values.frame_limit = ui->frame_limit->value(); 87 Settings::values.frame_limit = ui->frame_limit->value();
75 Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); 88 Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked();
89 Settings::values.bg_red = static_cast<float>(bg_color.redF());
90 Settings::values.bg_green = static_cast<float>(bg_color.greenF());
91 Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
76} 92}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 5497a55f7..9bda26fd6 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -25,4 +25,5 @@ private:
25 25
26private: 26private:
27 std::unique_ptr<Ui::ConfigureGraphics> ui; 27 std::unique_ptr<Ui::ConfigureGraphics> ui;
28 QColor bg_color;
28}; 29};
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 3bc18c26e..8fc00af1b 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -96,6 +96,27 @@
96 </item> 96 </item>
97 </layout> 97 </layout>
98 </item> 98 </item>
99 <item>
100 <layout class="QHBoxLayout" name="horizontalLayout_6">
101 <item>
102 <widget class="QLabel" name="bg_label">
103 <property name="text">
104 <string>Background Color:</string>
105 </property>
106 </widget>
107 </item>
108 <item>
109 <widget class="QPushButton" name="bg_button">
110 <property name="maximumSize">
111 <size>
112 <width>40</width>
113 <height>16777215</height>
114 </size>
115 </property>
116 </widget>
117 </item>
118 </layout>
119 </item>
99 </layout> 120 </layout>
100 </widget> 121 </widget>
101 </item> 122 </item>
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
index fe682b3b8..b5c88f944 100644
--- a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
+++ b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
@@ -42,7 +42,8 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const {
42 tr("Finished primitive batch")}, 42 tr("Finished primitive batch")},
43 }; 43 };
44 44
45 DEBUG_ASSERT(map.size() == static_cast<size_t>(Tegra::DebugContext::Event::NumEvents)); 45 DEBUG_ASSERT(map.size() ==
46 static_cast<std::size_t>(Tegra::DebugContext::Event::NumEvents));
46 return (map.find(event) != map.end()) ? map.at(event) : QString(); 47 return (map.find(event) != map.end()) ? map.at(event) : QString();
47 } 48 }
48 49
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 7e37962d5..cbcd5dd5f 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -341,8 +341,8 @@ void GraphicsSurfaceWidget::OnUpdate() {
341 // directly... 341 // directly...
342 342
343 const auto& registers = gpu.Maxwell3D().regs; 343 const auto& registers = gpu.Maxwell3D().regs;
344 const auto& rt = registers.rt[static_cast<size_t>(surface_source) - 344 const auto& rt = registers.rt[static_cast<std::size_t>(surface_source) -
345 static_cast<size_t>(Source::RenderTarget0)]; 345 static_cast<std::size_t>(Source::RenderTarget0)];
346 346
347 surface_address = rt.Address(); 347 surface_address = rt.Address();
348 surface_width = rt.width; 348 surface_width = rt.width;
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 6c2cd967e..f2a7e23f0 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -117,7 +117,7 @@ QString WaitTreeCallstack::GetText() const {
117std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { 117std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
118 std::vector<std::unique_ptr<WaitTreeItem>> list; 118 std::vector<std::unique_ptr<WaitTreeItem>> list;
119 119
120 constexpr size_t BaseRegister = 29; 120 constexpr std::size_t BaseRegister = 29;
121 u64 base_pointer = thread.context.cpu_registers[BaseRegister]; 121 u64 base_pointer = thread.context.cpu_registers[BaseRegister];
122 122
123 while (base_pointer != 0) { 123 while (base_pointer != 0) {
@@ -213,35 +213,35 @@ QString WaitTreeThread::GetText() const {
213 const auto& thread = static_cast<const Kernel::Thread&>(object); 213 const auto& thread = static_cast<const Kernel::Thread&>(object);
214 QString status; 214 QString status;
215 switch (thread.status) { 215 switch (thread.status) {
216 case ThreadStatus::Running: 216 case Kernel::ThreadStatus::Running:
217 status = tr("running"); 217 status = tr("running");
218 break; 218 break;
219 case ThreadStatus::Ready: 219 case Kernel::ThreadStatus::Ready:
220 status = tr("ready"); 220 status = tr("ready");
221 break; 221 break;
222 case ThreadStatus::WaitHLEEvent: 222 case Kernel::ThreadStatus::WaitHLEEvent:
223 status = tr("waiting for HLE return"); 223 status = tr("waiting for HLE return");
224 break; 224 break;
225 case ThreadStatus::WaitSleep: 225 case Kernel::ThreadStatus::WaitSleep:
226 status = tr("sleeping"); 226 status = tr("sleeping");
227 break; 227 break;
228 case ThreadStatus::WaitIPC: 228 case Kernel::ThreadStatus::WaitIPC:
229 status = tr("waiting for IPC reply"); 229 status = tr("waiting for IPC reply");
230 break; 230 break;
231 case ThreadStatus::WaitSynchAll: 231 case Kernel::ThreadStatus::WaitSynchAll:
232 case ThreadStatus::WaitSynchAny: 232 case Kernel::ThreadStatus::WaitSynchAny:
233 status = tr("waiting for objects"); 233 status = tr("waiting for objects");
234 break; 234 break;
235 case ThreadStatus::WaitMutex: 235 case Kernel::ThreadStatus::WaitMutex:
236 status = tr("waiting for mutex"); 236 status = tr("waiting for mutex");
237 break; 237 break;
238 case ThreadStatus::WaitArb: 238 case Kernel::ThreadStatus::WaitArb:
239 status = tr("waiting for address arbiter"); 239 status = tr("waiting for address arbiter");
240 break; 240 break;
241 case ThreadStatus::Dormant: 241 case Kernel::ThreadStatus::Dormant:
242 status = tr("dormant"); 242 status = tr("dormant");
243 break; 243 break;
244 case ThreadStatus::Dead: 244 case Kernel::ThreadStatus::Dead:
245 status = tr("dead"); 245 status = tr("dead");
246 break; 246 break;
247 } 247 }
@@ -254,23 +254,23 @@ QString WaitTreeThread::GetText() const {
254QColor WaitTreeThread::GetColor() const { 254QColor WaitTreeThread::GetColor() const {
255 const auto& thread = static_cast<const Kernel::Thread&>(object); 255 const auto& thread = static_cast<const Kernel::Thread&>(object);
256 switch (thread.status) { 256 switch (thread.status) {
257 case ThreadStatus::Running: 257 case Kernel::ThreadStatus::Running:
258 return QColor(Qt::GlobalColor::darkGreen); 258 return QColor(Qt::GlobalColor::darkGreen);
259 case ThreadStatus::Ready: 259 case Kernel::ThreadStatus::Ready:
260 return QColor(Qt::GlobalColor::darkBlue); 260 return QColor(Qt::GlobalColor::darkBlue);
261 case ThreadStatus::WaitHLEEvent: 261 case Kernel::ThreadStatus::WaitHLEEvent:
262 case ThreadStatus::WaitIPC: 262 case Kernel::ThreadStatus::WaitIPC:
263 return QColor(Qt::GlobalColor::darkRed); 263 return QColor(Qt::GlobalColor::darkRed);
264 case ThreadStatus::WaitSleep: 264 case Kernel::ThreadStatus::WaitSleep:
265 return QColor(Qt::GlobalColor::darkYellow); 265 return QColor(Qt::GlobalColor::darkYellow);
266 case ThreadStatus::WaitSynchAll: 266 case Kernel::ThreadStatus::WaitSynchAll:
267 case ThreadStatus::WaitSynchAny: 267 case Kernel::ThreadStatus::WaitSynchAny:
268 case ThreadStatus::WaitMutex: 268 case Kernel::ThreadStatus::WaitMutex:
269 case ThreadStatus::WaitArb: 269 case Kernel::ThreadStatus::WaitArb:
270 return QColor(Qt::GlobalColor::red); 270 return QColor(Qt::GlobalColor::red);
271 case ThreadStatus::Dormant: 271 case Kernel::ThreadStatus::Dormant:
272 return QColor(Qt::GlobalColor::darkCyan); 272 return QColor(Qt::GlobalColor::darkCyan);
273 case ThreadStatus::Dead: 273 case Kernel::ThreadStatus::Dead:
274 return QColor(Qt::GlobalColor::gray); 274 return QColor(Qt::GlobalColor::gray);
275 default: 275 default:
276 return WaitTreeItem::GetColor(); 276 return WaitTreeItem::GetColor();
@@ -284,13 +284,13 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
284 284
285 QString processor; 285 QString processor;
286 switch (thread.processor_id) { 286 switch (thread.processor_id) {
287 case ThreadProcessorId::THREADPROCESSORID_DEFAULT: 287 case Kernel::ThreadProcessorId::THREADPROCESSORID_DEFAULT:
288 processor = tr("default"); 288 processor = tr("default");
289 break; 289 break;
290 case ThreadProcessorId::THREADPROCESSORID_0: 290 case Kernel::ThreadProcessorId::THREADPROCESSORID_0:
291 case ThreadProcessorId::THREADPROCESSORID_1: 291 case Kernel::ThreadProcessorId::THREADPROCESSORID_1:
292 case ThreadProcessorId::THREADPROCESSORID_2: 292 case Kernel::ThreadProcessorId::THREADPROCESSORID_2:
293 case ThreadProcessorId::THREADPROCESSORID_3: 293 case Kernel::ThreadProcessorId::THREADPROCESSORID_3:
294 processor = tr("core %1").arg(thread.processor_id); 294 processor = tr("core %1").arg(thread.processor_id);
295 break; 295 break;
296 default: 296 default:
@@ -314,8 +314,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
314 else 314 else
315 list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); 315 list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex")));
316 316
317 if (thread.status == ThreadStatus::WaitSynchAny || 317 if (thread.status == Kernel::ThreadStatus::WaitSynchAny ||
318 thread.status == ThreadStatus::WaitSynchAll) { 318 thread.status == Kernel::ThreadStatus::WaitSynchAll) {
319 list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, 319 list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects,
320 thread.IsSleepingOnWaitAll())); 320 thread.IsSleepingOnWaitAll()));
321 } 321 }
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 8c6e16d47..3b3b551bb 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -366,7 +366,7 @@ void GameList::LoadCompatibilityList() {
366 QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8()); 366 QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8());
367 QJsonArray arr = json.array(); 367 QJsonArray arr = json.array();
368 368
369 for (const QJsonValue& value : arr) { 369 for (const QJsonValueRef& value : arr) {
370 QJsonObject game = value.toObject(); 370 QJsonObject game = value.toObject();
371 371
372 if (game.contains("compatibility") && game["compatibility"].isDouble()) { 372 if (game.contains("compatibility") && game["compatibility"].isDouble()) {
@@ -374,9 +374,9 @@ void GameList::LoadCompatibilityList() {
374 QString directory = game["directory"].toString(); 374 QString directory = game["directory"].toString();
375 QJsonArray ids = game["releases"].toArray(); 375 QJsonArray ids = game["releases"].toArray();
376 376
377 for (const QJsonValue& value : ids) { 377 for (const QJsonValueRef& id_ref : ids) {
378 QJsonObject object = value.toObject(); 378 QJsonObject id_object = id_ref.toObject();
379 QString id = object["id"].toString(); 379 QString id = id_object["id"].toString();
380 compatibility_list.emplace( 380 compatibility_list.emplace(
381 id.toUpper().toStdString(), 381 id.toUpper().toStdString(),
382 std::make_pair(QString::number(compatibility), directory)); 382 std::make_pair(QString::number(compatibility), directory));
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index f22e422e5..b6272d536 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -106,7 +106,7 @@ class GameListItemCompat : public GameListItem {
106public: 106public:
107 static const int CompatNumberRole = Qt::UserRole + 1; 107 static const int CompatNumberRole = Qt::UserRole + 1;
108 GameListItemCompat() = default; 108 GameListItemCompat() = default;
109 explicit GameListItemCompat(const QString& compatiblity) { 109 explicit GameListItemCompat(const QString& compatibility) {
110 struct CompatStatus { 110 struct CompatStatus {
111 QString color; 111 QString color;
112 const char* text; 112 const char* text;
@@ -123,13 +123,13 @@ public:
123 {"99", {"#000000", QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}}; 123 {"99", {"#000000", QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}};
124 // clang-format on 124 // clang-format on
125 125
126 auto iterator = status_data.find(compatiblity); 126 auto iterator = status_data.find(compatibility);
127 if (iterator == status_data.end()) { 127 if (iterator == status_data.end()) {
128 LOG_WARNING(Frontend, "Invalid compatibility number {}", compatiblity.toStdString()); 128 LOG_WARNING(Frontend, "Invalid compatibility number {}", compatibility.toStdString());
129 return; 129 return;
130 } 130 }
131 CompatStatus status = iterator->second; 131 const CompatStatus& status = iterator->second;
132 setData(compatiblity, CompatNumberRole); 132 setData(compatibility, CompatNumberRole);
133 setText(QObject::tr(status.text)); 133 setText(QObject::tr(status.text));
134 setToolTip(QObject::tr(status.tooltip)); 134 setToolTip(QObject::tr(status.tooltip));
135 setData(CreateCirclePixmapFromColor(status.color), Qt::DecorationRole); 135 setData(CreateCirclePixmapFromColor(status.color), Qt::DecorationRole);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index e36914f14..45bb1d1d1 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -447,6 +447,10 @@ QStringList GMainWindow::GetUnsupportedGLExtensions() {
447 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); 447 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge");
448 if (!GLAD_GL_ARB_base_instance) 448 if (!GLAD_GL_ARB_base_instance)
449 unsupported_ext.append("ARB_base_instance"); 449 unsupported_ext.append("ARB_base_instance");
450 if (!GLAD_GL_ARB_texture_storage)
451 unsupported_ext.append("ARB_texture_storage");
452 if (!GLAD_GL_ARB_multi_bind)
453 unsupported_ext.append("ARB_multi_bind");
450 454
451 // Extensions required to support some texture formats. 455 // Extensions required to support some texture formats.
452 if (!GLAD_GL_EXT_texture_compression_s3tc) 456 if (!GLAD_GL_EXT_texture_compression_s3tc)
@@ -800,7 +804,7 @@ void GMainWindow::OnMenuInstallToNAND() {
800 tr("Cancel"), 0, progress_maximum, this); 804 tr("Cancel"), 0, progress_maximum, this);
801 progress.setWindowModality(Qt::WindowModal); 805 progress.setWindowModality(Qt::WindowModal);
802 806
803 for (size_t i = 0; i < src->GetSize(); i += buffer.size()) { 807 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
804 if (progress.wasCanceled()) { 808 if (progress.wasCanceled()) {
805 dest->Resize(0); 809 dest->Resize(0);
806 return false; 810 return false;
diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp
index e99042a23..62c080aff 100644
--- a/src/yuzu/util/util.cpp
+++ b/src/yuzu/util/util.cpp
@@ -30,8 +30,9 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) {
30 QPixmap circle_pixmap(16, 16); 30 QPixmap circle_pixmap(16, 16);
31 circle_pixmap.fill(Qt::transparent); 31 circle_pixmap.fill(Qt::transparent);
32 QPainter painter(&circle_pixmap); 32 QPainter painter(&circle_pixmap);
33 painter.setRenderHint(QPainter::Antialiasing);
33 painter.setPen(color); 34 painter.setPen(color);
34 painter.setBrush(color); 35 painter.setBrush(color);
35 painter.drawEllipse(0, 0, 15, 15); 36 painter.drawEllipse({circle_pixmap.width() / 2.0, circle_pixmap.height() / 2.0}, 7.0, 7.0);
36 return circle_pixmap; 37 return circle_pixmap;
37} 38}
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index f00b5a66b..991abda2e 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -108,6 +108,8 @@ void Config::ReadValues() {
108 108
109 // Audio 109 // Audio
110 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); 110 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
111 Settings::values.enable_audio_stretching =
112 sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
111 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); 113 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
112 Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1); 114 Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1);
113 115
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 6ed9e7962..002a4ec15 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -150,6 +150,12 @@ swap_screen =
150# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available) 150# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available)
151output_engine = 151output_engine =
152 152
153# Whether or not to enable the audio-stretching post-processing effect.
154# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter,
155# at the cost of increasing audio latency.
156# 0: No, 1 (default): Yes
157enable_audio_stretching =
158
153# Which audio device to use. 159# Which audio device to use.
154# auto (default): Auto-select 160# auto (default): Auto-select
155output_device = 161output_device =
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 1c4717123..0733301b2 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -94,6 +94,10 @@ bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
94 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); 94 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
95 if (!GLAD_GL_ARB_base_instance) 95 if (!GLAD_GL_ARB_base_instance)
96 unsupported_ext.push_back("ARB_base_instance"); 96 unsupported_ext.push_back("ARB_base_instance");
97 if (!GLAD_GL_ARB_texture_storage)
98 unsupported_ext.push_back("ARB_texture_storage");
99 if (!GLAD_GL_ARB_multi_bind)
100 unsupported_ext.push_back("ARB_multi_bind");
97 101
98 // Extensions required to support some texture formats. 102 // Extensions required to support some texture formats.
99 if (!GLAD_GL_EXT_texture_compression_s3tc) 103 if (!GLAD_GL_EXT_texture_compression_s3tc)