diff options
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 | ||
| 33 | deploy: | 46 | deploy: |
| 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 |
| 12 | else | 12 | else |
| 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 | ||
| 14 | fi | 17 | fi |
| 15 | 18 | ||
| 16 | mv "$REV_NAME" $RELEASE_NAME | 19 | mv "$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 | ||
| 2 | mkdir "$HOME/.ccache" || true | ||
| 3 | docker 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 | |||
| 3 | docker 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 | |||
| 3 | cd /yuzu | ||
| 4 | MINGW_PACKAGES="sdl2-mingw-w64 qt5base-mingw-w64 qt5tools-mingw-w64 libsamplerate-mingw-w64 qt5multimedia-mingw-w64" | ||
| 5 | apt-get update | ||
| 6 | apt-get install -y gpg wget git python3-pip python ccache g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 mingw-w64-tools cmake | ||
| 7 | echo 'deb http://ppa.launchpad.net/tobydox/mingw-w64/ubuntu bionic main ' > /etc/apt/sources.list.d/extras.list | ||
| 8 | apt-key adv --keyserver keyserver.ubuntu.com --recv '72931B477E22FEFD47F8DECE02FE5F12ADDE29B2' | ||
| 9 | apt-get update | ||
| 10 | apt-get install -y ${MINGW_PACKAGES} | ||
| 11 | |||
| 12 | # fix a problem in current MinGW headers | ||
| 13 | wget -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 | ||
| 15 | echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf" | ||
| 16 | |||
| 17 | # Dirty hack to trick unicorn makefile into believing we are in a MINGW system | ||
| 18 | mv /bin/uname /bin/uname1 && echo -e '#!/bin/sh\necho MINGW64' >> /bin/uname | ||
| 19 | chmod +x /bin/uname | ||
| 20 | |||
| 21 | # Dirty hack to trick unicorn makefile into believing we have cmd | ||
| 22 | echo '' >> /bin/cmd | ||
| 23 | chmod +x /bin/cmd | ||
| 24 | |||
| 25 | mkdir build && cd build | ||
| 26 | cmake .. -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release | ||
| 27 | make -j4 | ||
| 28 | |||
| 29 | # Clean up the dirty hacks | ||
| 30 | rm /bin/uname && mv /bin/uname1 /bin/uname | ||
| 31 | rm /bin/cmd | ||
| 32 | |||
| 33 | ccache -s | ||
| 34 | |||
| 35 | echo "Tests skipped" | ||
| 36 | #ctest -VV -C Release | ||
| 37 | |||
| 38 | echo 'Prepare binaries...' | ||
| 39 | cd .. | ||
| 40 | mkdir package | ||
| 41 | |||
| 42 | QT_PLATFORM_DLL_PATH='/usr/x86_64-w64-mingw32/lib/qt5/plugins/platforms/' | ||
| 43 | find build/ -name "yuzu*.exe" -exec cp {} 'package' \; | ||
| 44 | |||
| 45 | # copy Qt plugins | ||
| 46 | mkdir package/platforms | ||
| 47 | cp "${QT_PLATFORM_DLL_PATH}/qwindows.dll" package/platforms/ | ||
| 48 | cp -rv "${QT_PLATFORM_DLL_PATH}/../mediaservice/" package/ | ||
| 49 | cp -rv "${QT_PLATFORM_DLL_PATH}/../imageformats/" package/ | ||
| 50 | rm -f package/mediaservice/*d.dll | ||
| 51 | |||
| 52 | for 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}" | ||
| 56 | done | ||
| 57 | |||
| 58 | pip3 install pefile | ||
| 59 | python3 .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 @@ | |||
| 1 | import pefile | ||
| 2 | import sys | ||
| 3 | import re | ||
| 4 | import os | ||
| 5 | import queue | ||
| 6 | import shutil | ||
| 7 | |||
| 8 | # constant definitions | ||
| 9 | KNOWN_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 | ||
| 13 | DLL_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 | |||
| 19 | missing = [] | ||
| 20 | |||
| 21 | |||
| 22 | def 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 | |||
| 38 | def 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 | |||
| 69 | def 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 | |||
| 77 | def 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 | |||
| 89 | def 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 | |||
| 105 | if __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 | |||
| 5 | REV_NAME="yuzu-windows-mingw-${GITDATE}-${GITREV}" | ||
| 6 | ARCHIVE_NAME="${REV_NAME}.tar.gz" | ||
| 7 | COMPRESSION_FLAGS="-czvf" | ||
| 8 | |||
| 9 | mkdir "$REV_NAME" | ||
| 10 | # get around the permission issues | ||
| 11 | cp -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 | |||
| 6 | cd /yuzu | 6 | cd /yuzu |
| 7 | 7 | ||
| 8 | mkdir build && cd build | 8 | mkdir build && cd build |
| 9 | cmake .. -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 | 9 | cmake .. -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 |
| 10 | ninja | 10 | ninja |
| 11 | 11 | ||
| 12 | ccache -s | ||
| 13 | |||
| 12 | ctest -VV -C Release | 14 | ctest -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 | ||
| 10 | mkdir build && cd build | 10 | mkdir build && cd build |
| 11 | cmake --version | 11 | cmake --version |
| 12 | cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON | 12 | cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON |
| 13 | make -j4 | 13 | make -j4 |
| 14 | 14 | ||
| 15 | ccache -s | ||
| 16 | |||
| 15 | ctest -VV -C Release | 17 | ctest -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 | ||
| 287 | if (UNICORN_FOUND) | 295 | if (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}") |
| 291 | else() | 300 | else() |
| @@ -431,8 +440,12 @@ enable_testing() | |||
| 431 | add_subdirectory(externals) | 440 | add_subdirectory(externals) |
| 432 | add_subdirectory(src) | 441 | add_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 |
| 435 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu) | 444 | if(ENABLE_QT) |
| 445 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu) | ||
| 446 | else() | ||
| 447 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu-cmd) | ||
| 448 | endif() | ||
| 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 @@ | |||
| 1 | set(MINGW_PREFIX /usr/x86_64-w64-mingw32/) | ||
| 2 | set(CMAKE_SYSTEM_NAME Windows) | ||
| 3 | set(CMAKE_SYSTEM_PROCESSOR x86_64) | ||
| 4 | # Actually a hack, w/o this will cause some strange errors | ||
| 5 | set(CMAKE_HOST_WIN32 TRUE) | ||
| 6 | |||
| 7 | |||
| 8 | set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX}) | ||
| 9 | set(SDL2_PATH ${MINGW_PREFIX}) | ||
| 10 | set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-) | ||
| 11 | |||
| 12 | # Specify the cross compiler | ||
| 13 | set(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc-posix) | ||
| 14 | set(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++-posix) | ||
| 15 | set(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres) | ||
| 16 | |||
| 17 | # Mingw tools | ||
| 18 | set(STRIP ${MINGW_TOOL_PREFIX}strip) | ||
| 19 | set(WINDRES ${MINGW_TOOL_PREFIX}windres) | ||
| 20 | set(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config) | ||
| 21 | |||
| 22 | # ccache wrapper | ||
| 23 | option(USE_CCACHE "Use ccache for compilation" OFF) | ||
| 24 | if(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) | ||
| 33 | endif(USE_CCACHE) | ||
| 34 | |||
| 35 | # Search for programs in the build host directories | ||
| 36 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | ||
| 37 | |||
| 38 | |||
| 39 | # Echo modified cmake vars to screen for debugging purposes | ||
| 40 | if(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) | ||
| 54 | endif() | ||
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 | ||
| 82 | u32 AudioRenderer::GetState() const { | ||
| 83 | return stream->GetState(); | ||
| 84 | } | ||
| 85 | |||
| 82 | std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { | 86 | std::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 | ||
| 174 | private: | 175 | private: |
| 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 | ||
| 51 | void Stream::Stop() { | 51 | void Stream::Stop() { |
| 52 | state = State::Stopped; | ||
| 52 | ASSERT_MSG(false, "Unimplemented"); | 53 | ASSERT_MSG(false, "Unimplemented"); |
| 53 | } | 54 | } |
| 54 | 55 | ||
| 56 | u32 Stream::GetState() const { | ||
| 57 | return static_cast<u32>(state); | ||
| 58 | } | ||
| 59 | |||
| 55 | s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { | 60 | s64 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 | |||
| 75 | private: | 78 | private: |
| 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 | ||
| 34 | public: | 35 | public: |
| 35 | /// Pushes slots into the ring buffer | 36 | /// Pushes slots into the ring buffer |
| @@ -102,8 +103,15 @@ public: | |||
| 102 | private: | 103 | private: |
| 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 | ||
| 88 | void SleepCurrentThread(int ms); | 88 | void SleepCurrentThread(int ms); |
| 89 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms | 89 | void 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. | ||
| 94 | inline void YieldCPU() { | ||
| 95 | std::this_thread::yield(); | ||
| 96 | } | ||
| 97 | |||
| 98 | void SetCurrentThreadName(const char* name); | 90 | void 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 | |
| 10 | namespace Kernel { | ||
| 11 | enum class VMAPermission : u8; | ||
| 12 | } | ||
| 10 | 13 | ||
| 11 | namespace Core { | 14 | namespace 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 | ||
| 19 | namespace Core { | 21 | namespace 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 | ||
| 15 | namespace Memory { | ||
| 16 | struct PageTable; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace Core { | 19 | namespace Core { |
| 16 | 20 | ||
| 17 | class ARM_Dynarmic_Callbacks; | 21 | class 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 | ||
| 466 | NCA::~NCA() = default; | ||
| 467 | |||
| 466 | Loader::ResultStatus NCA::GetStatus() const { | 468 | Loader::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 { | |||
| 81 | public: | 81 | public: |
| 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 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | const 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 | |||
| 11 | std::string LanguageEntry::GetApplicationName() const { | 19 | std::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 | ||
| 31 | NACP::~NACP() = default; | ||
| 32 | |||
| 23 | const LanguageEntry& NACP::GetLanguageEntry(Language language) const { | 33 | const 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 | ||
| 37 | std::string NACP::GetApplicationName(Language language) const { | 47 | std::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 | ||
| 69 | static constexpr std::array<const char*, 15> LANGUAGE_NAMES = { | 69 | extern 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. |
| 78 | class NACP { | 73 | class NACP { |
| 79 | public: | 74 | public: |
| 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 | ||
| 54 | CNMT::~CNMT() = default; | ||
| 55 | |||
| 54 | u64 CNMT::GetTitleID() const { | 56 | u64 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 | ||
| 75 | PartitionFilesystem::~PartitionFilesystem() = default; | ||
| 76 | |||
| 75 | Loader::ResultStatus PartitionFilesystem::GetStatus() const { | 77 | Loader::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 { | |||
| 25 | class PartitionFilesystem : public ReadOnlyVfsDirectory { | 25 | class PartitionFilesystem : public ReadOnlyVfsDirectory { |
| 26 | public: | 26 | public: |
| 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 | ||
| 42 | PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} | 42 | PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} |
| 43 | 43 | ||
| 44 | PatchManager::~PatchManager() = default; | ||
| 45 | |||
| 44 | VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | 46 | VirtualDir 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); | |||
| 34 | class PatchManager { | 34 | class PatchManager { |
| 35 | public: | 35 | public: |
| 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 | ||
| 13 | namespace FileSys { | 13 | namespace FileSys { |
| 14 | 14 | ||
| 15 | ProgramMetadata::ProgramMetadata() = default; | ||
| 16 | |||
| 17 | ProgramMetadata::~ProgramMetadata() = default; | ||
| 18 | |||
| 15 | Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { | 19 | Loader::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 | */ |
| 37 | class ProgramMetadata { | 37 | class ProgramMetadata { |
| 38 | public: | 38 | public: |
| 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 | ||
| 31 | RomFSFactory::~RomFSFactory() = default; | ||
| 32 | |||
| 31 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { | 33 | ResultVal<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 { | |||
| 30 | class RomFSFactory { | 30 | class RomFSFactory { |
| 31 | public: | 31 | public: |
| 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 | ||
| 21 | SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {} | 21 | SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {} |
| 22 | 22 | ||
| 23 | SaveDataFactory::~SaveDataFactory() = default; | ||
| 24 | |||
| 23 | ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) { | 25 | ResultVal<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 | |||
| 48 | class SaveDataFactory { | 48 | class SaveDataFactory { |
| 49 | public: | 49 | public: |
| 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; | |||
| 24 | class NSP : public ReadOnlyVfsDirectory { | 24 | class NSP : public ReadOnlyVfsDirectory { |
| 25 | public: | 25 | public: |
| 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 | ||
| 30 | ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; | ||
| 31 | |||
| 30 | std::string ConcatenatedVfsFile::GetName() const { | 32 | std::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 | ||
| 24 | public: | 24 | public: |
| 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 | ||
| 17 | OffsetVfsFile::~OffsetVfsFile() = default; | ||
| 18 | |||
| 17 | std::string OffsetVfsFile::GetName() const { | 19 | std::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 { | |||
| 19 | public: | 19 | public: |
| 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 | ||
| 16 | VectorVfsDirectory::~VectorVfsDirectory() = default; | ||
| 17 | |||
| 16 | std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const { | 18 | std::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 | ||
| 48 | NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NAXHeader>()) { | 45 | NAX::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 | ||
| 67 | NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id) | 64 | NAX::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 | ||
| 72 | NAX::~NAX() = default; | ||
| 73 | |||
| 75 | Loader::ResultStatus NAX::Parse(std::string_view path) { | 74 | Loader::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 | ||
| 141 | std::shared_ptr<NCA> NAX::AsNCA() const { | 140 | std::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 { | |||
| 33 | public: | 33 | public: |
| 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 | ||
| 20 | namespace Kernel { | 21 | namespace 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 | |||
| 133 | void 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 | */ | ||
| 168 | static 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 | |||
| 186 | VAddr 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 | |||
| 210 | void 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 | ||
| 131 | void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { | 218 | void 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 | ||
| 205 | private: | ||
| 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 | |||
| 208 | private: | ||
| 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 |
| 532 | static void ExitProcess() { | 532 | static 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 | ||
| 74 | void WaitCurrentThread_Sleep() { | 71 | void 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 | */ | ||
| 188 | static 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 | ||
| 313 | SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, | 259 | SharedPtr<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 | ||
| 63 | class Thread final : public WaitObject { | 63 | class Thread final : public WaitObject { |
| 64 | public: | 64 | public: |
| 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 | */ |
| 283 | SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, | 294 | SharedPtr<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 | ||
| 608 | class HidDbg final : public ServiceFramework<HidDbg> { | 614 | class 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 | ||
| 63 | private: | 63 | private: |
| 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 | ||
| 115 | private: | 121 | private: |
| 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 | ||
| 107 | class IEnsureNetworkClockAvailabilityService final | ||
| 108 | : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { | ||
| 109 | public: | ||
| 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 | |||
| 129 | private: | ||
| 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 | |||
| 103 | class NTC final : public ServiceFramework<NTC> { | 178 | class NTC final : public ServiceFramework<NTC> { |
| 104 | public: | 179 | public: |
| 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 | |||
| 192 | private: | ||
| 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 | ||
| 118 | void InstallInterfaces(SM::ServiceManager& sm) { | 214 | void 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 | ||
| 13 | namespace Loader { | 13 | namespace Loader { |
| 14 | namespace { | ||
| 15 | FileType 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 | ||
| 15 | AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) | 29 | AppLoader_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) | |||
| 19 | AppLoader_NAX::~AppLoader_NAX() = default; | 33 | AppLoader_NAX::~AppLoader_NAX() = default; |
| 20 | 34 | ||
| 21 | FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) { | 35 | FileType 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; | 40 | FileType AppLoader_NAX::GetFileType() { |
| 41 | return IdentifyTypeImpl(*nax); | ||
| 30 | } | 42 | } |
| 31 | 43 | ||
| 32 | ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 44 | ResultStatus 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 | ||
| 33 | struct NsoHeader { | 33 | struct 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 | }; |
| 41 | static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); | 48 | static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size."); |
| 42 | static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable."); | 49 | static_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 | ||
| 318 | enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; | 317 | enum class IpaInterpMode : u64 { |
| 319 | enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; | 318 | Linear = 0, |
| 319 | Perspective = 1, | ||
| 320 | Flat = 2, | ||
| 321 | Sc = 3, | ||
| 322 | }; | ||
| 323 | |||
| 324 | enum class IpaSampleMode : u64 { | ||
| 325 | Default = 0, | ||
| 326 | Centroid = 1, | ||
| 327 | Offset = 2, | ||
| 328 | }; | ||
| 320 | 329 | ||
| 321 | struct IpaMode { | 330 | struct 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 | ||
| 506 | static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { | 509 | static 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 | ||
| 12 | namespace OpenGL { | 13 | namespace 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 | ||
| 88 | GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { | 90 | GLuint 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 | |||
| 12 | namespace OpenGL { | 10 | namespace OpenGL { |
| 13 | 11 | ||
| 14 | using Regs = Tegra::Engines::Maxwell3D::Regs; | ||
| 15 | |||
| 16 | namespace TextureUnits { | 12 | namespace TextureUnits { |
| 17 | 13 | ||
| 18 | struct TextureUnit { | 14 | struct 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 | ||
| 164 | static 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 | ||
| 19 | WaitTreeItem::WaitTreeItem() = default; | 20 | WaitTreeItem::WaitTreeItem() = default; |
| 20 | WaitTreeItem::~WaitTreeItem() = default; | 21 | WaitTreeItem::~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 | ||
| 91 | void GameList::SearchField::setFilterResult(int visible, int total) { | 91 | void 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 | ||
| 103 | void GameList::SearchField::clear() { | 95 | void 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 | ||