summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml13
-rwxr-xr-x.travis/common/post-upload.sh3
-rwxr-xr-x.travis/linux-mingw/build.sh3
-rwxr-xr-x.travis/linux-mingw/deps.sh3
-rwxr-xr-x.travis/linux-mingw/docker.sh59
-rw-r--r--.travis/linux-mingw/scan_dll.py106
-rwxr-xr-x.travis/linux-mingw/upload.sh13
-rwxr-xr-x.travis/linux/docker.sh4
-rwxr-xr-x.travis/macos/build.sh4
-rw-r--r--CMakeLists.txt25
-rw-r--r--CMakeModules/MinGWCross.cmake54
m---------externals/dynarmic0
-rw-r--r--src/audio_core/audio_renderer.cpp4
-rw-r--r--src/audio_core/audio_renderer.h1
-rw-r--r--src/audio_core/stream.cpp5
-rw-r--r--src/audio_core/stream.h3
-rw-r--r--src/audio_core/time_stretch.cpp2
-rw-r--r--src/common/ring_buffer.h14
-rw-r--r--src/common/thread.h8
-rw-r--r--src/core/arm/arm_interface.h5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp13
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h4
-rw-r--r--src/core/file_sys/content_archive.cpp2
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp26
-rw-r--r--src/core/file_sys/control_metadata.h9
-rw-r--r--src/core/file_sys/nca_metadata.cpp2
-rw-r--r--src/core/file_sys/nca_metadata.h1
-rw-r--r--src/core/file_sys/partition_filesystem.cpp2
-rw-r--r--src/core/file_sys/partition_filesystem.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp2
-rw-r--r--src/core/file_sys/patch_manager.h1
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/program_metadata.h3
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/romfs_factory.h1
-rw-r--r--src/core/file_sys/savedata_factory.cpp13
-rw-r--r--src/core/file_sys/savedata_factory.h1
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs_concat.cpp2
-rw-r--r--src/core/file_sys/vfs_concat.h2
-rw-r--r--src/core/file_sys/vfs_offset.cpp2
-rw-r--r--src/core/file_sys/vfs_offset.h1
-rw-r--r--src/core/file_sys/vfs_vector.cpp2
-rw-r--r--src/core/file_sys/vfs_vector.h1
-rw-r--r--src/core/file_sys/xts_archive.cpp13
-rw-r--r--src/core/file_sys/xts_archive.h5
-rw-r--r--src/core/gdbstub/gdbstub.cpp2
-rw-r--r--src/core/hle/ipc_helpers.h7
-rw-r--r--src/core/hle/kernel/mutex.cpp1
-rw-r--r--src/core/hle/kernel/process.cpp89
-rw-r--r--src/core/hle/kernel/process.h55
-rw-r--r--src/core/hle/kernel/svc.cpp32
-rw-r--r--src/core/hle/kernel/thread.cpp64
-rw-r--r--src/core/hle/kernel/thread.h15
-rw-r--r--src/core/hle/service/acc/acc.cpp9
-rw-r--r--src/core/hle/service/am/am.cpp8
-rw-r--r--src/core/hle/service/audio/audout_u.cpp2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp15
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp8
-rw-r--r--src/core/hle/service/nifm/nifm.cpp19
-rw-r--r--src/core/hle/service/nim/nim.cpp102
-rw-r--r--src/core/hle/service/sm/sm.cpp5
-rw-r--r--src/core/hle/service/ssl/ssl.cpp2
-rw-r--r--src/core/hle/service/vi/vi.cpp30
-rw-r--r--src/core/loader/nax.cpp26
-rw-r--r--src/core/loader/nax.h4
-rw-r--r--src/core/loader/nso.cpp15
-rw-r--r--src/video_core/engines/shader_bytecode.h27
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h21
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp2
-rw-r--r--src/video_core/utils.h22
-rw-r--r--src/yuzu/debugger/wait_tree.cpp1
-rw-r--r--src/yuzu/game_list.cpp10
-rw-r--r--src/yuzu/game_list_p.h2
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp4
83 files changed, 831 insertions, 250 deletions
diff --git a/.travis.yml b/.travis.yml
index dee34a8e3..4d363cbc9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,6 +29,19 @@ matrix:
29 script: "./.travis/macos/build.sh" 29 script: "./.travis/macos/build.sh"
30 after_success: "./.travis/macos/upload.sh" 30 after_success: "./.travis/macos/upload.sh"
31 cache: ccache 31 cache: ccache
32 - os: linux
33 env: NAME="MinGW build"
34 sudo: required
35 dist: trusty
36 services: docker
37 addons:
38 apt:
39 packages:
40 - p7zip-full
41 install: "./.travis/linux-mingw/deps.sh"
42 script: "./.travis/linux-mingw/build.sh"
43 after_success: "./.travis/linux-mingw/upload.sh"
44 cache: ccache
32 45
33deploy: 46deploy:
34 provider: releases 47 provider: releases
diff --git a/.travis/common/post-upload.sh b/.travis/common/post-upload.sh
index 90deaaec8..28735a9cf 100755
--- a/.travis/common/post-upload.sh
+++ b/.travis/common/post-upload.sh
@@ -11,6 +11,9 @@ if [ -z $TRAVIS_TAG ]; then
11 RELEASE_NAME=head 11 RELEASE_NAME=head
12else 12else
13 RELEASE_NAME=$(echo $TRAVIS_TAG | cut -d- -f1) 13 RELEASE_NAME=$(echo $TRAVIS_TAG | cut -d- -f1)
14 if [ "$NAME" = "MinGW build" ]; then
15 RELEASE_NAME="${RELEASE_NAME}-mingw"
16 fi
14fi 17fi
15 18
16mv "$REV_NAME" $RELEASE_NAME 19mv "$REV_NAME" $RELEASE_NAME
diff --git a/.travis/linux-mingw/build.sh b/.travis/linux-mingw/build.sh
new file mode 100755
index 000000000..be03cc0f3
--- /dev/null
+++ b/.travis/linux-mingw/build.sh
@@ -0,0 +1,3 @@
1#!/bin/bash -ex
2mkdir "$HOME/.ccache" || true
3docker run --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /yuzu/.travis/linux-mingw/docker.sh
diff --git a/.travis/linux-mingw/deps.sh b/.travis/linux-mingw/deps.sh
new file mode 100755
index 000000000..540bb934a
--- /dev/null
+++ b/.travis/linux-mingw/deps.sh
@@ -0,0 +1,3 @@
1#!/bin/sh -ex
2
3docker pull ubuntu:18.04
diff --git a/.travis/linux-mingw/docker.sh b/.travis/linux-mingw/docker.sh
new file mode 100755
index 000000000..d15c3f6e8
--- /dev/null
+++ b/.travis/linux-mingw/docker.sh
@@ -0,0 +1,59 @@
1#!/bin/bash -ex
2
3cd /yuzu
4MINGW_PACKAGES="sdl2-mingw-w64 qt5base-mingw-w64 qt5tools-mingw-w64 libsamplerate-mingw-w64 qt5multimedia-mingw-w64"
5apt-get update
6apt-get install -y gpg wget git python3-pip python ccache g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 mingw-w64-tools cmake
7echo 'deb http://ppa.launchpad.net/tobydox/mingw-w64/ubuntu bionic main ' > /etc/apt/sources.list.d/extras.list
8apt-key adv --keyserver keyserver.ubuntu.com --recv '72931B477E22FEFD47F8DECE02FE5F12ADDE29B2'
9apt-get update
10apt-get install -y ${MINGW_PACKAGES}
11
12# fix a problem in current MinGW headers
13wget -q https://raw.githubusercontent.com/Alexpux/mingw-w64/d0d7f784833bbb0b2d279310ddc6afb52fe47a46/mingw-w64-headers/crt/errno.h -O /usr/x86_64-w64-mingw32/include/errno.h
14# override Travis CI unreasonable ccache size
15echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
16
17# Dirty hack to trick unicorn makefile into believing we are in a MINGW system
18mv /bin/uname /bin/uname1 && echo -e '#!/bin/sh\necho MINGW64' >> /bin/uname
19chmod +x /bin/uname
20
21# Dirty hack to trick unicorn makefile into believing we have cmd
22echo '' >> /bin/cmd
23chmod +x /bin/cmd
24
25mkdir build && cd build
26cmake .. -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
27make -j4
28
29# Clean up the dirty hacks
30rm /bin/uname && mv /bin/uname1 /bin/uname
31rm /bin/cmd
32
33ccache -s
34
35echo "Tests skipped"
36#ctest -VV -C Release
37
38echo 'Prepare binaries...'
39cd ..
40mkdir package
41
42QT_PLATFORM_DLL_PATH='/usr/x86_64-w64-mingw32/lib/qt5/plugins/platforms/'
43find build/ -name "yuzu*.exe" -exec cp {} 'package' \;
44
45# copy Qt plugins
46mkdir package/platforms
47cp "${QT_PLATFORM_DLL_PATH}/qwindows.dll" package/platforms/
48cp -rv "${QT_PLATFORM_DLL_PATH}/../mediaservice/" package/
49cp -rv "${QT_PLATFORM_DLL_PATH}/../imageformats/" package/
50rm -f package/mediaservice/*d.dll
51
52for i in package/*.exe; do
53 # we need to process pdb here, however, cv2pdb
54 # does not work here, so we just simply strip all the debug symbols
55 x86_64-w64-mingw32-strip "${i}"
56done
57
58pip3 install pefile
59python3 .travis/linux-mingw/scan_dll.py package/*.exe "package/"
diff --git a/.travis/linux-mingw/scan_dll.py b/.travis/linux-mingw/scan_dll.py
new file mode 100644
index 000000000..163183f2e
--- /dev/null
+++ b/.travis/linux-mingw/scan_dll.py
@@ -0,0 +1,106 @@
1import pefile
2import sys
3import re
4import os
5import queue
6import shutil
7
8# constant definitions
9KNOWN_SYS_DLLS = ['WINMM.DLL', 'MSVCRT.DLL', 'VERSION.DLL', 'MPR.DLL',
10 'DWMAPI.DLL', 'UXTHEME.DLL', 'DNSAPI.DLL', 'IPHLPAPI.DLL']
11# below is for Ubuntu 18.04 with specified PPA enabled, if you are using
12# other distro or different repositories, change the following accordingly
13DLL_PATH = [
14 '/usr/x86_64-w64-mingw32/bin/',
15 '/usr/x86_64-w64-mingw32/lib/',
16 '/usr/lib/gcc/x86_64-w64-mingw32/7.3-posix/'
17]
18
19missing = []
20
21
22def parse_imports(file_name):
23 results = []
24 pe = pefile.PE(file_name, fast_load=True)
25 pe.parse_data_directories()
26
27 for entry in pe.DIRECTORY_ENTRY_IMPORT:
28 current = entry.dll.decode()
29 current_u = current.upper() # b/c Windows is often case insensitive
30 # here we filter out system dlls
31 # dll w/ names like *32.dll are likely to be system dlls
32 if current_u.upper() not in KNOWN_SYS_DLLS and not re.match(string=current_u, pattern=r'.*32\.DLL'):
33 results.append(current)
34
35 return results
36
37
38def parse_imports_recursive(file_name, path_list=[]):
39 q = queue.Queue() # create a FIFO queue
40 # file_name can be a string or a list for the convience
41 if isinstance(file_name, str):
42 q.put(file_name)
43 elif isinstance(file_name, list):
44 for i in file_name:
45 q.put(i)
46 full_list = []
47 while q.qsize():
48 current = q.get_nowait()
49 print('> %s' % current)
50 deps = parse_imports(current)
51 # if this dll does not have any import, ignore it
52 if not deps:
53 continue
54 for dep in deps:
55 # the dependency already included in the list, skip
56 if dep in full_list:
57 continue
58 # find the requested dll in the provided paths
59 full_path = find_dll(dep)
60 if not full_path:
61 missing.append(dep)
62 continue
63 full_list.append(dep)
64 q.put(full_path)
65 path_list.append(full_path)
66 return full_list
67
68
69def find_dll(name):
70 for path in DLL_PATH:
71 for root, _, files in os.walk(path):
72 for f in files:
73 if name.lower() == f.lower():
74 return os.path.join(root, f)
75
76
77def deploy(name, dst, dry_run=False):
78 dlls_path = []
79 parse_imports_recursive(name, dlls_path)
80 for dll_entry in dlls_path:
81 if not dry_run:
82 shutil.copy(dll_entry, dst)
83 else:
84 print('[Dry-Run] Copy %s to %s' % (dll_entry, dst))
85 print('Deploy completed.')
86 return dlls_path
87
88
89def main():
90 if len(sys.argv) < 3:
91 print('Usage: %s [files to examine ...] [target deploy directory]')
92 return 1
93 to_deploy = sys.argv[1:-1]
94 tgt_dir = sys.argv[-1]
95 if not os.path.isdir(tgt_dir):
96 print('%s is not a directory.' % tgt_dir)
97 return 1
98 print('Scanning dependencies...')
99 deploy(to_deploy, tgt_dir)
100 if missing:
101 print('Following DLLs are not found: %s' % ('\n'.join(missing)))
102 return 0
103
104
105if __name__ == '__main__':
106 main()
diff --git a/.travis/linux-mingw/upload.sh b/.travis/linux-mingw/upload.sh
new file mode 100755
index 000000000..66e896bc4
--- /dev/null
+++ b/.travis/linux-mingw/upload.sh
@@ -0,0 +1,13 @@
1#!/bin/bash -ex
2
3. .travis/common/pre-upload.sh
4
5REV_NAME="yuzu-windows-mingw-${GITDATE}-${GITREV}"
6ARCHIVE_NAME="${REV_NAME}.tar.gz"
7COMPRESSION_FLAGS="-czvf"
8
9mkdir "$REV_NAME"
10# get around the permission issues
11cp -r package/* "$REV_NAME"
12
13. .travis/common/post-upload.sh
diff --git a/.travis/linux/docker.sh b/.travis/linux/docker.sh
index 459d6bc75..892d2480a 100755
--- a/.travis/linux/docker.sh
+++ b/.travis/linux/docker.sh
@@ -6,7 +6,9 @@ apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev
6cd /yuzu 6cd /yuzu
7 7
8mkdir build && cd build 8mkdir build && cd build
9cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -G Ninja 9cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -G Ninja
10ninja 10ninja
11 11
12ccache -s
13
12ctest -VV -C Release 14ctest -VV -C Release
diff --git a/.travis/macos/build.sh b/.travis/macos/build.sh
index b76a153be..b881fa190 100755
--- a/.travis/macos/build.sh
+++ b/.travis/macos/build.sh
@@ -9,7 +9,9 @@ export PATH="/usr/local/opt/ccache/libexec:$PATH"
9 9
10mkdir build && cd build 10mkdir build && cd build
11cmake --version 11cmake --version
12cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON 12cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON
13make -j4 13make -j4
14 14
15ccache -s
16
15ctest -VV -C Release 17ctest -VV -C Release
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 500d099fc..25c5cb112 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -269,10 +269,18 @@ if (YUZU_USE_BUNDLED_UNICORN)
269 269
270 find_package(PythonInterp 2.7 REQUIRED) 270 find_package(PythonInterp 2.7 REQUIRED)
271 271
272 add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY} 272 if (MINGW)
273 COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no 273 add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
274 WORKING_DIRECTORY ${UNICORN_PREFIX} 274 COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh cross-win64
275 ) 275 WORKING_DIRECTORY ${UNICORN_PREFIX}
276 )
277 else()
278 add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
279 COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
280 WORKING_DIRECTORY ${UNICORN_PREFIX}
281 )
282 endif()
283
276 # ALL makes this custom target build every time 284 # ALL makes this custom target build every time
277 # but it won't actually build if LIBUNICORN_LIBRARY is up to date 285 # but it won't actually build if LIBUNICORN_LIBRARY is up to date
278 add_custom_target(unicorn-build ALL 286 add_custom_target(unicorn-build ALL
@@ -286,6 +294,7 @@ endif()
286 294
287if (UNICORN_FOUND) 295if (UNICORN_FOUND)
288 add_library(unicorn INTERFACE) 296 add_library(unicorn INTERFACE)
297 add_dependencies(unicorn unicorn-build)
289 target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}") 298 target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}")
290 target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}") 299 target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}")
291else() 300else()
@@ -431,8 +440,12 @@ enable_testing()
431add_subdirectory(externals) 440add_subdirectory(externals)
432add_subdirectory(src) 441add_subdirectory(src)
433 442
434# Set yuzu project as default StartUp Project in Visual Studio 443# Set yuzu project or yuzu-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not
435set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu) 444if(ENABLE_QT)
445 set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
446else()
447 set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu-cmd)
448endif()
436 449
437 450
438# Installation instructions 451# Installation instructions
diff --git a/CMakeModules/MinGWCross.cmake b/CMakeModules/MinGWCross.cmake
new file mode 100644
index 000000000..29ecd1ac4
--- /dev/null
+++ b/CMakeModules/MinGWCross.cmake
@@ -0,0 +1,54 @@
1set(MINGW_PREFIX /usr/x86_64-w64-mingw32/)
2set(CMAKE_SYSTEM_NAME Windows)
3set(CMAKE_SYSTEM_PROCESSOR x86_64)
4# Actually a hack, w/o this will cause some strange errors
5set(CMAKE_HOST_WIN32 TRUE)
6
7
8set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
9set(SDL2_PATH ${MINGW_PREFIX})
10set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
11
12# Specify the cross compiler
13set(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc-posix)
14set(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++-posix)
15set(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres)
16
17# Mingw tools
18set(STRIP ${MINGW_TOOL_PREFIX}strip)
19set(WINDRES ${MINGW_TOOL_PREFIX}windres)
20set(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config)
21
22# ccache wrapper
23option(USE_CCACHE "Use ccache for compilation" OFF)
24if(USE_CCACHE)
25 find_program(CCACHE ccache)
26 if(CCACHE)
27 message(STATUS "Using ccache found in PATH")
28 set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
29 set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
30 else(CCACHE)
31 message(WARNING "USE_CCACHE enabled, but no ccache found")
32 endif(CCACHE)
33endif(USE_CCACHE)
34
35# Search for programs in the build host directories
36set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
37
38
39# Echo modified cmake vars to screen for debugging purposes
40if(NOT DEFINED ENV{MINGW_DEBUG_INFO})
41 message("")
42 message("Custom cmake vars: (blank = system default)")
43 message("-----------------------------------------")
44 message("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
45 message("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
46 message("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
47 message("* WINDRES : ${WINDRES}")
48 message("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}")
49 message("* STRIP : ${STRIP}")
50 message("* USE_CCACHE : ${USE_CCACHE}")
51 message("")
52 # So that the debug info only appears once
53 set(ENV{MINGW_DEBUG_INFO} SHOWN)
54endif()
diff --git a/externals/dynarmic b/externals/dynarmic
Subproject 959446573f3adfcba173ef4b0011a4a280f18eb Subproject 171d11659d760a4d4674d3a90698fe31ea407e2
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 83b75e61f..521b19ff7 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -79,6 +79,10 @@ u32 AudioRenderer::GetMixBufferCount() const {
79 return worker_params.mix_buffer_count; 79 return worker_params.mix_buffer_count;
80} 80}
81 81
82u32 AudioRenderer::GetState() const {
83 return stream->GetState();
84}
85
82std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { 86std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
83 // Copy UpdateDataHeader struct 87 // Copy UpdateDataHeader struct
84 UpdateDataHeader config{}; 88 UpdateDataHeader config{};
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 2c4f5ab75..be923ee65 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -170,6 +170,7 @@ public:
170 u32 GetSampleRate() const; 170 u32 GetSampleRate() const;
171 u32 GetSampleCount() const; 171 u32 GetSampleCount() const;
172 u32 GetMixBufferCount() const; 172 u32 GetMixBufferCount() const;
173 u32 GetState() const;
173 174
174private: 175private:
175 class VoiceState; 176 class VoiceState;
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 449db2416..ee4aa98af 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -49,9 +49,14 @@ void Stream::Play() {
49} 49}
50 50
51void Stream::Stop() { 51void Stream::Stop() {
52 state = State::Stopped;
52 ASSERT_MSG(false, "Unimplemented"); 53 ASSERT_MSG(false, "Unimplemented");
53} 54}
54 55
56u32 Stream::GetState() const {
57 return static_cast<u32>(state);
58}
59
55s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { 60s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
56 const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; 61 const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
57 return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); 62 return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 27db1112f..43eca74e1 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -72,6 +72,9 @@ public:
72 /// Gets the number of channels 72 /// Gets the number of channels
73 u32 GetNumChannels() const; 73 u32 GetNumChannels() const;
74 74
75 /// Get the state
76 u32 GetState() const;
77
75private: 78private:
76 /// Current state of the stream 79 /// Current state of the stream
77 enum class State { 80 enum class State {
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
index fc14151da..d72d67994 100644
--- a/src/audio_core/time_stretch.cpp
+++ b/src/audio_core/time_stretch.cpp
@@ -59,7 +59,7 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
59 m_stretch_ratio = std::max(m_stretch_ratio, 0.05); 59 m_stretch_ratio = std::max(m_stretch_ratio, 0.05);
60 m_sound_touch.setTempo(m_stretch_ratio); 60 m_sound_touch.setTempo(m_stretch_ratio);
61 61
62 LOG_DEBUG(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio, 62 LOG_TRACE(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio,
63 backlog_fullness); 63 backlog_fullness);
64 64
65 m_sound_touch.putSamples(in, static_cast<u32>(num_in)); 65 m_sound_touch.putSamples(in, static_cast<u32>(num_in));
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h
index 45926c9ec..abe3b4dc2 100644
--- a/src/common/ring_buffer.h
+++ b/src/common/ring_buffer.h
@@ -9,6 +9,7 @@
9#include <atomic> 9#include <atomic>
10#include <cstddef> 10#include <cstddef>
11#include <cstring> 11#include <cstring>
12#include <new>
12#include <type_traits> 13#include <type_traits>
13#include <vector> 14#include <vector>
14#include "common/common_types.h" 15#include "common/common_types.h"
@@ -29,7 +30,7 @@ class RingBuffer {
29 static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2 / granularity); 30 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 static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two");
31 // Ensure lock-free. 32 // Ensure lock-free.
32 static_assert(std::atomic<std::size_t>::is_always_lock_free); 33 static_assert(std::atomic_size_t::is_always_lock_free);
33 34
34public: 35public:
35 /// Pushes slots into the ring buffer 36 /// Pushes slots into the ring buffer
@@ -102,8 +103,15 @@ public:
102private: 103private:
103 // It is important to align the below variables for performance reasons: 104 // 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 // 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 // TODO: Remove this ifdef whenever clang and GCC support
106 alignas(128) std::atomic<std::size_t> m_write_index{0}; 107 // std::hardware_destructive_interference_size.
108#if defined(_MSC_VER) && _MSC_VER >= 1911
109 alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
110 alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
111#else
112 alignas(128) std::atomic_size_t m_read_index{0};
113 alignas(128) std::atomic_size_t m_write_index{0};
114#endif
107 115
108 std::array<T, granularity * capacity> m_data; 116 std::array<T, granularity * capacity> m_data;
109}; 117};
diff --git a/src/common/thread.h b/src/common/thread.h
index 12a1c095c..6cbdb96a3 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -87,14 +87,6 @@ private:
87 87
88void SleepCurrentThread(int ms); 88void SleepCurrentThread(int ms);
89void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms 89void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
90
91// Use this function during a spin-wait to make the current thread
92// relax while another thread is working. This may be more efficient
93// than using events because event functions use kernel calls.
94inline void YieldCPU() {
95 std::this_thread::yield();
96}
97
98void SetCurrentThreadName(const char* name); 90void SetCurrentThreadName(const char* name);
99 91
100} // namespace Common 92} // namespace Common
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 867e34932..16d528994 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -6,7 +6,10 @@
6 6
7#include <array> 7#include <array>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/kernel/vm_manager.h" 9
10namespace Kernel {
11enum class VMAPermission : u8;
12}
10 13
11namespace Core { 14namespace Core {
12 15
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 3f072c51f..7be5a38de 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -12,8 +12,10 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/core_cpu.h" 13#include "core/core_cpu.h"
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/gdbstub/gdbstub.h"
15#include "core/hle/kernel/process.h" 16#include "core/hle/kernel/process.h"
16#include "core/hle/kernel/svc.h" 17#include "core/hle/kernel/svc.h"
18#include "core/hle/kernel/vm_manager.h"
17#include "core/memory.h" 19#include "core/memory.h"
18 20
19namespace Core { 21namespace Core {
@@ -79,6 +81,17 @@ public:
79 case Dynarmic::A64::Exception::SendEventLocal: 81 case Dynarmic::A64::Exception::SendEventLocal:
80 case Dynarmic::A64::Exception::Yield: 82 case Dynarmic::A64::Exception::Yield:
81 return; 83 return;
84 case Dynarmic::A64::Exception::Breakpoint:
85 if (GDBStub::IsServerEnabled()) {
86 parent.jit->HaltExecution();
87 parent.SetPC(pc);
88 Kernel::Thread* thread = Kernel::GetCurrentThread();
89 parent.SaveContext(thread->context);
90 GDBStub::Break();
91 GDBStub::SendTrap(thread, 5);
92 return;
93 }
94 [[fallthrough]];
82 default: 95 default:
83 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})", 96 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
84 static_cast<std::size_t>(exception), pc); 97 static_cast<std::size_t>(exception), pc);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index e61382d3d..4ee92ee27 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -12,6 +12,10 @@
12#include "core/arm/exclusive_monitor.h" 12#include "core/arm/exclusive_monitor.h"
13#include "core/arm/unicorn/arm_unicorn.h" 13#include "core/arm/unicorn/arm_unicorn.h"
14 14
15namespace Memory {
16struct PageTable;
17}
18
15namespace Core { 19namespace Core {
16 20
17class ARM_Dynarmic_Callbacks; 21class ARM_Dynarmic_Callbacks;
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 45fc0b574..aa1b3c17d 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -463,6 +463,8 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
463 status = Loader::ResultStatus::Success; 463 status = Loader::ResultStatus::Success;
464} 464}
465 465
466NCA::~NCA() = default;
467
466Loader::ResultStatus NCA::GetStatus() const { 468Loader::ResultStatus NCA::GetStatus() const {
467 return status; 469 return status;
468} 470}
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 00eca52da..f9f66cae9 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -81,6 +81,8 @@ class NCA : public ReadOnlyVfsDirectory {
81public: 81public:
82 explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, 82 explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr,
83 u64 bktr_base_ivfc_offset = 0); 83 u64 bktr_base_ivfc_offset = 0);
84 ~NCA() override;
85
84 Loader::ResultStatus GetStatus() const; 86 Loader::ResultStatus GetStatus() const;
85 87
86 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 88 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index e76bf77bf..5b1177a03 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -8,6 +8,14 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11const std::array<const char*, 15> LANGUAGE_NAMES = {
12 "AmericanEnglish", "BritishEnglish", "Japanese",
13 "French", "German", "LatinAmericanSpanish",
14 "Spanish", "Italian", "Dutch",
15 "CanadianFrench", "Portugese", "Russian",
16 "Korean", "Taiwanese", "Chinese",
17};
18
11std::string LanguageEntry::GetApplicationName() const { 19std::string LanguageEntry::GetApplicationName() const {
12 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200); 20 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200);
13} 21}
@@ -20,18 +28,20 @@ NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
20 file->ReadObject(raw.get()); 28 file->ReadObject(raw.get());
21} 29}
22 30
31NACP::~NACP() = default;
32
23const LanguageEntry& NACP::GetLanguageEntry(Language language) const { 33const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
24 if (language != Language::Default) { 34 if (language != Language::Default) {
25 return raw->language_entries.at(static_cast<u8>(language)); 35 return raw->language_entries.at(static_cast<u8>(language));
26 } else {
27 for (const auto& language_entry : raw->language_entries) {
28 if (!language_entry.GetApplicationName().empty())
29 return language_entry;
30 }
31
32 // Fallback to English
33 return GetLanguageEntry(Language::AmericanEnglish);
34 } 36 }
37
38 for (const auto& language_entry : raw->language_entries) {
39 if (!language_entry.GetApplicationName().empty())
40 return language_entry;
41 }
42
43 // Fallback to English
44 return GetLanguageEntry(Language::AmericanEnglish);
35} 45}
36 46
37std::string NACP::GetApplicationName(Language language) const { 47std::string NACP::GetApplicationName(Language language) const {
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 8a510bf46..43d6f0719 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -66,18 +66,15 @@ enum class Language : u8 {
66 Default = 255, 66 Default = 255,
67}; 67};
68 68
69static constexpr std::array<const char*, 15> LANGUAGE_NAMES = { 69extern const std::array<const char*, 15> LANGUAGE_NAMES;
70 "AmericanEnglish", "BritishEnglish", "Japanese",
71 "French", "German", "LatinAmericanSpanish",
72 "Spanish", "Italian", "Dutch",
73 "CanadianFrench", "Portugese", "Russian",
74 "Korean", "Taiwanese", "Chinese"};
75 70
76// A class representing the format used by NX metadata files, typically named Control.nacp. 71// A class representing the format used by NX metadata files, typically named Control.nacp.
77// These store application name, dev name, title id, and other miscellaneous data. 72// These store application name, dev name, title id, and other miscellaneous data.
78class NACP { 73class NACP {
79public: 74public:
80 explicit NACP(VirtualFile file); 75 explicit NACP(VirtualFile file);
76 ~NACP();
77
81 const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const; 78 const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const;
82 std::string GetApplicationName(Language language = Language::Default) const; 79 std::string GetApplicationName(Language language = Language::Default) const;
83 std::string GetDeveloperName(Language language = Language::Default) const; 80 std::string GetDeveloperName(Language language = Language::Default) const;
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 479916b69..6f34b7836 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -51,6 +51,8 @@ CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentReco
51 : header(std::move(header)), opt_header(std::move(opt_header)), 51 : header(std::move(header)), opt_header(std::move(opt_header)),
52 content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} 52 content_records(std::move(content_records)), meta_records(std::move(meta_records)) {}
53 53
54CNMT::~CNMT() = default;
55
54u64 CNMT::GetTitleID() const { 56u64 CNMT::GetTitleID() const {
55 return header.title_id; 57 return header.title_id;
56} 58}
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index da5a8dbe8..a05d155f4 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -87,6 +87,7 @@ public:
87 explicit CNMT(VirtualFile file); 87 explicit CNMT(VirtualFile file);
88 CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, 88 CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
89 std::vector<MetaRecord> meta_records); 89 std::vector<MetaRecord> meta_records);
90 ~CNMT();
90 91
91 u64 GetTitleID() const; 92 u64 GetTitleID() const;
92 u32 GetTitleVersion() const; 93 u32 GetTitleVersion() const;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index f5b3b0175..5791c76ff 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -72,6 +72,8 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
72 status = Loader::ResultStatus::Success; 72 status = Loader::ResultStatus::Success;
73} 73}
74 74
75PartitionFilesystem::~PartitionFilesystem() = default;
76
75Loader::ResultStatus PartitionFilesystem::GetStatus() const { 77Loader::ResultStatus PartitionFilesystem::GetStatus() const {
76 return status; 78 return status;
77} 79}
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index e80d2456b..739c63a7f 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -25,6 +25,8 @@ namespace FileSys {
25class PartitionFilesystem : public ReadOnlyVfsDirectory { 25class PartitionFilesystem : public ReadOnlyVfsDirectory {
26public: 26public:
27 explicit PartitionFilesystem(std::shared_ptr<VfsFile> file); 27 explicit PartitionFilesystem(std::shared_ptr<VfsFile> file);
28 ~PartitionFilesystem() override;
29
28 Loader::ResultStatus GetStatus() const; 30 Loader::ResultStatus GetStatus() const;
29 31
30 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 32 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index b37b4c68b..aebc69d52 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -41,6 +41,8 @@ std::string FormatPatchTypeName(PatchType type) {
41 41
42PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} 42PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
43 43
44PatchManager::~PatchManager() = default;
45
44VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { 46VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
45 LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id); 47 LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
46 48
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index b521977b2..209cab1dc 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -34,6 +34,7 @@ std::string FormatPatchTypeName(PatchType type);
34class PatchManager { 34class PatchManager {
35public: 35public:
36 explicit PatchManager(u64 title_id); 36 explicit PatchManager(u64 title_id);
37 ~PatchManager();
37 38
38 // Currently tracked ExeFS patches: 39 // Currently tracked ExeFS patches:
39 // - Game Updates 40 // - Game Updates
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 9d19aaa6d..02319ce0f 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -12,6 +12,10 @@
12 12
13namespace FileSys { 13namespace FileSys {
14 14
15ProgramMetadata::ProgramMetadata() = default;
16
17ProgramMetadata::~ProgramMetadata() = default;
18
15Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { 19Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
16 std::size_t total_size = static_cast<std::size_t>(file->GetSize()); 20 std::size_t total_size = static_cast<std::size_t>(file->GetSize());
17 if (total_size < sizeof(Header)) 21 if (total_size < sizeof(Header))
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 3c0a49f16..1143e36c4 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -36,6 +36,9 @@ enum class ProgramFilePermission : u64 {
36 */ 36 */
37class ProgramMetadata { 37class ProgramMetadata {
38public: 38public:
39 ProgramMetadata();
40 ~ProgramMetadata();
41
39 Loader::ResultStatus Load(VirtualFile file); 42 Loader::ResultStatus Load(VirtualFile file);
40 43
41 bool Is64BitProgram() const; 44 bool Is64BitProgram() const;
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index d9d90939e..3d1a3685e 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -28,6 +28,8 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
28 ivfc_offset = app_loader.ReadRomFSIVFCOffset(); 28 ivfc_offset = app_loader.ReadRomFSIVFCOffset();
29} 29}
30 30
31RomFSFactory::~RomFSFactory() = default;
32
31ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { 33ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
32 if (!updatable) 34 if (!updatable)
33 return MakeResult<VirtualFile>(file); 35 return MakeResult<VirtualFile>(file);
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index 26b8f46cc..2cace8180 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -30,6 +30,7 @@ enum class StorageId : u8 {
30class RomFSFactory { 30class RomFSFactory {
31public: 31public:
32 explicit RomFSFactory(Loader::AppLoader& app_loader); 32 explicit RomFSFactory(Loader::AppLoader& app_loader);
33 ~RomFSFactory();
33 34
34 ResultVal<VirtualFile> OpenCurrentProcess(); 35 ResultVal<VirtualFile> OpenCurrentProcess();
35 ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type); 36 ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index e437d34e5..9b2c51bbd 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -20,6 +20,8 @@ std::string SaveDataDescriptor::DebugInfo() const {
20 20
21SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {} 21SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {}
22 22
23SaveDataFactory::~SaveDataFactory() = default;
24
23ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) { 25ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) {
24 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) { 26 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
25 if (meta.zero_1 != 0) { 27 if (meta.zero_1 != 0) {
@@ -85,10 +87,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
85 87
86 switch (space) { 88 switch (space) {
87 case SaveDataSpaceId::NandSystem: 89 case SaveDataSpaceId::NandSystem:
88 out = "/system/save/"; 90 out = "/system/";
89 break; 91 break;
90 case SaveDataSpaceId::NandUser: 92 case SaveDataSpaceId::NandUser:
91 out = "/user/save/"; 93 out = "/user/";
92 break; 94 break;
93 default: 95 default:
94 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); 96 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@@ -96,9 +98,12 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
96 98
97 switch (type) { 99 switch (type) {
98 case SaveDataType::SystemSaveData: 100 case SaveDataType::SystemSaveData:
99 return fmt::format("{}{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); 101 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
100 case SaveDataType::SaveData: 102 case SaveDataType::SaveData:
101 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 103 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
104 title_id);
105 case SaveDataType::TemporaryStorage:
106 return fmt::format("{}temp/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
102 title_id); 107 title_id);
103 default: 108 default:
104 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type)); 109 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index ba978695b..d69ef6741 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -48,6 +48,7 @@ static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorr
48class SaveDataFactory { 48class SaveDataFactory {
49public: 49public:
50 explicit SaveDataFactory(VirtualDir dir); 50 explicit SaveDataFactory(VirtualDir dir);
51 ~SaveDataFactory();
51 52
52 ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); 53 ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
53 54
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 1120a4920..e85a2b76e 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -24,7 +24,7 @@ enum class ContentRecordType : u8;
24class NSP : public ReadOnlyVfsDirectory { 24class NSP : public ReadOnlyVfsDirectory {
25public: 25public:
26 explicit NSP(VirtualFile file); 26 explicit NSP(VirtualFile file);
27 ~NSP(); 27 ~NSP() override;
28 28
29 Loader::ResultStatus GetStatus() const; 29 Loader::ResultStatus GetStatus() const;
30 Loader::ResultStatus GetProgramStatus(u64 title_id) const; 30 Loader::ResultStatus GetProgramStatus(u64 title_id) const;
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index 25a980cbb..dc7a279a9 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -27,6 +27,8 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s
27 } 27 }
28} 28}
29 29
30ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
31
30std::string ConcatenatedVfsFile::GetName() const { 32std::string ConcatenatedVfsFile::GetName() const {
31 if (files.empty()) 33 if (files.empty())
32 return ""; 34 return "";
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 31775db7e..717d04bdc 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -22,6 +22,8 @@ class ConcatenatedVfsFile : public VfsFile {
22 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); 22 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
23 23
24public: 24public:
25 ~ConcatenatedVfsFile() override;
26
25 std::string GetName() const override; 27 std::string GetName() const override;
26 std::size_t GetSize() const override; 28 std::size_t GetSize() const override;
27 bool Resize(std::size_t new_size) override; 29 bool Resize(std::size_t new_size) override;
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index f5ed291ea..a4c6719a0 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -14,6 +14,8 @@ OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_,
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_)) {}
16 16
17OffsetVfsFile::~OffsetVfsFile() = default;
18
17std::string OffsetVfsFile::GetName() const { 19std::string OffsetVfsFile::GetName() const {
18 return name.empty() ? file->GetName() : name; 20 return name.empty() ? file->GetName() : name;
19} 21}
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index 34cb180b3..8062702a7 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -19,6 +19,7 @@ class OffsetVfsFile : public VfsFile {
19public: 19public:
20 OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::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 ~OffsetVfsFile() override;
22 23
23 std::string GetName() const override; 24 std::string GetName() const override;
24 std::size_t GetSize() const override; 25 std::size_t GetSize() const override;
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 98e7c4598..ec7f735b5 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -13,6 +13,8 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
13 : files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)), 13 : files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)),
14 name(std::move(name_)) {} 14 name(std::move(name_)) {}
15 15
16VectorVfsDirectory::~VectorVfsDirectory() = default;
17
16std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const { 18std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const {
17 return files; 19 return files;
18} 20}
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 179f62e4b..cba44a7a6 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -15,6 +15,7 @@ public:
15 explicit VectorVfsDirectory(std::vector<VirtualFile> files = {}, 15 explicit VectorVfsDirectory(std::vector<VirtualFile> files = {},
16 std::vector<VirtualDir> dirs = {}, std::string name = "", 16 std::vector<VirtualDir> dirs = {}, std::string name = "",
17 VirtualDir parent = nullptr); 17 VirtualDir parent = nullptr);
18 ~VectorVfsDirectory() override;
18 19
19 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 20 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
20 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 21 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index 0173f71c1..b2b164368 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -30,9 +30,6 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
30 mbedtls_md_context_t context; 30 mbedtls_md_context_t context;
31 mbedtls_md_init(&context); 31 mbedtls_md_init(&context);
32 32
33 const auto key_f = reinterpret_cast<const u8*>(key);
34 const std::vector<u8> key_v(key_f, key_f + key_length);
35
36 if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) || 33 if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
37 mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) || 34 mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) ||
38 mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) || 35 mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) ||
@@ -45,7 +42,7 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
45 return true; 42 return true;
46} 43}
47 44
48NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NAXHeader>()) { 45NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
49 std::string path = FileUtil::SanitizePath(file->GetFullPath()); 46 std::string path = FileUtil::SanitizePath(file->GetFullPath());
50 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca", 47 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
51 std::regex_constants::ECMAScript | 48 std::regex_constants::ECMAScript |
@@ -65,13 +62,15 @@ NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NA
65} 62}
66 63
67NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id) 64NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
68 : file(std::move(file_)), header(std::make_unique<NAXHeader>()) { 65 : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
69 Core::Crypto::SHA256Hash hash{}; 66 Core::Crypto::SHA256Hash hash{};
70 mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); 67 mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
71 status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0], 68 status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
72 Common::HexArrayToString(nca_id, false))); 69 Common::HexArrayToString(nca_id, false)));
73} 70}
74 71
72NAX::~NAX() = default;
73
75Loader::ResultStatus NAX::Parse(std::string_view path) { 74Loader::ResultStatus NAX::Parse(std::string_view path) {
76 if (file->ReadObject(header.get()) != sizeof(NAXHeader)) 75 if (file->ReadObject(header.get()) != sizeof(NAXHeader))
77 return Loader::ResultStatus::ErrorBadNAXHeader; 76 return Loader::ResultStatus::ErrorBadNAXHeader;
@@ -138,9 +137,9 @@ VirtualFile NAX::GetDecrypted() const {
138 return dec_file; 137 return dec_file;
139} 138}
140 139
141std::shared_ptr<NCA> NAX::AsNCA() const { 140std::unique_ptr<NCA> NAX::AsNCA() const {
142 if (type == NAXContentType::NCA) 141 if (type == NAXContentType::NCA)
143 return std::make_shared<NCA>(GetDecrypted()); 142 return std::make_unique<NCA>(GetDecrypted());
144 return nullptr; 143 return nullptr;
145} 144}
146 145
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index 55d2154a6..8fedd8585 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -33,12 +33,13 @@ class NAX : public ReadOnlyVfsDirectory {
33public: 33public:
34 explicit NAX(VirtualFile file); 34 explicit NAX(VirtualFile file);
35 explicit NAX(VirtualFile file, std::array<u8, 0x10> nca_id); 35 explicit NAX(VirtualFile file, std::array<u8, 0x10> nca_id);
36 ~NAX() override;
36 37
37 Loader::ResultStatus GetStatus() const; 38 Loader::ResultStatus GetStatus() const;
38 39
39 VirtualFile GetDecrypted() const; 40 VirtualFile GetDecrypted() const;
40 41
41 std::shared_ptr<NCA> AsNCA() const; 42 std::unique_ptr<NCA> AsNCA() const;
42 43
43 NAXContentType GetContentType() const; 44 NAXContentType GetContentType() const;
44 45
@@ -60,7 +61,7 @@ private:
60 61
61 VirtualFile file; 62 VirtualFile file;
62 Loader::ResultStatus status; 63 Loader::ResultStatus status;
63 NAXContentType type; 64 NAXContentType type{};
64 65
65 VirtualFile dec_file; 66 VirtualFile dec_file;
66 67
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 1b04f68bf..0ecdd9f82 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -995,7 +995,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
995 breakpoint.addr = addr; 995 breakpoint.addr = addr;
996 breakpoint.len = len; 996 breakpoint.len = len;
997 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); 997 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
998 static constexpr std::array<u8, 4> btrap{{0xd4, 0x20, 0x7d, 0x0}}; 998 static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}};
999 Memory::WriteBlock(addr, btrap.data(), btrap.size()); 999 Memory::WriteBlock(addr, btrap.data(), btrap.size());
1000 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 1000 Core::System::GetInstance().InvalidateCpuInstructionCaches();
1001 p.insert({addr, breakpoint}); 1001 p.insert({addr, breakpoint});
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 7545ecf2a..a4bfe2eb0 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -290,13 +290,6 @@ public:
290 Skip(CommandIdSize, false); 290 Skip(CommandIdSize, false);
291 } 291 }
292 292
293 ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
294 u32 num_handles_to_move,
295 ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) const {
296 return ResponseBuilder{*context, normal_params_size, num_handles_to_copy,
297 num_handles_to_move, flags};
298 }
299
300 template <typename T> 293 template <typename T>
301 T Pop(); 294 T Pop();
302 295
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 51f4544be..81675eac5 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/object.h" 16#include "core/hle/kernel/object.h"
17#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
18#include "core/hle/result.h" 18#include "core/hle/result.h"
19#include "core/memory.h"
19 20
20namespace Kernel { 21namespace Kernel {
21 22
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 7a272d031..121f741fd 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -7,10 +7,12 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h"
10#include "core/hle/kernel/errors.h" 11#include "core/hle/kernel/errors.h"
11#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/resource_limit.h" 14#include "core/hle/kernel/resource_limit.h"
15#include "core/hle/kernel/scheduler.h"
14#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
15#include "core/hle/kernel/vm_manager.h" 17#include "core/hle/kernel/vm_manager.h"
16#include "core/memory.h" 18#include "core/memory.h"
@@ -125,7 +127,92 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
125 vm_manager.LogLayout(); 127 vm_manager.LogLayout();
126 status = ProcessStatus::Running; 128 status = ProcessStatus::Running;
127 129
128 Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, this); 130 Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
131}
132
133void Process::PrepareForTermination() {
134 status = ProcessStatus::Exited;
135
136 const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
137 for (auto& thread : thread_list) {
138 if (thread->owner_process != this)
139 continue;
140
141 if (thread == GetCurrentThread())
142 continue;
143
144 // TODO(Subv): When are the other running/ready threads terminated?
145 ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
146 thread->status == ThreadStatus::WaitSynchAll,
147 "Exiting processes with non-waiting threads is currently unimplemented");
148
149 thread->Stop();
150 }
151 };
152
153 auto& system = Core::System::GetInstance();
154 stop_threads(system.Scheduler(0)->GetThreadList());
155 stop_threads(system.Scheduler(1)->GetThreadList());
156 stop_threads(system.Scheduler(2)->GetThreadList());
157 stop_threads(system.Scheduler(3)->GetThreadList());
158}
159
160/**
161 * Finds a free location for the TLS section of a thread.
162 * @param tls_slots The TLS page array of the thread's owner process.
163 * Returns a tuple of (page, slot, alloc_needed) where:
164 * page: The index of the first allocated TLS page that has free slots.
165 * slot: The index of the first free slot in the indicated page.
166 * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
167 */
168static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
169 const std::vector<std::bitset<8>>& tls_slots) {
170 // Iterate over all the allocated pages, and try to find one where not all slots are used.
171 for (std::size_t page = 0; page < tls_slots.size(); ++page) {
172 const auto& page_tls_slots = tls_slots[page];
173 if (!page_tls_slots.all()) {
174 // We found a page with at least one free slot, find which slot it is
175 for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
176 if (!page_tls_slots.test(slot)) {
177 return std::make_tuple(page, slot, false);
178 }
179 }
180 }
181 }
182
183 return std::make_tuple(0, 0, true);
184}
185
186VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
187 auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
188
189 if (needs_allocation) {
190 tls_slots.emplace_back(0); // The page is completely available at the start
191 available_page = tls_slots.size() - 1;
192 available_slot = 0; // Use the first slot in the new page
193
194 // Allocate some memory from the end of the linear heap for this region.
195 auto& tls_memory = thread.GetTLSMemory();
196 tls_memory->insert(tls_memory->end(), Memory::PAGE_SIZE, 0);
197
198 vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
199
200 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
201 tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal);
202 }
203
204 tls_slots[available_page].set(available_slot);
205
206 return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
207 available_slot * Memory::TLS_ENTRY_SIZE;
208}
209
210void Process::FreeTLSSlot(VAddr tls_address) {
211 const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR;
212 const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
213 const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
214
215 tls_slots[tls_page].reset(tls_slot);
129} 216}
130 217
131void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { 218void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 81538f70c..04d74e572 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -131,6 +131,16 @@ public:
131 return HANDLE_TYPE; 131 return HANDLE_TYPE;
132 } 132 }
133 133
134 /// Gets the current status of the process
135 ProcessStatus GetStatus() const {
136 return status;
137 }
138
139 /// Gets the unique ID that identifies this particular process.
140 u32 GetProcessID() const {
141 return process_id;
142 }
143
134 /// Title ID corresponding to the process 144 /// Title ID corresponding to the process
135 u64 program_id; 145 u64 program_id;
136 146
@@ -154,11 +164,6 @@ public:
154 u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; 164 u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
155 u32 allowed_thread_priority_mask = 0xFFFFFFFF; 165 u32 allowed_thread_priority_mask = 0xFFFFFFFF;
156 u32 is_virtual_address_memory_enabled = 0; 166 u32 is_virtual_address_memory_enabled = 0;
157 /// Current status of the process
158 ProcessStatus status;
159
160 /// The ID of this process
161 u32 process_id = 0;
162 167
163 /** 168 /**
164 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them 169 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -171,13 +176,42 @@ public:
171 */ 176 */
172 void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size); 177 void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
173 178
179 /**
180 * Prepares a process for termination by stopping all of its threads
181 * and clearing any other resources.
182 */
183 void PrepareForTermination();
184
174 void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr); 185 void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr);
175 186
176 /////////////////////////////////////////////////////////////////////////////////////////////// 187 ///////////////////////////////////////////////////////////////////////////////////////////////
177 // Memory Management 188 // Memory Management
178 189
190 // Marks the next available region as used and returns the address of the slot.
191 VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
192
193 // Frees a used TLS slot identified by the given address
194 void FreeTLSSlot(VAddr tls_address);
195
196 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
197 ResultCode HeapFree(VAddr target, u32 size);
198
199 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
200
201 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
202
179 VMManager vm_manager; 203 VMManager vm_manager;
180 204
205private:
206 explicit Process(KernelCore& kernel);
207 ~Process() override;
208
209 /// Current status of the process
210 ProcessStatus status;
211
212 /// The ID of this process
213 u32 process_id = 0;
214
181 // Memory used to back the allocations in the regular heap. A single vector is used to cover 215 // Memory used to back the allocations in the regular heap. A single vector is used to cover
182 // the entire virtual address space extents that bound the allocations, including any holes. 216 // the entire virtual address space extents that bound the allocations, including any holes.
183 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous 217 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
@@ -197,17 +231,6 @@ public:
197 std::vector<std::bitset<8>> tls_slots; 231 std::vector<std::bitset<8>> tls_slots;
198 232
199 std::string name; 233 std::string name;
200
201 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
202 ResultCode HeapFree(VAddr target, u32 size);
203
204 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
205
206 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
207
208private:
209 explicit Process(KernelCore& kernel);
210 ~Process() override;
211}; 234};
212 235
213} // namespace Kernel 236} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 371fc439e..0bc407098 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -169,7 +169,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
169 return ERR_INVALID_HANDLE; 169 return ERR_INVALID_HANDLE;
170 } 170 }
171 171
172 *process_id = process->process_id; 172 *process_id = process->GetProcessID();
173 return RESULT_SUCCESS; 173 return RESULT_SUCCESS;
174} 174}
175 175
@@ -530,35 +530,13 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd
530 530
531/// Exits the current process 531/// Exits the current process
532static void ExitProcess() { 532static void ExitProcess() {
533 LOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id); 533 auto& current_process = Core::CurrentProcess();
534 534
535 ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running, 535 LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
536 ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
536 "Process has already exited"); 537 "Process has already exited");
537 538
538 Core::CurrentProcess()->status = ProcessStatus::Exited; 539 current_process->PrepareForTermination();
539
540 auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) {
541 for (auto& thread : thread_list) {
542 if (thread->owner_process != Core::CurrentProcess())
543 continue;
544
545 if (thread == GetCurrentThread())
546 continue;
547
548 // TODO(Subv): When are the other running/ready threads terminated?
549 ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
550 thread->status == ThreadStatus::WaitSynchAll,
551 "Exiting processes with non-waiting threads is currently unimplemented");
552
553 thread->Stop();
554 }
555 };
556
557 auto& system = Core::System::GetInstance();
558 stop_threads(system.Scheduler(0)->GetThreadList());
559 stop_threads(system.Scheduler(1)->GetThreadList());
560 stop_threads(system.Scheduler(2)->GetThreadList());
561 stop_threads(system.Scheduler(3)->GetThreadList());
562 540
563 // Kill the current thread 541 // Kill the current thread
564 GetCurrentThread()->Stop(); 542 GetCurrentThread()->Stop();
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index d4183d6e3..315f65338 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -65,10 +65,7 @@ void Thread::Stop() {
65 wait_objects.clear(); 65 wait_objects.clear();
66 66
67 // Mark the TLS slot in the thread's page as free. 67 // Mark the TLS slot in the thread's page as free.
68 const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; 68 owner_process->FreeTLSSlot(tls_address);
69 const u64 tls_slot =
70 ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
71 Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot);
72} 69}
73 70
74void WaitCurrentThread_Sleep() { 71void WaitCurrentThread_Sleep() {
@@ -178,32 +175,6 @@ void Thread::ResumeFromWait() {
178} 175}
179 176
180/** 177/**
181 * Finds a free location for the TLS section of a thread.
182 * @param tls_slots The TLS page array of the thread's owner process.
183 * Returns a tuple of (page, slot, alloc_needed) where:
184 * page: The index of the first allocated TLS page that has free slots.
185 * slot: The index of the first free slot in the indicated page.
186 * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
187 */
188static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
189 const std::vector<std::bitset<8>>& tls_slots) {
190 // Iterate over all the allocated pages, and try to find one where not all slots are used.
191 for (std::size_t page = 0; page < tls_slots.size(); ++page) {
192 const auto& page_tls_slots = tls_slots[page];
193 if (!page_tls_slots.all()) {
194 // We found a page with at least one free slot, find which slot it is
195 for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
196 if (!page_tls_slots.test(slot)) {
197 return std::make_tuple(page, slot, false);
198 }
199 }
200 }
201 }
202
203 return std::make_tuple(0, 0, true);
204}
205
206/**
207 * Resets a thread context, making it ready to be scheduled and run by the CPU 178 * Resets a thread context, making it ready to be scheduled and run by the CPU
208 * @param context Thread context to reset 179 * @param context Thread context to reset
209 * @param stack_top Address of the top of the stack 180 * @param stack_top Address of the top of the stack
@@ -264,32 +235,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
264 thread->owner_process = owner_process; 235 thread->owner_process = owner_process;
265 thread->scheduler = Core::System::GetInstance().Scheduler(processor_id); 236 thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
266 thread->scheduler->AddThread(thread, priority); 237 thread->scheduler->AddThread(thread, priority);
267 238 thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
268 // Find the next available TLS index, and mark it as used
269 auto& tls_slots = owner_process->tls_slots;
270
271 auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
272 if (needs_allocation) {
273 tls_slots.emplace_back(0); // The page is completely available at the start
274 available_page = tls_slots.size() - 1;
275 available_slot = 0; // Use the first slot in the new page
276
277 // Allocate some memory from the end of the linear heap for this region.
278 const std::size_t offset = thread->tls_memory->size();
279 thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0);
280
281 auto& vm_manager = owner_process->vm_manager;
282 vm_manager.RefreshMemoryBlockMappings(thread->tls_memory.get());
283
284 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
285 thread->tls_memory, 0, Memory::PAGE_SIZE,
286 MemoryState::ThreadLocal);
287 }
288
289 // Mark the slot as used
290 tls_slots[available_page].set(available_slot);
291 thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
292 available_slot * Memory::TLS_ENTRY_SIZE;
293 239
294 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used 240 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
295 // to initialize the context 241 // to initialize the context
@@ -311,13 +257,13 @@ void Thread::BoostPriority(u32 priority) {
311} 257}
312 258
313SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, 259SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
314 SharedPtr<Process> owner_process) { 260 Process& owner_process) {
315 // Setup page table so we can write to memory 261 // Setup page table so we can write to memory
316 SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); 262 SetCurrentPageTable(&owner_process.vm_manager.page_table);
317 263
318 // Initialize new "main" thread 264 // Initialize new "main" thread
319 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, 265 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
320 Memory::STACK_AREA_VADDR_END, std::move(owner_process)); 266 Memory::STACK_AREA_VADDR_END, &owner_process);
321 267
322 SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); 268 SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
323 269
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index df4748942..4250144c3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -62,6 +62,9 @@ enum class ThreadWakeupReason {
62 62
63class Thread final : public WaitObject { 63class Thread final : public WaitObject {
64public: 64public:
65 using TLSMemory = std::vector<u8>;
66 using TLSMemoryPtr = std::shared_ptr<TLSMemory>;
67
65 /** 68 /**
66 * Creates and returns a new thread. The new thread is immediately scheduled 69 * Creates and returns a new thread. The new thread is immediately scheduled
67 * @param kernel The kernel instance this thread will be created under. 70 * @param kernel The kernel instance this thread will be created under.
@@ -134,6 +137,14 @@ public:
134 return thread_id; 137 return thread_id;
135 } 138 }
136 139
140 TLSMemoryPtr& GetTLSMemory() {
141 return tls_memory;
142 }
143
144 const TLSMemoryPtr& GetTLSMemory() const {
145 return tls_memory;
146 }
147
137 /** 148 /**
138 * Resumes a thread from waiting 149 * Resumes a thread from waiting
139 */ 150 */
@@ -269,7 +280,7 @@ private:
269 explicit Thread(KernelCore& kernel); 280 explicit Thread(KernelCore& kernel);
270 ~Thread() override; 281 ~Thread() override;
271 282
272 std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>(); 283 TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>();
273}; 284};
274 285
275/** 286/**
@@ -281,7 +292,7 @@ private:
281 * @return A shared pointer to the main thread 292 * @return A shared pointer to the main thread
282 */ 293 */
283SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, 294SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
284 SharedPtr<Process> owner_process); 295 Process& owner_process);
285 296
286/** 297/**
287 * Gets the current thread 298 * Gets the current thread
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 4d4eb542e..e61748ca3 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -130,11 +130,10 @@ private:
130 130
131 void GetAccountId(Kernel::HLERequestContext& ctx) { 131 void GetAccountId(Kernel::HLERequestContext& ctx) {
132 LOG_WARNING(Service_ACC, "(STUBBED) called"); 132 LOG_WARNING(Service_ACC, "(STUBBED) called");
133 // TODO(Subv): Find out what this actually does and implement it. Stub it as an error for 133 // Should return a nintendo account ID
134 // now since we do not implement NNID. Returning a bogus id here will cause games to send 134 IPC::ResponseBuilder rb{ctx, 4};
135 // invalid IPC requests after ListOpenUsers is called. 135 rb.Push(RESULT_SUCCESS);
136 IPC::ResponseBuilder rb{ctx, 2}; 136 rb.PushRaw<u64>(1);
137 rb.Push(ResultCode(-1));
138 } 137 }
139}; 138};
140 139
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 9c975325a..69bfce1c1 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -462,7 +462,7 @@ private:
462 462
463 std::memcpy(&buffer[offset], data.data(), data.size()); 463 std::memcpy(&buffer[offset], data.data(), data.size());
464 464
465 IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; 465 IPC::ResponseBuilder rb{ctx, 2};
466 rb.Push(RESULT_SUCCESS); 466 rb.Push(RESULT_SUCCESS);
467 467
468 LOG_DEBUG(Service_AM, "called, offset={}", offset); 468 LOG_DEBUG(Service_AM, "called, offset={}", offset);
@@ -478,7 +478,7 @@ private:
478 478
479 ctx.WriteBuffer(buffer.data() + offset, size); 479 ctx.WriteBuffer(buffer.data() + offset, size);
480 480
481 IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; 481 IPC::ResponseBuilder rb{ctx, 2};
482 rb.Push(RESULT_SUCCESS); 482 rb.Push(RESULT_SUCCESS);
483 483
484 LOG_DEBUG(Service_AM, "called, offset={}", offset); 484 LOG_DEBUG(Service_AM, "called, offset={}", offset);
@@ -568,7 +568,7 @@ private:
568 IPC::RequestParser rp{ctx}; 568 IPC::RequestParser rp{ctx};
569 storage_stack.push(rp.PopIpcInterface<AM::IStorage>()); 569 storage_stack.push(rp.PopIpcInterface<AM::IStorage>());
570 570
571 IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; 571 IPC::ResponseBuilder rb{ctx, 2};
572 rb.Push(RESULT_SUCCESS); 572 rb.Push(RESULT_SUCCESS);
573 573
574 LOG_DEBUG(Service_AM, "called"); 574 LOG_DEBUG(Service_AM, "called");
@@ -616,7 +616,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
616 const u64 size{rp.Pop<u64>()}; 616 const u64 size{rp.Pop<u64>()};
617 std::vector<u8> buffer(size); 617 std::vector<u8> buffer(size);
618 618
619 IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 1)}; 619 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
620 rb.Push(RESULT_SUCCESS); 620 rb.Push(RESULT_SUCCESS);
621 rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); 621 rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
622 622
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 80a002322..ff1edefbb 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -190,7 +190,7 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
190 190
191 ctx.WriteBuffer(DefaultDevice); 191 ctx.WriteBuffer(DefaultDevice);
192 192
193 IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); 193 IPC::ResponseBuilder rb{ctx, 3};
194 194
195 rb.Push(RESULT_SUCCESS); 195 rb.Push(RESULT_SUCCESS);
196 rb.Push<u32>(1); // Amount of audio devices 196 rb.Push<u32>(1); // Amount of audio devices
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index e84c4fa2b..80ed4b152 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -25,7 +25,7 @@ public:
25 {0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"}, 25 {0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"},
26 {1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"}, 26 {1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"},
27 {2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"}, 27 {2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"},
28 {3, nullptr, "GetAudioRendererState"}, 28 {3, &IAudioRenderer::GetAudioRendererState, "GetAudioRendererState"},
29 {4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"}, 29 {4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
30 {5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"}, 30 {5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
31 {6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"}, 31 {6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
@@ -62,6 +62,13 @@ private:
62 LOG_DEBUG(Service_Audio, "called"); 62 LOG_DEBUG(Service_Audio, "called");
63 } 63 }
64 64
65 void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
66 IPC::ResponseBuilder rb{ctx, 3};
67 rb.Push(RESULT_SUCCESS);
68 rb.Push<u32>(renderer->GetState());
69 LOG_DEBUG(Service_Audio, "called");
70 }
71
65 void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) { 72 void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) {
66 IPC::ResponseBuilder rb{ctx, 3}; 73 IPC::ResponseBuilder rb{ctx, 3};
67 rb.Push(RESULT_SUCCESS); 74 rb.Push(RESULT_SUCCESS);
@@ -137,7 +144,7 @@ private:
137 constexpr std::array<char, 15> audio_interface{{"AudioInterface"}}; 144 constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
138 ctx.WriteBuffer(audio_interface); 145 ctx.WriteBuffer(audio_interface);
139 146
140 IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); 147 IPC::ResponseBuilder rb{ctx, 3};
141 rb.Push(RESULT_SUCCESS); 148 rb.Push(RESULT_SUCCESS);
142 rb.Push<u32>(1); 149 rb.Push<u32>(1);
143 } 150 }
@@ -151,7 +158,7 @@ private:
151 auto file_buffer = ctx.ReadBuffer(); 158 auto file_buffer = ctx.ReadBuffer();
152 auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); 159 auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
153 160
154 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 161 IPC::ResponseBuilder rb{ctx, 2};
155 rb.Push(RESULT_SUCCESS); 162 rb.Push(RESULT_SUCCESS);
156 } 163 }
157 164
@@ -162,7 +169,7 @@ private:
162 constexpr std::array<char, 12> audio_interface{{"AudioDevice"}}; 169 constexpr std::array<char, 12> audio_interface{{"AudioDevice"}};
163 ctx.WriteBuffer(audio_interface); 170 ctx.WriteBuffer(audio_interface);
164 171
165 IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); 172 IPC::ResponseBuilder rb{ctx, 3};
166 rb.Push(RESULT_SUCCESS); 173 rb.Push(RESULT_SUCCESS);
167 rb.Push<u32>(1); 174 rb.Push<u32>(1);
168 } 175 }
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 5c4971724..d349ee686 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -197,7 +197,7 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
197 auto dir = GetDirectoryRelativeWrapped(backing, path); 197 auto dir = GetDirectoryRelativeWrapped(backing, path);
198 if (dir == nullptr) { 198 if (dir == nullptr) {
199 // TODO(DarkLordZach): Find a better error code for this 199 // TODO(DarkLordZach): Find a better error code for this
200 return ResultCode(-1); 200 return FileSys::ERROR_PATH_NOT_FOUND;
201 } 201 }
202 return MakeResult(dir); 202 return MakeResult(dir);
203} 203}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 256c49bfc..7c6b0a4e6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -338,7 +338,7 @@ public:
338 {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, 338 {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
339 {107, &Hid::DisconnectNpad, "DisconnectNpad"}, 339 {107, &Hid::DisconnectNpad, "DisconnectNpad"},
340 {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, 340 {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
341 {109, nullptr, "ActivateNpadWithRevision"}, 341 {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
342 {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, 342 {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
343 {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, 343 {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
344 {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, 344 {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
@@ -603,6 +603,12 @@ private:
603 rb.Push(RESULT_SUCCESS); 603 rb.Push(RESULT_SUCCESS);
604 LOG_WARNING(Service_HID, "(STUBBED) called"); 604 LOG_WARNING(Service_HID, "(STUBBED) called");
605 } 605 }
606
607 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
608 IPC::ResponseBuilder rb{ctx, 2};
609 rb.Push(RESULT_SUCCESS);
610 LOG_WARNING(Service_HID, "(STUBBED) called");
611 }
606}; 612};
607 613
608class HidDbg final : public ServiceFramework<HidDbg> { 614class HidDbg final : public ServiceFramework<HidDbg> {
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index ed4f5f539..10611ed6a 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -31,7 +31,7 @@ public:
31 {1, &IRequest::GetResult, "GetResult"}, 31 {1, &IRequest::GetResult, "GetResult"},
32 {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"}, 32 {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"},
33 {3, &IRequest::Cancel, "Cancel"}, 33 {3, &IRequest::Cancel, "Cancel"},
34 {4, nullptr, "Submit"}, 34 {4, &IRequest::Submit, "Submit"},
35 {5, nullptr, "SetRequirement"}, 35 {5, nullptr, "SetRequirement"},
36 {6, nullptr, "SetRequirementPreset"}, 36 {6, nullptr, "SetRequirementPreset"},
37 {8, nullptr, "SetPriority"}, 37 {8, nullptr, "SetPriority"},
@@ -61,6 +61,12 @@ public:
61 } 61 }
62 62
63private: 63private:
64 void Submit(Kernel::HLERequestContext& ctx) {
65 LOG_WARNING(Service_NIFM, "(STUBBED) called");
66 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(RESULT_SUCCESS);
68 }
69
64 void GetRequestState(Kernel::HLERequestContext& ctx) { 70 void GetRequestState(Kernel::HLERequestContext& ctx) {
65 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 71 LOG_WARNING(Service_NIFM, "(STUBBED) called");
66 IPC::ResponseBuilder rb{ctx, 3}; 72 IPC::ResponseBuilder rb{ctx, 3};
@@ -114,10 +120,11 @@ public:
114 120
115private: 121private:
116 void GetClientId(Kernel::HLERequestContext& ctx) { 122 void GetClientId(Kernel::HLERequestContext& ctx) {
123 static constexpr u32 client_id = 1;
117 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 124 LOG_WARNING(Service_NIFM, "(STUBBED) called");
118 IPC::ResponseBuilder rb{ctx, 4}; 125 IPC::ResponseBuilder rb{ctx, 4};
119 rb.Push(RESULT_SUCCESS); 126 rb.Push(RESULT_SUCCESS);
120 rb.Push<u64>(0); 127 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
121 } 128 }
122 void CreateScanRequest(Kernel::HLERequestContext& ctx) { 129 void CreateScanRequest(Kernel::HLERequestContext& ctx) {
123 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 130 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -141,10 +148,16 @@ private:
141 rb.Push(RESULT_SUCCESS); 148 rb.Push(RESULT_SUCCESS);
142 } 149 }
143 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 150 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
144 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 151 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size");
152 u128 uuid{};
153 auto buffer = ctx.ReadBuffer();
154 std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
155
156 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
145 157
146 rb.Push(RESULT_SUCCESS); 158 rb.Push(RESULT_SUCCESS);
147 rb.PushIpcInterface<INetworkProfile>(); 159 rb.PushIpcInterface<INetworkProfile>();
160 rb.PushRaw<u128>(uuid);
148 161
149 LOG_DEBUG(Service_NIFM, "called"); 162 LOG_DEBUG(Service_NIFM, "called");
150 } 163 }
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index bd05b0a70..c1737defa 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.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 <chrono>
6#include <ctime>
7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/event.h"
5#include "core/hle/service/nim/nim.h" 9#include "core/hle/service/nim/nim.h"
6#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
7#include "core/hle/service/sm/sm.h" 11#include "core/hle/service/sm/sm.h"
@@ -100,19 +104,111 @@ public:
100 } 104 }
101}; 105};
102 106
107class IEnsureNetworkClockAvailabilityService final
108 : public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
109public:
110 IEnsureNetworkClockAvailabilityService()
111 : ServiceFramework("IEnsureNetworkClockAvailabilityService") {
112 static const FunctionInfo functions[] = {
113 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
114 {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent,
115 "GetFinishNotificationEvent"},
116 {2, &IEnsureNetworkClockAvailabilityService::GetResult, "GetResult"},
117 {3, &IEnsureNetworkClockAvailabilityService::Cancel, "Cancel"},
118 {4, &IEnsureNetworkClockAvailabilityService::IsProcessing, "IsProcessing"},
119 {5, &IEnsureNetworkClockAvailabilityService::GetServerTime, "GetServerTime"},
120 };
121 RegisterHandlers(functions);
122
123 auto& kernel = Core::System::GetInstance().Kernel();
124 finished_event =
125 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
126 "IEnsureNetworkClockAvailabilityService:FinishEvent");
127 }
128
129private:
130 Kernel::SharedPtr<Kernel::Event> finished_event;
131
132 void StartTask(Kernel::HLERequestContext& ctx) {
133 // No need to connect to the internet, just finish the task straight away.
134 finished_event->Signal();
135 IPC::ResponseBuilder rb{ctx, 2};
136 rb.Push(RESULT_SUCCESS);
137 LOG_DEBUG(Service_NIM, "called");
138 }
139
140 void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
141 IPC::ResponseBuilder rb{ctx, 2, 1};
142 rb.Push(RESULT_SUCCESS);
143 rb.PushCopyObjects(finished_event);
144 LOG_DEBUG(Service_NIM, "called");
145 }
146
147 void GetResult(Kernel::HLERequestContext& ctx) {
148 IPC::ResponseBuilder rb{ctx, 2};
149 rb.Push(RESULT_SUCCESS);
150 LOG_DEBUG(Service_NIM, "called");
151 }
152
153 void Cancel(Kernel::HLERequestContext& ctx) {
154 finished_event->Clear();
155 IPC::ResponseBuilder rb{ctx, 2};
156 rb.Push(RESULT_SUCCESS);
157 LOG_DEBUG(Service_NIM, "called");
158 }
159
160 void IsProcessing(Kernel::HLERequestContext& ctx) {
161 IPC::ResponseBuilder rb{ctx, 3};
162 rb.Push(RESULT_SUCCESS);
163 rb.PushRaw<u32>(0); // We instantly process the request
164 LOG_DEBUG(Service_NIM, "called");
165 }
166
167 void GetServerTime(Kernel::HLERequestContext& ctx) {
168 const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
169 std::chrono::system_clock::now().time_since_epoch())
170 .count()};
171 IPC::ResponseBuilder rb{ctx, 4};
172 rb.Push(RESULT_SUCCESS);
173 rb.PushRaw<s64>(server_time);
174 LOG_DEBUG(Service_NIM, "called");
175 }
176};
177
103class NTC final : public ServiceFramework<NTC> { 178class NTC final : public ServiceFramework<NTC> {
104public: 179public:
105 explicit NTC() : ServiceFramework{"ntc"} { 180 explicit NTC() : ServiceFramework{"ntc"} {
106 // clang-format off 181 // clang-format off
107 static const FunctionInfo functions[] = { 182 static const FunctionInfo functions[] = {
108 {0, nullptr, "OpenEnsureNetworkClockAvailabilityService"}, 183 {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"},
109 {100, nullptr, "SuspendAutonomicTimeCorrection"}, 184 {100, &NTC::SuspendAutonomicTimeCorrection, "SuspendAutonomicTimeCorrection"},
110 {101, nullptr, "ResumeAutonomicTimeCorrection"}, 185 {101, &NTC::ResumeAutonomicTimeCorrection, "ResumeAutonomicTimeCorrection"},
111 }; 186 };
112 // clang-format on 187 // clang-format on
113 188
114 RegisterHandlers(functions); 189 RegisterHandlers(functions);
115 } 190 }
191
192private:
193 void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
194 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
195 rb.Push(RESULT_SUCCESS);
196 rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
197 LOG_DEBUG(Service_NIM, "called");
198 }
199
200 // TODO(ogniK): Do we need these?
201 void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
202 IPC::ResponseBuilder rb{ctx, 2};
203 rb.Push(RESULT_SUCCESS);
204 LOG_WARNING(Service_NIM, "(STUBBED) called");
205 }
206
207 void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
208 IPC::ResponseBuilder rb{ctx, 2};
209 rb.Push(RESULT_SUCCESS);
210 LOG_WARNING(Service_NIM, "(STUBBED) called");
211 }
116}; 212};
117 213
118void InstallInterfaces(SM::ServiceManager& sm) { 214void InstallInterfaces(SM::ServiceManager& sm) {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 096f0fd52..464e79d01 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -108,7 +108,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
108 108
109 auto client_port = service_manager->GetServicePort(name); 109 auto client_port = service_manager->GetServicePort(name);
110 if (client_port.Failed()) { 110 if (client_port.Failed()) {
111 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 111 IPC::ResponseBuilder rb{ctx, 2};
112 rb.Push(client_port.Code()); 112 rb.Push(client_port.Code());
113 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); 113 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw);
114 if (name.length() == 0) 114 if (name.length() == 0)
@@ -121,8 +121,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
121 ASSERT(session.Succeeded()); 121 ASSERT(session.Succeeded());
122 if (session.Succeeded()) { 122 if (session.Succeeded()) {
123 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); 123 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId());
124 IPC::ResponseBuilder rb = 124 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
125 rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles);
126 rb.Push(session.Code()); 125 rb.Push(session.Code());
127 rb.PushMoveObjects(std::move(session).Unwrap()); 126 rb.PushMoveObjects(std::move(session).Unwrap());
128 } 127 }
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index bb5f5b321..bc4f7a437 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -71,7 +71,7 @@ private:
71 LOG_WARNING(Service_SSL, "(STUBBED) called"); 71 LOG_WARNING(Service_SSL, "(STUBBED) called");
72 IPC::RequestParser rp{ctx}; 72 IPC::RequestParser rp{ctx};
73 73
74 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(RESULT_SUCCESS); 75 rb.Push(RESULT_SUCCESS);
76 } 76 }
77 77
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d0cde5ede..2ee60f1ec 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -650,7 +650,7 @@ private:
650 u64 layer_id = rp.Pop<u64>(); 650 u64 layer_id = rp.Pop<u64>();
651 u64 z_value = rp.Pop<u64>(); 651 u64 z_value = rp.Pop<u64>();
652 652
653 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 653 IPC::ResponseBuilder rb{ctx, 2};
654 rb.Push(RESULT_SUCCESS); 654 rb.Push(RESULT_SUCCESS);
655 } 655 }
656 656
@@ -658,7 +658,7 @@ private:
658 IPC::RequestParser rp{ctx}; 658 IPC::RequestParser rp{ctx};
659 u64 layer_id = rp.Pop<u64>(); 659 u64 layer_id = rp.Pop<u64>();
660 bool visibility = rp.Pop<bool>(); 660 bool visibility = rp.Pop<bool>();
661 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 661 IPC::ResponseBuilder rb{ctx, 2};
662 rb.Push(RESULT_SUCCESS); 662 rb.Push(RESULT_SUCCESS);
663 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, 663 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
664 visibility); 664 visibility);
@@ -747,7 +747,7 @@ private:
747 IPC::RequestParser rp{ctx}; 747 IPC::RequestParser rp{ctx};
748 u64 display = rp.Pop<u64>(); 748 u64 display = rp.Pop<u64>();
749 749
750 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 750 IPC::ResponseBuilder rb{ctx, 2};
751 rb.Push(RESULT_SUCCESS); 751 rb.Push(RESULT_SUCCESS);
752 } 752 }
753 753
@@ -761,7 +761,7 @@ private:
761 761
762 u64 layer_id = nv_flinger->CreateLayer(display); 762 u64 layer_id = nv_flinger->CreateLayer(display);
763 763
764 IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); 764 IPC::ResponseBuilder rb{ctx, 4};
765 rb.Push(RESULT_SUCCESS); 765 rb.Push(RESULT_SUCCESS);
766 rb.Push(layer_id); 766 rb.Push(layer_id);
767 } 767 }
@@ -772,7 +772,7 @@ private:
772 u32 stack = rp.Pop<u32>(); 772 u32 stack = rp.Pop<u32>();
773 u64 layer_id = rp.Pop<u64>(); 773 u64 layer_id = rp.Pop<u64>();
774 774
775 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 775 IPC::ResponseBuilder rb{ctx, 2};
776 rb.Push(RESULT_SUCCESS); 776 rb.Push(RESULT_SUCCESS);
777 } 777 }
778 778
@@ -780,7 +780,7 @@ private:
780 IPC::RequestParser rp{ctx}; 780 IPC::RequestParser rp{ctx};
781 u64 layer_id = rp.Pop<u64>(); 781 u64 layer_id = rp.Pop<u64>();
782 bool visibility = rp.Pop<bool>(); 782 bool visibility = rp.Pop<bool>();
783 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 783 IPC::ResponseBuilder rb{ctx, 2};
784 rb.Push(RESULT_SUCCESS); 784 rb.Push(RESULT_SUCCESS);
785 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, 785 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
786 visibility); 786 visibility);
@@ -837,7 +837,7 @@ private:
837 837
838 ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); 838 ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
839 839
840 IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); 840 IPC::ResponseBuilder rb{ctx, 4};
841 rb.Push(RESULT_SUCCESS); 841 rb.Push(RESULT_SUCCESS);
842 rb.Push<u64>(nv_flinger->OpenDisplay(name)); 842 rb.Push<u64>(nv_flinger->OpenDisplay(name));
843 } 843 }
@@ -847,7 +847,7 @@ private:
847 IPC::RequestParser rp{ctx}; 847 IPC::RequestParser rp{ctx};
848 u64 display_id = rp.Pop<u64>(); 848 u64 display_id = rp.Pop<u64>();
849 849
850 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 850 IPC::ResponseBuilder rb{ctx, 2};
851 rb.Push(RESULT_SUCCESS); 851 rb.Push(RESULT_SUCCESS);
852 } 852 }
853 853
@@ -856,7 +856,7 @@ private:
856 IPC::RequestParser rp{ctx}; 856 IPC::RequestParser rp{ctx};
857 u64 display_id = rp.Pop<u64>(); 857 u64 display_id = rp.Pop<u64>();
858 858
859 IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); 859 IPC::ResponseBuilder rb{ctx, 6};
860 rb.Push(RESULT_SUCCESS); 860 rb.Push(RESULT_SUCCESS);
861 861
862 if (Settings::values.use_docked_mode) { 862 if (Settings::values.use_docked_mode) {
@@ -874,7 +874,7 @@ private:
874 u32 scaling_mode = rp.Pop<u32>(); 874 u32 scaling_mode = rp.Pop<u32>();
875 u64 unknown = rp.Pop<u64>(); 875 u64 unknown = rp.Pop<u64>();
876 876
877 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 877 IPC::ResponseBuilder rb{ctx, 2};
878 rb.Push(RESULT_SUCCESS); 878 rb.Push(RESULT_SUCCESS);
879 } 879 }
880 880
@@ -882,7 +882,7 @@ private:
882 IPC::RequestParser rp{ctx}; 882 IPC::RequestParser rp{ctx};
883 DisplayInfo display_info; 883 DisplayInfo display_info;
884 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); 884 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
885 IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); 885 IPC::ResponseBuilder rb{ctx, 4};
886 rb.Push(RESULT_SUCCESS); 886 rb.Push(RESULT_SUCCESS);
887 rb.Push<u64>(1); 887 rb.Push<u64>(1);
888 LOG_WARNING(Service_VI, "(STUBBED) called"); 888 LOG_WARNING(Service_VI, "(STUBBED) called");
@@ -903,7 +903,7 @@ private:
903 u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); 903 u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
904 904
905 NativeWindow native_window{buffer_queue_id}; 905 NativeWindow native_window{buffer_queue_id};
906 IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); 906 IPC::ResponseBuilder rb{ctx, 4};
907 rb.Push(RESULT_SUCCESS); 907 rb.Push(RESULT_SUCCESS);
908 rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); 908 rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
909 } 909 }
@@ -922,7 +922,7 @@ private:
922 u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); 922 u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id);
923 923
924 NativeWindow native_window{buffer_queue_id}; 924 NativeWindow native_window{buffer_queue_id};
925 IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); 925 IPC::ResponseBuilder rb{ctx, 6};
926 rb.Push(RESULT_SUCCESS); 926 rb.Push(RESULT_SUCCESS);
927 rb.Push(layer_id); 927 rb.Push(layer_id);
928 rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); 928 rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
@@ -934,7 +934,7 @@ private:
934 IPC::RequestParser rp{ctx}; 934 IPC::RequestParser rp{ctx};
935 u64 layer_id = rp.Pop<u64>(); 935 u64 layer_id = rp.Pop<u64>();
936 936
937 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); 937 IPC::ResponseBuilder rb{ctx, 2};
938 rb.Push(RESULT_SUCCESS); 938 rb.Push(RESULT_SUCCESS);
939 } 939 }
940 940
@@ -945,7 +945,7 @@ private:
945 945
946 auto vsync_event = nv_flinger->GetVsyncEvent(display_id); 946 auto vsync_event = nv_flinger->GetVsyncEvent(display_id);
947 947
948 IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0); 948 IPC::ResponseBuilder rb{ctx, 2, 1};
949 rb.Push(RESULT_SUCCESS); 949 rb.Push(RESULT_SUCCESS);
950 rb.PushCopyObjects(vsync_event); 950 rb.PushCopyObjects(vsync_event);
951 } 951 }
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index b46d81c02..5d4380684 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -11,6 +11,20 @@
11#include "core/loader/nca.h" 11#include "core/loader/nca.h"
12 12
13namespace Loader { 13namespace Loader {
14namespace {
15FileType IdentifyTypeImpl(const FileSys::NAX& nax) {
16 if (nax.GetStatus() != ResultStatus::Success) {
17 return FileType::Error;
18 }
19
20 const auto nca = nax.AsNCA();
21 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
22 return FileType::Error;
23 }
24
25 return FileType::NAX;
26}
27} // Anonymous namespace
14 28
15AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) 29AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
16 : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)), 30 : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)),
@@ -19,14 +33,12 @@ AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
19AppLoader_NAX::~AppLoader_NAX() = default; 33AppLoader_NAX::~AppLoader_NAX() = default;
20 34
21FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) { 35FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) {
22 FileSys::NAX nax(file); 36 const FileSys::NAX nax(file);
23 37 return IdentifyTypeImpl(nax);
24 if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr && 38}
25 nax.AsNCA()->GetStatus() == ResultStatus::Success) {
26 return FileType::NAX;
27 }
28 39
29 return FileType::Error; 40FileType AppLoader_NAX::GetFileType() {
41 return IdentifyTypeImpl(*nax);
30} 42}
31 43
32ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) { 44ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index 4dbae2918..56605fe45 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -31,9 +31,7 @@ public:
31 */ 31 */
32 static FileType IdentifyType(const FileSys::VirtualFile& file); 32 static FileType IdentifyType(const FileSys::VirtualFile& file);
33 33
34 FileType GetFileType() override { 34 FileType GetFileType() override;
35 return IdentifyType(file);
36 }
37 35
38 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 36 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
39 37
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 3c6306818..78a4438c4 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -32,11 +32,18 @@ static_assert(sizeof(NsoSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect
32 32
33struct NsoHeader { 33struct NsoHeader {
34 u32_le magic; 34 u32_le magic;
35 INSERT_PADDING_BYTES(0xc); 35 u32_le version;
36 INSERT_PADDING_WORDS(1);
37 u8 flags;
36 std::array<NsoSegmentHeader, 3> segments; // Text, RoData, Data (in that order) 38 std::array<NsoSegmentHeader, 3> segments; // Text, RoData, Data (in that order)
37 u32_le bss_size; 39 u32_le bss_size;
38 INSERT_PADDING_BYTES(0x1c); 40 INSERT_PADDING_BYTES(0x1c);
39 std::array<u32_le, 3> segments_compressed_size; 41 std::array<u32_le, 3> segments_compressed_size;
42
43 bool IsSegmentCompressed(size_t segment_num) const {
44 ASSERT_MSG(segment_num < 3, "Invalid segment {}", segment_num);
45 return ((flags >> segment_num) & 1);
46 }
40}; 47};
41static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); 48static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size.");
42static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable."); 49static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable.");
@@ -105,9 +112,11 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
105 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, ""); 112 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
106 std::vector<u8> program_image; 113 std::vector<u8> program_image;
107 for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { 114 for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
108 const std::vector<u8> compressed_data = 115 std::vector<u8> data =
109 file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); 116 file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
110 std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]); 117 if (nso_header.IsSegmentCompressed(i)) {
118 data = DecompressSegment(data, nso_header.segments[i]);
119 }
111 program_image.resize(nso_header.segments[i].location); 120 program_image.resize(nso_header.segments[i].location);
112 program_image.insert(program_image.end(), data.begin(), data.end()); 121 program_image.insert(program_image.end(), data.begin(), data.end());
113 codeset->segments[i].addr = nso_header.segments[i].location; 122 codeset->segments[i].addr = nso_header.segments[i].location;
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 7e1de0fa1..b1f137b9c 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -5,9 +5,8 @@
5#pragma once 5#pragma once
6 6
7#include <bitset> 7#include <bitset>
8#include <cstring>
9#include <map>
10#include <string> 8#include <string>
9#include <tuple>
11#include <vector> 10#include <vector>
12 11
13#include <boost/optional.hpp> 12#include <boost/optional.hpp>
@@ -315,17 +314,29 @@ enum class TextureMiscMode : u64 {
315 PTP, 314 PTP,
316}; 315};
317 316
318enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; 317enum class IpaInterpMode : u64 {
319enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; 318 Linear = 0,
319 Perspective = 1,
320 Flat = 2,
321 Sc = 3,
322};
323
324enum class IpaSampleMode : u64 {
325 Default = 0,
326 Centroid = 1,
327 Offset = 2,
328};
320 329
321struct IpaMode { 330struct IpaMode {
322 IpaInterpMode interpolation_mode; 331 IpaInterpMode interpolation_mode;
323 IpaSampleMode sampling_mode; 332 IpaSampleMode sampling_mode;
324 inline bool operator==(const IpaMode& a) { 333
325 return (a.interpolation_mode == interpolation_mode) && (a.sampling_mode == sampling_mode); 334 bool operator==(const IpaMode& a) const {
335 return std::tie(interpolation_mode, sampling_mode) ==
336 std::tie(a.interpolation_mode, a.sampling_mode);
326 } 337 }
327 inline bool operator!=(const IpaMode& a) { 338 bool operator!=(const IpaMode& a) const {
328 return !((*this) == a); 339 return !operator==(a);
329 } 340 }
330}; 341};
331 342
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 274c2dbcf..70fb54507 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -383,7 +383,7 @@ void RasterizerOpenGL::Clear() {
383 bool use_stencil{}; 383 bool use_stencil{};
384 384
385 OpenGLState clear_state; 385 OpenGLState clear_state;
386 clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; 386 clear_state.draw.draw_framebuffer = framebuffer.handle;
387 clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; 387 clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
388 clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; 388 clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
389 clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; 389 clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
@@ -484,8 +484,13 @@ void RasterizerOpenGL::DrawArrays() {
484 GLintptr index_buffer_offset = 0; 484 GLintptr index_buffer_offset = 0;
485 if (is_indexed) { 485 if (is_indexed) {
486 MICROPROFILE_SCOPE(OpenGL_Index); 486 MICROPROFILE_SCOPE(OpenGL_Index);
487 index_buffer_offset = 487
488 buffer_cache.UploadMemory(regs.index_array.StartAddress(), index_buffer_size); 488 // Adjust the index buffer offset so it points to the first desired index.
489 auto index_start = regs.index_array.StartAddress();
490 index_start += static_cast<size_t>(regs.index_array.first) *
491 static_cast<size_t>(regs.index_array.FormatSizeInBytes());
492
493 index_buffer_offset = buffer_cache.UploadMemory(index_start, index_buffer_size);
489 } 494 }
490 495
491 SetupShaders(); 496 SetupShaders();
@@ -499,10 +504,6 @@ void RasterizerOpenGL::DrawArrays() {
499 if (is_indexed) { 504 if (is_indexed) {
500 const GLint base_vertex{static_cast<GLint>(regs.vb_element_base)}; 505 const GLint base_vertex{static_cast<GLint>(regs.vb_element_base)};
501 506
502 // Adjust the index buffer offset so it points to the first desired index.
503 index_buffer_offset += static_cast<GLintptr>(regs.index_array.first) *
504 static_cast<GLintptr>(regs.index_array.FormatSizeInBytes());
505
506 if (gpu.state.current_instance > 0) { 507 if (gpu.state.current_instance > 0) {
507 glDrawElementsInstancedBaseVertexBaseInstance( 508 glDrawElementsInstancedBaseVertexBaseInstance(
508 primitive_mode, regs.index_array.count, 509 primitive_mode, regs.index_array.count,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 86682d7cb..24a540258 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -141,8 +141,8 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
141 {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 141 {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
142 true}, // BC7U 142 true}, // BC7U
143 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, 143 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8,
144 ComponentType::UNorm, true}, // BC6H_UF16 144 ComponentType::Float, true}, // BC6H_UF16
145 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 145 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
146 true}, // BC6H_SF16 146 true}, // BC6H_SF16
147 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 147 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
148 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U 148 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
@@ -501,6 +501,9 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
501 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); 501 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
502 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);
503 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);
504
505 VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr,
506 SurfaceParams::SurfaceTargetName(params.target));
504} 507}
505 508
506static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { 509static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index d7a4bc37f..80c5f324b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -137,6 +137,27 @@ struct SurfaceParams {
137 } 137 }
138 } 138 }
139 139
140 static std::string SurfaceTargetName(SurfaceTarget target) {
141 switch (target) {
142 case SurfaceTarget::Texture1D:
143 return "Texture1D";
144 case SurfaceTarget::Texture2D:
145 return "Texture2D";
146 case SurfaceTarget::Texture3D:
147 return "Texture3D";
148 case SurfaceTarget::Texture1DArray:
149 return "Texture1DArray";
150 case SurfaceTarget::Texture2DArray:
151 return "Texture2DArray";
152 case SurfaceTarget::TextureCubemap:
153 return "TextureCubemap";
154 default:
155 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
156 UNREACHABLE();
157 return fmt::format("TextureUnknown({})", static_cast<u32>(target));
158 }
159 }
160
140 /** 161 /**
141 * Gets the compression factor for the specified PixelFormat. This applies to just the 162 * Gets the compression factor for the specified PixelFormat. This applies to just the
142 * "compressed width" and "compressed height", not the overall compression factor of a 163 * "compressed width" and "compressed height", not the overall compression factor of a
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 894fe6eae..7cd8f91e4 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -8,6 +8,7 @@
8#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/renderer_opengl/gl_shader_cache.h" 9#include "video_core/renderer_opengl/gl_shader_cache.h"
10#include "video_core/renderer_opengl/gl_shader_manager.h" 10#include "video_core/renderer_opengl/gl_shader_manager.h"
11#include "video_core/utils.h"
11 12
12namespace OpenGL { 13namespace OpenGL {
13 14
@@ -83,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
83 shader.Create(program_result.first.c_str(), gl_type); 84 shader.Create(program_result.first.c_str(), gl_type);
84 program.Create(true, shader.handle); 85 program.Create(true, shader.handle);
85 SetShaderUniformBlockBindings(program.handle); 86 SetShaderUniformBlockBindings(program.handle);
87 VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr);
86} 88}
87 89
88GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { 90GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index af99132ba..e5173e20a 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -4,6 +4,7 @@
4 4
5#include <iterator> 5#include <iterator>
6#include <glad/glad.h> 6#include <glad/glad.h>
7#include "common/assert.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "video_core/renderer_opengl/gl_state.h" 9#include "video_core/renderer_opengl/gl_state.h"
9 10
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index e3e24b9e7..9a93029d8 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -7,12 +7,8 @@
7#include <array> 7#include <array>
8#include <glad/glad.h> 8#include <glad/glad.h>
9 9
10#include "video_core/engines/maxwell_3d.h"
11
12namespace OpenGL { 10namespace OpenGL {
13 11
14using Regs = Tegra::Engines::Maxwell3D::Regs;
15
16namespace TextureUnits { 12namespace TextureUnits {
17 13
18struct TextureUnit { 14struct TextureUnit {
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index 664f3ca20..e409228cc 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -74,7 +74,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
74 } 74 }
75 } 75 }
76 76
77 if (invalidate | !persistent) { 77 if (invalidate || !persistent) {
78 GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) | 78 GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
79 (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) | 79 (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
80 (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); 80 (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index e0a14d48f..681919ae3 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -161,4 +161,26 @@ static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixe
161 } 161 }
162} 162}
163 163
164static void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr,
165 std::string extra_info = "") {
166 if (!GLAD_GL_KHR_debug) {
167 return; // We don't need to throw an error as this is just for debugging
168 }
169 const std::string nice_addr = fmt::format("0x{:016x}", addr);
170 std::string object_label;
171
172 switch (identifier) {
173 case GL_TEXTURE:
174 object_label = extra_info + "@" + nice_addr;
175 break;
176 case GL_PROGRAM:
177 object_label = "ShaderProgram@" + nice_addr;
178 break;
179 default:
180 object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
181 break;
182 }
183 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
184}
185
164} // namespace VideoCore 186} // namespace VideoCore
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index f2a7e23f0..a3b1fd357 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -15,6 +15,7 @@
15#include "core/hle/kernel/thread.h" 15#include "core/hle/kernel/thread.h"
16#include "core/hle/kernel/timer.h" 16#include "core/hle/kernel/timer.h"
17#include "core/hle/kernel/wait_object.h" 17#include "core/hle/kernel/wait_object.h"
18#include "core/memory.h"
18 19
19WaitTreeItem::WaitTreeItem() = default; 20WaitTreeItem::WaitTreeItem() = default;
20WaitTreeItem::~WaitTreeItem() = default; 21WaitTreeItem::~WaitTreeItem() = default;
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 3b3b551bb..e8b2f720a 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -89,15 +89,7 @@ bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* e
89} 89}
90 90
91void GameList::SearchField::setFilterResult(int visible, int total) { 91void GameList::SearchField::setFilterResult(int visible, int total) {
92 QString result_of_text = tr("of"); 92 label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
93 QString result_text;
94 if (total == 1) {
95 result_text = tr("result");
96 } else {
97 result_text = tr("results");
98 }
99 label_filter_result->setText(
100 QString("%1 %2 %3 %4").arg(visible).arg(result_of_text).arg(total).arg(result_text));
101} 93}
102 94
103void GameList::SearchField::clear() { 95void GameList::SearchField::clear() {
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index b6272d536..cee109730 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -68,7 +68,7 @@ public:
68 if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) { 68 if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
69 picture = GetDefaultIcon(size); 69 picture = GetDefaultIcon(size);
70 } 70 }
71 picture = picture.scaled(size, size); 71 picture = picture.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
72 72
73 setData(picture, Qt::DecorationRole); 73 setData(picture, Qt::DecorationRole);
74 } 74 }
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 7ec1f5110..a478b0a56 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -120,7 +120,7 @@ void Config::ReadValues() {
120 sdl2_config->Get("Data Storage", "nand_directory", 120 sdl2_config->Get("Data Storage", "nand_directory",
121 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir))); 121 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
122 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir, 122 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
123 sdl2_config->Get("Data Storage", "nand_directory", 123 sdl2_config->Get("Data Storage", "sdmc_directory",
124 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); 124 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
125 125
126 // System 126 // System
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index b1c364fbb..b2559b717 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -20,8 +20,10 @@
20#include "common/string_util.h" 20#include "common/string_util.h"
21#include "common/telemetry.h" 21#include "common/telemetry.h"
22#include "core/core.h" 22#include "core/core.h"
23#include "core/crypto/key_manager.h"
23#include "core/file_sys/vfs_real.h" 24#include "core/file_sys/vfs_real.h"
24#include "core/gdbstub/gdbstub.h" 25#include "core/gdbstub/gdbstub.h"
26#include "core/hle/service/filesystem/filesystem.h"
25#include "core/loader/loader.h" 27#include "core/loader/loader.h"
26#include "core/settings.h" 28#include "core/settings.h"
27#include "core/telemetry_session.h" 29#include "core/telemetry_session.h"
@@ -29,7 +31,6 @@
29#include "yuzu_cmd/emu_window/emu_window_sdl2.h" 31#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
30 32
31#include <getopt.h> 33#include <getopt.h>
32#include "core/crypto/key_manager.h"
33#ifndef _MSC_VER 34#ifndef _MSC_VER
34#include <unistd.h> 35#include <unistd.h>
35#endif 36#endif
@@ -169,6 +170,7 @@ int main(int argc, char** argv) {
169 170
170 Core::System& system{Core::System::GetInstance()}; 171 Core::System& system{Core::System::GetInstance()};
171 system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); 172 system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
173 Service::FileSystem::CreateFactories(system.GetFilesystem());
172 174
173 SCOPE_EXIT({ system.Shutdown(); }); 175 SCOPE_EXIT({ system.Shutdown(); });
174 176