diff options
Diffstat (limited to 'src')
38 files changed, 796 insertions, 225 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt index dec2b7cf1..9fab88248 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt | |||
| @@ -14,8 +14,10 @@ import org.yuzu.yuzu_emu.R | |||
| 14 | import org.yuzu.yuzu_emu.databinding.DialogAddFolderBinding | 14 | import org.yuzu.yuzu_emu.databinding.DialogAddFolderBinding |
| 15 | import org.yuzu.yuzu_emu.model.GameDir | 15 | import org.yuzu.yuzu_emu.model.GameDir |
| 16 | import org.yuzu.yuzu_emu.model.GamesViewModel | 16 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 17 | import org.yuzu.yuzu_emu.model.HomeViewModel | ||
| 17 | 18 | ||
| 18 | class AddGameFolderDialogFragment : DialogFragment() { | 19 | class AddGameFolderDialogFragment : DialogFragment() { |
| 20 | private val homeViewModel: HomeViewModel by activityViewModels() | ||
| 19 | private val gamesViewModel: GamesViewModel by activityViewModels() | 21 | private val gamesViewModel: GamesViewModel by activityViewModels() |
| 20 | 22 | ||
| 21 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | 23 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
| @@ -30,6 +32,7 @@ class AddGameFolderDialogFragment : DialogFragment() { | |||
| 30 | .setTitle(R.string.add_game_folder) | 32 | .setTitle(R.string.add_game_folder) |
| 31 | .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> | 33 | .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> |
| 32 | val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked) | 34 | val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked) |
| 35 | homeViewModel.setGamesDirSelected(true) | ||
| 33 | gamesViewModel.addFolder(newGameDir) | 36 | gamesViewModel.addFolder(newGameDir) |
| 34 | } | 37 | } |
| 35 | .setNegativeButton(android.R.string.cancel, null) | 38 | .setNegativeButton(android.R.string.cancel, null) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt index c4277735d..eb5edaa10 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.Manifest | 6 | import android.Manifest |
| 7 | import android.annotation.SuppressLint | ||
| 7 | import android.content.Intent | 8 | import android.content.Intent |
| 8 | import android.os.Build | 9 | import android.os.Build |
| 9 | import android.os.Bundle | 10 | import android.os.Bundle |
| @@ -75,6 +76,8 @@ class SetupFragment : Fragment() { | |||
| 75 | return binding.root | 76 | return binding.root |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 79 | // This is using the correct scope, lint is just acting up | ||
| 80 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 78 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 81 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 79 | mainActivity = requireActivity() as MainActivity | 82 | mainActivity = requireActivity() as MainActivity |
| 80 | 83 | ||
| @@ -206,12 +209,24 @@ class SetupFragment : Fragment() { | |||
| 206 | ) | 209 | ) |
| 207 | } | 210 | } |
| 208 | 211 | ||
| 209 | viewLifecycleOwner.lifecycleScope.launch { | 212 | viewLifecycleOwner.lifecycleScope.apply { |
| 210 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 213 | launch { |
| 211 | homeViewModel.shouldPageForward.collect { | 214 | repeatOnLifecycle(Lifecycle.State.CREATED) { |
| 212 | if (it) { | 215 | homeViewModel.shouldPageForward.collect { |
| 213 | pageForward() | 216 | if (it) { |
| 214 | homeViewModel.setShouldPageForward(false) | 217 | pageForward() |
| 218 | homeViewModel.setShouldPageForward(false) | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | launch { | ||
| 224 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 225 | homeViewModel.gamesDirSelected.collect { | ||
| 226 | if (it) { | ||
| 227 | gamesDirCallback.onStepCompleted() | ||
| 228 | homeViewModel.setGamesDirSelected(false) | ||
| 229 | } | ||
| 215 | } | 230 | } |
| 216 | } | 231 | } |
| 217 | } | 232 | } |
| @@ -339,7 +354,6 @@ class SetupFragment : Fragment() { | |||
| 339 | registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result -> | 354 | registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result -> |
| 340 | if (result != null) { | 355 | if (result != null) { |
| 341 | mainActivity.processGamesDir(result) | 356 | mainActivity.processGamesDir(result) |
| 342 | gamesDirCallback.onStepCompleted() | ||
| 343 | } | 357 | } |
| 344 | } | 358 | } |
| 345 | 359 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt index 752d98c10..fd925235b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt | |||
| @@ -133,7 +133,7 @@ class GamesViewModel : ViewModel() { | |||
| 133 | viewModelScope.launch { | 133 | viewModelScope.launch { |
| 134 | withContext(Dispatchers.IO) { | 134 | withContext(Dispatchers.IO) { |
| 135 | NativeConfig.addGameDir(gameDir) | 135 | NativeConfig.addGameDir(gameDir) |
| 136 | getGameDirs() | 136 | getGameDirs(true) |
| 137 | } | 137 | } |
| 138 | } | 138 | } |
| 139 | 139 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt index 251b5a667..07e65b028 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt | |||
| @@ -6,6 +6,7 @@ package org.yuzu.yuzu_emu.model | |||
| 6 | import androidx.lifecycle.ViewModel | 6 | import androidx.lifecycle.ViewModel |
| 7 | import kotlinx.coroutines.flow.MutableStateFlow | 7 | import kotlinx.coroutines.flow.MutableStateFlow |
| 8 | import kotlinx.coroutines.flow.StateFlow | 8 | import kotlinx.coroutines.flow.StateFlow |
| 9 | import kotlinx.coroutines.flow.asStateFlow | ||
| 9 | 10 | ||
| 10 | class HomeViewModel : ViewModel() { | 11 | class HomeViewModel : ViewModel() { |
| 11 | val navigationVisible: StateFlow<Pair<Boolean, Boolean>> get() = _navigationVisible | 12 | val navigationVisible: StateFlow<Pair<Boolean, Boolean>> get() = _navigationVisible |
| @@ -17,6 +18,9 @@ class HomeViewModel : ViewModel() { | |||
| 17 | val shouldPageForward: StateFlow<Boolean> get() = _shouldPageForward | 18 | val shouldPageForward: StateFlow<Boolean> get() = _shouldPageForward |
| 18 | private val _shouldPageForward = MutableStateFlow(false) | 19 | private val _shouldPageForward = MutableStateFlow(false) |
| 19 | 20 | ||
| 21 | private val _gamesDirSelected = MutableStateFlow(false) | ||
| 22 | val gamesDirSelected get() = _gamesDirSelected.asStateFlow() | ||
| 23 | |||
| 20 | var navigatedToSetup = false | 24 | var navigatedToSetup = false |
| 21 | 25 | ||
| 22 | fun setNavigationVisibility(visible: Boolean, animated: Boolean) { | 26 | fun setNavigationVisibility(visible: Boolean, animated: Boolean) { |
| @@ -36,4 +40,8 @@ class HomeViewModel : ViewModel() { | |||
| 36 | fun setShouldPageForward(pageForward: Boolean) { | 40 | fun setShouldPageForward(pageForward: Boolean) { |
| 37 | _shouldPageForward.value = pageForward | 41 | _shouldPageForward.value = pageForward |
| 38 | } | 42 | } |
| 43 | |||
| 44 | fun setGamesDirSelected(selected: Boolean) { | ||
| 45 | _gamesDirSelected.value = selected | ||
| 46 | } | ||
| 39 | } | 47 | } |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 4666bd0a0..88f509ba7 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -160,12 +160,16 @@ static bool is_nce_enabled = false; | |||
| 160 | 160 | ||
| 161 | void SetNceEnabled(bool is_39bit) { | 161 | void SetNceEnabled(bool is_39bit) { |
| 162 | const bool is_nce_selected = values.cpu_backend.GetValue() == CpuBackend::Nce; | 162 | const bool is_nce_selected = values.cpu_backend.GetValue() == CpuBackend::Nce; |
| 163 | is_nce_enabled = IsFastmemEnabled() && is_nce_selected && is_39bit; | 163 | if (is_nce_selected && !IsFastmemEnabled()) { |
| 164 | if (is_nce_selected && !is_nce_enabled) { | 164 | LOG_WARNING(Common, "Fastmem is required to natively execute code in a performant manner, " |
| 165 | "falling back to Dynarmic"); | ||
| 166 | } | ||
| 167 | if (is_nce_selected && !is_39bit) { | ||
| 165 | LOG_WARNING( | 168 | LOG_WARNING( |
| 166 | Common, | 169 | Common, |
| 167 | "Program does not utilize 39-bit address space, unable to natively execute code"); | 170 | "Program does not utilize 39-bit address space, unable to natively execute code"); |
| 168 | } | 171 | } |
| 172 | is_nce_enabled = IsFastmemEnabled() && is_nce_selected && is_39bit; | ||
| 169 | } | 173 | } |
| 170 | 174 | ||
| 171 | bool IsNceEnabled() { | 175 | bool IsNceEnabled() { |
diff --git a/src/common/settings.h b/src/common/settings.h index 98341ad96..7dc18fffe 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -180,14 +180,20 @@ struct Values { | |||
| 180 | &use_speed_limit}; | 180 | &use_speed_limit}; |
| 181 | 181 | ||
| 182 | // Cpu | 182 | // Cpu |
| 183 | SwitchableSetting<CpuBackend, true> cpu_backend{ | 183 | SwitchableSetting<CpuBackend, true> cpu_backend{linkage, |
| 184 | linkage, CpuBackend::Dynarmic, CpuBackend::Dynarmic, | ||
| 185 | #ifdef HAS_NCE | 184 | #ifdef HAS_NCE |
| 186 | CpuBackend::Nce, | 185 | CpuBackend::Nce, |
| 187 | #else | 186 | #else |
| 188 | CpuBackend::Dynarmic, | 187 | CpuBackend::Dynarmic, |
| 189 | #endif | 188 | #endif |
| 190 | "cpu_backend", Category::Cpu}; | 189 | CpuBackend::Dynarmic, |
| 190 | #ifdef HAS_NCE | ||
| 191 | CpuBackend::Nce, | ||
| 192 | #else | ||
| 193 | CpuBackend::Dynarmic, | ||
| 194 | #endif | ||
| 195 | "cpu_backend", | ||
| 196 | Category::Cpu}; | ||
| 191 | SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto, | 197 | SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto, |
| 192 | CpuAccuracy::Auto, CpuAccuracy::Paranoid, | 198 | CpuAccuracy::Auto, CpuAccuracy::Paranoid, |
| 193 | "cpu_accuracy", Category::Cpu}; | 199 | "cpu_accuracy", Category::Cpu}; |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 05c103f51..27d636ed4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -549,6 +549,8 @@ add_library(core STATIC | |||
| 549 | hle/service/hid/xcd.cpp | 549 | hle/service/hid/xcd.cpp |
| 550 | hle/service/hid/xcd.h | 550 | hle/service/hid/xcd.h |
| 551 | hle/service/hid/errors.h | 551 | hle/service/hid/errors.h |
| 552 | hle/service/hid/controllers/applet_resource.cpp | ||
| 553 | hle/service/hid/controllers/applet_resource.h | ||
| 552 | hle/service/hid/controllers/console_six_axis.cpp | 554 | hle/service/hid/controllers/console_six_axis.cpp |
| 553 | hle/service/hid/controllers/console_six_axis.h | 555 | hle/service/hid/controllers/console_six_axis.h |
| 554 | hle/service/hid/controllers/controller_base.cpp | 556 | hle/service/hid/controllers/controller_base.cpp |
diff --git a/src/core/arm/debug.cpp b/src/core/arm/debug.cpp index 1fe37b8ee..af1c34bc3 100644 --- a/src/core/arm/debug.cpp +++ b/src/core/arm/debug.cpp | |||
| @@ -282,6 +282,8 @@ Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) { | |||
| 282 | 282 | ||
| 283 | // Ignore leading directories. | 283 | // Ignore leading directories. |
| 284 | char* path_pointer = module_path.path.data(); | 284 | char* path_pointer = module_path.path.data(); |
| 285 | char* path_end = | ||
| 286 | path_pointer + std::min(PathLengthMax, module_path.path_length); | ||
| 285 | 287 | ||
| 286 | for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) && | 288 | for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) && |
| 287 | module_path.path[i] != '\0'; | 289 | module_path.path[i] != '\0'; |
| @@ -292,7 +294,8 @@ Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) { | |||
| 292 | } | 294 | } |
| 293 | 295 | ||
| 294 | // Insert output. | 296 | // Insert output. |
| 295 | modules.emplace(svc_mem_info.base_address, path_pointer); | 297 | modules.emplace(svc_mem_info.base_address, |
| 298 | std::string_view(path_pointer, path_end)); | ||
| 296 | } | 299 | } |
| 297 | } | 300 | } |
| 298 | } | 301 | } |
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index f1d3e4129..dd9cca103 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <cstring> | 4 | #include <cstring> |
| 5 | #include <span> | ||
| 5 | #include <string_view> | 6 | #include <string_view> |
| 6 | #include "common/alignment.h" | 7 | #include "common/alignment.h" |
| 7 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| @@ -134,7 +135,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir, | |||
| 134 | 135 | ||
| 135 | child->size = child->source->GetSize(); | 136 | child->size = child->source->GetSize(); |
| 136 | 137 | ||
| 137 | AddFile(parent, child); | 138 | AddFile(parent, std::move(child)); |
| 138 | } | 139 | } |
| 139 | 140 | ||
| 140 | for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) { | 141 | for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) { |
| @@ -163,36 +164,24 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir, | |||
| 163 | 164 | ||
| 164 | bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, | 165 | bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, |
| 165 | std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { | 166 | std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { |
| 166 | // Check whether it's already in the known directories. | ||
| 167 | const auto [it, is_new] = directories.emplace(dir_ctx->path, nullptr); | ||
| 168 | if (!is_new) { | ||
| 169 | return false; | ||
| 170 | } | ||
| 171 | |||
| 172 | // Add a new directory. | 167 | // Add a new directory. |
| 173 | num_dirs++; | 168 | num_dirs++; |
| 174 | dir_table_size += | 169 | dir_table_size += |
| 175 | sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); | 170 | sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); |
| 176 | dir_ctx->parent = parent_dir_ctx; | 171 | dir_ctx->parent = std::move(parent_dir_ctx); |
| 177 | it->second = dir_ctx; | 172 | directories.emplace_back(std::move(dir_ctx)); |
| 178 | 173 | ||
| 179 | return true; | 174 | return true; |
| 180 | } | 175 | } |
| 181 | 176 | ||
| 182 | bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, | 177 | bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, |
| 183 | std::shared_ptr<RomFSBuildFileContext> file_ctx) { | 178 | std::shared_ptr<RomFSBuildFileContext> file_ctx) { |
| 184 | // Check whether it's already in the known files. | ||
| 185 | const auto [it, is_new] = files.emplace(file_ctx->path, nullptr); | ||
| 186 | if (!is_new) { | ||
| 187 | return false; | ||
| 188 | } | ||
| 189 | |||
| 190 | // Add a new file. | 179 | // Add a new file. |
| 191 | num_files++; | 180 | num_files++; |
| 192 | file_table_size += | 181 | file_table_size += |
| 193 | sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); | 182 | sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); |
| 194 | file_ctx->parent = parent_dir_ctx; | 183 | file_ctx->parent = std::move(parent_dir_ctx); |
| 195 | it->second = file_ctx; | 184 | files.emplace_back(std::move(file_ctx)); |
| 196 | 185 | ||
| 197 | return true; | 186 | return true; |
| 198 | } | 187 | } |
| @@ -201,7 +190,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) | |||
| 201 | : base(std::move(base_)), ext(std::move(ext_)) { | 190 | : base(std::move(base_)), ext(std::move(ext_)) { |
| 202 | root = std::make_shared<RomFSBuildDirectoryContext>(); | 191 | root = std::make_shared<RomFSBuildDirectoryContext>(); |
| 203 | root->path = "\0"; | 192 | root->path = "\0"; |
| 204 | directories.emplace(root->path, root); | 193 | directories.emplace_back(root); |
| 205 | num_dirs = 1; | 194 | num_dirs = 1; |
| 206 | dir_table_size = 0x18; | 195 | dir_table_size = 0x18; |
| 207 | 196 | ||
| @@ -210,28 +199,43 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) | |||
| 210 | 199 | ||
| 211 | RomFSBuildContext::~RomFSBuildContext() = default; | 200 | RomFSBuildContext::~RomFSBuildContext() = default; |
| 212 | 201 | ||
| 213 | std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | 202 | std::vector<std::pair<u64, VirtualFile>> RomFSBuildContext::Build() { |
| 214 | const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); | 203 | const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); |
| 215 | const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); | 204 | const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); |
| 216 | dir_hash_table_size = 4 * dir_hash_table_entry_count; | 205 | dir_hash_table_size = 4 * dir_hash_table_entry_count; |
| 217 | file_hash_table_size = 4 * file_hash_table_entry_count; | 206 | file_hash_table_size = 4 * file_hash_table_entry_count; |
| 218 | 207 | ||
| 219 | // Assign metadata pointers | 208 | // Assign metadata pointers. |
| 220 | RomFSHeader header{}; | 209 | RomFSHeader header{}; |
| 221 | 210 | ||
| 222 | std::vector<u32> dir_hash_table(dir_hash_table_entry_count, ROMFS_ENTRY_EMPTY); | 211 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + |
| 223 | std::vector<u32> file_hash_table(file_hash_table_entry_count, ROMFS_ENTRY_EMPTY); | 212 | dir_table_size); |
| 224 | 213 | u32* const dir_hash_table_pointer = reinterpret_cast<u32*>(metadata.data()); | |
| 225 | std::vector<u8> dir_table(dir_table_size); | 214 | u8* const dir_table_pointer = metadata.data() + dir_hash_table_size; |
| 226 | std::vector<u8> file_table(file_table_size); | 215 | u32* const file_hash_table_pointer = |
| 227 | 216 | reinterpret_cast<u32*>(metadata.data() + dir_hash_table_size + dir_table_size); | |
| 228 | std::shared_ptr<RomFSBuildFileContext> cur_file; | 217 | u8* const file_table_pointer = |
| 218 | metadata.data() + dir_hash_table_size + dir_table_size + file_hash_table_size; | ||
| 219 | |||
| 220 | std::span<u32> dir_hash_table(dir_hash_table_pointer, dir_hash_table_entry_count); | ||
| 221 | std::span<u32> file_hash_table(file_hash_table_pointer, file_hash_table_entry_count); | ||
| 222 | std::span<u8> dir_table(dir_table_pointer, dir_table_size); | ||
| 223 | std::span<u8> file_table(file_table_pointer, file_table_size); | ||
| 224 | |||
| 225 | // Initialize hash tables. | ||
| 226 | std::memset(dir_hash_table.data(), 0xFF, dir_hash_table.size_bytes()); | ||
| 227 | std::memset(file_hash_table.data(), 0xFF, file_hash_table.size_bytes()); | ||
| 228 | |||
| 229 | // Sort tables by name. | ||
| 230 | std::sort(files.begin(), files.end(), | ||
| 231 | [](const auto& a, const auto& b) { return a->path < b->path; }); | ||
| 232 | std::sort(directories.begin(), directories.end(), | ||
| 233 | [](const auto& a, const auto& b) { return a->path < b->path; }); | ||
| 229 | 234 | ||
| 230 | // Determine file offsets. | 235 | // Determine file offsets. |
| 231 | u32 entry_offset = 0; | 236 | u32 entry_offset = 0; |
| 232 | std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; | 237 | std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; |
| 233 | for (const auto& it : files) { | 238 | for (const auto& cur_file : files) { |
| 234 | cur_file = it.second; | ||
| 235 | file_partition_size = Common::AlignUp(file_partition_size, 16); | 239 | file_partition_size = Common::AlignUp(file_partition_size, 16); |
| 236 | cur_file->offset = file_partition_size; | 240 | cur_file->offset = file_partition_size; |
| 237 | file_partition_size += cur_file->size; | 241 | file_partition_size += cur_file->size; |
| @@ -243,34 +247,48 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 243 | } | 247 | } |
| 244 | // Assign deferred parent/sibling ownership. | 248 | // Assign deferred parent/sibling ownership. |
| 245 | for (auto it = files.rbegin(); it != files.rend(); ++it) { | 249 | for (auto it = files.rbegin(); it != files.rend(); ++it) { |
| 246 | cur_file = it->second; | 250 | auto& cur_file = *it; |
| 247 | cur_file->sibling = cur_file->parent->file; | 251 | cur_file->sibling = cur_file->parent->file; |
| 248 | cur_file->parent->file = cur_file; | 252 | cur_file->parent->file = cur_file; |
| 249 | } | 253 | } |
| 250 | 254 | ||
| 251 | std::shared_ptr<RomFSBuildDirectoryContext> cur_dir; | ||
| 252 | |||
| 253 | // Determine directory offsets. | 255 | // Determine directory offsets. |
| 254 | entry_offset = 0; | 256 | entry_offset = 0; |
| 255 | for (const auto& it : directories) { | 257 | for (const auto& cur_dir : directories) { |
| 256 | cur_dir = it.second; | ||
| 257 | cur_dir->entry_offset = entry_offset; | 258 | cur_dir->entry_offset = entry_offset; |
| 258 | entry_offset += | 259 | entry_offset += |
| 259 | static_cast<u32>(sizeof(RomFSDirectoryEntry) + | 260 | static_cast<u32>(sizeof(RomFSDirectoryEntry) + |
| 260 | Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); | 261 | Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); |
| 261 | } | 262 | } |
| 262 | // Assign deferred parent/sibling ownership. | 263 | // Assign deferred parent/sibling ownership. |
| 263 | for (auto it = directories.rbegin(); it->second != root; ++it) { | 264 | for (auto it = directories.rbegin(); (*it) != root; ++it) { |
| 264 | cur_dir = it->second; | 265 | auto& cur_dir = *it; |
| 265 | cur_dir->sibling = cur_dir->parent->child; | 266 | cur_dir->sibling = cur_dir->parent->child; |
| 266 | cur_dir->parent->child = cur_dir; | 267 | cur_dir->parent->child = cur_dir; |
| 267 | } | 268 | } |
| 268 | 269 | ||
| 269 | std::multimap<u64, VirtualFile> out; | 270 | // Create output map. |
| 271 | std::vector<std::pair<u64, VirtualFile>> out; | ||
| 272 | out.reserve(num_files + 2); | ||
| 273 | |||
| 274 | // Set header fields. | ||
| 275 | header.header_size = sizeof(RomFSHeader); | ||
| 276 | header.file_hash_table_size = file_hash_table_size; | ||
| 277 | header.file_table_size = file_table_size; | ||
| 278 | header.dir_hash_table_size = dir_hash_table_size; | ||
| 279 | header.dir_table_size = dir_table_size; | ||
| 280 | header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; | ||
| 281 | header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4); | ||
| 282 | header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; | ||
| 283 | header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; | ||
| 284 | header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; | ||
| 285 | |||
| 286 | std::vector<u8> header_data(sizeof(RomFSHeader)); | ||
| 287 | std::memcpy(header_data.data(), &header, header_data.size()); | ||
| 288 | out.emplace_back(0, std::make_shared<VectorVfsFile>(std::move(header_data))); | ||
| 270 | 289 | ||
| 271 | // Populate file tables. | 290 | // Populate file tables. |
| 272 | for (const auto& it : files) { | 291 | for (const auto& cur_file : files) { |
| 273 | cur_file = it.second; | ||
| 274 | RomFSFileEntry cur_entry{}; | 292 | RomFSFileEntry cur_entry{}; |
| 275 | 293 | ||
| 276 | cur_entry.parent = cur_file->parent->entry_offset; | 294 | cur_entry.parent = cur_file->parent->entry_offset; |
| @@ -287,7 +305,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 287 | 305 | ||
| 288 | cur_entry.name_size = name_size; | 306 | cur_entry.name_size = name_size; |
| 289 | 307 | ||
| 290 | out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); | 308 | out.emplace_back(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); |
| 291 | std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); | 309 | std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); |
| 292 | std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, | 310 | std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, |
| 293 | Common::AlignUp(cur_entry.name_size, 4)); | 311 | Common::AlignUp(cur_entry.name_size, 4)); |
| @@ -296,8 +314,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 296 | } | 314 | } |
| 297 | 315 | ||
| 298 | // Populate dir tables. | 316 | // Populate dir tables. |
| 299 | for (const auto& it : directories) { | 317 | for (const auto& cur_dir : directories) { |
| 300 | cur_dir = it.second; | ||
| 301 | RomFSDirectoryEntry cur_entry{}; | 318 | RomFSDirectoryEntry cur_entry{}; |
| 302 | 319 | ||
| 303 | cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; | 320 | cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; |
| @@ -323,34 +340,13 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 323 | cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); | 340 | cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); |
| 324 | } | 341 | } |
| 325 | 342 | ||
| 326 | // Set header fields. | 343 | // Write metadata. |
| 327 | header.header_size = sizeof(RomFSHeader); | 344 | out.emplace_back(header.dir_hash_table_ofs, |
| 328 | header.file_hash_table_size = file_hash_table_size; | 345 | std::make_shared<VectorVfsFile>(std::move(metadata))); |
| 329 | header.file_table_size = file_table_size; | ||
| 330 | header.dir_hash_table_size = dir_hash_table_size; | ||
| 331 | header.dir_table_size = dir_table_size; | ||
| 332 | header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; | ||
| 333 | header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4); | ||
| 334 | header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; | ||
| 335 | header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; | ||
| 336 | header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; | ||
| 337 | |||
| 338 | std::vector<u8> header_data(sizeof(RomFSHeader)); | ||
| 339 | std::memcpy(header_data.data(), &header, header_data.size()); | ||
| 340 | out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data))); | ||
| 341 | 346 | ||
| 342 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + | 347 | // Sort the output. |
| 343 | dir_table_size); | 348 | std::sort(out.begin(), out.end(), |
| 344 | std::size_t index = 0; | 349 | [](const auto& a, const auto& b) { return a.first < b.first; }); |
| 345 | std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); | ||
| 346 | index += dir_hash_table.size() * sizeof(u32); | ||
| 347 | std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); | ||
| 348 | index += dir_table.size(); | ||
| 349 | std::memcpy(metadata.data() + index, file_hash_table.data(), | ||
| 350 | file_hash_table.size() * sizeof(u32)); | ||
| 351 | index += file_hash_table.size() * sizeof(u32); | ||
| 352 | std::memcpy(metadata.data() + index, file_table.data(), file_table.size()); | ||
| 353 | out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata))); | ||
| 354 | 350 | ||
| 355 | return out; | 351 | return out; |
| 356 | } | 352 | } |
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h index 06e5d5a47..f387c79f1 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.h +++ b/src/core/file_sys/fsmitm_romfsbuild.h | |||
| @@ -22,14 +22,14 @@ public: | |||
| 22 | ~RomFSBuildContext(); | 22 | ~RomFSBuildContext(); |
| 23 | 23 | ||
| 24 | // This finalizes the context. | 24 | // This finalizes the context. |
| 25 | std::multimap<u64, VirtualFile> Build(); | 25 | std::vector<std::pair<u64, VirtualFile>> Build(); |
| 26 | 26 | ||
| 27 | private: | 27 | private: |
| 28 | VirtualDir base; | 28 | VirtualDir base; |
| 29 | VirtualDir ext; | 29 | VirtualDir ext; |
| 30 | std::shared_ptr<RomFSBuildDirectoryContext> root; | 30 | std::shared_ptr<RomFSBuildDirectoryContext> root; |
| 31 | std::map<std::string, std::shared_ptr<RomFSBuildDirectoryContext>, std::less<>> directories; | 31 | std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> directories; |
| 32 | std::map<std::string, std::shared_ptr<RomFSBuildFileContext>, std::less<>> files; | 32 | std::vector<std::shared_ptr<RomFSBuildFileContext>> files; |
| 33 | u64 num_dirs = 0; | 33 | u64 num_dirs = 0; |
| 34 | u64 num_files = 0; | 34 | u64 num_files = 0; |
| 35 | u64 dir_table_size = 0; | 35 | u64 dir_table_size = 0; |
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 6de2103a0..6182598ae 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp | |||
| @@ -55,44 +55,68 @@ struct FileEntry { | |||
| 55 | }; | 55 | }; |
| 56 | static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); | 56 | static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); |
| 57 | 57 | ||
| 58 | template <typename Entry> | 58 | struct RomFSTraversalContext { |
| 59 | std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { | 59 | RomFSHeader header; |
| 60 | Entry entry{}; | 60 | VirtualFile file; |
| 61 | if (file->ReadObject(&entry, offset) != sizeof(Entry)) | 61 | std::vector<u8> directory_meta; |
| 62 | return {}; | 62 | std::vector<u8> file_meta; |
| 63 | std::string string(entry.name_length, '\0'); | 63 | }; |
| 64 | if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size()) | 64 | |
| 65 | template <typename EntryType, auto Member> | ||
| 66 | std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, size_t offset) { | ||
| 67 | const size_t entry_end = offset + sizeof(EntryType); | ||
| 68 | const std::vector<u8>& vec = ctx.*Member; | ||
| 69 | const size_t size = vec.size(); | ||
| 70 | const u8* data = vec.data(); | ||
| 71 | EntryType entry{}; | ||
| 72 | |||
| 73 | if (entry_end > size) { | ||
| 65 | return {}; | 74 | return {}; |
| 66 | return {entry, string}; | 75 | } |
| 76 | std::memcpy(&entry, data + offset, sizeof(EntryType)); | ||
| 77 | |||
| 78 | const size_t name_length = std::min(entry_end + entry.name_length, size) - entry_end; | ||
| 79 | std::string name(reinterpret_cast<const char*>(data + entry_end), name_length); | ||
| 80 | |||
| 81 | return {entry, std::move(name)}; | ||
| 82 | } | ||
| 83 | |||
| 84 | std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx, | ||
| 85 | size_t directory_offset) { | ||
| 86 | return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset); | ||
| 87 | } | ||
| 88 | |||
| 89 | std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx, | ||
| 90 | size_t file_offset) { | ||
| 91 | return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset); | ||
| 67 | } | 92 | } |
| 68 | 93 | ||
| 69 | void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, | 94 | void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset, |
| 70 | u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) { | 95 | std::shared_ptr<VectorVfsDirectory>& parent) { |
| 71 | while (this_file_offset != ROMFS_ENTRY_EMPTY) { | 96 | while (this_file_offset != ROMFS_ENTRY_EMPTY) { |
| 72 | auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); | 97 | auto entry = GetFileEntry(ctx, this_file_offset); |
| 73 | 98 | ||
| 74 | parent->AddFile(std::make_shared<OffsetVfsFile>( | 99 | parent->AddFile(std::make_shared<OffsetVfsFile>(ctx.file, entry.first.size, |
| 75 | file, entry.first.size, entry.first.offset + data_offset, entry.second)); | 100 | entry.first.offset + ctx.header.data_offset, |
| 101 | std::move(entry.second))); | ||
| 76 | 102 | ||
| 77 | this_file_offset = entry.first.sibling; | 103 | this_file_offset = entry.first.sibling; |
| 78 | } | 104 | } |
| 79 | } | 105 | } |
| 80 | 106 | ||
| 81 | void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, | 107 | void ProcessDirectory(const RomFSTraversalContext& ctx, u32 this_dir_offset, |
| 82 | std::size_t data_offset, u32 this_dir_offset, | ||
| 83 | std::shared_ptr<VectorVfsDirectory>& parent) { | 108 | std::shared_ptr<VectorVfsDirectory>& parent) { |
| 84 | while (this_dir_offset != ROMFS_ENTRY_EMPTY) { | 109 | while (this_dir_offset != ROMFS_ENTRY_EMPTY) { |
| 85 | auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); | 110 | auto entry = GetDirectoryEntry(ctx, this_dir_offset); |
| 86 | auto current = std::make_shared<VectorVfsDirectory>( | 111 | auto current = std::make_shared<VectorVfsDirectory>( |
| 87 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); | 112 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); |
| 88 | 113 | ||
| 89 | if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { | 114 | if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { |
| 90 | ProcessFile(file, file_offset, data_offset, entry.first.child_file, current); | 115 | ProcessFile(ctx, entry.first.child_file, current); |
| 91 | } | 116 | } |
| 92 | 117 | ||
| 93 | if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { | 118 | if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { |
| 94 | ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir, | 119 | ProcessDirectory(ctx, entry.first.child_dir, current); |
| 95 | current); | ||
| 96 | } | 120 | } |
| 97 | 121 | ||
| 98 | parent->AddDirectory(current); | 122 | parent->AddDirectory(current); |
| @@ -107,22 +131,25 @@ VirtualDir ExtractRomFS(VirtualFile file) { | |||
| 107 | return root_container; | 131 | return root_container; |
| 108 | } | 132 | } |
| 109 | 133 | ||
| 110 | RomFSHeader header{}; | 134 | RomFSTraversalContext ctx{}; |
| 111 | if (file->ReadObject(&header) != sizeof(RomFSHeader)) { | 135 | |
| 112 | return root_container; | 136 | if (file->ReadObject(&ctx.header) != sizeof(RomFSHeader)) { |
| 137 | return nullptr; | ||
| 113 | } | 138 | } |
| 114 | 139 | ||
| 115 | if (header.header_size != sizeof(RomFSHeader)) { | 140 | if (ctx.header.header_size != sizeof(RomFSHeader)) { |
| 116 | return root_container; | 141 | return nullptr; |
| 117 | } | 142 | } |
| 118 | 143 | ||
| 119 | const u64 file_offset = header.file_meta.offset; | 144 | ctx.file = file; |
| 120 | const u64 dir_offset = header.directory_meta.offset; | 145 | ctx.directory_meta = |
| 146 | file->ReadBytes(ctx.header.directory_meta.size, ctx.header.directory_meta.offset); | ||
| 147 | ctx.file_meta = file->ReadBytes(ctx.header.file_meta.size, ctx.header.file_meta.offset); | ||
| 121 | 148 | ||
| 122 | ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); | 149 | ProcessDirectory(ctx, 0, root_container); |
| 123 | 150 | ||
| 124 | if (auto root = root_container->GetSubdirectory(""); root) { | 151 | if (auto root = root_container->GetSubdirectory(""); root) { |
| 125 | return std::make_shared<CachedVfsDirectory>(std::move(root)); | 152 | return root; |
| 126 | } | 153 | } |
| 127 | 154 | ||
| 128 | ASSERT(false); | 155 | ASSERT(false); |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 168b9cbec..7c7298527 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -59,8 +59,8 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name, | |||
| 59 | return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map))); | 59 | return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map))); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name, | 62 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile( |
| 63 | std::multimap<u64, VirtualFile>&& files) { | 63 | u8 filler_byte, std::string&& name, std::vector<std::pair<u64, VirtualFile>>&& files) { |
| 64 | // Fold trivial cases. | 64 | // Fold trivial cases. |
| 65 | if (files.empty()) { | 65 | if (files.empty()) { |
| 66 | return nullptr; | 66 | return nullptr; |
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index cbddd12bd..b5f3d72e3 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h | |||
| @@ -37,7 +37,7 @@ public: | |||
| 37 | /// Convenience function that turns a map of offsets to files into a concatenated file, filling | 37 | /// Convenience function that turns a map of offsets to files into a concatenated file, filling |
| 38 | /// gaps with a given filler byte. | 38 | /// gaps with a given filler byte. |
| 39 | static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name, | 39 | static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name, |
| 40 | std::multimap<u64, VirtualFile>&& files); | 40 | std::vector<std::pair<u64, VirtualFile>>&& files); |
| 41 | 41 | ||
| 42 | std::string GetName() const override; | 42 | std::string GetName() const override; |
| 43 | std::size_t GetSize() const override; | 43 | std::size_t GetSize() const override; |
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp index 08daca397..5551743fb 100644 --- a/src/core/file_sys/vfs_layered.cpp +++ b/src/core/file_sys/vfs_layered.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <algorithm> | 4 | #include <algorithm> |
| 5 | #include <set> | 5 | #include <set> |
| 6 | #include <unordered_set> | ||
| 6 | #include <utility> | 7 | #include <utility> |
| 7 | #include "core/file_sys/vfs_layered.h" | 8 | #include "core/file_sys/vfs_layered.h" |
| 8 | 9 | ||
| @@ -59,13 +60,12 @@ std::string LayeredVfsDirectory::GetFullPath() const { | |||
| 59 | 60 | ||
| 60 | std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { | 61 | std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { |
| 61 | std::vector<VirtualFile> out; | 62 | std::vector<VirtualFile> out; |
| 62 | std::set<std::string, std::less<>> out_names; | 63 | std::unordered_set<std::string> out_names; |
| 63 | 64 | ||
| 64 | for (const auto& layer : dirs) { | 65 | for (const auto& layer : dirs) { |
| 65 | for (auto& file : layer->GetFiles()) { | 66 | for (auto& file : layer->GetFiles()) { |
| 66 | auto file_name = file->GetName(); | 67 | const auto [it, is_new] = out_names.emplace(file->GetName()); |
| 67 | if (!out_names.contains(file_name)) { | 68 | if (is_new) { |
| 68 | out_names.emplace(std::move(file_name)); | ||
| 69 | out.emplace_back(std::move(file)); | 69 | out.emplace_back(std::move(file)); |
| 70 | } | 70 | } |
| 71 | } | 71 | } |
| @@ -75,18 +75,19 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { | |||
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { | 77 | std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { |
| 78 | std::vector<std::string> names; | 78 | std::vector<VirtualDir> out; |
| 79 | std::unordered_set<std::string> out_names; | ||
| 80 | |||
| 79 | for (const auto& layer : dirs) { | 81 | for (const auto& layer : dirs) { |
| 80 | for (const auto& sd : layer->GetSubdirectories()) { | 82 | for (const auto& sd : layer->GetSubdirectories()) { |
| 81 | if (std::find(names.begin(), names.end(), sd->GetName()) == names.end()) | 83 | out_names.emplace(sd->GetName()); |
| 82 | names.push_back(sd->GetName()); | ||
| 83 | } | 84 | } |
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | std::vector<VirtualDir> out; | 87 | out.reserve(out_names.size()); |
| 87 | out.reserve(names.size()); | 88 | for (const auto& subdir : out_names) { |
| 88 | for (const auto& subdir : names) | ||
| 89 | out.emplace_back(GetSubdirectory(subdir)); | 89 | out.emplace_back(GetSubdirectory(subdir)); |
| 90 | } | ||
| 90 | 91 | ||
| 91 | return out; | 92 | return out; |
| 92 | } | 93 | } |
diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp new file mode 100644 index 000000000..ee60d8b44 --- /dev/null +++ b/src/core/hle/service/hid/controllers/applet_resource.cpp | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/kernel/k_shared_memory.h" | ||
| 6 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 7 | #include "core/hle/service/hid/errors.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | AppletResource::AppletResource(Core::System& system_) : system{system_} {} | ||
| 12 | |||
| 13 | AppletResource::~AppletResource() = default; | ||
| 14 | |||
| 15 | Result AppletResource::CreateAppletResource(u64 aruid) { | ||
| 16 | const u64 index = GetIndexFromAruid(aruid); | ||
| 17 | |||
| 18 | if (index >= AruidIndexMax) { | ||
| 19 | return ResultAruidNotRegistered; | ||
| 20 | } | ||
| 21 | |||
| 22 | if (data[index].flag.is_assigned) { | ||
| 23 | return ResultAruidAlreadyRegistered; | ||
| 24 | } | ||
| 25 | |||
| 26 | // TODO: Here shared memory is created for the process we don't quite emulate this part so | ||
| 27 | // obtain this pointer from system | ||
| 28 | auto& shared_memory = system.Kernel().GetHidSharedMem(); | ||
| 29 | |||
| 30 | data[index].shared_memory_handle = &shared_memory; | ||
| 31 | data[index].flag.is_assigned.Assign(true); | ||
| 32 | // TODO: InitializeSixAxisControllerConfig(false); | ||
| 33 | active_aruid = aruid; | ||
| 34 | return ResultSuccess; | ||
| 35 | } | ||
| 36 | |||
| 37 | Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input) { | ||
| 38 | const u64 index = GetIndexFromAruid(aruid); | ||
| 39 | |||
| 40 | if (index < AruidIndexMax) { | ||
| 41 | return ResultAruidAlreadyRegistered; | ||
| 42 | } | ||
| 43 | |||
| 44 | std::size_t data_index = AruidIndexMax; | ||
| 45 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 46 | if (!data[i].flag.is_initialized) { | ||
| 47 | data_index = i; | ||
| 48 | break; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | if (data_index == AruidIndexMax) { | ||
| 53 | return ResultAruidNoAvailableEntries; | ||
| 54 | } | ||
| 55 | |||
| 56 | AruidData& aruid_data = data[data_index]; | ||
| 57 | |||
| 58 | aruid_data.aruid = aruid; | ||
| 59 | aruid_data.flag.is_initialized.Assign(true); | ||
| 60 | if (enable_input) { | ||
| 61 | aruid_data.flag.enable_pad_input.Assign(true); | ||
| 62 | aruid_data.flag.enable_six_axis_sensor.Assign(true); | ||
| 63 | aruid_data.flag.bit_18.Assign(true); | ||
| 64 | aruid_data.flag.enable_touchscreen.Assign(true); | ||
| 65 | } | ||
| 66 | |||
| 67 | data_index = AruidIndexMax; | ||
| 68 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 69 | if (registration_list.flag[i] == RegistrationStatus::Initialized) { | ||
| 70 | if (registration_list.aruid[i] != aruid) { | ||
| 71 | continue; | ||
| 72 | } | ||
| 73 | data_index = i; | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | if (registration_list.flag[i] == RegistrationStatus::None) { | ||
| 77 | data_index = i; | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | if (data_index == AruidIndexMax) { | ||
| 83 | return ResultSuccess; | ||
| 84 | } | ||
| 85 | |||
| 86 | registration_list.flag[data_index] = RegistrationStatus::Initialized; | ||
| 87 | registration_list.aruid[data_index] = aruid; | ||
| 88 | |||
| 89 | return ResultSuccess; | ||
| 90 | } | ||
| 91 | |||
| 92 | void AppletResource::UnregisterAppletResourceUserId(u64 aruid) { | ||
| 93 | u64 index = GetIndexFromAruid(aruid); | ||
| 94 | |||
| 95 | if (index < AruidIndexMax) { | ||
| 96 | if (data[index].flag.is_assigned) { | ||
| 97 | data[index].shared_memory_handle = nullptr; | ||
| 98 | data[index].flag.is_assigned.Assign(false); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | index = GetIndexFromAruid(aruid); | ||
| 103 | if (index < AruidIndexMax) { | ||
| 104 | DestroySevenSixAxisTransferMemory(); | ||
| 105 | data[index].flag.raw = 0; | ||
| 106 | data[index].aruid = 0; | ||
| 107 | |||
| 108 | index = GetIndexFromAruid(aruid); | ||
| 109 | if (index < AruidIndexMax) { | ||
| 110 | registration_list.flag[index] = RegistrationStatus::PendingDelete; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | u64 AppletResource::GetActiveAruid() { | ||
| 116 | return active_aruid; | ||
| 117 | } | ||
| 118 | |||
| 119 | Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { | ||
| 120 | u64 index = GetIndexFromAruid(aruid); | ||
| 121 | if (index >= AruidIndexMax) { | ||
| 122 | return ResultAruidNotRegistered; | ||
| 123 | } | ||
| 124 | |||
| 125 | *out_handle = data[index].shared_memory_handle; | ||
| 126 | return ResultSuccess; | ||
| 127 | } | ||
| 128 | |||
| 129 | u64 AppletResource::GetIndexFromAruid(u64 aruid) { | ||
| 130 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 131 | if (registration_list.flag[i] == RegistrationStatus::Initialized && | ||
| 132 | registration_list.aruid[i] == aruid) { | ||
| 133 | return i; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | return AruidIndexMax; | ||
| 137 | } | ||
| 138 | |||
| 139 | Result AppletResource::DestroySevenSixAxisTransferMemory() { | ||
| 140 | // TODO | ||
| 141 | return ResultSuccess; | ||
| 142 | } | ||
| 143 | |||
| 144 | void AppletResource::EnableInput(u64 aruid, bool is_enabled) { | ||
| 145 | const u64 index = GetIndexFromAruid(aruid); | ||
| 146 | if (index >= AruidIndexMax) { | ||
| 147 | return; | ||
| 148 | } | ||
| 149 | |||
| 150 | data[index].flag.enable_pad_input.Assign(is_enabled); | ||
| 151 | data[index].flag.enable_touchscreen.Assign(is_enabled); | ||
| 152 | } | ||
| 153 | |||
| 154 | void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) { | ||
| 155 | const u64 index = GetIndexFromAruid(aruid); | ||
| 156 | if (index >= AruidIndexMax) { | ||
| 157 | return; | ||
| 158 | } | ||
| 159 | |||
| 160 | data[index].flag.enable_six_axis_sensor.Assign(is_enabled); | ||
| 161 | } | ||
| 162 | |||
| 163 | void AppletResource::EnablePadInput(u64 aruid, bool is_enabled) { | ||
| 164 | const u64 index = GetIndexFromAruid(aruid); | ||
| 165 | if (index >= AruidIndexMax) { | ||
| 166 | return; | ||
| 167 | } | ||
| 168 | |||
| 169 | data[index].flag.enable_pad_input.Assign(is_enabled); | ||
| 170 | } | ||
| 171 | |||
| 172 | void AppletResource::EnableTouchScreen(u64 aruid, bool is_enabled) { | ||
| 173 | const u64 index = GetIndexFromAruid(aruid); | ||
| 174 | if (index >= AruidIndexMax) { | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | |||
| 178 | data[index].flag.enable_touchscreen.Assign(is_enabled); | ||
| 179 | } | ||
| 180 | |||
| 181 | void AppletResource::SetIsPalmaConnectable(u64 aruid, bool is_connectable) { | ||
| 182 | const u64 index = GetIndexFromAruid(aruid); | ||
| 183 | if (index >= AruidIndexMax) { | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | |||
| 187 | data[index].flag.is_palma_connectable.Assign(is_connectable); | ||
| 188 | } | ||
| 189 | |||
| 190 | void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) { | ||
| 191 | const u64 index = GetIndexFromAruid(aruid); | ||
| 192 | if (index >= AruidIndexMax) { | ||
| 193 | return; | ||
| 194 | } | ||
| 195 | |||
| 196 | data[index].flag.enable_palma_boost_mode.Assign(is_enabled); | ||
| 197 | } | ||
| 198 | |||
| 199 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h new file mode 100644 index 000000000..3dcec2898 --- /dev/null +++ b/src/core/hle/service/hid/controllers/applet_resource.h | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | class KSharedMemory; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::HID { | ||
| 21 | class AppletResource { | ||
| 22 | public: | ||
| 23 | explicit AppletResource(Core::System& system_); | ||
| 24 | ~AppletResource(); | ||
| 25 | |||
| 26 | Result CreateAppletResource(u64 aruid); | ||
| 27 | |||
| 28 | Result RegisterAppletResourceUserId(u64 aruid, bool enable_input); | ||
| 29 | void UnregisterAppletResourceUserId(u64 aruid); | ||
| 30 | |||
| 31 | u64 GetActiveAruid(); | ||
| 32 | Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); | ||
| 33 | |||
| 34 | u64 GetIndexFromAruid(u64 aruid); | ||
| 35 | |||
| 36 | Result DestroySevenSixAxisTransferMemory(); | ||
| 37 | |||
| 38 | void EnableInput(u64 aruid, bool is_enabled); | ||
| 39 | void EnableSixAxisSensor(u64 aruid, bool is_enabled); | ||
| 40 | void EnablePadInput(u64 aruid, bool is_enabled); | ||
| 41 | void EnableTouchScreen(u64 aruid, bool is_enabled); | ||
| 42 | void SetIsPalmaConnectable(u64 aruid, bool is_connectable); | ||
| 43 | void EnablePalmaBoostMode(u64 aruid, bool is_enabled); | ||
| 44 | |||
| 45 | private: | ||
| 46 | static constexpr std::size_t AruidIndexMax = 0x20; | ||
| 47 | |||
| 48 | enum RegistrationStatus : u32 { | ||
| 49 | None, | ||
| 50 | Initialized, | ||
| 51 | PendingDelete, | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct DataStatusFlag { | ||
| 55 | union { | ||
| 56 | u32 raw{}; | ||
| 57 | |||
| 58 | BitField<0, 1, u32> is_initialized; | ||
| 59 | BitField<1, 1, u32> is_assigned; | ||
| 60 | BitField<16, 1, u32> enable_pad_input; | ||
| 61 | BitField<17, 1, u32> enable_six_axis_sensor; | ||
| 62 | BitField<18, 1, u32> bit_18; | ||
| 63 | BitField<19, 1, u32> is_palma_connectable; | ||
| 64 | BitField<20, 1, u32> enable_palma_boost_mode; | ||
| 65 | BitField<21, 1, u32> enable_touchscreen; | ||
| 66 | }; | ||
| 67 | }; | ||
| 68 | |||
| 69 | struct AruidRegisterList { | ||
| 70 | std::array<RegistrationStatus, AruidIndexMax> flag{}; | ||
| 71 | std::array<u64, AruidIndexMax> aruid{}; | ||
| 72 | }; | ||
| 73 | static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size"); | ||
| 74 | |||
| 75 | struct AruidData { | ||
| 76 | DataStatusFlag flag{}; | ||
| 77 | u64 aruid{}; | ||
| 78 | Kernel::KSharedMemory* shared_memory_handle{nullptr}; | ||
| 79 | }; | ||
| 80 | |||
| 81 | u64 active_aruid{}; | ||
| 82 | AruidRegisterList registration_list{}; | ||
| 83 | std::array<AruidData, AruidIndexMax> data{}; | ||
| 84 | |||
| 85 | Core::System& system; | ||
| 86 | }; | ||
| 87 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index 9585bdaf0..f00cb831f 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h | |||
| @@ -19,6 +19,11 @@ constexpr Result NpadIsSameType{ErrorModule::HID, 602}; | |||
| 19 | constexpr Result InvalidNpadId{ErrorModule::HID, 709}; | 19 | constexpr Result InvalidNpadId{ErrorModule::HID, 709}; |
| 20 | constexpr Result NpadNotConnected{ErrorModule::HID, 710}; | 20 | constexpr Result NpadNotConnected{ErrorModule::HID, 710}; |
| 21 | constexpr Result InvalidArraySize{ErrorModule::HID, 715}; | 21 | constexpr Result InvalidArraySize{ErrorModule::HID, 715}; |
| 22 | |||
| 23 | constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044}; | ||
| 24 | constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046}; | ||
| 25 | constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047}; | ||
| 26 | |||
| 22 | constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; | 27 | constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; |
| 23 | 28 | ||
| 24 | } // namespace Service::HID | 29 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 1b7381d8d..afbcb019f 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/kernel/k_process.h" | ||
| 5 | #include "core/hle/kernel/kernel.h" | ||
| 4 | #include "core/hle/service/hid/hid.h" | 6 | #include "core/hle/service/hid/hid.h" |
| 5 | #include "core/hle/service/hid/hid_debug_server.h" | 7 | #include "core/hle/service/hid/hid_debug_server.h" |
| 6 | #include "core/hle/service/hid/hid_firmware_settings.h" | 8 | #include "core/hle/service/hid/hid_firmware_settings.h" |
| @@ -20,6 +22,12 @@ void LoopProcess(Core::System& system) { | |||
| 20 | std::shared_ptr<HidFirmwareSettings> firmware_settings = | 22 | std::shared_ptr<HidFirmwareSettings> firmware_settings = |
| 21 | std::make_shared<HidFirmwareSettings>(); | 23 | std::make_shared<HidFirmwareSettings>(); |
| 22 | 24 | ||
| 25 | // TODO: Remove this hack until this service is emulated properly. | ||
| 26 | const auto process_list = system.Kernel().GetProcessList(); | ||
| 27 | if (!process_list.empty()) { | ||
| 28 | resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); | ||
| 29 | } | ||
| 30 | |||
| 23 | server_manager->RegisterNamedService( | 31 | server_manager->RegisterNamedService( |
| 24 | "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); | 32 | "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); |
| 25 | server_manager->RegisterNamedService( | 33 | server_manager->RegisterNamedService( |
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index a7d1578d9..e0f4051aa 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp | |||
| @@ -224,8 +224,13 @@ void IHidServer::CreateAppletResource(HLERequestContext& ctx) { | |||
| 224 | 224 | ||
| 225 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 225 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 226 | 226 | ||
| 227 | Result result = GetResourceManager()->CreateAppletResource(applet_resource_user_id); | ||
| 228 | if (result.IsSuccess()) { | ||
| 229 | result = GetResourceManager()->GetNpad()->Activate(applet_resource_user_id); | ||
| 230 | } | ||
| 231 | |||
| 227 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 232 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 228 | rb.Push(ResultSuccess); | 233 | rb.Push(result); |
| 229 | rb.PushIpcInterface<IAppletResource>(system, resource_manager); | 234 | rb.PushIpcInterface<IAppletResource>(system, resource_manager); |
| 230 | } | 235 | } |
| 231 | 236 | ||
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp index b56d0347a..4d33456a3 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include "core/hid/hid_core.h" | 4 | #include "core/hid/hid_core.h" |
| 5 | #include "core/hle/service/hid/controllers/npad.h" | 5 | #include "core/hle/service/hid/controllers/npad.h" |
| 6 | #include "core/hle/service/hid/controllers/palma.h" | ||
| 6 | #include "core/hle/service/hid/controllers/touchscreen.h" | 7 | #include "core/hle/service/hid/controllers/touchscreen.h" |
| 7 | #include "core/hle/service/hid/errors.h" | 8 | #include "core/hle/service/hid/errors.h" |
| 8 | #include "core/hle/service/hid/hid_system_server.h" | 9 | #include "core/hle/service/hid/hid_system_server.h" |
| @@ -63,13 +64,13 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour | |||
| 63 | {329, nullptr, "DetachAbstractedPadAll"}, | 64 | {329, nullptr, "DetachAbstractedPadAll"}, |
| 64 | {330, nullptr, "CheckAbstractedPadConnection"}, | 65 | {330, nullptr, "CheckAbstractedPadConnection"}, |
| 65 | {500, nullptr, "SetAppletResourceUserId"}, | 66 | {500, nullptr, "SetAppletResourceUserId"}, |
| 66 | {501, nullptr, "RegisterAppletResourceUserId"}, | 67 | {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"}, |
| 67 | {502, nullptr, "UnregisterAppletResourceUserId"}, | 68 | {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"}, |
| 68 | {503, nullptr, "EnableAppletToGetInput"}, | 69 | {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"}, |
| 69 | {504, nullptr, "SetAruidValidForVibration"}, | 70 | {504, nullptr, "SetAruidValidForVibration"}, |
| 70 | {505, nullptr, "EnableAppletToGetSixAxisSensor"}, | 71 | {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"}, |
| 71 | {506, nullptr, "EnableAppletToGetPadInput"}, | 72 | {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"}, |
| 72 | {507, nullptr, "EnableAppletToGetTouchScreen"}, | 73 | {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"}, |
| 73 | {510, nullptr, "SetVibrationMasterVolume"}, | 74 | {510, nullptr, "SetVibrationMasterVolume"}, |
| 74 | {511, nullptr, "GetVibrationMasterVolume"}, | 75 | {511, nullptr, "GetVibrationMasterVolume"}, |
| 75 | {512, nullptr, "BeginPermitVibrationSession"}, | 76 | {512, nullptr, "BeginPermitVibrationSession"}, |
| @@ -420,6 +421,129 @@ void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) { | |||
| 420 | IPC::ResponseBuilder rb{ctx, 2}; | 421 | IPC::ResponseBuilder rb{ctx, 2}; |
| 421 | rb.Push(ResultSuccess); | 422 | rb.Push(ResultSuccess); |
| 422 | } | 423 | } |
| 424 | void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) { | ||
| 425 | IPC::RequestParser rp{ctx}; | ||
| 426 | struct Parameters { | ||
| 427 | bool enable_input; | ||
| 428 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 429 | u64 applet_resource_user_id; | ||
| 430 | }; | ||
| 431 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 432 | |||
| 433 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 434 | |||
| 435 | LOG_INFO(Service_HID, "called, enable_input={}, applet_resource_user_id={}", | ||
| 436 | parameters.enable_input, parameters.applet_resource_user_id); | ||
| 437 | |||
| 438 | Result result = GetResourceManager()->RegisterAppletResourceUserId( | ||
| 439 | parameters.applet_resource_user_id, parameters.enable_input); | ||
| 440 | |||
| 441 | if (result.IsSuccess()) { | ||
| 442 | // result = GetResourceManager()->GetNpad()->RegisterAppletResourceUserId( | ||
| 443 | // parameters.applet_resource_user_id); | ||
| 444 | } | ||
| 445 | |||
| 446 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 447 | rb.Push(ResultSuccess); | ||
| 448 | } | ||
| 449 | |||
| 450 | void IHidSystemServer::UnregisterAppletResourceUserId(HLERequestContext& ctx) { | ||
| 451 | IPC::RequestParser rp{ctx}; | ||
| 452 | u64 applet_resource_user_id{rp.Pop<u64>()}; | ||
| 453 | |||
| 454 | LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 455 | |||
| 456 | GetResourceManager()->UnregisterAppletResourceUserId(applet_resource_user_id); | ||
| 457 | // GetResourceManager()->GetNpad()->UnregisterAppletResourceUserId(applet_resource_user_id); | ||
| 458 | // GetResourceManager()->GetPalma()->UnregisterAppletResourceUserId(applet_resource_user_id); | ||
| 459 | |||
| 460 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 461 | rb.Push(ResultSuccess); | ||
| 462 | } | ||
| 463 | |||
| 464 | void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) { | ||
| 465 | IPC::RequestParser rp{ctx}; | ||
| 466 | struct Parameters { | ||
| 467 | bool is_enabled; | ||
| 468 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 469 | u64 applet_resource_user_id; | ||
| 470 | }; | ||
| 471 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 472 | |||
| 473 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 474 | |||
| 475 | LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", | ||
| 476 | parameters.is_enabled, parameters.applet_resource_user_id); | ||
| 477 | |||
| 478 | GetResourceManager()->EnableInput(parameters.applet_resource_user_id, parameters.is_enabled); | ||
| 479 | // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id); | ||
| 480 | |||
| 481 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 482 | rb.Push(ResultSuccess); | ||
| 483 | } | ||
| 484 | |||
| 485 | void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) { | ||
| 486 | IPC::RequestParser rp{ctx}; | ||
| 487 | struct Parameters { | ||
| 488 | bool is_enabled; | ||
| 489 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 490 | u64 applet_resource_user_id; | ||
| 491 | }; | ||
| 492 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 493 | |||
| 494 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 495 | |||
| 496 | LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", | ||
| 497 | parameters.is_enabled, parameters.applet_resource_user_id); | ||
| 498 | |||
| 499 | GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id, | ||
| 500 | parameters.is_enabled); | ||
| 501 | |||
| 502 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 503 | rb.Push(ResultSuccess); | ||
| 504 | } | ||
| 505 | |||
| 506 | void IHidSystemServer::EnableAppletToGetPadInput(HLERequestContext& ctx) { | ||
| 507 | IPC::RequestParser rp{ctx}; | ||
| 508 | struct Parameters { | ||
| 509 | bool is_enabled; | ||
| 510 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 511 | u64 applet_resource_user_id; | ||
| 512 | }; | ||
| 513 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 514 | |||
| 515 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 516 | |||
| 517 | LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", | ||
| 518 | parameters.is_enabled, parameters.applet_resource_user_id); | ||
| 519 | |||
| 520 | GetResourceManager()->EnablePadInput(parameters.applet_resource_user_id, parameters.is_enabled); | ||
| 521 | // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id); | ||
| 522 | |||
| 523 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 524 | rb.Push(ResultSuccess); | ||
| 525 | } | ||
| 526 | |||
| 527 | void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) { | ||
| 528 | IPC::RequestParser rp{ctx}; | ||
| 529 | struct Parameters { | ||
| 530 | bool is_enabled; | ||
| 531 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 532 | u64 applet_resource_user_id; | ||
| 533 | }; | ||
| 534 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 535 | |||
| 536 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 537 | |||
| 538 | LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", | ||
| 539 | parameters.is_enabled, parameters.applet_resource_user_id); | ||
| 540 | |||
| 541 | GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id, | ||
| 542 | parameters.is_enabled); | ||
| 543 | |||
| 544 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 545 | rb.Push(ResultSuccess); | ||
| 546 | } | ||
| 423 | 547 | ||
| 424 | void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { | 548 | void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { |
| 425 | LOG_INFO(Service_AM, "(STUBBED) called"); | 549 | LOG_INFO(Service_AM, "(STUBBED) called"); |
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h index 822d5e5b9..1e623dfc2 100644 --- a/src/core/hle/service/hid/hid_system_server.h +++ b/src/core/hle/service/hid/hid_system_server.h | |||
| @@ -38,6 +38,12 @@ private: | |||
| 38 | void HasLeftRightBattery(HLERequestContext& ctx); | 38 | void HasLeftRightBattery(HLERequestContext& ctx); |
| 39 | void GetUniquePadsFromNpad(HLERequestContext& ctx); | 39 | void GetUniquePadsFromNpad(HLERequestContext& ctx); |
| 40 | void GetIrSensorState(HLERequestContext& ctx); | 40 | void GetIrSensorState(HLERequestContext& ctx); |
| 41 | void RegisterAppletResourceUserId(HLERequestContext& ctx); | ||
| 42 | void UnregisterAppletResourceUserId(HLERequestContext& ctx); | ||
| 43 | void EnableAppletToGetInput(HLERequestContext& ctx); | ||
| 44 | void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); | ||
| 45 | void EnableAppletToGetPadInput(HLERequestContext& ctx); | ||
| 46 | void EnableAppletToGetTouchScreen(HLERequestContext& ctx); | ||
| 41 | void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); | 47 | void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); |
| 42 | void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); | 48 | void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); |
| 43 | void GetRegisteredDevices(HLERequestContext& ctx); | 49 | void GetRegisteredDevices(HLERequestContext& ctx); |
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp index e76d4eea9..60d4ef71f 100644 --- a/src/core/hle/service/hid/resource_manager.cpp +++ b/src/core/hle/service/hid/resource_manager.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/hle/service/hid/resource_manager.h" | 9 | #include "core/hle/service/hid/resource_manager.h" |
| 10 | #include "core/hle/service/ipc_helpers.h" | 10 | #include "core/hle/service/ipc_helpers.h" |
| 11 | 11 | ||
| 12 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 12 | #include "core/hle/service/hid/controllers/console_six_axis.h" | 13 | #include "core/hle/service/hid/controllers/console_six_axis.h" |
| 13 | #include "core/hle/service/hid/controllers/debug_pad.h" | 14 | #include "core/hle/service/hid/controllers/debug_pad.h" |
| 14 | #include "core/hle/service/hid/controllers/gesture.h" | 15 | #include "core/hle/service/hid/controllers/gesture.h" |
| @@ -33,7 +34,9 @@ constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 10 | |||
| 33 | constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) | 34 | constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) |
| 34 | 35 | ||
| 35 | ResourceManager::ResourceManager(Core::System& system_) | 36 | ResourceManager::ResourceManager(Core::System& system_) |
| 36 | : system{system_}, service_context{system_, "hid"} {} | 37 | : system{system_}, service_context{system_, "hid"} { |
| 38 | applet_resource = std::make_shared<AppletResource>(system); | ||
| 39 | } | ||
| 37 | 40 | ||
| 38 | ResourceManager::~ResourceManager() = default; | 41 | ResourceManager::~ResourceManager() = default; |
| 39 | 42 | ||
| @@ -77,6 +80,11 @@ void ResourceManager::Initialize() { | |||
| 77 | system.HIDCore().ReloadInputDevices(); | 80 | system.HIDCore().ReloadInputDevices(); |
| 78 | is_initialized = true; | 81 | is_initialized = true; |
| 79 | } | 82 | } |
| 83 | |||
| 84 | std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const { | ||
| 85 | return applet_resource; | ||
| 86 | } | ||
| 87 | |||
| 80 | std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const { | 88 | std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const { |
| 81 | return capture_button; | 89 | return capture_button; |
| 82 | } | 90 | } |
| @@ -137,6 +145,46 @@ std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const { | |||
| 137 | return unique_pad; | 145 | return unique_pad; |
| 138 | } | 146 | } |
| 139 | 147 | ||
| 148 | Result ResourceManager::CreateAppletResource(u64 aruid) { | ||
| 149 | std::scoped_lock lock{shared_mutex}; | ||
| 150 | return applet_resource->CreateAppletResource(aruid); | ||
| 151 | } | ||
| 152 | |||
| 153 | Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) { | ||
| 154 | std::scoped_lock lock{shared_mutex}; | ||
| 155 | return applet_resource->RegisterAppletResourceUserId(aruid, bool_value); | ||
| 156 | } | ||
| 157 | |||
| 158 | void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { | ||
| 159 | std::scoped_lock lock{shared_mutex}; | ||
| 160 | applet_resource->UnregisterAppletResourceUserId(aruid); | ||
| 161 | } | ||
| 162 | |||
| 163 | Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { | ||
| 164 | std::scoped_lock lock{shared_mutex}; | ||
| 165 | return applet_resource->GetSharedMemoryHandle(out_handle, aruid); | ||
| 166 | } | ||
| 167 | |||
| 168 | void ResourceManager::EnableInput(u64 aruid, bool is_enabled) { | ||
| 169 | std::scoped_lock lock{shared_mutex}; | ||
| 170 | applet_resource->EnableInput(aruid, is_enabled); | ||
| 171 | } | ||
| 172 | |||
| 173 | void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) { | ||
| 174 | std::scoped_lock lock{shared_mutex}; | ||
| 175 | applet_resource->EnableSixAxisSensor(aruid, is_enabled); | ||
| 176 | } | ||
| 177 | |||
| 178 | void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) { | ||
| 179 | std::scoped_lock lock{shared_mutex}; | ||
| 180 | applet_resource->EnablePadInput(aruid, is_enabled); | ||
| 181 | } | ||
| 182 | |||
| 183 | void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { | ||
| 184 | std::scoped_lock lock{shared_mutex}; | ||
| 185 | applet_resource->EnableTouchScreen(aruid, is_enabled); | ||
| 186 | } | ||
| 187 | |||
| 140 | void ResourceManager::UpdateControllers(std::uintptr_t user_data, | 188 | void ResourceManager::UpdateControllers(std::uintptr_t user_data, |
| 141 | std::chrono::nanoseconds ns_late) { | 189 | std::chrono::nanoseconds ns_late) { |
| 142 | auto& core_timing = system.CoreTiming(); | 190 | auto& core_timing = system.CoreTiming(); |
| @@ -172,14 +220,12 @@ void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose | |||
| 172 | } | 220 | } |
| 173 | 221 | ||
| 174 | IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource) | 222 | IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource) |
| 175 | : ServiceFramework{system_, "IAppletResource"} { | 223 | : ServiceFramework{system_, "IAppletResource"}, resource_manager{resource} { |
| 176 | static const FunctionInfo functions[] = { | 224 | static const FunctionInfo functions[] = { |
| 177 | {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, | 225 | {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, |
| 178 | }; | 226 | }; |
| 179 | RegisterHandlers(functions); | 227 | RegisterHandlers(functions); |
| 180 | 228 | ||
| 181 | resource->Initialize(); | ||
| 182 | |||
| 183 | // Register update callbacks | 229 | // Register update callbacks |
| 184 | npad_update_event = Core::Timing::CreateEvent( | 230 | npad_update_event = Core::Timing::CreateEvent( |
| 185 | "HID::UpdatePadCallback", | 231 | "HID::UpdatePadCallback", |
| @@ -233,9 +279,13 @@ IAppletResource::~IAppletResource() { | |||
| 233 | void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) { | 279 | void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) { |
| 234 | LOG_DEBUG(Service_HID, "called"); | 280 | LOG_DEBUG(Service_HID, "called"); |
| 235 | 281 | ||
| 282 | Kernel::KSharedMemory* handle; | ||
| 283 | const u64 applet_resource_user_id = resource_manager->GetAppletResource()->GetActiveAruid(); | ||
| 284 | const auto result = resource_manager->GetSharedMemoryHandle(&handle, applet_resource_user_id); | ||
| 285 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 286 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 237 | rb.Push(ResultSuccess); | 287 | rb.Push(result); |
| 238 | rb.PushCopyObjects(&system.Kernel().GetHidSharedMem()); | 288 | rb.PushCopyObjects(handle); |
| 239 | } | 289 | } |
| 240 | 290 | ||
| 241 | } // namespace Service::HID | 291 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h index 2b6a9b5e6..a78e2b729 100644 --- a/src/core/hle/service/hid/resource_manager.h +++ b/src/core/hle/service/hid/resource_manager.h | |||
| @@ -6,11 +6,20 @@ | |||
| 6 | #include "core/hle/service/kernel_helpers.h" | 6 | #include "core/hle/service/kernel_helpers.h" |
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Core::Timing { | 13 | namespace Core::Timing { |
| 10 | struct EventType; | 14 | struct EventType; |
| 11 | } | 15 | } |
| 12 | 16 | ||
| 17 | namespace Kernel { | ||
| 18 | class KSharedMemory; | ||
| 19 | } | ||
| 20 | |||
| 13 | namespace Service::HID { | 21 | namespace Service::HID { |
| 22 | class AppletResource; | ||
| 14 | class Controller_Stubbed; | 23 | class Controller_Stubbed; |
| 15 | class ConsoleSixAxis; | 24 | class ConsoleSixAxis; |
| 16 | class DebugPad; | 25 | class DebugPad; |
| @@ -38,6 +47,7 @@ public: | |||
| 38 | 47 | ||
| 39 | void Initialize(); | 48 | void Initialize(); |
| 40 | 49 | ||
| 50 | std::shared_ptr<AppletResource> GetAppletResource() const; | ||
| 41 | std::shared_ptr<CaptureButton> GetCaptureButton() const; | 51 | std::shared_ptr<CaptureButton> GetCaptureButton() const; |
| 42 | std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const; | 52 | std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const; |
| 43 | std::shared_ptr<DebugMouse> GetDebugMouse() const; | 53 | std::shared_ptr<DebugMouse> GetDebugMouse() const; |
| @@ -54,6 +64,18 @@ public: | |||
| 54 | std::shared_ptr<TouchScreen> GetTouchScreen() const; | 64 | std::shared_ptr<TouchScreen> GetTouchScreen() const; |
| 55 | std::shared_ptr<UniquePad> GetUniquePad() const; | 65 | std::shared_ptr<UniquePad> GetUniquePad() const; |
| 56 | 66 | ||
| 67 | Result CreateAppletResource(u64 aruid); | ||
| 68 | |||
| 69 | Result RegisterAppletResourceUserId(u64 aruid, bool bool_value); | ||
| 70 | void UnregisterAppletResourceUserId(u64 aruid); | ||
| 71 | |||
| 72 | Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); | ||
| 73 | |||
| 74 | void EnableInput(u64 aruid, bool is_enabled); | ||
| 75 | void EnableSixAxisSensor(u64 aruid, bool is_enabled); | ||
| 76 | void EnablePadInput(u64 aruid, bool is_enabled); | ||
| 77 | void EnableTouchScreen(u64 aruid, bool is_enabled); | ||
| 78 | |||
| 57 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 79 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 58 | void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 80 | void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 59 | void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 81 | void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| @@ -62,6 +84,9 @@ public: | |||
| 62 | private: | 84 | private: |
| 63 | bool is_initialized{false}; | 85 | bool is_initialized{false}; |
| 64 | 86 | ||
| 87 | mutable std::mutex shared_mutex; | ||
| 88 | std::shared_ptr<AppletResource> applet_resource = nullptr; | ||
| 89 | |||
| 65 | std::shared_ptr<CaptureButton> capture_button = nullptr; | 90 | std::shared_ptr<CaptureButton> capture_button = nullptr; |
| 66 | std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; | 91 | std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; |
| 67 | std::shared_ptr<DebugMouse> debug_mouse = nullptr; | 92 | std::shared_ptr<DebugMouse> debug_mouse = nullptr; |
| @@ -106,6 +131,8 @@ private: | |||
| 106 | std::shared_ptr<Core::Timing::EventType> default_update_event; | 131 | std::shared_ptr<Core::Timing::EventType> default_update_event; |
| 107 | std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; | 132 | std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; |
| 108 | std::shared_ptr<Core::Timing::EventType> motion_update_event; | 133 | std::shared_ptr<Core::Timing::EventType> motion_update_event; |
| 134 | |||
| 135 | std::shared_ptr<ResourceManager> resource_manager; | ||
| 109 | }; | 136 | }; |
| 110 | 137 | ||
| 111 | } // namespace Service::HID | 138 | } // namespace Service::HID |
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index d7db24f42..75bf31e32 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp | |||
| @@ -171,6 +171,7 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han | |||
| 171 | buffer->height = SharedBufferHeight; | 171 | buffer->height = SharedBufferHeight; |
| 172 | buffer->stride = SharedBufferBlockLinearStride; | 172 | buffer->stride = SharedBufferBlockLinearStride; |
| 173 | buffer->format = SharedBufferBlockLinearFormat; | 173 | buffer->format = SharedBufferBlockLinearFormat; |
| 174 | buffer->external_format = SharedBufferBlockLinearFormat; | ||
| 174 | buffer->buffer_id = handle; | 175 | buffer->buffer_id = handle; |
| 175 | buffer->offset = slot * SharedBufferSlotSize; | 176 | buffer->offset = slot * SharedBufferSlotSize; |
| 176 | ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError); | 177 | ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError); |
diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp index dcd07e6d2..96686da59 100644 --- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp +++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp | |||
| @@ -233,7 +233,12 @@ std::unique_ptr<Frame> DecoderContext::ReceiveFrame(bool* out_is_interlaced) { | |||
| 233 | return false; | 233 | return false; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | *out_is_interlaced = frame->interlaced_frame != 0; | 236 | *out_is_interlaced = |
| 237 | #if defined(FF_API_INTERLACED_FRAME) || LIBAVUTIL_VERSION_MAJOR >= 59 | ||
| 238 | (frame->flags & AV_FRAME_FLAG_INTERLACED) != 0; | ||
| 239 | #else | ||
| 240 | frame->interlaced_frame != 0; | ||
| 241 | #endif | ||
| 237 | return true; | 242 | return true; |
| 238 | }; | 243 | }; |
| 239 | 244 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 9995b6dd4..279e5a4e0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -714,7 +714,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 714 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); | 714 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); |
| 715 | 715 | ||
| 716 | std::scoped_lock lock{texture_cache.mutex}; | 716 | std::scoped_lock lock{texture_cache.mutex}; |
| 717 | ImageView* const image_view{texture_cache.TryFindFramebufferImageView(framebuffer_addr)}; | 717 | ImageView* const image_view{ |
| 718 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr)}; | ||
| 718 | if (!image_view) { | 719 | if (!image_view) { |
| 719 | return false; | 720 | return false; |
| 720 | } | 721 | } |
| @@ -725,7 +726,6 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 725 | screen_info.texture.width = image_view->size.width; | 726 | screen_info.texture.width = image_view->size.width; |
| 726 | screen_info.texture.height = image_view->size.height; | 727 | screen_info.texture.height = image_view->size.height; |
| 727 | screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); | 728 | screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); |
| 728 | screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); | ||
| 729 | return true; | 729 | return true; |
| 730 | } | 730 | } |
| 731 | 731 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 6bfed08a1..7a4f0c5c1 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -653,11 +653,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 653 | }; | 653 | }; |
| 654 | glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); | 654 | glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); |
| 655 | 655 | ||
| 656 | if (screen_info.display_srgb) { | 656 | glDisable(GL_FRAMEBUFFER_SRGB); |
| 657 | glEnable(GL_FRAMEBUFFER_SRGB); | ||
| 658 | } else { | ||
| 659 | glDisable(GL_FRAMEBUFFER_SRGB); | ||
| 660 | } | ||
| 661 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), | 657 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), |
| 662 | static_cast<GLfloat>(layout.height)); | 658 | static_cast<GLfloat>(layout.height)); |
| 663 | 659 | ||
| @@ -710,8 +706,7 @@ void RendererOpenGL::RenderScreenshot() { | |||
| 710 | GLuint renderbuffer; | 706 | GLuint renderbuffer; |
| 711 | glGenRenderbuffers(1, &renderbuffer); | 707 | glGenRenderbuffers(1, &renderbuffer); |
| 712 | glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); | 708 | glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
| 713 | glRenderbufferStorage(GL_RENDERBUFFER, screen_info.display_srgb ? GL_SRGB8 : GL_RGB8, | 709 | glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); |
| 714 | layout.width, layout.height); | ||
| 715 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); | 710 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); |
| 716 | 711 | ||
| 717 | DrawScreen(layout); | 712 | DrawScreen(layout); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index f1d5fd954..b70607635 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -53,7 +53,6 @@ struct TextureInfo { | |||
| 53 | struct ScreenInfo { | 53 | struct ScreenInfo { |
| 54 | GLuint display_texture{}; | 54 | GLuint display_texture{}; |
| 55 | bool was_accelerated = false; | 55 | bool was_accelerated = false; |
| 56 | bool display_srgb{}; | ||
| 57 | const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; | 56 | const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; |
| 58 | TextureInfo texture; | 57 | TextureInfo texture; |
| 59 | }; | 58 | }; |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index c4c30d807..100b70918 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -94,7 +94,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | |||
| 94 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), | 94 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), |
| 95 | scheduler(device, state_tracker), | 95 | scheduler(device, state_tracker), |
| 96 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, | 96 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, |
| 97 | render_window.GetFramebufferLayout().height, false), | 97 | render_window.GetFramebufferLayout().height), |
| 98 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, | 98 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, |
| 99 | surface), | 99 | surface), |
| 100 | blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager, | 100 | blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager, |
| @@ -131,11 +131,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 131 | const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; | 131 | const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; |
| 132 | const bool use_accelerated = | 132 | const bool use_accelerated = |
| 133 | rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); | 133 | rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); |
| 134 | const bool is_srgb = use_accelerated && screen_info.is_srgb; | ||
| 135 | RenderScreenshot(*framebuffer, use_accelerated); | 134 | RenderScreenshot(*framebuffer, use_accelerated); |
| 136 | 135 | ||
| 137 | Frame* frame = present_manager.GetRenderFrame(); | 136 | Frame* frame = present_manager.GetRenderFrame(); |
| 138 | blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb); | 137 | blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated); |
| 139 | scheduler.Flush(*frame->render_ready); | 138 | scheduler.Flush(*frame->render_ready); |
| 140 | present_manager.Present(frame); | 139 | present_manager.Present(frame); |
| 141 | 140 | ||
| @@ -205,7 +204,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 205 | .flags = 0, | 204 | .flags = 0, |
| 206 | .image = *staging_image, | 205 | .image = *staging_image, |
| 207 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | 206 | .viewType = VK_IMAGE_VIEW_TYPE_2D, |
| 208 | .format = screen_info.is_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM, | 207 | .format = VK_FORMAT_B8G8R8A8_UNORM, |
| 209 | .components{ | 208 | .components{ |
| 210 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | 209 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, |
| 211 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | 210 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 5e461fbd0..60432f5ad 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -127,9 +127,9 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin | |||
| 127 | Scheduler& scheduler_, const ScreenInfo& screen_info_) | 127 | Scheduler& scheduler_, const ScreenInfo& screen_info_) |
| 128 | : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, | 128 | : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, |
| 129 | memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, | 129 | memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, |
| 130 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_}, | 130 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { |
| 131 | current_srgb{swapchain.IsSrgb()}, image_view_format{swapchain.GetImageViewFormat()} { | ||
| 132 | resource_ticks.resize(image_count); | 131 | resource_ticks.resize(image_count); |
| 132 | swapchain_view_format = swapchain.GetImageViewFormat(); | ||
| 133 | 133 | ||
| 134 | CreateStaticResources(); | 134 | CreateStaticResources(); |
| 135 | CreateDynamicResources(); | 135 | CreateDynamicResources(); |
| @@ -480,28 +480,22 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 480 | } | 480 | } |
| 481 | 481 | ||
| 482 | void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | 482 | void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, |
| 483 | bool use_accelerated, bool is_srgb) { | 483 | bool use_accelerated) { |
| 484 | // Recreate dynamic resources if the the image count or colorspace changed | 484 | // Recreate dynamic resources if the the image count or input format changed |
| 485 | const VkFormat current_framebuffer_format = | ||
| 486 | std::exchange(framebuffer_view_format, GetFormat(framebuffer)); | ||
| 485 | if (const std::size_t swapchain_images = swapchain.GetImageCount(); | 487 | if (const std::size_t swapchain_images = swapchain.GetImageCount(); |
| 486 | swapchain_images != image_count || current_srgb != is_srgb) { | 488 | swapchain_images != image_count || current_framebuffer_format != framebuffer_view_format) { |
| 487 | current_srgb = is_srgb; | ||
| 488 | #ifdef ANDROID | ||
| 489 | // Android is already ordered the same as Switch. | ||
| 490 | image_view_format = current_srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; | ||
| 491 | #else | ||
| 492 | image_view_format = current_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; | ||
| 493 | #endif | ||
| 494 | image_count = swapchain_images; | 489 | image_count = swapchain_images; |
| 495 | Recreate(); | 490 | Recreate(); |
| 496 | } | 491 | } |
| 497 | 492 | ||
| 498 | // Recreate the presentation frame if the dimensions of the window changed | 493 | // Recreate the presentation frame if the dimensions of the window changed |
| 499 | const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); | 494 | const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); |
| 500 | if (layout.width != frame->width || layout.height != frame->height || | 495 | if (layout.width != frame->width || layout.height != frame->height) { |
| 501 | is_srgb != frame->is_srgb) { | ||
| 502 | Recreate(); | 496 | Recreate(); |
| 503 | present_manager.RecreateFrame(frame, layout.width, layout.height, is_srgb, | 497 | present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, |
| 504 | image_view_format, *renderpass); | 498 | *renderpass); |
| 505 | } | 499 | } |
| 506 | 500 | ||
| 507 | const VkExtent2D render_area{frame->width, frame->height}; | 501 | const VkExtent2D render_area{frame->width, frame->height}; |
| @@ -629,7 +623,7 @@ void BlitScreen::CreateDescriptorPool() { | |||
| 629 | } | 623 | } |
| 630 | 624 | ||
| 631 | void BlitScreen::CreateRenderPass() { | 625 | void BlitScreen::CreateRenderPass() { |
| 632 | renderpass = CreateRenderPassImpl(image_view_format); | 626 | renderpass = CreateRenderPassImpl(swapchain_view_format); |
| 633 | } | 627 | } |
| 634 | 628 | ||
| 635 | vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) { | 629 | vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) { |
| @@ -1149,7 +1143,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1149 | .pNext = nullptr, | 1143 | .pNext = nullptr, |
| 1150 | .flags = 0, | 1144 | .flags = 0, |
| 1151 | .imageType = VK_IMAGE_TYPE_2D, | 1145 | .imageType = VK_IMAGE_TYPE_2D, |
| 1152 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), | 1146 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, |
| 1153 | .extent = | 1147 | .extent = |
| 1154 | { | 1148 | { |
| 1155 | .width = (up_scale * framebuffer.width) >> down_shift, | 1149 | .width = (up_scale * framebuffer.width) >> down_shift, |
| @@ -1174,7 +1168,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1174 | .flags = 0, | 1168 | .flags = 0, |
| 1175 | .image = *image, | 1169 | .image = *image, |
| 1176 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | 1170 | .viewType = VK_IMAGE_VIEW_TYPE_2D, |
| 1177 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), | 1171 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, |
| 1178 | .components = | 1172 | .components = |
| 1179 | { | 1173 | { |
| 1180 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | 1174 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 8365b5668..16b882b6d 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -52,7 +52,6 @@ struct ScreenInfo { | |||
| 52 | VkImageView image_view{}; | 52 | VkImageView image_view{}; |
| 53 | u32 width{}; | 53 | u32 width{}; |
| 54 | u32 height{}; | 54 | u32 height{}; |
| 55 | bool is_srgb{}; | ||
| 56 | }; | 55 | }; |
| 57 | 56 | ||
| 58 | class BlitScreen { | 57 | class BlitScreen { |
| @@ -69,7 +68,7 @@ public: | |||
| 69 | const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated); | 68 | const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated); |
| 70 | 69 | ||
| 71 | void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | 70 | void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, |
| 72 | bool use_accelerated, bool is_srgb); | 71 | bool use_accelerated); |
| 73 | 72 | ||
| 74 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | 73 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, |
| 75 | VkExtent2D extent); | 74 | VkExtent2D extent); |
| @@ -161,8 +160,8 @@ private: | |||
| 161 | u32 raw_width = 0; | 160 | u32 raw_width = 0; |
| 162 | u32 raw_height = 0; | 161 | u32 raw_height = 0; |
| 163 | Service::android::PixelFormat pixel_format{}; | 162 | Service::android::PixelFormat pixel_format{}; |
| 164 | bool current_srgb; | 163 | VkFormat framebuffer_view_format; |
| 165 | VkFormat image_view_format; | 164 | VkFormat swapchain_view_format; |
| 166 | 165 | ||
| 167 | std::unique_ptr<FSR> fsr; | 166 | std::unique_ptr<FSR> fsr; |
| 168 | std::unique_ptr<SMAA> smaa; | 167 | std::unique_ptr<SMAA> smaa; |
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 2ef36583b..8e4c74b5c 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp | |||
| @@ -172,13 +172,12 @@ void PresentManager::Present(Frame* frame) { | |||
| 172 | }); | 172 | }); |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, | 175 | void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, |
| 176 | VkFormat image_view_format, VkRenderPass rd) { | 176 | VkRenderPass rd) { |
| 177 | auto& dld = device.GetLogical(); | 177 | auto& dld = device.GetLogical(); |
| 178 | 178 | ||
| 179 | frame->width = width; | 179 | frame->width = width; |
| 180 | frame->height = height; | 180 | frame->height = height; |
| 181 | frame->is_srgb = is_srgb; | ||
| 182 | 181 | ||
| 183 | frame->image = memory_allocator.CreateImage({ | 182 | frame->image = memory_allocator.CreateImage({ |
| 184 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 183 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| @@ -289,7 +288,7 @@ void PresentManager::PresentThread(std::stop_token token) { | |||
| 289 | } | 288 | } |
| 290 | 289 | ||
| 291 | void PresentManager::RecreateSwapchain(Frame* frame) { | 290 | void PresentManager::RecreateSwapchain(Frame* frame) { |
| 292 | swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb); | 291 | swapchain.Create(*surface, frame->width, frame->height); |
| 293 | image_count = swapchain.GetImageCount(); | 292 | image_count = swapchain.GetImageCount(); |
| 294 | } | 293 | } |
| 295 | 294 | ||
| @@ -319,12 +318,12 @@ void PresentManager::CopyToSwapchain(Frame* frame) { | |||
| 319 | void PresentManager::CopyToSwapchainImpl(Frame* frame) { | 318 | void PresentManager::CopyToSwapchainImpl(Frame* frame) { |
| 320 | MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); | 319 | MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); |
| 321 | 320 | ||
| 322 | // If the size or colorspace of the incoming frames has changed, recreate the swapchain | 321 | // If the size of the incoming frames has changed, recreate the swapchain |
| 323 | // to account for that. | 322 | // to account for that. |
| 324 | const bool srgb_changed = swapchain.NeedsRecreation(frame->is_srgb); | 323 | const bool is_suboptimal = swapchain.NeedsRecreation(); |
| 325 | const bool size_changed = | 324 | const bool size_changed = |
| 326 | swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; | 325 | swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; |
| 327 | if (srgb_changed || size_changed) { | 326 | if (is_suboptimal || size_changed) { |
| 328 | RecreateSwapchain(frame); | 327 | RecreateSwapchain(frame); |
| 329 | } | 328 | } |
| 330 | 329 | ||
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index a3d825fe6..337171a09 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h | |||
| @@ -25,7 +25,6 @@ class Swapchain; | |||
| 25 | struct Frame { | 25 | struct Frame { |
| 26 | u32 width; | 26 | u32 width; |
| 27 | u32 height; | 27 | u32 height; |
| 28 | bool is_srgb; | ||
| 29 | vk::Image image; | 28 | vk::Image image; |
| 30 | vk::ImageView image_view; | 29 | vk::ImageView image_view; |
| 31 | vk::Framebuffer framebuffer; | 30 | vk::Framebuffer framebuffer; |
| @@ -48,8 +47,8 @@ public: | |||
| 48 | void Present(Frame* frame); | 47 | void Present(Frame* frame); |
| 49 | 48 | ||
| 50 | /// Recreates the present frame to match the provided parameters | 49 | /// Recreates the present frame to match the provided parameters |
| 51 | void RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, | 50 | void RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, |
| 52 | VkFormat image_view_format, VkRenderPass rd); | 51 | VkRenderPass rd); |
| 53 | 52 | ||
| 54 | /// Waits for the present thread to finish presenting all queued frames. | 53 | /// Waits for the present thread to finish presenting all queued frames. |
| 55 | void WaitPresent(); | 54 | void WaitPresent(); |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index b6f52e017..59829c88b 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -783,7 +783,8 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 783 | return false; | 783 | return false; |
| 784 | } | 784 | } |
| 785 | std::scoped_lock lock{texture_cache.mutex}; | 785 | std::scoped_lock lock{texture_cache.mutex}; |
| 786 | ImageView* const image_view = texture_cache.TryFindFramebufferImageView(framebuffer_addr); | 786 | ImageView* const image_view = |
| 787 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); | ||
| 787 | if (!image_view) { | 788 | if (!image_view) { |
| 788 | return false; | 789 | return false; |
| 789 | } | 790 | } |
| @@ -792,7 +793,6 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 792 | screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D); | 793 | screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D); |
| 793 | screen_info.width = image_view->size.width; | 794 | screen_info.width = image_view->size.width; |
| 794 | screen_info.height = image_view->size.height; | 795 | screen_info.height = image_view->size.height; |
| 795 | screen_info.is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); | ||
| 796 | return true; | 796 | return true; |
| 797 | } | 797 | } |
| 798 | 798 | ||
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 821f44f1a..86a30dcd1 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp | |||
| @@ -105,14 +105,14 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap | |||
| 105 | } // Anonymous namespace | 105 | } // Anonymous namespace |
| 106 | 106 | ||
| 107 | Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, | 107 | Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, |
| 108 | u32 width_, u32 height_, bool srgb) | 108 | u32 width_, u32 height_) |
| 109 | : surface{surface_}, device{device_}, scheduler{scheduler_} { | 109 | : surface{surface_}, device{device_}, scheduler{scheduler_} { |
| 110 | Create(surface_, width_, height_, srgb); | 110 | Create(surface_, width_, height_); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | Swapchain::~Swapchain() = default; | 113 | Swapchain::~Swapchain() = default; |
| 114 | 114 | ||
| 115 | void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_, bool srgb) { | 115 | void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_) { |
| 116 | is_outdated = false; | 116 | is_outdated = false; |
| 117 | is_suboptimal = false; | 117 | is_suboptimal = false; |
| 118 | width = width_; | 118 | width = width_; |
| @@ -127,7 +127,7 @@ void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_, bool srgb | |||
| 127 | 127 | ||
| 128 | Destroy(); | 128 | Destroy(); |
| 129 | 129 | ||
| 130 | CreateSwapchain(capabilities, srgb); | 130 | CreateSwapchain(capabilities); |
| 131 | CreateSemaphores(); | 131 | CreateSemaphores(); |
| 132 | 132 | ||
| 133 | resource_ticks.clear(); | 133 | resource_ticks.clear(); |
| @@ -196,7 +196,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) { | |||
| 196 | } | 196 | } |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { | 199 | void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { |
| 200 | const auto physical_device{device.GetPhysical()}; | 200 | const auto physical_device{device.GetPhysical()}; |
| 201 | const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; | 201 | const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; |
| 202 | const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); | 202 | const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); |
| @@ -274,15 +274,14 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo | |||
| 274 | swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); | 274 | swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); |
| 275 | 275 | ||
| 276 | extent = swapchain_ci.imageExtent; | 276 | extent = swapchain_ci.imageExtent; |
| 277 | current_srgb = srgb; | ||
| 278 | 277 | ||
| 279 | images = swapchain.GetImages(); | 278 | images = swapchain.GetImages(); |
| 280 | image_count = static_cast<u32>(images.size()); | 279 | image_count = static_cast<u32>(images.size()); |
| 281 | #ifdef ANDROID | 280 | #ifdef ANDROID |
| 282 | // Android is already ordered the same as Switch. | 281 | // Android is already ordered the same as Switch. |
| 283 | image_view_format = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; | 282 | image_view_format = VK_FORMAT_R8G8B8A8_UNORM; |
| 284 | #else | 283 | #else |
| 285 | image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; | 284 | image_view_format = VK_FORMAT_B8G8R8A8_UNORM; |
| 286 | #endif | 285 | #endif |
| 287 | } | 286 | } |
| 288 | 287 | ||
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index b8a1465a6..d264f06e4 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h | |||
| @@ -20,11 +20,11 @@ class Scheduler; | |||
| 20 | class Swapchain { | 20 | class Swapchain { |
| 21 | public: | 21 | public: |
| 22 | explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width, | 22 | explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width, |
| 23 | u32 height, bool srgb); | 23 | u32 height); |
| 24 | ~Swapchain(); | 24 | ~Swapchain(); |
| 25 | 25 | ||
| 26 | /// Creates (or recreates) the swapchain with a given size. | 26 | /// Creates (or recreates) the swapchain with a given size. |
| 27 | void Create(VkSurfaceKHR surface, u32 width, u32 height, bool srgb); | 27 | void Create(VkSurfaceKHR surface, u32 width, u32 height); |
| 28 | 28 | ||
| 29 | /// Acquires the next image in the swapchain, waits as needed. | 29 | /// Acquires the next image in the swapchain, waits as needed. |
| 30 | bool AcquireNextImage(); | 30 | bool AcquireNextImage(); |
| @@ -33,13 +33,8 @@ public: | |||
| 33 | void Present(VkSemaphore render_semaphore); | 33 | void Present(VkSemaphore render_semaphore); |
| 34 | 34 | ||
| 35 | /// Returns true when the swapchain needs to be recreated. | 35 | /// Returns true when the swapchain needs to be recreated. |
| 36 | bool NeedsRecreation(bool is_srgb) const { | 36 | bool NeedsRecreation() const { |
| 37 | return HasColorSpaceChanged(is_srgb) || IsSubOptimal() || NeedsPresentModeUpdate(); | 37 | return IsSubOptimal() || NeedsPresentModeUpdate(); |
| 38 | } | ||
| 39 | |||
| 40 | /// Returns true when the color space has changed. | ||
| 41 | bool HasColorSpaceChanged(bool is_srgb) const { | ||
| 42 | return current_srgb != is_srgb; | ||
| 43 | } | 38 | } |
| 44 | 39 | ||
| 45 | /// Returns true when the swapchain is outdated. | 40 | /// Returns true when the swapchain is outdated. |
| @@ -52,11 +47,6 @@ public: | |||
| 52 | return is_suboptimal; | 47 | return is_suboptimal; |
| 53 | } | 48 | } |
| 54 | 49 | ||
| 55 | /// Returns true when the swapchain format is in the srgb color space | ||
| 56 | bool IsSrgb() const { | ||
| 57 | return current_srgb; | ||
| 58 | } | ||
| 59 | |||
| 60 | VkExtent2D GetSize() const { | 50 | VkExtent2D GetSize() const { |
| 61 | return extent; | 51 | return extent; |
| 62 | } | 52 | } |
| @@ -110,7 +100,7 @@ public: | |||
| 110 | } | 100 | } |
| 111 | 101 | ||
| 112 | private: | 102 | private: |
| 113 | void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb); | 103 | void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities); |
| 114 | void CreateSemaphores(); | 104 | void CreateSemaphores(); |
| 115 | void CreateImageViews(); | 105 | void CreateImageViews(); |
| 116 | 106 | ||
| @@ -144,7 +134,6 @@ private: | |||
| 144 | bool has_mailbox{false}; | 134 | bool has_mailbox{false}; |
| 145 | bool has_fifo_relaxed{false}; | 135 | bool has_fifo_relaxed{false}; |
| 146 | 136 | ||
| 147 | bool current_srgb{}; | ||
| 148 | bool is_outdated{}; | 137 | bool is_outdated{}; |
| 149 | bool is_suboptimal{}; | 138 | bool is_suboptimal{}; |
| 150 | }; | 139 | }; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index dade38b18..0d5a1709f 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -712,14 +712,15 @@ bool TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, | |||
| 712 | } | 712 | } |
| 713 | 713 | ||
| 714 | template <class P> | 714 | template <class P> |
| 715 | typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) { | 715 | typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView( |
| 716 | const Tegra::FramebufferConfig& config, VAddr cpu_addr) { | ||
| 716 | // TODO: Properly implement this | 717 | // TODO: Properly implement this |
| 717 | const auto it = page_table.find(cpu_addr >> YUZU_PAGEBITS); | 718 | const auto it = page_table.find(cpu_addr >> YUZU_PAGEBITS); |
| 718 | if (it == page_table.end()) { | 719 | if (it == page_table.end()) { |
| 719 | return nullptr; | 720 | return nullptr; |
| 720 | } | 721 | } |
| 721 | const auto& image_map_ids = it->second; | 722 | const auto& image_map_ids = it->second; |
| 722 | boost::container::small_vector<const ImageBase*, 4> valid_images; | 723 | boost::container::small_vector<ImageId, 4> valid_image_ids; |
| 723 | for (const ImageMapId map_id : image_map_ids) { | 724 | for (const ImageMapId map_id : image_map_ids) { |
| 724 | const ImageMapView& map = slot_map_views[map_id]; | 725 | const ImageMapView& map = slot_map_views[map_id]; |
| 725 | const ImageBase& image = slot_images[map.image_id]; | 726 | const ImageBase& image = slot_images[map.image_id]; |
| @@ -729,18 +730,34 @@ typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_ad | |||
| 729 | if (image.image_view_ids.empty()) { | 730 | if (image.image_view_ids.empty()) { |
| 730 | continue; | 731 | continue; |
| 731 | } | 732 | } |
| 732 | valid_images.push_back(&image); | 733 | valid_image_ids.push_back(map.image_id); |
| 733 | } | 734 | } |
| 734 | 735 | ||
| 735 | if (valid_images.size() == 1) [[likely]] { | 736 | const auto view_format = [&]() { |
| 736 | return &slot_image_views[valid_images[0]->image_view_ids.at(0)]; | 737 | switch (config.pixel_format) { |
| 738 | case Service::android::PixelFormat::Rgb565: | ||
| 739 | return PixelFormat::R5G6B5_UNORM; | ||
| 740 | case Service::android::PixelFormat::Bgra8888: | ||
| 741 | return PixelFormat::B8G8R8A8_UNORM; | ||
| 742 | default: | ||
| 743 | return PixelFormat::A8B8G8R8_UNORM; | ||
| 744 | } | ||
| 745 | }(); | ||
| 746 | |||
| 747 | const auto GetImageViewForFramebuffer = [&](ImageId image_id) { | ||
| 748 | const ImageViewInfo info{ImageViewType::e2D, view_format}; | ||
| 749 | return &slot_image_views[FindOrEmplaceImageView(image_id, info)]; | ||
| 750 | }; | ||
| 751 | |||
| 752 | if (valid_image_ids.size() == 1) [[likely]] { | ||
| 753 | return GetImageViewForFramebuffer(valid_image_ids.front()); | ||
| 737 | } | 754 | } |
| 738 | 755 | ||
| 739 | if (valid_images.size() > 0) [[unlikely]] { | 756 | if (valid_image_ids.size() > 0) [[unlikely]] { |
| 740 | std::ranges::sort(valid_images, [](const auto* a, const auto* b) { | 757 | auto most_recent = std::ranges::max_element(valid_image_ids, [&](auto a, auto b) { |
| 741 | return a->modification_tick > b->modification_tick; | 758 | return slot_images[a].modification_tick < slot_images[b].modification_tick; |
| 742 | }); | 759 | }); |
| 743 | return &slot_image_views[valid_images[0]->image_view_ids.at(0)]; | 760 | return GetImageViewForFramebuffer(*most_recent); |
| 744 | } | 761 | } |
| 745 | 762 | ||
| 746 | return nullptr; | 763 | return nullptr; |
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index a40825c9f..cbe56e166 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h | |||
| @@ -209,7 +209,8 @@ public: | |||
| 209 | const Tegra::Engines::Fermi2D::Config& copy); | 209 | const Tegra::Engines::Fermi2D::Config& copy); |
| 210 | 210 | ||
| 211 | /// Try to find a cached image view in the given CPU address | 211 | /// Try to find a cached image view in the given CPU address |
| 212 | [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr); | 212 | [[nodiscard]] ImageView* TryFindFramebufferImageView(const Tegra::FramebufferConfig& config, |
| 213 | VAddr cpu_addr); | ||
| 213 | 214 | ||
| 214 | /// Return true when there are uncommitted images to be downloaded | 215 | /// Return true when there are uncommitted images to be downloaded |
| 215 | [[nodiscard]] bool HasUncommittedFlushes() const noexcept; | 216 | [[nodiscard]] bool HasUncommittedFlushes() const noexcept; |