Compare commits
82 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5da70f7197 | ||
|
|
e3122c5b46 | ||
|
|
7eb7d56b1b | ||
|
|
8cb6b33809 | ||
|
|
8ad64bc253 | ||
|
|
eea2145698 | ||
|
|
e684515578 | ||
|
|
ae1a8a7dc7 | ||
|
|
fd5d7947f6 | ||
|
|
a67bdeb2c2 | ||
|
|
f1e12e3b08 | ||
|
|
93061d1ea1 | ||
|
|
6d12e7320b | ||
|
|
78ff2862f6 | ||
|
|
197e13d93d | ||
|
|
bedb5135c0 | ||
|
|
256c7ec0a7 | ||
|
|
e5f1b22e16 | ||
|
|
b0beca52a3 | ||
|
|
711190bb67 | ||
|
|
b9a86b040b | ||
|
|
346c253cd2 | ||
|
|
ce191ba32b | ||
|
|
23371fa187 | ||
|
|
af7f3f078c | ||
|
|
66b8042b59 | ||
|
|
8acf728d5d | ||
|
|
6e293be20b | ||
|
|
20db91f0fc | ||
|
|
8a526b2c26 | ||
|
|
565a1226d7 | ||
|
|
fd0ef5411c | ||
|
|
b99c4dd568 | ||
|
|
c0fd793ef6 | ||
|
|
27a36cd51b | ||
|
|
e681f5678c | ||
|
|
e34e1b1c95 | ||
|
|
76a676883a | ||
|
|
3e47ebe2e9 | ||
|
|
c309a1c69b | ||
|
|
4cbdce17b6 | ||
|
|
ec423c6919 | ||
|
|
24e1e4dcee | ||
|
|
975122f4bb | ||
|
|
a1adcc31d3 | ||
|
|
330358cd16 | ||
|
|
fc6a2fe779 | ||
|
|
b77a247e8c | ||
|
|
2dc0ff79ec | ||
|
|
1fa16bc594 | ||
|
|
d9e2824c4e | ||
|
|
d35c989902 | ||
|
|
7ffb96f474 | ||
|
|
e9701a3cda | ||
|
|
b23c358e3d | ||
|
|
cdc73498e3 | ||
|
|
8d8f850bd6 | ||
|
|
03e8d9aca7 | ||
|
|
a3b7b5b22a | ||
|
|
745d16132b | ||
|
|
3e8cd91d54 | ||
|
|
42c944b250 | ||
|
|
2c01669046 | ||
|
|
61b4588517 | ||
|
|
b1b13ddc6b | ||
|
|
8d6aefdcc4 | ||
|
|
0de6b9e3f5 | ||
|
|
a9e4dddad5 | ||
|
|
44f616edb9 | ||
|
|
b9bba3ac89 | ||
|
|
0eacf547c0 | ||
|
|
3e6d81a008 | ||
|
|
2e1e725443 | ||
|
|
907507886d | ||
|
|
9dcc7bde8b | ||
|
|
8e56a84566 | ||
|
|
bbd502f67a | ||
|
|
1492a65454 | ||
|
|
dd12dd4c67 | ||
|
|
013c34cb32 | ||
|
|
f9fc996083 | ||
|
|
fc0c4db20d |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -52,3 +52,6 @@
|
||||
[submodule "libadrenotools"]
|
||||
path = externals/libadrenotools
|
||||
url = https://github.com/bylaws/libadrenotools
|
||||
[submodule "tzdb_to_nx"]
|
||||
path = externals/nx_tzdb/tzdb_to_nx
|
||||
url = https://github.com/lat9nq/tzdb_to_nx.git
|
||||
|
||||
@@ -59,6 +59,8 @@ option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON)
|
||||
|
||||
option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF)
|
||||
|
||||
option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
|
||||
|
||||
# On Android, fetch and compile libcxx before doing anything else
|
||||
|
||||
100
externals/nx_tzdb/CMakeLists.txt
vendored
100
externals/nx_tzdb/CMakeLists.txt
vendored
@@ -1,24 +1,60 @@
|
||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(NX_TZDB_VERSION "220816")
|
||||
set(NX_TZDB_DOWNLOAD_URL "https://github.com/lat9nq/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
|
||||
|
||||
set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
|
||||
set(NX_TZDB_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
|
||||
|
||||
set(NX_TZDB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
|
||||
if (NOT EXISTS ${NX_TZDB_ARCHIVE})
|
||||
file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE})
|
||||
add_library(nx_tzdb INTERFACE)
|
||||
|
||||
find_program(GIT git)
|
||||
find_program(GNU_MAKE make)
|
||||
find_program(DATE_PROG date)
|
||||
|
||||
set(CAN_BUILD_NX_TZDB true)
|
||||
|
||||
if (NOT GIT)
|
||||
set(CAN_BUILD_NX_TZDB false)
|
||||
endif()
|
||||
if (NOT GNU_MAKE)
|
||||
set(CAN_BUILD_NX_TZDB false)
|
||||
endif()
|
||||
if (NOT DATE_PROG)
|
||||
set(CAN_BUILD_NX_TZDB false)
|
||||
endif()
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID)
|
||||
# tzdb_to_nx currently requires a posix-compliant host
|
||||
# MinGW and Android are handled here due to the executable format being different from the host system
|
||||
# TODO (lat9nq): cross-compiling support
|
||||
set(CAN_BUILD_NX_TZDB false)
|
||||
endif()
|
||||
|
||||
set(NX_TZDB_VERSION "220816")
|
||||
set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
|
||||
|
||||
set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
|
||||
|
||||
if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ARCHIVE})
|
||||
set(NX_TZDB_DOWNLOAD_URL "https://github.com/lat9nq/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
|
||||
|
||||
message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...")
|
||||
file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE}
|
||||
STATUS NX_TZDB_DOWNLOAD_STATUS)
|
||||
list(GET NX_TZDB_DOWNLOAD_STATUS 0 NX_TZDB_DOWNLOAD_STATUS_CODE)
|
||||
if (NOT NX_TZDB_DOWNLOAD_STATUS_CODE EQUAL 0)
|
||||
message(FATAL_ERROR "Time zone data download failed (status code ${NX_TZDB_DOWNLOAD_STATUS_CODE})")
|
||||
endif()
|
||||
|
||||
file(ARCHIVE_EXTRACT
|
||||
INPUT
|
||||
${NX_TZDB_ARCHIVE}
|
||||
DESTINATION
|
||||
${NX_TZDB_DIR})
|
||||
${NX_TZDB_ROMFS_DIR})
|
||||
elseif (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA)
|
||||
add_subdirectory(tzdb_to_nx)
|
||||
add_dependencies(nx_tzdb x80e)
|
||||
|
||||
set(NX_TZDB_ROMFS_DIR "${NX_TZDB_DIR}")
|
||||
endif()
|
||||
|
||||
add_library(nx_tzdb INTERFACE)
|
||||
target_include_directories(nx_tzdb
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
INTERFACE ${NX_TZDB_INCLUDE_DIR})
|
||||
@@ -41,25 +77,25 @@ function(CreateHeader ZONE_PATH HEADER_NAME)
|
||||
target_sources(nx_tzdb PRIVATE ${HEADER_PATH})
|
||||
endfunction()
|
||||
|
||||
CreateHeader(${NX_TZDB_DIR} base)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo zoneinfo)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Africa africa)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America america)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Argentina america_argentina)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Indiana america_indiana)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Kentucky america_kentucky)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/North_Dakota america_north_dakota)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Antartica antartica)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Arctic arctic)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Asia asia)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Atlantic atlantic)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Australia australia)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Brazil brazil)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Canada canada)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Chile chile)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Etc etc)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Europe europe)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Indian indian)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Mexico mexico)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Pacific pacific)
|
||||
CreateHeader(${NX_TZDB_DIR}/zoneinfo/US us)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR} base)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo zoneinfo)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Africa africa)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America america)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Argentina america_argentina)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Indiana america_indiana)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Kentucky america_kentucky)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/North_Dakota america_north_dakota)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Antarctica antarctica)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Arctic arctic)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Asia asia)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Atlantic atlantic)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Australia australia)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Brazil brazil)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Canada canada)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Chile chile)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Etc etc)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Europe europe)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Indian indian)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Mexico mexico)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Pacific pacific)
|
||||
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/US us)
|
||||
|
||||
8
externals/nx_tzdb/NxTzdbCreateHeader.cmake
vendored
8
externals/nx_tzdb/NxTzdbCreateHeader.cmake
vendored
@@ -15,7 +15,7 @@ set(DIRECTORY_NAME ${HEADER_NAME})
|
||||
|
||||
set(FILE_DATA "")
|
||||
foreach(ZONE_FILE ${FILE_LIST})
|
||||
if ("${ZONE_FILE}" STREQUAL "\n")
|
||||
if (ZONE_FILE STREQUAL "\n")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
@@ -26,13 +26,13 @@ foreach(ZONE_FILE ${FILE_LIST})
|
||||
foreach(I RANGE 0 ${ZONE_DATA_LEN} 2)
|
||||
math(EXPR BREAK_LINE "(${I} + 2) % 38")
|
||||
|
||||
string(SUBSTRING "${ZONE_DATA}" "${I}" "2" HEX_DATA)
|
||||
if ("${HEX_DATA}" STREQUAL "")
|
||||
string(SUBSTRING "${ZONE_DATA}" "${I}" 2 HEX_DATA)
|
||||
if (NOT HEX_DATA)
|
||||
break()
|
||||
endif()
|
||||
|
||||
string(APPEND FILE_DATA "0x${HEX_DATA},")
|
||||
if ("${BREAK_LINE}" STREQUAL "0")
|
||||
if (BREAK_LINE EQUAL 0)
|
||||
string(APPEND FILE_DATA "\n")
|
||||
else()
|
||||
string(APPEND FILE_DATA " ")
|
||||
|
||||
2
externals/nx_tzdb/include/nx_tzdb.h
vendored
2
externals/nx_tzdb/include/nx_tzdb.h
vendored
@@ -9,7 +9,7 @@
|
||||
#include "nx_tzdb/america_indiana.h"
|
||||
#include "nx_tzdb/america_kentucky.h"
|
||||
#include "nx_tzdb/america_north_dakota.h"
|
||||
#include "nx_tzdb/antartica.h"
|
||||
#include "nx_tzdb/antarctica.h"
|
||||
#include "nx_tzdb/arctic.h"
|
||||
#include "nx_tzdb/asia.h"
|
||||
#include "nx_tzdb/atlantic.h"
|
||||
|
||||
1
externals/nx_tzdb/tzdb_to_nx
vendored
Submodule
1
externals/nx_tzdb/tzdb_to_nx
vendored
Submodule
Submodule externals/nx_tzdb/tzdb_to_nx added at 8c272f21d1
2
externals/vcpkg
vendored
2
externals/vcpkg
vendored
Submodule externals/vcpkg updated: a487471068...cbf56573a9
@@ -163,13 +163,14 @@ android {
|
||||
tasks.getByPath("preBuild").dependsOn("ktlintCheck")
|
||||
|
||||
ktlint {
|
||||
version.set("0.47.0")
|
||||
version.set("0.47.1")
|
||||
android.set(true)
|
||||
ignoreFailures.set(false)
|
||||
disabledRules.set(
|
||||
setOf(
|
||||
"no-wildcard-imports",
|
||||
"package-name"
|
||||
"package-name",
|
||||
"import-ordering"
|
||||
)
|
||||
)
|
||||
reporters {
|
||||
|
||||
@@ -68,79 +68,109 @@ class HomeSettingsFragment : Fragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
mainActivity = requireActivity() as MainActivity
|
||||
|
||||
val optionsList: MutableList<HomeSetting> = mutableListOf(
|
||||
HomeSetting(
|
||||
R.string.advanced_settings,
|
||||
R.string.settings_description,
|
||||
R.drawable.ic_settings
|
||||
) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") },
|
||||
HomeSetting(
|
||||
R.string.open_user_folder,
|
||||
R.string.open_user_folder_description,
|
||||
R.drawable.ic_folder_open
|
||||
) { openFileManager() },
|
||||
HomeSetting(
|
||||
R.string.preferences_theme,
|
||||
R.string.theme_and_color_description,
|
||||
R.drawable.ic_palette
|
||||
) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") },
|
||||
HomeSetting(
|
||||
R.string.install_gpu_driver,
|
||||
R.string.install_gpu_driver_description,
|
||||
R.drawable.ic_exit
|
||||
) { driverInstaller() },
|
||||
HomeSetting(
|
||||
R.string.install_amiibo_keys,
|
||||
R.string.install_amiibo_keys_description,
|
||||
R.drawable.ic_nfc
|
||||
) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) },
|
||||
HomeSetting(
|
||||
R.string.install_game_content,
|
||||
R.string.install_game_content_description,
|
||||
R.drawable.ic_system_update_alt
|
||||
) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) },
|
||||
HomeSetting(
|
||||
R.string.select_games_folder,
|
||||
R.string.select_games_folder_description,
|
||||
R.drawable.ic_add
|
||||
) {
|
||||
mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
|
||||
},
|
||||
HomeSetting(
|
||||
R.string.manage_save_data,
|
||||
R.string.import_export_saves_description,
|
||||
R.drawable.ic_save
|
||||
) {
|
||||
ImportExportSavesFragment().show(
|
||||
parentFragmentManager,
|
||||
ImportExportSavesFragment.TAG
|
||||
val optionsList: MutableList<HomeSetting> = mutableListOf<HomeSetting>().apply {
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.advanced_settings,
|
||||
R.string.settings_description,
|
||||
R.drawable.ic_settings
|
||||
) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.open_user_folder,
|
||||
R.string.open_user_folder_description,
|
||||
R.drawable.ic_folder_open
|
||||
) { openFileManager() }
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.preferences_theme,
|
||||
R.string.theme_and_color_description,
|
||||
R.drawable.ic_palette
|
||||
) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
|
||||
)
|
||||
|
||||
if (GpuDriverHelper.supportsCustomDriverLoading()) {
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_gpu_driver,
|
||||
R.string.install_gpu_driver_description,
|
||||
R.drawable.ic_exit
|
||||
) { driverInstaller() }
|
||||
)
|
||||
},
|
||||
HomeSetting(
|
||||
R.string.install_prod_keys,
|
||||
R.string.install_prod_keys_description,
|
||||
R.drawable.ic_unlock
|
||||
) { mainActivity.getProdKey.launch(arrayOf("*/*")) },
|
||||
HomeSetting(
|
||||
R.string.install_firmware,
|
||||
R.string.install_firmware_description,
|
||||
R.drawable.ic_firmware
|
||||
) { mainActivity.getFirmware.launch(arrayOf("application/zip")) },
|
||||
HomeSetting(
|
||||
R.string.share_log,
|
||||
R.string.share_log_description,
|
||||
R.drawable.ic_log
|
||||
) { shareLog() },
|
||||
HomeSetting(
|
||||
R.string.about,
|
||||
R.string.about_description,
|
||||
R.drawable.ic_info_outline
|
||||
) {
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
parentFragmentManager.primaryNavigationFragment?.findNavController()
|
||||
?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
|
||||
}
|
||||
)
|
||||
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_amiibo_keys,
|
||||
R.string.install_amiibo_keys_description,
|
||||
R.drawable.ic_nfc
|
||||
) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_game_content,
|
||||
R.string.install_game_content_description,
|
||||
R.drawable.ic_system_update_alt
|
||||
) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.select_games_folder,
|
||||
R.string.select_games_folder_description,
|
||||
R.drawable.ic_add
|
||||
) {
|
||||
mainActivity.getGamesDirectory.launch(
|
||||
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
|
||||
)
|
||||
}
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.manage_save_data,
|
||||
R.string.import_export_saves_description,
|
||||
R.drawable.ic_save
|
||||
) {
|
||||
ImportExportSavesFragment().show(
|
||||
parentFragmentManager,
|
||||
ImportExportSavesFragment.TAG
|
||||
)
|
||||
}
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_prod_keys,
|
||||
R.string.install_prod_keys_description,
|
||||
R.drawable.ic_unlock
|
||||
) { mainActivity.getProdKey.launch(arrayOf("*/*")) }
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_firmware,
|
||||
R.string.install_firmware_description,
|
||||
R.drawable.ic_firmware
|
||||
) { mainActivity.getFirmware.launch(arrayOf("application/zip")) }
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.share_log,
|
||||
R.string.share_log_description,
|
||||
R.drawable.ic_log
|
||||
) { shareLog() }
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.about,
|
||||
R.string.about_description,
|
||||
R.drawable.ic_info_outline
|
||||
) {
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
parentFragmentManager.primaryNavigationFragment?.findNavController()
|
||||
?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (!BuildConfig.PREMIUM) {
|
||||
optionsList.add(
|
||||
|
||||
@@ -113,6 +113,8 @@ object GpuDriverHelper {
|
||||
initializeDriverParameters(context)
|
||||
}
|
||||
|
||||
external fun supportsCustomDriverLoading(): Boolean
|
||||
|
||||
// Parse the custom driver metadata to retrieve the name.
|
||||
val customDriverName: String?
|
||||
get() {
|
||||
|
||||
@@ -560,6 +560,26 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(
|
||||
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool CheckKgslPresent() {
|
||||
constexpr auto KgslPath{"/dev/kgsl-3d0"};
|
||||
|
||||
return access(KgslPath, F_OK) == 0;
|
||||
}
|
||||
|
||||
[[maybe_unused]] bool SupportsCustomDriver() {
|
||||
return android_get_device_api_level() >= 28 && CheckKgslPresent();
|
||||
}
|
||||
|
||||
jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject instance) {
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
// If the KGSL device exists custom drivers can be loaded using adrenotools
|
||||
return SupportsCustomDriver();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz) {
|
||||
Core::Crypto::KeyManager::Instance().ReloadKeys();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "audio_buffer.h"
|
||||
#include "audio_core/device/device_session.h"
|
||||
@@ -48,7 +49,7 @@ public:
|
||||
*
|
||||
* @param out_buffers - The buffers which were registered.
|
||||
*/
|
||||
void RegisterBuffers(std::vector<AudioBuffer>& out_buffers) {
|
||||
void RegisterBuffers(boost::container::static_vector<AudioBuffer, N>& out_buffers) {
|
||||
std::scoped_lock l{lock};
|
||||
const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit),
|
||||
BufferAppendLimit - registered_count)};
|
||||
@@ -162,7 +163,8 @@ public:
|
||||
* @param max_buffers - Maximum number of buffers to released.
|
||||
* @return The number of buffers released.
|
||||
*/
|
||||
u32 GetRegisteredAppendedBuffers(std::vector<AudioBuffer>& buffers_flushed, u32 max_buffers) {
|
||||
u32 GetRegisteredAppendedBuffers(
|
||||
boost::container::static_vector<AudioBuffer, N>& buffers_flushed, u32 max_buffers) {
|
||||
std::scoped_lock l{lock};
|
||||
if (registered_count + appended_count == 0) {
|
||||
return 0;
|
||||
@@ -270,7 +272,7 @@ public:
|
||||
*/
|
||||
bool FlushBuffers(u32& buffers_released) {
|
||||
std::scoped_lock l{lock};
|
||||
std::vector<AudioBuffer> buffers_flushed{};
|
||||
boost::container::static_vector<AudioBuffer, N> buffers_flushed{};
|
||||
|
||||
buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit);
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ void DeviceSession::ClearBuffers() {
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
|
||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
|
||||
for (const auto& buffer : buffers) {
|
||||
Sink::SinkBuffer new_buffer{
|
||||
.frames = buffer.size / (channel_count * sizeof(s16)),
|
||||
@@ -88,13 +88,13 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
|
||||
.consumed = false,
|
||||
};
|
||||
|
||||
tmp_samples.resize_destructive(buffer.size / sizeof(s16));
|
||||
if (type == Sink::StreamType::In) {
|
||||
std::vector<s16> samples{};
|
||||
stream->AppendBuffer(new_buffer, samples);
|
||||
stream->AppendBuffer(new_buffer, tmp_samples);
|
||||
} else {
|
||||
std::vector<s16> samples(buffer.size / sizeof(s16));
|
||||
system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size);
|
||||
stream->AppendBuffer(new_buffer, samples);
|
||||
system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(),
|
||||
buffer.size);
|
||||
stream->AppendBuffer(new_buffer, tmp_samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/sink/sink.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -62,7 +63,7 @@ public:
|
||||
*
|
||||
* @param buffers - The buffers to play.
|
||||
*/
|
||||
void AppendBuffers(std::span<const AudioBuffer> buffers) const;
|
||||
void AppendBuffers(std::span<const AudioBuffer> buffers);
|
||||
|
||||
/**
|
||||
* (Audio In only) Pop samples from the backend, and write them back to this buffer's address.
|
||||
@@ -146,8 +147,8 @@ private:
|
||||
std::shared_ptr<Core::Timing::EventType> thread_event;
|
||||
/// Is this session initialised?
|
||||
bool initialized{};
|
||||
/// Buffer queue
|
||||
std::vector<AudioBuffer> buffer_queue{};
|
||||
/// Temporary sample buffer
|
||||
Common::ScratchBuffer<s16> tmp_samples{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "audio_core/audio_event.h"
|
||||
#include "audio_core/audio_manager.h"
|
||||
#include "audio_core/in/audio_in_system.h"
|
||||
@@ -89,7 +90,7 @@ Result System::Start() {
|
||||
session->Start();
|
||||
state = State::Started;
|
||||
|
||||
std::vector<AudioBuffer> buffers_to_flush{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
|
||||
buffers.RegisterBuffers(buffers_to_flush);
|
||||
session->AppendBuffers(buffers_to_flush);
|
||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||
@@ -134,7 +135,7 @@ bool System::AppendBuffer(const AudioInBuffer& buffer, const u64 tag) {
|
||||
|
||||
void System::RegisterBuffers() {
|
||||
if (state == State::Started) {
|
||||
std::vector<AudioBuffer> registered_buffers{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
|
||||
buffers.RegisterBuffers(registered_buffers);
|
||||
session->AppendBuffers(registered_buffers);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ Result System::Start() {
|
||||
session->Start();
|
||||
state = State::Started;
|
||||
|
||||
std::vector<AudioBuffer> buffers_to_flush{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
|
||||
buffers.RegisterBuffers(buffers_to_flush);
|
||||
session->AppendBuffers(buffers_to_flush);
|
||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||
@@ -134,7 +134,7 @@ bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) {
|
||||
|
||||
void System::RegisterBuffers() {
|
||||
if (state == State::Started) {
|
||||
std::vector<AudioBuffer> registered_buffers{};
|
||||
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
|
||||
buffers.RegisterBuffers(registered_buffers);
|
||||
session->AppendBuffers(registered_buffers);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer::ADSP {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "common/thread.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
|
||||
MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97));
|
||||
|
||||
@@ -144,6 +143,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
|
||||
|
||||
mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK);
|
||||
|
||||
// 0.12 seconds (2304000 / 19200000)
|
||||
constexpr u64 max_process_time{2'304'000ULL};
|
||||
|
||||
while (!stop_token.stop_requested()) {
|
||||
@@ -184,8 +184,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
|
||||
u64 max_time{max_process_time};
|
||||
if (index == 1 && command_buffer.applet_resource_user_id ==
|
||||
mailbox->GetCommandBuffer(0).applet_resource_user_id) {
|
||||
max_time = max_process_time -
|
||||
Core::Timing::CyclesToNs(render_times_taken[0]).count();
|
||||
max_time = max_process_time - render_times_taken[0];
|
||||
if (render_times_taken[0] > max_process_time) {
|
||||
max_time = 0;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer::ADSP {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "audio_core/renderer/command/resample/resample.h"
|
||||
#include "common/fixed_point.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
@@ -27,6 +28,7 @@ constexpr std::array<u8, 3> PitchBySrcQuality = {4, 8, 4};
|
||||
template <typename T>
|
||||
static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const DecodeArg& req) {
|
||||
std::array<T, TempBufferSize> tmp_samples{};
|
||||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||
|
||||
@@ -49,18 +51,17 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const u64 size{channel_count * samples_to_decode};
|
||||
const u64 size_bytes{size * sizeof(T)};
|
||||
|
||||
std::vector<T> samples(size);
|
||||
memory.ReadBlockUnsafe(source, samples.data(), size_bytes);
|
||||
memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes);
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
|
||||
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
|
||||
std::numeric_limits<s16>::max())};
|
||||
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
|
||||
}
|
||||
} else {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
out_buffer[i] = samples[i * channel_count + req.target_channel];
|
||||
out_buffer[i] = tmp_samples[i * channel_count + req.target_channel];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -73,17 +74,16 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
}
|
||||
|
||||
const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
|
||||
std::vector<T> samples(samples_to_decode);
|
||||
memory.ReadBlockUnsafe(source, samples.data(), samples_to_decode * sizeof(T));
|
||||
memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T));
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
for (u32 i = 0; i < samples_to_decode; i++) {
|
||||
auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] *
|
||||
auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] *
|
||||
std::numeric_limits<s16>::max())};
|
||||
out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max));
|
||||
}
|
||||
} else {
|
||||
std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16));
|
||||
std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -101,6 +101,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
*/
|
||||
static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
const DecodeArg& req) {
|
||||
std::array<u8, TempBufferSize> wavebuffer{};
|
||||
constexpr u32 SamplesPerFrame{14};
|
||||
constexpr u32 NibblesPerFrame{16};
|
||||
|
||||
@@ -138,9 +139,7 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
||||
}
|
||||
|
||||
const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
|
||||
std::vector<u8> wavebuffer(size);
|
||||
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(),
|
||||
wavebuffer.size());
|
||||
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size);
|
||||
|
||||
auto context{req.adpcm_context};
|
||||
auto header{context->header};
|
||||
@@ -258,7 +257,7 @@ void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuf
|
||||
u32 offset{voice_state.offset};
|
||||
|
||||
auto output_buffer{args.output};
|
||||
std::vector<s16> temp_buffer(TempBufferSize, 0);
|
||||
std::array<s16, TempBufferSize> temp_buffer{};
|
||||
|
||||
while (remaining_sample_count > 0) {
|
||||
const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)};
|
||||
|
||||
@@ -44,8 +44,8 @@ static void InitializeCompressorEffect(const CompressorInfo::ParameterVersion2&
|
||||
|
||||
static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params,
|
||||
CompressorInfo::State& state, bool enabled,
|
||||
std::vector<std::span<const s32>> input_buffers,
|
||||
std::vector<std::span<s32>> output_buffers, u32 sample_count) {
|
||||
std::span<std::span<const s32>> input_buffers,
|
||||
std::span<std::span<s32>> output_buffers, u32 sample_count) {
|
||||
if (enabled) {
|
||||
auto state_00{state.unk_00};
|
||||
auto state_04{state.unk_04};
|
||||
@@ -124,8 +124,8 @@ void CompressorCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor&
|
||||
}
|
||||
|
||||
void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
||||
@@ -51,7 +51,7 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params,
|
||||
state.delay_lines[channel].sample_count_max = sample_count_max.to_int_floor();
|
||||
state.delay_lines[channel].sample_count = sample_count.to_int_floor();
|
||||
state.delay_lines[channel].buffer.resize(state.delay_lines[channel].sample_count, 0);
|
||||
if (state.delay_lines[channel].buffer.size() == 0) {
|
||||
if (state.delay_lines[channel].sample_count == 0) {
|
||||
state.delay_lines[channel].buffer.push_back(0);
|
||||
}
|
||||
state.delay_lines[channel].buffer_pos = 0;
|
||||
@@ -74,8 +74,8 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params,
|
||||
*/
|
||||
template <size_t NumChannels>
|
||||
static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
||||
std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
std::span<std::span<const s32>> inputs, std::span<std::span<s32>> outputs,
|
||||
const u32 sample_count) {
|
||||
for (u32 sample_index = 0; sample_index < sample_count; sample_index++) {
|
||||
std::array<Common::FixedPoint<50, 14>, NumChannels> input_samples{};
|
||||
for (u32 channel = 0; channel < NumChannels; channel++) {
|
||||
@@ -153,8 +153,8 @@ static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::St
|
||||
* @param sample_count - Number of samples to process.
|
||||
*/
|
||||
static void ApplyDelayEffect(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
||||
const bool enabled, std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
const bool enabled, std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
||||
|
||||
if (!IsChannelCountValid(params.channel_count)) {
|
||||
LOG_ERROR(Service_Audio, "Invalid delay channels {}", params.channel_count);
|
||||
@@ -208,8 +208,8 @@ void DelayCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proce
|
||||
}
|
||||
|
||||
void DelayCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
||||
@@ -408,8 +408,8 @@ void I3dl2ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor&
|
||||
}
|
||||
|
||||
void I3dl2ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
||||
@@ -47,8 +47,8 @@ static void InitializeLightLimiterEffect(const LightLimiterInfo::ParameterVersio
|
||||
*/
|
||||
static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& params,
|
||||
LightLimiterInfo::State& state, const bool enabled,
|
||||
std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count,
|
||||
std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count,
|
||||
LightLimiterInfo::StatisticsInternal* statistics) {
|
||||
constexpr s64 min{std::numeric_limits<s32>::min()};
|
||||
constexpr s64 max{std::numeric_limits<s32>::max()};
|
||||
@@ -147,8 +147,8 @@ void LightLimiterVersion1Command::Dump([[maybe_unused]] const ADSP::CommandListP
|
||||
}
|
||||
|
||||
void LightLimiterVersion1Command::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
@@ -190,8 +190,8 @@ void LightLimiterVersion2Command::Dump([[maybe_unused]] const ADSP::CommandListP
|
||||
}
|
||||
|
||||
void LightLimiterVersion2Command::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
||||
@@ -250,8 +250,8 @@ static Common::FixedPoint<50, 14> Axfx2AllPassTick(ReverbInfo::ReverbDelayLine&
|
||||
*/
|
||||
template <size_t NumChannels>
|
||||
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
||||
std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
||||
static constexpr std::array<u8, ReverbInfo::MaxDelayTaps> OutTapIndexes1Ch{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
@@ -369,8 +369,8 @@ static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, Rever
|
||||
* @param sample_count - Number of samples to process.
|
||||
*/
|
||||
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
||||
const bool enabled, std::vector<std::span<const s32>>& inputs,
|
||||
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||
const bool enabled, std::span<std::span<const s32>> inputs,
|
||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
||||
if (enabled) {
|
||||
switch (params.channel_count) {
|
||||
case 0:
|
||||
@@ -412,8 +412,8 @@ void ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proc
|
||||
}
|
||||
|
||||
void ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||
std::array<std::span<const s32>, MaxChannels> input_buffers{};
|
||||
std::array<std::span<s32>, MaxChannels> output_buffers{};
|
||||
|
||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "audio_core/renderer/command/performance/performance.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
@@ -18,20 +17,18 @@ void PerformanceCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
auto base{entry_address.translated_address};
|
||||
if (state == PerformanceState::Start) {
|
||||
auto start_time_ptr{reinterpret_cast<u32*>(base + entry_address.entry_start_time_offset)};
|
||||
*start_time_ptr = static_cast<u32>(
|
||||
Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() -
|
||||
processor.start_time - processor.current_processing_time)
|
||||
.count());
|
||||
*start_time_ptr =
|
||||
static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time -
|
||||
processor.current_processing_time);
|
||||
} else if (state == PerformanceState::Stop) {
|
||||
auto processed_time_ptr{
|
||||
reinterpret_cast<u32*>(base + entry_address.entry_processed_time_offset)};
|
||||
auto entry_count_ptr{
|
||||
reinterpret_cast<u32*>(base + entry_address.header_entry_count_offset)};
|
||||
|
||||
*processed_time_ptr = static_cast<u32>(
|
||||
Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() -
|
||||
processor.start_time - processor.current_processing_time)
|
||||
.count());
|
||||
*processed_time_ptr =
|
||||
static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time -
|
||||
processor.current_processing_time);
|
||||
(*entry_count_ptr)++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces
|
||||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||
|
||||
std::vector<s16> output(processor.sample_count);
|
||||
std::array<s16, TargetSampleCount * MaxChannels> output{};
|
||||
for (u32 channel = 0; channel < input_count; channel++) {
|
||||
auto input{processor.mix_buffers.subspan(inputs[channel] * processor.sample_count,
|
||||
processor.sample_count)};
|
||||
@@ -33,7 +33,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces
|
||||
}
|
||||
|
||||
processor.memory->WriteBlockUnsafe(address + pos, output.data(),
|
||||
output.size() * sizeof(s16));
|
||||
processor.sample_count * sizeof(s16));
|
||||
pos += static_cast<u32>(processor.sample_count * sizeof(s16));
|
||||
if (pos >= size) {
|
||||
pos = 0;
|
||||
|
||||
@@ -33,8 +33,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
.consumed{false},
|
||||
};
|
||||
|
||||
std::vector<s16> samples(out_buffer.frames * input_count);
|
||||
|
||||
std::array<s16, TargetSampleCount * MaxChannels> samples{};
|
||||
for (u32 channel = 0; channel < input_count; channel++) {
|
||||
const auto offset{inputs[channel] * out_buffer.frames};
|
||||
|
||||
@@ -45,7 +44,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||
}
|
||||
|
||||
out_buffer.tag = reinterpret_cast<u64>(samples.data());
|
||||
stream->AppendBuffer(out_buffer, samples);
|
||||
stream->AppendBuffer(out_buffer, {samples.data(), out_buffer.frames * input_count});
|
||||
|
||||
if (stream->IsPaused()) {
|
||||
stream->Start();
|
||||
|
||||
@@ -125,10 +125,10 @@ bool MixContext::TSortInfo(const SplitterContext& splitter_context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<s32> sorted_results{node_states.GetSortedResuls()};
|
||||
const auto result_size{std::min(count, static_cast<s32>(sorted_results.size()))};
|
||||
auto sorted_results{node_states.GetSortedResuls()};
|
||||
const auto result_size{std::min(count, static_cast<s32>(sorted_results.second))};
|
||||
for (s32 i = 0; i < result_size; i++) {
|
||||
sorted_mix_infos[i] = &mix_infos[sorted_results[i]];
|
||||
sorted_mix_infos[i] = &mix_infos[sorted_results.first[i]];
|
||||
}
|
||||
|
||||
CalcMixBufferOffset();
|
||||
|
||||
@@ -134,8 +134,8 @@ u32 NodeStates::GetNodeCount() const {
|
||||
return node_count;
|
||||
}
|
||||
|
||||
std::vector<s32> NodeStates::GetSortedResuls() const {
|
||||
return {results.rbegin(), results.rbegin() + result_pos};
|
||||
std::pair<std::span<u32>::reverse_iterator, size_t> NodeStates::GetSortedResuls() const {
|
||||
return {results.rbegin(), result_pos};
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
||||
|
||||
@@ -175,7 +175,7 @@ public:
|
||||
*
|
||||
* @return Vector of nodes in reverse order.
|
||||
*/
|
||||
std::vector<s32> GetSortedResuls() const;
|
||||
std::pair<std::span<u32>::reverse_iterator, size_t> GetSortedResuls() const;
|
||||
|
||||
private:
|
||||
/// Number of nodes in the graph
|
||||
|
||||
@@ -444,6 +444,7 @@ Result System::Update(std::span<const u8> input, std::span<u8> performance, std:
|
||||
std::scoped_lock l{lock};
|
||||
|
||||
const auto start_time{core.CoreTiming().GetClockTicks()};
|
||||
std::memset(output.data(), 0, output.size());
|
||||
|
||||
InfoUpdater info_updater(input, output, process_handle, behavior);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
explicit NullSinkStreamImpl(Core::System& system_, StreamType type_)
|
||||
: SinkStream{system_, type_} {}
|
||||
~NullSinkStreamImpl() override {}
|
||||
void AppendBuffer(SinkBuffer&, std::vector<s16>&) override {}
|
||||
void AppendBuffer(SinkBuffer&, std::span<s16>) override {}
|
||||
std::vector<s16> ReleaseBuffer(u64) override {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
|
||||
namespace AudioCore::Sink {
|
||||
|
||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
||||
if (type == StreamType::In) {
|
||||
queue.enqueue(buffer);
|
||||
queued_buffers++;
|
||||
@@ -67,15 +66,16 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
||||
static_cast<s16>(std::clamp(right_sample, min, max));
|
||||
}
|
||||
|
||||
samples.resize(samples.size() / system_channels * device_channels);
|
||||
samples = samples.subspan(0, samples.size() / system_channels * device_channels);
|
||||
|
||||
} else if (system_channels == 2 && device_channels == 6) {
|
||||
// We need moar samples! Not all games will provide 6 channel audio.
|
||||
// TODO: Implement some upmixing here. Currently just passthrough, with other
|
||||
// channels left as silence.
|
||||
std::vector<s16> new_samples(samples.size() / system_channels * device_channels, 0);
|
||||
auto new_size = samples.size() / system_channels * device_channels;
|
||||
tmp_samples.resize_destructive(new_size);
|
||||
|
||||
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||
for (u32 read_index = 0, write_index = 0; read_index < new_size;
|
||||
read_index += system_channels, write_index += device_channels) {
|
||||
const auto left_sample{static_cast<s16>(std::clamp(
|
||||
static_cast<s32>(
|
||||
@@ -83,7 +83,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
||||
volume),
|
||||
min, max))};
|
||||
|
||||
new_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample;
|
||||
tmp_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample;
|
||||
|
||||
const auto right_sample{static_cast<s16>(std::clamp(
|
||||
static_cast<s32>(
|
||||
@@ -91,9 +91,9 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
||||
volume),
|
||||
min, max))};
|
||||
|
||||
new_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample;
|
||||
tmp_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample;
|
||||
}
|
||||
samples = std::move(new_samples);
|
||||
samples = std::span<s16>(tmp_samples);
|
||||
|
||||
} else if (volume != 1.0f) {
|
||||
for (u32 i = 0; i < samples.size(); i++) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/reader_writer_queue.h"
|
||||
#include "common/ring_buffer.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/thread.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -170,7 +171,7 @@ public:
|
||||
* @param buffer - Audio buffer information to be queued.
|
||||
* @param samples - The s16 samples to be queue for playback.
|
||||
*/
|
||||
virtual void AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples);
|
||||
virtual void AppendBuffer(SinkBuffer& buffer, std::span<s16> samples);
|
||||
|
||||
/**
|
||||
* Release a buffer. Audio In only, will fill a buffer with recorded samples.
|
||||
@@ -255,6 +256,8 @@ private:
|
||||
/// Signalled when ring buffer entries are consumed
|
||||
std::condition_variable_any release_cv;
|
||||
std::mutex release_mutex;
|
||||
/// Temporary buffer for appending samples when upmixing
|
||||
Common::ScratchBuffer<s16> tmp_samples{};
|
||||
};
|
||||
|
||||
using SinkStreamPtr = std::unique_ptr<SinkStream>;
|
||||
|
||||
@@ -172,6 +172,8 @@ if(ARCHITECTURE_x86_64)
|
||||
x64/cpu_wait.h
|
||||
x64/native_clock.cpp
|
||||
x64/native_clock.h
|
||||
x64/rdtsc.cpp
|
||||
x64/rdtsc.h
|
||||
x64/xbyak_abi.h
|
||||
x64/xbyak_util.h
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
@@ -53,7 +54,7 @@ public:
|
||||
return push_count;
|
||||
}
|
||||
|
||||
std::size_t Push(const std::vector<T>& input) {
|
||||
std::size_t Push(const std::span<T> input) {
|
||||
return Push(input.data(), input.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "common/concepts.h"
|
||||
#include "common/make_unique_for_overwrite.h"
|
||||
|
||||
namespace Common {
|
||||
@@ -16,6 +19,12 @@ namespace Common {
|
||||
template <typename T>
|
||||
class ScratchBuffer {
|
||||
public:
|
||||
using iterator = T*;
|
||||
using const_iterator = const T*;
|
||||
using value_type = T;
|
||||
using element_type = T;
|
||||
using iterator_category = std::contiguous_iterator_tag;
|
||||
|
||||
ScratchBuffer() = default;
|
||||
|
||||
explicit ScratchBuffer(size_t initial_capacity)
|
||||
|
||||
@@ -483,6 +483,7 @@ struct Values {
|
||||
AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3,
|
||||
"astc_recompression"};
|
||||
SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"};
|
||||
SwitchableSetting<bool> barrier_feedback_loops{true, "barrier_feedback_loops"};
|
||||
|
||||
SwitchableSetting<u8> bg_red{0, "bg_red"};
|
||||
SwitchableSetting<u8> bg_green{0, "bg_green"};
|
||||
|
||||
@@ -28,13 +28,12 @@ static s64 GetSystemTimeNS() {
|
||||
// GetSystemTimePreciseAsFileTime returns the file time in 100ns units.
|
||||
static constexpr s64 Multiplier = 100;
|
||||
// Convert Windows epoch to Unix epoch.
|
||||
static constexpr s64 WindowsEpochToUnixEpochNS = 0x19DB1DED53E8000LL;
|
||||
static constexpr s64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL;
|
||||
|
||||
FILETIME filetime;
|
||||
GetSystemTimePreciseAsFileTime(&filetime);
|
||||
return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) +
|
||||
static_cast<s64>(filetime.dwLowDateTime)) -
|
||||
WindowsEpochToUnixEpochNS;
|
||||
static_cast<s64>(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,88 +2,75 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/steady_clock.h"
|
||||
#include "common/uint128.h"
|
||||
#include "common/wall_clock.h"
|
||||
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#include "common/x64/native_clock.h"
|
||||
#include "common/x64/rdtsc.h"
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
class StandardWallClock final : public WallClock {
|
||||
public:
|
||||
explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_)
|
||||
: WallClock{emulated_cpu_frequency_, emulated_clock_frequency_, false},
|
||||
start_time{SteadyClock::Now()} {}
|
||||
explicit StandardWallClock() : start_time{SteadyClock::Now()} {}
|
||||
|
||||
std::chrono::nanoseconds GetTimeNS() override {
|
||||
std::chrono::nanoseconds GetTimeNS() const override {
|
||||
return SteadyClock::Now() - start_time;
|
||||
}
|
||||
|
||||
std::chrono::microseconds GetTimeUS() override {
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(GetTimeNS());
|
||||
std::chrono::microseconds GetTimeUS() const override {
|
||||
return static_cast<std::chrono::microseconds>(GetHostTicksElapsed() / NsToUsRatio::den);
|
||||
}
|
||||
|
||||
std::chrono::milliseconds GetTimeMS() override {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(GetTimeNS());
|
||||
std::chrono::milliseconds GetTimeMS() const override {
|
||||
return static_cast<std::chrono::milliseconds>(GetHostTicksElapsed() / NsToMsRatio::den);
|
||||
}
|
||||
|
||||
u64 GetClockCycles() override {
|
||||
const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_clock_frequency);
|
||||
return Common::Divide128On32(temp, NS_RATIO).first;
|
||||
u64 GetCNTPCT() const override {
|
||||
return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
|
||||
}
|
||||
|
||||
u64 GetCPUCycles() override {
|
||||
const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_cpu_frequency);
|
||||
return Common::Divide128On32(temp, NS_RATIO).first;
|
||||
u64 GetGPUTick() const override {
|
||||
return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
|
||||
}
|
||||
|
||||
void Pause([[maybe_unused]] bool is_paused) override {
|
||||
// Do nothing in this clock type.
|
||||
u64 GetHostTicksNow() const override {
|
||||
return static_cast<u64>(SteadyClock::Now().time_since_epoch().count());
|
||||
}
|
||||
|
||||
u64 GetHostTicksElapsed() const override {
|
||||
return static_cast<u64>(GetTimeNS().count());
|
||||
}
|
||||
|
||||
bool IsNative() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
SteadyClock::time_point start_time;
|
||||
};
|
||||
|
||||
std::unique_ptr<WallClock> CreateOptimalClock() {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
|
||||
std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
|
||||
u64 emulated_clock_frequency) {
|
||||
const auto& caps = GetCPUCaps();
|
||||
u64 rtsc_frequency = 0;
|
||||
if (caps.invariant_tsc) {
|
||||
rtsc_frequency = caps.tsc_frequency ? caps.tsc_frequency : EstimateRDTSCFrequency();
|
||||
}
|
||||
|
||||
// Fallback to StandardWallClock if the hardware TSC does not have the precision greater than:
|
||||
// - A nanosecond
|
||||
// - The emulated CPU frequency
|
||||
// - The emulated clock counter frequency (CNTFRQ)
|
||||
if (rtsc_frequency <= WallClock::NS_RATIO || rtsc_frequency <= emulated_cpu_frequency ||
|
||||
rtsc_frequency <= emulated_clock_frequency) {
|
||||
return std::make_unique<StandardWallClock>(emulated_cpu_frequency,
|
||||
emulated_clock_frequency);
|
||||
if (caps.invariant_tsc && caps.tsc_frequency >= WallClock::GPUTickFreq) {
|
||||
return std::make_unique<X64::NativeClock>(caps.tsc_frequency);
|
||||
} else {
|
||||
return std::make_unique<X64::NativeClock>(emulated_cpu_frequency, emulated_clock_frequency,
|
||||
rtsc_frequency);
|
||||
// Fallback to StandardWallClock if the hardware TSC
|
||||
// - Is not invariant
|
||||
// - Is not more precise than GPUTickFreq
|
||||
return std::make_unique<StandardWallClock>();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
|
||||
u64 emulated_clock_frequency) {
|
||||
return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency);
|
||||
return std::make_unique<StandardWallClock>();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency,
|
||||
u64 emulated_clock_frequency) {
|
||||
return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency);
|
||||
std::unique_ptr<WallClock> CreateStandardWallClock() {
|
||||
return std::make_unique<StandardWallClock>();
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <ratio>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -12,50 +13,82 @@ namespace Common {
|
||||
|
||||
class WallClock {
|
||||
public:
|
||||
static constexpr u64 NS_RATIO = 1'000'000'000;
|
||||
static constexpr u64 US_RATIO = 1'000'000;
|
||||
static constexpr u64 MS_RATIO = 1'000;
|
||||
static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
|
||||
static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz
|
||||
static constexpr u64 CPUTickFreq = 1'020'000'000; // T210/4 A57 CPU Tick Frequency = 1020.0 MHz
|
||||
|
||||
virtual ~WallClock() = default;
|
||||
|
||||
/// Returns current wall time in nanoseconds
|
||||
[[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
|
||||
/// @returns The time in nanoseconds since the construction of this clock.
|
||||
virtual std::chrono::nanoseconds GetTimeNS() const = 0;
|
||||
|
||||
/// Returns current wall time in microseconds
|
||||
[[nodiscard]] virtual std::chrono::microseconds GetTimeUS() = 0;
|
||||
/// @returns The time in microseconds since the construction of this clock.
|
||||
virtual std::chrono::microseconds GetTimeUS() const = 0;
|
||||
|
||||
/// Returns current wall time in milliseconds
|
||||
[[nodiscard]] virtual std::chrono::milliseconds GetTimeMS() = 0;
|
||||
/// @returns The time in milliseconds since the construction of this clock.
|
||||
virtual std::chrono::milliseconds GetTimeMS() const = 0;
|
||||
|
||||
/// Returns current wall time in emulated clock cycles
|
||||
[[nodiscard]] virtual u64 GetClockCycles() = 0;
|
||||
/// @returns The guest CNTPCT ticks since the construction of this clock.
|
||||
virtual u64 GetCNTPCT() const = 0;
|
||||
|
||||
/// Returns current wall time in emulated cpu cycles
|
||||
[[nodiscard]] virtual u64 GetCPUCycles() = 0;
|
||||
/// @returns The guest GPU ticks since the construction of this clock.
|
||||
virtual u64 GetGPUTick() const = 0;
|
||||
|
||||
virtual void Pause(bool is_paused) = 0;
|
||||
/// @returns The raw host timer ticks since an indeterminate epoch.
|
||||
virtual u64 GetHostTicksNow() const = 0;
|
||||
|
||||
/// Tells if the wall clock, uses the host CPU's hardware clock
|
||||
[[nodiscard]] bool IsNative() const {
|
||||
return is_native;
|
||||
/// @returns The raw host timer ticks since the construction of this clock.
|
||||
virtual u64 GetHostTicksElapsed() const = 0;
|
||||
|
||||
/// @returns Whether the clock directly uses the host's hardware clock.
|
||||
virtual bool IsNative() const = 0;
|
||||
|
||||
static inline u64 NSToCNTPCT(u64 ns) {
|
||||
return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
|
||||
}
|
||||
|
||||
static inline u64 NSToGPUTick(u64 ns) {
|
||||
return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
|
||||
}
|
||||
|
||||
// Cycle Timing
|
||||
|
||||
static inline u64 CPUTickToNS(u64 cpu_tick) {
|
||||
return cpu_tick * CPUTickToNsRatio::num / CPUTickToNsRatio::den;
|
||||
}
|
||||
|
||||
static inline u64 CPUTickToUS(u64 cpu_tick) {
|
||||
return cpu_tick * CPUTickToUsRatio::num / CPUTickToUsRatio::den;
|
||||
}
|
||||
|
||||
static inline u64 CPUTickToCNTPCT(u64 cpu_tick) {
|
||||
return cpu_tick * CPUTickToCNTPCTRatio::num / CPUTickToCNTPCTRatio::den;
|
||||
}
|
||||
|
||||
static inline u64 CPUTickToGPUTick(u64 cpu_tick) {
|
||||
return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_)
|
||||
: emulated_cpu_frequency{emulated_cpu_frequency_},
|
||||
emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {}
|
||||
using NsRatio = std::nano;
|
||||
using UsRatio = std::micro;
|
||||
using MsRatio = std::milli;
|
||||
|
||||
u64 emulated_cpu_frequency;
|
||||
u64 emulated_clock_frequency;
|
||||
using NsToUsRatio = std::ratio_divide<std::nano, std::micro>;
|
||||
using NsToMsRatio = std::ratio_divide<std::nano, std::milli>;
|
||||
using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>;
|
||||
using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>;
|
||||
|
||||
private:
|
||||
bool is_native;
|
||||
// Cycle Timing
|
||||
|
||||
using CPUTickToNsRatio = std::ratio<std::nano::den, CPUTickFreq>;
|
||||
using CPUTickToUsRatio = std::ratio<std::micro::den, CPUTickFreq>;
|
||||
using CPUTickToCNTPCTRatio = std::ratio<CNTFRQ, CPUTickFreq>;
|
||||
using CPUTickToGPUTickRatio = std::ratio<GPUTickFreq, CPUTickFreq>;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency,
|
||||
u64 emulated_clock_frequency);
|
||||
std::unique_ptr<WallClock> CreateOptimalClock();
|
||||
|
||||
[[nodiscard]] std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency,
|
||||
u64 emulated_clock_frequency);
|
||||
std::unique_ptr<WallClock> CreateStandardWallClock();
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#include "common/x64/rdtsc.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@@ -187,6 +188,8 @@ static CPUCaps Detect() {
|
||||
caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) *
|
||||
caps.tsc_crystal_ratio_numerator /
|
||||
caps.tsc_crystal_ratio_denominator;
|
||||
} else {
|
||||
caps.tsc_frequency = X64::EstimateRDTSCFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,19 +9,11 @@
|
||||
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#include "common/x64/cpu_wait.h"
|
||||
#include "common/x64/rdtsc.h"
|
||||
|
||||
namespace Common::X64 {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
__forceinline static u64 FencedRDTSC() {
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
const u64 result = __rdtsc();
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
return result;
|
||||
}
|
||||
|
||||
__forceinline static void TPAUSE() {
|
||||
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
|
||||
// For reference:
|
||||
@@ -32,16 +24,6 @@ __forceinline static void TPAUSE() {
|
||||
_tpause(0, FencedRDTSC() + PauseCycles);
|
||||
}
|
||||
#else
|
||||
static u64 FencedRDTSC() {
|
||||
u64 eax;
|
||||
u64 edx;
|
||||
asm volatile("lfence\n\t"
|
||||
"rdtsc\n\t"
|
||||
"lfence\n\t"
|
||||
: "=a"(eax), "=d"(edx));
|
||||
return (edx << 32) | eax;
|
||||
}
|
||||
|
||||
static void TPAUSE() {
|
||||
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
|
||||
// For reference:
|
||||
|
||||
@@ -1,164 +1,50 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "common/atomic_ops.h"
|
||||
#include "common/steady_clock.h"
|
||||
#include "common/uint128.h"
|
||||
#include "common/x64/native_clock.h"
|
||||
#include "common/x64/rdtsc.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
namespace Common::X64 {
|
||||
|
||||
namespace Common {
|
||||
NativeClock::NativeClock(u64 rdtsc_frequency_)
|
||||
: start_ticks{FencedRDTSC()}, rdtsc_frequency{rdtsc_frequency_},
|
||||
ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)},
|
||||
us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)},
|
||||
ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)},
|
||||
cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)},
|
||||
gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
__forceinline static u64 FencedRDTSC() {
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
const u64 result = __rdtsc();
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
static u64 FencedRDTSC() {
|
||||
u64 eax;
|
||||
u64 edx;
|
||||
asm volatile("lfence\n\t"
|
||||
"rdtsc\n\t"
|
||||
"lfence\n\t"
|
||||
: "=a"(eax), "=d"(edx));
|
||||
return (edx << 32) | eax;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <u64 Nearest>
|
||||
static u64 RoundToNearest(u64 value) {
|
||||
const auto mod = value % Nearest;
|
||||
return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod);
|
||||
std::chrono::nanoseconds NativeClock::GetTimeNS() const {
|
||||
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)};
|
||||
}
|
||||
|
||||
u64 EstimateRDTSCFrequency() {
|
||||
// Discard the first result measuring the rdtsc.
|
||||
FencedRDTSC();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
FencedRDTSC();
|
||||
|
||||
// Get the current time.
|
||||
const auto start_time = Common::RealTimeClock::Now();
|
||||
const u64 tsc_start = FencedRDTSC();
|
||||
// Wait for 250 milliseconds.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{250});
|
||||
const auto end_time = Common::RealTimeClock::Now();
|
||||
const u64 tsc_end = FencedRDTSC();
|
||||
// Calculate differences.
|
||||
const u64 timer_diff = static_cast<u64>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
|
||||
const u64 tsc_diff = tsc_end - tsc_start;
|
||||
const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
|
||||
return RoundToNearest<1000>(tsc_freq);
|
||||
std::chrono::microseconds NativeClock::GetTimeUS() const {
|
||||
return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_rdtsc_factor)};
|
||||
}
|
||||
|
||||
namespace X64 {
|
||||
NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
|
||||
u64 rtsc_frequency_)
|
||||
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
|
||||
rtsc_frequency_} {
|
||||
// Thread to re-adjust the RDTSC frequency after 10 seconds has elapsed.
|
||||
time_sync_thread = std::jthread{[this](std::stop_token token) {
|
||||
// Get the current time.
|
||||
const auto start_time = Common::RealTimeClock::Now();
|
||||
const u64 tsc_start = FencedRDTSC();
|
||||
// Wait for 10 seconds.
|
||||
if (!Common::StoppableTimedWait(token, std::chrono::seconds{10})) {
|
||||
return;
|
||||
}
|
||||
const auto end_time = Common::RealTimeClock::Now();
|
||||
const u64 tsc_end = FencedRDTSC();
|
||||
// Calculate differences.
|
||||
const u64 timer_diff = static_cast<u64>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
|
||||
const u64 tsc_diff = tsc_end - tsc_start;
|
||||
const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
|
||||
rtsc_frequency = tsc_freq;
|
||||
CalculateAndSetFactors();
|
||||
}};
|
||||
|
||||
time_point.inner.last_measure = FencedRDTSC();
|
||||
time_point.inner.accumulated_ticks = 0U;
|
||||
CalculateAndSetFactors();
|
||||
std::chrono::milliseconds NativeClock::GetTimeMS() const {
|
||||
return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_rdtsc_factor)};
|
||||
}
|
||||
|
||||
u64 NativeClock::GetRTSC() {
|
||||
TimePoint new_time_point{};
|
||||
TimePoint current_time_point{};
|
||||
|
||||
current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());
|
||||
do {
|
||||
const u64 current_measure = FencedRDTSC();
|
||||
u64 diff = current_measure - current_time_point.inner.last_measure;
|
||||
diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0)
|
||||
new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure
|
||||
? current_measure
|
||||
: current_time_point.inner.last_measure;
|
||||
new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff;
|
||||
} while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
|
||||
current_time_point.pack, current_time_point.pack));
|
||||
return new_time_point.inner.accumulated_ticks;
|
||||
u64 NativeClock::GetCNTPCT() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor);
|
||||
}
|
||||
|
||||
void NativeClock::Pause(bool is_paused) {
|
||||
if (!is_paused) {
|
||||
TimePoint current_time_point{};
|
||||
TimePoint new_time_point{};
|
||||
|
||||
current_time_point.pack = Common::AtomicLoad128(time_point.pack.data());
|
||||
do {
|
||||
new_time_point.pack = current_time_point.pack;
|
||||
new_time_point.inner.last_measure = FencedRDTSC();
|
||||
} while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack,
|
||||
current_time_point.pack, current_time_point.pack));
|
||||
}
|
||||
u64 NativeClock::GetGPUTick() const {
|
||||
return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor);
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds NativeClock::GetTimeNS() {
|
||||
const u64 rtsc_value = GetRTSC();
|
||||
return std::chrono::nanoseconds{MultiplyHigh(rtsc_value, ns_rtsc_factor)};
|
||||
u64 NativeClock::GetHostTicksNow() const {
|
||||
return FencedRDTSC();
|
||||
}
|
||||
|
||||
std::chrono::microseconds NativeClock::GetTimeUS() {
|
||||
const u64 rtsc_value = GetRTSC();
|
||||
return std::chrono::microseconds{MultiplyHigh(rtsc_value, us_rtsc_factor)};
|
||||
u64 NativeClock::GetHostTicksElapsed() const {
|
||||
return FencedRDTSC() - start_ticks;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds NativeClock::GetTimeMS() {
|
||||
const u64 rtsc_value = GetRTSC();
|
||||
return std::chrono::milliseconds{MultiplyHigh(rtsc_value, ms_rtsc_factor)};
|
||||
bool NativeClock::IsNative() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 NativeClock::GetClockCycles() {
|
||||
const u64 rtsc_value = GetRTSC();
|
||||
return MultiplyHigh(rtsc_value, clock_rtsc_factor);
|
||||
}
|
||||
|
||||
u64 NativeClock::GetCPUCycles() {
|
||||
const u64 rtsc_value = GetRTSC();
|
||||
return MultiplyHigh(rtsc_value, cpu_rtsc_factor);
|
||||
}
|
||||
|
||||
void NativeClock::CalculateAndSetFactors() {
|
||||
ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
|
||||
us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
|
||||
ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency);
|
||||
clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency);
|
||||
cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency);
|
||||
}
|
||||
|
||||
} // namespace X64
|
||||
|
||||
} // namespace Common
|
||||
} // namespace Common::X64
|
||||
|
||||
@@ -3,58 +3,39 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/wall_clock.h"
|
||||
|
||||
namespace Common {
|
||||
namespace Common::X64 {
|
||||
|
||||
namespace X64 {
|
||||
class NativeClock final : public WallClock {
|
||||
public:
|
||||
explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
|
||||
u64 rtsc_frequency_);
|
||||
explicit NativeClock(u64 rdtsc_frequency_);
|
||||
|
||||
std::chrono::nanoseconds GetTimeNS() override;
|
||||
std::chrono::nanoseconds GetTimeNS() const override;
|
||||
|
||||
std::chrono::microseconds GetTimeUS() override;
|
||||
std::chrono::microseconds GetTimeUS() const override;
|
||||
|
||||
std::chrono::milliseconds GetTimeMS() override;
|
||||
std::chrono::milliseconds GetTimeMS() const override;
|
||||
|
||||
u64 GetClockCycles() override;
|
||||
u64 GetCNTPCT() const override;
|
||||
|
||||
u64 GetCPUCycles() override;
|
||||
u64 GetGPUTick() const override;
|
||||
|
||||
void Pause(bool is_paused) override;
|
||||
u64 GetHostTicksNow() const override;
|
||||
|
||||
u64 GetHostTicksElapsed() const override;
|
||||
|
||||
bool IsNative() const override;
|
||||
|
||||
private:
|
||||
u64 GetRTSC();
|
||||
u64 start_ticks;
|
||||
u64 rdtsc_frequency;
|
||||
|
||||
void CalculateAndSetFactors();
|
||||
|
||||
union alignas(16) TimePoint {
|
||||
TimePoint() : pack{} {}
|
||||
u128 pack{};
|
||||
struct Inner {
|
||||
u64 last_measure{};
|
||||
u64 accumulated_ticks{};
|
||||
} inner;
|
||||
};
|
||||
|
||||
TimePoint time_point;
|
||||
|
||||
// factors
|
||||
u64 clock_rtsc_factor{};
|
||||
u64 cpu_rtsc_factor{};
|
||||
u64 ns_rtsc_factor{};
|
||||
u64 us_rtsc_factor{};
|
||||
u64 ms_rtsc_factor{};
|
||||
|
||||
u64 rtsc_frequency;
|
||||
|
||||
std::jthread time_sync_thread;
|
||||
u64 ns_rdtsc_factor;
|
||||
u64 us_rdtsc_factor;
|
||||
u64 ms_rdtsc_factor;
|
||||
u64 cntpct_rdtsc_factor;
|
||||
u64 gputick_rdtsc_factor;
|
||||
};
|
||||
} // namespace X64
|
||||
|
||||
u64 EstimateRDTSCFrequency();
|
||||
|
||||
} // namespace Common
|
||||
} // namespace Common::X64
|
||||
|
||||
39
src/common/x64/rdtsc.cpp
Normal file
39
src/common/x64/rdtsc.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "common/steady_clock.h"
|
||||
#include "common/uint128.h"
|
||||
#include "common/x64/rdtsc.h"
|
||||
|
||||
namespace Common::X64 {
|
||||
|
||||
template <u64 Nearest>
|
||||
static u64 RoundToNearest(u64 value) {
|
||||
const auto mod = value % Nearest;
|
||||
return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod);
|
||||
}
|
||||
|
||||
u64 EstimateRDTSCFrequency() {
|
||||
// Discard the first result measuring the rdtsc.
|
||||
FencedRDTSC();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
FencedRDTSC();
|
||||
|
||||
// Get the current time.
|
||||
const auto start_time = RealTimeClock::Now();
|
||||
const u64 tsc_start = FencedRDTSC();
|
||||
// Wait for 100 milliseconds.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{100});
|
||||
const auto end_time = RealTimeClock::Now();
|
||||
const u64 tsc_end = FencedRDTSC();
|
||||
// Calculate differences.
|
||||
const u64 timer_diff = static_cast<u64>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
|
||||
const u64 tsc_diff = tsc_end - tsc_start;
|
||||
const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
|
||||
return RoundToNearest<100'000>(tsc_freq);
|
||||
}
|
||||
|
||||
} // namespace Common::X64
|
||||
37
src/common/x64/rdtsc.h
Normal file
37
src/common/x64/rdtsc.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::X64 {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
__forceinline static u64 FencedRDTSC() {
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
const u64 result = __rdtsc();
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
static inline u64 FencedRDTSC() {
|
||||
u64 eax;
|
||||
u64 edx;
|
||||
asm volatile("lfence\n\t"
|
||||
"rdtsc\n\t"
|
||||
"lfence\n\t"
|
||||
: "=a"(eax), "=d"(edx));
|
||||
return (edx << 32) | eax;
|
||||
}
|
||||
#endif
|
||||
|
||||
u64 EstimateRDTSCFrequency();
|
||||
|
||||
} // namespace Common::X64
|
||||
@@ -14,7 +14,6 @@ add_library(core STATIC
|
||||
core.h
|
||||
core_timing.cpp
|
||||
core_timing.h
|
||||
core_timing_util.h
|
||||
cpu_manager.cpp
|
||||
cpu_manager.h
|
||||
crypto/aes_util.cpp
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
|
||||
#include "common/microprofile.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
constexpr s64 MAX_SLICE_LENGTH = 4000;
|
||||
constexpr s64 MAX_SLICE_LENGTH = 10000;
|
||||
|
||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
||||
@@ -45,9 +44,7 @@ struct CoreTiming::Event {
|
||||
}
|
||||
};
|
||||
|
||||
CoreTiming::CoreTiming()
|
||||
: cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)},
|
||||
event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
|
||||
CoreTiming::CoreTiming() : clock{Common::CreateOptimalClock()} {}
|
||||
|
||||
CoreTiming::~CoreTiming() {
|
||||
Reset();
|
||||
@@ -68,7 +65,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
on_thread_init = std::move(on_thread_init_);
|
||||
event_fifo_id = 0;
|
||||
shutting_down = false;
|
||||
ticks = 0;
|
||||
cpu_ticks = 0;
|
||||
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
|
||||
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
||||
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
||||
@@ -173,38 +170,30 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
}
|
||||
|
||||
void CoreTiming::AddTicks(u64 ticks_to_add) {
|
||||
ticks += ticks_to_add;
|
||||
downcount -= static_cast<s64>(ticks);
|
||||
cpu_ticks += ticks_to_add;
|
||||
downcount -= static_cast<s64>(cpu_ticks);
|
||||
}
|
||||
|
||||
void CoreTiming::Idle() {
|
||||
if (!event_queue.empty()) {
|
||||
const u64 next_event_time = event_queue.front().time;
|
||||
const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U;
|
||||
if (next_ticks > ticks) {
|
||||
ticks = next_ticks;
|
||||
}
|
||||
return;
|
||||
}
|
||||
ticks += 1000U;
|
||||
cpu_ticks += 1000U;
|
||||
}
|
||||
|
||||
void CoreTiming::ResetTicks() {
|
||||
downcount = MAX_SLICE_LENGTH;
|
||||
}
|
||||
|
||||
u64 CoreTiming::GetCPUTicks() const {
|
||||
if (is_multicore) [[likely]] {
|
||||
return cpu_clock->GetCPUCycles();
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
|
||||
u64 CoreTiming::GetClockTicks() const {
|
||||
if (is_multicore) [[likely]] {
|
||||
return cpu_clock->GetClockCycles();
|
||||
return clock->GetCNTPCT();
|
||||
}
|
||||
return CpuCyclesToClockCycles(ticks);
|
||||
return Common::WallClock::CPUTickToCNTPCT(cpu_ticks);
|
||||
}
|
||||
|
||||
u64 CoreTiming::GetGPUTicks() const {
|
||||
if (is_multicore) [[likely]] {
|
||||
return clock->GetGPUTick();
|
||||
}
|
||||
return Common::WallClock::CPUTickToGPUTick(cpu_ticks);
|
||||
}
|
||||
|
||||
std::optional<s64> CoreTiming::Advance() {
|
||||
@@ -297,9 +286,7 @@ void CoreTiming::ThreadLoop() {
|
||||
}
|
||||
|
||||
paused_set = true;
|
||||
event_clock->Pause(true);
|
||||
pause_event.Wait();
|
||||
event_clock->Pause(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,25 +302,18 @@ void CoreTiming::Reset() {
|
||||
has_started = false;
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const {
|
||||
if (is_multicore) [[likely]] {
|
||||
return cpu_clock->GetTimeNS();
|
||||
}
|
||||
return CyclesToNs(ticks);
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
|
||||
if (is_multicore) [[likely]] {
|
||||
return event_clock->GetTimeNS();
|
||||
return clock->GetTimeNS();
|
||||
}
|
||||
return CyclesToNs(ticks);
|
||||
return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)};
|
||||
}
|
||||
|
||||
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
||||
if (is_multicore) [[likely]] {
|
||||
return event_clock->GetTimeUS();
|
||||
return clock->GetTimeUS();
|
||||
}
|
||||
return CyclesToUs(ticks);
|
||||
return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)};
|
||||
}
|
||||
|
||||
} // namespace Core::Timing
|
||||
|
||||
@@ -116,14 +116,11 @@ public:
|
||||
return downcount;
|
||||
}
|
||||
|
||||
/// Returns current time in emulated CPU cycles
|
||||
u64 GetCPUTicks() const;
|
||||
|
||||
/// Returns current time in emulated in Clock cycles
|
||||
/// Returns the current CNTPCT tick value.
|
||||
u64 GetClockTicks() const;
|
||||
|
||||
/// Returns current time in nanoseconds.
|
||||
std::chrono::nanoseconds GetCPUTimeNs() const;
|
||||
/// Returns the current GPU tick value.
|
||||
u64 GetGPUTicks() const;
|
||||
|
||||
/// Returns current time in microseconds.
|
||||
std::chrono::microseconds GetGlobalTimeUs() const;
|
||||
@@ -142,8 +139,7 @@ private:
|
||||
|
||||
void Reset();
|
||||
|
||||
std::unique_ptr<Common::WallClock> cpu_clock;
|
||||
std::unique_ptr<Common::WallClock> event_clock;
|
||||
std::unique_ptr<Common::WallClock> clock;
|
||||
|
||||
s64 global_timer = 0;
|
||||
|
||||
@@ -171,7 +167,7 @@ private:
|
||||
s64 pause_end_time{};
|
||||
|
||||
/// Cycle timing
|
||||
u64 ticks{};
|
||||
u64 cpu_ticks{};
|
||||
s64 downcount{};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
namespace detail {
|
||||
constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000;
|
||||
constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000;
|
||||
} // namespace detail
|
||||
|
||||
[[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) {
|
||||
return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) {
|
||||
return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) {
|
||||
return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) {
|
||||
return static_cast<u64>(ms.count()) * detail::CNTFREQ_ADJUSTED;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) {
|
||||
return us.count() * detail::CNTFREQ_ADJUSTED / 1000;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) {
|
||||
return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) {
|
||||
return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) {
|
||||
return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) {
|
||||
return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) {
|
||||
return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED);
|
||||
}
|
||||
|
||||
} // namespace Core::Timing
|
||||
@@ -15,7 +15,7 @@ namespace FileSys::SystemArchive {
|
||||
const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&>
|
||||
tzdb_zoneinfo_dirs = {{"Africa", NxTzdb::africa},
|
||||
{"America", NxTzdb::america},
|
||||
{"Antartica", NxTzdb::antartica},
|
||||
{"Antarctica", NxTzdb::antarctica},
|
||||
{"Arctic", NxTzdb::arctic},
|
||||
{"Asia", NxTzdb::asia},
|
||||
{"Atlantic", NxTzdb::atlantic},
|
||||
|
||||
@@ -150,23 +150,29 @@ std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t
|
||||
while (cur_length > 0 && it != concatenation_map.end()) {
|
||||
// Check if we can read the file at this position.
|
||||
const auto& file = it->file;
|
||||
const u64 file_offset = it->offset;
|
||||
const u64 map_offset = it->offset;
|
||||
const u64 file_size = file->GetSize();
|
||||
|
||||
if (cur_offset >= file_offset + file_size) {
|
||||
if (cur_offset > map_offset + file_size) {
|
||||
// Entirely out of bounds read.
|
||||
break;
|
||||
}
|
||||
|
||||
// Read the file at this position.
|
||||
const u64 intended_read_size = std::min<u64>(cur_length, file_size);
|
||||
const u64 file_seek = cur_offset - map_offset;
|
||||
const u64 intended_read_size = std::min<u64>(cur_length, file_size - file_seek);
|
||||
const u64 actual_read_size =
|
||||
file->Read(data + (cur_offset - offset), intended_read_size, cur_offset - file_offset);
|
||||
file->Read(data + (cur_offset - offset), intended_read_size, file_seek);
|
||||
|
||||
// Update tracking.
|
||||
cur_offset += actual_read_size;
|
||||
cur_length -= actual_read_size;
|
||||
it++;
|
||||
|
||||
// If we encountered a short read, we're done.
|
||||
if (actual_read_size < intended_read_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cur_offset - offset;
|
||||
|
||||
@@ -184,7 +184,8 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
|
||||
prev_highest_thread != highest_thread) [[likely]] {
|
||||
if (prev_highest_thread != nullptr) [[likely]] {
|
||||
IncrementScheduledCount(prev_highest_thread);
|
||||
prev_highest_thread->SetLastScheduledTick(m_kernel.System().CoreTiming().GetCPUTicks());
|
||||
prev_highest_thread->SetLastScheduledTick(
|
||||
m_kernel.System().CoreTiming().GetClockTicks());
|
||||
}
|
||||
if (m_state.should_count_idle) {
|
||||
if (highest_thread != nullptr) [[likely]] {
|
||||
@@ -351,7 +352,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
|
||||
|
||||
// Update the CPU time tracking variables.
|
||||
const s64 prev_tick = m_last_context_switch_time;
|
||||
const s64 cur_tick = m_kernel.System().CoreTiming().GetCPUTicks();
|
||||
const s64 cur_tick = m_kernel.System().CoreTiming().GetClockTicks();
|
||||
const s64 tick_diff = cur_tick - prev_tick;
|
||||
cur_thread->AddCpuTime(m_core_id, tick_diff);
|
||||
if (cur_process != nullptr) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
@@ -75,7 +76,7 @@ Result KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
|
||||
KSynchronizationObject** objects, const s32 num_objects,
|
||||
s64 timeout) {
|
||||
// Allocate space on stack for thread nodes.
|
||||
std::vector<ThreadListNode> thread_nodes(num_objects);
|
||||
std::array<ThreadListNode, Svc::ArgumentHandleCountMax> thread_nodes;
|
||||
|
||||
// Prepare for wait.
|
||||
KThread* thread = GetCurrentThreadPointer(kernel);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cinttypes>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
@@ -907,7 +909,7 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KThread::GetThreadContext3(std::vector<u8>& out) {
|
||||
Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) {
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk{m_activity_pause_lock};
|
||||
|
||||
@@ -925,15 +927,13 @@ Result KThread::GetThreadContext3(std::vector<u8>& out) {
|
||||
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||
auto context = GetContext64();
|
||||
context.pstate &= 0xFF0FFE20;
|
||||
|
||||
out.resize(sizeof(context));
|
||||
out.resize_destructive(sizeof(context));
|
||||
std::memcpy(out.data(), std::addressof(context), sizeof(context));
|
||||
} else {
|
||||
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||
auto context = GetContext32();
|
||||
context.cpsr &= 0xFF0FFE20;
|
||||
|
||||
out.resize(sizeof(context));
|
||||
out.resize_destructive(sizeof(context));
|
||||
std::memcpy(out.data(), std::addressof(context), sizeof(context));
|
||||
}
|
||||
}
|
||||
@@ -1313,7 +1313,8 @@ void KThread::RequestDummyThreadWait() {
|
||||
ASSERT(this->IsDummyThread());
|
||||
|
||||
// We will block when the scheduler lock is released.
|
||||
m_dummy_thread_runnable.store(false);
|
||||
std::scoped_lock lock{m_dummy_thread_mutex};
|
||||
m_dummy_thread_runnable = false;
|
||||
}
|
||||
|
||||
void KThread::DummyThreadBeginWait() {
|
||||
@@ -1323,7 +1324,8 @@ void KThread::DummyThreadBeginWait() {
|
||||
}
|
||||
|
||||
// Block until runnable is no longer false.
|
||||
m_dummy_thread_runnable.wait(false);
|
||||
std::unique_lock lock{m_dummy_thread_mutex};
|
||||
m_dummy_thread_cv.wait(lock, [this] { return m_dummy_thread_runnable; });
|
||||
}
|
||||
|
||||
void KThread::DummyThreadEndWait() {
|
||||
@@ -1331,8 +1333,11 @@ void KThread::DummyThreadEndWait() {
|
||||
ASSERT(this->IsDummyThread());
|
||||
|
||||
// Wake up the waiting thread.
|
||||
m_dummy_thread_runnable.store(true);
|
||||
m_dummy_thread_runnable.notify_one();
|
||||
{
|
||||
std::scoped_lock lock{m_dummy_thread_mutex};
|
||||
m_dummy_thread_runnable = true;
|
||||
}
|
||||
m_dummy_thread_cv.notify_one();
|
||||
}
|
||||
|
||||
void KThread::BeginWait(KThreadQueue* queue) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/hle/kernel/k_affinity_mask.h"
|
||||
@@ -567,7 +568,7 @@ public:
|
||||
|
||||
void RemoveWaiter(KThread* thread);
|
||||
|
||||
Result GetThreadContext3(std::vector<u8>& out);
|
||||
Result GetThreadContext3(Common::ScratchBuffer<u8>& out);
|
||||
|
||||
KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) {
|
||||
return this->RemoveWaiterByKey(out_has_waiters, key, false);
|
||||
@@ -892,7 +893,9 @@ private:
|
||||
std::shared_ptr<Common::Fiber> m_host_context{};
|
||||
ThreadType m_thread_type{};
|
||||
StepState m_step_state{};
|
||||
std::atomic<bool> m_dummy_thread_runnable{true};
|
||||
bool m_dummy_thread_runnable{true};
|
||||
std::mutex m_dummy_thread_mutex{};
|
||||
std::condition_variable m_dummy_thread_cv{};
|
||||
|
||||
// For debugging
|
||||
std::vector<KSynchronizationObject*> m_wait_objects_for_debugging{};
|
||||
|
||||
@@ -199,9 +199,9 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
|
||||
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
||||
const u64 thread_ticks = current_thread->GetCpuTime();
|
||||
|
||||
out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
|
||||
out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks);
|
||||
} else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
|
||||
out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks;
|
||||
out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks;
|
||||
}
|
||||
|
||||
*result = out_ticks;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_client_session.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
@@ -45,11 +46,11 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad
|
||||
handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
|
||||
ResultInvalidPointer);
|
||||
|
||||
std::vector<Handle> handles(num_handles);
|
||||
std::array<Handle, Svc::ArgumentHandleCountMax> handles;
|
||||
GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles);
|
||||
|
||||
// Convert handle list to object table.
|
||||
std::vector<KSynchronizationObject*> objs(num_handles);
|
||||
std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
|
||||
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(),
|
||||
num_handles),
|
||||
ResultInvalidHandle);
|
||||
@@ -80,7 +81,7 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad
|
||||
// Wait for an object.
|
||||
s32 index;
|
||||
Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(),
|
||||
static_cast<s32>(objs.size()), timeout_ns);
|
||||
num_handles, timeout_ns);
|
||||
if (result == ResultTimedOut) {
|
||||
R_RETURN(result);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
@@ -54,7 +55,7 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons
|
||||
// Get the synchronization context.
|
||||
auto& kernel = system.Kernel();
|
||||
auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
|
||||
std::vector<KSynchronizationObject*> objs(num_handles);
|
||||
std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
|
||||
|
||||
// Copy user handles.
|
||||
if (num_handles > 0) {
|
||||
@@ -72,8 +73,8 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons
|
||||
});
|
||||
|
||||
// Wait on the objects.
|
||||
Result res = KSynchronizationObject::Wait(kernel, out_index, objs.data(),
|
||||
static_cast<s32>(objs.size()), timeout_ns);
|
||||
Result res =
|
||||
KSynchronizationObject::Wait(kernel, out_index, objs.data(), num_handles, timeout_ns);
|
||||
|
||||
R_SUCCEED_IF(res == ResultSessionClosed);
|
||||
R_RETURN(res);
|
||||
@@ -87,8 +88,7 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha
|
||||
|
||||
// Ensure number of handles is valid.
|
||||
R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
|
||||
|
||||
std::vector<Handle> handles(num_handles);
|
||||
std::array<Handle, Svc::ArgumentHandleCountMax> handles;
|
||||
if (num_handles > 0) {
|
||||
GetCurrentMemory(system.Kernel())
|
||||
.ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle));
|
||||
|
||||
@@ -174,7 +174,7 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha
|
||||
}
|
||||
|
||||
// Get the thread context.
|
||||
std::vector<u8> context;
|
||||
static thread_local Common::ScratchBuffer<u8> context;
|
||||
R_TRY(thread->GetThreadContext3(context));
|
||||
|
||||
// Copy the thread context to user space.
|
||||
|
||||
@@ -12,16 +12,8 @@ namespace Kernel::Svc {
|
||||
int64_t GetSystemTick(Core::System& system) {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
|
||||
const u64 result{core_timing.GetClockTicks()};
|
||||
|
||||
if (!system.Kernel().IsMulticore()) {
|
||||
core_timing.AddTicks(400U);
|
||||
}
|
||||
|
||||
return static_cast<int64_t>(result);
|
||||
return static_cast<int64_t>(system.CoreTiming().GetClockTicks());
|
||||
}
|
||||
|
||||
int64_t GetSystemTick64(Core::System& system) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "audio_core/renderer/audio_device.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
@@ -123,19 +124,13 @@ private:
|
||||
|
||||
void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
|
||||
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
|
||||
std::vector<u64> released_buffers(write_buffer_size);
|
||||
tmp_buffer.resize_destructive(write_buffer_size);
|
||||
tmp_buffer[0] = 0;
|
||||
|
||||
const auto count = impl->GetReleasedBuffers(released_buffers);
|
||||
const auto count = impl->GetReleasedBuffers(tmp_buffer);
|
||||
|
||||
[[maybe_unused]] std::string tags{};
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
tags += fmt::format("{:08X}, ", released_buffers[i]);
|
||||
}
|
||||
[[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
|
||||
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count,
|
||||
tags);
|
||||
ctx.WriteBuffer(tmp_buffer);
|
||||
|
||||
ctx.WriteBuffer(released_buffers);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(count);
|
||||
@@ -200,6 +195,7 @@ private:
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Kernel::KEvent* event;
|
||||
std::shared_ptr<AudioCore::AudioIn::In> impl;
|
||||
Common::ScratchBuffer<u64> tmp_buffer;
|
||||
};
|
||||
|
||||
AudInU::AudInU(Core::System& system_)
|
||||
|
||||
@@ -123,19 +123,13 @@ private:
|
||||
|
||||
void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
|
||||
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
|
||||
std::vector<u64> released_buffers(write_buffer_size);
|
||||
tmp_buffer.resize_destructive(write_buffer_size);
|
||||
tmp_buffer[0] = 0;
|
||||
|
||||
const auto count = impl->GetReleasedBuffers(released_buffers);
|
||||
const auto count = impl->GetReleasedBuffers(tmp_buffer);
|
||||
|
||||
[[maybe_unused]] std::string tags{};
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
tags += fmt::format("{:08X}, ", released_buffers[i]);
|
||||
}
|
||||
[[maybe_unused]] const auto sessionid{impl->GetSystem().GetSessionId()};
|
||||
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count,
|
||||
tags);
|
||||
ctx.WriteBuffer(tmp_buffer);
|
||||
|
||||
ctx.WriteBuffer(released_buffers);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(count);
|
||||
@@ -211,6 +205,7 @@ private:
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Kernel::KEvent* event;
|
||||
std::shared_ptr<AudioCore::AudioOut::Out> impl;
|
||||
Common::ScratchBuffer<u64> tmp_buffer;
|
||||
};
|
||||
|
||||
AudOutU::AudOutU(Core::System& system_)
|
||||
|
||||
@@ -116,28 +116,26 @@ private:
|
||||
// These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
|
||||
// checking size 0. Performance size is 0 for most games.
|
||||
|
||||
std::vector<u8> output{};
|
||||
std::vector<u8> performance{};
|
||||
auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
|
||||
if (is_buffer_b) {
|
||||
const auto buffersB{ctx.BufferDescriptorB()};
|
||||
output.resize(buffersB[0].Size(), 0);
|
||||
performance.resize(buffersB[1].Size(), 0);
|
||||
tmp_output.resize_destructive(buffersB[0].Size());
|
||||
tmp_performance.resize_destructive(buffersB[1].Size());
|
||||
} else {
|
||||
const auto buffersC{ctx.BufferDescriptorC()};
|
||||
output.resize(buffersC[0].Size(), 0);
|
||||
performance.resize(buffersC[1].Size(), 0);
|
||||
tmp_output.resize_destructive(buffersC[0].Size());
|
||||
tmp_performance.resize_destructive(buffersC[1].Size());
|
||||
}
|
||||
|
||||
auto result = impl->RequestUpdate(input, performance, output);
|
||||
auto result = impl->RequestUpdate(input, tmp_performance, tmp_output);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
if (is_buffer_b) {
|
||||
ctx.WriteBufferB(output.data(), output.size(), 0);
|
||||
ctx.WriteBufferB(performance.data(), performance.size(), 1);
|
||||
ctx.WriteBufferB(tmp_output.data(), tmp_output.size(), 0);
|
||||
ctx.WriteBufferB(tmp_performance.data(), tmp_performance.size(), 1);
|
||||
} else {
|
||||
ctx.WriteBufferC(output.data(), output.size(), 0);
|
||||
ctx.WriteBufferC(performance.data(), performance.size(), 1);
|
||||
ctx.WriteBufferC(tmp_output.data(), tmp_output.size(), 0);
|
||||
ctx.WriteBufferC(tmp_performance.data(), tmp_performance.size(), 1);
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description);
|
||||
@@ -235,6 +233,8 @@ private:
|
||||
Kernel::KEvent* rendered_event;
|
||||
Manager& manager;
|
||||
std::unique_ptr<Renderer> impl;
|
||||
Common::ScratchBuffer<u8> tmp_output;
|
||||
Common::ScratchBuffer<u8> tmp_performance;
|
||||
};
|
||||
|
||||
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "audio_core/audio_render_manager.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
|
||||
@@ -68,13 +68,13 @@ private:
|
||||
ExtraBehavior extra_behavior) {
|
||||
u32 consumed = 0;
|
||||
u32 sample_count = 0;
|
||||
std::vector<opus_int16> samples(ctx.GetWriteBufferNumElements<opus_int16>());
|
||||
tmp_samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>());
|
||||
|
||||
if (extra_behavior == ExtraBehavior::ResetContext) {
|
||||
ResetDecoderContext();
|
||||
}
|
||||
|
||||
if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) {
|
||||
if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), tmp_samples, performance)) {
|
||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
@@ -90,11 +90,11 @@ private:
|
||||
if (performance) {
|
||||
rb.Push<u64>(*performance);
|
||||
}
|
||||
ctx.WriteBuffer(samples);
|
||||
ctx.WriteBuffer(tmp_samples);
|
||||
}
|
||||
|
||||
bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input,
|
||||
std::vector<opus_int16>& output, u64* out_performance_time) const {
|
||||
std::span<opus_int16> output, u64* out_performance_time) const {
|
||||
const auto start_time = std::chrono::steady_clock::now();
|
||||
const std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
|
||||
if (sizeof(OpusPacketHeader) > input.size()) {
|
||||
@@ -154,6 +154,7 @@ private:
|
||||
OpusDecoderPtr decoder;
|
||||
u32 sample_rate;
|
||||
u32 channel_count;
|
||||
Common::ScratchBuffer<opus_int16> tmp_samples;
|
||||
};
|
||||
|
||||
class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
|
||||
@@ -36,12 +36,12 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
|
||||
|
||||
// Validate UUID
|
||||
constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3`
|
||||
if ((CT ^ ntag_file.uuid.uid[0] ^ ntag_file.uuid.uid[1] ^ ntag_file.uuid.uid[2]) !=
|
||||
ntag_file.uuid.uid[3]) {
|
||||
if ((CT ^ ntag_file.uuid.part1[0] ^ ntag_file.uuid.part1[1] ^ ntag_file.uuid.part1[2]) !=
|
||||
ntag_file.uuid.crc_check1) {
|
||||
return false;
|
||||
}
|
||||
if ((ntag_file.uuid.uid[4] ^ ntag_file.uuid.uid[5] ^ ntag_file.uuid.uid[6] ^
|
||||
ntag_file.uuid.nintendo_id) != ntag_file.uuid.lock_bytes[0]) {
|
||||
if ((ntag_file.uuid.part2[0] ^ ntag_file.uuid.part2[1] ^ ntag_file.uuid.part2[2] ^
|
||||
ntag_file.uuid.nintendo_id) != ntag_file.uuid_crc_check2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -74,8 +74,9 @@ bool IsAmiiboValid(const NTAG215File& ntag_file) {
|
||||
NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
|
||||
NTAG215File encoded_data{};
|
||||
|
||||
encoded_data.uid = nfc_data.uuid.uid;
|
||||
encoded_data.nintendo_id = nfc_data.uuid.nintendo_id;
|
||||
encoded_data.uid = nfc_data.uuid;
|
||||
encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
|
||||
encoded_data.internal_number = nfc_data.internal_number;
|
||||
encoded_data.static_lock = nfc_data.static_lock;
|
||||
encoded_data.compability_container = nfc_data.compability_container;
|
||||
encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
|
||||
@@ -94,7 +95,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
|
||||
encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;
|
||||
encoded_data.application_area = nfc_data.user_memory.application_area;
|
||||
encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;
|
||||
encoded_data.lock_bytes = nfc_data.uuid.lock_bytes;
|
||||
encoded_data.model_info = nfc_data.user_memory.model_info;
|
||||
encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt;
|
||||
encoded_data.dynamic_lock = nfc_data.dynamic_lock;
|
||||
@@ -108,9 +108,9 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
|
||||
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
|
||||
EncryptedNTAG215File nfc_data{};
|
||||
|
||||
nfc_data.uuid.uid = encoded_data.uid;
|
||||
nfc_data.uuid.nintendo_id = encoded_data.nintendo_id;
|
||||
nfc_data.uuid.lock_bytes = encoded_data.lock_bytes;
|
||||
nfc_data.uuid = encoded_data.uid;
|
||||
nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
|
||||
nfc_data.internal_number = encoded_data.internal_number;
|
||||
nfc_data.static_lock = encoded_data.static_lock;
|
||||
nfc_data.compability_container = encoded_data.compability_container;
|
||||
nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
|
||||
@@ -139,23 +139,12 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
|
||||
return nfc_data;
|
||||
}
|
||||
|
||||
u32 GetTagPassword(const TagUuid& uuid) {
|
||||
// Verify that the generated password is correct
|
||||
u32 password = 0xAA ^ (uuid.uid[1] ^ uuid.uid[3]);
|
||||
password &= (0x55 ^ (uuid.uid[2] ^ uuid.uid[4])) << 8;
|
||||
password &= (0xAA ^ (uuid.uid[3] ^ uuid.uid[5])) << 16;
|
||||
password &= (0x55 ^ (uuid.uid[4] ^ uuid.uid[6])) << 24;
|
||||
return password;
|
||||
}
|
||||
|
||||
HashSeed GetSeed(const NTAG215File& data) {
|
||||
HashSeed seed{
|
||||
.magic = data.write_counter,
|
||||
.padding = {},
|
||||
.uid_1 = data.uid,
|
||||
.nintendo_id_1 = data.nintendo_id,
|
||||
.uid_2 = data.uid,
|
||||
.nintendo_id_2 = data.nintendo_id,
|
||||
.keygen_salt = data.keygen_salt,
|
||||
};
|
||||
|
||||
@@ -177,10 +166,11 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
|
||||
output.insert(output.end(), key.magic_bytes.begin(),
|
||||
key.magic_bytes.begin() + key.magic_length);
|
||||
|
||||
output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end());
|
||||
output.emplace_back(seed.nintendo_id_1);
|
||||
output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end());
|
||||
output.emplace_back(seed.nintendo_id_2);
|
||||
std::array<u8, sizeof(NFP::TagUuid)> seed_uuid{};
|
||||
memcpy(seed_uuid.data(), &seed.uid_1, sizeof(NFP::TagUuid));
|
||||
output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
|
||||
memcpy(seed_uuid.data(), &seed.uid_2, sizeof(NFP::TagUuid));
|
||||
output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
|
||||
|
||||
for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) {
|
||||
output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i]));
|
||||
@@ -264,8 +254,8 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
|
||||
|
||||
// Copy the rest of the data directly
|
||||
out_data.uid = in_data.uid;
|
||||
out_data.nintendo_id = in_data.nintendo_id;
|
||||
out_data.lock_bytes = in_data.lock_bytes;
|
||||
out_data.uid_crc_check2 = in_data.uid_crc_check2;
|
||||
out_data.internal_number = in_data.internal_number;
|
||||
out_data.static_lock = in_data.static_lock;
|
||||
out_data.compability_container = in_data.compability_container;
|
||||
|
||||
|
||||
@@ -24,10 +24,8 @@ using DrgbOutput = std::array<u8, 0x20>;
|
||||
struct HashSeed {
|
||||
u16_be magic;
|
||||
std::array<u8, 0xE> padding;
|
||||
NFC::UniqueSerialNumber uid_1;
|
||||
u8 nintendo_id_1;
|
||||
NFC::UniqueSerialNumber uid_2;
|
||||
u8 nintendo_id_2;
|
||||
TagUuid uid_1;
|
||||
TagUuid uid_2;
|
||||
std::array<u8, 0x20> keygen_salt;
|
||||
};
|
||||
static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size");
|
||||
@@ -69,9 +67,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data);
|
||||
/// Converts from encoded file format to encrypted file format
|
||||
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data);
|
||||
|
||||
/// Returns password needed to allow write access to protected memory
|
||||
u32 GetTagPassword(const TagUuid& uuid);
|
||||
|
||||
// Generates Seed needed for key derivation
|
||||
HashSeed GetSeed(const NTAG215File& data);
|
||||
|
||||
|
||||
@@ -242,34 +242,39 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
|
||||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
UniqueSerialNumber uuid = encrypted_tag_data.uuid.uid;
|
||||
|
||||
// Generate random UUID to bypass amiibo load limits
|
||||
if (Settings::values.random_amiibo_id) {
|
||||
Common::TinyMT rng{};
|
||||
rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
|
||||
rng.GenerateRandomBytes(uuid.data(), sizeof(UniqueSerialNumber));
|
||||
uuid[3] = 0x88 ^ uuid[0] ^ uuid[1] ^ uuid[2];
|
||||
}
|
||||
UniqueSerialNumber uuid{};
|
||||
u8 uuid_length{};
|
||||
NfcProtocol protocol{NfcProtocol::TypeA};
|
||||
TagType tag_type{TagType::Type2};
|
||||
|
||||
if (is_mifare) {
|
||||
tag_info = {
|
||||
.uuid = uuid,
|
||||
.uuid_extension = {},
|
||||
.uuid_length = static_cast<u8>(uuid.size()),
|
||||
.protocol = NfcProtocol::TypeA,
|
||||
.tag_type = TagType::Type4,
|
||||
tag_type = TagType::Mifare;
|
||||
uuid_length = sizeof(NFP::NtagTagUuid);
|
||||
memcpy(uuid.data(), mifare_data.data(), uuid_length);
|
||||
} else {
|
||||
tag_type = TagType::Type2;
|
||||
uuid_length = sizeof(NFP::NtagTagUuid);
|
||||
NFP::NtagTagUuid nUuid{
|
||||
.part1 = encrypted_tag_data.uuid.part1,
|
||||
.part2 = encrypted_tag_data.uuid.part2,
|
||||
.nintendo_id = encrypted_tag_data.uuid.nintendo_id,
|
||||
};
|
||||
return ResultSuccess;
|
||||
memcpy(uuid.data(), &nUuid, uuid_length);
|
||||
|
||||
// Generate random UUID to bypass amiibo load limits
|
||||
if (Settings::values.random_amiibo_id) {
|
||||
Common::TinyMT rng{};
|
||||
rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
|
||||
rng.GenerateRandomBytes(uuid.data(), uuid_length);
|
||||
}
|
||||
}
|
||||
|
||||
// Protocol and tag type may change here
|
||||
tag_info = {
|
||||
.uuid = uuid,
|
||||
.uuid_extension = {},
|
||||
.uuid_length = static_cast<u8>(uuid.size()),
|
||||
.protocol = NfcProtocol::TypeA,
|
||||
.tag_type = TagType::Type2,
|
||||
.uuid_length = uuid_length,
|
||||
.protocol = protocol,
|
||||
.tag_type = tag_type,
|
||||
};
|
||||
|
||||
return ResultSuccess;
|
||||
@@ -277,8 +282,38 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
|
||||
|
||||
Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
|
||||
std::span<MifareReadBlockData> read_block_data) const {
|
||||
if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == DeviceState::TagRemoved) {
|
||||
return ResultTagRemoved;
|
||||
}
|
||||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
TagInfo tag_info{};
|
||||
result = GetTagInfo(tag_info, true);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
|
||||
return ResultInvalidTagType;
|
||||
}
|
||||
|
||||
if (parameters.size() == 0) {
|
||||
return ResultInvalidArgument;
|
||||
}
|
||||
|
||||
const auto unknown = parameters[0].sector_key.unknown;
|
||||
for (std::size_t i = 0; i < parameters.size(); i++) {
|
||||
if (unknown != parameters[i].sector_key.unknown) {
|
||||
return ResultInvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < parameters.size(); i++) {
|
||||
result = ReadMifare(parameters[i], read_block_data[i]);
|
||||
if (result.IsError()) {
|
||||
@@ -293,17 +328,8 @@ Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
|
||||
MifareReadBlockData& read_block_data) const {
|
||||
const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
|
||||
read_block_data.sector_number = parameter.sector_number;
|
||||
|
||||
if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == DeviceState::TagRemoved) {
|
||||
return ResultTagRemoved;
|
||||
}
|
||||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
|
||||
return Mifare::ResultReadError;
|
||||
return ResultMifareError288;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to read encrypted data
|
||||
@@ -315,6 +341,28 @@ Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
|
||||
Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
|
||||
Result result = ResultSuccess;
|
||||
|
||||
TagInfo tag_info{};
|
||||
result = GetTagInfo(tag_info, true);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
|
||||
return ResultInvalidTagType;
|
||||
}
|
||||
|
||||
if (parameters.size() == 0) {
|
||||
return ResultInvalidArgument;
|
||||
}
|
||||
|
||||
const auto unknown = parameters[0].sector_key.unknown;
|
||||
for (std::size_t i = 0; i < parameters.size(); i++) {
|
||||
if (unknown != parameters[i].sector_key.unknown) {
|
||||
return ResultInvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < parameters.size(); i++) {
|
||||
result = WriteMifare(parameters[i]);
|
||||
if (result.IsError()) {
|
||||
@@ -324,7 +372,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
|
||||
|
||||
if (!npad_device->WriteNfc(mifare_data)) {
|
||||
LOG_ERROR(Service_NFP, "Error writing to file");
|
||||
return Mifare::ResultReadError;
|
||||
return ResultMifareError288;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -342,7 +390,7 @@ Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
|
||||
}
|
||||
|
||||
if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
|
||||
return Mifare::ResultReadError;
|
||||
return ResultMifareError288;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to encrypt the data
|
||||
@@ -366,7 +414,7 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
|
||||
|
||||
if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
|
||||
LOG_ERROR(Service_NFP, "Not an amiibo");
|
||||
return ResultNotAnAmiibo;
|
||||
return ResultInvalidTagType;
|
||||
}
|
||||
|
||||
// The loaded amiibo is not encrypted
|
||||
@@ -381,14 +429,14 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
|
||||
}
|
||||
|
||||
if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
|
||||
bool has_backup = HasBackup(encrypted_tag_data.uuid.uid).IsSuccess();
|
||||
bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess();
|
||||
LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
|
||||
return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
|
||||
}
|
||||
|
||||
std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
|
||||
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
|
||||
WriteBackupData(encrypted_tag_data.uuid.uid, data);
|
||||
WriteBackupData(encrypted_tag_data.uuid, data);
|
||||
|
||||
device_state = DeviceState::TagMounted;
|
||||
mount_target = mount_target_;
|
||||
@@ -492,7 +540,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
|
||||
}
|
||||
|
||||
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
|
||||
WriteBackupData(encrypted_tag_data.uuid.uid, data);
|
||||
WriteBackupData(encrypted_tag_data.uuid, data);
|
||||
}
|
||||
|
||||
if (!npad_device->WriteNfc(data)) {
|
||||
@@ -520,7 +568,7 @@ Result NfcDevice::Restore() {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ReadBackupData(tag_info.uuid, data);
|
||||
result = ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
@@ -548,7 +596,7 @@ Result NfcDevice::Restore() {
|
||||
}
|
||||
|
||||
if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
|
||||
return ResultNotAnAmiibo;
|
||||
return ResultInvalidTagType;
|
||||
}
|
||||
|
||||
if (!is_plain_amiibo) {
|
||||
@@ -1194,10 +1242,12 @@ Result NfcDevice::BreakTag(NFP::BreakType break_type) {
|
||||
return FlushWithBreak(break_type);
|
||||
}
|
||||
|
||||
Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
|
||||
Result NfcDevice::HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const {
|
||||
ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
|
||||
constexpr auto backup_dir = "backup";
|
||||
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
|
||||
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
|
||||
const auto file_name =
|
||||
fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
|
||||
|
||||
if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
|
||||
return ResultUnableToAccessBackupFile;
|
||||
@@ -1206,10 +1256,19 @@ Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const {
|
||||
Result NfcDevice::HasBackup(const NFP::TagUuid& tag_uid) const {
|
||||
UniqueSerialNumber uuid{};
|
||||
memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
|
||||
return HasBackup(uuid, sizeof(NFP::TagUuid));
|
||||
}
|
||||
|
||||
Result NfcDevice::ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
|
||||
std::span<u8> data) const {
|
||||
ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
|
||||
constexpr auto backup_dir = "backup";
|
||||
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
|
||||
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
|
||||
const auto file_name =
|
||||
fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
|
||||
|
||||
const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
|
||||
Common::FS::FileAccessMode::Read,
|
||||
@@ -1228,12 +1287,21 @@ Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data) {
|
||||
Result NfcDevice::ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const {
|
||||
UniqueSerialNumber uuid{};
|
||||
memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
|
||||
return ReadBackupData(uuid, sizeof(NFP::TagUuid), data);
|
||||
}
|
||||
|
||||
Result NfcDevice::WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
|
||||
std::span<const u8> data) {
|
||||
ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
|
||||
constexpr auto backup_dir = "backup";
|
||||
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
|
||||
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
|
||||
const auto file_name =
|
||||
fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
|
||||
|
||||
if (HasBackup(uid).IsError()) {
|
||||
if (HasBackup(uid, uuid_size).IsError()) {
|
||||
if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
|
||||
return ResultBackupPathAlreadyExist;
|
||||
}
|
||||
@@ -1260,6 +1328,12 @@ Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data) {
|
||||
UniqueSerialNumber uuid{};
|
||||
memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
|
||||
return WriteBackupData(uuid, sizeof(NFP::TagUuid), data);
|
||||
}
|
||||
|
||||
Result NfcDevice::WriteNtf(std::span<const u8> data) {
|
||||
if (device_state != DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
|
||||
@@ -86,9 +86,14 @@ public:
|
||||
Result GetAll(NFP::NfpData& data) const;
|
||||
Result SetAll(const NFP::NfpData& data);
|
||||
Result BreakTag(NFP::BreakType break_type);
|
||||
Result HasBackup(const NFC::UniqueSerialNumber& uid) const;
|
||||
Result ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const;
|
||||
Result WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data);
|
||||
Result HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const;
|
||||
Result HasBackup(const NFP::TagUuid& tag_uid) const;
|
||||
Result ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
|
||||
std::span<u8> data) const;
|
||||
Result ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const;
|
||||
Result WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
|
||||
std::span<const u8> data);
|
||||
Result WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data);
|
||||
Result WriteNtf(std::span<const u8> data);
|
||||
|
||||
u64 GetHandle() const;
|
||||
|
||||
@@ -550,7 +550,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->ReadBackupData(tag_info.uuid, data);
|
||||
result = device->ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
@@ -569,7 +569,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->WriteBackupData(tag_info.uuid, data);
|
||||
result = device->WriteBackupData(tag_info.uuid, tag_info.uuid_length, data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,6 @@ constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
|
||||
constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
|
||||
constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
|
||||
constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
|
||||
constexpr Result ResultReadError(ErrorModule::NFCMifare, 288);
|
||||
constexpr Result ResultNotAMifare(ErrorModule::NFCMifare, 288);
|
||||
|
||||
} // namespace Service::NFC::Mifare
|
||||
|
||||
@@ -142,9 +142,13 @@ void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
|
||||
void NfcInterface::StartDetection(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto tag_protocol{rp.PopEnum<NfcProtocol>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
|
||||
auto tag_protocol{NfcProtocol::All};
|
||||
|
||||
if (backend_type == BackendType::Nfc) {
|
||||
tag_protocol = rp.PopEnum<NfcProtocol>();
|
||||
}
|
||||
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
|
||||
auto result = GetManager()->StartDetection(device_handle, tag_protocol);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
@@ -355,7 +359,7 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
|
||||
if (result == ResultApplicationAreaExist) {
|
||||
return NFP::ResultApplicationAreaExist;
|
||||
}
|
||||
if (result == ResultNotAnAmiibo) {
|
||||
if (result == ResultInvalidTagType) {
|
||||
return NFP::ResultNotAnAmiibo;
|
||||
}
|
||||
if (result == ResultUnableToAccessBackupFile) {
|
||||
@@ -381,6 +385,9 @@ Result NfcInterface::TranslateResultToMifare(Result result) const {
|
||||
if (result == ResultTagRemoved) {
|
||||
return Mifare::ResultTagRemoved;
|
||||
}
|
||||
if (result == ResultInvalidTagType) {
|
||||
return Mifare::ResultNotAMifare;
|
||||
}
|
||||
LOG_WARNING(Service_NFC, "Result conversion not handled");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
|
||||
constexpr Result ResultCorruptedData(ErrorModule::NFC, 144);
|
||||
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152);
|
||||
constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168);
|
||||
constexpr Result ResultNotAnAmiibo(ErrorModule::NFC, 178);
|
||||
constexpr Result ResultInvalidTagType(ErrorModule::NFC, 178);
|
||||
constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216);
|
||||
constexpr Result ResultMifareError288(ErrorModule::NFC, 288);
|
||||
|
||||
} // namespace Service::NFC
|
||||
|
||||
@@ -35,32 +35,35 @@ enum class State : u32 {
|
||||
|
||||
// This is nn::nfc::TagType
|
||||
enum class TagType : u32 {
|
||||
None,
|
||||
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
|
||||
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
|
||||
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
|
||||
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
|
||||
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
|
||||
None = 0,
|
||||
Type1 = 1U << 0, // ISO14443A RW. Topaz
|
||||
Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
|
||||
Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
|
||||
Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
|
||||
Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
|
||||
Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
|
||||
Mifare = 1U << 6, // Mifare classic. Skylanders
|
||||
All = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
enum class PackedTagType : u8 {
|
||||
None,
|
||||
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
|
||||
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
|
||||
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
|
||||
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
|
||||
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
|
||||
None = 0,
|
||||
Type1 = 1U << 0, // ISO14443A RW. Topaz
|
||||
Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
|
||||
Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
|
||||
Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
|
||||
Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
|
||||
Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
|
||||
Mifare = 1U << 6, // Mifare classic. Skylanders
|
||||
All = 0xFF,
|
||||
};
|
||||
|
||||
// This is nn::nfc::NfcProtocol
|
||||
// Verify this enum. It might be completely wrong default protocol is 0x48
|
||||
enum class NfcProtocol : u32 {
|
||||
None,
|
||||
TypeA = 1U << 0, // ISO14443A
|
||||
TypeB = 1U << 1, // ISO14443B
|
||||
TypeF = 1U << 2, // Sony FeliCa
|
||||
Unknown1 = 1U << 3,
|
||||
Unknown2 = 1U << 5,
|
||||
All = 0xFFFFFFFFU,
|
||||
};
|
||||
|
||||
@@ -69,8 +72,7 @@ enum class TestWaveType : u32 {
|
||||
Unknown,
|
||||
};
|
||||
|
||||
using UniqueSerialNumber = std::array<u8, 7>;
|
||||
using UniqueSerialNumberExtension = std::array<u8, 3>;
|
||||
using UniqueSerialNumber = std::array<u8, 10>;
|
||||
|
||||
// This is nn::nfc::DeviceHandle
|
||||
using DeviceHandle = u64;
|
||||
@@ -78,7 +80,6 @@ using DeviceHandle = u64;
|
||||
// This is nn::nfc::TagInfo
|
||||
struct TagInfo {
|
||||
UniqueSerialNumber uuid;
|
||||
UniqueSerialNumberExtension uuid_extension;
|
||||
u8 uuid_length;
|
||||
INSERT_PADDING_BYTES(0x15);
|
||||
NfcProtocol protocol;
|
||||
|
||||
@@ -85,7 +85,7 @@ enum class CabinetMode : u8 {
|
||||
StartFormatter,
|
||||
};
|
||||
|
||||
using LockBytes = std::array<u8, 2>;
|
||||
using UuidPart = std::array<u8, 3>;
|
||||
using HashData = std::array<u8, 0x20>;
|
||||
using ApplicationArea = std::array<u8, 0xD8>;
|
||||
using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
|
||||
@@ -93,12 +93,20 @@ using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
|
||||
// This is nn::nfp::TagInfo
|
||||
using TagInfo = NFC::TagInfo;
|
||||
|
||||
struct TagUuid {
|
||||
NFC::UniqueSerialNumber uid;
|
||||
struct NtagTagUuid {
|
||||
UuidPart part1;
|
||||
UuidPart part2;
|
||||
u8 nintendo_id;
|
||||
LockBytes lock_bytes;
|
||||
};
|
||||
static_assert(sizeof(TagUuid) == 10, "TagUuid is an invalid size");
|
||||
static_assert(sizeof(NtagTagUuid) == 7, "NtagTagUuid is an invalid size");
|
||||
|
||||
struct TagUuid {
|
||||
UuidPart part1;
|
||||
u8 crc_check1;
|
||||
UuidPart part2;
|
||||
u8 nintendo_id;
|
||||
};
|
||||
static_assert(sizeof(TagUuid) == 8, "TagUuid is an invalid size");
|
||||
|
||||
struct WriteDate {
|
||||
u16 year;
|
||||
@@ -231,7 +239,8 @@ struct EncryptedAmiiboFile {
|
||||
static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
|
||||
|
||||
struct NTAG215File {
|
||||
LockBytes lock_bytes; // Tag UUID
|
||||
u8 uid_crc_check2;
|
||||
u8 internal_number;
|
||||
u16 static_lock; // Set defined pages as read only
|
||||
u32 compability_container; // Defines available memory
|
||||
HashData hmac_data; // Hash
|
||||
@@ -250,8 +259,7 @@ struct NTAG215File {
|
||||
u32_be register_info_crc;
|
||||
ApplicationArea application_area; // Encrypted Game data
|
||||
HashData hmac_tag; // Hash
|
||||
NFC::UniqueSerialNumber uid; // Unique serial number
|
||||
u8 nintendo_id; // Tag UUID
|
||||
TagUuid uid;
|
||||
AmiiboModelInfo model_info;
|
||||
HashData keygen_salt; // Salt
|
||||
u32 dynamic_lock; // Dynamic lock
|
||||
@@ -264,7 +272,9 @@ static_assert(std::is_trivially_copyable_v<NTAG215File>, "NTAG215File must be tr
|
||||
#pragma pack()
|
||||
|
||||
struct EncryptedNTAG215File {
|
||||
TagUuid uuid; // Unique serial number
|
||||
TagUuid uuid;
|
||||
u8 uuid_crc_check2;
|
||||
u8 internal_number;
|
||||
u16 static_lock; // Set defined pages as read only
|
||||
u32 compability_container; // Defines available memory
|
||||
EncryptedAmiiboFile user_memory; // Writable data
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) = 0;
|
||||
std::span<u8> output) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl2 request.
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) = 0;
|
||||
std::span<const u8> inline_input, std::span<u8> output) = 0;
|
||||
|
||||
/**
|
||||
* Handles an ioctl3 request.
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
* @returns The result code of the ioctl.
|
||||
*/
|
||||
virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) = 0;
|
||||
std::span<u8> output, std::span<u8> inline_output) = 0;
|
||||
|
||||
/**
|
||||
* Called once a device is opened
|
||||
|
||||
@@ -18,19 +18,19 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
|
||||
nvdisp_disp0::~nvdisp_disp0() = default;
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
std::span<u8> output, std::span<u8> inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
@@ -51,8 +51,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form
|
||||
stride, format, transform, crop_rect};
|
||||
|
||||
system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences);
|
||||
system.GetPerfStats().EndSystemFrame();
|
||||
system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
|
||||
system.GetPerfStats().EndSystemFrame();
|
||||
system.GetPerfStats().BeginSystemFrame();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ public:
|
||||
~nvdisp_disp0() override;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
|
||||
@@ -28,7 +28,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Con
|
||||
nvhost_as_gpu::~nvhost_as_gpu() = default;
|
||||
|
||||
NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
@@ -61,13 +61,13 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
std::span<u8> output, std::span<u8> inline_output) {
|
||||
switch (command.group) {
|
||||
case 'A':
|
||||
switch (command.cmd) {
|
||||
@@ -87,7 +87,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
|
||||
void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocAsEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -141,7 +141,7 @@ NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::vector<u8>& ou
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -220,7 +220,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
|
||||
mapping_map.erase(offset);
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlFreeSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -266,15 +266,14 @@ NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::vector<u8>& ou
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) {
|
||||
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
|
||||
|
||||
std::vector<IoctlRemapEntry> entries(num_entries);
|
||||
std::memcpy(entries.data(), input.data(), input.size());
|
||||
|
||||
std::scoped_lock lock(mutex);
|
||||
entries.resize_destructive(num_entries);
|
||||
std::memcpy(entries.data(), input.data(), input.size());
|
||||
|
||||
if (!vm.initialised) {
|
||||
return NvResult::BadValue;
|
||||
@@ -320,7 +319,7 @@ NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::vector<u8>& output
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -424,7 +423,7 @@ NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::vector<u8>&
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlUnmapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -463,7 +462,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::vector<u8>&
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlBindChannel params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
|
||||
@@ -492,7 +491,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
|
||||
};
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
@@ -511,8 +510,8 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>&
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) {
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "common/address_space.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
@@ -48,11 +49,11 @@ public:
|
||||
~nvhost_as_gpu() override;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
@@ -138,18 +139,18 @@ private:
|
||||
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
|
||||
"IoctlGetVaRegions is incorrect size");
|
||||
|
||||
NvResult AllocAsEx(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult AllocateSpace(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult Remap(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult MapBufferEx(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult FreeSpace(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult BindChannel(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult AllocAsEx(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocateSpace(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult Remap(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult MapBufferEx(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult FreeSpace(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult BindChannel(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
void GetVARegionsImpl(IoctlGetVaRegions& params);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
|
||||
void FreeMappingLocked(u64 offset);
|
||||
|
||||
@@ -212,6 +213,7 @@ private:
|
||||
bool initialised{};
|
||||
} vm;
|
||||
std::shared_ptr<Tegra::MemoryManager> gmmu;
|
||||
Common::ScratchBuffer<IoctlRemapEntry> entries;
|
||||
|
||||
// s32 channel{};
|
||||
// u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE};
|
||||
|
||||
@@ -35,7 +35,7 @@ nvhost_ctrl::~nvhost_ctrl() {
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
@@ -64,13 +64,13 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inp
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_outpu) {
|
||||
std::span<u8> output, std::span<u8> inline_outpu) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {}
|
||||
|
||||
void nvhost_ctrl::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output) {
|
||||
IocGetConfigParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
|
||||
@@ -87,7 +87,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::vector<u8
|
||||
return NvResult::ConfigVarNotFound; // Returns error on production mode
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output,
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::span<u8> output,
|
||||
bool is_allocation) {
|
||||
IocCtrlEventWaitParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
@@ -231,7 +231,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventRegisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
const u32 event_id = params.user_event_id;
|
||||
@@ -252,7 +252,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::vecto
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventUnregisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
const u32 event_id = params.user_event_id & 0x00FF;
|
||||
@@ -262,8 +262,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::vec
|
||||
return FreeEvent(event_id);
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventUnregisterBatchParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
u64 event_mask = params.user_events;
|
||||
@@ -281,7 +280,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input,
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventClearParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ public:
|
||||
~nvhost_ctrl() override;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
@@ -186,13 +186,12 @@ private:
|
||||
static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8,
|
||||
"IocCtrlEventKill is incorrect size");
|
||||
|
||||
NvResult NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output,
|
||||
bool is_allocation);
|
||||
NvResult IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, bool is_allocation);
|
||||
NvResult IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
NvResult FreeEvent(u32 slot);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
@@ -54,13 +54,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
std::span<u8> output, std::span<u8> inline_output) {
|
||||
switch (command.group) {
|
||||
case 'G':
|
||||
switch (command.cmd) {
|
||||
@@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
|
||||
void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlCharacteristics params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
@@ -127,8 +127,8 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vec
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) {
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlCharacteristics params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
@@ -175,7 +175,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vec
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||
@@ -186,8 +186,8 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) {
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||
@@ -199,7 +199,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlActiveSlotMask params{};
|
||||
@@ -212,7 +212,7 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::vect
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlZcullGetCtxSize params{};
|
||||
@@ -224,7 +224,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::vector
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
||||
@@ -247,7 +247,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::vector<u8
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcSetTable params{};
|
||||
@@ -263,7 +263,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::vector<u8>
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcQueryTable params{};
|
||||
@@ -273,7 +273,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::vector<u
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlFlushL2 params{};
|
||||
@@ -283,7 +283,7 @@ NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::vector<u8>& ou
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlGetGpuTime params{};
|
||||
|
||||
@@ -22,11 +22,11 @@ public:
|
||||
~nvhost_ctrl_gpu() override;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
@@ -151,21 +151,21 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
|
||||
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output);
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output);
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
|
||||
NvResult GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult ZBCSetTable(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult FlushL2(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetGpuTime(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetActiveSlotMask(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullGetInfo(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZBCSetTable(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZBCQueryTable(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult FlushL2(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetGpuTime(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
EventInterface& events_interface;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ nvhost_gpu::~nvhost_gpu() {
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
@@ -99,7 +99,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
};
|
||||
|
||||
NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
@@ -113,7 +113,7 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
std::span<u8> output, std::span<u8> inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
@@ -121,7 +121,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
void nvhost_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
@@ -130,7 +130,7 @@ NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& outp
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
@@ -139,7 +139,7 @@ NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::vector<u8>& o
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
@@ -149,7 +149,7 @@ NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::vector<u8>& o
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&zcull_params, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
||||
zcull_params.mode);
|
||||
@@ -158,7 +158,7 @@ NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::vector<u8>& outpu
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetErrorNotifier params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
||||
@@ -168,14 +168,14 @@ NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::vector<u8>
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&channel_priority, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocGpfifoEx2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV,
|
||||
@@ -197,7 +197,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>&
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocObjCtx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
|
||||
@@ -208,7 +208,8 @@ NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::vecto
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) {
|
||||
static boost::container::small_vector<Tegra::CommandHeader, 512> BuildWaitCommandList(
|
||||
NvFence fence) {
|
||||
return {
|
||||
Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1,
|
||||
Tegra::SubmissionMode::Increasing),
|
||||
@@ -219,35 +220,35 @@ static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) {
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(NvFence fence) {
|
||||
std::vector<Tegra::CommandHeader> result{
|
||||
static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementCommandList(
|
||||
NvFence fence) {
|
||||
boost::container::small_vector<Tegra::CommandHeader, 512> result{
|
||||
Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1,
|
||||
Tegra::SubmissionMode::Increasing),
|
||||
{}};
|
||||
|
||||
for (u32 count = 0; count < 2; ++count) {
|
||||
result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1,
|
||||
Tegra::SubmissionMode::Increasing));
|
||||
result.emplace_back(
|
||||
result.push_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1,
|
||||
Tegra::SubmissionMode::Increasing));
|
||||
result.push_back(
|
||||
BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Increment, fence.id));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(NvFence fence) {
|
||||
std::vector<Tegra::CommandHeader> result{
|
||||
static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementWithWfiCommandList(
|
||||
NvFence fence) {
|
||||
boost::container::small_vector<Tegra::CommandHeader, 512> result{
|
||||
Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1,
|
||||
Tegra::SubmissionMode::Increasing),
|
||||
{}};
|
||||
const std::vector<Tegra::CommandHeader> increment{BuildIncrementCommandList(fence)};
|
||||
|
||||
result.insert(result.end(), increment.begin(), increment.end());
|
||||
|
||||
auto increment_list{BuildIncrementCommandList(fence)};
|
||||
result.insert(result.end(), increment_list.begin(), increment_list.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
||||
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
|
||||
Tegra::CommandList&& entries) {
|
||||
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
|
||||
params.num_entries, params.flags.raw);
|
||||
@@ -293,7 +294,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output,
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
|
||||
bool kickoff) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
UNIMPLEMENTED();
|
||||
@@ -315,7 +316,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
UNIMPLEMENTED();
|
||||
return NvResult::InvalidSize;
|
||||
@@ -327,7 +328,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const
|
||||
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
@@ -337,7 +338,7 @@ NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::vector<u8>& out
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlChannelSetTimeout params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
||||
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
|
||||
@@ -345,7 +346,7 @@ NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::vector<u8
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetTimeslice params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));
|
||||
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
|
||||
|
||||
@@ -41,11 +41,11 @@ public:
|
||||
~nvhost_gpu() override;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
@@ -186,23 +186,23 @@ private:
|
||||
u32_le channel_priority{};
|
||||
u32_le channel_timeslice{};
|
||||
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult SetClientData(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetClientData(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult ZCullBind(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult SetChannelPriority(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetClientData(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetClientData(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullBind(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetErrorNotifier(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetChannelPriority(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocateObjectContext(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
|
||||
Tegra::CommandList&& entries);
|
||||
NvResult SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output,
|
||||
NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
|
||||
bool kickoff = false);
|
||||
NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
|
||||
std::vector<u8>& output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output);
|
||||
std::span<u8> output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ChannelSetTimeout(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
EventInterface& events_interface;
|
||||
NvCore::Container& core;
|
||||
|
||||
@@ -16,7 +16,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_)
|
||||
nvhost_nvdec::~nvhost_nvdec() = default;
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
@@ -56,13 +56,13 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
std::span<u8> output, std::span<u8> inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ public:
|
||||
~nvhost_nvdec() override;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
|
||||
@@ -36,7 +36,7 @@ std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::si
|
||||
// Writes the data in src to an offset into the dst vector. The offset is specified in bytes
|
||||
// Returns the number of bytes written into dst.
|
||||
template <typename T>
|
||||
std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
|
||||
std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size_t offset) {
|
||||
if (src.empty()) {
|
||||
return 0;
|
||||
}
|
||||
@@ -72,8 +72,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSubmit params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
||||
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
|
||||
@@ -121,7 +120,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input,
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetSyncpoint params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
||||
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
|
||||
@@ -133,7 +132,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::vecto
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetWaitbase params{};
|
||||
LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
@@ -142,7 +141,7 @@ NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::vector
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
@@ -159,7 +158,7 @@ NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::vector<u
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
@@ -173,7 +172,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::vector
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&submit_timeout, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
return NvResult::Success;
|
||||
|
||||
@@ -108,12 +108,12 @@ protected:
|
||||
|
||||
/// Ioctl command implementations
|
||||
NvResult SetNVMAPfd(std::span<const u8> input);
|
||||
NvResult Submit(DeviceFD fd, std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetSyncpoint(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult MapBuffer(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetSyncpoint(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult MapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetSubmitTimeout(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {}
|
||||
nvhost_nvjpg::~nvhost_nvjpg() = default;
|
||||
|
||||
NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 'H':
|
||||
switch (command.cmd) {
|
||||
@@ -32,13 +32,13 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
}
|
||||
|
||||
NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
std::span<u8> output, std::span<u8> inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
||||
void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_nvjpg::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
@@ -16,11 +16,11 @@ public:
|
||||
~nvhost_nvjpg() override;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
@@ -33,7 +33,7 @@ private:
|
||||
|
||||
s32_le nvmap_fd{};
|
||||
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -16,7 +16,7 @@ nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_)
|
||||
nvhost_vic::~nvhost_vic() = default;
|
||||
|
||||
NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
@@ -56,13 +56,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
||||
}
|
||||
|
||||
NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
std::span<u8> output, std::span<u8> inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ public:
|
||||
~nvhost_vic();
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
|
||||
@@ -26,7 +26,7 @@ nvmap::nvmap(Core::System& system_, NvCore::Container& container_)
|
||||
nvmap::~nvmap() = default;
|
||||
|
||||
NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) {
|
||||
std::span<u8> output) {
|
||||
switch (command.group) {
|
||||
case 0x1:
|
||||
switch (command.cmd) {
|
||||
@@ -55,13 +55,13 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
}
|
||||
|
||||
NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) {
|
||||
std::span<const u8> inline_input, std::span<u8> output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
|
||||
NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||
NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||
return NvResult::NotImplemented;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
void nvmap::OnOpen(DeviceFD fd) {}
|
||||
void nvmap::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvmap::IocCreate(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCreateParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
|
||||
@@ -89,7 +89,7 @@ NvResult nvmap::IocCreate(std::span<const u8> input, std::vector<u8>& output) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocAlloc(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
|
||||
IocAllocParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
|
||||
@@ -137,7 +137,7 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::vector<u8>& output) {
|
||||
return result;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocGetId(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) {
|
||||
IocGetIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
@@ -161,7 +161,7 @@ NvResult nvmap::IocGetId(std::span<const u8> input, std::vector<u8>& output) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocFromId(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) {
|
||||
IocFromIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
@@ -192,7 +192,7 @@ NvResult nvmap::IocFromId(std::span<const u8> input, std::vector<u8>& output) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocParam(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) {
|
||||
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
|
||||
|
||||
IocParamParams params;
|
||||
@@ -241,7 +241,7 @@ NvResult nvmap::IocParam(std::span<const u8> input, std::vector<u8>& output) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocFree(std::span<const u8> input, std::vector<u8>& output) {
|
||||
NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
|
||||
IocFreeParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@ public:
|
||||
nvmap& operator=(const nvmap&) = delete;
|
||||
|
||||
NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::vector<u8>& output) override;
|
||||
std::span<u8> output) override;
|
||||
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
||||
std::span<const u8> inline_input, std::vector<u8>& output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
|
||||
std::vector<u8>& inline_output) override;
|
||||
std::span<const u8> inline_input, std::span<u8> output) override;
|
||||
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) override;
|
||||
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
@@ -106,12 +106,12 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
||||
|
||||
NvResult IocCreate(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocAlloc(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocGetId(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocFromId(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocParam(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocFree(std::span<const u8> input, std::vector<u8>& output);
|
||||
NvResult IocCreate(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocAlloc(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocGetId(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocFromId(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocParam(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocFree(std::span<const u8> input, std::span<u8> output);
|
||||
|
||||
NvCore::Container& container;
|
||||
NvCore::NvMap& file;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user