summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/templates/build-msvc.yml2
-rw-r--r--externals/CMakeLists.txt4
m---------externals/dynarmic0
-rw-r--r--externals/find-modules/FindLibzip.cmake72
-rw-r--r--externals/find-modules/Findlibzip.cmake72
-rw-r--r--externals/libusb/CMakeLists.txt5
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/assert.cpp11
-rw-r--r--src/common/assert.h14
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/threadsafe_queue.h10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp40
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp47
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h5
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/hle/kernel/k_scheduler.h4
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h13
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp6
-rw-r--r--src/core/hle/kernel/process_capability.cpp5
-rw-r--r--src/core/hle/kernel/process_capability.h2
-rw-r--r--src/core/hle/kernel/svc.cpp132
-rw-r--r--src/core/hle/service/acc/acc.cpp17
-rw-r--r--src/core/hle/service/acc/acc_su.cpp36
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp28
-rw-r--r--src/core/hle/service/am/am.cpp39
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp2
-rw-r--r--src/core/hle/service/audio/audin_a.cpp8
-rw-r--r--src/core/hle/service/audio/audin_u.cpp14
-rw-r--r--src/core/hle/service/audio/audout_a.cpp12
-rw-r--r--src/core/hle/service/audio/audout_u.cpp6
-rw-r--r--src/core/hle/service/audio/audrec_a.cpp4
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp7
-rw-r--r--src/core/hle/service/audio/audren_a.cpp12
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.h2
-rw-r--r--src/core/hle/service/audio/codecctl.cpp26
-rw-r--r--src/core/hle/service/audio/hwopus.cpp4
-rw-r--r--src/core/hle/service/bcat/module.cpp2
-rw-r--r--src/core/hle/service/bpc/bpc.cpp4
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp19
-rw-r--r--src/core/hle/service/btm/btm.cpp1
-rw-r--r--src/core/hle/service/caps/caps_a.cpp1
-rw-r--r--src/core/hle/service/caps/caps_u.cpp1
-rw-r--r--src/core/hle/service/erpt/erpt.cpp7
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp19
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h2
-rw-r--r--src/core/hle/service/friend/friend.cpp37
-rw-r--r--src/core/hle/service/glue/arp.cpp11
-rw-r--r--src/core/hle/service/glue/arp.h2
-rw-r--r--src/core/hle/service/glue/bgtc.cpp27
-rw-r--r--src/core/hle/service/glue/bgtc.h8
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp11
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp12
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp5
-rw-r--r--src/core/hle/service/hid/hid.cpp106
-rw-r--r--src/core/hle/service/hid/hid.h1
-rw-r--r--src/core/hle/service/hid/xcd.cpp2
-rw-r--r--src/core/hle/service/ldr/ldr.cpp32
-rw-r--r--src/core/hle/service/nim/nim.cpp99
-rw-r--r--src/core/hle/service/npns/npns.cpp3
-rw-r--r--src/core/hle/service/ns/ns.cpp41
-rw-r--r--src/core/hle/service/ns/pl_u.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp60
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h39
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp17
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp17
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h12
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp10
-rw-r--r--src/core/hle/service/olsc/olsc.cpp1
-rw-r--r--src/core/hle/service/pcie/pcie.cpp2
-rw-r--r--src/core/hle/service/pctl/module.cpp3
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/set/set_sys.cpp6
-rw-r--r--src/core/hle/service/sm/sm.cpp9
-rw-r--r--src/core/hle/service/sockets/ethc.cpp1
-rw-r--r--src/core/hle/service/sockets/nsd.cpp1
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp4
-rw-r--r--src/core/hle/service/spl/spl.cpp3
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp1
-rw-r--r--src/core/hle/service/usb/usb.cpp42
-rw-r--r--src/core/hle/service/vi/vi.cpp8
-rw-r--r--src/core/hle/service/wlan/wlan.cpp7
-rw-r--r--src/core/settings.h1
-rw-r--r--src/input_common/udp/client.cpp147
-rw-r--r--src/input_common/udp/client.h44
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp16
-rw-r--r--src/video_core/gpu.cpp4
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/gpu_thread.cpp62
-rw-r--r--src/video_core/gpu_thread.h15
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt1
-rw-r--r--src/video_core/host_shaders/StringShaderHeader.cmake22
-rw-r--r--src/video_core/host_shaders/astc_decoder.comp1339
-rw-r--r--src/video_core/host_shaders/source_shader.h.in4
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h2
-rw-r--r--src/video_core/renderer_opengl/util_shaders.cpp76
-rw-r--r--src/video_core/renderer_opengl/util_shaders.h5
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp333
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h32
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp49
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h19
-rw-r--r--src/video_core/texture_cache/accelerated_swizzle.h4
-rw-r--r--src/video_core/texture_cache/util.cpp14
-rw-r--r--src/video_core/textures/astc.cpp1710
-rw-r--r--src/video_core/textures/astc.h124
-rw-r--r--src/video_core/textures/decoders.cpp23
-rw-r--r--src/video_core/textures/decoders.h18
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp2
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp8
-rw-r--r--src/yuzu/configuration/config.cpp1
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.ui22
-rw-r--r--src/yuzu/configuration/configure_filesystem.cpp5
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp2
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp9
-rw-r--r--src/yuzu/configuration/configure_motion_touch.h3
-rw-r--r--src/yuzu/main.cpp28
143 files changed, 3370 insertions, 2391 deletions
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml
index 721179550..097367018 100644
--- a/.ci/templates/build-msvc.yml
+++ b/.ci/templates/build-msvc.yml
@@ -8,7 +8,7 @@ steps:
8 displayName: 'Install vulkan-sdk' 8 displayName: 'Install vulkan-sdk'
9- script: python -m pip install --upgrade pip conan 9- script: python -m pip install --upgrade pip conan
10 displayName: 'Install conan' 10 displayName: 'Install conan'
11- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd .. 11- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cmake --install . --config Release && cd ..
12 displayName: 'Configure CMake' 12 displayName: 'Configure CMake'
13- task: MSBuild@1 13- task: MSBuild@1
14 displayName: 'Build' 14 displayName: 'Build'
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index c629bbc5c..851c282b4 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -64,8 +64,8 @@ endif()
64add_subdirectory(sirit) 64add_subdirectory(sirit)
65 65
66# libzip 66# libzip
67find_package(Libzip 1.5) 67find_package(libzip 1.5)
68if (NOT LIBZIP_FOUND) 68if (NOT libzip_FOUND)
69 message(STATUS "libzip 1.5 or newer not found, falling back to externals") 69 message(STATUS "libzip 1.5 or newer not found, falling back to externals")
70 add_subdirectory(libzip EXCLUDE_FROM_ALL) 70 add_subdirectory(libzip EXCLUDE_FROM_ALL)
71endif() 71endif()
diff --git a/externals/dynarmic b/externals/dynarmic
Subproject 646fd0592091c5c1e5899fa715bd7b7fcc977a3 Subproject c788bcdf17e6bc1d1a1dd315106b952013f5ecb
diff --git a/externals/find-modules/FindLibzip.cmake b/externals/find-modules/FindLibzip.cmake
deleted file mode 100644
index f36b1687a..000000000
--- a/externals/find-modules/FindLibzip.cmake
+++ /dev/null
@@ -1,72 +0,0 @@
1
2find_package(PkgConfig QUIET)
3pkg_check_modules(PC_LIBZIP QUIET libzip)
4
5find_path(LIBZIP_INCLUDE_DIR
6 NAMES zip.h
7 PATHS ${PC_LIBZIP_INCLUDE_DIRS}
8 "$ENV{LIB_DIR}/include"
9 "$ENV{INCLUDE}"
10 /usr/local/include
11 /usr/include
12)
13find_path(LIBZIP_INCLUDE_DIR_ZIPCONF
14 NAMES zipconf.h
15 HINTS ${PC_LIBZIP_INCLUDE_DIRS}
16 "$ENV{LIB_DIR}/include"
17 "$ENV{LIB_DIR}/lib/libzip/include"
18 "$ENV{LIB}/lib/libzip/include"
19 /usr/local/lib/libzip/include
20 /usr/lib/libzip/include
21 /usr/local/include
22 /usr/include
23 "$ENV{INCLUDE}"
24)
25find_library(LIBZIP_LIBRARY
26 NAMES zip
27 PATHS ${PC_LIBZIP_LIBRARY_DIRS}
28 "$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
29)
30
31if (LIBZIP_INCLUDE_DIR_ZIPCONF)
32 FILE(READ "${LIBZIP_INCLUDE_DIR_ZIPCONF}/zipconf.h" _LIBZIP_VERSION_CONTENTS)
33 if (_LIBZIP_VERSION_CONTENTS)
34 STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" LIBZIP_VERSION "${_LIBZIP_VERSION_CONTENTS}")
35 endif()
36 unset(_LIBZIP_VERSION_CONTENTS)
37endif()
38
39set(LIBZIP_VERSION ${LIBZIP_VERSION} CACHE STRING "Version number of libzip")
40
41include(FindPackageHandleStandardArgs)
42find_package_handle_standard_args(Libzip
43 FOUND_VAR LIBZIP_FOUND
44 REQUIRED_VARS
45 LIBZIP_LIBRARY
46 LIBZIP_INCLUDE_DIR
47 LIBZIP_INCLUDE_DIR_ZIPCONF
48 LIBZIP_VERSION
49 VERSION_VAR LIBZIP_VERSION
50)
51
52if(LIBZIP_FOUND)
53 set(LIBZIP_LIBRARIES ${LIBZIP_LIBRARY})
54 set(LIBZIP_INCLUDE_DIRS ${LIBZIP_INCLUDE_DIR})
55 set(LIBZIP_DEFINITIONS ${PC_LIBZIP_CFLAGS_OTHER})
56endif()
57
58if(LIBZIP_FOUND AND NOT TARGET libzip::libzip)
59 add_library(libzip::libzip UNKNOWN IMPORTED)
60 set_target_properties(libzip::libzip PROPERTIES
61 IMPORTED_LOCATION "${LIBZIP_LIBRARY}"
62 INTERFACE_COMPILE_OPTIONS "${PC_LIBZIP_CFLAGS_OTHER}"
63 INTERFACE_INCLUDE_DIRECTORIES "${LIBZIP_INCLUDE_DIR}"
64 )
65endif()
66
67mark_as_advanced(
68 LIBZIP_INCLUDE_DIR
69 LIBZIP_INCLUDE_DIR_ZIPCONF
70 LIBZIP_LIBRARY
71 LIBZIP_VERSION
72)
diff --git a/externals/find-modules/Findlibzip.cmake b/externals/find-modules/Findlibzip.cmake
new file mode 100644
index 000000000..8934de3b8
--- /dev/null
+++ b/externals/find-modules/Findlibzip.cmake
@@ -0,0 +1,72 @@
1
2find_package(PkgConfig QUIET)
3pkg_check_modules(PC_libzip QUIET libzip)
4
5find_path(libzip_INCLUDE_DIR
6 NAMES zip.h
7 PATHS ${PC_libzip_INCLUDE_DIRS}
8 "$ENV{LIB_DIR}/include"
9 "$ENV{INCLUDE}"
10 /usr/local/include
11 /usr/include
12)
13find_path(libzip_INCLUDE_DIR_ZIPCONF
14 NAMES zipconf.h
15 HINTS ${PC_libzip_INCLUDE_DIRS}
16 "$ENV{LIB_DIR}/include"
17 "$ENV{LIB_DIR}/lib/libzip/include"
18 "$ENV{LIB}/lib/libzip/include"
19 /usr/local/lib/libzip/include
20 /usr/lib/libzip/include
21 /usr/local/include
22 /usr/include
23 "$ENV{INCLUDE}"
24)
25find_library(libzip_LIBRARY
26 NAMES zip
27 PATHS ${PC_libzip_LIBRARY_DIRS}
28 "$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
29)
30
31if (libzip_INCLUDE_DIR_ZIPCONF)
32 FILE(READ "${libzip_INCLUDE_DIR_ZIPCONF}/zipconf.h" _libzip_VERSION_CONTENTS)
33 if (_libzip_VERSION_CONTENTS)
34 STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" libzip_VERSION "${_libzip_VERSION_CONTENTS}")
35 endif()
36 unset(_libzip_VERSION_CONTENTS)
37endif()
38
39set(libzip_VERSION ${libzip_VERSION} CACHE STRING "Version number of libzip")
40
41include(FindPackageHandleStandardArgs)
42find_package_handle_standard_args(libzip
43 FOUND_VAR libzip_FOUND
44 REQUIRED_VARS
45 libzip_LIBRARY
46 libzip_INCLUDE_DIR
47 libzip_INCLUDE_DIR_ZIPCONF
48 libzip_VERSION
49 VERSION_VAR libzip_VERSION
50)
51
52if(libzip_FOUND)
53 set(libzip_LIBRARIES ${libzip_LIBRARY})
54 set(libzip_INCLUDE_DIRS ${libzip_INCLUDE_DIR})
55 set(libzip_DEFINITIONS ${PC_libzip_CFLAGS_OTHER})
56endif()
57
58if(libzip_FOUND AND NOT TARGET libzip::libzip)
59 add_library(libzip::libzip UNKNOWN IMPORTED)
60 set_target_properties(libzip::libzip PROPERTIES
61 IMPORTED_LOCATION "${libzip_LIBRARY}"
62 INTERFACE_COMPILE_OPTIONS "${PC_libzip_CFLAGS_OTHER}"
63 INTERFACE_INCLUDE_DIRECTORIES "${libzip_INCLUDE_DIR}"
64 )
65endif()
66
67mark_as_advanced(
68 libzip_INCLUDE_DIR
69 libzip_INCLUDE_DIR_ZIPCONF
70 libzip_LIBRARY
71 libzip_VERSION
72)
diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt
index c0d24b126..70d6735e3 100644
--- a/externals/libusb/CMakeLists.txt
+++ b/externals/libusb/CMakeLists.txt
@@ -1,3 +1,8 @@
1# Ensure libusb compiles with UTF-8 encoding on MSVC
2if(MSVC)
3 add_compile_options(/utf-8)
4endif()
5
1add_library(usb STATIC EXCLUDE_FROM_ALL 6add_library(usb STATIC EXCLUDE_FROM_ALL
2 libusb/libusb/core.c 7 libusb/libusb/core.c
3 libusb/libusb/core.c 8 libusb/libusb/core.c
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 7253c0f4d..9f8dafa3b 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -97,6 +97,7 @@ add_custom_command(OUTPUT scm_rev.cpp
97add_library(common STATIC 97add_library(common STATIC
98 algorithm.h 98 algorithm.h
99 alignment.h 99 alignment.h
100 assert.cpp
100 assert.h 101 assert.h
101 atomic_ops.h 102 atomic_ops.h
102 detached_tasks.cpp 103 detached_tasks.cpp
diff --git a/src/common/assert.cpp b/src/common/assert.cpp
new file mode 100644
index 000000000..d7d91b96b
--- /dev/null
+++ b/src/common/assert.cpp
@@ -0,0 +1,11 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6
7#include "common/common_funcs.h"
8
9void assert_handle_failure() {
10 Crash();
11}
diff --git a/src/common/assert.h b/src/common/assert.h
index 06d7b5612..b3ba35c0f 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -4,10 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstdlib>
8#include "common/common_funcs.h"
9#include "common/logging/log.h" 7#include "common/logging/log.h"
10 8
9// Sometimes we want to try to continue even after hitting an assert.
10// However touching this file yields a global recompilation as this header is included almost
11// everywhere. So let's just move the handling of the failed assert to a single cpp file.
12void assert_handle_failure();
13
11// For asserts we'd like to keep all the junk executed when an assert happens away from the 14// For asserts we'd like to keep all the junk executed when an assert happens away from the
12// important code in the function. One way of doing this is to put all the relevant code inside a 15// important code in the function. One way of doing this is to put all the relevant code inside a
13// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to 16// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
@@ -17,15 +20,14 @@
17// enough for our purposes. 20// enough for our purposes.
18template <typename Fn> 21template <typename Fn>
19#if defined(_MSC_VER) 22#if defined(_MSC_VER)
20[[msvc::noinline, noreturn]] 23[[msvc::noinline]]
21#elif defined(__GNUC__) 24#elif defined(__GNUC__)
22[[gnu::cold, gnu::noinline, noreturn]] 25[[gnu::cold, gnu::noinline]]
23#endif 26#endif
24static void 27static void
25assert_noinline_call(const Fn& fn) { 28assert_noinline_call(const Fn& fn) {
26 fn(); 29 fn();
27 Crash(); 30 assert_handle_failure();
28 exit(1); // Keeps GCC's mouth shut about this actually returning
29} 31}
30 32
31#define ASSERT(_a_) \ 33#define ASSERT(_a_) \
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 2d4d2e9e7..4575df24d 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -212,6 +212,7 @@ void DebuggerBackend::Write(const Entry& entry) {
212 SUB(Service, ARP) \ 212 SUB(Service, ARP) \
213 SUB(Service, BCAT) \ 213 SUB(Service, BCAT) \
214 SUB(Service, BPC) \ 214 SUB(Service, BPC) \
215 SUB(Service, BGTC) \
215 SUB(Service, BTDRV) \ 216 SUB(Service, BTDRV) \
216 SUB(Service, BTM) \ 217 SUB(Service, BTM) \
217 SUB(Service, Capture) \ 218 SUB(Service, Capture) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 835894918..3d7b7dab7 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -66,6 +66,7 @@ enum class Class : ClassType {
66 Service_ARP, ///< The ARP service 66 Service_ARP, ///< The ARP service
67 Service_Audio, ///< The Audio (Audio control) service 67 Service_Audio, ///< The Audio (Audio control) service
68 Service_BCAT, ///< The BCAT service 68 Service_BCAT, ///< The BCAT service
69 Service_BGTC, ///< The BGTC (Background Task Controller) service
69 Service_BPC, ///< The BPC service 70 Service_BPC, ///< The BPC service
70 Service_BTDRV, ///< The Bluetooth driver service 71 Service_BTDRV, ///< The Bluetooth driver service
71 Service_BTM, ///< The BTM service 72 Service_BTM, ///< The BTM service
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index a4647314a..ad04df8ca 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -83,11 +83,15 @@ public:
83 return true; 83 return true;
84 } 84 }
85 85
86 T PopWait() { 86 void Wait() {
87 if (Empty()) { 87 if (Empty()) {
88 std::unique_lock lock{cv_mutex}; 88 std::unique_lock lock{cv_mutex};
89 cv.wait(lock, [this]() { return !Empty(); }); 89 cv.wait(lock, [this]() { return !Empty(); });
90 } 90 }
91 }
92
93 T PopWait() {
94 Wait();
91 T t; 95 T t;
92 Pop(t); 96 Pop(t);
93 return t; 97 return t;
@@ -156,6 +160,10 @@ public:
156 return spsc_queue.Pop(t); 160 return spsc_queue.Pop(t);
157 } 161 }
158 162
163 void Wait() {
164 spsc_queue.Wait();
165 }
166
159 T PopWait() { 167 T PopWait() {
160 return spsc_queue.PopWait(); 168 return spsc_queue.PopWait();
161 } 169 }
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index ec4407b6e..08d889135 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -114,18 +114,17 @@ public:
114 static constexpr u64 minimum_run_cycles = 1000U; 114 static constexpr u64 minimum_run_cycles = 1000U;
115}; 115};
116 116
117std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, 117std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
118 std::size_t address_space_bits) const {
119 Dynarmic::A32::UserConfig config; 118 Dynarmic::A32::UserConfig config;
120 config.callbacks = cb.get(); 119 config.callbacks = cb.get();
121 // TODO(bunnei): Implement page table for 32-bit
122 // config.page_table = &page_table.pointers;
123 config.coprocessors[15] = cp15; 120 config.coprocessors[15] = cp15;
124 config.define_unpredictable_behaviour = true; 121 config.define_unpredictable_behaviour = true;
125 static constexpr std::size_t PAGE_BITS = 12; 122 static constexpr std::size_t PAGE_BITS = 12;
126 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS); 123 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
127 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( 124 if (page_table) {
128 page_table.pointers.data()); 125 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
126 page_table->pointers.data());
127 }
129 config.absolute_offset_page_table = true; 128 config.absolute_offset_page_table = true;
130 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; 129 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
131 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; 130 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -138,6 +137,10 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
138 // Timing 137 // Timing
139 config.wall_clock_cntpct = uses_wall_clock; 138 config.wall_clock_cntpct = uses_wall_clock;
140 139
140 // Code cache size
141 config.code_cache_size = 512 * 1024 * 1024;
142 config.far_code_offset = 256 * 1024 * 1024;
143
141 // Safe optimizations 144 // Safe optimizations
142 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 145 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
143 if (!Settings::values.cpuopt_page_tables) { 146 if (!Settings::values.cpuopt_page_tables) {
@@ -201,7 +204,8 @@ ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handle
201 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 204 : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
202 cb(std::make_unique<DynarmicCallbacks32>(*this)), 205 cb(std::make_unique<DynarmicCallbacks32>(*this)),
203 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index}, 206 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
204 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} 207 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
208 jit(MakeJit(nullptr)) {}
205 209
206ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; 210ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
207 211
@@ -256,9 +260,6 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
256} 260}
257 261
258void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { 262void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
259 if (!jit) {
260 return;
261 }
262 Dynarmic::A32::Context context; 263 Dynarmic::A32::Context context;
263 jit->SaveContext(context); 264 jit->SaveContext(context);
264 ctx.cpu_registers = context.Regs(); 265 ctx.cpu_registers = context.Regs();
@@ -268,9 +269,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
268} 269}
269 270
270void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { 271void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
271 if (!jit) {
272 return;
273 }
274 Dynarmic::A32::Context context; 272 Dynarmic::A32::Context context;
275 context.Regs() = ctx.cpu_registers; 273 context.Regs() = ctx.cpu_registers;
276 context.ExtRegs() = ctx.extension_registers; 274 context.ExtRegs() = ctx.extension_registers;
@@ -284,35 +282,31 @@ void ARM_Dynarmic_32::PrepareReschedule() {
284} 282}
285 283
286void ARM_Dynarmic_32::ClearInstructionCache() { 284void ARM_Dynarmic_32::ClearInstructionCache() {
287 if (!jit) {
288 return;
289 }
290 jit->ClearCache(); 285 jit->ClearCache();
291} 286}
292 287
293void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) { 288void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
294 if (!jit) {
295 return;
296 }
297 jit->InvalidateCacheRange(static_cast<u32>(addr), size); 289 jit->InvalidateCacheRange(static_cast<u32>(addr), size);
298} 290}
299 291
300void ARM_Dynarmic_32::ClearExclusiveState() { 292void ARM_Dynarmic_32::ClearExclusiveState() {
301 if (!jit) {
302 return;
303 }
304 jit->ClearExclusiveState(); 293 jit->ClearExclusiveState();
305} 294}
306 295
307void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, 296void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
308 std::size_t new_address_space_size_in_bits) { 297 std::size_t new_address_space_size_in_bits) {
298 ThreadContext32 ctx{};
299 SaveContext(ctx);
300
309 auto key = std::make_pair(&page_table, new_address_space_size_in_bits); 301 auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
310 auto iter = jit_cache.find(key); 302 auto iter = jit_cache.find(key);
311 if (iter != jit_cache.end()) { 303 if (iter != jit_cache.end()) {
312 jit = iter->second; 304 jit = iter->second;
305 LoadContext(ctx);
313 return; 306 return;
314 } 307 }
315 jit = MakeJit(page_table, new_address_space_size_in_bits); 308 jit = MakeJit(&page_table);
309 LoadContext(ctx);
316 jit_cache.emplace(key, jit); 310 jit_cache.emplace(key, jit);
317} 311}
318 312
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index f6c4d4db9..d40aef7a9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -68,8 +68,7 @@ public:
68 std::size_t new_address_space_size_in_bits) override; 68 std::size_t new_address_space_size_in_bits) override;
69 69
70private: 70private:
71 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable& page_table, 71 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
72 std::size_t address_space_bits) const;
73 72
74 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; 73 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
75 using JitCacheType = 74 using JitCacheType =
@@ -80,10 +79,10 @@ private:
80 79
81 std::unique_ptr<DynarmicCallbacks32> cb; 80 std::unique_ptr<DynarmicCallbacks32> cb;
82 JitCacheType jit_cache; 81 JitCacheType jit_cache;
83 std::shared_ptr<Dynarmic::A32::Jit> jit;
84 std::shared_ptr<DynarmicCP15> cp15; 82 std::shared_ptr<DynarmicCP15> cp15;
85 std::size_t core_index; 83 std::size_t core_index;
86 DynarmicExclusiveMonitor& exclusive_monitor; 84 DynarmicExclusiveMonitor& exclusive_monitor;
85 std::shared_ptr<Dynarmic::A32::Jit> jit;
87}; 86};
88 87
89} // namespace Core 88} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index ae5566ab8..e12e50658 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -142,7 +142,7 @@ public:
142 static constexpr u64 minimum_run_cycles = 1000U; 142 static constexpr u64 minimum_run_cycles = 1000U;
143}; 143};
144 144
145std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, 145std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
146 std::size_t address_space_bits) const { 146 std::size_t address_space_bits) const {
147 Dynarmic::A64::UserConfig config; 147 Dynarmic::A64::UserConfig config;
148 148
@@ -150,13 +150,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
150 config.callbacks = cb.get(); 150 config.callbacks = cb.get();
151 151
152 // Memory 152 // Memory
153 config.page_table = reinterpret_cast<void**>(page_table.pointers.data()); 153 if (page_table) {
154 config.page_table_address_space_bits = address_space_bits; 154 config.page_table = reinterpret_cast<void**>(page_table->pointers.data());
155 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; 155 config.page_table_address_space_bits = address_space_bits;
156 config.silently_mirror_page_table = false; 156 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
157 config.absolute_offset_page_table = true; 157 config.silently_mirror_page_table = false;
158 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; 158 config.absolute_offset_page_table = true;
159 config.only_detect_misalignment_via_page_table_on_page_boundary = true; 159 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
160 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
161 }
160 162
161 // Multi-process state 163 // Multi-process state
162 config.processor_id = core_index; 164 config.processor_id = core_index;
@@ -175,6 +177,10 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
175 // Timing 177 // Timing
176 config.wall_clock_cntpct = uses_wall_clock; 178 config.wall_clock_cntpct = uses_wall_clock;
177 179
180 // Code cache size
181 config.code_cache_size = 512 * 1024 * 1024;
182 config.far_code_offset = 256 * 1024 * 1024;
183
178 // Safe optimizations 184 // Safe optimizations
179 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 185 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
180 if (!Settings::values.cpuopt_page_tables) { 186 if (!Settings::values.cpuopt_page_tables) {
@@ -237,7 +243,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
237 std::size_t core_index) 243 std::size_t core_index)
238 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 244 : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
239 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index}, 245 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
240 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} 246 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
247 jit(MakeJit(nullptr, 48)) {}
241 248
242ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; 249ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
243 250
@@ -294,9 +301,6 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
294} 301}
295 302
296void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { 303void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
297 if (!jit) {
298 return;
299 }
300 ctx.cpu_registers = jit->GetRegisters(); 304 ctx.cpu_registers = jit->GetRegisters();
301 ctx.sp = jit->GetSP(); 305 ctx.sp = jit->GetSP();
302 ctx.pc = jit->GetPC(); 306 ctx.pc = jit->GetPC();
@@ -308,9 +312,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
308} 312}
309 313
310void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { 314void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
311 if (!jit) {
312 return;
313 }
314 jit->SetRegisters(ctx.cpu_registers); 315 jit->SetRegisters(ctx.cpu_registers);
315 jit->SetSP(ctx.sp); 316 jit->SetSP(ctx.sp);
316 jit->SetPC(ctx.pc); 317 jit->SetPC(ctx.pc);
@@ -326,35 +327,31 @@ void ARM_Dynarmic_64::PrepareReschedule() {
326} 327}
327 328
328void ARM_Dynarmic_64::ClearInstructionCache() { 329void ARM_Dynarmic_64::ClearInstructionCache() {
329 if (!jit) {
330 return;
331 }
332 jit->ClearCache(); 330 jit->ClearCache();
333} 331}
334 332
335void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) { 333void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
336 if (!jit) {
337 return;
338 }
339 jit->InvalidateCacheRange(addr, size); 334 jit->InvalidateCacheRange(addr, size);
340} 335}
341 336
342void ARM_Dynarmic_64::ClearExclusiveState() { 337void ARM_Dynarmic_64::ClearExclusiveState() {
343 if (!jit) {
344 return;
345 }
346 jit->ClearExclusiveState(); 338 jit->ClearExclusiveState();
347} 339}
348 340
349void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, 341void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
350 std::size_t new_address_space_size_in_bits) { 342 std::size_t new_address_space_size_in_bits) {
343 ThreadContext64 ctx{};
344 SaveContext(ctx);
345
351 auto key = std::make_pair(&page_table, new_address_space_size_in_bits); 346 auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
352 auto iter = jit_cache.find(key); 347 auto iter = jit_cache.find(key);
353 if (iter != jit_cache.end()) { 348 if (iter != jit_cache.end()) {
354 jit = iter->second; 349 jit = iter->second;
350 LoadContext(ctx);
355 return; 351 return;
356 } 352 }
357 jit = MakeJit(page_table, new_address_space_size_in_bits); 353 jit = MakeJit(&page_table, new_address_space_size_in_bits);
354 LoadContext(ctx);
358 jit_cache.emplace(key, jit); 355 jit_cache.emplace(key, jit);
359} 356}
360 357
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 329b59a32..edef04376 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -61,7 +61,7 @@ public:
61 std::size_t new_address_space_size_in_bits) override; 61 std::size_t new_address_space_size_in_bits) override;
62 62
63private: 63private:
64 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table, 64 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
65 std::size_t address_space_bits) const; 65 std::size_t address_space_bits) const;
66 66
67 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; 67 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
@@ -71,10 +71,11 @@ private:
71 friend class DynarmicCallbacks64; 71 friend class DynarmicCallbacks64;
72 std::unique_ptr<DynarmicCallbacks64> cb; 72 std::unique_ptr<DynarmicCallbacks64> cb;
73 JitCacheType jit_cache; 73 JitCacheType jit_cache;
74 std::shared_ptr<Dynarmic::A64::Jit> jit;
75 74
76 std::size_t core_index; 75 std::size_t core_index;
77 DynarmicExclusiveMonitor& exclusive_monitor; 76 DynarmicExclusiveMonitor& exclusive_monitor;
77
78 std::shared_ptr<Dynarmic::A64::Jit> jit;
78}; 79};
79 80
80} // namespace Core 81} // namespace Core
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 305f56ff1..56b47e671 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -296,7 +296,7 @@ struct System::Impl {
296 exit_lock = false; 296 exit_lock = false;
297 297
298 if (gpu_core) { 298 if (gpu_core) {
299 gpu_core->WaitIdle(); 299 gpu_core->ShutDown();
300 } 300 }
301 301
302 services.reset(); 302 services.reset();
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index f1cca51dc..8e32865aa 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -195,9 +195,9 @@ private:
195 KSpinLock guard{}; 195 KSpinLock guard{};
196}; 196};
197 197
198class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> { 198class [[nodiscard]] KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
199public: 199public:
200 explicit KScopedSchedulerLock(KernelCore& kernel); 200 explicit KScopedSchedulerLock(KernelCore & kernel);
201 ~KScopedSchedulerLock(); 201 ~KScopedSchedulerLock();
202}; 202};
203 203
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
index d7cc557b2..72c3b0252 100644
--- a/src/core/hle/kernel/k_scoped_lock.h
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -20,19 +20,22 @@ concept KLockable = !std::is_reference_v<T> && requires(T & t) {
20}; 20};
21 21
22template <typename T> 22template <typename T>
23requires KLockable<T> class KScopedLock { 23requires KLockable<T> class [[nodiscard]] KScopedLock {
24public: 24public:
25 explicit KScopedLock(T* l) : lock_ptr(l) { 25 explicit KScopedLock(T * l) : lock_ptr(l) {
26 this->lock_ptr->Lock(); 26 this->lock_ptr->Lock();
27 } 27 }
28 explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) { /* ... */ 28 explicit KScopedLock(T & l) : KScopedLock(std::addressof(l)) {}
29 } 29
30 ~KScopedLock() { 30 ~KScopedLock() {
31 this->lock_ptr->Unlock(); 31 this->lock_ptr->Unlock();
32 } 32 }
33 33
34 KScopedLock(const KScopedLock&) = delete; 34 KScopedLock(const KScopedLock&) = delete;
35 KScopedLock(KScopedLock&&) = delete; 35 KScopedLock& operator=(const KScopedLock&) = delete;
36
37 KScopedLock(KScopedLock &&) = delete;
38 KScopedLock& operator=(KScopedLock&&) = delete;
36 39
37private: 40private:
38 T* lock_ptr; 41 T* lock_ptr;
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
index f8189e107..ebecf0c77 100644
--- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -15,9 +15,9 @@
15 15
16namespace Kernel { 16namespace Kernel {
17 17
18class KScopedSchedulerLockAndSleep { 18class [[nodiscard]] KScopedSchedulerLockAndSleep {
19public: 19public:
20 explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout) 20 explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout)
21 : kernel(kernel), thread(t), timeout_tick(timeout) { 21 : kernel(kernel), thread(t), timeout_tick(timeout) {
22 // Lock the scheduler. 22 // Lock the scheduler.
23 kernel.GlobalSchedulerContext().scheduler_lock.Lock(); 23 kernel.GlobalSchedulerContext().scheduler_lock.Lock();
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 557e63ea0..8fd990577 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -69,9 +69,9 @@ struct KernelCore::Impl {
69 InitializePhysicalCores(); 69 InitializePhysicalCores();
70 InitializeSystemResourceLimit(kernel, system); 70 InitializeSystemResourceLimit(kernel, system);
71 InitializeMemoryLayout(); 71 InitializeMemoryLayout();
72 InitializePreemption(kernel);
73 InitializeSchedulers(); 72 InitializeSchedulers();
74 InitializeSuspendThreads(); 73 InitializeSuspendThreads();
74 InitializePreemption(kernel);
75 } 75 }
76 76
77 void InitializeCores() { 77 void InitializeCores() {
@@ -144,10 +144,10 @@ struct KernelCore::Impl {
144 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000) 144 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000)
145 .IsSuccess()); 145 .IsSuccess());
146 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); 146 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
147 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess()); 147 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
148 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) 148 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
149 .IsSuccess()); 149 .IsSuccess());
150 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 933).IsSuccess()); 150 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
151 151
152 // Derived from recent software updates. The kernel reserves 27MB 152 // Derived from recent software updates. The kernel reserves 27MB
153 constexpr u64 kernel_size{0x1b00000}; 153 constexpr u64 kernel_size{0x1b00000};
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp
index 3fc326eab..1006ee50c 100644
--- a/src/core/hle/kernel/process_capability.cpp
+++ b/src/core/hle/kernel/process_capability.cpp
@@ -281,11 +281,6 @@ ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags)
281 continue; 281 continue;
282 } 282 }
283 283
284 if (svc_number >= svc_capabilities.size()) {
285 LOG_ERROR(Kernel, "Process svc capability is out of range! svc_number={}", svc_number);
286 return ResultOutOfRange;
287 }
288
289 svc_capabilities[svc_number] = true; 284 svc_capabilities[svc_number] = true;
290 } 285 }
291 286
diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h
index 73ad197fa..b7a9b2e45 100644
--- a/src/core/hle/kernel/process_capability.h
+++ b/src/core/hle/kernel/process_capability.h
@@ -68,7 +68,7 @@ enum class ProgramType {
68class ProcessCapabilities { 68class ProcessCapabilities {
69public: 69public:
70 using InterruptCapabilities = std::bitset<1024>; 70 using InterruptCapabilities = std::bitset<1024>;
71 using SyscallCapabilities = std::bitset<128>; 71 using SyscallCapabilities = std::bitset<192>;
72 72
73 ProcessCapabilities() = default; 73 ProcessCapabilities() = default;
74 ProcessCapabilities(const ProcessCapabilities&) = delete; 74 ProcessCapabilities(const ProcessCapabilities&) = delete;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 326d3b9ec..fcffc746d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2455,6 +2455,74 @@ static const FunctionDef SVC_Table_32[] = {
2455 {0x79, nullptr, "Unknown"}, 2455 {0x79, nullptr, "Unknown"},
2456 {0x7A, nullptr, "Unknown"}, 2456 {0x7A, nullptr, "Unknown"},
2457 {0x7B, nullptr, "TerminateProcess32"}, 2457 {0x7B, nullptr, "TerminateProcess32"},
2458 {0x7C, nullptr, "GetProcessInfo32"},
2459 {0x7D, nullptr, "CreateResourceLimit32"},
2460 {0x7E, nullptr, "SetResourceLimitLimitValue32"},
2461 {0x7F, nullptr, "CallSecureMonitor32"},
2462 {0x80, nullptr, "Unknown"},
2463 {0x81, nullptr, "Unknown"},
2464 {0x82, nullptr, "Unknown"},
2465 {0x83, nullptr, "Unknown"},
2466 {0x84, nullptr, "Unknown"},
2467 {0x85, nullptr, "Unknown"},
2468 {0x86, nullptr, "Unknown"},
2469 {0x87, nullptr, "Unknown"},
2470 {0x88, nullptr, "Unknown"},
2471 {0x89, nullptr, "Unknown"},
2472 {0x8A, nullptr, "Unknown"},
2473 {0x8B, nullptr, "Unknown"},
2474 {0x8C, nullptr, "Unknown"},
2475 {0x8D, nullptr, "Unknown"},
2476 {0x8E, nullptr, "Unknown"},
2477 {0x8F, nullptr, "Unknown"},
2478 {0x90, nullptr, "Unknown"},
2479 {0x91, nullptr, "Unknown"},
2480 {0x92, nullptr, "Unknown"},
2481 {0x93, nullptr, "Unknown"},
2482 {0x94, nullptr, "Unknown"},
2483 {0x95, nullptr, "Unknown"},
2484 {0x96, nullptr, "Unknown"},
2485 {0x97, nullptr, "Unknown"},
2486 {0x98, nullptr, "Unknown"},
2487 {0x99, nullptr, "Unknown"},
2488 {0x9A, nullptr, "Unknown"},
2489 {0x9B, nullptr, "Unknown"},
2490 {0x9C, nullptr, "Unknown"},
2491 {0x9D, nullptr, "Unknown"},
2492 {0x9E, nullptr, "Unknown"},
2493 {0x9F, nullptr, "Unknown"},
2494 {0xA0, nullptr, "Unknown"},
2495 {0xA1, nullptr, "Unknown"},
2496 {0xA2, nullptr, "Unknown"},
2497 {0xA3, nullptr, "Unknown"},
2498 {0xA4, nullptr, "Unknown"},
2499 {0xA5, nullptr, "Unknown"},
2500 {0xA6, nullptr, "Unknown"},
2501 {0xA7, nullptr, "Unknown"},
2502 {0xA8, nullptr, "Unknown"},
2503 {0xA9, nullptr, "Unknown"},
2504 {0xAA, nullptr, "Unknown"},
2505 {0xAB, nullptr, "Unknown"},
2506 {0xAC, nullptr, "Unknown"},
2507 {0xAD, nullptr, "Unknown"},
2508 {0xAE, nullptr, "Unknown"},
2509 {0xAF, nullptr, "Unknown"},
2510 {0xB0, nullptr, "Unknown"},
2511 {0xB1, nullptr, "Unknown"},
2512 {0xB2, nullptr, "Unknown"},
2513 {0xB3, nullptr, "Unknown"},
2514 {0xB4, nullptr, "Unknown"},
2515 {0xB5, nullptr, "Unknown"},
2516 {0xB6, nullptr, "Unknown"},
2517 {0xB7, nullptr, "Unknown"},
2518 {0xB8, nullptr, "Unknown"},
2519 {0xB9, nullptr, "Unknown"},
2520 {0xBA, nullptr, "Unknown"},
2521 {0xBB, nullptr, "Unknown"},
2522 {0xBC, nullptr, "Unknown"},
2523 {0xBD, nullptr, "Unknown"},
2524 {0xBE, nullptr, "Unknown"},
2525 {0xBF, nullptr, "Unknown"},
2458}; 2526};
2459 2527
2460static const FunctionDef SVC_Table_64[] = { 2528static const FunctionDef SVC_Table_64[] = {
@@ -2586,6 +2654,70 @@ static const FunctionDef SVC_Table_64[] = {
2586 {0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"}, 2654 {0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"},
2587 {0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"}, 2655 {0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
2588 {0x7F, nullptr, "CallSecureMonitor"}, 2656 {0x7F, nullptr, "CallSecureMonitor"},
2657 {0x80, nullptr, "Unknown"},
2658 {0x81, nullptr, "Unknown"},
2659 {0x82, nullptr, "Unknown"},
2660 {0x83, nullptr, "Unknown"},
2661 {0x84, nullptr, "Unknown"},
2662 {0x85, nullptr, "Unknown"},
2663 {0x86, nullptr, "Unknown"},
2664 {0x87, nullptr, "Unknown"},
2665 {0x88, nullptr, "Unknown"},
2666 {0x89, nullptr, "Unknown"},
2667 {0x8A, nullptr, "Unknown"},
2668 {0x8B, nullptr, "Unknown"},
2669 {0x8C, nullptr, "Unknown"},
2670 {0x8D, nullptr, "Unknown"},
2671 {0x8E, nullptr, "Unknown"},
2672 {0x8F, nullptr, "Unknown"},
2673 {0x90, nullptr, "Unknown"},
2674 {0x91, nullptr, "Unknown"},
2675 {0x92, nullptr, "Unknown"},
2676 {0x93, nullptr, "Unknown"},
2677 {0x94, nullptr, "Unknown"},
2678 {0x95, nullptr, "Unknown"},
2679 {0x96, nullptr, "Unknown"},
2680 {0x97, nullptr, "Unknown"},
2681 {0x98, nullptr, "Unknown"},
2682 {0x99, nullptr, "Unknown"},
2683 {0x9A, nullptr, "Unknown"},
2684 {0x9B, nullptr, "Unknown"},
2685 {0x9C, nullptr, "Unknown"},
2686 {0x9D, nullptr, "Unknown"},
2687 {0x9E, nullptr, "Unknown"},
2688 {0x9F, nullptr, "Unknown"},
2689 {0xA0, nullptr, "Unknown"},
2690 {0xA1, nullptr, "Unknown"},
2691 {0xA2, nullptr, "Unknown"},
2692 {0xA3, nullptr, "Unknown"},
2693 {0xA4, nullptr, "Unknown"},
2694 {0xA5, nullptr, "Unknown"},
2695 {0xA6, nullptr, "Unknown"},
2696 {0xA7, nullptr, "Unknown"},
2697 {0xA8, nullptr, "Unknown"},
2698 {0xA9, nullptr, "Unknown"},
2699 {0xAA, nullptr, "Unknown"},
2700 {0xAB, nullptr, "Unknown"},
2701 {0xAC, nullptr, "Unknown"},
2702 {0xAD, nullptr, "Unknown"},
2703 {0xAE, nullptr, "Unknown"},
2704 {0xAF, nullptr, "Unknown"},
2705 {0xB0, nullptr, "Unknown"},
2706 {0xB1, nullptr, "Unknown"},
2707 {0xB2, nullptr, "Unknown"},
2708 {0xB3, nullptr, "Unknown"},
2709 {0xB4, nullptr, "Unknown"},
2710 {0xB5, nullptr, "Unknown"},
2711 {0xB6, nullptr, "Unknown"},
2712 {0xB7, nullptr, "Unknown"},
2713 {0xB8, nullptr, "Unknown"},
2714 {0xB9, nullptr, "Unknown"},
2715 {0xBA, nullptr, "Unknown"},
2716 {0xBB, nullptr, "Unknown"},
2717 {0xBC, nullptr, "Unknown"},
2718 {0xBD, nullptr, "Unknown"},
2719 {0xBE, nullptr, "Unknown"},
2720 {0xBF, nullptr, "Unknown"},
2589}; 2721};
2590 2722
2591static const FunctionDef* GetSVCInfo32(u32 func_num) { 2723static const FunctionDef* GetSVCInfo32(u32 func_num) {
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 615e20a54..52535ecc0 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -610,12 +610,17 @@ public:
610 explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} { 610 explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} {
611 // clang-format off 611 // clang-format off
612 static const FunctionInfo functions[] = { 612 static const FunctionInfo functions[] = {
613 {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData 613 {0, nullptr, "EnsureAuthenticationTokenCacheAsync"},
614 {1, nullptr, "LoadAuthenticationTokenCache"}, // 6.0.0+ 614 {1, nullptr, "LoadAuthenticationTokenCache"},
615 {2, nullptr, "InvalidateAuthenticationTokenCache"}, // 6.0.0+ 615 {2, nullptr, "InvalidateAuthenticationTokenCache"},
616 {10, nullptr, "EnsureEdgeTokenCacheAsync"}, // 6.0.0+ 616 {10, nullptr, "EnsureEdgeTokenCacheAsync"},
617 {11, nullptr, "LoadEdgeTokenCache"}, // 6.0.0+ 617 {11, nullptr, "LoadEdgeTokenCache"},
618 {12, nullptr, "InvalidateEdgeTokenCache"}, // 6.0.0+ 618 {12, nullptr, "InvalidateEdgeTokenCache"},
619 {20, nullptr, "EnsureApplicationAuthenticationCacheAsync"},
620 {21, nullptr, "LoadApplicationAuthenticationTokenCache"},
621 {22, nullptr, "LoadApplicationNetworkServiceClientConfigCache"},
622 {23, nullptr, "IsApplicationAuthenticationCacheAvailable"},
623 {24, nullptr, "InvalidateApplicationAuthenticationCache"},
619 }; 624 };
620 // clang-format on 625 // clang-format on
621 626
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index 49b22583e..bb6118abf 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -17,28 +17,30 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
17 {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"}, 17 {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"},
18 {4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"}, 18 {4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"},
19 {5, &ACC_SU::GetProfile, "GetProfile"}, 19 {5, &ACC_SU::GetProfile, "GetProfile"},
20 {6, nullptr, "GetProfileDigest"}, // 3.0.0+ 20 {6, nullptr, "GetProfileDigest"},
21 {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, 21 {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
22 {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, 22 {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
23 {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 23 {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
24 {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ 24 {99, nullptr, "DebugActivateOpenContextRetention"},
25 {100, nullptr, "GetUserRegistrationNotifier"}, 25 {100, nullptr, "GetUserRegistrationNotifier"},
26 {101, nullptr, "GetUserStateChangeNotifier"}, 26 {101, nullptr, "GetUserStateChangeNotifier"},
27 {102, nullptr, "GetBaasAccountManagerForSystemService"}, 27 {102, nullptr, "GetBaasAccountManagerForSystemService"},
28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, 28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
29 {104, nullptr, "GetProfileUpdateNotifier"}, 29 {104, nullptr, "GetProfileUpdateNotifier"},
30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ 30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
31 {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ 31 {106, nullptr, "GetProfileSyncNotifier"},
32 {110, &ACC_SU::StoreSaveDataThumbnailSystem, "StoreSaveDataThumbnail"}, 32 {110, &ACC_SU::StoreSaveDataThumbnailSystem, "StoreSaveDataThumbnail"},
33 {111, nullptr, "ClearSaveDataThumbnail"}, 33 {111, nullptr, "ClearSaveDataThumbnail"},
34 {112, nullptr, "LoadSaveDataThumbnail"}, 34 {112, nullptr, "LoadSaveDataThumbnail"},
35 {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ 35 {113, nullptr, "GetSaveDataThumbnailExistence"},
36 {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+ 36 {120, nullptr, "ListOpenUsersInApplication"},
37 {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+ 37 {130, nullptr, "ActivateOpenContextRetention"},
38 {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ 38 {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"},
39 {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+ 39 {150, nullptr, "AuthenticateApplicationAsync"},
40 {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0 40 {151, nullptr, "Unknown151"},
41 {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+ 41 {152, nullptr, "Unknown152"},
42 {190, nullptr, "GetUserLastOpenedApplication"},
43 {191, nullptr, "ActivateOpenContextHolder"},
42 {200, nullptr, "BeginUserRegistration"}, 44 {200, nullptr, "BeginUserRegistration"},
43 {201, nullptr, "CompleteUserRegistration"}, 45 {201, nullptr, "CompleteUserRegistration"},
44 {202, nullptr, "CancelUserRegistration"}, 46 {202, nullptr, "CancelUserRegistration"},
@@ -46,15 +48,15 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
46 {204, nullptr, "SetUserPosition"}, 48 {204, nullptr, "SetUserPosition"},
47 {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"}, 49 {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
48 {206, nullptr, "CompleteUserRegistrationForcibly"}, 50 {206, nullptr, "CompleteUserRegistrationForcibly"},
49 {210, nullptr, "CreateFloatingRegistrationRequest"}, // 3.0.0+ 51 {210, nullptr, "CreateFloatingRegistrationRequest"},
50 {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+ 52 {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"},
51 {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+ 53 {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"},
52 {230, nullptr, "AuthenticateServiceAsync"}, 54 {230, nullptr, "AuthenticateServiceAsync"},
53 {250, nullptr, "GetBaasAccountAdministrator"}, 55 {250, nullptr, "GetBaasAccountAdministrator"},
54 {290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"}, 56 {290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
55 {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"}, // 3.0.0+ 57 {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
56 {299, nullptr, "SuspendBackgroundDaemon"}, 58 {299, nullptr, "SuspendBackgroundDaemon"},
57 {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+ 59 {997, nullptr, "DebugInvalidateTokenCacheForUser"},
58 {998, nullptr, "DebugSetUserStateClose"}, 60 {998, nullptr, "DebugSetUserStateClose"},
59 {999, nullptr, "DebugSetUserStateOpen"}, 61 {999, nullptr, "DebugSetUserStateOpen"},
60 }; 62 };
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index 951081cd0..71982ad5a 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -17,29 +17,31 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
17 {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"}, 17 {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"},
18 {4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"}, 18 {4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"},
19 {5, &ACC_U1::GetProfile, "GetProfile"}, 19 {5, &ACC_U1::GetProfile, "GetProfile"},
20 {6, nullptr, "GetProfileDigest"}, // 3.0.0+ 20 {6, nullptr, "GetProfileDigest"},
21 {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, 21 {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
22 {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, 22 {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
23 {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 23 {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
24 {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ 24 {99, nullptr, "DebugActivateOpenContextRetention"},
25 {100, nullptr, "GetUserRegistrationNotifier"}, 25 {100, nullptr, "GetUserRegistrationNotifier"},
26 {101, nullptr, "GetUserStateChangeNotifier"}, 26 {101, nullptr, "GetUserStateChangeNotifier"},
27 {102, nullptr, "GetBaasAccountManagerForSystemService"}, 27 {102, nullptr, "GetBaasAccountManagerForSystemService"},
28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, 28 {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
29 {104, nullptr, "GetProfileUpdateNotifier"}, 29 {104, nullptr, "GetProfileUpdateNotifier"},
30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ 30 {105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
31 {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ 31 {106, nullptr, "GetProfileSyncNotifier"},
32 {110, &ACC_U1::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"}, 32 {110, &ACC_U1::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},
33 {111, nullptr, "ClearSaveDataThumbnail"}, 33 {111, nullptr, "ClearSaveDataThumbnail"},
34 {112, nullptr, "LoadSaveDataThumbnail"}, 34 {112, nullptr, "LoadSaveDataThumbnail"},
35 {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ 35 {113, nullptr, "GetSaveDataThumbnailExistence"},
36 {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+ 36 {120, nullptr, "ListOpenUsersInApplication"},
37 {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+ 37 {130, nullptr, "ActivateOpenContextRetention"},
38 {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ 38 {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"},
39 {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+ 39 {150, nullptr, "AuthenticateApplicationAsync"},
40 {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0 40 {151, nullptr, "Unknown151"},
41 {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+ 41 {152, nullptr, "Unknown152"},
42 {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+ 42 {190, nullptr, "GetUserLastOpenedApplication"},
43 {191, nullptr, "ActivateOpenContextHolder"},
44 {997, nullptr, "DebugInvalidateTokenCacheForUser"},
43 {998, nullptr, "DebugSetUserStateClose"}, 45 {998, nullptr, "DebugSetUserStateClose"},
44 {999, nullptr, "DebugSetUserStateOpen"}, 46 {999, nullptr, "DebugSetUserStateOpen"},
45 }; 47 };
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 8e1fe9438..4374487a3 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -231,6 +231,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
231 {10, nullptr, "PerformSystemButtonPressing"}, 231 {10, nullptr, "PerformSystemButtonPressing"},
232 {20, nullptr, "InvalidateTransitionLayer"}, 232 {20, nullptr, "InvalidateTransitionLayer"},
233 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, 233 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
234 {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
234 {40, nullptr, "GetAppletResourceUsageInfo"}, 235 {40, nullptr, "GetAppletResourceUsageInfo"},
235 {100, nullptr, "SetCpuBoostModeForApplet"}, 236 {100, nullptr, "SetCpuBoostModeForApplet"},
236 {101, nullptr, "CancelCpuBoostModeForApplet"}, 237 {101, nullptr, "CancelCpuBoostModeForApplet"},
@@ -242,6 +243,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
242 {130, nullptr, "FriendInvitationSetApplicationParameter"}, 243 {130, nullptr, "FriendInvitationSetApplicationParameter"},
243 {131, nullptr, "FriendInvitationClearApplicationParameter"}, 244 {131, nullptr, "FriendInvitationClearApplicationParameter"},
244 {132, nullptr, "FriendInvitationPushApplicationParameter"}, 245 {132, nullptr, "FriendInvitationPushApplicationParameter"},
246 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
245 }; 247 };
246 // clang-format on 248 // clang-format on
247 249
@@ -295,8 +297,9 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
295 {80, nullptr, "SetWirelessPriorityMode"}, 297 {80, nullptr, "SetWirelessPriorityMode"},
296 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, 298 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
297 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, 299 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
298 {100, nullptr, "SetAlbumImageTakenNotificationEnabled"}, 300 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
299 {110, nullptr, "SetApplicationAlbumUserData"}, 301 {110, nullptr, "SetApplicationAlbumUserData"},
302 {120, nullptr, "SaveCurrentScreenshot"},
300 {1000, nullptr, "GetDebugStorageChannel"}, 303 {1000, nullptr, "GetDebugStorageChannel"},
301 }; 304 };
302 // clang-format on 305 // clang-format on
@@ -560,6 +563,21 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
560 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); 563 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
561} 564}
562 565
566void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
567 IPC::RequestParser rp{ctx};
568
569 // This service call sets an internal flag whether a notification is shown when an image is
570 // captured. Currently we do not support capturing images via the capture button, so this can be
571 // stubbed for now.
572 const bool album_image_taken_notification_enabled = rp.Pop<bool>();
573
574 LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}",
575 album_image_taken_notification_enabled);
576
577 IPC::ResponseBuilder rb{ctx, 2};
578 rb.Push(RESULT_SUCCESS);
579}
580
563AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { 581AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
564 on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived"); 582 on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived");
565 on_new_message->Initialize(); 583 on_new_message->Initialize();
@@ -630,6 +648,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
630 {11, nullptr, "ReleaseSleepLock"}, 648 {11, nullptr, "ReleaseSleepLock"},
631 {12, nullptr, "ReleaseSleepLockTransiently"}, 649 {12, nullptr, "ReleaseSleepLockTransiently"},
632 {13, nullptr, "GetAcquiredSleepLockEvent"}, 650 {13, nullptr, "GetAcquiredSleepLockEvent"},
651 {14, nullptr, "GetWakeupCount"},
633 {20, nullptr, "PushToGeneralChannel"}, 652 {20, nullptr, "PushToGeneralChannel"},
634 {30, nullptr, "GetHomeButtonReaderLockAccessor"}, 653 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
635 {31, nullptr, "GetReaderLockAccessorEx"}, 654 {31, nullptr, "GetReaderLockAccessorEx"},
@@ -641,6 +660,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
641 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, 660 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
642 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, 661 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
643 {55, nullptr, "IsInControllerFirmwareUpdateSection"}, 662 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
663 {59, nullptr, "SetVrPositionForDebug"},
644 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, 664 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
645 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, 665 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
646 {62, nullptr, "GetHdcpAuthenticationState"}, 666 {62, nullptr, "GetHdcpAuthenticationState"},
@@ -649,14 +669,21 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
649 {65, nullptr, "GetApplicationIdByContentActionName"}, 669 {65, nullptr, "GetApplicationIdByContentActionName"},
650 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, 670 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
651 {67, nullptr, "CancelCpuBoostMode"}, 671 {67, nullptr, "CancelCpuBoostMode"},
672 {68, nullptr, "GetBuiltInDisplayType"},
652 {80, nullptr, "PerformSystemButtonPressingIfInFocus"}, 673 {80, nullptr, "PerformSystemButtonPressingIfInFocus"},
653 {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, 674 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
654 {91, nullptr, "GetCurrentPerformanceConfiguration"}, 675 {91, nullptr, "GetCurrentPerformanceConfiguration"},
655 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, 676 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
677 {110, nullptr, "OpenMyGpuErrorHandler"},
656 {200, nullptr, "GetOperationModeSystemInfo"}, 678 {200, nullptr, "GetOperationModeSystemInfo"},
657 {300, nullptr, "GetSettingsPlatformRegion"}, 679 {300, nullptr, "GetSettingsPlatformRegion"},
658 {400, nullptr, "ActivateMigrationService"}, 680 {400, nullptr, "ActivateMigrationService"},
659 {401, nullptr, "DeactivateMigrationService"}, 681 {401, nullptr, "DeactivateMigrationService"},
682 {500, nullptr, "DisableSleepTillShutdown"},
683 {501, nullptr, "SuppressDisablingSleepTemporarily"},
684 {502, nullptr, "IsSleepEnabled"},
685 {503, nullptr, "IsDisablingSleepSuppressed"},
686 {900, nullptr, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
660 }; 687 };
661 // clang-format on 688 // clang-format on
662 689
@@ -1188,11 +1215,14 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1188 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, 1215 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
1189 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, 1216 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
1190 {27, nullptr, "CreateCacheStorage"}, 1217 {27, nullptr, "CreateCacheStorage"},
1218 {28, nullptr, "GetSaveDataSizeMax"},
1219 {29, nullptr, "GetCacheStorageMax"},
1191 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, 1220 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
1192 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, 1221 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
1193 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, 1222 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
1194 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, 1223 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
1195 {34, nullptr, "SelectApplicationLicense"}, 1224 {34, nullptr, "SelectApplicationLicense"},
1225 {35, nullptr, "GetDeviceSaveDataSizeMax"},
1196 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, 1226 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
1197 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, 1227 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
1198 {60, nullptr, "SetMediaPlaybackStateForApplication"}, 1228 {60, nullptr, "SetMediaPlaybackStateForApplication"},
@@ -1216,6 +1246,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1216 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, 1246 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
1217 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, 1247 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
1218 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, 1248 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
1249 {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
1219 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, 1250 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
1220 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, 1251 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
1221 {150, nullptr, "GetNotificationStorageChannelEvent"}, 1252 {150, nullptr, "GetNotificationStorageChannelEvent"},
@@ -1224,6 +1255,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1224 {170, nullptr, "SetHdcpAuthenticationActivated"}, 1255 {170, nullptr, "SetHdcpAuthenticationActivated"},
1225 {180, nullptr, "GetLaunchRequiredVersion"}, 1256 {180, nullptr, "GetLaunchRequiredVersion"},
1226 {181, nullptr, "UpgradeLaunchRequiredVersion"}, 1257 {181, nullptr, "UpgradeLaunchRequiredVersion"},
1258 {190, nullptr, "SendServerMaintenanceOverlayNotification"},
1259 {200, nullptr, "GetLastApplicationExitReason"},
1227 {500, nullptr, "StartContinuousRecordingFlushForDebug"}, 1260 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
1228 {1000, nullptr, "CreateMovieMaker"}, 1261 {1000, nullptr, "CreateMovieMaker"},
1229 {1001, nullptr, "PrepareForJit"}, 1262 {1001, nullptr, "PrepareForJit"},
@@ -1690,9 +1723,12 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
1690 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, 1723 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
1691 {30, nullptr, "GetHomeButtonWriterLockAccessor"}, 1724 {30, nullptr, "GetHomeButtonWriterLockAccessor"},
1692 {31, nullptr, "GetWriterLockAccessorEx"}, 1725 {31, nullptr, "GetWriterLockAccessorEx"},
1726 {40, nullptr, "IsSleepEnabled"},
1727 {41, nullptr, "IsRebootEnabled"},
1693 {100, nullptr, "PopRequestLaunchApplicationForDebug"}, 1728 {100, nullptr, "PopRequestLaunchApplicationForDebug"},
1694 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, 1729 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
1695 {200, nullptr, "LaunchDevMenu"}, 1730 {200, nullptr, "LaunchDevMenu"},
1731 {1000, nullptr, "SetLastApplicationExitReason"},
1696 }; 1732 };
1697 // clang-format on 1733 // clang-format on
1698 1734
@@ -1736,6 +1772,7 @@ IGlobalStateController::IGlobalStateController(Core::System& system_)
1736 {13, nullptr, "UpdateDefaultDisplayResolution"}, 1772 {13, nullptr, "UpdateDefaultDisplayResolution"},
1737 {14, nullptr, "ShouldSleepOnBoot"}, 1773 {14, nullptr, "ShouldSleepOnBoot"},
1738 {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, 1774 {15, nullptr, "GetHdcpAuthenticationFailedEvent"},
1775 {30, nullptr, "OpenCradleFirmwareUpdater"},
1739 }; 1776 };
1740 // clang-format on 1777 // clang-format on
1741 1778
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 6911f0d6e..f6a453ab7 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -146,6 +146,7 @@ private:
146 void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx); 146 void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx);
147 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); 147 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
148 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); 148 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
149 void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx);
149 150
150 enum class ScreenshotPermission : u32 { 151 enum class ScreenshotPermission : u32 {
151 Inherit = 0, 152 Inherit = 0,
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 8d657c0bf..0f51e5871 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -118,8 +118,10 @@ AOC_U::AOC_U(Core::System& system_)
118 {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, 118 {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
119 {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, 119 {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
120 {9, nullptr, "GetAddOnContentLostErrorCode"}, 120 {9, nullptr, "GetAddOnContentLostErrorCode"},
121 {10, nullptr, "GetAddOnContentListChangedEventWithProcessId"},
121 {100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"}, 122 {100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
122 {101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"}, 123 {101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
124 {110, nullptr, "CreateContentsServiceManager"},
123 }; 125 };
124 // clang-format on 126 // clang-format on
125 127
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
index 79c3aa920..10acaad19 100644
--- a/src/core/hle/service/audio/audin_a.cpp
+++ b/src/core/hle/service/audio/audin_a.cpp
@@ -9,10 +9,10 @@ namespace Service::Audio {
9AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} { 9AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioIns"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeAudioIns"}, 13 {1, nullptr, "RequestResume"},
14 {2, nullptr, "GetAudioInsProcessMasterVolume"}, 14 {2, nullptr, "GetProcessMasterVolume"},
15 {3, nullptr, "SetAudioInsProcessMasterVolume"}, 15 {3, nullptr, "SetProcessMasterVolume"},
16 }; 16 };
17 // clang-format on 17 // clang-format on
18 18
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 26a6deddf..ecd05e4a6 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -15,19 +15,19 @@ public:
15 // clang-format off 15 // clang-format off
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GetAudioInState"}, 17 {0, nullptr, "GetAudioInState"},
18 {1, nullptr, "StartAudioIn"}, 18 {1, nullptr, "Start"},
19 {2, nullptr, "StopAudioIn"}, 19 {2, nullptr, "Stop"},
20 {3, nullptr, "AppendAudioInBuffer"}, 20 {3, nullptr, "AppendAudioInBuffer"},
21 {4, nullptr, "RegisterBufferEvent"}, 21 {4, nullptr, "RegisterBufferEvent"},
22 {5, nullptr, "GetReleasedAudioInBuffer"}, 22 {5, nullptr, "GetReleasedAudioInBuffer"},
23 {6, nullptr, "ContainsAudioInBuffer"}, 23 {6, nullptr, "ContainsAudioInBuffer"},
24 {7, nullptr, "AppendAudioInBufferWithUserEvent"}, 24 {7, nullptr, "AppendUacInBuffer"},
25 {8, nullptr, "AppendAudioInBufferAuto"}, 25 {8, nullptr, "AppendAudioInBufferAuto"},
26 {9, nullptr, "GetReleasedAudioInBufferAuto"}, 26 {9, nullptr, "GetReleasedAudioInBuffersAuto"},
27 {10, nullptr, "AppendAudioInBufferWithUserEventAuto"}, 27 {10, nullptr, "AppendUacInBufferAuto"},
28 {11, nullptr, "GetAudioInBufferCount"}, 28 {11, nullptr, "GetAudioInBufferCount"},
29 {12, nullptr, "SetAudioInDeviceGain"}, 29 {12, nullptr, "SetDeviceGain"},
30 {13, nullptr, "GetAudioInDeviceGain"}, 30 {13, nullptr, "GetDeviceGain"},
31 {14, nullptr, "FlushAudioInBuffers"}, 31 {14, nullptr, "FlushAudioInBuffers"},
32 }; 32 };
33 // clang-format on 33 // clang-format on
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
index 19825fd5d..3ee522b50 100644
--- a/src/core/hle/service/audio/audout_a.cpp
+++ b/src/core/hle/service/audio/audout_a.cpp
@@ -9,12 +9,12 @@ namespace Service::Audio {
9AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} { 9AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioOuts"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeAudioOuts"}, 13 {1, nullptr, "RequestResume"},
14 {2, nullptr, "GetAudioOutsProcessMasterVolume"}, 14 {2, nullptr, "GetProcessMasterVolume"},
15 {3, nullptr, "SetAudioOutsProcessMasterVolume"}, 15 {3, nullptr, "SetProcessMasterVolume"},
16 {4, nullptr, "GetAudioOutsProcessRecordVolume"}, 16 {4, nullptr, "GetProcessRecordVolume"},
17 {5, nullptr, "SetAudioOutsProcessRecordVolume"}, 17 {5, nullptr, "SetProcessRecordVolume"},
18 }; 18 };
19 // clang-format on 19 // clang-format on
20 20
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 5ed9cb20e..5f51fca9a 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -49,11 +49,11 @@ public:
49 // clang-format off 49 // clang-format off
50 static const FunctionInfo functions[] = { 50 static const FunctionInfo functions[] = {
51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
52 {1, &IAudioOut::StartAudioOut, "StartAudioOut"}, 52 {1, &IAudioOut::StartAudioOut, "Start"},
53 {2, &IAudioOut::StopAudioOut, "StopAudioOut"}, 53 {2, &IAudioOut::StopAudioOut, "Stop"},
54 {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"}, 54 {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
55 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, 55 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
56 {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"}, 56 {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffers"},
57 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"}, 57 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
58 {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"}, 58 {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
59 {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"}, 59 {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp
index c5ab7cad4..70fc17ae2 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/audrec_a.cpp
@@ -9,8 +9,8 @@ namespace Service::Audio {
9AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} { 9AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendFinalOutputRecorders"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeFinalOutputRecorders"}, 13 {1, nullptr, "RequestResume"},
14 }; 14 };
15 // clang-format on 15 // clang-format on
16 16
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
index eb5c63c62..74a65ccff 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -13,16 +13,17 @@ public:
13 // clang-format off 13 // clang-format off
14 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
15 {0, nullptr, "GetFinalOutputRecorderState"}, 15 {0, nullptr, "GetFinalOutputRecorderState"},
16 {1, nullptr, "StartFinalOutputRecorder"}, 16 {1, nullptr, "Start"},
17 {2, nullptr, "StopFinalOutputRecorder"}, 17 {2, nullptr, "Stop"},
18 {3, nullptr, "AppendFinalOutputRecorderBuffer"}, 18 {3, nullptr, "AppendFinalOutputRecorderBuffer"},
19 {4, nullptr, "RegisterBufferEvent"}, 19 {4, nullptr, "RegisterBufferEvent"},
20 {5, nullptr, "GetReleasedFinalOutputRecorderBuffer"}, 20 {5, nullptr, "GetReleasedFinalOutputRecorderBuffers"},
21 {6, nullptr, "ContainsFinalOutputRecorderBuffer"}, 21 {6, nullptr, "ContainsFinalOutputRecorderBuffer"},
22 {7, nullptr, "GetFinalOutputRecorderBufferEndTime"}, 22 {7, nullptr, "GetFinalOutputRecorderBufferEndTime"},
23 {8, nullptr, "AppendFinalOutputRecorderBufferAuto"}, 23 {8, nullptr, "AppendFinalOutputRecorderBufferAuto"},
24 {9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"}, 24 {9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"},
25 {10, nullptr, "FlushFinalOutputRecorderBuffers"}, 25 {10, nullptr, "FlushFinalOutputRecorderBuffers"},
26 {11, nullptr, "AttachWorkBuffer"},
26 }; 27 };
27 // clang-format on 28 // clang-format on
28 29
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
index 5e9f866f0..cf8c34a15 100644
--- a/src/core/hle/service/audio/audren_a.cpp
+++ b/src/core/hle/service/audio/audren_a.cpp
@@ -9,14 +9,14 @@ namespace Service::Audio {
9AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} { 9AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioRenderers"}, 12 {0, nullptr, "RequestSuspend"},
13 {1, nullptr, "RequestResumeAudioRenderers"}, 13 {1, nullptr, "RequestResume"},
14 {2, nullptr, "GetAudioRenderersProcessMasterVolume"}, 14 {2, nullptr, "GetProcessMasterVolume"},
15 {3, nullptr, "SetAudioRenderersProcessMasterVolume"}, 15 {3, nullptr, "SetProcessMasterVolume"},
16 {4, nullptr, "RegisterAppletResourceUserId"}, 16 {4, nullptr, "RegisterAppletResourceUserId"},
17 {5, nullptr, "UnregisterAppletResourceUserId"}, 17 {5, nullptr, "UnregisterAppletResourceUserId"},
18 {6, nullptr, "GetAudioRenderersProcessRecordVolume"}, 18 {6, nullptr, "GetProcessRecordVolume"},
19 {7, nullptr, "SetAudioRenderersProcessRecordVolume"}, 19 {7, nullptr, "SetProcessRecordVolume"},
20 }; 20 };
21 // clang-format on 21 // clang-format on
22 22
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index b2b2ffc5a..572be8e00 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -332,9 +332,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"}
332 // clang-format off 332 // clang-format off
333 static const FunctionInfo functions[] = { 333 static const FunctionInfo functions[] = {
334 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 334 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
335 {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"}, 335 {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetWorkBufferSize"},
336 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"}, 336 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
337 {3, &AudRenU::OpenAudioRendererAuto, "OpenAudioRendererAuto"}, 337 {3, &AudRenU::OpenAudioRendererForManualExecution, "OpenAudioRendererForManualExecution"},
338 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"}, 338 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
339 }; 339 };
340 // clang-format on 340 // clang-format on
@@ -665,7 +665,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
665 rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); 665 rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1'));
666} 666}
667 667
668void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { 668void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
669 LOG_DEBUG(Service_Audio, "called"); 669 LOG_DEBUG(Service_Audio, "called");
670 670
671 OpenAudioRendererImpl(ctx); 671 OpenAudioRendererImpl(ctx);
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index d693dc406..37e8b4716 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -25,7 +25,7 @@ private:
25 void OpenAudioRenderer(Kernel::HLERequestContext& ctx); 25 void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
26 void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); 26 void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
27 void GetAudioDeviceService(Kernel::HLERequestContext& ctx); 27 void GetAudioDeviceService(Kernel::HLERequestContext& ctx);
28 void OpenAudioRendererAuto(Kernel::HLERequestContext& ctx); 28 void OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx);
29 void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx); 29 void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
30 30
31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); 31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
index 94afec1b6..42961d908 100644
--- a/src/core/hle/service/audio/codecctl.cpp
+++ b/src/core/hle/service/audio/codecctl.cpp
@@ -8,19 +8,19 @@ namespace Service::Audio {
8 8
9CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} { 9CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} {
10 static const FunctionInfo functions[] = { 10 static const FunctionInfo functions[] = {
11 {0, nullptr, "InitializeCodecController"}, 11 {0, nullptr, "Initialize"},
12 {1, nullptr, "FinalizeCodecController"}, 12 {1, nullptr, "Finalize"},
13 {2, nullptr, "SleepCodecController"}, 13 {2, nullptr, "Sleep"},
14 {3, nullptr, "WakeCodecController"}, 14 {3, nullptr, "Wake"},
15 {4, nullptr, "SetCodecVolume"}, 15 {4, nullptr, "SetVolume"},
16 {5, nullptr, "GetCodecVolumeMax"}, 16 {5, nullptr, "GetVolumeMax"},
17 {6, nullptr, "GetCodecVolumeMin"}, 17 {6, nullptr, "GetVolumeMin"},
18 {7, nullptr, "SetCodecActiveTarget"}, 18 {7, nullptr, "SetActiveTarget"},
19 {8, nullptr, "GetCodecActiveTarget"}, 19 {8, nullptr, "GetActiveTarget"},
20 {9, nullptr, "BindCodecHeadphoneMicJackInterrupt"}, 20 {9, nullptr, "BindHeadphoneMicJackInterrupt"},
21 {10, nullptr, "IsCodecHeadphoneMicJackInserted"}, 21 {10, nullptr, "IsHeadphoneMicJackInserted"},
22 {11, nullptr, "ClearCodecHeadphoneMicJackInterrupt"}, 22 {11, nullptr, "ClearHeadphoneMicJackInterrupt"},
23 {12, nullptr, "IsCodecDeviceRequested"}, 23 {12, nullptr, "IsRequested"},
24 }; 24 };
25 RegisterHandlers(functions); 25 RegisterHandlers(functions);
26} 26}
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index ea3414fd2..19c578b3a 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -297,6 +297,10 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
297 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, 297 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
298 {2, nullptr, "OpenOpusDecoderForMultiStream"}, 298 {2, nullptr, "OpenOpusDecoderForMultiStream"},
299 {3, nullptr, "GetWorkBufferSizeForMultiStream"}, 299 {3, nullptr, "GetWorkBufferSizeForMultiStream"},
300 {4, nullptr, "OpenHardwareOpusDecoderEx"},
301 {5, nullptr, "GetWorkBufferSizeEx"},
302 {6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
303 {7, nullptr, "GetWorkBufferSizeForMultiStreamEx"},
300 }; 304 };
301 RegisterHandlers(functions); 305 RegisterHandlers(functions);
302} 306}
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 503109fdd..b68e2c345 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -155,10 +155,12 @@ public:
155 {30210, nullptr, "SetDeliveryTaskTimer"}, 155 {30210, nullptr, "SetDeliveryTaskTimer"},
156 {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"}, 156 {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"},
157 {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, 157 {90100, nullptr, "EnumerateBackgroundDeliveryTask"},
158 {90101, nullptr, "Unknown90101"},
158 {90200, nullptr, "GetDeliveryList"}, 159 {90200, nullptr, "GetDeliveryList"},
159 {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, 160 {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"},
160 {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"}, 161 {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
161 {90300, nullptr, "GetPushNotificationLog"}, 162 {90300, nullptr, "GetPushNotificationLog"},
163 {90301, nullptr, "Unknown90301"},
162 }; 164 };
163 // clang-format on 165 // clang-format on
164 RegisterHandlers(functions); 166 RegisterHandlers(functions);
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp
index e4630320e..78e01d8d8 100644
--- a/src/core/hle/service/bpc/bpc.cpp
+++ b/src/core/hle/service/bpc/bpc.cpp
@@ -29,8 +29,8 @@ public:
29 {11, nullptr, "CreateWakeupTimerEx"}, 29 {11, nullptr, "CreateWakeupTimerEx"},
30 {12, nullptr, "GetLastEnabledWakeupTimerType"}, 30 {12, nullptr, "GetLastEnabledWakeupTimerType"},
31 {13, nullptr, "CleanAllWakeupTimers"}, 31 {13, nullptr, "CleanAllWakeupTimers"},
32 {14, nullptr, "Unknown"}, 32 {14, nullptr, "GetPowerButton"},
33 {15, nullptr, "Unknown2"}, 33 {15, nullptr, "SetEnableWakeupTimer"},
34 }; 34 };
35 // clang-format on 35 // clang-format on
36 36
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 17a2ac899..af3a5842d 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -156,6 +156,25 @@ public:
156 {97, nullptr, "RegisterBleHidEvent"}, 156 {97, nullptr, "RegisterBleHidEvent"},
157 {98, nullptr, "SetBleScanParameter"}, 157 {98, nullptr, "SetBleScanParameter"},
158 {99, nullptr, "MoveToSecondaryPiconet"}, 158 {99, nullptr, "MoveToSecondaryPiconet"},
159 {100, nullptr, "IsBluetoothEnabled"},
160 {128, nullptr, "AcquireAudioEvent"},
161 {129, nullptr, "GetAudioEventInfo"},
162 {130, nullptr, "OpenAudioConnection"},
163 {131, nullptr, "CloseAudioConnection"},
164 {132, nullptr, "OpenAudioOut"},
165 {133, nullptr, "CloseAudioOut"},
166 {134, nullptr, "AcquireAudioOutStateChangedEvent"},
167 {135, nullptr, "StartAudioOut"},
168 {136, nullptr, "StopAudioOut"},
169 {137, nullptr, "GetAudioOutState"},
170 {138, nullptr, "GetAudioOutFeedingCodec"},
171 {139, nullptr, "GetAudioOutFeedingParameter"},
172 {140, nullptr, "AcquireAudioOutBufferAvailableEvent"},
173 {141, nullptr, "SendAudioData"},
174 {142, nullptr, "AcquireAudioControlInputStateChangedEvent"},
175 {143, nullptr, "GetAudioControlInputState"},
176 {144, nullptr, "AcquireAudioConnectionStateChangedEvent"},
177 {145, nullptr, "GetConnectedAudioDevice"},
159 {256, nullptr, "IsManufacturingMode"}, 178 {256, nullptr, "IsManufacturingMode"},
160 {257, nullptr, "EmulateBluetoothCrash"}, 179 {257, nullptr, "EmulateBluetoothCrash"},
161 {258, nullptr, "GetBleChannelMap"}, 180 {258, nullptr, "GetBleChannelMap"},
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 9cf2ee92a..d1ebc2388 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -223,6 +223,7 @@ public:
223 {10, nullptr, "GetGattClientDisconnectionReason"}, 223 {10, nullptr, "GetGattClientDisconnectionReason"},
224 {11, nullptr, "GetBleConnectionParameter"}, 224 {11, nullptr, "GetBleConnectionParameter"},
225 {12, nullptr, "GetBleConnectionParameterRequest"}, 225 {12, nullptr, "GetBleConnectionParameterRequest"},
226 {13, nullptr, "Unknown13"},
226 }; 227 };
227 // clang-format on 228 // clang-format on
228 229
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
index 1fe4f0e14..6220e9f77 100644
--- a/src/core/hle/service/caps/caps_a.cpp
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -49,6 +49,7 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
49 {16, nullptr, "GetAlbumMountResult"}, 49 {16, nullptr, "GetAlbumMountResult"},
50 {17, nullptr, "GetAlbumUsage16"}, 50 {17, nullptr, "GetAlbumUsage16"},
51 {18, nullptr, "Unknown18"}, 51 {18, nullptr, "Unknown18"},
52 {19, nullptr, "Unknown19"},
52 {100, nullptr, "GetAlbumFileCountEx0"}, 53 {100, nullptr, "GetAlbumFileCountEx0"},
53 {101, nullptr, "GetAlbumFileListEx0"}, 54 {101, nullptr, "GetAlbumFileListEx0"},
54 {202, nullptr, "SaveEditedScreenShot"}, 55 {202, nullptr, "SaveEditedScreenShot"},
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index 842316a2e..10b8d54b1 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -43,6 +43,7 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
43 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, 43 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
44 {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, 44 {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
45 {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, 45 {143, nullptr, "GetAlbumFileList4AaeUidAruid"},
46 {144, nullptr, "GetAllAlbumFileList3AaeAruid"},
46 {60002, nullptr, "OpenAccessorSessionForApplication"}, 47 {60002, nullptr, "OpenAccessorSessionForApplication"},
47 }; 48 };
48 // clang-format on 49 // clang-format on
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index 4924c61c3..c767926a4 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -16,7 +16,7 @@ public:
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SubmitContext"}, 18 {0, nullptr, "SubmitContext"},
19 {1, nullptr, "CreateReport"}, 19 {1, nullptr, "CreateReportV0"},
20 {2, nullptr, "SetInitialLaunchSettingsCompletionTime"}, 20 {2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
21 {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"}, 21 {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
22 {4, nullptr, "UpdatePowerOnTime"}, 22 {4, nullptr, "UpdatePowerOnTime"},
@@ -26,6 +26,11 @@ public:
26 {8, nullptr, "ClearApplicationLaunchTime"}, 26 {8, nullptr, "ClearApplicationLaunchTime"},
27 {9, nullptr, "SubmitAttachment"}, 27 {9, nullptr, "SubmitAttachment"},
28 {10, nullptr, "CreateReportWithAttachments"}, 28 {10, nullptr, "CreateReportWithAttachments"},
29 {11, nullptr, "CreateReport"},
30 {20, nullptr, "RegisterRunningApplet"},
31 {21, nullptr, "UnregisterRunningApplet"},
32 {22, nullptr, "UpdateAppletSuspendedDuration"},
33 {30, nullptr, "InvalidateForcedShutdownDetection"},
29 }; 34 };
30 // clang-format on 35 // clang-format on
31 36
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 9cc260515..a0215c4d7 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -118,9 +118,13 @@ public:
118 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) 118 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
119 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 119 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
120 static const FunctionInfo functions[] = { 120 static const FunctionInfo functions[] = {
121 {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, 121 {0, &IFile::Read, "Read"},
122 {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, 122 {1, &IFile::Write, "Write"},
123 {4, &IFile::GetSize, "GetSize"}, {5, nullptr, "OperateRange"}, 123 {2, &IFile::Flush, "Flush"},
124 {3, &IFile::SetSize, "SetSize"},
125 {4, &IFile::GetSize, "GetSize"},
126 {5, nullptr, "OperateRange"},
127 {6, nullptr, "OperateRangeWithBuffer"},
124 }; 128 };
125 RegisterHandlers(functions); 129 RegisterHandlers(functions);
126 } 130 }
@@ -708,7 +712,10 @@ FSP_SRV::FSP_SRV(Core::System& system_)
708 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"}, 712 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
709 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"}, 713 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
710 {86, nullptr, "OpenSaveDataMover"}, 714 {86, nullptr, "OpenSaveDataMover"},
715 {87, nullptr, "OpenSaveDataTransferManagerForRepair"},
711 {100, nullptr, "OpenImageDirectoryFileSystem"}, 716 {100, nullptr, "OpenImageDirectoryFileSystem"},
717 {101, nullptr, "OpenBaseFileSystem"},
718 {102, nullptr, "FormatBaseFileSystem"},
712 {110, nullptr, "OpenContentStorageFileSystem"}, 719 {110, nullptr, "OpenContentStorageFileSystem"},
713 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, 720 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
714 {130, nullptr, "OpenCustomStorageFileSystem"}, 721 {130, nullptr, "OpenCustomStorageFileSystem"},
@@ -764,10 +771,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
764 {1008, nullptr, "OpenRegisteredUpdatePartition"}, 771 {1008, nullptr, "OpenRegisteredUpdatePartition"},
765 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 772 {1009, nullptr, "GetAndClearMemoryReportInfo"},
766 {1010, nullptr, "SetDataStorageRedirectTarget"}, 773 {1010, nullptr, "SetDataStorageRedirectTarget"},
767 {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"}, 774 {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
768 {1012, nullptr, "GetFsStackUsage"}, 775 {1012, nullptr, "GetFsStackUsage"},
769 {1013, nullptr, "UnsetSaveDataRootPath"}, 776 {1013, nullptr, "UnsetSaveDataRootPath"},
770 {1014, nullptr, "OutputMultiProgramTagAccessLog"}, 777 {1014, nullptr, "OutputMultiProgramTagAccessLog"},
778 {1016, nullptr, "FlushAccessLogOnSdCard"},
779 {1017, nullptr, "OutputApplicationInfoAccessLog"},
771 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 780 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
772 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, 781 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
773 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, 782 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
@@ -1051,7 +1060,7 @@ void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
1051 rb.Push(RESULT_SUCCESS); 1060 rb.Push(RESULT_SUCCESS);
1052} 1061}
1053 1062
1054void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) { 1063void FSP_SRV::GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx) {
1055 LOG_DEBUG(Service_FS, "called"); 1064 LOG_DEBUG(Service_FS, "called");
1056 1065
1057 IPC::ResponseBuilder rb{ctx, 4}; 1066 IPC::ResponseBuilder rb{ctx, 4};
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 8ed933279..b01b924eb 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -53,7 +53,7 @@ private:
53 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 53 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
54 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 54 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
55 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); 55 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
56 void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); 56 void GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx);
57 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); 57 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
58 58
59 FileSystemController& fsc; 59 FileSystemController& fsc;
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 72a877d68..a35979053 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -38,7 +38,7 @@ public:
38 {10600, nullptr, "DeclareOpenOnlinePlaySession"}, 38 {10600, nullptr, "DeclareOpenOnlinePlaySession"},
39 {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, 39 {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
40 {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, 40 {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
41 {10700, nullptr, "GetPlayHistoryRegistrationKey"}, 41 {10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"},
42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, 42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
43 {10702, nullptr, "AddPlayHistory"}, 43 {10702, nullptr, "AddPlayHistory"},
44 {11000, nullptr, "GetProfileImageUrl"}, 44 {11000, nullptr, "GetProfileImageUrl"},
@@ -133,7 +133,7 @@ private:
133 void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) { 133 void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) {
134 // This is safe to stub, as there should be no adverse consequences from reporting no 134 // This is safe to stub, as there should be no adverse consequences from reporting no
135 // blocked users. 135 // blocked users.
136 LOG_WARNING(Service_ACC, "(STUBBED) called"); 136 LOG_WARNING(Service_Friend, "(STUBBED) called");
137 IPC::ResponseBuilder rb{ctx, 3}; 137 IPC::ResponseBuilder rb{ctx, 3};
138 rb.Push(RESULT_SUCCESS); 138 rb.Push(RESULT_SUCCESS);
139 rb.Push<u32>(0); // Indicates there are no blocked users 139 rb.Push<u32>(0); // Indicates there are no blocked users
@@ -141,14 +141,26 @@ private:
141 141
142 void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) { 142 void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
143 // Stub used by Splatoon 2 143 // Stub used by Splatoon 2
144 LOG_WARNING(Service_ACC, "(STUBBED) called"); 144 LOG_WARNING(Service_Friend, "(STUBBED) called");
145 IPC::ResponseBuilder rb{ctx, 2}; 145 IPC::ResponseBuilder rb{ctx, 2};
146 rb.Push(RESULT_SUCCESS); 146 rb.Push(RESULT_SUCCESS);
147 } 147 }
148 148
149 void UpdateUserPresence(Kernel::HLERequestContext& ctx) { 149 void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
150 // Stub used by Retro City Rampage 150 // Stub used by Retro City Rampage
151 LOG_WARNING(Service_ACC, "(STUBBED) called"); 151 LOG_WARNING(Service_Friend, "(STUBBED) called");
152 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(RESULT_SUCCESS);
154 }
155
156 void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
157 IPC::RequestParser rp{ctx};
158 const auto local_play = rp.Pop<bool>();
159 const auto uuid = rp.PopRaw<Common::UUID>();
160
161 LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play,
162 uuid.Format());
163
152 IPC::ResponseBuilder rb{ctx, 2}; 164 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(RESULT_SUCCESS); 165 rb.Push(RESULT_SUCCESS);
154 } 166 }
@@ -159,7 +171,7 @@ private:
159 const auto uuid = rp.PopRaw<Common::UUID>(); 171 const auto uuid = rp.PopRaw<Common::UUID>();
160 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); 172 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
161 const auto pid = rp.Pop<u64>(); 173 const auto pid = rp.Pop<u64>();
162 LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset, 174 LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
163 uuid.Format(), pid); 175 uuid.Format(), pid);
164 176
165 IPC::ResponseBuilder rb{ctx, 3}; 177 IPC::ResponseBuilder rb{ctx, 3};
@@ -191,7 +203,7 @@ public:
191 203
192private: 204private:
193 void GetEvent(Kernel::HLERequestContext& ctx) { 205 void GetEvent(Kernel::HLERequestContext& ctx) {
194 LOG_DEBUG(Service_ACC, "called"); 206 LOG_DEBUG(Service_Friend, "called");
195 207
196 IPC::ResponseBuilder rb{ctx, 2, 1}; 208 IPC::ResponseBuilder rb{ctx, 2, 1};
197 rb.Push(RESULT_SUCCESS); 209 rb.Push(RESULT_SUCCESS);
@@ -199,7 +211,7 @@ private:
199 } 211 }
200 212
201 void Clear(Kernel::HLERequestContext& ctx) { 213 void Clear(Kernel::HLERequestContext& ctx) {
202 LOG_DEBUG(Service_ACC, "called"); 214 LOG_DEBUG(Service_Friend, "called");
203 while (!notifications.empty()) { 215 while (!notifications.empty()) {
204 notifications.pop(); 216 notifications.pop();
205 } 217 }
@@ -210,10 +222,10 @@ private:
210 } 222 }
211 223
212 void Pop(Kernel::HLERequestContext& ctx) { 224 void Pop(Kernel::HLERequestContext& ctx) {
213 LOG_DEBUG(Service_ACC, "called"); 225 LOG_DEBUG(Service_Friend, "called");
214 226
215 if (notifications.empty()) { 227 if (notifications.empty()) {
216 LOG_ERROR(Service_ACC, "No notifications in queue!"); 228 LOG_ERROR(Service_Friend, "No notifications in queue!");
217 IPC::ResponseBuilder rb{ctx, 2}; 229 IPC::ResponseBuilder rb{ctx, 2};
218 rb.Push(ERR_NO_NOTIFICATIONS); 230 rb.Push(ERR_NO_NOTIFICATIONS);
219 return; 231 return;
@@ -231,7 +243,8 @@ private:
231 break; 243 break;
232 default: 244 default:
233 // HOS seems not have an error case for an unknown notification 245 // HOS seems not have an error case for an unknown notification
234 LOG_WARNING(Service_ACC, "Unknown notification {:08X}", notification.notification_type); 246 LOG_WARNING(Service_Friend, "Unknown notification {:08X}",
247 notification.notification_type);
235 break; 248 break;
236 } 249 }
237 250
@@ -269,14 +282,14 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
269 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 282 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
270 rb.Push(RESULT_SUCCESS); 283 rb.Push(RESULT_SUCCESS);
271 rb.PushIpcInterface<IFriendService>(system); 284 rb.PushIpcInterface<IFriendService>(system);
272 LOG_DEBUG(Service_ACC, "called"); 285 LOG_DEBUG(Service_Friend, "called");
273} 286}
274 287
275void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) { 288void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
276 IPC::RequestParser rp{ctx}; 289 IPC::RequestParser rp{ctx};
277 auto uuid = rp.PopRaw<Common::UUID>(); 290 auto uuid = rp.PopRaw<Common::UUID>();
278 291
279 LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format()); 292 LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format());
280 293
281 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 294 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
282 rb.Push(RESULT_SUCCESS); 295 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index fc77e7286..322125135 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -41,6 +41,12 @@ ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_)
41 {1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"}, 41 {1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"},
42 {2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"}, 42 {2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"},
43 {3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"}, 43 {3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"},
44 {4, nullptr, "GetApplicationInstanceUnregistrationNotifier"},
45 {5, nullptr, "ListApplicationInstanceId"},
46 {6, nullptr, "GetMicroApplicationInstanceId"},
47 {7, nullptr, "GetApplicationCertificate"},
48 {9998, nullptr, "GetPreomiaApplicationLaunchProperty"},
49 {9999, nullptr, "GetPreomiaApplicationControlProperty"},
44 }; 50 };
45 // clang-format on 51 // clang-format on
46 52
@@ -243,7 +249,8 @@ ARP_W::ARP_W(Core::System& system_, ARPManager& manager_)
243 // clang-format off 249 // clang-format off
244 static const FunctionInfo functions[] = { 250 static const FunctionInfo functions[] = {
245 {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"}, 251 {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
246 {1, &ARP_W::DeleteProperties, "DeleteProperties"}, 252 {1, &ARP_W::UnregisterApplicationInstance , "UnregisterApplicationInstance "},
253 {2, nullptr, "AcquireUpdater"},
247 }; 254 };
248 // clang-format on 255 // clang-format on
249 256
@@ -270,7 +277,7 @@ void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
270 rb.PushIpcInterface(registrar); 277 rb.PushIpcInterface(registrar);
271} 278}
272 279
273void ARP_W::DeleteProperties(Kernel::HLERequestContext& ctx) { 280void ARP_W::UnregisterApplicationInstance(Kernel::HLERequestContext& ctx) {
274 IPC::RequestParser rp{ctx}; 281 IPC::RequestParser rp{ctx};
275 const auto process_id = rp.PopRaw<u64>(); 282 const auto process_id = rp.PopRaw<u64>();
276 283
diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h
index 34b412e26..0df3c5e1f 100644
--- a/src/core/hle/service/glue/arp.h
+++ b/src/core/hle/service/glue/arp.h
@@ -32,7 +32,7 @@ public:
32 32
33private: 33private:
34 void AcquireRegistrar(Kernel::HLERequestContext& ctx); 34 void AcquireRegistrar(Kernel::HLERequestContext& ctx);
35 void DeleteProperties(Kernel::HLERequestContext& ctx); 35 void UnregisterApplicationInstance(Kernel::HLERequestContext& ctx);
36 36
37 ARPManager& manager; 37 ARPManager& manager;
38 std::shared_ptr<IRegistrar> registrar; 38 std::shared_ptr<IRegistrar> registrar;
diff --git a/src/core/hle/service/glue/bgtc.cpp b/src/core/hle/service/glue/bgtc.cpp
index a478b68e1..daecfff15 100644
--- a/src/core/hle/service/glue/bgtc.cpp
+++ b/src/core/hle/service/glue/bgtc.cpp
@@ -2,6 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/hle/ipc_helpers.h"
5#include "core/hle/service/glue/bgtc.h" 8#include "core/hle/service/glue/bgtc.h"
6 9
7namespace Service::Glue { 10namespace Service::Glue {
@@ -9,6 +12,26 @@ namespace Service::Glue {
9BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} { 12BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
10 // clang-format off 13 // clang-format off
11 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
15 {100, &BGTC_T::OpenTaskService, "OpenTaskService"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22BGTC_T::~BGTC_T() = default;
23
24void BGTC_T::OpenTaskService(Kernel::HLERequestContext& ctx) {
25 LOG_DEBUG(Service_BGTC, "called");
26
27 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
28 rb.Push(RESULT_SUCCESS);
29 rb.PushIpcInterface<ITaskService>(system);
30}
31
32ITaskService::ITaskService(Core::System& system_) : ServiceFramework{system_, "ITaskService"} {
33 // clang-format off
34 static const FunctionInfo functions[] = {
12 {1, nullptr, "NotifyTaskStarting"}, 35 {1, nullptr, "NotifyTaskStarting"},
13 {2, nullptr, "NotifyTaskFinished"}, 36 {2, nullptr, "NotifyTaskFinished"},
14 {3, nullptr, "GetTriggerEvent"}, 37 {3, nullptr, "GetTriggerEvent"},
@@ -20,16 +43,18 @@ BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
20 {13, nullptr, "UnscheduleTask"}, 43 {13, nullptr, "UnscheduleTask"},
21 {14, nullptr, "GetScheduleEvent"}, 44 {14, nullptr, "GetScheduleEvent"},
22 {15, nullptr, "SchedulePeriodicTask"}, 45 {15, nullptr, "SchedulePeriodicTask"},
46 {16, nullptr, "Unknown16"},
23 {101, nullptr, "GetOperationMode"}, 47 {101, nullptr, "GetOperationMode"},
24 {102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"}, 48 {102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"},
25 {103, nullptr, "WillStayHalfAwakeInsteadSleep"}, 49 {103, nullptr, "WillStayHalfAwakeInsteadSleep"},
50 {200, nullptr, "Unknown200"},
26 }; 51 };
27 // clang-format on 52 // clang-format on
28 53
29 RegisterHandlers(functions); 54 RegisterHandlers(functions);
30} 55}
31 56
32BGTC_T::~BGTC_T() = default; 57ITaskService::~ITaskService() = default;
33 58
34BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} { 59BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} {
35 // clang-format off 60 // clang-format off
diff --git a/src/core/hle/service/glue/bgtc.h b/src/core/hle/service/glue/bgtc.h
index 906116ba6..4c0142fd5 100644
--- a/src/core/hle/service/glue/bgtc.h
+++ b/src/core/hle/service/glue/bgtc.h
@@ -16,6 +16,14 @@ class BGTC_T final : public ServiceFramework<BGTC_T> {
16public: 16public:
17 explicit BGTC_T(Core::System& system_); 17 explicit BGTC_T(Core::System& system_);
18 ~BGTC_T() override; 18 ~BGTC_T() override;
19
20 void OpenTaskService(Kernel::HLERequestContext& ctx);
21};
22
23class ITaskService final : public ServiceFramework<ITaskService> {
24public:
25 explicit ITaskService(Core::System& system_);
26 ~ITaskService() override;
19}; 27};
20 28
21class BGTC_SC final : public ServiceFramework<BGTC_SC> { 29class BGTC_SC final : public ServiceFramework<BGTC_SC> {
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index e7063f8ef..93c43a203 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -4,6 +4,7 @@
4 4
5#include <cstring> 5#include <cstring>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "common/logging/log.h"
7#include "core/core_timing.h" 8#include "core/core_timing.h"
8#include "core/frontend/emu_window.h" 9#include "core/frontend/emu_window.h"
9#include "core/hle/service/hid/controllers/gesture.h" 10#include "core/hle/service/hid/controllers/gesture.h"
@@ -19,9 +20,9 @@ Controller_Gesture::~Controller_Gesture() = default;
19 20
20void Controller_Gesture::OnInit() { 21void Controller_Gesture::OnInit() {
21 for (std::size_t id = 0; id < MAX_FINGERS; ++id) { 22 for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
22 mouse_finger_id[id] = MAX_FINGERS; 23 mouse_finger_id[id] = MAX_POINTS;
23 keyboard_finger_id[id] = MAX_FINGERS; 24 keyboard_finger_id[id] = MAX_POINTS;
24 udp_finger_id[id] = MAX_FINGERS; 25 udp_finger_id[id] = MAX_POINTS;
25 } 26 }
26} 27}
27 28
@@ -142,6 +143,10 @@ std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const {
142std::size_t Controller_Gesture::UpdateTouchInputEvent( 143std::size_t Controller_Gesture::UpdateTouchInputEvent(
143 const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { 144 const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
144 const auto& [x, y, pressed] = touch_input; 145 const auto& [x, y, pressed] = touch_input;
146 if (finger_id > MAX_POINTS) {
147 LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
148 return MAX_POINTS;
149 }
145 if (pressed) { 150 if (pressed) {
146 if (finger_id == MAX_POINTS) { 151 if (finger_id == MAX_POINTS) {
147 const auto first_free_id = GetUnusedFingerID(); 152 const auto first_free_id = GetUnusedFingerID();
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 70b9f3824..673db68c7 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -413,12 +413,16 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
413 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); 413 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
414 } 414 }
415 415
416 if (controller_type == NPadControllerType::JoyLeft || 416 if (controller_type == NPadControllerType::JoyLeft) {
417 controller_type == NPadControllerType::JoyRight) {
418 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); 417 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
419 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); 418 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
420 } 419 }
421 420
421 if (controller_type == NPadControllerType::JoyRight) {
422 pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
423 pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
424 }
425
422 if (controller_type == NPadControllerType::GameCube) { 426 if (controller_type == NPadControllerType::GameCube) {
423 trigger_entry.l_analog = static_cast<s32>( 427 trigger_entry.l_analog = static_cast<s32>(
424 button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); 428 button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
@@ -1134,6 +1138,10 @@ void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_prot
1134 unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; 1138 unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
1135} 1139}
1136 1140
1141void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
1142 analog_stick_use_center_clamp = use_center_clamp;
1143}
1144
1137void Controller_NPad::ClearAllConnectedControllers() { 1145void Controller_NPad::ClearAllConnectedControllers() {
1138 for (auto& controller : connected_controllers) { 1146 for (auto& controller : connected_controllers) {
1139 if (controller.is_connected && controller.type != NPadControllerType::None) { 1147 if (controller.is_connected && controller.type != NPadControllerType::None) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index bc2e6779d..873a0a1e2 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -219,6 +219,7 @@ public:
219 LedPattern GetLedPattern(u32 npad_id); 219 LedPattern GetLedPattern(u32 npad_id);
220 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; 220 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
221 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); 221 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
222 void SetAnalogStickUseCenterClamp(bool use_center_clamp);
222 void ClearAllConnectedControllers(); 223 void ClearAllConnectedControllers();
223 void DisconnectAllConnectedControllers(); 224 void DisconnectAllConnectedControllers();
224 void ConnectAllDisconnectedControllers(); 225 void ConnectAllDisconnectedControllers();
@@ -577,6 +578,7 @@ private:
577 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{}; 578 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
578 std::array<ControllerHolder, 10> connected_controllers{}; 579 std::array<ControllerHolder, 10> connected_controllers{};
579 std::array<bool, 10> unintended_home_button_input_protection{}; 580 std::array<bool, 10> unintended_home_button_input_protection{};
581 bool analog_stick_use_center_clamp{};
580 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; 582 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
581 bool sixaxis_sensors_enabled{true}; 583 bool sixaxis_sensors_enabled{true};
582 f32 sixaxis_fusion_parameter1{}; 584 f32 sixaxis_fusion_parameter1{};
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 5219f2dad..be60492a4 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -5,6 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h"
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/frontend/emu_window.h" 10#include "core/frontend/emu_window.h"
10#include "core/frontend/input.h" 11#include "core/frontend/input.h"
@@ -118,6 +119,10 @@ std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const {
118std::size_t Controller_Touchscreen::UpdateTouchInputEvent( 119std::size_t Controller_Touchscreen::UpdateTouchInputEvent(
119 const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { 120 const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
120 const auto& [x, y, pressed] = touch_input; 121 const auto& [x, y, pressed] = touch_input;
122 if (finger_id > MAX_FINGERS) {
123 LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
124 return MAX_FINGERS;
125 }
121 if (pressed) { 126 if (pressed) {
122 Attributes attribute{}; 127 Attributes attribute{};
123 if (finger_id == MAX_FINGERS) { 128 if (finger_id == MAX_FINGERS) {
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index ba27bbb05..a1a779cc0 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -263,7 +263,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
263 {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"}, 263 {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
264 {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, 264 {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
265 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, 265 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
266 {134, nullptr, "SetNpadAnalogStickUseCenterClamp"}, 266 {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
267 {135, nullptr, "SetNpadCaptureButtonAssignment"}, 267 {135, nullptr, "SetNpadCaptureButtonAssignment"},
268 {136, nullptr, "ClearNpadCaptureButtonAssignment"}, 268 {136, nullptr, "ClearNpadCaptureButtonAssignment"},
269 {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, 269 {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
@@ -278,6 +278,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
278 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, 278 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
279 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, 279 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
280 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, 280 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
281 {212, nullptr, "SendVibrationValueInBool"},
281 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, 282 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
282 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, 283 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
283 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, 284 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -1087,6 +1088,27 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
1087 rb.Push(RESULT_SUCCESS); 1088 rb.Push(RESULT_SUCCESS);
1088} 1089}
1089 1090
1091void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
1092 IPC::RequestParser rp{ctx};
1093 struct Parameters {
1094 bool analog_stick_use_center_clamp;
1095 u64 applet_resource_user_id;
1096 };
1097 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1098
1099 const auto parameters{rp.PopRaw<Parameters>()};
1100
1101 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1102 .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
1103
1104 LOG_WARNING(Service_HID,
1105 "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
1106 parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
1107
1108 IPC::ResponseBuilder rb{ctx, 2};
1109 rb.Push(RESULT_SUCCESS);
1110}
1111
1090void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 1112void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
1091 IPC::RequestParser rp{ctx}; 1113 IPC::RequestParser rp{ctx};
1092 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; 1114 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
@@ -1553,6 +1575,7 @@ public:
1553 {11, nullptr, "SetTouchScreenAutoPilotState"}, 1575 {11, nullptr, "SetTouchScreenAutoPilotState"},
1554 {12, nullptr, "UnsetTouchScreenAutoPilotState"}, 1576 {12, nullptr, "UnsetTouchScreenAutoPilotState"},
1555 {13, nullptr, "GetTouchScreenConfiguration"}, 1577 {13, nullptr, "GetTouchScreenConfiguration"},
1578 {14, nullptr, "ProcessTouchScreenAutoTune"},
1556 {20, nullptr, "DeactivateMouse"}, 1579 {20, nullptr, "DeactivateMouse"},
1557 {21, nullptr, "SetMouseAutoPilotState"}, 1580 {21, nullptr, "SetMouseAutoPilotState"},
1558 {22, nullptr, "UnsetMouseAutoPilotState"}, 1581 {22, nullptr, "UnsetMouseAutoPilotState"},
@@ -1562,6 +1585,7 @@ public:
1562 {50, nullptr, "DeactivateXpad"}, 1585 {50, nullptr, "DeactivateXpad"},
1563 {51, nullptr, "SetXpadAutoPilotState"}, 1586 {51, nullptr, "SetXpadAutoPilotState"},
1564 {52, nullptr, "UnsetXpadAutoPilotState"}, 1587 {52, nullptr, "UnsetXpadAutoPilotState"},
1588 {53, nullptr, "DeactivateJoyXpad"},
1565 {60, nullptr, "ClearNpadSystemCommonPolicy"}, 1589 {60, nullptr, "ClearNpadSystemCommonPolicy"},
1566 {61, nullptr, "DeactivateNpad"}, 1590 {61, nullptr, "DeactivateNpad"},
1567 {62, nullptr, "ForceDisconnectNpad"}, 1591 {62, nullptr, "ForceDisconnectNpad"},
@@ -1632,6 +1656,11 @@ public:
1632 {244, nullptr, "RequestKuinaFirmwareVersion"}, 1656 {244, nullptr, "RequestKuinaFirmwareVersion"},
1633 {245, nullptr, "GetKuinaFirmwareVersion"}, 1657 {245, nullptr, "GetKuinaFirmwareVersion"},
1634 {246, nullptr, "GetVidPid"}, 1658 {246, nullptr, "GetVidPid"},
1659 {247, nullptr, "GetAnalogStickCalibrationValue"},
1660 {248, nullptr, "GetUniquePadIdsFull"},
1661 {249, nullptr, "ConnectUniquePad"},
1662 {250, nullptr, "IsVirtual"},
1663 {251, nullptr, "GetAnalogStickModuleParam"},
1635 {301, nullptr, "GetAbstractedPadHandles"}, 1664 {301, nullptr, "GetAbstractedPadHandles"},
1636 {302, nullptr, "GetAbstractedPadState"}, 1665 {302, nullptr, "GetAbstractedPadState"},
1637 {303, nullptr, "GetAbstractedPadsState"}, 1666 {303, nullptr, "GetAbstractedPadsState"},
@@ -1652,12 +1681,16 @@ public:
1652 {401, nullptr, "DisableRailDeviceFiltering"}, 1681 {401, nullptr, "DisableRailDeviceFiltering"},
1653 {402, nullptr, "EnableWiredPairing"}, 1682 {402, nullptr, "EnableWiredPairing"},
1654 {403, nullptr, "EnableShipmentModeAutoClear"}, 1683 {403, nullptr, "EnableShipmentModeAutoClear"},
1684 {404, nullptr, "SetRailEnabled"},
1655 {500, nullptr, "SetFactoryInt"}, 1685 {500, nullptr, "SetFactoryInt"},
1656 {501, nullptr, "IsFactoryBootEnabled"}, 1686 {501, nullptr, "IsFactoryBootEnabled"},
1657 {550, nullptr, "SetAnalogStickModelDataTemporarily"}, 1687 {550, nullptr, "SetAnalogStickModelDataTemporarily"},
1658 {551, nullptr, "GetAnalogStickModelData"}, 1688 {551, nullptr, "GetAnalogStickModelData"},
1659 {552, nullptr, "ResetAnalogStickModelData"}, 1689 {552, nullptr, "ResetAnalogStickModelData"},
1660 {600, nullptr, "ConvertPadState"}, 1690 {600, nullptr, "ConvertPadState"},
1691 {650, nullptr, "AddButtonPlayData"},
1692 {651, nullptr, "StartButtonPlayData"},
1693 {652, nullptr, "StopButtonPlayData"},
1661 {2000, nullptr, "DeactivateDigitizer"}, 1694 {2000, nullptr, "DeactivateDigitizer"},
1662 {2001, nullptr, "SetDigitizerAutoPilotState"}, 1695 {2001, nullptr, "SetDigitizerAutoPilotState"},
1663 {2002, nullptr, "UnsetDigitizerAutoPilotState"}, 1696 {2002, nullptr, "UnsetDigitizerAutoPilotState"},
@@ -1689,6 +1722,8 @@ public:
1689 {215, nullptr, "IsNfcActivated"}, 1722 {215, nullptr, "IsNfcActivated"},
1690 {230, nullptr, "AcquireIrSensorEventHandle"}, 1723 {230, nullptr, "AcquireIrSensorEventHandle"},
1691 {231, nullptr, "ActivateIrSensor"}, 1724 {231, nullptr, "ActivateIrSensor"},
1725 {232, nullptr, "GetIrSensorState"},
1726 {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
1692 {301, nullptr, "ActivateNpadSystem"}, 1727 {301, nullptr, "ActivateNpadSystem"},
1693 {303, nullptr, "ApplyNpadSystemCommonPolicy"}, 1728 {303, nullptr, "ApplyNpadSystemCommonPolicy"},
1694 {304, nullptr, "EnableAssigningSingleOnSlSrPress"}, 1729 {304, nullptr, "EnableAssigningSingleOnSlSrPress"},
@@ -1703,9 +1738,16 @@ public:
1703 {313, nullptr, "GetNpadCaptureButtonAssignment"}, 1738 {313, nullptr, "GetNpadCaptureButtonAssignment"},
1704 {314, nullptr, "GetAppletFooterUiType"}, 1739 {314, nullptr, "GetAppletFooterUiType"},
1705 {315, nullptr, "GetAppletDetailedUiType"}, 1740 {315, nullptr, "GetAppletDetailedUiType"},
1741 {316, nullptr, "GetNpadInterfaceType"},
1742 {317, nullptr, "GetNpadLeftRightInterfaceType"},
1743 {318, nullptr, "HasBattery"},
1744 {319, nullptr, "HasLeftRightBattery"},
1706 {321, nullptr, "GetUniquePadsFromNpad"}, 1745 {321, nullptr, "GetUniquePadsFromNpad"},
1707 {322, nullptr, "GetIrSensorState"}, 1746 {322, nullptr, "GetIrSensorState"},
1708 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, 1747 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
1748 {324, nullptr, "GetUniquePadButtonSet"},
1749 {325, nullptr, "GetUniquePadColor"},
1750 {326, nullptr, "GetUniquePadAppletDetailedUiType"},
1709 {500, nullptr, "SetAppletResourceUserId"}, 1751 {500, nullptr, "SetAppletResourceUserId"},
1710 {501, nullptr, "RegisterAppletResourceUserId"}, 1752 {501, nullptr, "RegisterAppletResourceUserId"},
1711 {502, nullptr, "UnregisterAppletResourceUserId"}, 1753 {502, nullptr, "UnregisterAppletResourceUserId"},
@@ -1716,10 +1758,13 @@ public:
1716 {511, nullptr, "GetVibrationMasterVolume"}, 1758 {511, nullptr, "GetVibrationMasterVolume"},
1717 {512, nullptr, "BeginPermitVibrationSession"}, 1759 {512, nullptr, "BeginPermitVibrationSession"},
1718 {513, nullptr, "EndPermitVibrationSession"}, 1760 {513, nullptr, "EndPermitVibrationSession"},
1761 {514, nullptr, "Unknown514"},
1719 {520, nullptr, "EnableHandheldHids"}, 1762 {520, nullptr, "EnableHandheldHids"},
1720 {521, nullptr, "DisableHandheldHids"}, 1763 {521, nullptr, "DisableHandheldHids"},
1721 {522, nullptr, "SetJoyConRailEnabled"}, 1764 {522, nullptr, "SetJoyConRailEnabled"},
1722 {523, nullptr, "IsJoyConRailEnabled"}, 1765 {523, nullptr, "IsJoyConRailEnabled"},
1766 {524, nullptr, "IsHandheldHidsEnabled"},
1767 {525, nullptr, "IsJoyConAttachedOnAllRail"},
1723 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, 1768 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
1724 {541, nullptr, "GetPlayReportControllerUsages"}, 1769 {541, nullptr, "GetPlayReportControllerUsages"},
1725 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, 1770 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
@@ -1795,6 +1840,65 @@ public:
1795 {1154, nullptr, "IsFirmwareAvailableForNotification"}, 1840 {1154, nullptr, "IsFirmwareAvailableForNotification"},
1796 {1155, nullptr, "SetForceHandheldStyleVibration"}, 1841 {1155, nullptr, "SetForceHandheldStyleVibration"},
1797 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, 1842 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
1843 {1157, nullptr, "CancelConnectionTrigger"},
1844 {1200, nullptr, "IsButtonConfigSupported"},
1845 {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
1846 {1202, nullptr, "DeleteButtonConfig"},
1847 {1203, nullptr, "DeleteButtonConfigEmbedded"},
1848 {1204, nullptr, "SetButtonConfigEnabled"},
1849 {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
1850 {1206, nullptr, "IsButtonConfigEnabled"},
1851 {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
1852 {1208, nullptr, "SetButtonConfigEmbedded"},
1853 {1209, nullptr, "SetButtonConfigFull"},
1854 {1210, nullptr, "SetButtonConfigLeft"},
1855 {1211, nullptr, "SetButtonConfigRight"},
1856 {1212, nullptr, "GetButtonConfigEmbedded"},
1857 {1213, nullptr, "GetButtonConfigFull"},
1858 {1214, nullptr, "GetButtonConfigLeft"},
1859 {1215, nullptr, "GetButtonConfigRight"},
1860 {1250, nullptr, "IsCustomButtonConfigSupported"},
1861 {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
1862 {1252, nullptr, "IsDefaultButtonConfigFull"},
1863 {1253, nullptr, "IsDefaultButtonConfigLeft"},
1864 {1254, nullptr, "IsDefaultButtonConfigRight"},
1865 {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
1866 {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
1867 {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
1868 {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
1869 {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
1870 {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
1871 {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
1872 {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
1873 {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
1874 {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
1875 {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
1876 {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
1877 {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
1878 {1268, nullptr, "DeleteButtonConfigStorageFull"},
1879 {1269, nullptr, "DeleteButtonConfigStorageLeft"},
1880 {1270, nullptr, "DeleteButtonConfigStorageRight"},
1881 {1271, nullptr, "IsUsingCustomButtonConfig"},
1882 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
1883 {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
1884 {1274, nullptr, "SetDefaultButtonConfig"},
1885 {1275, nullptr, "SetAllDefaultButtonConfig"},
1886 {1276, nullptr, "SetHidButtonConfigEmbedded"},
1887 {1277, nullptr, "SetHidButtonConfigFull"},
1888 {1278, nullptr, "SetHidButtonConfigLeft"},
1889 {1279, nullptr, "SetHidButtonConfigRight"},
1890 {1280, nullptr, "GetHidButtonConfigEmbedded"},
1891 {1281, nullptr, "GetHidButtonConfigFull"},
1892 {1282, nullptr, "GetHidButtonConfigLeft"},
1893 {1283, nullptr, "GetHidButtonConfigRight"},
1894 {1284, nullptr, "GetButtonConfigStorageEmbedded"},
1895 {1285, nullptr, "GetButtonConfigStorageFull"},
1896 {1286, nullptr, "GetButtonConfigStorageLeft"},
1897 {1287, nullptr, "GetButtonConfigStorageRight"},
1898 {1288, nullptr, "SetButtonConfigStorageEmbedded"},
1899 {1289, nullptr, "SetButtonConfigStorageFull"},
1900 {1290, nullptr, "DeleteButtonConfigStorageRight"},
1901 {1291, nullptr, "DeleteButtonConfigStorageRight"},
1798 }; 1902 };
1799 // clang-format on 1903 // clang-format on
1800 1904
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 36ed228c8..c2bdd39a3 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -129,6 +129,7 @@ private:
129 void SwapNpadAssignment(Kernel::HLERequestContext& ctx); 129 void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
130 void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); 130 void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
131 void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); 131 void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
132 void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx);
132 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); 133 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
133 void SendVibrationValue(Kernel::HLERequestContext& ctx); 134 void SendVibrationValue(Kernel::HLERequestContext& ctx);
134 void GetActualVibrationValue(Kernel::HLERequestContext& ctx); 135 void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp
index 43a8840d0..b1efa3d05 100644
--- a/src/core/hle/service/hid/xcd.cpp
+++ b/src/core/hle/service/hid/xcd.cpp
@@ -28,6 +28,8 @@ XCD_SYS::XCD_SYS(Core::System& system_) : ServiceFramework{system_, "xcd:sys"} {
28 {20, nullptr, "StartMifareWrite"}, 28 {20, nullptr, "StartMifareWrite"},
29 {101, nullptr, "GetAwakeTriggerReasonForLeftRail"}, 29 {101, nullptr, "GetAwakeTriggerReasonForLeftRail"},
30 {102, nullptr, "GetAwakeTriggerReasonForRightRail"}, 30 {102, nullptr, "GetAwakeTriggerReasonForRightRail"},
31 {103, nullptr, "GetAwakeTriggerBatteryLevelTransitionForLeftRail"},
32 {104, nullptr, "GetAwakeTriggerBatteryLevelTransitionForRightRail"},
31 }; 33 };
32 // clang-format on 34 // clang-format on
33 35
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index d111c1357..c8bc60ad1 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -118,9 +118,9 @@ public:
118 explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} { 118 explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} {
119 // clang-format off 119 // clang-format off
120 static const FunctionInfo functions[] = { 120 static const FunctionInfo functions[] = {
121 {0, nullptr, "AddProcessToDebugLaunchQueue"}, 121 {0, nullptr, "SetProgramArgument"},
122 {1, nullptr, "ClearDebugLaunchQueue"}, 122 {1, nullptr, "FlushArguments"},
123 {2, nullptr, "GetNsoInfos"}, 123 {2, nullptr, "GetProcessModuleInfo"},
124 }; 124 };
125 // clang-format on 125 // clang-format on
126 126
@@ -135,8 +135,8 @@ public:
135 static const FunctionInfo functions[] = { 135 static const FunctionInfo functions[] = {
136 {0, nullptr, "CreateProcess"}, 136 {0, nullptr, "CreateProcess"},
137 {1, nullptr, "GetProgramInfo"}, 137 {1, nullptr, "GetProgramInfo"},
138 {2, nullptr, "RegisterTitle"}, 138 {2, nullptr, "PinProgram"},
139 {3, nullptr, "UnregisterTitle"}, 139 {3, nullptr, "UnpinProgram"},
140 {4, nullptr, "SetEnabledProgramVerification"}, 140 {4, nullptr, "SetEnabledProgramVerification"},
141 }; 141 };
142 // clang-format on 142 // clang-format on
@@ -150,8 +150,8 @@ public:
150 explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} { 150 explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} {
151 // clang-format off 151 // clang-format off
152 static const FunctionInfo functions[] = { 152 static const FunctionInfo functions[] = {
153 {0, nullptr, "AddProcessToLaunchQueue"}, 153 {0, nullptr, "SetProgramArgument"},
154 {1, nullptr, "ClearLaunchQueue"}, 154 {1, nullptr, "FlushArguments"},
155 }; 155 };
156 // clang-format on 156 // clang-format on
157 157
@@ -164,19 +164,19 @@ public:
164 explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} { 164 explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
165 // clang-format off 165 // clang-format off
166 static const FunctionInfo functions[] = { 166 static const FunctionInfo functions[] = {
167 {0, &RelocatableObject::LoadNro, "LoadNro"}, 167 {0, &RelocatableObject::LoadModule, "LoadModule"},
168 {1, &RelocatableObject::UnloadNro, "UnloadNro"}, 168 {1, &RelocatableObject::UnloadModule, "UnloadModule"},
169 {2, &RelocatableObject::LoadNrr, "LoadNrr"}, 169 {2, &RelocatableObject::RegisterModuleInfo, "RegisterModuleInfo"},
170 {3, &RelocatableObject::UnloadNrr, "UnloadNrr"}, 170 {3, &RelocatableObject::UnregisterModuleInfo, "UnregisterModuleInfo"},
171 {4, &RelocatableObject::Initialize, "Initialize"}, 171 {4, &RelocatableObject::Initialize, "Initialize"},
172 {10, nullptr, "LoadNrrEx"}, 172 {10, nullptr, "RegisterModuleInfo2"},
173 }; 173 };
174 // clang-format on 174 // clang-format on
175 175
176 RegisterHandlers(functions); 176 RegisterHandlers(functions);
177 } 177 }
178 178
179 void LoadNrr(Kernel::HLERequestContext& ctx) { 179 void RegisterModuleInfo(Kernel::HLERequestContext& ctx) {
180 struct Parameters { 180 struct Parameters {
181 u64_le process_id; 181 u64_le process_id;
182 u64_le nrr_address; 182 u64_le nrr_address;
@@ -273,7 +273,7 @@ public:
273 rb.Push(RESULT_SUCCESS); 273 rb.Push(RESULT_SUCCESS);
274 } 274 }
275 275
276 void UnloadNrr(Kernel::HLERequestContext& ctx) { 276 void UnregisterModuleInfo(Kernel::HLERequestContext& ctx) {
277 IPC::RequestParser rp{ctx}; 277 IPC::RequestParser rp{ctx};
278 const auto pid = rp.Pop<u64>(); 278 const auto pid = rp.Pop<u64>();
279 const auto nrr_address = rp.Pop<VAddr>(); 279 const auto nrr_address = rp.Pop<VAddr>();
@@ -408,7 +408,7 @@ public:
408 data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); 408 data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite);
409 } 409 }
410 410
411 void LoadNro(Kernel::HLERequestContext& ctx) { 411 void LoadModule(Kernel::HLERequestContext& ctx) {
412 struct Parameters { 412 struct Parameters {
413 u64_le process_id; 413 u64_le process_id;
414 u64_le image_address; 414 u64_le image_address;
@@ -546,7 +546,7 @@ public:
546 return RESULT_SUCCESS; 546 return RESULT_SUCCESS;
547 } 547 }
548 548
549 void UnloadNro(Kernel::HLERequestContext& ctx) { 549 void UnloadModule(Kernel::HLERequestContext& ctx) {
550 if (!initialized) { 550 if (!initialized) {
551 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); 551 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
552 IPC::ResponseBuilder rb{ctx, 2}; 552 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index f3be0b878..fee360ab9 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -125,51 +125,51 @@ public:
125 {39, nullptr, "PrepareShutdown"}, 125 {39, nullptr, "PrepareShutdown"},
126 {40, nullptr, "ListApplyDeltaTask"}, 126 {40, nullptr, "ListApplyDeltaTask"},
127 {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"}, 127 {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
128 {42, nullptr, "Unknown42"}, 128 {42, nullptr, "CreateApplyDeltaTaskFromDownloadTask"},
129 {43, nullptr, "Unknown43"}, 129 {43, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
130 {44, nullptr, "Unknown44"}, 130 {44, nullptr, "GetApplyDeltaTaskRequiredStorage"},
131 {45, nullptr, "Unknown45"}, 131 {45, nullptr, "CalculateNetworkInstallTaskContentsSize"},
132 {46, nullptr, "Unknown46"}, 132 {46, nullptr, "PrepareShutdownForSystemUpdate"},
133 {47, nullptr, "Unknown47"}, 133 {47, nullptr, "FindMaxRequiredApplicationVersionOfTask"},
134 {48, nullptr, "Unknown48"}, 134 {48, nullptr, "CommitNetworkInstallTaskPartially"},
135 {49, nullptr, "Unknown49"}, 135 {49, nullptr, "ListNetworkInstallTaskCommittedContentMeta"},
136 {50, nullptr, "Unknown50"}, 136 {50, nullptr, "ListNetworkInstallTaskNotCommittedContentMeta"},
137 {51, nullptr, "Unknown51"}, 137 {51, nullptr, "FindMaxRequiredSystemVersionOfTask"},
138 {52, nullptr, "Unknown52"}, 138 {52, nullptr, "GetNetworkInstallTaskErrorContext"},
139 {53, nullptr, "Unknown53"}, 139 {53, nullptr, "CreateLocalCommunicationReceiveApplicationTask"},
140 {54, nullptr, "Unknown54"}, 140 {54, nullptr, "DestroyLocalCommunicationReceiveApplicationTask"},
141 {55, nullptr, "Unknown55"}, 141 {55, nullptr, "ListLocalCommunicationReceiveApplicationTask"},
142 {56, nullptr, "Unknown56"}, 142 {56, nullptr, "RequestLocalCommunicationReceiveApplicationTaskRun"},
143 {57, nullptr, "Unknown57"}, 143 {57, nullptr, "GetLocalCommunicationReceiveApplicationTaskInfo"},
144 {58, nullptr, "Unknown58"}, 144 {58, nullptr, "CommitLocalCommunicationReceiveApplicationTask"},
145 {59, nullptr, "Unknown59"}, 145 {59, nullptr, "ListLocalCommunicationReceiveApplicationTaskContentMeta"},
146 {60, nullptr, "Unknown60"}, 146 {60, nullptr, "CreateLocalCommunicationSendApplicationTask"},
147 {61, nullptr, "Unknown61"}, 147 {61, nullptr, "RequestLocalCommunicationSendApplicationTaskRun"},
148 {62, nullptr, "Unknown62"}, 148 {62, nullptr, "GetLocalCommunicationReceiveApplicationTaskErrorContext"},
149 {63, nullptr, "Unknown63"}, 149 {63, nullptr, "GetLocalCommunicationSendApplicationTaskInfo"},
150 {64, nullptr, "Unknown64"}, 150 {64, nullptr, "DestroyLocalCommunicationSendApplicationTask"},
151 {65, nullptr, "Unknown65"}, 151 {65, nullptr, "GetLocalCommunicationSendApplicationTaskErrorContext"},
152 {66, nullptr, "Unknown66"}, 152 {66, nullptr, "CalculateLocalCommunicationReceiveApplicationTaskRequiredSize"},
153 {67, nullptr, "Unknown67"}, 153 {67, nullptr, "ListApplicationLocalCommunicationReceiveApplicationTask"},
154 {68, nullptr, "Unknown68"}, 154 {68, nullptr, "ListApplicationLocalCommunicationSendApplicationTask"},
155 {69, nullptr, "Unknown69"}, 155 {69, nullptr, "CreateLocalCommunicationReceiveSystemUpdateTask"},
156 {70, nullptr, "Unknown70"}, 156 {70, nullptr, "DestroyLocalCommunicationReceiveSystemUpdateTask"},
157 {71, nullptr, "Unknown71"}, 157 {71, nullptr, "ListLocalCommunicationReceiveSystemUpdateTask"},
158 {72, nullptr, "Unknown72"}, 158 {72, nullptr, "RequestLocalCommunicationReceiveSystemUpdateTaskRun"},
159 {73, nullptr, "Unknown73"}, 159 {73, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskInfo"},
160 {74, nullptr, "Unknown74"}, 160 {74, nullptr, "CommitLocalCommunicationReceiveSystemUpdateTask"},
161 {75, nullptr, "Unknown75"}, 161 {75, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskErrorContext"},
162 {76, nullptr, "Unknown76"}, 162 {76, nullptr, "CreateLocalCommunicationSendSystemUpdateTask"},
163 {77, nullptr, "Unknown77"}, 163 {77, nullptr, "RequestLocalCommunicationSendSystemUpdateTaskRun"},
164 {78, nullptr, "Unknown78"}, 164 {78, nullptr, "GetLocalCommunicationSendSystemUpdateTaskInfo"},
165 {79, nullptr, "Unknown79"}, 165 {79, nullptr, "DestroyLocalCommunicationSendSystemUpdateTask"},
166 {80, nullptr, "Unknown80"}, 166 {80, nullptr, "GetLocalCommunicationSendSystemUpdateTaskErrorContext"},
167 {81, nullptr, "Unknown81"}, 167 {81, nullptr, "ListLocalCommunicationSendSystemUpdateTask"},
168 {82, nullptr, "Unknown82"}, 168 {82, nullptr, "GetReceivedSystemDataPath"},
169 {83, nullptr, "Unknown83"}, 169 {83, nullptr, "CalculateApplyDeltaTaskOccupiedSize"},
170 {84, nullptr, "Unknown84"}, 170 {84, nullptr, "Unknown84"},
171 {85, nullptr, "Unknown85"}, 171 {85, nullptr, "ListNetworkInstallTaskContentMetaFromInstallMeta"},
172 {86, nullptr, "Unknown86"}, 172 {86, nullptr, "ListNetworkInstallTaskOccupiedSize"},
173 {87, nullptr, "Unknown87"}, 173 {87, nullptr, "Unknown87"},
174 {88, nullptr, "Unknown88"}, 174 {88, nullptr, "Unknown88"},
175 {89, nullptr, "Unknown89"}, 175 {89, nullptr, "Unknown89"},
@@ -202,6 +202,17 @@ public:
202 {116, nullptr, "Unknown116"}, 202 {116, nullptr, "Unknown116"},
203 {117, nullptr, "Unknown117"}, 203 {117, nullptr, "Unknown117"},
204 {118, nullptr, "Unknown118"}, 204 {118, nullptr, "Unknown118"},
205 {119, nullptr, "Unknown119"},
206 {120, nullptr, "Unknown120"},
207 {121, nullptr, "Unknown121"},
208 {122, nullptr, "Unknown122"},
209 {123, nullptr, "Unknown123"},
210 {124, nullptr, "Unknown124"},
211 {125, nullptr, "Unknown125"},
212 {126, nullptr, "Unknown126"},
213 {127, nullptr, "Unknown127"},
214 {128, nullptr, "Unknown128"},
215 {129, nullptr, "Unknown129"},
205 }; 216 };
206 // clang-format on 217 // clang-format on
207 218
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index f7a58f659..e4c703da4 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -49,6 +49,8 @@ public:
49 {151, nullptr, "GetStateWithHandover"}, 49 {151, nullptr, "GetStateWithHandover"},
50 {152, nullptr, "GetStateChangeEventWithHandover"}, 50 {152, nullptr, "GetStateChangeEventWithHandover"},
51 {153, nullptr, "GetDropEventWithHandover"}, 51 {153, nullptr, "GetDropEventWithHandover"},
52 {154, nullptr, "CreateTokenAsync"},
53 {155, nullptr, "CreateTokenAsyncWithApplicationId"},
52 {161, nullptr, "GetRequestChangeStateCancelEvent"}, 54 {161, nullptr, "GetRequestChangeStateCancelEvent"},
53 {162, nullptr, "RequestChangeStateForceTimedWithCancelEvent"}, 55 {162, nullptr, "RequestChangeStateForceTimedWithCancelEvent"},
54 {201, nullptr, "RequestChangeStateForceTimed"}, 56 {201, nullptr, "RequestChangeStateForceTimed"},
@@ -84,6 +86,7 @@ public:
84 {151, nullptr, "GetStateWithHandover"}, 86 {151, nullptr, "GetStateWithHandover"},
85 {152, nullptr, "GetStateChangeEventWithHandover"}, 87 {152, nullptr, "GetStateChangeEventWithHandover"},
86 {153, nullptr, "GetDropEventWithHandover"}, 88 {153, nullptr, "GetDropEventWithHandover"},
89 {154, nullptr, "CreateTokenAsync"},
87 }; 90 };
88 // clang-format on 91 // clang-format on
89 92
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 6ccf8995c..5fe7a9189 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -55,6 +55,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
55 {26, nullptr, "BeginInstallApplication"}, 55 {26, nullptr, "BeginInstallApplication"},
56 {27, nullptr, "DeleteApplicationRecord"}, 56 {27, nullptr, "DeleteApplicationRecord"},
57 {30, nullptr, "RequestApplicationUpdateInfo"}, 57 {30, nullptr, "RequestApplicationUpdateInfo"},
58 {31, nullptr, "Unknown31"},
58 {32, nullptr, "CancelApplicationDownload"}, 59 {32, nullptr, "CancelApplicationDownload"},
59 {33, nullptr, "ResumeApplicationDownload"}, 60 {33, nullptr, "ResumeApplicationDownload"},
60 {35, nullptr, "UpdateVersionList"}, 61 {35, nullptr, "UpdateVersionList"},
@@ -182,6 +183,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
182 {913, nullptr, "ListAllApplicationRecord"}, 183 {913, nullptr, "ListAllApplicationRecord"},
183 {914, nullptr, "HideApplicationRecord"}, 184 {914, nullptr, "HideApplicationRecord"},
184 {915, nullptr, "ShowApplicationRecord"}, 185 {915, nullptr, "ShowApplicationRecord"},
186 {916, nullptr, "IsApplicationAutoDeleteDisabled"},
185 {1000, nullptr, "RequestVerifyApplicationDeprecated"}, 187 {1000, nullptr, "RequestVerifyApplicationDeprecated"},
186 {1001, nullptr, "CorruptApplicationForDebug"}, 188 {1001, nullptr, "CorruptApplicationForDebug"},
187 {1002, nullptr, "RequestVerifyAddOnContentsRights"}, 189 {1002, nullptr, "RequestVerifyAddOnContentsRights"},
@@ -201,6 +203,8 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
201 {1310, nullptr, "RequestMoveApplicationEntity"}, 203 {1310, nullptr, "RequestMoveApplicationEntity"},
202 {1311, nullptr, "EstimateSizeToMove"}, 204 {1311, nullptr, "EstimateSizeToMove"},
203 {1312, nullptr, "HasMovableEntity"}, 205 {1312, nullptr, "HasMovableEntity"},
206 {1313, nullptr, "CleanupOrphanContents"},
207 {1314, nullptr, "CheckPreconditionSatisfiedToMove"},
204 {1400, nullptr, "PrepareShutdown"}, 208 {1400, nullptr, "PrepareShutdown"},
205 {1500, nullptr, "FormatSdCard"}, 209 {1500, nullptr, "FormatSdCard"},
206 {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"}, 210 {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
@@ -215,6 +219,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
215 {1702, nullptr, "GetApplicationDownloadTaskStatus"}, 219 {1702, nullptr, "GetApplicationDownloadTaskStatus"},
216 {1703, nullptr, "GetApplicationViewDownloadErrorContext"}, 220 {1703, nullptr, "GetApplicationViewDownloadErrorContext"},
217 {1704, nullptr, "GetApplicationViewWithPromotionInfo"}, 221 {1704, nullptr, "GetApplicationViewWithPromotionInfo"},
222 {1705, nullptr, "IsPatchAutoDeletableApplication"},
218 {1800, nullptr, "IsNotificationSetupCompleted"}, 223 {1800, nullptr, "IsNotificationSetupCompleted"},
219 {1801, nullptr, "GetLastNotificationInfoCount"}, 224 {1801, nullptr, "GetLastNotificationInfoCount"},
220 {1802, nullptr, "ListLastNotificationInfo"}, 225 {1802, nullptr, "ListLastNotificationInfo"},
@@ -269,6 +274,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
269 {2351, nullptr, "RequestNoDownloadRightsErrorResolution"}, 274 {2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
270 {2352, nullptr, "RequestResolveNoDownloadRightsError"}, 275 {2352, nullptr, "RequestResolveNoDownloadRightsError"},
271 {2353, nullptr, "GetApplicationDownloadTaskInfo"}, 276 {2353, nullptr, "GetApplicationDownloadTaskInfo"},
277 {2354, nullptr, "PrioritizeApplicationBackgroundTask"},
278 {2355, nullptr, "Unknown2355"},
279 {2356, nullptr, "Unknown2356"},
272 {2400, nullptr, "GetPromotionInfo"}, 280 {2400, nullptr, "GetPromotionInfo"},
273 {2401, nullptr, "CountPromotionInfo"}, 281 {2401, nullptr, "CountPromotionInfo"},
274 {2402, nullptr, "ListPromotionInfo"}, 282 {2402, nullptr, "ListPromotionInfo"},
@@ -282,6 +290,21 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
282 {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"}, 290 {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
283 {2516, nullptr, "EnsureApplicationCertificate"}, 291 {2516, nullptr, "EnsureApplicationCertificate"},
284 {2800, nullptr, "GetApplicationIdOfPreomia"}, 292 {2800, nullptr, "GetApplicationIdOfPreomia"},
293 {3000, nullptr, "RegisterDeviceLockKey"},
294 {3001, nullptr, "UnregisterDeviceLockKey"},
295 {3002, nullptr, "VerifyDeviceLockKey"},
296 {3003, nullptr, "HideApplicationIcon"},
297 {3004, nullptr, "ShowApplicationIcon"},
298 {3005, nullptr, "HideApplicationTitle"},
299 {3006, nullptr, "ShowApplicationTitle"},
300 {3007, nullptr, "EnableGameCard"},
301 {3008, nullptr, "DisableGameCard"},
302 {3009, nullptr, "EnableLocalContentShare"},
303 {3010, nullptr, "DisableLocalContentShare"},
304 {3011, nullptr, "IsApplicationIconHidden"},
305 {3012, nullptr, "IsApplicationTitleHidden"},
306 {3013, nullptr, "IsGameCardEnabled"},
307 {3014, nullptr, "IsLocalContentShareEnabled"},
285 {9999, nullptr, "GetApplicationCertificate"}, 308 {9999, nullptr, "GetApplicationCertificate"},
286 }; 309 };
287 // clang-format on 310 // clang-format on
@@ -441,7 +464,11 @@ IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_
441 {800, nullptr, "RequestVersionList"}, 464 {800, nullptr, "RequestVersionList"},
442 {801, nullptr, "ListVersionList"}, 465 {801, nullptr, "ListVersionList"},
443 {802, nullptr, "RequestVersionListData"}, 466 {802, nullptr, "RequestVersionListData"},
467 {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"},
468 {901, nullptr, "ListDefaultAutoUpdatePolicy"},
469 {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"},
444 {1000, nullptr, "PerformAutoUpdate"}, 470 {1000, nullptr, "PerformAutoUpdate"},
471 {1001, nullptr, "ListAutoUpdateSchedule"},
445 }; 472 };
446 // clang-format on 473 // clang-format on
447 474
@@ -547,6 +574,9 @@ IFactoryResetInterface::~IFactoryResetInterface() = default;
547NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { 574NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
548 // clang-format off 575 // clang-format off
549 static const FunctionInfo functions[] = { 576 static const FunctionInfo functions[] = {
577 {7988, nullptr, "GetDynamicRightsInterface"},
578 {7989, nullptr, "GetReadOnlyApplicationControlDataInterface"},
579 {7991, nullptr, "GetReadOnlyApplicationRecordInterface"},
550 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, 580 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
551 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, 581 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
552 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, 582 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
@@ -575,18 +605,22 @@ public:
575 {0, nullptr, "LaunchProgram"}, 605 {0, nullptr, "LaunchProgram"},
576 {1, nullptr, "TerminateProcess"}, 606 {1, nullptr, "TerminateProcess"},
577 {2, nullptr, "TerminateProgram"}, 607 {2, nullptr, "TerminateProgram"},
578 {4, nullptr, "GetShellEventHandle"}, 608 {4, nullptr, "GetShellEvent"},
579 {5, nullptr, "GetShellEventInfo"}, 609 {5, nullptr, "GetShellEventInfo"},
580 {6, nullptr, "TerminateApplication"}, 610 {6, nullptr, "TerminateApplication"},
581 {7, nullptr, "PrepareLaunchProgramFromHost"}, 611 {7, nullptr, "PrepareLaunchProgramFromHost"},
582 {8, nullptr, "LaunchApplication"}, 612 {8, nullptr, "LaunchApplicationFromHost"},
583 {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"}, 613 {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
584 {10, nullptr, "IsSystemMemoryResourceLimitBoosted"}, 614 {10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
585 {11, nullptr, "GetRunningApplicationProcessIdForDevelop"}, 615 {11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
586 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"}, 616 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"},
587 {13, nullptr, "CreateApplicationResourceForDevelop"}, 617 {13, nullptr, "CreateApplicationResourceForDevelop"},
588 {14, nullptr, "IsPreomiaForDevelop"}, 618 {14, nullptr, "IsPreomiaForDevelop"},
589 {15, nullptr, "GetApplicationProgramIdFromHost"}, 619 {15, nullptr, "GetApplicationProgramIdFromHost"},
620 {16, nullptr, "RefreshCachedDebugValues"},
621 {17, nullptr, "PrepareLaunchApplicationFromHost"},
622 {18, nullptr, "GetLaunchEvent"},
623 {19, nullptr, "GetLaunchResult"},
590 }; 624 };
591 // clang-format on 625 // clang-format on
592 626
@@ -699,6 +733,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
699 std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager); 733 std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager);
700 std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager); 734 std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager);
701 std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager); 735 std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);
736 std::make_shared<NS>("ns:ro", system)->InstallAsService(service_manager);
702 737
703 std::make_shared<NS_DEV>(system)->InstallAsService(service_manager); 738 std::make_shared<NS_DEV>(system)->InstallAsService(service_manager);
704 std::make_shared<NS_SU>(system)->InstallAsService(service_manager); 739 std::make_shared<NS_SU>(system)->InstallAsService(service_manager);
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index fcd15d81f..da139fdc4 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -154,6 +154,10 @@ PL_U::PL_U(Core::System& system_)
154 {100, nullptr, "RequestApplicationFunctionAuthorization"}, 154 {100, nullptr, "RequestApplicationFunctionAuthorization"},
155 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, 155 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
156 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, 156 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
157 {103, nullptr, "RefreshApplicationFunctionBlackListDebugRecord"},
158 {104, nullptr, "RequestApplicationFunctionAuthorizationByProgramId"},
159 {105, nullptr, "GetFunctionBlackListSystemVersionToAuthorize"},
160 {106, nullptr, "GetFunctionBlackListVersion"},
157 {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"}, 161 {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
158 {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"}, 162 {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"},
159 }; 163 };
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 5681599ba..b37f023df 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -31,7 +31,7 @@ public:
31 * @param output A buffer where the output data will be written to. 31 * @param output A buffer where the output data will be written to.
32 * @returns The result code of the ioctl. 32 * @returns The result code of the ioctl.
33 */ 33 */
34 virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, 34 virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
35 std::vector<u8>& output) = 0; 35 std::vector<u8>& output) = 0;
36 36
37 /** 37 /**
@@ -42,7 +42,7 @@ public:
42 * @param output A buffer where the output data will be written to. 42 * @param output A buffer where the output data will be written to.
43 * @returns The result code of the ioctl. 43 * @returns The result code of the ioctl.
44 */ 44 */
45 virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 45 virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
46 const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; 46 const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
47 47
48 /** 48 /**
@@ -53,8 +53,20 @@ public:
53 * @param inline_output A buffer where the inlined output data will be written to. 53 * @param inline_output A buffer where the inlined output data will be written to.
54 * @returns The result code of the ioctl. 54 * @returns The result code of the ioctl.
55 */ 55 */
56 virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 56 virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
57 std::vector<u8>& inline_output) = 0; 57 std::vector<u8>& output, std::vector<u8>& inline_output) = 0;
58
59 /**
60 * Called once a device is openned
61 * @param fd The device fd
62 */
63 virtual void OnOpen(DeviceFD fd) = 0;
64
65 /**
66 * Called once a device is closed
67 * @param fd The device fd
68 */
69 virtual void OnClose(DeviceFD fd) = 0;
58 70
59protected: 71protected:
60 Core::System& system; 72 Core::System& system;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index ce615c758..5ab7e39b0 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -18,24 +18,27 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
18 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 18 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
19nvdisp_disp0 ::~nvdisp_disp0() = default; 19nvdisp_disp0 ::~nvdisp_disp0() = default;
20 20
21NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, 21NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
22 std::vector<u8>& output) { 22 std::vector<u8>& output) {
23 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 23 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
24 return NvResult::NotImplemented; 24 return NvResult::NotImplemented;
25} 25}
26 26
27NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input, 27NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
28 const std::vector<u8>& inline_input, std::vector<u8>& output) { 28 const std::vector<u8>& inline_input, std::vector<u8>& output) {
29 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 29 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
30 return NvResult::NotImplemented; 30 return NvResult::NotImplemented;
31} 31}
32 32
33NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 33NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
34 std::vector<u8>& inline_output) { 34 std::vector<u8>& output, std::vector<u8>& inline_output) {
35 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 35 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
36 return NvResult::NotImplemented; 36 return NvResult::NotImplemented;
37} 37}
38 38
39void nvdisp_disp0::OnOpen(DeviceFD fd) {}
40void nvdisp_disp0::OnClose(DeviceFD fd) {}
41
39void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, 42void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
40 u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform, 43 u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform,
41 const Common::Rectangle<int>& crop_rect) { 44 const Common::Rectangle<int>& crop_rect) {
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 55a33b7e4..59c9b6101 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -20,11 +20,15 @@ public:
20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
21 ~nvdisp_disp0() override; 21 ~nvdisp_disp0() override;
22 22
23 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 23 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
24 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 24 std::vector<u8>& output) override;
25 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
25 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 26 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
26 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 27 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
27 std::vector<u8>& inline_output) override; 28 std::vector<u8>& output, std::vector<u8>& inline_output) override;
29
30 void OnOpen(DeviceFD fd) override;
31 void OnClose(DeviceFD fd) override;
28 32
29 /// Performs a screen flip, drawing the buffer pointed to by the handle. 33 /// Performs a screen flip, drawing the buffer pointed to by the handle.
30 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, 34 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 6b062e10e..f7b3dc317 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -21,7 +21,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_
21 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 21 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
22nvhost_as_gpu::~nvhost_as_gpu() = default; 22nvhost_as_gpu::~nvhost_as_gpu() = default;
23 23
24NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, 24NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
25 std::vector<u8>& output) { 25 std::vector<u8>& output) {
26 switch (command.group) { 26 switch (command.group) {
27 case 'A': 27 case 'A':
@@ -39,7 +39,7 @@ NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
39 case 0x8: 39 case 0x8:
40 return GetVARegions(input, output); 40 return GetVARegions(input, output);
41 case 0x9: 41 case 0x9:
42 return InitalizeEx(input, output); 42 return AllocAsEx(input, output);
43 case 0x14: 43 case 0x14:
44 return Remap(input, output); 44 return Remap(input, output);
45 default: 45 default:
@@ -54,14 +54,14 @@ NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
54 return NvResult::NotImplemented; 54 return NvResult::NotImplemented;
55} 55}
56 56
57NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, 57NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
58 const std::vector<u8>& inline_input, std::vector<u8>& output) { 58 const std::vector<u8>& inline_input, std::vector<u8>& output) {
59 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 59 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
60 return NvResult::NotImplemented; 60 return NvResult::NotImplemented;
61} 61}
62 62
63NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 63NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
64 std::vector<u8>& inline_output) { 64 std::vector<u8>& output, std::vector<u8>& inline_output) {
65 switch (command.group) { 65 switch (command.group) {
66 case 'A': 66 case 'A':
67 switch (command.cmd) { 67 switch (command.cmd) {
@@ -78,11 +78,19 @@ NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std:
78 return NvResult::NotImplemented; 78 return NvResult::NotImplemented;
79} 79}
80 80
81NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { 81void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
82 IoctlInitalizeEx params{}; 82void nvhost_as_gpu::OnClose(DeviceFD fd) {}
83
84NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output) {
85 IoctlAllocAsEx params{};
83 std::memcpy(&params, input.data(), input.size()); 86 std::memcpy(&params, input.data(), input.size());
84 87
85 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); 88 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
89 if (params.big_page_size == 0) {
90 params.big_page_size = DEFAULT_BIG_PAGE_SIZE;
91 }
92
93 big_page_size = params.big_page_size;
86 94
87 return NvResult::Success; 95 return NvResult::Success;
88} 96}
@@ -276,13 +284,18 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
276 params.buf_size); 284 params.buf_size);
277 285
278 params.buf_size = 0x30; 286 params.buf_size = 0x30;
279 params.regions[0].offset = 0x04000000;
280 params.regions[0].page_size = 0x1000;
281 params.regions[0].pages = 0x3fbfff;
282 287
283 params.regions[1].offset = 0x04000000; 288 params.small = IoctlVaRegion{
284 params.regions[1].page_size = 0x10000; 289 .offset = 0x04000000,
285 params.regions[1].pages = 0x1bffff; 290 .page_size = DEFAULT_SMALL_PAGE_SIZE,
291 .pages = 0x3fbfff,
292 };
293
294 params.big = IoctlVaRegion{
295 .offset = 0x04000000,
296 .page_size = big_page_size,
297 .pages = 0x1bffff,
298 };
286 299
287 // TODO(ogniK): This probably can stay stubbed but should add support way way later 300 // TODO(ogniK): This probably can stay stubbed but should add support way way later
288 301
@@ -299,18 +312,25 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
299 params.buf_size); 312 params.buf_size);
300 313
301 params.buf_size = 0x30; 314 params.buf_size = 0x30;
302 params.regions[0].offset = 0x04000000;
303 params.regions[0].page_size = 0x1000;
304 params.regions[0].pages = 0x3fbfff;
305 315
306 params.regions[1].offset = 0x04000000; 316 params.small = IoctlVaRegion{
307 params.regions[1].page_size = 0x10000; 317 .offset = 0x04000000,
308 params.regions[1].pages = 0x1bffff; 318 .page_size = 0x1000,
319 .pages = 0x3fbfff,
320 };
321
322 params.big = IoctlVaRegion{
323 .offset = 0x04000000,
324 .page_size = big_page_size,
325 .pages = 0x1bffff,
326 };
309 327
310 // TODO(ogniK): This probably can stay stubbed but should add support way way later 328 // TODO(ogniK): This probably can stay stubbed but should add support way way later
311 329
312 std::memcpy(output.data(), &params, output.size()); 330 std::memcpy(output.data(), &params, output.size());
313 std::memcpy(inline_output.data(), &params.regions, inline_output.size()); 331 std::memcpy(inline_output.data(), &params.small, sizeof(IoctlVaRegion));
332 std::memcpy(inline_output.data() + sizeof(IoctlVaRegion), &params.big, sizeof(IoctlVaRegion));
333
314 return NvResult::Success; 334 return NvResult::Success;
315} 335}
316 336
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 08035fa0e..d86a9cab6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -16,6 +16,9 @@
16 16
17namespace Service::Nvidia::Devices { 17namespace Service::Nvidia::Devices {
18 18
19constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16;
20constexpr u32 DEFAULT_SMALL_PAGE_SIZE = 1 << 12;
21
19class nvmap; 22class nvmap;
20 23
21enum class AddressSpaceFlags : u32 { 24enum class AddressSpaceFlags : u32 {
@@ -30,11 +33,15 @@ public:
30 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 33 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
31 ~nvhost_as_gpu() override; 34 ~nvhost_as_gpu() override;
32 35
33 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 36 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
34 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 37 std::vector<u8>& output) override;
38 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
35 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 39 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
36 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 40 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
37 std::vector<u8>& inline_output) override; 41 std::vector<u8>& output, std::vector<u8>& inline_output) override;
42
43 void OnOpen(DeviceFD fd) override;
44 void OnClose(DeviceFD fd) override;
38 45
39private: 46private:
40 class BufferMap final { 47 class BufferMap final {
@@ -76,16 +83,16 @@ private:
76 bool is_allocated{}; 83 bool is_allocated{};
77 }; 84 };
78 85
79 struct IoctlInitalizeEx { 86 struct IoctlAllocAsEx {
80 u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default 87 u32_le flags{}; // usually passes 1
81 s32_le as_fd{}; // ignored; passes 0 88 s32_le as_fd{}; // ignored; passes 0
82 u32_le flags{}; // passes 0 89 u32_le big_page_size{};
83 u32_le reserved{}; // ignored; passes 0 90 u32_le reserved{}; // ignored; passes 0
84 u64_le unk0{}; 91 u64_le va_range_start{};
85 u64_le unk1{}; 92 u64_le va_range_end{};
86 u64_le unk2{}; 93 u64_le va_range_split{};
87 }; 94 };
88 static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); 95 static_assert(sizeof(IoctlAllocAsEx) == 40, "IoctlAllocAsEx is incorrect size");
89 96
90 struct IoctlAllocSpace { 97 struct IoctlAllocSpace {
91 u32_le pages{}; 98 u32_le pages{};
@@ -149,14 +156,16 @@ private:
149 u64_le buf_addr{}; // (contained output user ptr on linux, ignored) 156 u64_le buf_addr{}; // (contained output user ptr on linux, ignored)
150 u32_le buf_size{}; // forced to 2*sizeof(struct va_region) 157 u32_le buf_size{}; // forced to 2*sizeof(struct va_region)
151 u32_le reserved{}; 158 u32_le reserved{};
152 IoctlVaRegion regions[2]{}; 159 IoctlVaRegion small{};
160 IoctlVaRegion big{};
153 }; 161 };
154 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, 162 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
155 "IoctlGetVaRegions is incorrect size"); 163 "IoctlGetVaRegions is incorrect size");
156 164
157 s32 channel{}; 165 s32 channel{};
166 u32 big_page_size{DEFAULT_BIG_PAGE_SIZE};
158 167
159 NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); 168 NvResult AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output);
160 NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); 169 NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
161 NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); 170 NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
162 NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); 171 NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index f6129ef10..9f00d5cb0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -20,7 +20,8 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
20 : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} 20 : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
21nvhost_ctrl::~nvhost_ctrl() = default; 21nvhost_ctrl::~nvhost_ctrl() = default;
22 22
23NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 23NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
24 std::vector<u8>& output) {
24 switch (command.group) { 25 switch (command.group) {
25 case 0x0: 26 case 0x0:
26 switch (command.cmd) { 27 switch (command.cmd) {
@@ -46,18 +47,21 @@ NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::v
46 return NvResult::NotImplemented; 47 return NvResult::NotImplemented;
47} 48}
48 49
49NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input, 50NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
50 const std::vector<u8>& inline_input, std::vector<u8>& output) { 51 const std::vector<u8>& inline_input, std::vector<u8>& output) {
51 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
52 return NvResult::NotImplemented; 53 return NvResult::NotImplemented;
53} 54}
54 55
55NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 56NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
56 std::vector<u8>& inline_outpu) { 57 std::vector<u8>& output, std::vector<u8>& inline_outpu) {
57 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 58 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
58 return NvResult::NotImplemented; 59 return NvResult::NotImplemented;
59} 60}
60 61
62void nvhost_ctrl::OnOpen(DeviceFD fd) {}
63void nvhost_ctrl::OnClose(DeviceFD fd) {}
64
61NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { 65NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
62 IocGetConfigParams params{}; 66 IocGetConfigParams params{};
63 std::memcpy(&params, input.data(), sizeof(params)); 67 std::memcpy(&params, input.data(), sizeof(params));
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index c5aa1362a..9178789c3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -18,11 +18,15 @@ public:
18 SyncpointManager& syncpoint_manager); 18 SyncpointManager& syncpoint_manager);
19 ~nvhost_ctrl() override; 19 ~nvhost_ctrl() override;
20 20
21 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 21 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
22 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 22 std::vector<u8>& output) override;
23 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
23 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 24 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
24 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 25 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
25 std::vector<u8>& inline_output) override; 26 std::vector<u8>& output, std::vector<u8>& inline_output) override;
27
28 void OnOpen(DeviceFD fd) override;
29 void OnClose(DeviceFD fd) override;
26 30
27private: 31private:
28 struct IocSyncptReadParams { 32 struct IocSyncptReadParams {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 0320d3ae2..2edd803f3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices {
15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} 15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; 16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
17 17
18NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, 18NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
19 std::vector<u8>& output) { 19 std::vector<u8>& output) {
20 switch (command.group) { 20 switch (command.group) {
21 case 'G': 21 case 'G':
@@ -47,13 +47,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
47 return NvResult::NotImplemented; 47 return NvResult::NotImplemented;
48} 48}
49 49
50NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, 50NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
51 const std::vector<u8>& inline_input, std::vector<u8>& output) { 51 const std::vector<u8>& inline_input, std::vector<u8>& output) {
52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
53 return NvResult::NotImplemented; 53 return NvResult::NotImplemented;
54} 54}
55 55
56NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, 56NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
57 std::vector<u8>& output, std::vector<u8>& inline_output) { 57 std::vector<u8>& output, std::vector<u8>& inline_output) {
58 switch (command.group) { 58 switch (command.group) {
59 case 'G': 59 case 'G':
@@ -73,6 +73,9 @@ NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
73 return NvResult::NotImplemented; 73 return NvResult::NotImplemented;
74} 74}
75 75
76void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
77void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
78
76NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, 79NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
77 std::vector<u8>& output) { 80 std::vector<u8>& output) {
78 LOG_DEBUG(Service_NVDRV, "called"); 81 LOG_DEBUG(Service_NVDRV, "called");
@@ -245,7 +248,13 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<
245 IoctlZbcSetTable params{}; 248 IoctlZbcSetTable params{};
246 std::memcpy(&params, input.data(), input.size()); 249 std::memcpy(&params, input.data(), input.size());
247 // TODO(ogniK): What does this even actually do? 250 // TODO(ogniK): What does this even actually do?
248 std::memcpy(output.data(), &params, output.size()); 251
252 // Prevent null pointer being passed as arg 1
253 if (output.empty()) {
254 LOG_WARNING(Service_NVDRV, "Avoiding passing null pointer to memcpy");
255 } else {
256 std::memcpy(output.data(), &params, output.size());
257 }
249 return NvResult::Success; 258 return NvResult::Success;
250} 259}
251 260
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 137b88238..f98aa841a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -16,11 +16,15 @@ public:
16 explicit nvhost_ctrl_gpu(Core::System& system); 16 explicit nvhost_ctrl_gpu(Core::System& system);
17 ~nvhost_ctrl_gpu() override; 17 ~nvhost_ctrl_gpu() override;
18 18
19 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 19 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
20 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 20 std::vector<u8>& output) override;
21 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
21 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 22 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
22 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 23 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
23 std::vector<u8>& inline_output) override; 24 std::vector<u8>& output, std::vector<u8>& inline_output) override;
25
26 void OnOpen(DeviceFD fd) override;
27 void OnClose(DeviceFD fd) override;
24 28
25private: 29private:
26 struct IoctlGpuCharacteristics { 30 struct IoctlGpuCharacteristics {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index af8b3d9f1..e83aaa798 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -23,7 +23,8 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
23 23
24nvhost_gpu::~nvhost_gpu() = default; 24nvhost_gpu::~nvhost_gpu() = default;
25 25
26NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 26NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
27 std::vector<u8>& output) {
27 switch (command.group) { 28 switch (command.group) {
28 case 0x0: 29 case 0x0:
29 switch (command.cmd) { 30 switch (command.cmd) {
@@ -74,7 +75,7 @@ NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
74 return NvResult::NotImplemented; 75 return NvResult::NotImplemented;
75}; 76};
76 77
77NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, 78NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
78 const std::vector<u8>& inline_input, std::vector<u8>& output) { 79 const std::vector<u8>& inline_input, std::vector<u8>& output) {
79 switch (command.group) { 80 switch (command.group) {
80 case 'H': 81 case 'H':
@@ -88,12 +89,15 @@ NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
88 return NvResult::NotImplemented; 89 return NvResult::NotImplemented;
89} 90}
90 91
91NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 92NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
92 std::vector<u8>& inline_output) { 93 std::vector<u8>& output, std::vector<u8>& inline_output) {
93 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 94 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
94 return NvResult::NotImplemented; 95 return NvResult::NotImplemented;
95} 96}
96 97
98void nvhost_gpu::OnOpen(DeviceFD fd) {}
99void nvhost_gpu::OnClose(DeviceFD fd) {}
100
97NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 101NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
98 IoctlSetNvmapFD params{}; 102 IoctlSetNvmapFD params{};
99 std::memcpy(&params, input.data(), input.size()); 103 std::memcpy(&params, input.data(), input.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index e0298b4fe..12a1a1133 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -26,11 +26,15 @@ public:
26 SyncpointManager& syncpoint_manager); 26 SyncpointManager& syncpoint_manager);
27 ~nvhost_gpu() override; 27 ~nvhost_gpu() override;
28 28
29 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 29 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
30 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 30 std::vector<u8>& output) override;
31 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
31 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 32 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
32 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 33 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
33 std::vector<u8>& inline_output) override; 34 std::vector<u8>& output, std::vector<u8>& inline_output) override;
35
36 void OnOpen(DeviceFD fd) override;
37 void OnClose(DeviceFD fd) override;
34 38
35private: 39private:
36 enum class CtxObjects : u32_le { 40 enum class CtxObjects : u32_le {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index ecba1dba1..c8031970b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -16,7 +16,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de
16 : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {} 16 : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
17nvhost_nvdec::~nvhost_nvdec() = default; 17nvhost_nvdec::~nvhost_nvdec() = default;
18 18
19NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, 19NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
20 std::vector<u8>& output) { 20 std::vector<u8>& output) {
21 switch (command.group) { 21 switch (command.group) {
22 case 0x0: 22 case 0x0:
@@ -57,16 +57,19 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
57 return NvResult::NotImplemented; 57 return NvResult::NotImplemented;
58} 58}
59 59
60NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input, 60NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
61 const std::vector<u8>& inline_input, std::vector<u8>& output) { 61 const std::vector<u8>& inline_input, std::vector<u8>& output) {
62 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 62 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
63 return NvResult::NotImplemented; 63 return NvResult::NotImplemented;
64} 64}
65 65
66NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 66NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
67 std::vector<u8>& inline_output) { 67 std::vector<u8>& output, std::vector<u8>& inline_output) {
68 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 68 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
69 return NvResult::NotImplemented; 69 return NvResult::NotImplemented;
70} 70}
71 71
72void nvhost_nvdec::OnOpen(DeviceFD fd) {}
73void nvhost_nvdec::OnClose(DeviceFD fd) {}
74
72} // namespace Service::Nvidia::Devices 75} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 77ef53cdd..6c38a8c24 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -15,11 +15,15 @@ public:
15 SyncpointManager& syncpoint_manager); 15 SyncpointManager& syncpoint_manager);
16 ~nvhost_nvdec() override; 16 ~nvhost_nvdec() override;
17 17
18 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 18 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
19 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 19 std::vector<u8>& output) override;
20 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
20 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 21 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
21 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 22 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
22 std::vector<u8>& inline_output) override; 23 std::vector<u8>& output, std::vector<u8>& inline_output) override;
24
25 void OnOpen(DeviceFD fd) override;
26 void OnClose(DeviceFD fd) override;
23}; 27};
24 28
25} // namespace Service::Nvidia::Devices 29} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 4898dc27a..c2f152190 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -23,17 +23,22 @@ namespace {
23template <typename T> 23template <typename T>
24std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count, 24std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
25 std::size_t offset) { 25 std::size_t offset) {
26 std::memcpy(dst.data(), input.data() + offset, count * sizeof(T)); 26 if (!dst.empty()) {
27 offset += count * sizeof(T); 27 std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
28 return offset; 28 }
29 return 0;
29} 30}
30 31
31// Write vectors will write data to the output buffer 32// Write vectors will write data to the output buffer
32template <typename T> 33template <typename T>
33std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) { 34std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
34 std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T)); 35 if (src.empty()) {
35 offset += src.size() * sizeof(T); 36 return 0;
36 return offset; 37 } else {
38 std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
39 offset += src.size() * sizeof(T);
40 return offset;
41 }
37} 42}
38} // Anonymous namespace 43} // Anonymous namespace
39 44
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 2d06955c0..0a9c35c01 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -13,7 +13,7 @@ namespace Service::Nvidia::Devices {
13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} 13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
14nvhost_nvjpg::~nvhost_nvjpg() = default; 14nvhost_nvjpg::~nvhost_nvjpg() = default;
15 15
16NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, 16NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
17 std::vector<u8>& output) { 17 std::vector<u8>& output) {
18 switch (command.group) { 18 switch (command.group) {
19 case 'H': 19 case 'H':
@@ -32,18 +32,21 @@ NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input,
32 return NvResult::NotImplemented; 32 return NvResult::NotImplemented;
33} 33}
34 34
35NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input, 35NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
36 const std::vector<u8>& inline_input, std::vector<u8>& output) { 36 const std::vector<u8>& inline_input, std::vector<u8>& output) {
37 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 37 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
38 return NvResult::NotImplemented; 38 return NvResult::NotImplemented;
39} 39}
40 40
41NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 41NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
42 std::vector<u8>& inline_output) { 42 std::vector<u8>& output, std::vector<u8>& inline_output) {
43 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 43 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
44 return NvResult::NotImplemented; 44 return NvResult::NotImplemented;
45} 45}
46 46
47void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
48void nvhost_nvjpg::OnClose(DeviceFD fd) {}
49
47NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 50NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
48 IoctlSetNvmapFD params{}; 51 IoctlSetNvmapFD params{};
49 std::memcpy(&params, input.data(), input.size()); 52 std::memcpy(&params, input.data(), input.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 43948d18d..1f97b642f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -16,11 +16,15 @@ public:
16 explicit nvhost_nvjpg(Core::System& system); 16 explicit nvhost_nvjpg(Core::System& system);
17 ~nvhost_nvjpg() override; 17 ~nvhost_nvjpg() override;
18 18
19 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 19 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
20 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 20 std::vector<u8>& output) override;
21 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
21 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 22 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
22 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 23 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
23 std::vector<u8>& inline_output) override; 24 std::vector<u8>& output, std::vector<u8>& inline_output) override;
25
26 void OnOpen(DeviceFD fd) override;
27 void OnClose(DeviceFD fd) override;
24 28
25private: 29private:
26 struct IoctlSetNvmapFD { 30 struct IoctlSetNvmapFD {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 70849a9bd..0421fb956 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -16,7 +16,8 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
16 16
17nvhost_vic::~nvhost_vic() = default; 17nvhost_vic::~nvhost_vic() = default;
18 18
19NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 19NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
20 std::vector<u8>& output) {
20 switch (command.group) { 21 switch (command.group) {
21 case 0x0: 22 case 0x0:
22 switch (command.cmd) { 23 switch (command.cmd) {
@@ -55,16 +56,19 @@ NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
55 return NvResult::NotImplemented; 56 return NvResult::NotImplemented;
56} 57}
57 58
58NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input, 59NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
59 const std::vector<u8>& inline_input, std::vector<u8>& output) { 60 const std::vector<u8>& inline_input, std::vector<u8>& output) {
60 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 61 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
61 return NvResult::NotImplemented; 62 return NvResult::NotImplemented;
62} 63}
63 64
64NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 65NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
65 std::vector<u8>& inline_output) { 66 std::vector<u8>& output, std::vector<u8>& inline_output) {
66 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 67 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
67 return NvResult::NotImplemented; 68 return NvResult::NotImplemented;
68} 69}
69 70
71void nvhost_vic::OnOpen(DeviceFD fd) {}
72void nvhost_vic::OnClose(DeviceFD fd) {}
73
70} // namespace Service::Nvidia::Devices 74} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index f401c61fa..cebefad71 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -14,10 +14,14 @@ public:
14 SyncpointManager& syncpoint_manager); 14 SyncpointManager& syncpoint_manager);
15 ~nvhost_vic(); 15 ~nvhost_vic();
16 16
17 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 17 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
18 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 18 std::vector<u8>& output) override;
19 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
19 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 20 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
20 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 21 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
21 std::vector<u8>& inline_output) override; 22 std::vector<u8>& output, std::vector<u8>& inline_output) override;
23
24 void OnOpen(DeviceFD fd) override;
25 void OnClose(DeviceFD fd) override;
22}; 26};
23} // namespace Service::Nvidia::Devices 27} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 4015a2740..dd1355522 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -19,7 +19,8 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {
19 19
20nvmap::~nvmap() = default; 20nvmap::~nvmap() = default;
21 21
22NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 22NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
23 std::vector<u8>& output) {
23 switch (command.group) { 24 switch (command.group) {
24 case 0x1: 25 case 0x1:
25 switch (command.cmd) { 26 switch (command.cmd) {
@@ -47,18 +48,21 @@ NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<
47 return NvResult::NotImplemented; 48 return NvResult::NotImplemented;
48} 49}
49 50
50NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input, 51NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
51 const std::vector<u8>& inline_input, std::vector<u8>& output) { 52 const std::vector<u8>& inline_input, std::vector<u8>& output) {
52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 53 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
53 return NvResult::NotImplemented; 54 return NvResult::NotImplemented;
54} 55}
55 56
56NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 57NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
57 std::vector<u8>& inline_output) { 58 std::vector<u8>& output, std::vector<u8>& inline_output) {
58 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); 59 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
59 return NvResult::NotImplemented; 60 return NvResult::NotImplemented;
60} 61}
61 62
63void nvmap::OnOpen(DeviceFD fd) {}
64void nvmap::OnClose(DeviceFD fd) {}
65
62VAddr nvmap::GetObjectAddress(u32 handle) const { 66VAddr nvmap::GetObjectAddress(u32 handle) const {
63 auto object = GetObject(handle); 67 auto object = GetObject(handle);
64 ASSERT(object); 68 ASSERT(object);
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 4484bd79f..208875845 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -19,11 +19,15 @@ public:
19 explicit nvmap(Core::System& system); 19 explicit nvmap(Core::System& system);
20 ~nvmap() override; 20 ~nvmap() override;
21 21
22 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 22 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
23 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, 23 std::vector<u8>& output) override;
24 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
24 const std::vector<u8>& inline_input, std::vector<u8>& output) override; 25 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
25 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 26 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
26 std::vector<u8>& inline_output) override; 27 std::vector<u8>& output, std::vector<u8>& inline_output) override;
28
29 void OnOpen(DeviceFD fd) override;
30 void OnClose(DeviceFD fd) override;
27 31
28 /// Returns the allocated address of an nvmap object given its handle. 32 /// Returns the allocated address of an nvmap object given its handle.
29 VAddr GetObjectAddress(u32 handle) const; 33 VAddr GetObjectAddress(u32 handle) const;
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index abba80112..ede77858a 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -89,6 +89,8 @@ DeviceFD Module::Open(const std::string& device_name) {
89 auto device = devices[device_name]; 89 auto device = devices[device_name];
90 const DeviceFD fd = next_fd++; 90 const DeviceFD fd = next_fd++;
91 91
92 device->OnOpen(fd);
93
92 open_files[fd] = std::move(device); 94 open_files[fd] = std::move(device);
93 95
94 return fd; 96 return fd;
@@ -108,7 +110,7 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input
108 return NvResult::NotImplemented; 110 return NvResult::NotImplemented;
109 } 111 }
110 112
111 return itr->second->Ioctl1(command, input, output); 113 return itr->second->Ioctl1(fd, command, input, output);
112} 114}
113 115
114NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 116NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -125,7 +127,7 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input
125 return NvResult::NotImplemented; 127 return NvResult::NotImplemented;
126 } 128 }
127 129
128 return itr->second->Ioctl2(command, input, inline_input, output); 130 return itr->second->Ioctl2(fd, command, input, inline_input, output);
129} 131}
130 132
131NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 133NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -142,7 +144,7 @@ NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input
142 return NvResult::NotImplemented; 144 return NvResult::NotImplemented;
143 } 145 }
144 146
145 return itr->second->Ioctl3(command, input, output, inline_output); 147 return itr->second->Ioctl3(fd, command, input, output, inline_output);
146} 148}
147 149
148NvResult Module::Close(DeviceFD fd) { 150NvResult Module::Close(DeviceFD fd) {
@@ -158,6 +160,8 @@ NvResult Module::Close(DeviceFD fd) {
158 return NvResult::NotImplemented; 160 return NvResult::NotImplemented;
159 } 161 }
160 162
163 itr->second->OnClose(fd);
164
161 open_files.erase(itr); 165 open_files.erase(itr);
162 166
163 return NvResult::Success; 167 return NvResult::Success;
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index e2ac71fa1..b066c3417 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -26,6 +26,7 @@ public:
26 {22, nullptr, "DeleteSaveDataBackupAsync"}, 26 {22, nullptr, "DeleteSaveDataBackupAsync"},
27 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"}, 27 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
28 {26, nullptr, "DownloadSaveDataBackupAsync"}, 28 {26, nullptr, "DownloadSaveDataBackupAsync"},
29 {27, nullptr, "UploadSaveDataBackupAsync"},
29 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"}, 30 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
30 {9013, nullptr, "GetSaveDataBackupSettingForDebug"}, 31 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
31 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"}, 32 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
index f6686fc4d..9bc851591 100644
--- a/src/core/hle/service/pcie/pcie.cpp
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -37,7 +37,7 @@ public:
37 {19, nullptr, "SetIrqEnable"}, 37 {19, nullptr, "SetIrqEnable"},
38 {20, nullptr, "SetAspmEnable"}, 38 {20, nullptr, "SetAspmEnable"},
39 {21, nullptr, "SetResetUponResumeEnable"}, 39 {21, nullptr, "SetResetUponResumeEnable"},
40 {22, nullptr, "Unknown22"}, 40 {22, nullptr, "ResetFunction"},
41 {23, nullptr, "Unknown23"}, 41 {23, nullptr, "Unknown23"},
42 }; 42 };
43 // clang-format on 43 // clang-format on
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index f9089bf2f..e6cd4b3c7 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -50,6 +50,7 @@ public:
50 {1046, nullptr, "DisableFeaturesForReset"}, 50 {1046, nullptr, "DisableFeaturesForReset"},
51 {1047, nullptr, "NotifyApplicationDownloadStarted"}, 51 {1047, nullptr, "NotifyApplicationDownloadStarted"},
52 {1048, nullptr, "NotifyNetworkProfileCreated"}, 52 {1048, nullptr, "NotifyNetworkProfileCreated"},
53 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
53 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"}, 54 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
54 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"}, 55 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
55 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"}, 56 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
@@ -69,6 +70,8 @@ public:
69 {1421, nullptr, "GetAccountNickname"}, 70 {1421, nullptr, "GetAccountNickname"},
70 {1424, nullptr, "GetAccountState"}, 71 {1424, nullptr, "GetAccountState"},
71 {1425, nullptr, "RequestPostEvents"}, 72 {1425, nullptr, "RequestPostEvents"},
73 {1426, nullptr, "GetPostEventInterval"},
74 {1427, nullptr, "SetPostEventInterval"},
72 {1432, nullptr, "GetSynchronizationEvent"}, 75 {1432, nullptr, "GetSynchronizationEvent"},
73 {1451, nullptr, "StartPlayTimer"}, 76 {1451, nullptr, "StartPlayTimer"},
74 {1452, nullptr, "StopPlayTimer"}, 77 {1452, nullptr, "StopPlayTimer"},
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 1da56bc27..aec399076 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -70,6 +70,7 @@
70#include "core/hle/service/vi/vi.h" 70#include "core/hle/service/vi/vi.h"
71#include "core/hle/service/wlan/wlan.h" 71#include "core/hle/service/wlan/wlan.h"
72#include "core/reporter.h" 72#include "core/reporter.h"
73#include "core/settings.h"
73 74
74namespace Service { 75namespace Service {
75 76
@@ -146,6 +147,11 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
146 system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, 147 system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
147 service_name); 148 service_name);
148 UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); 149 UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
150 if (Settings::values.use_auto_stub) {
151 LOG_WARNING(Service, "Using auto stub fallback!");
152 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(RESULT_SUCCESS);
154 }
149} 155}
150 156
151void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { 157void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index b58b2c8c5..5909fdd85 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -261,6 +261,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
261 {155, nullptr, "SetAccountOnlineStorageSettings"}, 261 {155, nullptr, "SetAccountOnlineStorageSettings"},
262 {156, nullptr, "GetPctlReadyFlag"}, 262 {156, nullptr, "GetPctlReadyFlag"},
263 {157, nullptr, "SetPctlReadyFlag"}, 263 {157, nullptr, "SetPctlReadyFlag"},
264 {158, nullptr, "GetAnalogStickUserCalibrationL"},
265 {159, nullptr, "SetAnalogStickUserCalibrationL"},
266 {160, nullptr, "GetAnalogStickUserCalibrationR"},
267 {161, nullptr, "SetAnalogStickUserCalibrationR"},
264 {162, nullptr, "GetPtmBatteryVersion"}, 268 {162, nullptr, "GetPtmBatteryVersion"},
265 {163, nullptr, "SetPtmBatteryVersion"}, 269 {163, nullptr, "SetPtmBatteryVersion"},
266 {164, nullptr, "GetUsb30HostEnableFlag"}, 270 {164, nullptr, "GetUsb30HostEnableFlag"},
@@ -302,6 +306,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
302 {200, nullptr, "SetButtonConfigRegisteredSettings"}, 306 {200, nullptr, "SetButtonConfigRegisteredSettings"},
303 {201, nullptr, "GetFieldTestingFlag"}, 307 {201, nullptr, "GetFieldTestingFlag"},
304 {202, nullptr, "SetFieldTestingFlag"}, 308 {202, nullptr, "SetFieldTestingFlag"},
309 {203, nullptr, "GetPanelCrcMode"},
310 {204, nullptr, "SetPanelCrcMode"},
305 }; 311 };
306 // clang-format on 312 // clang-format on
307 313
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 2b91a89d1..94608d529 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -190,10 +190,11 @@ SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_)
190 : ServiceFramework{system_, "sm:", 4}, 190 : ServiceFramework{system_, "sm:", 4},
191 service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { 191 service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
192 static const FunctionInfo functions[] = { 192 static const FunctionInfo functions[] = {
193 {0x00000000, &SM::Initialize, "Initialize"}, 193 {0, &SM::Initialize, "Initialize"},
194 {0x00000001, &SM::GetService, "GetService"}, 194 {1, &SM::GetService, "GetService"},
195 {0x00000002, &SM::RegisterService, "RegisterService"}, 195 {2, &SM::RegisterService, "RegisterService"},
196 {0x00000003, &SM::UnregisterService, "UnregisterService"}, 196 {3, &SM::UnregisterService, "UnregisterService"},
197 {4, nullptr, "DetachClient"},
197 }; 198 };
198 RegisterHandlers(functions); 199 RegisterHandlers(functions);
199} 200}
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp
index 05681ca2d..899a64c2f 100644
--- a/src/core/hle/service/sockets/ethc.cpp
+++ b/src/core/hle/service/sockets/ethc.cpp
@@ -15,6 +15,7 @@ ETHC_C::ETHC_C(Core::System& system_) : ServiceFramework{system_, "ethc:c"} {
15 {3, nullptr, "GetMediaList"}, 15 {3, nullptr, "GetMediaList"},
16 {4, nullptr, "SetMediaType"}, 16 {4, nullptr, "SetMediaType"},
17 {5, nullptr, "GetMediaType"}, 17 {5, nullptr, "GetMediaType"},
18 {6, nullptr, "Unknown6"},
18 }; 19 };
19 // clang-format on 20 // clang-format on
20 21
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index 51c3739bb..1159debc5 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -9,6 +9,7 @@ namespace Service::Sockets {
9NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { 9NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {5, nullptr, "GetSettingUrl"},
12 {10, nullptr, "GetSettingName"}, 13 {10, nullptr, "GetSettingName"},
13 {11, nullptr, "GetEnvironmentIdentifier"}, 14 {11, nullptr, "GetEnvironmentIdentifier"},
14 {12, nullptr, "GetDeviceId"}, 15 {12, nullptr, "GetDeviceId"},
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 3a6329f56..5c71f423c 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -9,8 +9,8 @@ namespace Service::Sockets {
9 9
10SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} { 10SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "SetDnsAddressesPrivate"}, 12 {0, nullptr, "SetDnsAddressesPrivateRequest"},
13 {1, nullptr, "GetDnsAddressPrivate"}, 13 {1, nullptr, "GetDnsAddressPrivateRequest"},
14 {2, nullptr, "GetHostByNameRequest"}, 14 {2, nullptr, "GetHostByNameRequest"},
15 {3, nullptr, "GetHostByAddrRequest"}, 15 {3, nullptr, "GetHostByAddrRequest"},
16 {4, nullptr, "GetHostStringErrorRequest"}, 16 {4, nullptr, "GetHostStringErrorRequest"},
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp
index 4e212610f..fff3f3c42 100644
--- a/src/core/hle/service/spl/spl.cpp
+++ b/src/core/hle/service/spl/spl.cpp
@@ -60,6 +60,8 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
60 {4, nullptr, "GenerateAesKey"}, 60 {4, nullptr, "GenerateAesKey"},
61 {5, nullptr, "SetConfig"}, 61 {5, nullptr, "SetConfig"},
62 {7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, 62 {7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
63 {9, nullptr, "ImportLotusKey"},
64 {10, nullptr, "DecryptLotusMessage"},
63 {11, nullptr, "IsDevelopment"}, 65 {11, nullptr, "IsDevelopment"},
64 {12, nullptr, "GenerateSpecificAesKey"}, 66 {12, nullptr, "GenerateSpecificAesKey"},
65 {14, nullptr, "DecryptAesKey"}, 67 {14, nullptr, "DecryptAesKey"},
@@ -123,6 +125,7 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
123 {14, nullptr, "DecryptAesKey"}, 125 {14, nullptr, "DecryptAesKey"},
124 {15, nullptr, "CryptAesCtr"}, 126 {15, nullptr, "CryptAesCtr"},
125 {16, nullptr, "ComputeCmac"}, 127 {16, nullptr, "ComputeCmac"},
128 {17, nullptr, "ImportEsKey"},
126 {18, nullptr, "UnwrapTitleKey"}, 129 {18, nullptr, "UnwrapTitleKey"},
127 {20, nullptr, "PrepareEsCommonKey"}, 130 {20, nullptr, "PrepareEsCommonKey"},
128 {21, nullptr, "AllocateAesKeyslot"}, 131 {21, nullptr, "AllocateAesKeyslot"},
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index 25cecbc83..3117627cf 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -20,6 +20,7 @@ ITimeZoneService ::ITimeZoneService(Core::System& system_,
20 {3, nullptr, "LoadLocationNameList"}, 20 {3, nullptr, "LoadLocationNameList"},
21 {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, 21 {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
22 {5, nullptr, "GetTimeZoneRuleVersion"}, 22 {5, nullptr, "GetTimeZoneRuleVersion"},
23 {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
23 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, 24 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
24 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, 25 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
25 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, 26 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index 579de83e4..b3b230a8c 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -69,15 +69,15 @@ public:
69 : ServiceFramework{system_, "IClientEpSession"} { 69 : ServiceFramework{system_, "IClientEpSession"} {
70 // clang-format off 70 // clang-format off
71 static const FunctionInfo functions[] = { 71 static const FunctionInfo functions[] = {
72 {0, nullptr, "Open"}, 72 {0, nullptr, "ReOpen"},
73 {1, nullptr, "Close"}, 73 {1, nullptr, "Close"},
74 {2, nullptr, "Unknown2"}, 74 {2, nullptr, "GetCompletionEvent"},
75 {3, nullptr, "Populate"}, 75 {3, nullptr, "PopulateRing"},
76 {4, nullptr, "PostBufferAsync"}, 76 {4, nullptr, "PostBufferAsync"},
77 {5, nullptr, "GetXferReport"}, 77 {5, nullptr, "GetXferReport"},
78 {6, nullptr, "PostBufferMultiAsync"}, 78 {6, nullptr, "PostBufferMultiAsync"},
79 {7, nullptr, "Unknown7"}, 79 {7, nullptr, "CreateSmmuSpace"},
80 {8, nullptr, "Unknown8"}, 80 {8, nullptr, "ShareReportRing"},
81 }; 81 };
82 // clang-format on 82 // clang-format on
83 83
@@ -91,7 +91,7 @@ public:
91 : ServiceFramework{system_, "IClientIfSession"} { 91 : ServiceFramework{system_, "IClientIfSession"} {
92 // clang-format off 92 // clang-format off
93 static const FunctionInfo functions[] = { 93 static const FunctionInfo functions[] = {
94 {0, nullptr, "Unknown0"}, 94 {0, nullptr, "GetStateChangeEvent"},
95 {1, nullptr, "SetInterface"}, 95 {1, nullptr, "SetInterface"},
96 {2, nullptr, "GetInterface"}, 96 {2, nullptr, "GetInterface"},
97 {3, nullptr, "GetAlternateInterface"}, 97 {3, nullptr, "GetAlternateInterface"},
@@ -176,15 +176,15 @@ public:
176 : ServiceFramework{system_, "IPdCradleSession"} { 176 : ServiceFramework{system_, "IPdCradleSession"} {
177 // clang-format off 177 // clang-format off
178 static const FunctionInfo functions[] = { 178 static const FunctionInfo functions[] = {
179 {0, nullptr, "VdmUserWrite"}, 179 {0, nullptr, "SetCradleVdo"},
180 {1, nullptr, "VdmUserRead"}, 180 {1, nullptr, "GetCradleVdo"},
181 {2, nullptr, "Vdm20Init"}, 181 {2, nullptr, "ResetCradleUsbHub"},
182 {3, nullptr, "GetFwType"}, 182 {3, nullptr, "GetHostPdcFirmwareType"},
183 {4, nullptr, "GetFwRevision"}, 183 {4, nullptr, "GetHostPdcFirmwareRevision"},
184 {5, nullptr, "GetManufacturerId"}, 184 {5, nullptr, "GetHostPdcManufactureId"},
185 {6, nullptr, "GetDeviceId"}, 185 {6, nullptr, "GetHostPdcDeviceId"},
186 {7, nullptr, "Unknown7"}, 186 {7, nullptr, "AwakeCradle"},
187 {8, nullptr, "Unknown8"}, 187 {8, nullptr, "SleepCradle"},
188 }; 188 };
189 // clang-format on 189 // clang-format on
190 190
@@ -219,12 +219,12 @@ public:
219 explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} { 219 explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} {
220 // clang-format off 220 // clang-format off
221 static const FunctionInfo functions[] = { 221 static const FunctionInfo functions[] = {
222 {0, nullptr, "Unknown0"}, 222 {0, nullptr, "GetPowerEvent"},
223 {1, nullptr, "Unknown1"}, 223 {1, nullptr, "GetPowerState"},
224 {2, nullptr, "Unknown2"}, 224 {2, nullptr, "GetDataEvent"},
225 {3, nullptr, "Unknown3"}, 225 {3, nullptr, "GetDataRole"},
226 {4, nullptr, "Unknown4"}, 226 {4, nullptr, "SetDiagData"},
227 {5, nullptr, "Unknown5"}, 227 {5, nullptr, "GetDiagData"},
228 }; 228 };
229 // clang-format on 229 // clang-format on
230 230
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 7423287ea..a1a7ac987 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -695,6 +695,7 @@ public:
695 {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"}, 695 {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
696 {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"}, 696 {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
697 {2209, nullptr, "SetLayerAlpha"}, 697 {2209, nullptr, "SetLayerAlpha"},
698 {2210, nullptr, "SetLayerPositionAndSize"},
698 {2312, nullptr, "CreateStrayLayer"}, 699 {2312, nullptr, "CreateStrayLayer"},
699 {2400, nullptr, "OpenIndirectLayer"}, 700 {2400, nullptr, "OpenIndirectLayer"},
700 {2401, nullptr, "CloseIndirectLayer"}, 701 {2401, nullptr, "CloseIndirectLayer"},
@@ -718,6 +719,7 @@ public:
718 {3215, nullptr, "SetDisplayGamma"}, 719 {3215, nullptr, "SetDisplayGamma"},
719 {3216, nullptr, "GetDisplayCmuLuma"}, 720 {3216, nullptr, "GetDisplayCmuLuma"},
720 {3217, nullptr, "SetDisplayCmuLuma"}, 721 {3217, nullptr, "SetDisplayCmuLuma"},
722 {3218, nullptr, "SetDisplayCrcMode"},
721 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"}, 723 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
722 {8225, nullptr, "GetSharedBufferMemoryHandleId"}, 724 {8225, nullptr, "GetSharedBufferMemoryHandleId"},
723 {8250, nullptr, "OpenSharedLayer"}, 725 {8250, nullptr, "OpenSharedLayer"},
@@ -729,6 +731,7 @@ public:
729 {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"}, 731 {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
730 {8257, nullptr, "FillSharedFrameBufferColor"}, 732 {8257, nullptr, "FillSharedFrameBufferColor"},
731 {8258, nullptr, "CancelSharedFrameBuffer"}, 733 {8258, nullptr, "CancelSharedFrameBuffer"},
734 {9000, nullptr, "GetDp2hdmiController"},
732 }; 735 };
733 RegisterHandlers(functions); 736 RegisterHandlers(functions);
734 } 737 }
@@ -808,10 +811,15 @@ public:
808 {2402, nullptr, "GetDisplayHotplugState"}, 811 {2402, nullptr, "GetDisplayHotplugState"},
809 {2501, nullptr, "GetCompositorErrorInfo"}, 812 {2501, nullptr, "GetCompositorErrorInfo"},
810 {2601, nullptr, "GetDisplayErrorEvent"}, 813 {2601, nullptr, "GetDisplayErrorEvent"},
814 {2701, nullptr, "GetDisplayFatalErrorEvent"},
811 {4201, nullptr, "SetDisplayAlpha"}, 815 {4201, nullptr, "SetDisplayAlpha"},
812 {4203, nullptr, "SetDisplayLayerStack"}, 816 {4203, nullptr, "SetDisplayLayerStack"},
813 {4205, nullptr, "SetDisplayPowerState"}, 817 {4205, nullptr, "SetDisplayPowerState"},
814 {4206, nullptr, "SetDefaultDisplay"}, 818 {4206, nullptr, "SetDefaultDisplay"},
819 {4207, nullptr, "ResetDisplayPanel"},
820 {4208, nullptr, "SetDisplayFatalErrorEnabled"},
821 {4209, nullptr, "IsDisplayPanelOn"},
822 {4300, nullptr, "GetInternalPanelId"},
815 {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"}, 823 {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
816 {6001, nullptr, "RemoveFromLayerStack"}, 824 {6001, nullptr, "RemoveFromLayerStack"},
817 {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"}, 825 {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"},
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
index ddbf04069..44957e01d 100644
--- a/src/core/hle/service/wlan/wlan.cpp
+++ b/src/core/hle/service/wlan/wlan.cpp
@@ -46,6 +46,13 @@ public:
46 {28, nullptr, "Unknown28"}, 46 {28, nullptr, "Unknown28"},
47 {29, nullptr, "Unknown29"}, 47 {29, nullptr, "Unknown29"},
48 {30, nullptr, "Unknown30"}, 48 {30, nullptr, "Unknown30"},
49 {31, nullptr, "Unknown31"},
50 {32, nullptr, "Unknown32"},
51 {33, nullptr, "Unknown33"},
52 {34, nullptr, "Unknown34"},
53 {35, nullptr, "Unknown35"},
54 {36, nullptr, "Unknown36"},
55 {37, nullptr, "Unknown37"},
49 }; 56 };
50 // clang-format on 57 // clang-format on
51 58
diff --git a/src/core/settings.h b/src/core/settings.h
index d849dded3..a81016b23 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -222,6 +222,7 @@ struct Values {
222 bool quest_flag; 222 bool quest_flag;
223 bool disable_macro_jit; 223 bool disable_macro_jit;
224 bool extended_logging; 224 bool extended_logging;
225 bool use_auto_stub;
225 226
226 // Miscellaneous 227 // Miscellaneous
227 std::string log_filter; 228 std::string log_filter;
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index df73f9ff7..e72df924b 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -27,11 +27,9 @@ class Socket {
27public: 27public:
28 using clock = std::chrono::system_clock; 28 using clock = std::chrono::system_clock;
29 29
30 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, 30 explicit Socket(const std::string& host, u16 port, SocketCallback callback_)
31 SocketCallback callback_)
32 : callback(std::move(callback_)), timer(io_service), 31 : callback(std::move(callback_)), timer(io_service),
33 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), 32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) {
34 pad_index(pad_index_) {
35 boost::system::error_code ec{}; 33 boost::system::error_code ec{};
36 auto ipv4 = boost::asio::ip::make_address_v4(host, ec); 34 auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
37 if (ec.value() != boost::system::errc::success) { 35 if (ec.value() != boost::system::errc::success) {
@@ -99,15 +97,15 @@ private:
99 void HandleSend(const boost::system::error_code&) { 97 void HandleSend(const boost::system::error_code&) {
100 boost::system::error_code _ignored{}; 98 boost::system::error_code _ignored{};
101 // Send a request for getting port info for the pad 99 // Send a request for getting port info for the pad
102 const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}}; 100 const Request::PortInfo port_info{4, {0, 1, 2, 3}};
103 const auto port_message = Request::Create(port_info, client_id); 101 const auto port_message = Request::Create(port_info, client_id);
104 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); 102 std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
105 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); 103 socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
106 104
107 // Send a request for getting pad data for the pad 105 // Send a request for getting pad data for the pad
108 const Request::PadData pad_data{ 106 const Request::PadData pad_data{
109 Request::PadData::Flags::Id, 107 Request::PadData::Flags::AllPorts,
110 static_cast<u8>(pad_index), 108 0,
111 EMPTY_MAC_ADDRESS, 109 EMPTY_MAC_ADDRESS,
112 }; 110 };
113 const auto pad_message = Request::Create(pad_data, client_id); 111 const auto pad_message = Request::Create(pad_data, client_id);
@@ -122,7 +120,6 @@ private:
122 udp::socket socket; 120 udp::socket socket;
123 121
124 const u32 client_id; 122 const u32 client_id;
125 std::size_t pad_index{};
126 123
127 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); 124 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
128 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); 125 static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -150,34 +147,32 @@ Client::~Client() {
150 Reset(); 147 Reset();
151} 148}
152 149
153Client::ClientData::ClientData() = default; 150Client::ClientConnection::ClientConnection() = default;
154 151
155Client::ClientData::~ClientData() = default; 152Client::ClientConnection::~ClientConnection() = default;
156 153
157std::vector<Common::ParamPackage> Client::GetInputDevices() const { 154std::vector<Common::ParamPackage> Client::GetInputDevices() const {
158 std::vector<Common::ParamPackage> devices; 155 std::vector<Common::ParamPackage> devices;
159 for (std::size_t client = 0; client < clients.size(); client++) { 156 for (std::size_t pad = 0; pad < pads.size(); pad++) {
160 if (!DeviceConnected(client)) { 157 if (!DeviceConnected(pad)) {
161 continue; 158 continue;
162 } 159 }
163 std::string name = fmt::format("UDP Controller {}", client); 160 std::string name = fmt::format("UDP Controller {}", pad);
164 devices.emplace_back(Common::ParamPackage{ 161 devices.emplace_back(Common::ParamPackage{
165 {"class", "cemuhookudp"}, 162 {"class", "cemuhookudp"},
166 {"display", std::move(name)}, 163 {"display", std::move(name)},
167 {"port", std::to_string(client)}, 164 {"port", std::to_string(pad)},
168 }); 165 });
169 } 166 }
170 return devices; 167 return devices;
171} 168}
172 169
173bool Client::DeviceConnected(std::size_t client) const { 170bool Client::DeviceConnected(std::size_t pad) const {
174 // Use last timestamp to detect if the socket has stopped sending data 171 // Use last timestamp to detect if the socket has stopped sending data
175 const auto now = std::chrono::steady_clock::now(); 172 const auto now = std::chrono::steady_clock::now();
176 const auto time_difference = 173 const auto time_difference = static_cast<u64>(
177 static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>( 174 std::chrono::duration_cast<std::chrono::milliseconds>(now - pads[pad].last_update).count());
178 now - clients[client].last_motion_update) 175 return time_difference < 1000 && pads[pad].connected;
179 .count());
180 return time_difference < 1000 && clients[client].active == 1;
181} 176}
182 177
183void Client::ReloadSockets() { 178void Client::ReloadSockets() {
@@ -202,25 +197,21 @@ void Client::ReloadSockets() {
202 continue; 197 continue;
203 } 198 }
204 199
205 for (std::size_t pad = 0; pad < 4; ++pad) { 200 const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port);
206 const std::size_t client_number = 201 if (client_number != MAX_UDP_CLIENTS) {
207 GetClientNumber(udp_input_address, udp_input_port, pad); 202 LOG_ERROR(Input, "Duplicated UDP servers found");
208 if (client_number != MAX_UDP_CLIENTS) { 203 continue;
209 LOG_ERROR(Input, "Duplicated UDP servers found");
210 continue;
211 }
212 StartCommunication(client++, udp_input_address, udp_input_port, pad);
213 } 204 }
205 StartCommunication(client++, udp_input_address, udp_input_port);
214 } 206 }
215} 207}
216 208
217std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const { 209std::size_t Client::GetClientNumber(std::string_view host, u16 port) const {
218 for (std::size_t client = 0; client < clients.size(); client++) { 210 for (std::size_t client = 0; client < clients.size(); client++) {
219 if (clients[client].active == -1) { 211 if (clients[client].active == -1) {
220 continue; 212 continue;
221 } 213 }
222 if (clients[client].host == host && clients[client].port == port && 214 if (clients[client].host == host && clients[client].port == port) {
223 clients[client].pad_index == pad) {
224 return client; 215 return client;
225 } 216 }
226 } 217 }
@@ -236,69 +227,75 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {
236} 227}
237 228
238void Client::OnPadData(Response::PadData data, std::size_t client) { 229void Client::OnPadData(Response::PadData data, std::size_t client) {
239 // Accept packets only for the correct pad 230 const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id;
240 if (static_cast<u8>(clients[client].pad_index) != data.info.id) { 231
232 if (pad_index >= pads.size()) {
233 LOG_ERROR(Input, "Invalid pad id {}", data.info.id);
241 return; 234 return;
242 } 235 }
243 236
244 LOG_TRACE(Input, "PadData packet received"); 237 LOG_TRACE(Input, "PadData packet received");
245 if (data.packet_counter == clients[client].packet_sequence) { 238 if (data.packet_counter == pads[pad_index].packet_sequence) {
246 LOG_WARNING( 239 LOG_WARNING(
247 Input, 240 Input,
248 "PadData packet dropped because its stale info. Current count: {} Packet count: {}", 241 "PadData packet dropped because its stale info. Current count: {} Packet count: {}",
249 clients[client].packet_sequence, data.packet_counter); 242 pads[pad_index].packet_sequence, data.packet_counter);
243 pads[pad_index].connected = false;
250 return; 244 return;
251 } 245 }
252 clients[client].active = static_cast<s8>(data.info.is_pad_active); 246
253 clients[client].packet_sequence = data.packet_counter; 247 clients[client].active = 1;
248 pads[pad_index].connected = true;
249 pads[pad_index].packet_sequence = data.packet_counter;
250
254 const auto now = std::chrono::steady_clock::now(); 251 const auto now = std::chrono::steady_clock::now();
255 const auto time_difference = 252 const auto time_difference = static_cast<u64>(
256 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( 253 std::chrono::duration_cast<std::chrono::microseconds>(now - pads[pad_index].last_update)
257 now - clients[client].last_motion_update) 254 .count());
258 .count()); 255 pads[pad_index].last_update = now;
259 clients[client].last_motion_update = now; 256
260 const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; 257 const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
261 clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); 258 pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
262 // Gyroscope values are not it the correct scale from better joy. 259 // Gyroscope values are not it the correct scale from better joy.
263 // Dividing by 312 allows us to make one full turn = 1 turn 260 // Dividing by 312 allows us to make one full turn = 1 turn
264 // This must be a configurable valued called sensitivity 261 // This must be a configurable valued called sensitivity
265 clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f); 262 pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f);
266 clients[client].motion.UpdateRotation(time_difference); 263 pads[pad_index].motion.UpdateRotation(time_difference);
267 clients[client].motion.UpdateOrientation(time_difference); 264 pads[pad_index].motion.UpdateOrientation(time_difference);
268 265
269 { 266 {
270 std::lock_guard guard(clients[client].status.update_mutex); 267 std::lock_guard guard(pads[pad_index].status.update_mutex);
271 clients[client].status.motion_status = clients[client].motion.GetMotion(); 268 pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion();
272 269
273 for (std::size_t id = 0; id < data.touch.size(); ++id) { 270 for (std::size_t id = 0; id < data.touch.size(); ++id) {
274 UpdateTouchInput(data.touch[id], client, id); 271 UpdateTouchInput(data.touch[id], client, id);
275 } 272 }
276 273
277 if (configuring) { 274 if (configuring) {
278 const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); 275 const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope();
279 const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); 276 const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration();
280 UpdateYuzuSettings(client, accelerometer, gyroscope); 277 UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope);
281 } 278 }
282 } 279 }
283} 280}
284 281
285void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, 282void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) {
286 std::size_t pad_index) {
287 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 283 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
288 [this](Response::PortInfo info) { OnPortInfo(info); }, 284 [this](Response::PortInfo info) { OnPortInfo(info); },
289 [this, client](Response::PadData data) { OnPadData(data, client); }}; 285 [this, client](Response::PadData data) { OnPadData(data, client); }};
290 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port, 286 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
291 pad_index);
292 clients[client].host = host; 287 clients[client].host = host;
293 clients[client].port = port; 288 clients[client].port = port;
294 clients[client].pad_index = pad_index;
295 clients[client].active = 0; 289 clients[client].active = 0;
296 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback); 290 clients[client].socket = std::make_unique<Socket>(host, port, callback);
297 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; 291 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
292
298 // Set motion parameters 293 // Set motion parameters
299 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode 294 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
300 // Real HW values are unknown, 0.0001 is an approximate to Standard 295 // Real HW values are unknown, 0.0001 is an approximate to Standard
301 clients[client].motion.SetGyroThreshold(0.0001f); 296 for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) {
297 pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f);
298 }
302} 299}
303 300
304void Client::Reset() { 301void Client::Reset() {
@@ -311,8 +308,8 @@ void Client::Reset() {
311 } 308 }
312} 309}
313 310
314void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 311void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
315 const Common::Vec3<float>& gyro) { 312 const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro) {
316 if (gyro.Length() > 0.2f) { 313 if (gyro.Length() > 0.2f) {
317 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, 314 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client,
318 gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); 315 gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]);
@@ -320,7 +317,7 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a
320 UDPPadStatus pad{ 317 UDPPadStatus pad{
321 .host = clients[client].host, 318 .host = clients[client].host,
322 .port = clients[client].port, 319 .port = clients[client].port,
323 .pad_index = clients[client].pad_index, 320 .pad_index = pad_index,
324 }; 321 };
325 for (std::size_t i = 0; i < 3; ++i) { 322 for (std::size_t i = 0; i < 3; ++i) {
326 if (gyro[i] > 5.0f || gyro[i] < -5.0f) { 323 if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
@@ -391,19 +388,19 @@ void Client::EndConfiguration() {
391} 388}
392 389
393DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { 390DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
394 const std::size_t client_number = GetClientNumber(host, port, pad); 391 const std::size_t client_number = GetClientNumber(host, port);
395 if (client_number == MAX_UDP_CLIENTS) { 392 if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
396 return clients[0].status; 393 return pads[0].status;
397 } 394 }
398 return clients[client_number].status; 395 return pads[(client_number * PADS_PER_CLIENT) + pad].status;
399} 396}
400 397
401const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { 398const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
402 const std::size_t client_number = GetClientNumber(host, port, pad); 399 const std::size_t client_number = GetClientNumber(host, port);
403 if (client_number == MAX_UDP_CLIENTS) { 400 if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
404 return clients[0].status; 401 return pads[0].status;
405 } 402 }
406 return clients[client_number].status; 403 return pads[(client_number * PADS_PER_CLIENT) + pad].status;
407} 404}
408 405
409Input::TouchStatus& Client::GetTouchState() { 406Input::TouchStatus& Client::GetTouchState() {
@@ -422,7 +419,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
422 return pad_queue; 419 return pad_queue;
423} 420}
424 421
425void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, 422void TestCommunication(const std::string& host, u16 port,
426 const std::function<void()>& success_callback, 423 const std::function<void()>& success_callback,
427 const std::function<void()>& failure_callback) { 424 const std::function<void()>& failure_callback) {
428 std::thread([=] { 425 std::thread([=] {
@@ -432,9 +429,10 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
432 .port_info = [](Response::PortInfo) {}, 429 .port_info = [](Response::PortInfo) {},
433 .pad_data = [&](Response::PadData) { success_event.Set(); }, 430 .pad_data = [&](Response::PadData) { success_event.Set(); },
434 }; 431 };
435 Socket socket{host, port, pad_index, std::move(callback)}; 432 Socket socket{host, port, std::move(callback)};
436 std::thread worker_thread{SocketLoop, &socket}; 433 std::thread worker_thread{SocketLoop, &socket};
437 const bool result = success_event.WaitFor(std::chrono::seconds(5)); 434 const bool result =
435 success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10));
438 socket.Stop(); 436 socket.Stop();
439 worker_thread.join(); 437 worker_thread.join();
440 if (result) { 438 if (result) {
@@ -446,8 +444,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
446} 444}
447 445
448CalibrationConfigurationJob::CalibrationConfigurationJob( 446CalibrationConfigurationJob::CalibrationConfigurationJob(
449 const std::string& host, u16 port, std::size_t pad_index, 447 const std::string& host, u16 port, std::function<void(Status)> status_callback,
450 std::function<void(Status)> status_callback,
451 std::function<void(u16, u16, u16, u16)> data_callback) { 448 std::function<void(u16, u16, u16, u16)> data_callback) {
452 449
453 std::thread([=, this] { 450 std::thread([=, this] {
@@ -491,7 +488,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
491 complete_event.Set(); 488 complete_event.Set();
492 } 489 }
493 }}; 490 }};
494 Socket socket{host, port, pad_index, std::move(callback)}; 491 Socket socket{host, port, std::move(callback)};
495 std::thread worker_thread{SocketLoop, &socket}; 492 std::thread worker_thread{SocketLoop, &socket};
496 complete_event.Wait(); 493 complete_event.Wait();
497 socket.Stop(); 494 socket.Stop();
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index e9e438e88..a11ea3068 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -84,7 +84,7 @@ public:
84 84
85 std::vector<Common::ParamPackage> GetInputDevices() const; 85 std::vector<Common::ParamPackage> GetInputDevices() const;
86 86
87 bool DeviceConnected(std::size_t client) const; 87 bool DeviceConnected(std::size_t pad) const;
88 void ReloadSockets(); 88 void ReloadSockets();
89 89
90 Common::SPSCQueue<UDPPadStatus>& GetPadQueue(); 90 Common::SPSCQueue<UDPPadStatus>& GetPadQueue();
@@ -97,38 +97,40 @@ public:
97 const Input::TouchStatus& GetTouchState() const; 97 const Input::TouchStatus& GetTouchState() const;
98 98
99private: 99private:
100 struct ClientData { 100 struct PadData {
101 ClientData();
102 ~ClientData();
103
104 std::string host{"127.0.0.1"};
105 u16 port{26760};
106 std::size_t pad_index{}; 101 std::size_t pad_index{};
107 std::unique_ptr<Socket> socket; 102 bool connected{};
108 DeviceStatus status; 103 DeviceStatus status;
109 std::thread thread;
110 u64 packet_sequence{}; 104 u64 packet_sequence{};
111 s8 active{-1};
112 105
113 // Realtime values 106 // Realtime values
114 // motion is initalized with PID values for drift correction on joycons 107 // motion is initalized with PID values for drift correction on joycons
115 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; 108 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
116 std::chrono::time_point<std::chrono::steady_clock> last_motion_update; 109 std::chrono::time_point<std::chrono::steady_clock> last_update;
110 };
111
112 struct ClientConnection {
113 ClientConnection();
114 ~ClientConnection();
115 std::string host{"127.0.0.1"};
116 u16 port{26760};
117 s8 active{-1};
118 std::unique_ptr<Socket> socket;
119 std::thread thread;
117 }; 120 };
118 121
119 // For shutting down, clear all data, join all threads, release usb 122 // For shutting down, clear all data, join all threads, release usb
120 void Reset(); 123 void Reset();
121 124
122 // Translates configuration to client number 125 // Translates configuration to client number
123 std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const; 126 std::size_t GetClientNumber(std::string_view host, u16 port) const;
124 127
125 void OnVersion(Response::Version); 128 void OnVersion(Response::Version);
126 void OnPortInfo(Response::PortInfo); 129 void OnPortInfo(Response::PortInfo);
127 void OnPadData(Response::PadData, std::size_t client); 130 void OnPadData(Response::PadData, std::size_t client);
128 void StartCommunication(std::size_t client, const std::string& host, u16 port, 131 void StartCommunication(std::size_t client, const std::string& host, u16 port);
129 std::size_t pad_index); 132 void UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
130 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 133 const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro);
131 const Common::Vec3<float>& gyro);
132 134
133 // Returns an unused finger id, if there is no fingers available std::nullopt will be 135 // Returns an unused finger id, if there is no fingers available std::nullopt will be
134 // returned 136 // returned
@@ -140,10 +142,12 @@ private:
140 bool configuring = false; 142 bool configuring = false;
141 143
142 // Allocate clients for 8 udp servers 144 // Allocate clients for 8 udp servers
143 static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8; 145 static constexpr std::size_t MAX_UDP_CLIENTS = 8;
146 static constexpr std::size_t PADS_PER_CLIENT = 4;
144 // Each client can have up 2 touch inputs 147 // Each client can have up 2 touch inputs
145 static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; 148 static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2;
146 std::array<ClientData, MAX_UDP_CLIENTS> clients{}; 149 std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{};
150 std::array<ClientConnection, MAX_UDP_CLIENTS> clients{};
147 Common::SPSCQueue<UDPPadStatus> pad_queue{}; 151 Common::SPSCQueue<UDPPadStatus> pad_queue{};
148 Input::TouchStatus touch_status{}; 152 Input::TouchStatus touch_status{};
149 std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{}; 153 std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{};
@@ -164,7 +168,7 @@ public:
164 * @param status_callback Callback for job status updates 168 * @param status_callback Callback for job status updates
165 * @param data_callback Called when calibration data is ready 169 * @param data_callback Called when calibration data is ready
166 */ 170 */
167 explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, 171 explicit CalibrationConfigurationJob(const std::string& host, u16 port,
168 std::function<void(Status)> status_callback, 172 std::function<void(Status)> status_callback,
169 std::function<void(u16, u16, u16, u16)> data_callback); 173 std::function<void(u16, u16, u16, u16)> data_callback);
170 ~CalibrationConfigurationJob(); 174 ~CalibrationConfigurationJob();
@@ -174,7 +178,7 @@ private:
174 Common::Event complete_event; 178 Common::Event complete_event;
175}; 179};
176 180
177void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, 181void TestCommunication(const std::string& host, u16 port,
178 const std::function<void()>& success_callback, 182 const std::function<void()>& success_callback,
179 const std::function<void()>& failure_callback); 183 const std::function<void()>& failure_callback);
180 184
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 9b931976a..47190c464 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -236,7 +236,6 @@ add_library(video_core STATIC
236 texture_cache/types.h 236 texture_cache/types.h
237 texture_cache/util.cpp 237 texture_cache/util.cpp
238 texture_cache/util.h 238 texture_cache/util.h
239 textures/astc.cpp
240 textures/astc.h 239 textures/astc.h
241 textures/decoders.cpp 240 textures/decoders.cpp
242 textures/decoders.h 241 textures/decoders.h
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index 59e586695..29bb31418 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -2,8 +2,9 @@
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 <cstring> // for std::memcpy 5#include <algorithm> // for std::copy
6#include <numeric> 6#include <numeric>
7#include "common/assert.h"
7#include "video_core/command_classes/codecs/vp9.h" 8#include "video_core/command_classes/codecs/vp9.h"
8#include "video_core/gpu.h" 9#include "video_core/gpu.h"
9#include "video_core/memory_manager.h" 10#include "video_core/memory_manager.h"
@@ -362,7 +363,8 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state)
362 // surface_luma_offset[0:3] contains the address of the reference frame offsets in the following 363 // surface_luma_offset[0:3] contains the address of the reference frame offsets in the following
363 // order: last, golden, altref, current. It may be worthwhile to track the updates done here 364 // order: last, golden, altref, current. It may be worthwhile to track the updates done here
364 // to avoid buffering frame data needed for reference frame updating in the header composition. 365 // to avoid buffering frame data needed for reference frame updating in the header composition.
365 std::memcpy(vp9_info.frame_offsets.data(), state.surface_luma_offset.data(), 4 * sizeof(u64)); 366 std::copy(state.surface_luma_offset.begin(), state.surface_luma_offset.begin() + 4,
367 vp9_info.frame_offsets.begin());
366 368
367 return vp9_info; 369 return vp9_info;
368} 370}
@@ -821,11 +823,11 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
821 823
822 // Write headers and frame to buffer 824 // Write headers and frame to buffer
823 frame.resize(uncompressed_header.size() + compressed_header.size() + bitstream.size()); 825 frame.resize(uncompressed_header.size() + compressed_header.size() + bitstream.size());
824 std::memcpy(frame.data(), uncompressed_header.data(), uncompressed_header.size()); 826 std::copy(uncompressed_header.begin(), uncompressed_header.end(), frame.begin());
825 std::memcpy(frame.data() + uncompressed_header.size(), compressed_header.data(), 827 std::copy(compressed_header.begin(), compressed_header.end(),
826 compressed_header.size()); 828 frame.begin() + uncompressed_header.size());
827 std::memcpy(frame.data() + uncompressed_header.size() + compressed_header.size(), 829 std::copy(bitstream.begin(), bitstream.end(),
828 bitstream.data(), bitstream.size()); 830 frame.begin() + uncompressed_header.size() + compressed_header.size());
829 831
830 // keep track of frame number 832 // keep track of frame number
831 current_frame_number++; 833 current_frame_number++;
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index c61f44619..009c6f574 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -517,8 +517,8 @@ void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
517 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value); 517 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
518} 518}
519 519
520void GPU::WaitIdle() const { 520void GPU::ShutDown() {
521 gpu_thread.WaitIdle(); 521 gpu_thread.ShutDown();
522} 522}
523 523
524void GPU::OnCommandListEnd() { 524void GPU::OnCommandListEnd() {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index b2ee45496..ecab35d3b 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -219,8 +219,8 @@ public:
219 return *shader_notify; 219 return *shader_notify;
220 } 220 }
221 221
222 // Waits for the GPU to finish working 222 // Stops the GPU execution and waits for the GPU to finish working
223 void WaitIdle() const; 223 void ShutDown();
224 224
225 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame. 225 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
226 void WaitFence(u32 syncpoint_id, u32 value); 226 void WaitFence(u32 syncpoint_id, u32 value);
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 99353f15f..7addfbc7b 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -29,8 +29,7 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
29 system.RegisterHostThread(); 29 system.RegisterHostThread();
30 30
31 // Wait for first GPU command before acquiring the window context 31 // Wait for first GPU command before acquiring the window context
32 while (state.queue.Empty()) 32 state.queue.Wait();
33 ;
34 33
35 // If emulation was stopped during disk shader loading, abort before trying to acquire context 34 // If emulation was stopped during disk shader loading, abort before trying to acquire context
36 if (!state.is_running) { 35 if (!state.is_running) {
@@ -57,11 +56,17 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
57 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) { 56 } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
58 rasterizer->OnCPUWrite(invalidate->addr, invalidate->size); 57 rasterizer->OnCPUWrite(invalidate->addr, invalidate->size);
59 } else if (std::holds_alternative<EndProcessingCommand>(next.data)) { 58 } else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
60 return; 59 ASSERT(state.is_running == false);
61 } else { 60 } else {
62 UNREACHABLE(); 61 UNREACHABLE();
63 } 62 }
64 state.signaled_fence.store(next.fence); 63 state.signaled_fence.store(next.fence);
64 if (next.block) {
65 // We have to lock the write_lock to ensure that the condition_variable wait not get a
66 // race between the check and the lock itself.
67 std::lock_guard lk(state.write_lock);
68 state.cv.notify_all();
69 }
65 } 70 }
66} 71}
67 72
@@ -69,13 +74,7 @@ ThreadManager::ThreadManager(Core::System& system_, bool is_async_)
69 : system{system_}, is_async{is_async_} {} 74 : system{system_}, is_async{is_async_} {}
70 75
71ThreadManager::~ThreadManager() { 76ThreadManager::~ThreadManager() {
72 if (!thread.joinable()) { 77 ShutDown();
73 return;
74 }
75
76 // Notify GPU thread that a shutdown is pending
77 PushCommand(EndProcessingCommand());
78 thread.join();
79} 78}
80 79
81void ThreadManager::StartThread(VideoCore::RendererBase& renderer, 80void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
@@ -112,9 +111,8 @@ void ThreadManager::FlushRegion(VAddr addr, u64 size) {
112 case Settings::GPUAccuracy::Extreme: { 111 case Settings::GPUAccuracy::Extreme: {
113 auto& gpu = system.GPU(); 112 auto& gpu = system.GPU();
114 u64 fence = gpu.RequestFlush(addr, size); 113 u64 fence = gpu.RequestFlush(addr, size);
115 PushCommand(GPUTickCommand()); 114 PushCommand(GPUTickCommand(), true);
116 while (fence > gpu.CurrentFlushRequestFence()) { 115 ASSERT(fence <= gpu.CurrentFlushRequestFence());
117 }
118 break; 116 break;
119 } 117 }
120 default: 118 default:
@@ -131,23 +129,45 @@ void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) {
131 rasterizer->OnCPUWrite(addr, size); 129 rasterizer->OnCPUWrite(addr, size);
132} 130}
133 131
134void ThreadManager::WaitIdle() const { 132void ThreadManager::ShutDown() {
135 while (state.last_fence > state.signaled_fence.load(std::memory_order_relaxed) && 133 if (!state.is_running) {
136 system.IsPoweredOn()) { 134 return;
137 } 135 }
136
137 {
138 std::lock_guard lk(state.write_lock);
139 state.is_running = false;
140 state.cv.notify_all();
141 }
142
143 if (!thread.joinable()) {
144 return;
145 }
146
147 // Notify GPU thread that a shutdown is pending
148 PushCommand(EndProcessingCommand());
149 thread.join();
138} 150}
139 151
140void ThreadManager::OnCommandListEnd() { 152void ThreadManager::OnCommandListEnd() {
141 PushCommand(OnCommandListEndCommand()); 153 PushCommand(OnCommandListEndCommand());
142} 154}
143 155
144u64 ThreadManager::PushCommand(CommandData&& command_data) { 156u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
145 const u64 fence{++state.last_fence};
146 state.queue.Push(CommandDataContainer(std::move(command_data), fence));
147
148 if (!is_async) { 157 if (!is_async) {
149 // In synchronous GPU mode, block the caller until the command has executed 158 // In synchronous GPU mode, block the caller until the command has executed
150 WaitIdle(); 159 block = true;
160 }
161
162 std::unique_lock lk(state.write_lock);
163 const u64 fence{++state.last_fence};
164 state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
165
166 if (block) {
167 state.cv.wait(lk, [this, fence] {
168 return fence <= state.signaled_fence.load(std::memory_order_relaxed) ||
169 !state.is_running;
170 });
151 } 171 }
152 172
153 return fence; 173 return fence;
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 18269e51c..11a648f38 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -90,21 +90,24 @@ using CommandData =
90struct CommandDataContainer { 90struct CommandDataContainer {
91 CommandDataContainer() = default; 91 CommandDataContainer() = default;
92 92
93 explicit CommandDataContainer(CommandData&& data_, u64 next_fence_) 93 explicit CommandDataContainer(CommandData&& data_, u64 next_fence_, bool block_)
94 : data{std::move(data_)}, fence{next_fence_} {} 94 : data{std::move(data_)}, fence{next_fence_}, block(block_) {}
95 95
96 CommandData data; 96 CommandData data;
97 u64 fence{}; 97 u64 fence{};
98 bool block{};
98}; 99};
99 100
100/// Struct used to synchronize the GPU thread 101/// Struct used to synchronize the GPU thread
101struct SynchState final { 102struct SynchState final {
102 std::atomic_bool is_running{true}; 103 std::atomic_bool is_running{true};
103 104
104 using CommandQueue = Common::MPSCQueue<CommandDataContainer>; 105 using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
106 std::mutex write_lock;
105 CommandQueue queue; 107 CommandQueue queue;
106 u64 last_fence{}; 108 u64 last_fence{};
107 std::atomic<u64> signaled_fence{}; 109 std::atomic<u64> signaled_fence{};
110 std::condition_variable cv;
108}; 111};
109 112
110/// Class used to manage the GPU thread 113/// Class used to manage the GPU thread
@@ -132,14 +135,14 @@ public:
132 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 135 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
133 void FlushAndInvalidateRegion(VAddr addr, u64 size); 136 void FlushAndInvalidateRegion(VAddr addr, u64 size);
134 137
135 // Wait until the gpu thread is idle. 138 // Stops the GPU execution and waits for the GPU to finish working
136 void WaitIdle() const; 139 void ShutDown();
137 140
138 void OnCommandListEnd(); 141 void OnCommandListEnd();
139 142
140private: 143private:
141 /// Pushes a command to be executed by the GPU thread 144 /// Pushes a command to be executed by the GPU thread
142 u64 PushCommand(CommandData&& command_data); 145 u64 PushCommand(CommandData&& command_data, bool block = false);
143 146
144 Core::System& system; 147 Core::System& system;
145 const bool is_async; 148 const bool is_async;
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index 3494318ca..2208e1922 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -1,4 +1,5 @@
1set(SHADER_FILES 1set(SHADER_FILES
2 astc_decoder.comp
2 block_linear_unswizzle_2d.comp 3 block_linear_unswizzle_2d.comp
3 block_linear_unswizzle_3d.comp 4 block_linear_unswizzle_3d.comp
4 convert_depth_to_float.frag 5 convert_depth_to_float.frag
diff --git a/src/video_core/host_shaders/StringShaderHeader.cmake b/src/video_core/host_shaders/StringShaderHeader.cmake
index c0fc49768..1b4bc6103 100644
--- a/src/video_core/host_shaders/StringShaderHeader.cmake
+++ b/src/video_core/host_shaders/StringShaderHeader.cmake
@@ -6,7 +6,27 @@ get_filename_component(CONTENTS_NAME ${SOURCE_FILE} NAME)
6string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME}) 6string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME})
7string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME) 7string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
8 8
9file(READ ${SOURCE_FILE} CONTENTS) 9FILE(READ ${SOURCE_FILE} line_contents)
10
11# Replace double quotes with single quotes,
12# as double quotes will be used to wrap the lines
13STRING(REGEX REPLACE "\"" "'" line_contents "${line_contents}")
14
15# CMake separates list elements with semicolons, but semicolons
16# are used extensively in the shader code.
17# Replace with a temporary marker, to be reverted later.
18STRING(REGEX REPLACE ";" "{{SEMICOLON}}" line_contents "${line_contents}")
19
20# Make every line an individual element in the CMake list.
21STRING(REGEX REPLACE "\n" ";" line_contents "${line_contents}")
22
23# Build the shader string, wrapping each line in double quotes.
24foreach(line IN LISTS line_contents)
25 string(CONCAT CONTENTS "${CONTENTS}" \"${line}\\n\"\n)
26endforeach()
27
28# Revert the original semicolons in the source.
29STRING(REGEX REPLACE "{{SEMICOLON}}" ";" CONTENTS "${CONTENTS}")
10 30
11get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY) 31get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY)
12make_directory(${OUTPUT_DIR}) 32make_directory(${OUTPUT_DIR})
diff --git a/src/video_core/host_shaders/astc_decoder.comp b/src/video_core/host_shaders/astc_decoder.comp
new file mode 100644
index 000000000..703e34587
--- /dev/null
+++ b/src/video_core/host_shaders/astc_decoder.comp
@@ -0,0 +1,1339 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 450
6
7#ifdef VULKAN
8
9#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
10#define END_PUSH_CONSTANTS };
11#define UNIFORM(n)
12#define BINDING_INPUT_BUFFER 0
13#define BINDING_ENC_BUFFER 1
14#define BINDING_6_TO_8_BUFFER 2
15#define BINDING_7_TO_8_BUFFER 3
16#define BINDING_8_TO_8_BUFFER 4
17#define BINDING_BYTE_TO_16_BUFFER 5
18#define BINDING_SWIZZLE_BUFFER 6
19#define BINDING_OUTPUT_IMAGE 7
20
21#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
22
23#define BEGIN_PUSH_CONSTANTS
24#define END_PUSH_CONSTANTS
25#define UNIFORM(n) layout(location = n) uniform
26#define BINDING_SWIZZLE_BUFFER 0
27#define BINDING_INPUT_BUFFER 1
28#define BINDING_ENC_BUFFER 2
29#define BINDING_6_TO_8_BUFFER 3
30#define BINDING_7_TO_8_BUFFER 4
31#define BINDING_8_TO_8_BUFFER 5
32#define BINDING_BYTE_TO_16_BUFFER 6
33#define BINDING_OUTPUT_IMAGE 0
34
35#endif
36
37layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
38
39BEGIN_PUSH_CONSTANTS
40UNIFORM(1) uvec2 block_dims;
41
42UNIFORM(2) uint bytes_per_block_log2;
43UNIFORM(3) uint layer_stride;
44UNIFORM(4) uint block_size;
45UNIFORM(5) uint x_shift;
46UNIFORM(6) uint block_height;
47UNIFORM(7) uint block_height_mask;
48END_PUSH_CONSTANTS
49
50struct EncodingData {
51 uint encoding;
52 uint num_bits;
53 uint bit_value;
54 uint quint_trit_value;
55};
56
57struct TexelWeightParams {
58 uvec2 size;
59 uint max_weight;
60 bool dual_plane;
61 bool error_state;
62 bool void_extent_ldr;
63 bool void_extent_hdr;
64};
65
66// Swizzle data
67layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
68 uint swizzle_table[];
69};
70
71layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 {
72 uint astc_data[];
73};
74
75// ASTC Encodings data
76layout(binding = BINDING_ENC_BUFFER, std430) readonly buffer EncodingsValues {
77 EncodingData encoding_values[];
78};
79// ASTC Precompiled tables
80layout(binding = BINDING_6_TO_8_BUFFER, std430) readonly buffer REPLICATE_6_BIT_TO_8 {
81 uint REPLICATE_6_BIT_TO_8_TABLE[];
82};
83layout(binding = BINDING_7_TO_8_BUFFER, std430) readonly buffer REPLICATE_7_BIT_TO_8 {
84 uint REPLICATE_7_BIT_TO_8_TABLE[];
85};
86layout(binding = BINDING_8_TO_8_BUFFER, std430) readonly buffer REPLICATE_8_BIT_TO_8 {
87 uint REPLICATE_8_BIT_TO_8_TABLE[];
88};
89layout(binding = BINDING_BYTE_TO_16_BUFFER, std430) readonly buffer REPLICATE_BYTE_TO_16 {
90 uint REPLICATE_BYTE_TO_16_TABLE[];
91};
92
93layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image;
94
95const uint GOB_SIZE_X = 64;
96const uint GOB_SIZE_Y = 8;
97const uint GOB_SIZE_Z = 1;
98const uint GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z;
99
100const uint GOB_SIZE_X_SHIFT = 6;
101const uint GOB_SIZE_Y_SHIFT = 3;
102const uint GOB_SIZE_Z_SHIFT = 0;
103const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT;
104
105const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1, GOB_SIZE_Y - 1);
106
107const int BLOCK_SIZE_IN_BYTES = 16;
108
109const int BLOCK_INFO_ERROR = 0;
110const int BLOCK_INFO_VOID_EXTENT_HDR = 1;
111const int BLOCK_INFO_VOID_EXTENT_LDR = 2;
112const int BLOCK_INFO_NORMAL = 3;
113
114const int JUST_BITS = 0;
115const int QUINT = 1;
116const int TRIT = 2;
117
118// The following constants are expanded variants of the Replicate()
119// function calls corresponding to the following arguments:
120// value: index into the generated table
121// num_bits: the after "REPLICATE" in the table name. i.e. 4 is num_bits in REPLICATE_4.
122// to_bit: the integer after "TO_"
123const uint REPLICATE_BIT_TO_7_TABLE[2] = uint[](0, 127);
124const uint REPLICATE_1_BIT_TO_9_TABLE[2] = uint[](0, 511);
125
126const uint REPLICATE_1_BIT_TO_8_TABLE[2] = uint[](0, 255);
127const uint REPLICATE_2_BIT_TO_8_TABLE[4] = uint[](0, 85, 170, 255);
128const uint REPLICATE_3_BIT_TO_8_TABLE[8] = uint[](0, 36, 73, 109, 146, 182, 219, 255);
129const uint REPLICATE_4_BIT_TO_8_TABLE[16] =
130 uint[](0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255);
131const uint REPLICATE_5_BIT_TO_8_TABLE[32] =
132 uint[](0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165,
133 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255);
134const uint REPLICATE_1_BIT_TO_6_TABLE[2] = uint[](0, 63);
135const uint REPLICATE_2_BIT_TO_6_TABLE[4] = uint[](0, 21, 42, 63);
136const uint REPLICATE_3_BIT_TO_6_TABLE[8] = uint[](0, 9, 18, 27, 36, 45, 54, 63);
137const uint REPLICATE_4_BIT_TO_6_TABLE[16] =
138 uint[](0, 4, 8, 12, 17, 21, 25, 29, 34, 38, 42, 46, 51, 55, 59, 63);
139const uint REPLICATE_5_BIT_TO_6_TABLE[32] =
140 uint[](0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 33, 35, 37, 39, 41, 43, 45,
141 47, 49, 51, 53, 55, 57, 59, 61, 63);
142
143// Input ASTC texture globals
144uint current_index = 0;
145int bitsread = 0;
146uint total_bitsread = 0;
147uint local_buff[16];
148
149// Color data globals
150uint color_endpoint_data[16];
151int color_bitsread = 0;
152uint total_color_bitsread = 0;
153int color_index = 0;
154
155// Four values, two endpoints, four maximum paritions
156uint color_values[32];
157int colvals_index = 0;
158
159// Weight data globals
160uint texel_weight_data[16];
161int texel_bitsread = 0;
162uint total_texel_bitsread = 0;
163int texel_index = 0;
164
165bool texel_flag = false;
166
167// Global "vectors" to be pushed into when decoding
168EncodingData result_vector[100];
169int result_index = 0;
170
171EncodingData texel_vector[100];
172int texel_vector_index = 0;
173
174uint unquantized_texel_weights[2][144];
175
176uint SwizzleOffset(uvec2 pos) {
177 pos = pos & SWIZZLE_MASK;
178 return swizzle_table[pos.y * 64 + pos.x];
179}
180
181uint ReadTexel(uint offset) {
182 // extract the 8-bit value from the 32-bit packed data.
183 return bitfieldExtract(astc_data[offset / 4], int((offset * 8) & 24), 8);
184}
185
186// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
187// is the same as [(num_bits - 1):0] and repeats all the way down.
188uint Replicate(uint val, uint num_bits, uint to_bit) {
189 if (num_bits == 0 || to_bit == 0) {
190 return 0;
191 }
192 const uint v = val & uint((1 << num_bits) - 1);
193 uint res = v;
194 uint reslen = num_bits;
195 while (reslen < to_bit) {
196 uint comp = 0;
197 if (num_bits > to_bit - reslen) {
198 uint newshift = to_bit - reslen;
199 comp = num_bits - newshift;
200 num_bits = newshift;
201 }
202 res = uint(res << num_bits);
203 res = uint(res | (v >> comp));
204 reslen += num_bits;
205 }
206 return res;
207}
208
209uvec4 ReplicateByteTo16(uvec4 value) {
210 return uvec4(REPLICATE_BYTE_TO_16_TABLE[value.x], REPLICATE_BYTE_TO_16_TABLE[value.y],
211 REPLICATE_BYTE_TO_16_TABLE[value.z], REPLICATE_BYTE_TO_16_TABLE[value.w]);
212}
213
214uint ReplicateBitTo7(uint value) {
215 return REPLICATE_BIT_TO_7_TABLE[value];
216}
217
218uint ReplicateBitTo9(uint value) {
219 return REPLICATE_1_BIT_TO_9_TABLE[value];
220}
221
222uint FastReplicateTo8(uint value, uint num_bits) {
223 switch (num_bits) {
224 case 1:
225 return REPLICATE_1_BIT_TO_8_TABLE[value];
226 case 2:
227 return REPLICATE_2_BIT_TO_8_TABLE[value];
228 case 3:
229 return REPLICATE_3_BIT_TO_8_TABLE[value];
230 case 4:
231 return REPLICATE_4_BIT_TO_8_TABLE[value];
232 case 5:
233 return REPLICATE_5_BIT_TO_8_TABLE[value];
234 case 6:
235 return REPLICATE_6_BIT_TO_8_TABLE[value];
236 case 7:
237 return REPLICATE_7_BIT_TO_8_TABLE[value];
238 case 8:
239 return REPLICATE_8_BIT_TO_8_TABLE[value];
240 }
241 return Replicate(value, num_bits, 8);
242}
243
244uint FastReplicateTo6(uint value, uint num_bits) {
245 switch (num_bits) {
246 case 1:
247 return REPLICATE_1_BIT_TO_6_TABLE[value];
248 case 2:
249 return REPLICATE_2_BIT_TO_6_TABLE[value];
250 case 3:
251 return REPLICATE_3_BIT_TO_6_TABLE[value];
252 case 4:
253 return REPLICATE_4_BIT_TO_6_TABLE[value];
254 case 5:
255 return REPLICATE_5_BIT_TO_6_TABLE[value];
256 }
257 return Replicate(value, num_bits, 6);
258}
259
260uint Div3Floor(uint v) {
261 return (v * 0x5556) >> 16;
262}
263
264uint Div3Ceil(uint v) {
265 return Div3Floor(v + 2);
266}
267
268uint Div5Floor(uint v) {
269 return (v * 0x3334) >> 16;
270}
271
272uint Div5Ceil(uint v) {
273 return Div5Floor(v + 4);
274}
275
276uint Hash52(uint p) {
277 p ^= p >> 15;
278 p -= p << 17;
279 p += p << 7;
280 p += p << 4;
281 p ^= p >> 5;
282 p += p << 16;
283 p ^= p >> 7;
284 p ^= p >> 3;
285 p ^= p << 6;
286 p ^= p >> 17;
287 return p;
288}
289
290uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bool small_block) {
291 if (partition_count == 1) {
292 return 0;
293 }
294 if (small_block) {
295 x <<= 1;
296 y <<= 1;
297 z <<= 1;
298 }
299
300 seed += (partition_count - 1) * 1024;
301
302 uint rnum = Hash52(uint(seed));
303 uint seed1 = uint(rnum & 0xF);
304 uint seed2 = uint((rnum >> 4) & 0xF);
305 uint seed3 = uint((rnum >> 8) & 0xF);
306 uint seed4 = uint((rnum >> 12) & 0xF);
307 uint seed5 = uint((rnum >> 16) & 0xF);
308 uint seed6 = uint((rnum >> 20) & 0xF);
309 uint seed7 = uint((rnum >> 24) & 0xF);
310 uint seed8 = uint((rnum >> 28) & 0xF);
311 uint seed9 = uint((rnum >> 18) & 0xF);
312 uint seed10 = uint((rnum >> 22) & 0xF);
313 uint seed11 = uint((rnum >> 26) & 0xF);
314 uint seed12 = uint(((rnum >> 30) | (rnum << 2)) & 0xF);
315
316 seed1 = (seed1 * seed1);
317 seed2 = (seed2 * seed2);
318 seed3 = (seed3 * seed3);
319 seed4 = (seed4 * seed4);
320 seed5 = (seed5 * seed5);
321 seed6 = (seed6 * seed6);
322 seed7 = (seed7 * seed7);
323 seed8 = (seed8 * seed8);
324 seed9 = (seed9 * seed9);
325 seed10 = (seed10 * seed10);
326 seed11 = (seed11 * seed11);
327 seed12 = (seed12 * seed12);
328
329 int sh1, sh2, sh3;
330 if ((seed & 1) > 0) {
331 sh1 = (seed & 2) > 0 ? 4 : 5;
332 sh2 = (partition_count == 3) ? 6 : 5;
333 } else {
334 sh1 = (partition_count == 3) ? 6 : 5;
335 sh2 = (seed & 2) > 0 ? 4 : 5;
336 }
337 sh3 = (seed & 0x10) > 0 ? sh1 : sh2;
338
339 seed1 = (seed1 >> sh1);
340 seed2 = (seed2 >> sh2);
341 seed3 = (seed3 >> sh1);
342 seed4 = (seed4 >> sh2);
343 seed5 = (seed5 >> sh1);
344 seed6 = (seed6 >> sh2);
345 seed7 = (seed7 >> sh1);
346 seed8 = (seed8 >> sh2);
347 seed9 = (seed9 >> sh3);
348 seed10 = (seed10 >> sh3);
349 seed11 = (seed11 >> sh3);
350 seed12 = (seed12 >> sh3);
351
352 uint a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
353 uint b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
354 uint c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
355 uint d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
356
357 a &= 0x3F;
358 b &= 0x3F;
359 c &= 0x3F;
360 d &= 0x3F;
361
362 if (partition_count < 4) {
363 d = 0;
364 }
365 if (partition_count < 3) {
366 c = 0;
367 }
368
369 if (a >= b && a >= c && a >= d) {
370 return 0;
371 } else if (b >= c && b >= d) {
372 return 1;
373 } else if (c >= d) {
374 return 2;
375 } else {
376 return 3;
377 }
378}
379
380uint Select2DPartition(uint seed, uint x, uint y, uint partition_count, bool small_block) {
381 return SelectPartition(seed, x, y, 0, partition_count, small_block);
382}
383
384uint ReadBit() {
385 if (current_index >= local_buff.length()) {
386 return 0;
387 }
388 uint bit = bitfieldExtract(local_buff[current_index], bitsread, 1);
389 ++bitsread;
390 ++total_bitsread;
391 if (bitsread == 8) {
392 ++current_index;
393 bitsread = 0;
394 }
395 return bit;
396}
397
398uint StreamBits(uint num_bits) {
399 uint ret = 0;
400 for (uint i = 0; i < num_bits; i++) {
401 ret |= ((ReadBit() & 1) << i);
402 }
403 return ret;
404}
405
406uint ReadColorBit() {
407 uint bit = 0;
408 if (texel_flag) {
409 bit = bitfieldExtract(texel_weight_data[texel_index], texel_bitsread, 1);
410 ++texel_bitsread;
411 ++total_texel_bitsread;
412 if (texel_bitsread == 8) {
413 ++texel_index;
414 texel_bitsread = 0;
415 }
416 } else {
417 bit = bitfieldExtract(color_endpoint_data[color_index], color_bitsread, 1);
418 ++color_bitsread;
419 ++total_color_bitsread;
420 if (color_bitsread == 8) {
421 ++color_index;
422 color_bitsread = 0;
423 }
424 }
425 return bit;
426}
427
428uint StreamColorBits(uint num_bits) {
429 uint ret = 0;
430 for (uint i = 0; i < num_bits; i++) {
431 ret |= ((ReadColorBit() & 1) << i);
432 }
433 return ret;
434}
435
436void ResultEmplaceBack(EncodingData val) {
437 if (texel_flag) {
438 texel_vector[texel_vector_index] = val;
439 ++texel_vector_index;
440 } else {
441 result_vector[result_index] = val;
442 ++result_index;
443 }
444}
445
446// Returns the number of bits required to encode n_vals values.
447uint GetBitLength(uint n_vals, uint encoding_index) {
448 uint total_bits = encoding_values[encoding_index].num_bits * n_vals;
449 if (encoding_values[encoding_index].encoding == TRIT) {
450 total_bits += Div5Ceil(n_vals * 8);
451 } else if (encoding_values[encoding_index].encoding == QUINT) {
452 total_bits += Div3Ceil(n_vals * 7);
453 }
454 return total_bits;
455}
456
457uint GetNumWeightValues(uvec2 size, bool dual_plane) {
458 uint n_vals = size.x * size.y;
459 if (dual_plane) {
460 n_vals *= 2;
461 }
462 return n_vals;
463}
464
465uint GetPackedBitSize(uvec2 size, bool dual_plane, uint max_weight) {
466 uint n_vals = GetNumWeightValues(size, dual_plane);
467 return GetBitLength(n_vals, max_weight);
468}
469
470uint BitsBracket(uint bits, uint pos) {
471 return ((bits >> pos) & 1);
472}
473
474uint BitsOp(uint bits, uint start, uint end) {
475 if (start == end) {
476 return BitsBracket(bits, start);
477 } else if (start > end) {
478 uint t = start;
479 start = end;
480 end = t;
481 }
482
483 uint mask = (1 << (end - start + 1)) - 1;
484 return ((bits >> start) & mask);
485}
486
487void DecodeQuintBlock(uint num_bits) {
488 uint m[3];
489 uint q[3];
490 uint Q;
491 m[0] = StreamColorBits(num_bits);
492 Q = StreamColorBits(3);
493 m[1] = StreamColorBits(num_bits);
494 Q |= StreamColorBits(2) << 3;
495 m[2] = StreamColorBits(num_bits);
496 Q |= StreamColorBits(2) << 5;
497 if (BitsOp(Q, 1, 2) == 3 && BitsOp(Q, 5, 6) == 0) {
498 q[0] = 4;
499 q[1] = 4;
500 q[2] = (BitsBracket(Q, 0) << 2) | ((BitsBracket(Q, 4) & ~BitsBracket(Q, 0)) << 1) |
501 (BitsBracket(Q, 3) & ~BitsBracket(Q, 0));
502 } else {
503 uint C = 0;
504 if (BitsOp(Q, 1, 2) == 3) {
505 q[2] = 4;
506 C = (BitsOp(Q, 3, 4) << 3) | ((~BitsOp(Q, 5, 6) & 3) << 1) | BitsBracket(Q, 0);
507 } else {
508 q[2] = BitsOp(Q, 5, 6);
509 C = BitsOp(Q, 0, 4);
510 }
511 if (BitsOp(C, 0, 2) == 5) {
512 q[1] = 4;
513 q[0] = BitsOp(C, 3, 4);
514 } else {
515 q[1] = BitsOp(C, 3, 4);
516 q[0] = BitsOp(C, 0, 2);
517 }
518 }
519 for (uint i = 0; i < 3; i++) {
520 EncodingData val;
521 val.encoding = QUINT;
522 val.num_bits = num_bits;
523 val.bit_value = m[i];
524 val.quint_trit_value = q[i];
525 ResultEmplaceBack(val);
526 }
527}
528
529void DecodeTritBlock(uint num_bits) {
530 uint m[5];
531 uint t[5];
532 uint T;
533 m[0] = StreamColorBits(num_bits);
534 T = StreamColorBits(2);
535 m[1] = StreamColorBits(num_bits);
536 T |= StreamColorBits(2) << 2;
537 m[2] = StreamColorBits(num_bits);
538 T |= StreamColorBits(1) << 4;
539 m[3] = StreamColorBits(num_bits);
540 T |= StreamColorBits(2) << 5;
541 m[4] = StreamColorBits(num_bits);
542 T |= StreamColorBits(1) << 7;
543 uint C = 0;
544 if (BitsOp(T, 2, 4) == 7) {
545 C = (BitsOp(T, 5, 7) << 2) | BitsOp(T, 0, 1);
546 t[4] = 2;
547 t[3] = 2;
548 } else {
549 C = BitsOp(T, 0, 4);
550 if (BitsOp(T, 5, 6) == 3) {
551 t[4] = 2;
552 t[3] = BitsBracket(T, 7);
553 } else {
554 t[4] = BitsBracket(T, 7);
555 t[3] = BitsOp(T, 5, 6);
556 }
557 }
558 if (BitsOp(C, 0, 1) == 3) {
559 t[2] = 2;
560 t[1] = BitsBracket(C, 4);
561 t[0] = (BitsBracket(C, 3) << 1) | (BitsBracket(C, 2) & ~BitsBracket(C, 3));
562 } else if (BitsOp(C, 2, 3) == 3) {
563 t[2] = 2;
564 t[1] = 2;
565 t[0] = BitsOp(C, 0, 1);
566 } else {
567 t[2] = BitsBracket(C, 4);
568 t[1] = BitsOp(C, 2, 3);
569 t[0] = (BitsBracket(C, 1) << 1) | (BitsBracket(C, 0) & ~BitsBracket(C, 1));
570 }
571 for (uint i = 0; i < 5; i++) {
572 EncodingData val;
573 val.encoding = TRIT;
574 val.num_bits = num_bits;
575 val.bit_value = m[i];
576 val.quint_trit_value = t[i];
577 ResultEmplaceBack(val);
578 }
579}
580
581void DecodeIntegerSequence(uint max_range, uint num_values) {
582 EncodingData val = encoding_values[max_range];
583 uint vals_decoded = 0;
584 while (vals_decoded < num_values) {
585 switch (val.encoding) {
586 case QUINT:
587 DecodeQuintBlock(val.num_bits);
588 vals_decoded += 3;
589 break;
590 case TRIT:
591 DecodeTritBlock(val.num_bits);
592 vals_decoded += 5;
593 break;
594 case JUST_BITS:
595 val.bit_value = StreamColorBits(val.num_bits);
596 ResultEmplaceBack(val);
597 vals_decoded++;
598 break;
599 }
600 }
601}
602
603void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
604 uint num_values = 0;
605 for (uint i = 0; i < num_partitions; i++) {
606 num_values += ((modes[i] >> 2) + 1) << 1;
607 }
608 int range = 256;
609 while (--range > 0) {
610 EncodingData val = encoding_values[range];
611 uint bit_length = GetBitLength(num_values, range);
612 if (bit_length <= color_data_bits) {
613 while (--range > 0) {
614 EncodingData newval = encoding_values[range];
615 if (newval.encoding != val.encoding && newval.num_bits != val.num_bits) {
616 break;
617 }
618 }
619 ++range;
620 break;
621 }
622 }
623 DecodeIntegerSequence(range, num_values);
624 uint out_index = 0;
625 for (int itr = 0; itr < result_index; ++itr) {
626 if (out_index >= num_values) {
627 break;
628 }
629 EncodingData val = result_vector[itr];
630 uint bitlen = val.num_bits;
631 uint bitval = val.bit_value;
632 uint A = 0, B = 0, C = 0, D = 0;
633 A = ReplicateBitTo9((bitval & 1));
634 switch (val.encoding) {
635 case JUST_BITS:
636 color_values[out_index++] = FastReplicateTo8(bitval, bitlen);
637 break;
638 case TRIT: {
639 D = val.quint_trit_value;
640 switch (bitlen) {
641 case 1:
642 C = 204;
643 break;
644 case 2: {
645 C = 93;
646 uint b = (bitval >> 1) & 1;
647 B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
648 break;
649 }
650 case 3: {
651 C = 44;
652 uint cb = (bitval >> 1) & 3;
653 B = (cb << 7) | (cb << 2) | cb;
654 break;
655 }
656 case 4: {
657 C = 22;
658 uint dcb = (bitval >> 1) & 7;
659 B = (dcb << 6) | dcb;
660 break;
661 }
662 case 5: {
663 C = 11;
664 uint edcb = (bitval >> 1) & 0xF;
665 B = (edcb << 5) | (edcb >> 2);
666 break;
667 }
668 case 6: {
669 C = 5;
670 uint fedcb = (bitval >> 1) & 0x1F;
671 B = (fedcb << 4) | (fedcb >> 4);
672 break;
673 }
674 }
675 break;
676 }
677 case QUINT: {
678 D = val.quint_trit_value;
679 switch (bitlen) {
680 case 1:
681 C = 113;
682 break;
683 case 2: {
684 C = 54;
685 uint b = (bitval >> 1) & 1;
686 B = (b << 8) | (b << 3) | (b << 2);
687 break;
688 }
689 case 3: {
690 C = 26;
691 uint cb = (bitval >> 1) & 3;
692 B = (cb << 7) | (cb << 1) | (cb >> 1);
693 break;
694 }
695 case 4: {
696 C = 13;
697 uint dcb = (bitval >> 1) & 7;
698 B = (dcb << 6) | (dcb >> 1);
699 break;
700 }
701 case 5: {
702 C = 6;
703 uint edcb = (bitval >> 1) & 0xF;
704 B = (edcb << 5) | (edcb >> 3);
705 break;
706 }
707 }
708 break;
709 }
710 }
711 if (val.encoding != JUST_BITS) {
712 uint T = (D * C) + B;
713 T ^= A;
714 T = (A & 0x80) | (T >> 2);
715 color_values[out_index++] = T;
716 }
717 }
718}
719
720ivec2 BitTransferSigned(int a, int b) {
721 ivec2 transferred;
722 transferred.y = b >> 1;
723 transferred.y |= a & 0x80;
724 transferred.x = a >> 1;
725 transferred.x &= 0x3F;
726 if ((transferred.x & 0x20) > 0) {
727 transferred.x -= 0x40;
728 }
729 return transferred;
730}
731
732uvec4 ClampByte(ivec4 color) {
733 for (uint i = 0; i < 4; ++i) {
734 color[i] = (color[i] < 0) ? 0 : ((color[i] > 255) ? 255 : color[i]);
735 }
736 return uvec4(color);
737}
738
739ivec4 BlueContract(int a, int r, int g, int b) {
740 return ivec4(a, (r + b) >> 1, (g + b) >> 1, b);
741}
742
743void ComputeEndpoints(out uvec4 ep1, out uvec4 ep2, uint color_endpoint_mode) {
744#define READ_UINT_VALUES(N) \
745 uint v[N]; \
746 for (uint i = 0; i < N; i++) { \
747 v[i] = color_values[colvals_index++]; \
748 }
749
750#define READ_INT_VALUES(N) \
751 int v[N]; \
752 for (uint i = 0; i < N; i++) { \
753 v[i] = int(color_values[colvals_index++]); \
754 }
755
756 switch (color_endpoint_mode) {
757 case 0: {
758 READ_UINT_VALUES(2)
759 ep1 = uvec4(0xFF, v[0], v[0], v[0]);
760 ep2 = uvec4(0xFF, v[1], v[1], v[1]);
761 break;
762 }
763 case 1: {
764 READ_UINT_VALUES(2)
765 uint L0 = (v[0] >> 2) | (v[1] & 0xC0);
766 uint L1 = max(L0 + (v[1] & 0x3F), 0xFFU);
767 ep1 = uvec4(0xFF, L0, L0, L0);
768 ep2 = uvec4(0xFF, L1, L1, L1);
769 break;
770 }
771 case 4: {
772 READ_UINT_VALUES(4)
773 ep1 = uvec4(v[2], v[0], v[0], v[0]);
774 ep2 = uvec4(v[3], v[1], v[1], v[1]);
775 break;
776 }
777 case 5: {
778 READ_INT_VALUES(4)
779 ivec2 transferred = BitTransferSigned(v[1], v[0]);
780 v[1] = transferred.x;
781 v[0] = transferred.y;
782 transferred = BitTransferSigned(v[3], v[2]);
783 v[3] = transferred.x;
784 v[2] = transferred.y;
785 ep1 = ClampByte(ivec4(v[2], v[0], v[0], v[0]));
786 ep2 = ClampByte(ivec4(v[2] + v[3], v[0] + v[1], v[0] + v[1], v[0] + v[1]));
787 break;
788 }
789 case 6: {
790 READ_UINT_VALUES(4)
791 ep1 = uvec4(0xFF, (v[0] * v[3]) >> 8, (v[1] * v[3]) >> 8, (v[2] * v[3]) >> 8);
792 ep2 = uvec4(0xFF, v[0], v[1], v[2]);
793 break;
794 }
795 case 8: {
796 READ_UINT_VALUES(6)
797 if ((v[1] + v[3] + v[5]) >= (v[0] + v[2] + v[4])) {
798 ep1 = uvec4(0xFF, v[0], v[2], v[4]);
799 ep2 = uvec4(0xFF, v[1], v[3], v[5]);
800 } else {
801 ep1 = uvec4(BlueContract(0xFF, int(v[1]), int(v[3]), int(v[5])));
802 ep2 = uvec4(BlueContract(0xFF, int(v[0]), int(v[2]), int(v[4])));
803 }
804 break;
805 }
806 case 9: {
807 READ_INT_VALUES(6)
808 ivec2 transferred = BitTransferSigned(v[1], v[0]);
809 v[1] = transferred.x;
810 v[0] = transferred.y;
811 transferred = BitTransferSigned(v[3], v[2]);
812 v[3] = transferred.x;
813 v[2] = transferred.y;
814 transferred = BitTransferSigned(v[5], v[4]);
815 v[5] = transferred.x;
816 v[4] = transferred.y;
817 if ((v[1] + v[3] + v[5]) >= 0) {
818 ep1 = ClampByte(ivec4(0xFF, v[0], v[2], v[4]));
819 ep2 = ClampByte(ivec4(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]));
820 } else {
821 ep1 = ClampByte(BlueContract(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]));
822 ep2 = ClampByte(BlueContract(0xFF, v[0], v[2], v[4]));
823 }
824 break;
825 }
826 case 10: {
827 READ_UINT_VALUES(6)
828 ep1 = uvec4(v[4], (v[0] * v[3]) >> 8, (v[1] * v[3]) >> 8, (v[2] * v[3]) >> 8);
829 ep2 = uvec4(v[5], v[0], v[1], v[2]);
830 break;
831 }
832 case 12: {
833 READ_UINT_VALUES(8)
834 if ((v[1] + v[3] + v[5]) >= (v[0] + v[2] + v[4])) {
835 ep1 = uvec4(v[6], v[0], v[2], v[4]);
836 ep2 = uvec4(v[7], v[1], v[3], v[5]);
837 } else {
838 ep1 = uvec4(BlueContract(int(v[7]), int(v[1]), int(v[3]), int(v[5])));
839 ep2 = uvec4(BlueContract(int(v[6]), int(v[0]), int(v[2]), int(v[4])));
840 }
841 break;
842 }
843 case 13: {
844 READ_INT_VALUES(8)
845 ivec2 transferred = BitTransferSigned(v[1], v[0]);
846 v[1] = transferred.x;
847 v[0] = transferred.y;
848 transferred = BitTransferSigned(v[3], v[2]);
849 v[3] = transferred.x;
850 v[2] = transferred.y;
851
852 transferred = BitTransferSigned(v[5], v[4]);
853 v[5] = transferred.x;
854 v[4] = transferred.y;
855
856 transferred = BitTransferSigned(v[7], v[6]);
857 v[7] = transferred.x;
858 v[6] = transferred.y;
859
860 if ((v[1] + v[3] + v[5]) >= 0) {
861 ep1 = ClampByte(ivec4(v[6], v[0], v[2], v[4]));
862 ep2 = ClampByte(ivec4(v[7] + v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5]));
863 } else {
864 ep1 = ClampByte(BlueContract(v[6] + v[7], v[0] + v[1], v[2] + v[3], v[4] + v[5]));
865 ep2 = ClampByte(BlueContract(v[6], v[0], v[2], v[4]));
866 }
867 break;
868 }
869 default: {
870 // HDR mode, or more likely a bug computing the color_endpoint_mode
871 ep1 = uvec4(0xFF, 0xFF, 0, 0);
872 ep2 = uvec4(0xFF, 0xFF, 0, 0);
873 break;
874 }
875 }
876#undef READ_UINT_VALUES
877#undef READ_INT_VALUES
878}
879
880uint UnquantizeTexelWeight(EncodingData val) {
881 uint bitval = val.bit_value;
882 uint bitlen = val.num_bits;
883 uint A = ReplicateBitTo7((bitval & 1));
884 uint B = 0, C = 0, D = 0;
885 uint result = 0;
886 switch (val.encoding) {
887 case JUST_BITS:
888 result = FastReplicateTo6(bitval, bitlen);
889 break;
890 case TRIT: {
891 D = val.quint_trit_value;
892 switch (bitlen) {
893 case 0: {
894 uint results[3] = {0, 32, 63};
895 result = results[D];
896 break;
897 }
898 case 1: {
899 C = 50;
900 break;
901 }
902 case 2: {
903 C = 23;
904 uint b = (bitval >> 1) & 1;
905 B = (b << 6) | (b << 2) | b;
906 break;
907 }
908 case 3: {
909 C = 11;
910 uint cb = (bitval >> 1) & 3;
911 B = (cb << 5) | cb;
912 break;
913 }
914 default:
915 break;
916 }
917 break;
918 }
919 case QUINT: {
920 D = val.quint_trit_value;
921 switch (bitlen) {
922 case 0: {
923 uint results[5] = {0, 16, 32, 47, 63};
924 result = results[D];
925 break;
926 }
927 case 1: {
928 C = 28;
929 break;
930 }
931 case 2: {
932 C = 13;
933 uint b = (bitval >> 1) & 1;
934 B = (b << 6) | (b << 1);
935 break;
936 }
937 }
938 break;
939 }
940 }
941 if (val.encoding != JUST_BITS && bitlen > 0) {
942 result = D * C + B;
943 result ^= A;
944 result = (A & 0x20) | (result >> 2);
945 }
946 if (result > 32) {
947 result += 1;
948 }
949 return result;
950}
951
952void UnquantizeTexelWeights(bool dual_plane, uvec2 size) {
953 uint weight_idx = 0;
954 uint unquantized[2][144];
955 uint area = size.x * size.y;
956 for (uint itr = 0; itr < texel_vector_index; itr++) {
957 unquantized[0][weight_idx] = UnquantizeTexelWeight(texel_vector[itr]);
958 if (dual_plane) {
959 ++itr;
960 unquantized[1][weight_idx] = UnquantizeTexelWeight(texel_vector[itr]);
961 if (itr == texel_vector_index) {
962 break;
963 }
964 }
965 if (++weight_idx >= (area))
966 break;
967 }
968
969 const uint Ds = uint((block_dims.x * 0.5f + 1024) / (block_dims.x - 1));
970 const uint Dt = uint((block_dims.y * 0.5f + 1024) / (block_dims.y - 1));
971 const uint k_plane_scale = dual_plane ? 2 : 1;
972 for (uint plane = 0; plane < k_plane_scale; plane++) {
973 for (uint t = 0; t < block_dims.y; t++) {
974 for (uint s = 0; s < block_dims.x; s++) {
975 uint cs = Ds * s;
976 uint ct = Dt * t;
977 uint gs = (cs * (size.x - 1) + 32) >> 6;
978 uint gt = (ct * (size.y - 1) + 32) >> 6;
979 uint js = gs >> 4;
980 uint fs = gs & 0xF;
981 uint jt = gt >> 4;
982 uint ft = gt & 0x0F;
983 uint w11 = (fs * ft + 8) >> 4;
984 uint w10 = ft - w11;
985 uint w01 = fs - w11;
986 uint w00 = 16 - fs - ft + w11;
987 uvec4 w = uvec4(w00, w01, w10, w11);
988 uint v0 = jt * size.x + js;
989
990 uvec4 p = uvec4(0);
991 if (v0 < area) {
992 p.x = unquantized[plane][v0];
993 }
994 if ((v0 + 1) < (area)) {
995 p.y = unquantized[plane][v0 + 1];
996 }
997 if ((v0 + size.x) < (area)) {
998 p.z = unquantized[plane][(v0 + size.x)];
999 }
1000 if ((v0 + size.x + 1) < (area)) {
1001 p.w = unquantized[plane][(v0 + size.x + 1)];
1002 }
1003 unquantized_texel_weights[plane][t * block_dims.x + s] = (uint(dot(p, w)) + 8) >> 4;
1004 }
1005 }
1006 }
1007}
1008
1009int FindLayout(uint mode) {
1010 if ((mode & 3) != 0) {
1011 if ((mode & 8) != 0) {
1012 if ((mode & 4) != 0) {
1013 if ((mode & 0x100) != 0) {
1014 return 4;
1015 }
1016 return 3;
1017 }
1018 return 2;
1019 }
1020 if ((mode & 4) != 0) {
1021 return 1;
1022 }
1023 return 0;
1024 }
1025 if ((mode & 0x100) != 0) {
1026 if ((mode & 0x80) != 0) {
1027 if ((mode & 0x20) != 0) {
1028 return 8;
1029 }
1030 return 7;
1031 }
1032 return 9;
1033 }
1034 if ((mode & 0x80) != 0) {
1035 return 6;
1036 }
1037 return 5;
1038}
1039
1040TexelWeightParams DecodeBlockInfo(uint block_index) {
1041 TexelWeightParams params = TexelWeightParams(uvec2(0), 0, false, false, false, false);
1042 uint mode = StreamBits(11);
1043 if ((mode & 0x1ff) == 0x1fc) {
1044 if ((mode & 0x200) != 0) {
1045 params.void_extent_hdr = true;
1046 } else {
1047 params.void_extent_ldr = true;
1048 }
1049 if ((mode & 0x400) == 0 || StreamBits(1) == 0) {
1050 params.error_state = true;
1051 }
1052 return params;
1053 }
1054 if ((mode & 0xf) == 0) {
1055 params.error_state = true;
1056 return params;
1057 }
1058 if ((mode & 3) == 0 && (mode & 0x1c0) == 0x1c0) {
1059 params.error_state = true;
1060 return params;
1061 }
1062 uint A, B;
1063 uint mode_layout = FindLayout(mode);
1064 switch (mode_layout) {
1065 case 0:
1066 A = (mode >> 5) & 0x3;
1067 B = (mode >> 7) & 0x3;
1068 params.size = uvec2(B + 4, A + 2);
1069 break;
1070 case 1:
1071 A = (mode >> 5) & 0x3;
1072 B = (mode >> 7) & 0x3;
1073 params.size = uvec2(B + 8, A + 2);
1074 break;
1075 case 2:
1076 A = (mode >> 5) & 0x3;
1077 B = (mode >> 7) & 0x3;
1078 params.size = uvec2(A + 2, B + 8);
1079 break;
1080 case 3:
1081 A = (mode >> 5) & 0x3;
1082 B = (mode >> 7) & 0x1;
1083 params.size = uvec2(A + 2, B + 6);
1084 break;
1085 case 4:
1086 A = (mode >> 5) & 0x3;
1087 B = (mode >> 7) & 0x1;
1088 params.size = uvec2(B + 2, A + 2);
1089 break;
1090 case 5:
1091 A = (mode >> 5) & 0x3;
1092 params.size = uvec2(12, A + 2);
1093 break;
1094 case 6:
1095 A = (mode >> 5) & 0x3;
1096 params.size = uvec2(A + 2, 12);
1097 break;
1098 case 7:
1099 params.size = uvec2(6, 10);
1100 break;
1101 case 8:
1102 params.size = uvec2(10, 6);
1103 break;
1104 case 9:
1105 A = (mode >> 5) & 0x3;
1106 B = (mode >> 9) & 0x3;
1107 params.size = uvec2(A + 6, B + 6);
1108 break;
1109 default:
1110 params.error_state = true;
1111 break;
1112 }
1113 params.dual_plane = (mode_layout != 9) && ((mode & 0x400) != 0);
1114 uint weight_index = (mode & 0x10) != 0 ? 1 : 0;
1115 if (mode_layout < 5) {
1116 weight_index |= (mode & 0x3) << 1;
1117 } else {
1118 weight_index |= (mode & 0xc) >> 1;
1119 }
1120 weight_index -= 2;
1121 if ((mode_layout != 9) && ((mode & 0x200) != 0)) {
1122 const int max_weights[6] = int[6](9, 11, 15, 19, 23, 31);
1123 params.max_weight = max_weights[weight_index];
1124 } else {
1125 const int max_weights[6] = int[6](1, 2, 3, 4, 5, 7);
1126 params.max_weight = max_weights[weight_index];
1127 }
1128 return params;
1129}
1130
1131void FillError(ivec3 coord) {
1132 for (uint j = 0; j < block_dims.y; j++) {
1133 for (uint i = 0; i < block_dims.x; i++) {
1134 imageStore(dest_image, coord + ivec3(i, j, 0), vec4(1.0, 1.0, 0.0, 1.0));
1135 }
1136 }
1137}
1138
1139void FillVoidExtentLDR(ivec3 coord) {
1140 StreamBits(52);
1141 uint r_u = StreamBits(16);
1142 uint g_u = StreamBits(16);
1143 uint b_u = StreamBits(16);
1144 uint a_u = StreamBits(16);
1145 float a = float(a_u) / 65535.0f;
1146 float r = float(r_u) / 65535.0f;
1147 float g = float(g_u) / 65535.0f;
1148 float b = float(b_u) / 65535.0f;
1149 for (uint j = 0; j < block_dims.y; j++) {
1150 for (uint i = 0; i < block_dims.x; i++) {
1151 imageStore(dest_image, coord + ivec3(i, j, 0), vec4(r, g, b, a));
1152 }
1153 }
1154}
1155
1156void DecompressBlock(ivec3 coord, uint block_index) {
1157 TexelWeightParams params = DecodeBlockInfo(block_index);
1158 if (params.error_state) {
1159 FillError(coord);
1160 return;
1161 }
1162 if (params.void_extent_hdr) {
1163 FillError(coord);
1164 return;
1165 }
1166 if (params.void_extent_ldr) {
1167 FillVoidExtentLDR(coord);
1168 return;
1169 }
1170 if ((params.size.x > block_dims.x) || (params.size.y > block_dims.y)) {
1171 FillError(coord);
1172 return;
1173 }
1174 uint num_partitions = StreamBits(2) + 1;
1175 if (num_partitions > 4 || (num_partitions == 4 && params.dual_plane)) {
1176 FillError(coord);
1177 return;
1178 }
1179 int plane_index = -1;
1180 uint partition_index = 1;
1181 uvec4 color_endpoint_mode = uvec4(0);
1182 uint ced_pointer = 0;
1183 uint base_cem = 0;
1184 if (num_partitions == 1) {
1185 color_endpoint_mode.x = StreamBits(4);
1186 partition_index = 0;
1187 } else {
1188 partition_index = StreamBits(10);
1189 base_cem = StreamBits(6);
1190 }
1191 uint base_mode = base_cem & 3;
1192 uint weight_bits = GetPackedBitSize(params.size, params.dual_plane, params.max_weight);
1193 uint remaining_bits = 128 - weight_bits - total_bitsread;
1194 uint extra_cem_bits = 0;
1195 if (base_mode > 0) {
1196 switch (num_partitions) {
1197 case 2:
1198 extra_cem_bits += 2;
1199 break;
1200 case 3:
1201 extra_cem_bits += 5;
1202 break;
1203 case 4:
1204 extra_cem_bits += 8;
1205 break;
1206 default:
1207 return;
1208 }
1209 }
1210 remaining_bits -= extra_cem_bits;
1211 uint plane_selector_bits = 0;
1212 if (params.dual_plane) {
1213 plane_selector_bits = 2;
1214 }
1215 remaining_bits -= plane_selector_bits;
1216 if (remaining_bits > 128) {
1217 // Bad data, more remaining bits than 4 bytes
1218 // return early
1219 return;
1220 }
1221 // Read color data...
1222 uint color_data_bits = remaining_bits;
1223 while (remaining_bits > 0) {
1224 int nb = int(min(remaining_bits, 8U));
1225 uint b = StreamBits(nb);
1226 color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb));
1227 ++ced_pointer;
1228 remaining_bits -= nb;
1229 }
1230 plane_index = int(StreamBits(plane_selector_bits));
1231 if (base_mode > 0) {
1232 uint extra_cem = StreamBits(extra_cem_bits);
1233 uint cem = (extra_cem << 6) | base_cem;
1234 cem >>= 2;
1235 uvec4 C = uvec4(0);
1236 for (uint i = 0; i < num_partitions; i++) {
1237 C[i] = (cem & 1);
1238 cem >>= 1;
1239 }
1240 uvec4 M = uvec4(0);
1241 for (uint i = 0; i < num_partitions; i++) {
1242 M[i] = cem & 3;
1243 cem >>= 2;
1244 }
1245 for (uint i = 0; i < num_partitions; i++) {
1246 color_endpoint_mode[i] = base_mode;
1247 if (C[i] == 0) {
1248 --color_endpoint_mode[i];
1249 }
1250 color_endpoint_mode[i] <<= 2;
1251 color_endpoint_mode[i] |= M[i];
1252 }
1253 } else if (num_partitions > 1) {
1254 uint cem = base_cem >> 2;
1255 for (uint i = 0; i < num_partitions; i++) {
1256 color_endpoint_mode[i] = cem;
1257 }
1258 }
1259 DecodeColorValues(color_endpoint_mode, num_partitions, color_data_bits);
1260
1261 uvec4 endpoints[4][2];
1262 for (uint i = 0; i < num_partitions; i++) {
1263 ComputeEndpoints(endpoints[i][0], endpoints[i][1], color_endpoint_mode[i]);
1264 }
1265
1266 for (uint i = 0; i < 16; i++) {
1267 texel_weight_data[i] = local_buff[i];
1268 }
1269 for (uint i = 0; i < 8; i++) {
1270#define REVERSE_BYTE(b) ((b * 0x0802U & 0x22110U) | (b * 0x8020U & 0x88440U)) * 0x10101U >> 16
1271 uint a = REVERSE_BYTE(texel_weight_data[i]);
1272 uint b = REVERSE_BYTE(texel_weight_data[15 - i]);
1273#undef REVERSE_BYTE
1274 texel_weight_data[i] = uint(bitfieldExtract(b, 0, 8));
1275 texel_weight_data[15 - i] = uint(bitfieldExtract(a, 0, 8));
1276 }
1277 uint clear_byte_start =
1278 (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) >> 3) + 1;
1279 texel_weight_data[clear_byte_start - 1] =
1280 texel_weight_data[clear_byte_start - 1] &
1281 uint(
1282 ((1 << (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) % 8)) - 1));
1283 for (uint i = 0; i < 16 - clear_byte_start; i++) {
1284 texel_weight_data[clear_byte_start + i] = 0U;
1285 }
1286 texel_flag = true; // use texel "vector" and bit stream in integer decoding
1287 DecodeIntegerSequence(params.max_weight, GetNumWeightValues(params.size, params.dual_plane));
1288
1289 UnquantizeTexelWeights(params.dual_plane, params.size);
1290
1291 for (uint j = 0; j < block_dims.y; j++) {
1292 for (uint i = 0; i < block_dims.x; i++) {
1293 uint local_partition = Select2DPartition(partition_index, i, j, num_partitions,
1294 (block_dims.y * block_dims.x) < 32);
1295 vec4 p;
1296 uvec4 C0 = ReplicateByteTo16(endpoints[local_partition][0]);
1297 uvec4 C1 = ReplicateByteTo16(endpoints[local_partition][1]);
1298 uvec4 plane_vec = uvec4(0);
1299 uvec4 weight_vec = uvec4(0);
1300 for (uint c = 0; c < 4; c++) {
1301 if (params.dual_plane && (((plane_index + 1) & 3) == c)) {
1302 plane_vec[c] = 1;
1303 }
1304 weight_vec[c] = unquantized_texel_weights[plane_vec[c]][j * block_dims.x + i];
1305 }
1306 vec4 Cf = vec4((C0 * (uvec4(64) - weight_vec) + C1 * weight_vec + uvec4(32)) / 64);
1307 p = (Cf / 65535.0);
1308 imageStore(dest_image, coord + ivec3(i, j, 0), p.gbar);
1309 }
1310 }
1311}
1312
1313void main() {
1314 uvec3 pos = gl_GlobalInvocationID;
1315 pos.x <<= bytes_per_block_log2;
1316
1317 // Read as soon as possible due to its latency
1318 const uint swizzle = SwizzleOffset(pos.xy);
1319
1320 const uint block_y = pos.y >> GOB_SIZE_Y_SHIFT;
1321
1322 uint offset = 0;
1323 offset += pos.z * layer_stride;
1324 offset += (block_y >> block_height) * block_size;
1325 offset += (block_y & block_height_mask) << GOB_SIZE_SHIFT;
1326 offset += (pos.x >> GOB_SIZE_X_SHIFT) << x_shift;
1327 offset += swizzle;
1328
1329 const ivec3 coord = ivec3(gl_GlobalInvocationID * uvec3(block_dims, 1));
1330 uint block_index =
1331 pos.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + pos.y * gl_WorkGroupSize.x + pos.x;
1332
1333 current_index = 0;
1334 bitsread = 0;
1335 for (int i = 0; i < 16; i++) {
1336 local_buff[i] = ReadTexel(offset + i);
1337 }
1338 DecompressBlock(coord, block_index);
1339}
diff --git a/src/video_core/host_shaders/source_shader.h.in b/src/video_core/host_shaders/source_shader.h.in
index ccdb0d2a9..929dec39b 100644
--- a/src/video_core/host_shaders/source_shader.h.in
+++ b/src/video_core/host_shaders/source_shader.h.in
@@ -4,6 +4,8 @@
4 4
5namespace HostShaders { 5namespace HostShaders {
6 6
7constexpr std::string_view @CONTENTS_NAME@ = R"(@CONTENTS@)"; 7constexpr std::string_view @CONTENTS_NAME@ = {
8@CONTENTS@
9};
8 10
9} // namespace HostShaders 11} // namespace HostShaders
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 1ae5f1d62..5776fccdc 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -210,6 +210,12 @@ Device::Device() {
210 const bool is_amd = vendor == "ATI Technologies Inc."; 210 const bool is_amd = vendor == "ATI Technologies Inc.";
211 const bool is_intel = vendor == "Intel"; 211 const bool is_intel = vendor == "Intel";
212 212
213#ifdef __unix__
214 const bool is_linux = true;
215#else
216 const bool is_linux = false;
217#endif
218
213 bool disable_fast_buffer_sub_data = false; 219 bool disable_fast_buffer_sub_data = false;
214 if (is_nvidia && version == "4.6.0 NVIDIA 443.24") { 220 if (is_nvidia && version == "4.6.0 NVIDIA 443.24") {
215 LOG_WARNING( 221 LOG_WARNING(
@@ -249,7 +255,9 @@ Device::Device() {
249 GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 && 255 GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
250 GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2; 256 GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
251 257
252 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); 258 // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.
259 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() &&
260 !(is_amd || (is_intel && !is_linux));
253 use_driver_cache = is_nvidia; 261 use_driver_cache = is_nvidia;
254 262
255 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); 263 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
@@ -261,6 +269,10 @@ Device::Device() {
261 if (Settings::values.use_assembly_shaders.GetValue() && !use_assembly_shaders) { 269 if (Settings::values.use_assembly_shaders.GetValue() && !use_assembly_shaders) {
262 LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported"); 270 LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
263 } 271 }
272
273 if (Settings::values.use_asynchronous_shaders.GetValue() && !use_asynchronous_shaders) {
274 LOG_WARNING(Render_OpenGL, "Asynchronous shader compilation enabled but not supported");
275 }
264} 276}
265 277
266Device::Device(std::nullptr_t) { 278Device::Device(std::nullptr_t) {
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index e028677e9..623b43d8a 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -307,7 +307,8 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
307 307
308[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime, 308[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
309 const VideoCommon::ImageInfo& info) { 309 const VideoCommon::ImageInfo& info) {
310 // Disable accelerated uploads for now as they don't implement swizzled uploads 310 return !runtime.HasNativeASTC() && IsPixelFormatASTC(info.format);
311 // Disable other accelerated uploads for now as they don't implement swizzled uploads
311 return false; 312 return false;
312 switch (info.type) { 313 switch (info.type) {
313 case ImageType::e2D: 314 case ImageType::e2D:
@@ -569,7 +570,11 @@ void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferM
569 std::span<const SwizzleParameters> swizzles) { 570 std::span<const SwizzleParameters> swizzles) {
570 switch (image.info.type) { 571 switch (image.info.type) {
571 case ImageType::e2D: 572 case ImageType::e2D:
572 return util_shaders.BlockLinearUpload2D(image, map, swizzles); 573 if (IsPixelFormatASTC(image.info.format)) {
574 return util_shaders.ASTCDecode(image, map, swizzles);
575 } else {
576 return util_shaders.BlockLinearUpload2D(image, map, swizzles);
577 }
573 case ImageType::e3D: 578 case ImageType::e3D:
574 return util_shaders.BlockLinearUpload3D(image, map, swizzles); 579 return util_shaders.BlockLinearUpload3D(image, map, swizzles);
575 case ImageType::Linear: 580 case ImageType::Linear:
@@ -599,6 +604,10 @@ FormatProperties TextureCacheRuntime::FormatInfo(ImageType type, GLenum internal
599 } 604 }
600} 605}
601 606
607bool TextureCacheRuntime::HasNativeASTC() const noexcept {
608 return device.HasASTC();
609}
610
602TextureCacheRuntime::StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_) 611TextureCacheRuntime::StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_)
603 : storage_flags{storage_flags_}, map_flags{map_flags_} {} 612 : storage_flags{storage_flags_}, map_flags{map_flags_} {}
604 613
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 3fbaa102f..3c871541b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -95,6 +95,8 @@ public:
95 return has_broken_texture_view_formats; 95 return has_broken_texture_view_formats;
96 } 96 }
97 97
98 bool HasNativeASTC() const noexcept;
99
98private: 100private:
99 struct StagingBuffers { 101 struct StagingBuffers {
100 explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_); 102 explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp
index 2fe4799bc..47fddcb6e 100644
--- a/src/video_core/renderer_opengl/util_shaders.cpp
+++ b/src/video_core/renderer_opengl/util_shaders.cpp
@@ -2,7 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <bit>
6#include <span> 5#include <span>
7#include <string_view> 6#include <string_view>
8 7
@@ -11,6 +10,7 @@
11#include "common/assert.h" 10#include "common/assert.h"
12#include "common/common_types.h" 11#include "common/common_types.h"
13#include "common/div_ceil.h" 12#include "common/div_ceil.h"
13#include "video_core/host_shaders/astc_decoder_comp.h"
14#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" 14#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h"
15#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" 15#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h"
16#include "video_core/host_shaders/opengl_copy_bc4_comp.h" 16#include "video_core/host_shaders/opengl_copy_bc4_comp.h"
@@ -20,16 +20,18 @@
20#include "video_core/renderer_opengl/gl_shader_manager.h" 20#include "video_core/renderer_opengl/gl_shader_manager.h"
21#include "video_core/renderer_opengl/gl_texture_cache.h" 21#include "video_core/renderer_opengl/gl_texture_cache.h"
22#include "video_core/renderer_opengl/util_shaders.h" 22#include "video_core/renderer_opengl/util_shaders.h"
23#include "video_core/surface.h"
24#include "video_core/texture_cache/accelerated_swizzle.h" 23#include "video_core/texture_cache/accelerated_swizzle.h"
25#include "video_core/texture_cache/types.h" 24#include "video_core/texture_cache/types.h"
26#include "video_core/texture_cache/util.h" 25#include "video_core/texture_cache/util.h"
26#include "video_core/textures/astc.h"
27#include "video_core/textures/decoders.h" 27#include "video_core/textures/decoders.h"
28 28
29namespace OpenGL { 29namespace OpenGL {
30 30
31using namespace HostShaders; 31using namespace HostShaders;
32using namespace Tegra::Texture::ASTC;
32 33
34using VideoCommon::Extent2D;
33using VideoCommon::Extent3D; 35using VideoCommon::Extent3D;
34using VideoCommon::ImageCopy; 36using VideoCommon::ImageCopy;
35using VideoCommon::ImageType; 37using VideoCommon::ImageType;
@@ -57,7 +59,7 @@ size_t NumPixelsInCopy(const VideoCommon::ImageCopy& copy) {
57} // Anonymous namespace 59} // Anonymous namespace
58 60
59UtilShaders::UtilShaders(ProgramManager& program_manager_) 61UtilShaders::UtilShaders(ProgramManager& program_manager_)
60 : program_manager{program_manager_}, 62 : program_manager{program_manager_}, astc_decoder_program(MakeProgram(ASTC_DECODER_COMP)),
61 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), 63 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)),
62 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), 64 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)),
63 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), 65 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)),
@@ -65,11 +67,79 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
65 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { 67 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) {
66 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); 68 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
67 swizzle_table_buffer.Create(); 69 swizzle_table_buffer.Create();
70 astc_buffer.Create();
68 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); 71 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
72 glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_BUFFER_DATA), &ASTC_BUFFER_DATA, 0);
69} 73}
70 74
71UtilShaders::~UtilShaders() = default; 75UtilShaders::~UtilShaders() = default;
72 76
77void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
78 std::span<const VideoCommon::SwizzleParameters> swizzles) {
79 static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
80 static constexpr GLuint BINDING_INPUT_BUFFER = 1;
81 static constexpr GLuint BINDING_ENC_BUFFER = 2;
82
83 static constexpr GLuint BINDING_6_TO_8_BUFFER = 3;
84 static constexpr GLuint BINDING_7_TO_8_BUFFER = 4;
85 static constexpr GLuint BINDING_8_TO_8_BUFFER = 5;
86 static constexpr GLuint BINDING_BYTE_TO_16_BUFFER = 6;
87
88 static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
89
90 const Extent2D tile_size{
91 .width = VideoCore::Surface::DefaultBlockWidth(image.info.format),
92 .height = VideoCore::Surface::DefaultBlockHeight(image.info.format),
93 };
94 program_manager.BindHostCompute(astc_decoder_program.handle);
95 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
96 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle,
97 offsetof(AstcBufferData, encoding_values),
98 sizeof(AstcBufferData::encoding_values));
99 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_6_TO_8_BUFFER, astc_buffer.handle,
100 offsetof(AstcBufferData, replicate_6_to_8),
101 sizeof(AstcBufferData::replicate_6_to_8));
102 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_7_TO_8_BUFFER, astc_buffer.handle,
103 offsetof(AstcBufferData, replicate_7_to_8),
104 sizeof(AstcBufferData::replicate_7_to_8));
105 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_8_TO_8_BUFFER, astc_buffer.handle,
106 offsetof(AstcBufferData, replicate_8_to_8),
107 sizeof(AstcBufferData::replicate_8_to_8));
108 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_BYTE_TO_16_BUFFER, astc_buffer.handle,
109 offsetof(AstcBufferData, replicate_byte_to_16),
110 sizeof(AstcBufferData::replicate_byte_to_16));
111
112 glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
113 glUniform2ui(1, tile_size.width, tile_size.height);
114 // Ensure buffer data is valid before dispatching
115 glFlush();
116 for (const SwizzleParameters& swizzle : swizzles) {
117 const size_t input_offset = swizzle.buffer_offset + map.offset;
118 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
119 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
120
121 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
122 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
123 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
124
125 glUniform1ui(2, params.bytes_per_block_log2);
126 glUniform1ui(3, params.layer_stride);
127 glUniform1ui(4, params.block_size);
128 glUniform1ui(5, params.x_shift);
129 glUniform1ui(6, params.block_height);
130 glUniform1ui(7, params.block_height_mask);
131
132 glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
133 GL_WRITE_ONLY, GL_RGBA8);
134 // ASTC texture data
135 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
136 image.guest_size_bytes - swizzle.buffer_offset);
137
138 glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
139 }
140 program_manager.RestoreGuestCompute();
141}
142
73void UtilShaders::BlockLinearUpload2D(Image& image, const ImageBufferMap& map, 143void UtilShaders::BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
74 std::span<const SwizzleParameters> swizzles) { 144 std::span<const SwizzleParameters> swizzles) {
75 static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1}; 145 static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1};
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h
index 93b009743..53d65f368 100644
--- a/src/video_core/renderer_opengl/util_shaders.h
+++ b/src/video_core/renderer_opengl/util_shaders.h
@@ -40,6 +40,9 @@ public:
40 explicit UtilShaders(ProgramManager& program_manager); 40 explicit UtilShaders(ProgramManager& program_manager);
41 ~UtilShaders(); 41 ~UtilShaders();
42 42
43 void ASTCDecode(Image& image, const ImageBufferMap& map,
44 std::span<const VideoCommon::SwizzleParameters> swizzles);
45
43 void BlockLinearUpload2D(Image& image, const ImageBufferMap& map, 46 void BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
44 std::span<const VideoCommon::SwizzleParameters> swizzles); 47 std::span<const VideoCommon::SwizzleParameters> swizzles);
45 48
@@ -59,7 +62,9 @@ private:
59 ProgramManager& program_manager; 62 ProgramManager& program_manager;
60 63
61 OGLBuffer swizzle_table_buffer; 64 OGLBuffer swizzle_table_buffer;
65 OGLBuffer astc_buffer;
62 66
67 OGLProgram astc_decoder_program;
63 OGLProgram block_linear_unswizzle_2d_program; 68 OGLProgram block_linear_unswizzle_2d_program;
64 OGLProgram block_linear_unswizzle_3d_program; 69 OGLProgram block_linear_unswizzle_3d_program;
65 OGLProgram pitch_unswizzle_program; 70 OGLProgram pitch_unswizzle_program;
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 19aaf034f..f088447e9 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -166,7 +166,7 @@ struct FormatTuple {
166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT 166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT
167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM 167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT 168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
169 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB 169 {VK_FORMAT_A8B8G8R8_SRGB_PACK32, Attachable}, // A8B8G8R8_SRGB
170 {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM 170 {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM
171 {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM 171 {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM
172 {VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT 172 {VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 2f9a7b028..e11406e58 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -11,18 +11,39 @@
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/div_ceil.h" 13#include "common/div_ceil.h"
14#include "video_core/host_shaders/astc_decoder_comp_spv.h"
14#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h" 15#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
15#include "video_core/host_shaders/vulkan_uint8_comp_spv.h" 16#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
16#include "video_core/renderer_vulkan/vk_compute_pass.h" 17#include "video_core/renderer_vulkan/vk_compute_pass.h"
17#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 18#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
18#include "video_core/renderer_vulkan/vk_scheduler.h" 19#include "video_core/renderer_vulkan/vk_scheduler.h"
19#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 20#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
21#include "video_core/renderer_vulkan/vk_texture_cache.h"
20#include "video_core/renderer_vulkan/vk_update_descriptor.h" 22#include "video_core/renderer_vulkan/vk_update_descriptor.h"
23#include "video_core/texture_cache/accelerated_swizzle.h"
24#include "video_core/texture_cache/types.h"
25#include "video_core/textures/astc.h"
26#include "video_core/textures/decoders.h"
21#include "video_core/vulkan_common/vulkan_device.h" 27#include "video_core/vulkan_common/vulkan_device.h"
22#include "video_core/vulkan_common/vulkan_wrapper.h" 28#include "video_core/vulkan_common/vulkan_wrapper.h"
23 29
24namespace Vulkan { 30namespace Vulkan {
31
32using Tegra::Texture::SWIZZLE_TABLE;
33using Tegra::Texture::ASTC::EncodingsValues;
34using namespace Tegra::Texture::ASTC;
35
25namespace { 36namespace {
37
38constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
39constexpr u32 ASTC_BINDING_ENC_BUFFER = 1;
40constexpr u32 ASTC_BINDING_6_TO_8_BUFFER = 2;
41constexpr u32 ASTC_BINDING_7_TO_8_BUFFER = 3;
42constexpr u32 ASTC_BINDING_8_TO_8_BUFFER = 4;
43constexpr u32 ASTC_BINDING_BYTE_TO_16_BUFFER = 5;
44constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 6;
45constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 7;
46
26VkPushConstantRange BuildComputePushConstantRange(std::size_t size) { 47VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
27 return { 48 return {
28 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, 49 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
@@ -50,6 +71,67 @@ std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBinding
50 }}; 71 }};
51} 72}
52 73
74std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
75 return {{
76 {
77 .binding = ASTC_BINDING_INPUT_BUFFER,
78 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
79 .descriptorCount = 1,
80 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
81 .pImmutableSamplers = nullptr,
82 },
83 {
84 .binding = ASTC_BINDING_ENC_BUFFER,
85 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
86 .descriptorCount = 1,
87 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
88 .pImmutableSamplers = nullptr,
89 },
90 {
91 .binding = ASTC_BINDING_6_TO_8_BUFFER,
92 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
93 .descriptorCount = 1,
94 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
95 .pImmutableSamplers = nullptr,
96 },
97 {
98 .binding = ASTC_BINDING_7_TO_8_BUFFER,
99 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
100 .descriptorCount = 1,
101 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
102 .pImmutableSamplers = nullptr,
103 },
104 {
105 .binding = ASTC_BINDING_8_TO_8_BUFFER,
106 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
107 .descriptorCount = 1,
108 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
109 .pImmutableSamplers = nullptr,
110 },
111 {
112 .binding = ASTC_BINDING_BYTE_TO_16_BUFFER,
113 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
114 .descriptorCount = 1,
115 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
116 .pImmutableSamplers = nullptr,
117 },
118 {
119 .binding = ASTC_BINDING_SWIZZLE_BUFFER,
120 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
121 .descriptorCount = 1,
122 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
123 .pImmutableSamplers = nullptr,
124 },
125 {
126 .binding = ASTC_BINDING_OUTPUT_IMAGE,
127 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
128 .descriptorCount = 1,
129 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
130 .pImmutableSamplers = nullptr,
131 },
132 }};
133}
134
53VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() { 135VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
54 return { 136 return {
55 .dstBinding = 0, 137 .dstBinding = 0,
@@ -61,6 +143,94 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
61 }; 143 };
62} 144}
63 145
146std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateTemplateEntry() {
147 return {{
148 {
149 .dstBinding = ASTC_BINDING_INPUT_BUFFER,
150 .dstArrayElement = 0,
151 .descriptorCount = 1,
152 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
153 .offset = ASTC_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
154 .stride = sizeof(DescriptorUpdateEntry),
155 },
156 {
157 .dstBinding = ASTC_BINDING_ENC_BUFFER,
158 .dstArrayElement = 0,
159 .descriptorCount = 1,
160 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
161 .offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
162 .stride = sizeof(DescriptorUpdateEntry),
163 },
164 {
165 .dstBinding = ASTC_BINDING_6_TO_8_BUFFER,
166 .dstArrayElement = 0,
167 .descriptorCount = 1,
168 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
169 .offset = ASTC_BINDING_6_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
170 .stride = sizeof(DescriptorUpdateEntry),
171 },
172 {
173 .dstBinding = ASTC_BINDING_7_TO_8_BUFFER,
174 .dstArrayElement = 0,
175 .descriptorCount = 1,
176 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
177 .offset = ASTC_BINDING_7_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
178 .stride = sizeof(DescriptorUpdateEntry),
179 },
180 {
181 .dstBinding = ASTC_BINDING_8_TO_8_BUFFER,
182 .dstArrayElement = 0,
183 .descriptorCount = 1,
184 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
185 .offset = ASTC_BINDING_8_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
186 .stride = sizeof(DescriptorUpdateEntry),
187 },
188 {
189 .dstBinding = ASTC_BINDING_BYTE_TO_16_BUFFER,
190 .dstArrayElement = 0,
191 .descriptorCount = 1,
192 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
193 .offset = ASTC_BINDING_BYTE_TO_16_BUFFER * sizeof(DescriptorUpdateEntry),
194 .stride = sizeof(DescriptorUpdateEntry),
195 },
196 {
197 .dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
198 .dstArrayElement = 0,
199 .descriptorCount = 1,
200 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
201 .offset = ASTC_BINDING_SWIZZLE_BUFFER * sizeof(DescriptorUpdateEntry),
202 .stride = sizeof(DescriptorUpdateEntry),
203 },
204 {
205 .dstBinding = ASTC_BINDING_OUTPUT_IMAGE,
206 .dstArrayElement = 0,
207 .descriptorCount = 1,
208 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
209 .offset = ASTC_BINDING_OUTPUT_IMAGE * sizeof(DescriptorUpdateEntry),
210 .stride = sizeof(DescriptorUpdateEntry),
211 },
212 }};
213}
214
215struct AstcPushConstants {
216 std::array<u32, 2> blocks_dims;
217 u32 bytes_per_block_log2;
218 u32 layer_stride;
219 u32 block_size;
220 u32 x_shift;
221 u32 block_height;
222 u32 block_height_mask;
223};
224
225struct AstcBufferData {
226 decltype(SWIZZLE_TABLE) swizzle_table_buffer = SWIZZLE_TABLE;
227 decltype(EncodingsValues) encoding_values = EncodingsValues;
228 decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
229 decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
230 decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
231 decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
232} constexpr ASTC_BUFFER_DATA;
233
64} // Anonymous namespace 234} // Anonymous namespace
65 235
66VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool, 236VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool,
@@ -238,4 +408,167 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
238 return {staging.buffer, staging.offset}; 408 return {staging.buffer, staging.offset};
239} 409}
240 410
411ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
412 VKDescriptorPool& descriptor_pool_,
413 StagingBufferPool& staging_buffer_pool_,
414 VKUpdateDescriptorQueue& update_descriptor_queue_,
415 MemoryAllocator& memory_allocator_)
416 : VKComputePass(device_, descriptor_pool_, BuildASTCDescriptorSetBindings(),
417 BuildASTCPassDescriptorUpdateTemplateEntry(),
418 BuildComputePushConstantRange(sizeof(AstcPushConstants)),
419 ASTC_DECODER_COMP_SPV),
420 device{device_}, scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
421 update_descriptor_queue{update_descriptor_queue_}, memory_allocator{memory_allocator_} {}
422
423ASTCDecoderPass::~ASTCDecoderPass() = default;
424
425void ASTCDecoderPass::MakeDataBuffer() {
426 constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_BUFFER_DATA) + sizeof(SWIZZLE_TABLE);
427 data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
428 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
429 .pNext = nullptr,
430 .flags = 0,
431 .size = TOTAL_BUFFER_SIZE,
432 .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
433 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
434 .queueFamilyIndexCount = 0,
435 .pQueueFamilyIndices = nullptr,
436 });
437 data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
438
439 const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
440 std::memcpy(staging_ref.mapped_span.data(), &ASTC_BUFFER_DATA, sizeof(ASTC_BUFFER_DATA));
441 // Tack on the swizzle table at the end of the buffer
442 std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_BUFFER_DATA), &SWIZZLE_TABLE,
443 sizeof(SWIZZLE_TABLE));
444
445 scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
446 TOTAL_BUFFER_SIZE](vk::CommandBuffer cmdbuf) {
447 cmdbuf.CopyBuffer(src, dst,
448 VkBufferCopy{
449 .srcOffset = offset,
450 .dstOffset = 0,
451 .size = TOTAL_BUFFER_SIZE,
452 });
453 cmdbuf.PipelineBarrier(
454 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
455 VkMemoryBarrier{
456 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
457 .pNext = nullptr,
458 .srcAccessMask = 0,
459 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
460 });
461 });
462}
463
464void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
465 std::span<const VideoCommon::SwizzleParameters> swizzles) {
466 using namespace VideoCommon::Accelerated;
467 const std::array<u32, 2> block_dims{
468 VideoCore::Surface::DefaultBlockWidth(image.info.format),
469 VideoCore::Surface::DefaultBlockHeight(image.info.format),
470 };
471 scheduler.RequestOutsideRenderPassOperationContext();
472 if (!data_buffer) {
473 MakeDataBuffer();
474 }
475 const VkPipeline vk_pipeline = *pipeline;
476 const VkImageAspectFlags aspect_mask = image.AspectMask();
477 const VkImage vk_image = image.Handle();
478 const bool is_initialized = image.ExchangeInitialization();
479 scheduler.Record(
480 [vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
481 const VkImageMemoryBarrier image_barrier{
482 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
483 .pNext = nullptr,
484 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
485 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
486 .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
487 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
488 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
489 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
490 .image = vk_image,
491 .subresourceRange{
492 .aspectMask = aspect_mask,
493 .baseMipLevel = 0,
494 .levelCount = VK_REMAINING_MIP_LEVELS,
495 .baseArrayLayer = 0,
496 .layerCount = VK_REMAINING_ARRAY_LAYERS,
497 },
498 };
499 cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : 0,
500 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
501 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
502 });
503 for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
504 const size_t input_offset = swizzle.buffer_offset + map.offset;
505 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
506 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
507 const u32 num_dispatches_z = image.info.resources.layers;
508
509 update_descriptor_queue.Acquire();
510 update_descriptor_queue.AddBuffer(map.buffer, input_offset,
511 image.guest_size_bytes - swizzle.buffer_offset);
512 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, encoding_values),
513 sizeof(AstcBufferData::encoding_values));
514 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_6_to_8),
515 sizeof(AstcBufferData::replicate_6_to_8));
516 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_7_to_8),
517 sizeof(AstcBufferData::replicate_7_to_8));
518 update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_8_to_8),
519 sizeof(AstcBufferData::replicate_8_to_8));
520 update_descriptor_queue.AddBuffer(*data_buffer,
521 offsetof(AstcBufferData, replicate_byte_to_16),
522 sizeof(AstcBufferData::replicate_byte_to_16));
523 update_descriptor_queue.AddBuffer(*data_buffer, sizeof(AstcBufferData),
524 sizeof(SWIZZLE_TABLE));
525 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
526
527 const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
528 const VkPipelineLayout vk_layout = *layout;
529
530 // To unswizzle the ASTC data
531 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
532 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
533 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
534 scheduler.Record([vk_layout, num_dispatches_x, num_dispatches_y, num_dispatches_z,
535 block_dims, params, set](vk::CommandBuffer cmdbuf) {
536 const AstcPushConstants uniforms{
537 .blocks_dims = block_dims,
538 .bytes_per_block_log2 = params.bytes_per_block_log2,
539 .layer_stride = params.layer_stride,
540 .block_size = params.block_size,
541 .x_shift = params.x_shift,
542 .block_height = params.block_height,
543 .block_height_mask = params.block_height_mask,
544 };
545 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, vk_layout, 0, set, {});
546 cmdbuf.PushConstants(vk_layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
547 cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_dispatches_z);
548 });
549 }
550 scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
551 const VkImageMemoryBarrier image_barrier{
552 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
553 .pNext = nullptr,
554 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
555 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
556 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
557 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
558 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
559 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
560 .image = vk_image,
561 .subresourceRange{
562 .aspectMask = aspect_mask,
563 .baseMipLevel = 0,
564 .levelCount = VK_REMAINING_MIP_LEVELS,
565 .baseArrayLayer = 0,
566 .layerCount = VK_REMAINING_ARRAY_LAYERS,
567 },
568 };
569 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
570 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, image_barrier);
571 });
572}
573
241} // namespace Vulkan 574} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 17d781d99..5ea187c30 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -11,14 +11,21 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
13#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 13#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
14#include "video_core/vulkan_common/vulkan_memory_allocator.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
15 16
17namespace VideoCommon {
18struct SwizzleParameters;
19}
20
16namespace Vulkan { 21namespace Vulkan {
17 22
18class Device; 23class Device;
19class StagingBufferPool; 24class StagingBufferPool;
20class VKScheduler; 25class VKScheduler;
21class VKUpdateDescriptorQueue; 26class VKUpdateDescriptorQueue;
27class Image;
28struct StagingBufferRef;
22 29
23class VKComputePass { 30class VKComputePass {
24public: 31public:
@@ -77,4 +84,29 @@ private:
77 VKUpdateDescriptorQueue& update_descriptor_queue; 84 VKUpdateDescriptorQueue& update_descriptor_queue;
78}; 85};
79 86
87class ASTCDecoderPass final : public VKComputePass {
88public:
89 explicit ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
90 VKDescriptorPool& descriptor_pool_,
91 StagingBufferPool& staging_buffer_pool_,
92 VKUpdateDescriptorQueue& update_descriptor_queue_,
93 MemoryAllocator& memory_allocator_);
94 ~ASTCDecoderPass();
95
96 void Assemble(Image& image, const StagingBufferRef& map,
97 std::span<const VideoCommon::SwizzleParameters> swizzles);
98
99private:
100 void MakeDataBuffer();
101
102 const Device& device;
103 VKScheduler& scheduler;
104 StagingBufferPool& staging_buffer_pool;
105 VKUpdateDescriptorQueue& update_descriptor_queue;
106 MemoryAllocator& memory_allocator;
107
108 vk::Buffer data_buffer;
109 MemoryCommit data_buffer_commit;
110};
111
80} // namespace Vulkan 112} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index dfd38f575..df5b7b172 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -241,7 +241,10 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
241 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), 241 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
242 update_descriptor_queue(device, scheduler), 242 update_descriptor_queue(device, scheduler),
243 blit_image(device, scheduler, state_tracker, descriptor_pool), 243 blit_image(device, scheduler, state_tracker, descriptor_pool),
244 texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image}, 244 astc_decoder_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue,
245 memory_allocator),
246 texture_cache_runtime{device, scheduler, memory_allocator,
247 staging_pool, blit_image, astc_decoder_pass},
245 texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), 248 texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory),
246 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool, 249 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
247 update_descriptor_queue, descriptor_pool), 250 update_descriptor_queue, descriptor_pool),
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index acea1ba2d..235afc6f3 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -173,6 +173,7 @@ private:
173 VKDescriptorPool descriptor_pool; 173 VKDescriptorPool descriptor_pool;
174 VKUpdateDescriptorQueue update_descriptor_queue; 174 VKUpdateDescriptorQueue update_descriptor_queue;
175 BlitImageHelper blit_image; 175 BlitImageHelper blit_image;
176 ASTCDecoderPass astc_decoder_pass;
176 177
177 GraphicsPipelineCacheKey graphics_key; 178 GraphicsPipelineCacheKey graphics_key;
178 179
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 22a1014a9..18155e449 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -10,6 +10,7 @@
10#include "video_core/engines/fermi_2d.h" 10#include "video_core/engines/fermi_2d.h"
11#include "video_core/renderer_vulkan/blit_image.h" 11#include "video_core/renderer_vulkan/blit_image.h"
12#include "video_core/renderer_vulkan/maxwell_to_vk.h" 12#include "video_core/renderer_vulkan/maxwell_to_vk.h"
13#include "video_core/renderer_vulkan/vk_compute_pass.h"
13#include "video_core/renderer_vulkan/vk_rasterizer.h" 14#include "video_core/renderer_vulkan/vk_rasterizer.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h" 15#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 16#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -807,7 +808,7 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
807 commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); 808 commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
808 } 809 }
809 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { 810 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
810 flags |= VideoCommon::ImageFlagBits::Converted; 811 flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
811 } 812 }
812 if (runtime.device.HasDebuggingToolAttached()) { 813 if (runtime.device.HasDebuggingToolAttached()) {
813 if (image) { 814 if (image) {
@@ -816,6 +817,38 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
816 buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); 817 buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
817 } 818 }
818 } 819 }
820 static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
821 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
822 .pNext = nullptr,
823 .usage = VK_IMAGE_USAGE_STORAGE_BIT,
824 };
825 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
826 const auto& device = runtime.device.GetLogical();
827 storage_image_views.reserve(info.resources.levels);
828 for (s32 level = 0; level < info.resources.levels; ++level) {
829 storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{
830 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
831 .pNext = &storage_image_view_usage_create_info,
832 .flags = 0,
833 .image = *image,
834 .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
835 .format = VK_FORMAT_A8B8G8R8_UNORM_PACK32,
836 .components{
837 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
838 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
839 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
840 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
841 },
842 .subresourceRange{
843 .aspectMask = aspect_mask,
844 .baseMipLevel = static_cast<u32>(level),
845 .levelCount = 1,
846 .baseArrayLayer = 0,
847 .layerCount = VK_REMAINING_ARRAY_LAYERS,
848 },
849 }));
850 }
851 }
819} 852}
820 853
821void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) { 854void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
@@ -918,7 +951,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
918 } 951 }
919 } 952 }
920 const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); 953 const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
921 const VkFormat vk_format = format_info.format;
922 const VkImageViewUsageCreateInfo image_view_usage{ 954 const VkImageViewUsageCreateInfo image_view_usage{
923 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, 955 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
924 .pNext = nullptr, 956 .pNext = nullptr,
@@ -930,7 +962,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
930 .flags = 0, 962 .flags = 0,
931 .image = image.Handle(), 963 .image = image.Handle(),
932 .viewType = VkImageViewType{}, 964 .viewType = VkImageViewType{},
933 .format = vk_format, 965 .format = format_info.format,
934 .components{ 966 .components{
935 .r = ComponentSwizzle(swizzle[0]), 967 .r = ComponentSwizzle(swizzle[0]),
936 .g = ComponentSwizzle(swizzle[1]), 968 .g = ComponentSwizzle(swizzle[1]),
@@ -982,7 +1014,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
982 .pNext = nullptr, 1014 .pNext = nullptr,
983 .flags = 0, 1015 .flags = 0,
984 .buffer = image.Buffer(), 1016 .buffer = image.Buffer(),
985 .format = vk_format, 1017 .format = format_info.format,
986 .offset = 0, // TODO: Redesign buffer cache to support this 1018 .offset = 0, // TODO: Redesign buffer cache to support this
987 .range = image.guest_size_bytes, 1019 .range = image.guest_size_bytes,
988 }); 1020 });
@@ -1167,4 +1199,13 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1167 } 1199 }
1168} 1200}
1169 1201
1202void TextureCacheRuntime::AccelerateImageUpload(
1203 Image& image, const StagingBufferRef& map,
1204 std::span<const VideoCommon::SwizzleParameters> swizzles) {
1205 if (IsPixelFormatASTC(image.info.format)) {
1206 return astc_decoder_pass.Assemble(image, map, swizzles);
1207 }
1208 UNREACHABLE();
1209}
1210
1170} // namespace Vulkan 1211} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 3aee27ce0..628785d5e 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -20,6 +20,7 @@ using VideoCommon::Offset2D;
20using VideoCommon::RenderTargets; 20using VideoCommon::RenderTargets;
21using VideoCore::Surface::PixelFormat; 21using VideoCore::Surface::PixelFormat;
22 22
23class ASTCDecoderPass;
23class BlitImageHelper; 24class BlitImageHelper;
24class Device; 25class Device;
25class Image; 26class Image;
@@ -60,6 +61,7 @@ struct TextureCacheRuntime {
60 MemoryAllocator& memory_allocator; 61 MemoryAllocator& memory_allocator;
61 StagingBufferPool& staging_buffer_pool; 62 StagingBufferPool& staging_buffer_pool;
62 BlitImageHelper& blit_image_helper; 63 BlitImageHelper& blit_image_helper;
64 ASTCDecoderPass& astc_decoder_pass;
63 std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache{}; 65 std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache{};
64 66
65 void Finish(); 67 void Finish();
@@ -83,9 +85,7 @@ struct TextureCacheRuntime {
83 } 85 }
84 86
85 void AccelerateImageUpload(Image&, const StagingBufferRef&, 87 void AccelerateImageUpload(Image&, const StagingBufferRef&,
86 std::span<const VideoCommon::SwizzleParameters>) { 88 std::span<const VideoCommon::SwizzleParameters>);
87 UNREACHABLE();
88 }
89 89
90 void InsertUploadMemoryBarrier() {} 90 void InsertUploadMemoryBarrier() {}
91 91
@@ -121,15 +121,26 @@ public:
121 return *buffer; 121 return *buffer;
122 } 122 }
123 123
124 [[nodiscard]] VkImageCreateFlags AspectMask() const noexcept { 124 [[nodiscard]] VkImageAspectFlags AspectMask() const noexcept {
125 return aspect_mask; 125 return aspect_mask;
126 } 126 }
127 127
128 [[nodiscard]] VkImageView StorageImageView(s32 level) const noexcept {
129 return *storage_image_views[level];
130 }
131
132 /// Returns true when the image is already initialized and mark it as initialized
133 [[nodiscard]] bool ExchangeInitialization() noexcept {
134 return std::exchange(initialized, true);
135 }
136
128private: 137private:
129 VKScheduler* scheduler; 138 VKScheduler* scheduler;
130 vk::Image image; 139 vk::Image image;
131 vk::Buffer buffer; 140 vk::Buffer buffer;
132 MemoryCommit commit; 141 MemoryCommit commit;
142 vk::ImageView image_view;
143 std::vector<vk::ImageView> storage_image_views;
133 VkImageAspectFlags aspect_mask = 0; 144 VkImageAspectFlags aspect_mask = 0;
134 bool initialized = false; 145 bool initialized = false;
135}; 146};
diff --git a/src/video_core/texture_cache/accelerated_swizzle.h b/src/video_core/texture_cache/accelerated_swizzle.h
index 6ec5c78c4..a11c924e1 100644
--- a/src/video_core/texture_cache/accelerated_swizzle.h
+++ b/src/video_core/texture_cache/accelerated_swizzle.h
@@ -13,8 +13,8 @@
13namespace VideoCommon::Accelerated { 13namespace VideoCommon::Accelerated {
14 14
15struct BlockLinearSwizzle2DParams { 15struct BlockLinearSwizzle2DParams {
16 std::array<u32, 3> origin; 16 alignas(16) std::array<u32, 3> origin;
17 std::array<s32, 3> destination; 17 alignas(16) std::array<s32, 3> destination;
18 u32 bytes_per_block_log2; 18 u32 bytes_per_block_log2;
19 u32 layer_stride; 19 u32 layer_stride;
20 u32 block_size; 20 u32 block_size;
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index 2c42d1449..c22dd0148 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -47,7 +47,6 @@
47#include "video_core/texture_cache/formatter.h" 47#include "video_core/texture_cache/formatter.h"
48#include "video_core/texture_cache/samples_helper.h" 48#include "video_core/texture_cache/samples_helper.h"
49#include "video_core/texture_cache/util.h" 49#include "video_core/texture_cache/util.h"
50#include "video_core/textures/astc.h"
51#include "video_core/textures/decoders.h" 50#include "video_core/textures/decoders.h"
52 51
53namespace VideoCommon { 52namespace VideoCommon {
@@ -879,17 +878,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
879 ASSERT(copy.image_extent == mip_size); 878 ASSERT(copy.image_extent == mip_size);
880 ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width)); 879 ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width));
881 ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height)); 880 ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height));
882 881 DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
883 if (IsPixelFormatASTC(info.format)) { 882 output.subspan(output_offset));
884 ASSERT(copy.image_extent.depth == 1);
885 Tegra::Texture::ASTC::Decompress(input.subspan(copy.buffer_offset),
886 copy.image_extent.width, copy.image_extent.height,
887 copy.image_subresource.num_layers, tile_size.width,
888 tile_size.height, output.subspan(output_offset));
889 } else {
890 DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
891 output.subspan(output_offset));
892 }
893 copy.buffer_offset = output_offset; 883 copy.buffer_offset = output_offset;
894 copy.buffer_row_length = mip_size.width; 884 copy.buffer_row_length = mip_size.width;
895 copy.buffer_image_height = mip_size.height; 885 copy.buffer_image_height = mip_size.height;
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
deleted file mode 100644
index 3625b666c..000000000
--- a/src/video_core/textures/astc.cpp
+++ /dev/null
@@ -1,1710 +0,0 @@
1// Copyright 2016 The University of North Carolina at Chapel Hill
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
16// <http://gamma.cs.unc.edu/FasTC/>
17
18#include <algorithm>
19#include <cassert>
20#include <cstring>
21#include <span>
22#include <vector>
23
24#include <boost/container/static_vector.hpp>
25
26#include "common/common_types.h"
27
28#include "video_core/textures/astc.h"
29
30namespace {
31
32/// Count the number of bits set in a number.
33constexpr u32 Popcnt(u32 n) {
34 u32 c = 0;
35 for (; n; c++) {
36 n &= n - 1;
37 }
38 return c;
39}
40
41} // Anonymous namespace
42
43class InputBitStream {
44public:
45 constexpr explicit InputBitStream(std::span<const u8> data, size_t start_offset = 0)
46 : cur_byte{data.data()}, total_bits{data.size()}, next_bit{start_offset % 8} {}
47
48 constexpr size_t GetBitsRead() const {
49 return bits_read;
50 }
51
52 constexpr bool ReadBit() {
53 if (bits_read >= total_bits * 8) {
54 return 0;
55 }
56 const bool bit = ((*cur_byte >> next_bit) & 1) != 0;
57 ++next_bit;
58 while (next_bit >= 8) {
59 next_bit -= 8;
60 ++cur_byte;
61 }
62 ++bits_read;
63 return bit;
64 }
65
66 constexpr u32 ReadBits(std::size_t nBits) {
67 u32 ret = 0;
68 for (std::size_t i = 0; i < nBits; ++i) {
69 ret |= (ReadBit() & 1) << i;
70 }
71 return ret;
72 }
73
74 template <std::size_t nBits>
75 constexpr u32 ReadBits() {
76 u32 ret = 0;
77 for (std::size_t i = 0; i < nBits; ++i) {
78 ret |= (ReadBit() & 1) << i;
79 }
80 return ret;
81 }
82
83private:
84 const u8* cur_byte;
85 size_t total_bits = 0;
86 size_t next_bit = 0;
87 size_t bits_read = 0;
88};
89
90class OutputBitStream {
91public:
92 constexpr explicit OutputBitStream(u8* ptr, std::size_t bits = 0, std::size_t start_offset = 0)
93 : cur_byte{ptr}, num_bits{bits}, next_bit{start_offset % 8} {}
94
95 constexpr std::size_t GetBitsWritten() const {
96 return bits_written;
97 }
98
99 constexpr void WriteBitsR(u32 val, u32 nBits) {
100 for (u32 i = 0; i < nBits; i++) {
101 WriteBit((val >> (nBits - i - 1)) & 1);
102 }
103 }
104
105 constexpr void WriteBits(u32 val, u32 nBits) {
106 for (u32 i = 0; i < nBits; i++) {
107 WriteBit((val >> i) & 1);
108 }
109 }
110
111private:
112 constexpr void WriteBit(bool b) {
113 if (bits_written >= num_bits) {
114 return;
115 }
116
117 const u32 mask = 1 << next_bit++;
118
119 // clear the bit
120 *cur_byte &= static_cast<u8>(~mask);
121
122 // Write the bit, if necessary
123 if (b)
124 *cur_byte |= static_cast<u8>(mask);
125
126 // Next byte?
127 if (next_bit >= 8) {
128 cur_byte += 1;
129 next_bit = 0;
130 }
131 }
132
133 u8* cur_byte;
134 std::size_t num_bits;
135 std::size_t bits_written = 0;
136 std::size_t next_bit = 0;
137};
138
139template <typename IntType>
140class Bits {
141public:
142 explicit Bits(const IntType& v) : m_Bits(v) {}
143
144 Bits(const Bits&) = delete;
145 Bits& operator=(const Bits&) = delete;
146
147 u8 operator[](u32 bitPos) const {
148 return static_cast<u8>((m_Bits >> bitPos) & 1);
149 }
150
151 IntType operator()(u32 start, u32 end) const {
152 if (start == end) {
153 return (*this)[start];
154 } else if (start > end) {
155 u32 t = start;
156 start = end;
157 end = t;
158 }
159
160 u64 mask = (1 << (end - start + 1)) - 1;
161 return (m_Bits >> start) & static_cast<IntType>(mask);
162 }
163
164private:
165 const IntType& m_Bits;
166};
167
168enum class IntegerEncoding { JustBits, Qus32, Trit };
169
170struct IntegerEncodedValue {
171 constexpr IntegerEncodedValue() = default;
172
173 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
174 : encoding{encoding_}, num_bits{num_bits_} {}
175
176 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
177 return encoding == other.encoding && num_bits == other.num_bits;
178 }
179
180 // Returns the number of bits required to encode nVals values.
181 u32 GetBitLength(u32 nVals) const {
182 u32 totalBits = num_bits * nVals;
183 if (encoding == IntegerEncoding::Trit) {
184 totalBits += (nVals * 8 + 4) / 5;
185 } else if (encoding == IntegerEncoding::Qus32) {
186 totalBits += (nVals * 7 + 2) / 3;
187 }
188 return totalBits;
189 }
190
191 IntegerEncoding encoding{};
192 u32 num_bits = 0;
193 u32 bit_value = 0;
194 union {
195 u32 qus32_value = 0;
196 u32 trit_value;
197 };
198};
199using IntegerEncodedVector = boost::container::static_vector<
200 IntegerEncodedValue, 256,
201 boost::container::static_vector_options<
202 boost::container::inplace_alignment<alignof(IntegerEncodedValue)>,
203 boost::container::throw_on_overflow<false>>::type>;
204
205static void DecodeTritBlock(InputBitStream& bits, IntegerEncodedVector& result, u32 nBitsPerValue) {
206 // Implement the algorithm in section C.2.12
207 std::array<u32, 5> m;
208 std::array<u32, 5> t;
209 u32 T;
210
211 // Read the trit encoded block according to
212 // table C.2.14
213 m[0] = bits.ReadBits(nBitsPerValue);
214 T = bits.ReadBits<2>();
215 m[1] = bits.ReadBits(nBitsPerValue);
216 T |= bits.ReadBits<2>() << 2;
217 m[2] = bits.ReadBits(nBitsPerValue);
218 T |= bits.ReadBit() << 4;
219 m[3] = bits.ReadBits(nBitsPerValue);
220 T |= bits.ReadBits<2>() << 5;
221 m[4] = bits.ReadBits(nBitsPerValue);
222 T |= bits.ReadBit() << 7;
223
224 u32 C = 0;
225
226 Bits<u32> Tb(T);
227 if (Tb(2, 4) == 7) {
228 C = (Tb(5, 7) << 2) | Tb(0, 1);
229 t[4] = t[3] = 2;
230 } else {
231 C = Tb(0, 4);
232 if (Tb(5, 6) == 3) {
233 t[4] = 2;
234 t[3] = Tb[7];
235 } else {
236 t[4] = Tb[7];
237 t[3] = Tb(5, 6);
238 }
239 }
240
241 Bits<u32> Cb(C);
242 if (Cb(0, 1) == 3) {
243 t[2] = 2;
244 t[1] = Cb[4];
245 t[0] = (Cb[3] << 1) | (Cb[2] & ~Cb[3]);
246 } else if (Cb(2, 3) == 3) {
247 t[2] = 2;
248 t[1] = 2;
249 t[0] = Cb(0, 1);
250 } else {
251 t[2] = Cb[4];
252 t[1] = Cb(2, 3);
253 t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]);
254 }
255
256 for (std::size_t i = 0; i < 5; ++i) {
257 IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Trit, nBitsPerValue);
258 val.bit_value = m[i];
259 val.trit_value = t[i];
260 }
261}
262
263static void DecodeQus32Block(InputBitStream& bits, IntegerEncodedVector& result,
264 u32 nBitsPerValue) {
265 // Implement the algorithm in section C.2.12
266 u32 m[3];
267 u32 q[3];
268 u32 Q;
269
270 // Read the trit encoded block according to
271 // table C.2.15
272 m[0] = bits.ReadBits(nBitsPerValue);
273 Q = bits.ReadBits<3>();
274 m[1] = bits.ReadBits(nBitsPerValue);
275 Q |= bits.ReadBits<2>() << 3;
276 m[2] = bits.ReadBits(nBitsPerValue);
277 Q |= bits.ReadBits<2>() << 5;
278
279 Bits<u32> Qb(Q);
280 if (Qb(1, 2) == 3 && Qb(5, 6) == 0) {
281 q[0] = q[1] = 4;
282 q[2] = (Qb[0] << 2) | ((Qb[4] & ~Qb[0]) << 1) | (Qb[3] & ~Qb[0]);
283 } else {
284 u32 C = 0;
285 if (Qb(1, 2) == 3) {
286 q[2] = 4;
287 C = (Qb(3, 4) << 3) | ((~Qb(5, 6) & 3) << 1) | Qb[0];
288 } else {
289 q[2] = Qb(5, 6);
290 C = Qb(0, 4);
291 }
292
293 Bits<u32> Cb(C);
294 if (Cb(0, 2) == 5) {
295 q[1] = 4;
296 q[0] = Cb(3, 4);
297 } else {
298 q[1] = Cb(3, 4);
299 q[0] = Cb(0, 2);
300 }
301 }
302
303 for (std::size_t i = 0; i < 3; ++i) {
304 IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Qus32, nBitsPerValue);
305 val.bit_value = m[i];
306 val.qus32_value = q[i];
307 }
308}
309
310// Returns a new instance of this struct that corresponds to the
311// can take no more than maxval values
312static constexpr IntegerEncodedValue CreateEncoding(u32 maxVal) {
313 while (maxVal > 0) {
314 u32 check = maxVal + 1;
315
316 // Is maxVal a power of two?
317 if (!(check & (check - 1))) {
318 return IntegerEncodedValue(IntegerEncoding::JustBits, Popcnt(maxVal));
319 }
320
321 // Is maxVal of the type 3*2^n - 1?
322 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
323 return IntegerEncodedValue(IntegerEncoding::Trit, Popcnt(check / 3 - 1));
324 }
325
326 // Is maxVal of the type 5*2^n - 1?
327 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
328 return IntegerEncodedValue(IntegerEncoding::Qus32, Popcnt(check / 5 - 1));
329 }
330
331 // Apparently it can't be represented with a bounded integer sequence...
332 // just iterate.
333 maxVal--;
334 }
335 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
336}
337
338static constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
339 std::array<IntegerEncodedValue, 256> encodings{};
340 for (std::size_t i = 0; i < encodings.size(); ++i) {
341 encodings[i] = CreateEncoding(static_cast<u32>(i));
342 }
343 return encodings;
344}
345
346static constexpr std::array EncodingsValues = MakeEncodedValues();
347
348// Fills result with the values that are encoded in the given
349// bitstream. We must know beforehand what the maximum possible
350// value is, and how many values we're decoding.
351static void DecodeIntegerSequence(IntegerEncodedVector& result, InputBitStream& bits, u32 maxRange,
352 u32 nValues) {
353 // Determine encoding parameters
354 IntegerEncodedValue val = EncodingsValues[maxRange];
355
356 // Start decoding
357 u32 nValsDecoded = 0;
358 while (nValsDecoded < nValues) {
359 switch (val.encoding) {
360 case IntegerEncoding::Qus32:
361 DecodeQus32Block(bits, result, val.num_bits);
362 nValsDecoded += 3;
363 break;
364
365 case IntegerEncoding::Trit:
366 DecodeTritBlock(bits, result, val.num_bits);
367 nValsDecoded += 5;
368 break;
369
370 case IntegerEncoding::JustBits:
371 val.bit_value = bits.ReadBits(val.num_bits);
372 result.push_back(val);
373 nValsDecoded++;
374 break;
375 }
376 }
377}
378
379namespace ASTCC {
380
381struct TexelWeightParams {
382 u32 m_Width = 0;
383 u32 m_Height = 0;
384 bool m_bDualPlane = false;
385 u32 m_MaxWeight = 0;
386 bool m_bError = false;
387 bool m_bVoidExtentLDR = false;
388 bool m_bVoidExtentHDR = false;
389
390 u32 GetPackedBitSize() const {
391 // How many indices do we have?
392 u32 nIdxs = m_Height * m_Width;
393 if (m_bDualPlane) {
394 nIdxs *= 2;
395 }
396
397 return EncodingsValues[m_MaxWeight].GetBitLength(nIdxs);
398 }
399
400 u32 GetNumWeightValues() const {
401 u32 ret = m_Width * m_Height;
402 if (m_bDualPlane) {
403 ret *= 2;
404 }
405 return ret;
406 }
407};
408
409static TexelWeightParams DecodeBlockInfo(InputBitStream& strm) {
410 TexelWeightParams params;
411
412 // Read the entire block mode all at once
413 u16 modeBits = static_cast<u16>(strm.ReadBits<11>());
414
415 // Does this match the void extent block mode?
416 if ((modeBits & 0x01FF) == 0x1FC) {
417 if (modeBits & 0x200) {
418 params.m_bVoidExtentHDR = true;
419 } else {
420 params.m_bVoidExtentLDR = true;
421 }
422
423 // Next two bits must be one.
424 if (!(modeBits & 0x400) || !strm.ReadBit()) {
425 params.m_bError = true;
426 }
427
428 return params;
429 }
430
431 // First check if the last four bits are zero
432 if ((modeBits & 0xF) == 0) {
433 params.m_bError = true;
434 return params;
435 }
436
437 // If the last two bits are zero, then if bits
438 // [6-8] are all ones, this is also reserved.
439 if ((modeBits & 0x3) == 0 && (modeBits & 0x1C0) == 0x1C0) {
440 params.m_bError = true;
441 return params;
442 }
443
444 // Otherwise, there is no error... Figure out the layout
445 // of the block mode. Layout is determined by a number
446 // between 0 and 9 corresponding to table C.2.8 of the
447 // ASTC spec.
448 u32 layout = 0;
449
450 if ((modeBits & 0x1) || (modeBits & 0x2)) {
451 // layout is in [0-4]
452 if (modeBits & 0x8) {
453 // layout is in [2-4]
454 if (modeBits & 0x4) {
455 // layout is in [3-4]
456 if (modeBits & 0x100) {
457 layout = 4;
458 } else {
459 layout = 3;
460 }
461 } else {
462 layout = 2;
463 }
464 } else {
465 // layout is in [0-1]
466 if (modeBits & 0x4) {
467 layout = 1;
468 } else {
469 layout = 0;
470 }
471 }
472 } else {
473 // layout is in [5-9]
474 if (modeBits & 0x100) {
475 // layout is in [7-9]
476 if (modeBits & 0x80) {
477 // layout is in [7-8]
478 assert((modeBits & 0x40) == 0U);
479 if (modeBits & 0x20) {
480 layout = 8;
481 } else {
482 layout = 7;
483 }
484 } else {
485 layout = 9;
486 }
487 } else {
488 // layout is in [5-6]
489 if (modeBits & 0x80) {
490 layout = 6;
491 } else {
492 layout = 5;
493 }
494 }
495 }
496
497 assert(layout < 10);
498
499 // Determine R
500 u32 R = !!(modeBits & 0x10);
501 if (layout < 5) {
502 R |= (modeBits & 0x3) << 1;
503 } else {
504 R |= (modeBits & 0xC) >> 1;
505 }
506 assert(2 <= R && R <= 7);
507
508 // Determine width & height
509 switch (layout) {
510 case 0: {
511 u32 A = (modeBits >> 5) & 0x3;
512 u32 B = (modeBits >> 7) & 0x3;
513 params.m_Width = B + 4;
514 params.m_Height = A + 2;
515 break;
516 }
517
518 case 1: {
519 u32 A = (modeBits >> 5) & 0x3;
520 u32 B = (modeBits >> 7) & 0x3;
521 params.m_Width = B + 8;
522 params.m_Height = A + 2;
523 break;
524 }
525
526 case 2: {
527 u32 A = (modeBits >> 5) & 0x3;
528 u32 B = (modeBits >> 7) & 0x3;
529 params.m_Width = A + 2;
530 params.m_Height = B + 8;
531 break;
532 }
533
534 case 3: {
535 u32 A = (modeBits >> 5) & 0x3;
536 u32 B = (modeBits >> 7) & 0x1;
537 params.m_Width = A + 2;
538 params.m_Height = B + 6;
539 break;
540 }
541
542 case 4: {
543 u32 A = (modeBits >> 5) & 0x3;
544 u32 B = (modeBits >> 7) & 0x1;
545 params.m_Width = B + 2;
546 params.m_Height = A + 2;
547 break;
548 }
549
550 case 5: {
551 u32 A = (modeBits >> 5) & 0x3;
552 params.m_Width = 12;
553 params.m_Height = A + 2;
554 break;
555 }
556
557 case 6: {
558 u32 A = (modeBits >> 5) & 0x3;
559 params.m_Width = A + 2;
560 params.m_Height = 12;
561 break;
562 }
563
564 case 7: {
565 params.m_Width = 6;
566 params.m_Height = 10;
567 break;
568 }
569
570 case 8: {
571 params.m_Width = 10;
572 params.m_Height = 6;
573 break;
574 }
575
576 case 9: {
577 u32 A = (modeBits >> 5) & 0x3;
578 u32 B = (modeBits >> 9) & 0x3;
579 params.m_Width = A + 6;
580 params.m_Height = B + 6;
581 break;
582 }
583
584 default:
585 assert(false && "Don't know this layout...");
586 params.m_bError = true;
587 break;
588 }
589
590 // Determine whether or not we're using dual planes
591 // and/or high precision layouts.
592 bool D = (layout != 9) && (modeBits & 0x400);
593 bool H = (layout != 9) && (modeBits & 0x200);
594
595 if (H) {
596 const u32 maxWeights[6] = {9, 11, 15, 19, 23, 31};
597 params.m_MaxWeight = maxWeights[R - 2];
598 } else {
599 const u32 maxWeights[6] = {1, 2, 3, 4, 5, 7};
600 params.m_MaxWeight = maxWeights[R - 2];
601 }
602
603 params.m_bDualPlane = D;
604
605 return params;
606}
607
608static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 blockWidth,
609 u32 blockHeight) {
610 // Don't actually care about the void extent, just read the bits...
611 for (s32 i = 0; i < 4; ++i) {
612 strm.ReadBits<13>();
613 }
614
615 // Decode the RGBA components and renormalize them to the range [0, 255]
616 u16 r = static_cast<u16>(strm.ReadBits<16>());
617 u16 g = static_cast<u16>(strm.ReadBits<16>());
618 u16 b = static_cast<u16>(strm.ReadBits<16>());
619 u16 a = static_cast<u16>(strm.ReadBits<16>());
620
621 u32 rgba = (r >> 8) | (g & 0xFF00) | (static_cast<u32>(b) & 0xFF00) << 8 |
622 (static_cast<u32>(a) & 0xFF00) << 16;
623
624 for (u32 j = 0; j < blockHeight; j++) {
625 for (u32 i = 0; i < blockWidth; i++) {
626 outBuf[j * blockWidth + i] = rgba;
627 }
628 }
629}
630
631static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) {
632 for (u32 j = 0; j < blockHeight; j++) {
633 for (u32 i = 0; i < blockWidth; i++) {
634 outBuf[j * blockWidth + i] = 0xFFFF00FF;
635 }
636 }
637}
638
639// Replicates low numBits such that [(toBit - 1):(toBit - 1 - fromBit)]
640// is the same as [(numBits - 1):0] and repeats all the way down.
641template <typename IntType>
642static constexpr IntType Replicate(IntType val, u32 numBits, u32 toBit) {
643 if (numBits == 0) {
644 return 0;
645 }
646 if (toBit == 0) {
647 return 0;
648 }
649 const IntType v = val & static_cast<IntType>((1 << numBits) - 1);
650 IntType res = v;
651 u32 reslen = numBits;
652 while (reslen < toBit) {
653 u32 comp = 0;
654 if (numBits > toBit - reslen) {
655 u32 newshift = toBit - reslen;
656 comp = numBits - newshift;
657 numBits = newshift;
658 }
659 res = static_cast<IntType>(res << numBits);
660 res = static_cast<IntType>(res | (v >> comp));
661 reslen += numBits;
662 }
663 return res;
664}
665
666static constexpr std::size_t NumReplicateEntries(u32 num_bits) {
667 return std::size_t(1) << num_bits;
668}
669
670template <typename IntType, u32 num_bits, u32 to_bit>
671static constexpr auto MakeReplicateTable() {
672 std::array<IntType, NumReplicateEntries(num_bits)> table{};
673 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
674 table[value] = Replicate(value, num_bits, to_bit);
675 }
676 return table;
677}
678
679static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
680static constexpr u32 ReplicateByteTo16(std::size_t value) {
681 return REPLICATE_BYTE_TO_16_TABLE[value];
682}
683
684static constexpr auto REPLICATE_BIT_TO_7_TABLE = MakeReplicateTable<u32, 1, 7>();
685static constexpr u32 ReplicateBitTo7(std::size_t value) {
686 return REPLICATE_BIT_TO_7_TABLE[value];
687}
688
689static constexpr auto REPLICATE_BIT_TO_9_TABLE = MakeReplicateTable<u32, 1, 9>();
690static constexpr u32 ReplicateBitTo9(std::size_t value) {
691 return REPLICATE_BIT_TO_9_TABLE[value];
692}
693
694static constexpr auto REPLICATE_1_BIT_TO_8_TABLE = MakeReplicateTable<u32, 1, 8>();
695static constexpr auto REPLICATE_2_BIT_TO_8_TABLE = MakeReplicateTable<u32, 2, 8>();
696static constexpr auto REPLICATE_3_BIT_TO_8_TABLE = MakeReplicateTable<u32, 3, 8>();
697static constexpr auto REPLICATE_4_BIT_TO_8_TABLE = MakeReplicateTable<u32, 4, 8>();
698static constexpr auto REPLICATE_5_BIT_TO_8_TABLE = MakeReplicateTable<u32, 5, 8>();
699static constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
700static constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
701static constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
702/// Use a precompiled table with the most common usages, if it's not in the expected range, fallback
703/// to the runtime implementation
704static constexpr u32 FastReplicateTo8(u32 value, u32 num_bits) {
705 switch (num_bits) {
706 case 1:
707 return REPLICATE_1_BIT_TO_8_TABLE[value];
708 case 2:
709 return REPLICATE_2_BIT_TO_8_TABLE[value];
710 case 3:
711 return REPLICATE_3_BIT_TO_8_TABLE[value];
712 case 4:
713 return REPLICATE_4_BIT_TO_8_TABLE[value];
714 case 5:
715 return REPLICATE_5_BIT_TO_8_TABLE[value];
716 case 6:
717 return REPLICATE_6_BIT_TO_8_TABLE[value];
718 case 7:
719 return REPLICATE_7_BIT_TO_8_TABLE[value];
720 case 8:
721 return REPLICATE_8_BIT_TO_8_TABLE[value];
722 default:
723 return Replicate(value, num_bits, 8);
724 }
725}
726
727static constexpr auto REPLICATE_1_BIT_TO_6_TABLE = MakeReplicateTable<u32, 1, 6>();
728static constexpr auto REPLICATE_2_BIT_TO_6_TABLE = MakeReplicateTable<u32, 2, 6>();
729static constexpr auto REPLICATE_3_BIT_TO_6_TABLE = MakeReplicateTable<u32, 3, 6>();
730static constexpr auto REPLICATE_4_BIT_TO_6_TABLE = MakeReplicateTable<u32, 4, 6>();
731static constexpr auto REPLICATE_5_BIT_TO_6_TABLE = MakeReplicateTable<u32, 5, 6>();
732static constexpr u32 FastReplicateTo6(u32 value, u32 num_bits) {
733 switch (num_bits) {
734 case 1:
735 return REPLICATE_1_BIT_TO_6_TABLE[value];
736 case 2:
737 return REPLICATE_2_BIT_TO_6_TABLE[value];
738 case 3:
739 return REPLICATE_3_BIT_TO_6_TABLE[value];
740 case 4:
741 return REPLICATE_4_BIT_TO_6_TABLE[value];
742 case 5:
743 return REPLICATE_5_BIT_TO_6_TABLE[value];
744 default:
745 return Replicate(value, num_bits, 6);
746 }
747}
748
749class Pixel {
750protected:
751 using ChannelType = s16;
752 u8 m_BitDepth[4] = {8, 8, 8, 8};
753 s16 color[4] = {};
754
755public:
756 Pixel() = default;
757 Pixel(u32 a, u32 r, u32 g, u32 b, u32 bitDepth = 8)
758 : m_BitDepth{u8(bitDepth), u8(bitDepth), u8(bitDepth), u8(bitDepth)},
759 color{static_cast<ChannelType>(a), static_cast<ChannelType>(r),
760 static_cast<ChannelType>(g), static_cast<ChannelType>(b)} {}
761
762 // Changes the depth of each pixel. This scales the values to
763 // the appropriate bit depth by either truncating the least
764 // significant bits when going from larger to smaller bit depth
765 // or by repeating the most significant bits when going from
766 // smaller to larger bit depths.
767 void ChangeBitDepth() {
768 for (u32 i = 0; i < 4; i++) {
769 Component(i) = ChangeBitDepth(Component(i), m_BitDepth[i]);
770 m_BitDepth[i] = 8;
771 }
772 }
773
774 template <typename IntType>
775 static float ConvertChannelToFloat(IntType channel, u8 bitDepth) {
776 float denominator = static_cast<float>((1 << bitDepth) - 1);
777 return static_cast<float>(channel) / denominator;
778 }
779
780 // Changes the bit depth of a single component. See the comment
781 // above for how we do this.
782 static ChannelType ChangeBitDepth(Pixel::ChannelType val, u8 oldDepth) {
783 assert(oldDepth <= 8);
784
785 if (oldDepth == 8) {
786 // Do nothing
787 return val;
788 } else if (oldDepth == 0) {
789 return static_cast<ChannelType>((1 << 8) - 1);
790 } else if (8 > oldDepth) {
791 return static_cast<ChannelType>(FastReplicateTo8(static_cast<u32>(val), oldDepth));
792 } else {
793 // oldDepth > newDepth
794 const u8 bitsWasted = static_cast<u8>(oldDepth - 8);
795 u16 v = static_cast<u16>(val);
796 v = static_cast<u16>((v + (1 << (bitsWasted - 1))) >> bitsWasted);
797 v = ::std::min<u16>(::std::max<u16>(0, v), static_cast<u16>((1 << 8) - 1));
798 return static_cast<u8>(v);
799 }
800
801 assert(false && "We shouldn't get here.");
802 return 0;
803 }
804
805 const ChannelType& A() const {
806 return color[0];
807 }
808 ChannelType& A() {
809 return color[0];
810 }
811 const ChannelType& R() const {
812 return color[1];
813 }
814 ChannelType& R() {
815 return color[1];
816 }
817 const ChannelType& G() const {
818 return color[2];
819 }
820 ChannelType& G() {
821 return color[2];
822 }
823 const ChannelType& B() const {
824 return color[3];
825 }
826 ChannelType& B() {
827 return color[3];
828 }
829 const ChannelType& Component(u32 idx) const {
830 return color[idx];
831 }
832 ChannelType& Component(u32 idx) {
833 return color[idx];
834 }
835
836 void GetBitDepth(u8 (&outDepth)[4]) const {
837 for (s32 i = 0; i < 4; i++) {
838 outDepth[i] = m_BitDepth[i];
839 }
840 }
841
842 // Take all of the components, transform them to their 8-bit variants,
843 // and then pack each channel into an R8G8B8A8 32-bit integer. We assume
844 // that the architecture is little-endian, so the alpha channel will end
845 // up in the most-significant byte.
846 u32 Pack() const {
847 Pixel eightBit(*this);
848 eightBit.ChangeBitDepth();
849
850 u32 r = 0;
851 r |= eightBit.A();
852 r <<= 8;
853 r |= eightBit.B();
854 r <<= 8;
855 r |= eightBit.G();
856 r <<= 8;
857 r |= eightBit.R();
858 return r;
859 }
860
861 // Clamps the pixel to the range [0,255]
862 void ClampByte() {
863 for (u32 i = 0; i < 4; i++) {
864 color[i] = (color[i] < 0) ? 0 : ((color[i] > 255) ? 255 : color[i]);
865 }
866 }
867
868 void MakeOpaque() {
869 A() = 255;
870 }
871};
872
873static void DecodeColorValues(u32* out, std::span<u8> data, const u32* modes, const u32 nPartitions,
874 const u32 nBitsForColorData) {
875 // First figure out how many color values we have
876 u32 nValues = 0;
877 for (u32 i = 0; i < nPartitions; i++) {
878 nValues += ((modes[i] >> 2) + 1) << 1;
879 }
880
881 // Then based on the number of values and the remaining number of bits,
882 // figure out the max value for each of them...
883 u32 range = 256;
884 while (--range > 0) {
885 IntegerEncodedValue val = EncodingsValues[range];
886 u32 bitLength = val.GetBitLength(nValues);
887 if (bitLength <= nBitsForColorData) {
888 // Find the smallest possible range that matches the given encoding
889 while (--range > 0) {
890 IntegerEncodedValue newval = EncodingsValues[range];
891 if (!newval.MatchesEncoding(val)) {
892 break;
893 }
894 }
895
896 // Return to last matching range.
897 range++;
898 break;
899 }
900 }
901
902 // We now have enough to decode our integer sequence.
903 IntegerEncodedVector decodedColorValues;
904
905 InputBitStream colorStream(data, 0);
906 DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues);
907
908 // Once we have the decoded values, we need to dequantize them to the 0-255 range
909 // This procedure is outlined in ASTC spec C.2.13
910 u32 outIdx = 0;
911 for (auto itr = decodedColorValues.begin(); itr != decodedColorValues.end(); ++itr) {
912 // Have we already decoded all that we need?
913 if (outIdx >= nValues) {
914 break;
915 }
916
917 const IntegerEncodedValue& val = *itr;
918 u32 bitlen = val.num_bits;
919 u32 bitval = val.bit_value;
920
921 assert(bitlen >= 1);
922
923 u32 A = 0, B = 0, C = 0, D = 0;
924 // A is just the lsb replicated 9 times.
925 A = ReplicateBitTo9(bitval & 1);
926
927 switch (val.encoding) {
928 // Replicate bits
929 case IntegerEncoding::JustBits:
930 out[outIdx++] = FastReplicateTo8(bitval, bitlen);
931 break;
932
933 // Use algorithm in C.2.13
934 case IntegerEncoding::Trit: {
935
936 D = val.trit_value;
937
938 switch (bitlen) {
939 case 1: {
940 C = 204;
941 } break;
942
943 case 2: {
944 C = 93;
945 // B = b000b0bb0
946 u32 b = (bitval >> 1) & 1;
947 B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
948 } break;
949
950 case 3: {
951 C = 44;
952 // B = cb000cbcb
953 u32 cb = (bitval >> 1) & 3;
954 B = (cb << 7) | (cb << 2) | cb;
955 } break;
956
957 case 4: {
958 C = 22;
959 // B = dcb000dcb
960 u32 dcb = (bitval >> 1) & 7;
961 B = (dcb << 6) | dcb;
962 } break;
963
964 case 5: {
965 C = 11;
966 // B = edcb000ed
967 u32 edcb = (bitval >> 1) & 0xF;
968 B = (edcb << 5) | (edcb >> 2);
969 } break;
970
971 case 6: {
972 C = 5;
973 // B = fedcb000f
974 u32 fedcb = (bitval >> 1) & 0x1F;
975 B = (fedcb << 4) | (fedcb >> 4);
976 } break;
977
978 default:
979 assert(false && "Unsupported trit encoding for color values!");
980 break;
981 } // switch(bitlen)
982 } // case IntegerEncoding::Trit
983 break;
984
985 case IntegerEncoding::Qus32: {
986
987 D = val.qus32_value;
988
989 switch (bitlen) {
990 case 1: {
991 C = 113;
992 } break;
993
994 case 2: {
995 C = 54;
996 // B = b0000bb00
997 u32 b = (bitval >> 1) & 1;
998 B = (b << 8) | (b << 3) | (b << 2);
999 } break;
1000
1001 case 3: {
1002 C = 26;
1003 // B = cb0000cbc
1004 u32 cb = (bitval >> 1) & 3;
1005 B = (cb << 7) | (cb << 1) | (cb >> 1);
1006 } break;
1007
1008 case 4: {
1009 C = 13;
1010 // B = dcb0000dc
1011 u32 dcb = (bitval >> 1) & 7;
1012 B = (dcb << 6) | (dcb >> 1);
1013 } break;
1014
1015 case 5: {
1016 C = 6;
1017 // B = edcb0000e
1018 u32 edcb = (bitval >> 1) & 0xF;
1019 B = (edcb << 5) | (edcb >> 3);
1020 } break;
1021
1022 default:
1023 assert(false && "Unsupported quint encoding for color values!");
1024 break;
1025 } // switch(bitlen)
1026 } // case IntegerEncoding::Qus32
1027 break;
1028 } // switch(val.encoding)
1029
1030 if (val.encoding != IntegerEncoding::JustBits) {
1031 u32 T = D * C + B;
1032 T ^= A;
1033 T = (A & 0x80) | (T >> 2);
1034 out[outIdx++] = T;
1035 }
1036 }
1037
1038 // Make sure that each of our values is in the proper range...
1039 for (u32 i = 0; i < nValues; i++) {
1040 assert(out[i] <= 255);
1041 }
1042}
1043
1044static u32 UnquantizeTexelWeight(const IntegerEncodedValue& val) {
1045 u32 bitval = val.bit_value;
1046 u32 bitlen = val.num_bits;
1047
1048 u32 A = ReplicateBitTo7(bitval & 1);
1049 u32 B = 0, C = 0, D = 0;
1050
1051 u32 result = 0;
1052 switch (val.encoding) {
1053 case IntegerEncoding::JustBits:
1054 result = FastReplicateTo6(bitval, bitlen);
1055 break;
1056
1057 case IntegerEncoding::Trit: {
1058 D = val.trit_value;
1059 assert(D < 3);
1060
1061 switch (bitlen) {
1062 case 0: {
1063 u32 results[3] = {0, 32, 63};
1064 result = results[D];
1065 } break;
1066
1067 case 1: {
1068 C = 50;
1069 } break;
1070
1071 case 2: {
1072 C = 23;
1073 u32 b = (bitval >> 1) & 1;
1074 B = (b << 6) | (b << 2) | b;
1075 } break;
1076
1077 case 3: {
1078 C = 11;
1079 u32 cb = (bitval >> 1) & 3;
1080 B = (cb << 5) | cb;
1081 } break;
1082
1083 default:
1084 assert(false && "Invalid trit encoding for texel weight");
1085 break;
1086 }
1087 } break;
1088
1089 case IntegerEncoding::Qus32: {
1090 D = val.qus32_value;
1091 assert(D < 5);
1092
1093 switch (bitlen) {
1094 case 0: {
1095 u32 results[5] = {0, 16, 32, 47, 63};
1096 result = results[D];
1097 } break;
1098
1099 case 1: {
1100 C = 28;
1101 } break;
1102
1103 case 2: {
1104 C = 13;
1105 u32 b = (bitval >> 1) & 1;
1106 B = (b << 6) | (b << 1);
1107 } break;
1108
1109 default:
1110 assert(false && "Invalid quint encoding for texel weight");
1111 break;
1112 }
1113 } break;
1114 }
1115
1116 if (val.encoding != IntegerEncoding::JustBits && bitlen > 0) {
1117 // Decode the value...
1118 result = D * C + B;
1119 result ^= A;
1120 result = (A & 0x20) | (result >> 2);
1121 }
1122
1123 assert(result < 64);
1124
1125 // Change from [0,63] to [0,64]
1126 if (result > 32) {
1127 result += 1;
1128 }
1129
1130 return result;
1131}
1132
1133static void UnquantizeTexelWeights(u32 out[2][144], const IntegerEncodedVector& weights,
1134 const TexelWeightParams& params, const u32 blockWidth,
1135 const u32 blockHeight) {
1136 u32 weightIdx = 0;
1137 u32 unquantized[2][144];
1138
1139 for (auto itr = weights.begin(); itr != weights.end(); ++itr) {
1140 unquantized[0][weightIdx] = UnquantizeTexelWeight(*itr);
1141
1142 if (params.m_bDualPlane) {
1143 ++itr;
1144 unquantized[1][weightIdx] = UnquantizeTexelWeight(*itr);
1145 if (itr == weights.end()) {
1146 break;
1147 }
1148 }
1149
1150 if (++weightIdx >= (params.m_Width * params.m_Height))
1151 break;
1152 }
1153
1154 // Do infill if necessary (Section C.2.18) ...
1155 u32 Ds = (1024 + (blockWidth / 2)) / (blockWidth - 1);
1156 u32 Dt = (1024 + (blockHeight / 2)) / (blockHeight - 1);
1157
1158 const u32 kPlaneScale = params.m_bDualPlane ? 2U : 1U;
1159 for (u32 plane = 0; plane < kPlaneScale; plane++)
1160 for (u32 t = 0; t < blockHeight; t++)
1161 for (u32 s = 0; s < blockWidth; s++) {
1162 u32 cs = Ds * s;
1163 u32 ct = Dt * t;
1164
1165 u32 gs = (cs * (params.m_Width - 1) + 32) >> 6;
1166 u32 gt = (ct * (params.m_Height - 1) + 32) >> 6;
1167
1168 u32 js = gs >> 4;
1169 u32 fs = gs & 0xF;
1170
1171 u32 jt = gt >> 4;
1172 u32 ft = gt & 0x0F;
1173
1174 u32 w11 = (fs * ft + 8) >> 4;
1175 u32 w10 = ft - w11;
1176 u32 w01 = fs - w11;
1177 u32 w00 = 16 - fs - ft + w11;
1178
1179 u32 v0 = js + jt * params.m_Width;
1180
1181#define FIND_TEXEL(tidx, bidx) \
1182 u32 p##bidx = 0; \
1183 do { \
1184 if ((tidx) < (params.m_Width * params.m_Height)) { \
1185 p##bidx = unquantized[plane][(tidx)]; \
1186 } \
1187 } while (0)
1188
1189 FIND_TEXEL(v0, 00);
1190 FIND_TEXEL(v0 + 1, 01);
1191 FIND_TEXEL(v0 + params.m_Width, 10);
1192 FIND_TEXEL(v0 + params.m_Width + 1, 11);
1193
1194#undef FIND_TEXEL
1195
1196 out[plane][t * blockWidth + s] =
1197 (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4;
1198 }
1199}
1200
1201// Transfers a bit as described in C.2.14
1202static inline void BitTransferSigned(s32& a, s32& b) {
1203 b >>= 1;
1204 b |= a & 0x80;
1205 a >>= 1;
1206 a &= 0x3F;
1207 if (a & 0x20)
1208 a -= 0x40;
1209}
1210
1211// Adds more precision to the blue channel as described
1212// in C.2.14
1213static inline Pixel BlueContract(s32 a, s32 r, s32 g, s32 b) {
1214 return Pixel(static_cast<s16>(a), static_cast<s16>((r + b) >> 1),
1215 static_cast<s16>((g + b) >> 1), static_cast<s16>(b));
1216}
1217
1218// Partition selection functions as specified in
1219// C.2.21
1220static inline u32 hash52(u32 p) {
1221 p ^= p >> 15;
1222 p -= p << 17;
1223 p += p << 7;
1224 p += p << 4;
1225 p ^= p >> 5;
1226 p += p << 16;
1227 p ^= p >> 7;
1228 p ^= p >> 3;
1229 p ^= p << 6;
1230 p ^= p >> 17;
1231 return p;
1232}
1233
1234static u32 SelectPartition(s32 seed, s32 x, s32 y, s32 z, s32 partitionCount, s32 smallBlock) {
1235 if (1 == partitionCount)
1236 return 0;
1237
1238 if (smallBlock) {
1239 x <<= 1;
1240 y <<= 1;
1241 z <<= 1;
1242 }
1243
1244 seed += (partitionCount - 1) * 1024;
1245
1246 u32 rnum = hash52(static_cast<u32>(seed));
1247 u8 seed1 = static_cast<u8>(rnum & 0xF);
1248 u8 seed2 = static_cast<u8>((rnum >> 4) & 0xF);
1249 u8 seed3 = static_cast<u8>((rnum >> 8) & 0xF);
1250 u8 seed4 = static_cast<u8>((rnum >> 12) & 0xF);
1251 u8 seed5 = static_cast<u8>((rnum >> 16) & 0xF);
1252 u8 seed6 = static_cast<u8>((rnum >> 20) & 0xF);
1253 u8 seed7 = static_cast<u8>((rnum >> 24) & 0xF);
1254 u8 seed8 = static_cast<u8>((rnum >> 28) & 0xF);
1255 u8 seed9 = static_cast<u8>((rnum >> 18) & 0xF);
1256 u8 seed10 = static_cast<u8>((rnum >> 22) & 0xF);
1257 u8 seed11 = static_cast<u8>((rnum >> 26) & 0xF);
1258 u8 seed12 = static_cast<u8>(((rnum >> 30) | (rnum << 2)) & 0xF);
1259
1260 seed1 = static_cast<u8>(seed1 * seed1);
1261 seed2 = static_cast<u8>(seed2 * seed2);
1262 seed3 = static_cast<u8>(seed3 * seed3);
1263 seed4 = static_cast<u8>(seed4 * seed4);
1264 seed5 = static_cast<u8>(seed5 * seed5);
1265 seed6 = static_cast<u8>(seed6 * seed6);
1266 seed7 = static_cast<u8>(seed7 * seed7);
1267 seed8 = static_cast<u8>(seed8 * seed8);
1268 seed9 = static_cast<u8>(seed9 * seed9);
1269 seed10 = static_cast<u8>(seed10 * seed10);
1270 seed11 = static_cast<u8>(seed11 * seed11);
1271 seed12 = static_cast<u8>(seed12 * seed12);
1272
1273 s32 sh1, sh2, sh3;
1274 if (seed & 1) {
1275 sh1 = (seed & 2) ? 4 : 5;
1276 sh2 = (partitionCount == 3) ? 6 : 5;
1277 } else {
1278 sh1 = (partitionCount == 3) ? 6 : 5;
1279 sh2 = (seed & 2) ? 4 : 5;
1280 }
1281 sh3 = (seed & 0x10) ? sh1 : sh2;
1282
1283 seed1 = static_cast<u8>(seed1 >> sh1);
1284 seed2 = static_cast<u8>(seed2 >> sh2);
1285 seed3 = static_cast<u8>(seed3 >> sh1);
1286 seed4 = static_cast<u8>(seed4 >> sh2);
1287 seed5 = static_cast<u8>(seed5 >> sh1);
1288 seed6 = static_cast<u8>(seed6 >> sh2);
1289 seed7 = static_cast<u8>(seed7 >> sh1);
1290 seed8 = static_cast<u8>(seed8 >> sh2);
1291 seed9 = static_cast<u8>(seed9 >> sh3);
1292 seed10 = static_cast<u8>(seed10 >> sh3);
1293 seed11 = static_cast<u8>(seed11 >> sh3);
1294 seed12 = static_cast<u8>(seed12 >> sh3);
1295
1296 s32 a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
1297 s32 b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
1298 s32 c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
1299 s32 d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
1300
1301 a &= 0x3F;
1302 b &= 0x3F;
1303 c &= 0x3F;
1304 d &= 0x3F;
1305
1306 if (partitionCount < 4)
1307 d = 0;
1308 if (partitionCount < 3)
1309 c = 0;
1310
1311 if (a >= b && a >= c && a >= d)
1312 return 0;
1313 else if (b >= c && b >= d)
1314 return 1;
1315 else if (c >= d)
1316 return 2;
1317 return 3;
1318}
1319
1320static inline u32 Select2DPartition(s32 seed, s32 x, s32 y, s32 partitionCount, s32 smallBlock) {
1321 return SelectPartition(seed, x, y, 0, partitionCount, smallBlock);
1322}
1323
1324// Section C.2.14
1325static void ComputeEndpos32s(Pixel& ep1, Pixel& ep2, const u32*& colorValues,
1326 u32 colorEndpos32Mode) {
1327#define READ_UINT_VALUES(N) \
1328 u32 v[N]; \
1329 for (u32 i = 0; i < N; i++) { \
1330 v[i] = *(colorValues++); \
1331 }
1332
1333#define READ_INT_VALUES(N) \
1334 s32 v[N]; \
1335 for (u32 i = 0; i < N; i++) { \
1336 v[i] = static_cast<s32>(*(colorValues++)); \
1337 }
1338
1339 switch (colorEndpos32Mode) {
1340 case 0: {
1341 READ_UINT_VALUES(2)
1342 ep1 = Pixel(0xFF, v[0], v[0], v[0]);
1343 ep2 = Pixel(0xFF, v[1], v[1], v[1]);
1344 } break;
1345
1346 case 1: {
1347 READ_UINT_VALUES(2)
1348 u32 L0 = (v[0] >> 2) | (v[1] & 0xC0);
1349 u32 L1 = std::max(L0 + (v[1] & 0x3F), 0xFFU);
1350 ep1 = Pixel(0xFF, L0, L0, L0);
1351 ep2 = Pixel(0xFF, L1, L1, L1);
1352 } break;
1353
1354 case 4: {
1355 READ_UINT_VALUES(4)
1356 ep1 = Pixel(v[2], v[0], v[0], v[0]);
1357 ep2 = Pixel(v[3], v[1], v[1], v[1]);
1358 } break;
1359
1360 case 5: {
1361 READ_INT_VALUES(4)
1362 BitTransferSigned(v[1], v[0]);
1363 BitTransferSigned(v[3], v[2]);
1364 ep1 = Pixel(v[2], v[0], v[0], v[0]);
1365 ep2 = Pixel(v[2] + v[3], v[0] + v[1], v[0] + v[1], v[0] + v[1]);
1366 ep1.ClampByte();
1367 ep2.ClampByte();
1368 } break;
1369
1370 case 6: {
1371 READ_UINT_VALUES(4)
1372 ep1 = Pixel(0xFF, v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8);
1373 ep2 = Pixel(0xFF, v[0], v[1], v[2]);
1374 } break;
1375
1376 case 8: {
1377 READ_UINT_VALUES(6)
1378 if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) {
1379 ep1 = Pixel(0xFF, v[0], v[2], v[4]);
1380 ep2 = Pixel(0xFF, v[1], v[3], v[5]);
1381 } else {
1382 ep1 = BlueContract(0xFF, v[1], v[3], v[5]);
1383 ep2 = BlueContract(0xFF, v[0], v[2], v[4]);
1384 }
1385 } break;
1386
1387 case 9: {
1388 READ_INT_VALUES(6)
1389 BitTransferSigned(v[1], v[0]);
1390 BitTransferSigned(v[3], v[2]);
1391 BitTransferSigned(v[5], v[4]);
1392 if (v[1] + v[3] + v[5] >= 0) {
1393 ep1 = Pixel(0xFF, v[0], v[2], v[4]);
1394 ep2 = Pixel(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1395 } else {
1396 ep1 = BlueContract(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1397 ep2 = BlueContract(0xFF, v[0], v[2], v[4]);
1398 }
1399 ep1.ClampByte();
1400 ep2.ClampByte();
1401 } break;
1402
1403 case 10: {
1404 READ_UINT_VALUES(6)
1405 ep1 = Pixel(v[4], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8);
1406 ep2 = Pixel(v[5], v[0], v[1], v[2]);
1407 } break;
1408
1409 case 12: {
1410 READ_UINT_VALUES(8)
1411 if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) {
1412 ep1 = Pixel(v[6], v[0], v[2], v[4]);
1413 ep2 = Pixel(v[7], v[1], v[3], v[5]);
1414 } else {
1415 ep1 = BlueContract(v[7], v[1], v[3], v[5]);
1416 ep2 = BlueContract(v[6], v[0], v[2], v[4]);
1417 }
1418 } break;
1419
1420 case 13: {
1421 READ_INT_VALUES(8)
1422 BitTransferSigned(v[1], v[0]);
1423 BitTransferSigned(v[3], v[2]);
1424 BitTransferSigned(v[5], v[4]);
1425 BitTransferSigned(v[7], v[6]);
1426 if (v[1] + v[3] + v[5] >= 0) {
1427 ep1 = Pixel(v[6], v[0], v[2], v[4]);
1428 ep2 = Pixel(v[7] + v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1429 } else {
1430 ep1 = BlueContract(v[6] + v[7], v[0] + v[1], v[2] + v[3], v[4] + v[5]);
1431 ep2 = BlueContract(v[6], v[0], v[2], v[4]);
1432 }
1433 ep1.ClampByte();
1434 ep2.ClampByte();
1435 } break;
1436
1437 default:
1438 assert(false && "Unsupported color endpoint mode (is it HDR?)");
1439 break;
1440 }
1441
1442#undef READ_UINT_VALUES
1443#undef READ_INT_VALUES
1444}
1445
1446static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
1447 const u32 blockHeight, std::span<u32, 12 * 12> outBuf) {
1448 InputBitStream strm(inBuf);
1449 TexelWeightParams weightParams = DecodeBlockInfo(strm);
1450
1451 // Was there an error?
1452 if (weightParams.m_bError) {
1453 assert(false && "Invalid block mode");
1454 FillError(outBuf, blockWidth, blockHeight);
1455 return;
1456 }
1457
1458 if (weightParams.m_bVoidExtentLDR) {
1459 FillVoidExtentLDR(strm, outBuf, blockWidth, blockHeight);
1460 return;
1461 }
1462
1463 if (weightParams.m_bVoidExtentHDR) {
1464 assert(false && "HDR void extent blocks are unsupported!");
1465 FillError(outBuf, blockWidth, blockHeight);
1466 return;
1467 }
1468
1469 if (weightParams.m_Width > blockWidth) {
1470 assert(false && "Texel weight grid width should be smaller than block width");
1471 FillError(outBuf, blockWidth, blockHeight);
1472 return;
1473 }
1474
1475 if (weightParams.m_Height > blockHeight) {
1476 assert(false && "Texel weight grid height should be smaller than block height");
1477 FillError(outBuf, blockWidth, blockHeight);
1478 return;
1479 }
1480
1481 // Read num partitions
1482 u32 nPartitions = strm.ReadBits<2>() + 1;
1483 assert(nPartitions <= 4);
1484
1485 if (nPartitions == 4 && weightParams.m_bDualPlane) {
1486 assert(false && "Dual plane mode is incompatible with four partition blocks");
1487 FillError(outBuf, blockWidth, blockHeight);
1488 return;
1489 }
1490
1491 // Based on the number of partitions, read the color endpos32 mode for
1492 // each partition.
1493
1494 // Determine partitions, partition index, and color endpos32 modes
1495 s32 planeIdx = -1;
1496 u32 partitionIndex;
1497 u32 colorEndpos32Mode[4] = {0, 0, 0, 0};
1498
1499 // Define color data.
1500 u8 colorEndpos32Data[16];
1501 memset(colorEndpos32Data, 0, sizeof(colorEndpos32Data));
1502 OutputBitStream colorEndpos32Stream(colorEndpos32Data, 16 * 8, 0);
1503
1504 // Read extra config data...
1505 u32 baseCEM = 0;
1506 if (nPartitions == 1) {
1507 colorEndpos32Mode[0] = strm.ReadBits<4>();
1508 partitionIndex = 0;
1509 } else {
1510 partitionIndex = strm.ReadBits<10>();
1511 baseCEM = strm.ReadBits<6>();
1512 }
1513 u32 baseMode = (baseCEM & 3);
1514
1515 // Remaining bits are color endpos32 data...
1516 u32 nWeightBits = weightParams.GetPackedBitSize();
1517 s32 remainingBits = 128 - nWeightBits - static_cast<s32>(strm.GetBitsRead());
1518
1519 // Consider extra bits prior to texel data...
1520 u32 extraCEMbits = 0;
1521 if (baseMode) {
1522 switch (nPartitions) {
1523 case 2:
1524 extraCEMbits += 2;
1525 break;
1526 case 3:
1527 extraCEMbits += 5;
1528 break;
1529 case 4:
1530 extraCEMbits += 8;
1531 break;
1532 default:
1533 assert(false);
1534 break;
1535 }
1536 }
1537 remainingBits -= extraCEMbits;
1538
1539 // Do we have a dual plane situation?
1540 u32 planeSelectorBits = 0;
1541 if (weightParams.m_bDualPlane) {
1542 planeSelectorBits = 2;
1543 }
1544 remainingBits -= planeSelectorBits;
1545
1546 // Read color data...
1547 u32 colorDataBits = remainingBits;
1548 while (remainingBits > 0) {
1549 u32 nb = std::min(remainingBits, 8);
1550 u32 b = strm.ReadBits(nb);
1551 colorEndpos32Stream.WriteBits(b, nb);
1552 remainingBits -= 8;
1553 }
1554
1555 // Read the plane selection bits
1556 planeIdx = strm.ReadBits(planeSelectorBits);
1557
1558 // Read the rest of the CEM
1559 if (baseMode) {
1560 u32 extraCEM = strm.ReadBits(extraCEMbits);
1561 u32 CEM = (extraCEM << 6) | baseCEM;
1562 CEM >>= 2;
1563
1564 bool C[4] = {0};
1565 for (u32 i = 0; i < nPartitions; i++) {
1566 C[i] = CEM & 1;
1567 CEM >>= 1;
1568 }
1569
1570 u8 M[4] = {0};
1571 for (u32 i = 0; i < nPartitions; i++) {
1572 M[i] = CEM & 3;
1573 CEM >>= 2;
1574 assert(M[i] <= 3);
1575 }
1576
1577 for (u32 i = 0; i < nPartitions; i++) {
1578 colorEndpos32Mode[i] = baseMode;
1579 if (!(C[i]))
1580 colorEndpos32Mode[i] -= 1;
1581 colorEndpos32Mode[i] <<= 2;
1582 colorEndpos32Mode[i] |= M[i];
1583 }
1584 } else if (nPartitions > 1) {
1585 u32 CEM = baseCEM >> 2;
1586 for (u32 i = 0; i < nPartitions; i++) {
1587 colorEndpos32Mode[i] = CEM;
1588 }
1589 }
1590
1591 // Make sure everything up till here is sane.
1592 for (u32 i = 0; i < nPartitions; i++) {
1593 assert(colorEndpos32Mode[i] < 16);
1594 }
1595 assert(strm.GetBitsRead() + weightParams.GetPackedBitSize() == 128);
1596
1597 // Decode both color data and texel weight data
1598 u32 colorValues[32]; // Four values, two endpos32s, four maximum paritions
1599 DecodeColorValues(colorValues, colorEndpos32Data, colorEndpos32Mode, nPartitions,
1600 colorDataBits);
1601
1602 Pixel endpos32s[4][2];
1603 const u32* colorValuesPtr = colorValues;
1604 for (u32 i = 0; i < nPartitions; i++) {
1605 ComputeEndpos32s(endpos32s[i][0], endpos32s[i][1], colorValuesPtr, colorEndpos32Mode[i]);
1606 }
1607
1608 // Read the texel weight data..
1609 std::array<u8, 16> texelWeightData;
1610 std::ranges::copy(inBuf, texelWeightData.begin());
1611
1612 // Reverse everything
1613 for (u32 i = 0; i < 8; i++) {
1614// Taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
1615#define REVERSE_BYTE(b) (((b)*0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32
1616 u8 a = static_cast<u8>(REVERSE_BYTE(texelWeightData[i]));
1617 u8 b = static_cast<u8>(REVERSE_BYTE(texelWeightData[15 - i]));
1618#undef REVERSE_BYTE
1619
1620 texelWeightData[i] = b;
1621 texelWeightData[15 - i] = a;
1622 }
1623
1624 // Make sure that higher non-texel bits are set to zero
1625 const u32 clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1;
1626 if (clearByteStart > 0 && clearByteStart <= texelWeightData.size()) {
1627 texelWeightData[clearByteStart - 1] &=
1628 static_cast<u8>((1 << (weightParams.GetPackedBitSize() % 8)) - 1);
1629 std::memset(texelWeightData.data() + clearByteStart, 0,
1630 std::min(16U - clearByteStart, 16U));
1631 }
1632
1633 IntegerEncodedVector texelWeightValues;
1634
1635 InputBitStream weightStream(texelWeightData);
1636
1637 DecodeIntegerSequence(texelWeightValues, weightStream, weightParams.m_MaxWeight,
1638 weightParams.GetNumWeightValues());
1639
1640 // Blocks can be at most 12x12, so we can have as many as 144 weights
1641 u32 weights[2][144];
1642 UnquantizeTexelWeights(weights, texelWeightValues, weightParams, blockWidth, blockHeight);
1643
1644 // Now that we have endpos32s and weights, we can s32erpolate and generate
1645 // the proper decoding...
1646 for (u32 j = 0; j < blockHeight; j++)
1647 for (u32 i = 0; i < blockWidth; i++) {
1648 u32 partition = Select2DPartition(partitionIndex, i, j, nPartitions,
1649 (blockHeight * blockWidth) < 32);
1650 assert(partition < nPartitions);
1651
1652 Pixel p;
1653 for (u32 c = 0; c < 4; c++) {
1654 u32 C0 = endpos32s[partition][0].Component(c);
1655 C0 = ReplicateByteTo16(C0);
1656 u32 C1 = endpos32s[partition][1].Component(c);
1657 C1 = ReplicateByteTo16(C1);
1658
1659 u32 plane = 0;
1660 if (weightParams.m_bDualPlane && (((planeIdx + 1) & 3) == c)) {
1661 plane = 1;
1662 }
1663
1664 u32 weight = weights[plane][j * blockWidth + i];
1665 u32 C = (C0 * (64 - weight) + C1 * weight + 32) / 64;
1666 if (C == 65535) {
1667 p.Component(c) = 255;
1668 } else {
1669 double Cf = static_cast<double>(C);
1670 p.Component(c) = static_cast<u16>(255.0 * (Cf / 65536.0) + 0.5);
1671 }
1672 }
1673
1674 outBuf[j * blockWidth + i] = p.Pack();
1675 }
1676}
1677
1678} // namespace ASTCC
1679
1680namespace Tegra::Texture::ASTC {
1681
1682void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
1683 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output) {
1684 u32 block_index = 0;
1685 std::size_t depth_offset = 0;
1686 for (u32 z = 0; z < depth; z++) {
1687 for (u32 y = 0; y < height; y += block_height) {
1688 for (u32 x = 0; x < width; x += block_width) {
1689 const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)};
1690
1691 // Blocks can be at most 12x12
1692 std::array<u32, 12 * 12> uncompData;
1693 ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
1694
1695 u32 decompWidth = std::min(block_width, width - x);
1696 u32 decompHeight = std::min(block_height, height - y);
1697
1698 const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4);
1699 for (u32 jj = 0; jj < decompHeight; jj++) {
1700 std::memcpy(outRow.data() + jj * width * 4,
1701 uncompData.data() + jj * block_width, decompWidth * 4);
1702 }
1703 ++block_index;
1704 }
1705 }
1706 depth_offset += height * width * 4;
1707 }
1708}
1709
1710} // namespace Tegra::Texture::ASTC
diff --git a/src/video_core/textures/astc.h b/src/video_core/textures/astc.h
index 9105119bc..c1c73fda5 100644
--- a/src/video_core/textures/astc.h
+++ b/src/video_core/textures/astc.h
@@ -4,11 +4,129 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstdint> 7#include <bit>
8#include "common/common_types.h"
8 9
9namespace Tegra::Texture::ASTC { 10namespace Tegra::Texture::ASTC {
10 11
11void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 12enum class IntegerEncoding { JustBits, Quint, Trit };
12 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output); 13
14struct IntegerEncodedValue {
15 constexpr IntegerEncodedValue() = default;
16
17 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
18 : encoding{encoding_}, num_bits{num_bits_} {}
19
20 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
21 return encoding == other.encoding && num_bits == other.num_bits;
22 }
23
24 // Returns the number of bits required to encode num_vals values.
25 u32 GetBitLength(u32 num_vals) const {
26 u32 total_bits = num_bits * num_vals;
27 if (encoding == IntegerEncoding::Trit) {
28 total_bits += (num_vals * 8 + 4) / 5;
29 } else if (encoding == IntegerEncoding::Quint) {
30 total_bits += (num_vals * 7 + 2) / 3;
31 }
32 return total_bits;
33 }
34
35 IntegerEncoding encoding{};
36 u32 num_bits = 0;
37 u32 bit_value = 0;
38 union {
39 u32 quint_value = 0;
40 u32 trit_value;
41 };
42};
43
44// Returns a new instance of this struct that corresponds to the
45// can take no more than mav_value values
46constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
47 while (mav_value > 0) {
48 u32 check = mav_value + 1;
49
50 // Is mav_value a power of two?
51 if (!(check & (check - 1))) {
52 return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
53 }
54
55 // Is mav_value of the type 3*2^n - 1?
56 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
57 return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
58 }
59
60 // Is mav_value of the type 5*2^n - 1?
61 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
62 return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
63 }
64
65 // Apparently it can't be represented with a bounded integer sequence...
66 // just iterate.
67 mav_value--;
68 }
69 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
70}
71
72constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
73 std::array<IntegerEncodedValue, 256> encodings{};
74 for (std::size_t i = 0; i < encodings.size(); ++i) {
75 encodings[i] = CreateEncoding(static_cast<u32>(i));
76 }
77 return encodings;
78}
79
80constexpr std::array<IntegerEncodedValue, 256> EncodingsValues = MakeEncodedValues();
81
82// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
83// is the same as [(num_bits - 1):0] and repeats all the way down.
84template <typename IntType>
85constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
86 if (num_bits == 0 || to_bit == 0) {
87 return 0;
88 }
89 const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
90 IntType res = v;
91 u32 reslen = num_bits;
92 while (reslen < to_bit) {
93 u32 comp = 0;
94 if (num_bits > to_bit - reslen) {
95 u32 newshift = to_bit - reslen;
96 comp = num_bits - newshift;
97 num_bits = newshift;
98 }
99 res = static_cast<IntType>(res << num_bits);
100 res = static_cast<IntType>(res | (v >> comp));
101 reslen += num_bits;
102 }
103 return res;
104}
105
106constexpr std::size_t NumReplicateEntries(u32 num_bits) {
107 return std::size_t(1) << num_bits;
108}
109
110template <typename IntType, u32 num_bits, u32 to_bit>
111constexpr auto MakeReplicateTable() {
112 std::array<IntType, NumReplicateEntries(num_bits)> table{};
113 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
114 table[value] = Replicate(value, num_bits, to_bit);
115 }
116 return table;
117}
118
119constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
120constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
121constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
122constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
123
124struct AstcBufferData {
125 decltype(EncodingsValues) encoding_values = EncodingsValues;
126 decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
127 decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
128 decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
129 decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
130} constexpr ASTC_BUFFER_DATA;
13 131
14} // namespace Tegra::Texture::ASTC 132} // namespace Tegra::Texture::ASTC
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 62685a183..3a463d5db 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -17,26 +17,7 @@
17#include "video_core/textures/texture.h" 17#include "video_core/textures/texture.h"
18 18
19namespace Tegra::Texture { 19namespace Tegra::Texture {
20
21namespace { 20namespace {
22/**
23 * This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
24 * Calculates the offset of an (x, y) position within a swizzled texture.
25 * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
26 */
27constexpr SwizzleTable MakeSwizzleTableConst() {
28 SwizzleTable table{};
29 for (u32 y = 0; y < table.size(); ++y) {
30 for (u32 x = 0; x < table[0].size(); ++x) {
31 table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
32 (y % 2) * 16 + (x % 16);
33 }
34 }
35 return table;
36}
37
38constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTableConst();
39
40template <bool TO_LINEAR> 21template <bool TO_LINEAR>
41void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width, 22void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width,
42 u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride_alignment) { 23 u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride_alignment) {
@@ -91,10 +72,6 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe
91} 72}
92} // Anonymous namespace 73} // Anonymous namespace
93 74
94SwizzleTable MakeSwizzleTable() {
95 return SWIZZLE_TABLE;
96}
97
98void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, 75void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
99 u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth, 76 u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth,
100 u32 stride_alignment) { 77 u32 stride_alignment) {
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index d7cdc81e8..4c14cefbf 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -23,8 +23,22 @@ constexpr u32 GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_
23 23
24using SwizzleTable = std::array<std::array<u32, GOB_SIZE_X>, GOB_SIZE_Y>; 24using SwizzleTable = std::array<std::array<u32, GOB_SIZE_X>, GOB_SIZE_Y>;
25 25
26/// Returns a z-order swizzle table 26/**
27SwizzleTable MakeSwizzleTable(); 27 * This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
28 * Calculates the offset of an (x, y) position within a swizzled texture.
29 * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
30 */
31constexpr SwizzleTable MakeSwizzleTable() {
32 SwizzleTable table{};
33 for (u32 y = 0; y < table.size(); ++y) {
34 for (u32 x = 0; x < table[0].size(); ++x) {
35 table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
36 (y % 2) * 16 + (x % 16);
37 }
38 }
39 return table;
40}
41constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTable();
28 42
29/// Unswizzles a block linear texture into linear memory. 43/// Unswizzles a block linear texture into linear memory.
30void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, 44void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 34d396434..697cb16b9 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -51,7 +51,7 @@ constexpr std::array REQUIRED_EXTENSIONS{
51#ifdef _WIN32 51#ifdef _WIN32
52 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, 52 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
53#endif 53#endif
54#ifdef __linux__ 54#ifdef __unix__
55 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, 55 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
56#endif 56#endif
57}; 57};
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 2a8b7a907..fa37aa79a 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -62,7 +62,7 @@ public:
62 : memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties}, 62 : memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties},
63 shifted_memory_type{1U << type} {} 63 shifted_memory_type{1U << type} {}
64 64
65#if defined(_WIN32) || defined(__linux__) 65#if defined(_WIN32) || defined(__unix__)
66 ~MemoryAllocation() { 66 ~MemoryAllocation() {
67 if (owning_opengl_handle != 0) { 67 if (owning_opengl_handle != 0) {
68 glDeleteMemoryObjectsEXT(1, &owning_opengl_handle); 68 glDeleteMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -114,7 +114,7 @@ public:
114 } 114 }
115 return owning_opengl_handle; 115 return owning_opengl_handle;
116 } 116 }
117#elif __linux__ 117#elif __unix__
118 [[nodiscard]] u32 ExportOpenGLHandle() { 118 [[nodiscard]] u32 ExportOpenGLHandle() {
119 if (!owning_opengl_handle) { 119 if (!owning_opengl_handle) {
120 glCreateMemoryObjectsEXT(1, &owning_opengl_handle); 120 glCreateMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -165,7 +165,7 @@ private:
165 const u32 shifted_memory_type; ///< Shifted Vulkan memory type. 165 const u32 shifted_memory_type; ///< Shifted Vulkan memory type.
166 std::vector<Range> commits; ///< All commit ranges done from this allocation. 166 std::vector<Range> commits; ///< All commit ranges done from this allocation.
167 std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. 167 std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before.
168#if defined(_WIN32) || defined(__linux__) 168#if defined(_WIN32) || defined(__unix__)
169 u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle. 169 u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle.
170#endif 170#endif
171}; 171};
@@ -249,7 +249,7 @@ void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u6
249 .pNext = nullptr, 249 .pNext = nullptr,
250#ifdef _WIN32 250#ifdef _WIN32
251 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, 251 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
252#elif __linux__ 252#elif __unix__
253 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 253 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
254#else 254#else
255 .handleTypes = 0, 255 .handleTypes = 0,
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 1bac57bb2..1d6155999 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -641,6 +641,7 @@ void Config::ReadDebuggingValues() {
641 ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); 641 ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
642 Settings::values.extended_logging = 642 Settings::values.extended_logging =
643 ReadSetting(QStringLiteral("extended_logging"), false).toBool(); 643 ReadSetting(QStringLiteral("extended_logging"), false).toBool();
644 Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
644 645
645 qt_config->endGroup(); 646 qt_config->endGroup();
646} 647}
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 121873f95..2a5b3f5e7 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -34,6 +34,7 @@ void ConfigureDebug::SetConfiguration() {
34 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); 34 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
35 ui->reporting_services->setChecked(Settings::values.reporting_services); 35 ui->reporting_services->setChecked(Settings::values.reporting_services);
36 ui->quest_flag->setChecked(Settings::values.quest_flag); 36 ui->quest_flag->setChecked(Settings::values.quest_flag);
37 ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
37 ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 38 ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
38 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); 39 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
39 ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 40 ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
@@ -47,6 +48,7 @@ void ConfigureDebug::ApplyConfiguration() {
47 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); 48 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
48 Settings::values.reporting_services = ui->reporting_services->isChecked(); 49 Settings::values.reporting_services = ui->reporting_services->isChecked();
49 Settings::values.quest_flag = ui->quest_flag->isChecked(); 50 Settings::values.quest_flag = ui->quest_flag->isChecked();
51 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
50 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); 52 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
51 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); 53 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
52 Settings::values.extended_logging = ui->extended_logging->isChecked(); 54 Settings::values.extended_logging = ui->extended_logging->isChecked();
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 9186aa732..ae48b728c 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -185,6 +185,28 @@
185 </property> 185 </property>
186 </widget> 186 </widget>
187 </item> 187 </item>
188 <item>
189 <widget class="QCheckBox" name="use_auto_stub">
190 <property name="text">
191 <string>Enable Auto-Stub</string>
192 </property>
193 </widget>
194 </item>
195 <item>
196 <widget class="QLabel" name="label_3">
197 <property name="font">
198 <font>
199 <italic>true</italic>
200 </font>
201 </property>
202 <property name="text">
203 <string>This will be reset automatically when yuzu closes.</string>
204 </property>
205 <property name="indent">
206 <number>20</number>
207 </property>
208 </widget>
209 </item>
188 </layout> 210 </layout>
189 </widget> 211 </widget>
190 </item> 212 </item>
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index bde2d4620..58f644af4 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -103,7 +103,10 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit)
103 str = QFileDialog::getOpenFileName(this, caption, QFileInfo(edit->text()).dir().path(), 103 str = QFileDialog::getOpenFileName(this, caption, QFileInfo(edit->text()).dir().path(),
104 QStringLiteral("NX Gamecard;*.xci")); 104 QStringLiteral("NX Gamecard;*.xci"));
105 } else { 105 } else {
106 str = QFileDialog::getExistingDirectory(this, caption, edit->text()) + QDir::separator(); 106 str = QFileDialog::getExistingDirectory(this, caption, edit->text());
107 if (!str.isNull() && str.back() != QDir::separator()) {
108 str.append(QDir::separator());
109 }
107 } 110 }
108 111
109 if (str.isEmpty()) 112 if (str.isEmpty())
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 9ff32aec4..49acc48b2 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -227,7 +227,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
227 vulkan_devices.clear(); 227 vulkan_devices.clear();
228 vulkan_devices.reserve(physical_devices.size()); 228 vulkan_devices.reserve(physical_devices.size());
229 for (const VkPhysicalDevice device : physical_devices) { 229 for (const VkPhysicalDevice device : physical_devices) {
230 const char* const name = vk::PhysicalDevice(device, dld).GetProperties().deviceName; 230 const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
231 vulkan_devices.push_back(QString::fromStdString(name)); 231 vulkan_devices.push_back(QString::fromStdString(name));
232 } 232 }
233 233
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 52fdf7265..083d1ea43 100644
--- a/src/yuzu/configuration/configure_motion_touch.cpp
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -23,8 +23,7 @@
23#include "yuzu/configuration/configure_touch_from_button.h" 23#include "yuzu/configuration/configure_touch_from_button.h"
24 24
25CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, 25CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
26 const std::string& host, u16 port, 26 const std::string& host, u16 port)
27 u8 pad_index)
28 : QDialog(parent) { 27 : QDialog(parent) {
29 layout = new QVBoxLayout; 28 layout = new QVBoxLayout;
30 status_label = new QLabel(tr("Communicating with the server...")); 29 status_label = new QLabel(tr("Communicating with the server..."));
@@ -41,7 +40,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
41 40
42 using namespace InputCommon::CemuhookUDP; 41 using namespace InputCommon::CemuhookUDP;
43 job = std::make_unique<CalibrationConfigurationJob>( 42 job = std::make_unique<CalibrationConfigurationJob>(
44 host, port, pad_index, 43 host, port,
45 [this](CalibrationConfigurationJob::Status status) { 44 [this](CalibrationConfigurationJob::Status status) {
46 QString text; 45 QString text;
47 switch (status) { 46 switch (status) {
@@ -217,7 +216,7 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
217 ui->udp_test->setText(tr("Testing")); 216 ui->udp_test->setText(tr("Testing"));
218 udp_test_in_progress = true; 217 udp_test_in_progress = true;
219 InputCommon::CemuhookUDP::TestCommunication( 218 InputCommon::CemuhookUDP::TestCommunication(
220 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0, 219 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()),
221 [this] { 220 [this] {
222 LOG_INFO(Frontend, "UDP input test success"); 221 LOG_INFO(Frontend, "UDP input test success");
223 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); 222 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
@@ -232,7 +231,7 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() {
232 ui->touch_calibration_config->setEnabled(false); 231 ui->touch_calibration_config->setEnabled(false);
233 ui->touch_calibration_config->setText(tr("Configuring")); 232 ui->touch_calibration_config->setText(tr("Configuring"));
234 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(), 233 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(),
235 static_cast<u16>(ui->udp_port->text().toUInt()), 0); 234 static_cast<u16>(ui->udp_port->text().toUInt()));
236 dialog.exec(); 235 dialog.exec();
237 if (dialog.completed) { 236 if (dialog.completed) {
238 min_x = dialog.min_x; 237 min_x = dialog.min_x;
diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h
index d76bc8154..8b707d2ff 100644
--- a/src/yuzu/configuration/configure_motion_touch.h
+++ b/src/yuzu/configuration/configure_motion_touch.h
@@ -29,8 +29,7 @@ class ConfigureMotionTouch;
29class CalibrationConfigurationDialog : public QDialog { 29class CalibrationConfigurationDialog : public QDialog {
30 Q_OBJECT 30 Q_OBJECT
31public: 31public:
32 explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, 32 explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port);
33 u8 pad_index);
34 ~CalibrationConfigurationDialog() override; 33 ~CalibrationConfigurationDialog() override;
35 34
36private: 35private:
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 24bfa4d34..06445b993 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -320,6 +320,34 @@ GMainWindow::GMainWindow()
320 continue; 320 continue;
321 } 321 }
322 322
323 // Launch game with a specific user
324 if (args[i] == QStringLiteral("-u")) {
325 if (i >= args.size() - 1) {
326 continue;
327 }
328
329 if (args[i + 1].startsWith(QChar::fromLatin1('-'))) {
330 continue;
331 }
332
333 bool argument_ok;
334 const std::size_t selected_user = args[++i].toUInt(&argument_ok);
335
336 if (!argument_ok) {
337 LOG_ERROR(Frontend, "Invalid user argument");
338 continue;
339 }
340
341 const Service::Account::ProfileManager manager;
342 if (!manager.UserExistsIndex(selected_user)) {
343 LOG_ERROR(Frontend, "Selected user doesn't exist");
344 continue;
345 }
346
347 Settings::values.current_user = selected_user;
348 continue;
349 }
350
323 // Launch game at path 351 // Launch game at path
324 if (args[i] == QStringLiteral("-g")) { 352 if (args[i] == QStringLiteral("-g")) {
325 if (i >= args.size() - 1) { 353 if (i >= args.size() - 1) {