Compare commits

..

2 Commits

Author SHA1 Message Date
b1996bc8ca Android #158 2023-12-12 00:57:40 +00:00
fd0433ef16 Merge PR 12335 2023-12-12 00:57:40 +00:00
56 changed files with 228 additions and 4460 deletions

View File

@ -1,9 +1,6 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12237](https://github.com/yuzu-emu/yuzu//pull/12237) | [`a05c24242`](https://github.com/yuzu-emu/yuzu//pull/12237/files) | nce: implement instruction emulation for misaligned memory accesses | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12335](https://github.com/yuzu-emu/yuzu//pull/12335) | [`86d26914a`](https://github.com/yuzu-emu/yuzu//pull/12335/files) | android: Game Properties | [t895](https://github.com/t895/) | Yes |
| [12345](https://github.com/yuzu-emu/yuzu//pull/12345) | [`24a0bde93`](https://github.com/yuzu-emu/yuzu//pull/12345/files) | renderer_vulkan: cap async presentation frame count | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12349](https://github.com/yuzu-emu/yuzu//pull/12349) | [`8abdfcf8d`](https://github.com/yuzu-emu/yuzu//pull/12349/files) | Have GetActiveChannelCount return the system channels instead of host device channels | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12335](https://github.com/yuzu-emu/yuzu//pull/12335) | [`edcd6d547`](https://github.com/yuzu-emu/yuzu//pull/12335/files) | android: Game Properties | [t895](https://github.com/t895/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -174,8 +174,7 @@ android {
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DYUZU_USE_BUNDLED_VCPKG=ON",
"-DYUZU_USE_BUNDLED_FFMPEG=ON",
"-DYUZU_ENABLE_LTO=ON",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
"-DYUZU_ENABLE_LTO=ON"
)
abiFilters("arm64-v8a", "x86_64")

View File

@ -14,7 +14,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty
import org.yuzu.yuzu_emu.model.InstallableProperty
@ -42,7 +42,7 @@ class GamePropertiesAdapter(
}
else -> InstallablePropertyViewHolder(
CardInstallableIconBinding.inflate(
CardInstallableBinding.inflate(
inflater,
parent,
false
@ -107,20 +107,13 @@ class GamePropertiesAdapter(
}
}
inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) :
inner class InstallablePropertyViewHolder(val binding: CardInstallableBinding) :
GamePropertyViewHolder(binding.root) {
override fun bind(property: GameProperty) {
val installableProperty = property as InstallableProperty
binding.title.setText(installableProperty.titleId)
binding.description.setText(installableProperty.descriptionId)
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.context.resources,
installableProperty.iconId,
binding.icon.context.theme
)
)
if (installableProperty.install != null) {
binding.buttonInstall.visibility = View.VISIBLE

View File

@ -22,9 +22,6 @@ interface AbstractSetting {
get() = NativeConfig.usingGlobal(key)
set(value) = NativeConfig.setGlobal(key, value)
val isSaveable: Boolean
get() = NativeConfig.getIsSaveable(key)
fun getValueAsString(needsGlobal: Boolean = false): String
fun reset()

View File

@ -32,7 +32,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
override val defaultValue: Boolean by lazy { NativeConfig.getDefaultToString(key).toBoolean() }
override fun getValueAsString(needsGlobal: Boolean): String = getBoolean(needsGlobal).toString()
override fun getValueAsString(needsGlobal: Boolean): String =
if (getBoolean(needsGlobal)) "1" else "0"
override fun reset() = NativeConfig.setBoolean(key, defaultValue)
}

View File

@ -30,11 +30,6 @@ abstract class SettingsItem(
val isEditable: Boolean
get() {
// Can't edit settings that aren't saveable in per-game config even if they are switchable
if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) {
return false
}
if (!NativeLibrary.isRunning()) return true
// Prevent editing settings that were modified in per-game config while editing global
@ -42,7 +37,6 @@ abstract class SettingsItem(
if (!NativeConfig.isPerGameConfigLoaded() && !setting.global) {
return false
}
return setting.isRuntimeModifiable
}
@ -65,7 +59,6 @@ abstract class SettingsItem(
val emptySetting = object : AbstractSetting {
override val key: String = ""
override val defaultValue: Any = false
override val isSaveable = true
override fun getValueAsString(needsGlobal: Boolean): String = ""
override fun reset() {}
}
@ -310,8 +303,6 @@ abstract class SettingsItem(
BooleanSetting.FASTMEM_EXCLUSIVES.global = value
}
override val isSaveable = true
override fun getValueAsString(needsGlobal: Boolean): String =
getBoolean().toString()

View File

@ -128,9 +128,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
return
}
// Always load custom settings when launching a game from an intent
if (args.custom || intentGame != null) {
SettingsFile.loadCustomConfig(game)
if (args.custom) {
SettingsFile.loadCustomConfig(args.game!!)
NativeConfig.unloadPerGameConfig()
} else {
NativeConfig.reloadGlobalConfig()

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
@ -74,8 +73,6 @@ class GamePropertiesFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true)
@ -102,24 +99,12 @@ class GamePropertiesFragment : Fragment() {
reloadList()
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
homeViewModel.openImportSaves.collect {
if (it) {
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
homeViewModel.reloadPropertiesList.collect {
if (it) {
reloadList()
homeViewModel.reloadPropertiesList(false)
}
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
homeViewModel.openImportSaves.collect {
if (it) {
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}
}
@ -194,7 +179,6 @@ class GamePropertiesFragment : Fragment() {
InstallableProperty(
R.string.save_data,
R.string.save_data_description,
R.drawable.ic_save,
{
MessageDialogFragment.newInstance(
requireActivity(),
@ -230,7 +214,7 @@ class GamePropertiesFragment : Fragment() {
R.string.save_data_deleted_successfully,
Toast.LENGTH_SHORT
).show()
homeViewModel.reloadPropertiesList(true)
reloadList()
}
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
@ -258,20 +242,13 @@ class GamePropertiesFragment : Fragment() {
}
}
) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.clear_shader_cache,
descriptionId = R.string.clear_shader_cache_warning_description,
positiveAction = {
shaderCacheDir.deleteRecursively()
Toast.makeText(
YuzuApplication.appContext,
R.string.cleared_shaders_successfully,
Toast.LENGTH_SHORT
).show()
homeViewModel.reloadPropertiesList(true)
}
).show(parentFragmentManager, MessageDialogFragment.TAG)
shaderCacheDir.deleteRecursively()
Toast.makeText(
YuzuApplication.appContext,
R.string.cleared_shaders_successfully,
Toast.LENGTH_SHORT
).show()
reloadList()
}
)
}
@ -411,7 +388,7 @@ class GamePropertiesFragment : Fragment() {
getString(R.string.save_file_imported_success),
Toast.LENGTH_LONG
).show()
homeViewModel.reloadPropertiesList(true)
reloadList()
}
cacheSaveDir.deleteRecursively()

View File

@ -15,7 +15,7 @@ import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable
class LaunchGameDialogFragment : DialogFragment() {
private var selectedItem = 1
private var selectedItem = 0
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val game = requireArguments().parcelable<Game>(GAME)
@ -32,7 +32,7 @@ class LaunchGameDialogFragment : DialogFragment() {
.actionGlobalEmulationActivity(game, selectedItem != 0)
requireParentFragment().findNavController().navigate(action)
}
.setSingleChoiceItems(launchOptions, 1) { _: DialogInterface, i: Int ->
.setSingleChoiceItems(launchOptions, 0) { _: DialogInterface, i: Int ->
selectedItem = i
}
.setNegativeButton(android.R.string.cancel, null)

View File

@ -10,18 +10,17 @@ import kotlinx.coroutines.flow.StateFlow
interface GameProperty {
@get:StringRes
val titleId: Int
get() = -1
@get:StringRes
val descriptionId: Int
@get:DrawableRes
val iconId: Int
get() = -1
}
data class SubmenuProperty(
override val titleId: Int,
override val descriptionId: Int,
override val iconId: Int,
@DrawableRes val iconId: Int,
val details: (() -> String)? = null,
val detailsFlow: StateFlow<String>? = null,
val action: () -> Unit
@ -30,7 +29,6 @@ data class SubmenuProperty(
data class InstallableProperty(
override val titleId: Int,
override val descriptionId: Int,
override val iconId: Int,
val install: (() -> Unit)? = null,
val export: (() -> Unit)? = null
) : GameProperty

View File

@ -28,9 +28,6 @@ class HomeViewModel : ViewModel() {
private val _contentToInstall = MutableStateFlow<List<Uri>?>(null)
val contentToInstall get() = _contentToInstall.asStateFlow()
private val _reloadPropertiesList = MutableStateFlow(false)
val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow()
var navigatedToSetup = false
fun setNavigationVisibility(visible: Boolean, animated: Boolean) {
@ -62,8 +59,4 @@ class HomeViewModel : ViewModel() {
fun setContentToInstall(documents: List<Uri>?) {
_contentToInstall.value = documents
}
fun reloadPropertiesList(reload: Boolean) {
_reloadPropertiesList.value = reload
}
}

View File

@ -110,8 +110,6 @@ object NativeConfig {
@Synchronized
external fun setGlobal(key: String, global: Boolean)
external fun getIsSaveable(key: String): Boolean
external fun getDefaultToString(key: String): String
/**

View File

@ -89,13 +89,13 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj
return false;
}
const auto file_type = loader->GetFileType();
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
const auto fileType = loader->GetFileType();
if (fileType == Loader::FileType::Unknown || fileType == Loader::FileType::Error) {
return false;
}
u64 program_id = 0;
Loader::ResultStatus res = loader->ReadProgramId(program_id);
u64 programId = 0;
Loader::ResultStatus res = loader->ReadProgramId(programId);
if (res != Loader::ResultStatus::Success) {
return false;
}

View File

@ -80,7 +80,7 @@ Core::System& EmulationSession::System() {
return m_system;
}
FileSys::ManualContentProvider* EmulationSession::GetContentProvider() {
FileSys::ManualContentProvider* EmulationSession::ContentProvider() {
return m_manual_provider.get();
}
@ -296,6 +296,9 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
// Initialize filesystem.
ConfigureFilesystemProvider(filepath);
// Initialize account manager
m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
// Load the ROM.
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
if (m_load_result != Core::SystemResultStatus::Success) {
@ -460,13 +463,15 @@ void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) {
static_cast<jint>(result));
}
u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
u64 EmulationSession::getProgramId(JNIEnv* env, jstring jprogramId) {
u64 program_id;
auto program_id_string = GetJString(env, jprogramId);
try {
return std::stoull(program_id_string);
} catch (...) {
return 0;
if (program_id_string.empty()) {
program_id = 0;
} else {
program_id = std::stoull(program_id_string);
}
return program_id;
}
static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
@ -521,16 +526,16 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId,
jstring jupdatePath) {
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
u64 programId = EmulationSession::getProgramId(env, jprogramId);
std::string updatePath = GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(updatePath,
FileSys::Mode::Read));
for (const auto& item : nsp->GetNCAs()) {
for (const auto& nca_details : item.second) {
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
if (update_id == program_id) {
for (const auto& ncaDetails : item.second) {
if (ncaDetails.second->GetName().ends_with(".cnmt.nca")) {
auto updateId = ncaDetails.second->GetTitleId() & ~0xFFFULL;
if (updateId == programId) {
return true;
}
}
@ -765,8 +770,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory(
Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read);
const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser(
static_cast<std::size_t>(0));
Service::Account::ProfileManager manager;
const auto user_id = manager.GetUser(static_cast<std::size_t>(0));
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
@ -835,8 +840,8 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env,
}
auto& system = EmulationSession::GetInstance().System();
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
auto programId = EmulationSession::getProgramId(env, jprogramId);
const FileSys::PatchManager pm{programId, system.GetFileSystemController(),
system.GetContentProvider()};
const auto loader = Loader::GetLoader(system, vFile);
@ -844,11 +849,11 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env,
loader->ReadUpdateRaw(update_raw);
auto addons = pm.GetPatchVersionNames(update_raw);
auto jemptyString = ToJString(env, "");
auto jemptyStringPair = env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
jemptyString, jemptyString);
auto emptyString = ToJString(env, "");
auto emptyStringPair = env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
emptyString, emptyString);
jobjectArray jaddonsArray =
env->NewObjectArray(addons.size(), IDCache::GetPairClass(), jemptyStringPair);
env->NewObjectArray(addons.size(), IDCache::GetPairClass(), emptyStringPair);
int i = 0;
for (const auto& addon : addons) {
jobject jaddon = env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
@ -861,7 +866,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env,
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto programId = EmulationSession::getProgramId(env, jprogramId);
auto& system = EmulationSession::GetInstance().System();
@ -876,7 +881,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
system, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
program_id, user_id->AsU128(), 0);
programId, user_id->AsU128(), 0);
return ToJString(env, user_save_data_path);
}
@ -886,7 +891,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* e
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) {
EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries();
EmulationSession::GetInstance().ContentProvider()->ClearAllEntries();
}
} // extern "C"

View File

@ -21,7 +21,7 @@ public:
static EmulationSession& GetInstance();
const Core::System& System() const;
Core::System& System();
FileSys::ManualContentProvider* GetContentProvider();
FileSys::ManualContentProvider* ContentProvider();
const EmuWindow_Android& Window() const;
EmuWindow_Android& Window();
@ -55,7 +55,7 @@ public:
static void OnEmulationStarted();
static u64 GetProgramId(JNIEnv* env, jstring jprogramId);
static u64 getProgramId(JNIEnv* env, jstring jprogramId);
private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
@ -76,6 +76,7 @@ private:
std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false;
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
// GPU driver parameters

View File

@ -21,13 +21,13 @@ std::unique_ptr<AndroidConfig> per_game_config;
template <typename T>
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
auto key = GetJString(env, jkey);
auto basic_setting = Settings::values.linkage.by_key[key];
if (basic_setting != 0) {
return static_cast<Settings::Setting<T>*>(basic_setting);
auto basicSetting = Settings::values.linkage.by_key[key];
if (basicSetting != 0) {
return static_cast<Settings::Setting<T>*>(basicSetting);
}
auto basic_android_setting = AndroidSettings::values.linkage.by_key[key];
if (basic_android_setting != 0) {
return static_cast<Settings::Setting<T>*>(basic_android_setting);
auto basicAndroidSetting = AndroidSettings::values.linkage.by_key[key];
if (basicAndroidSetting != 0) {
return static_cast<Settings::Setting<T>*>(basicAndroidSetting);
}
LOG_ERROR(Frontend, "[Android Native] Could not find setting - {}", key);
return nullptr;
@ -54,7 +54,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jo
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializePerGameConfig(JNIEnv* env, jobject obj,
jstring jprogramId,
jstring jfileName) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto program_id = EmulationSession::getProgramId(env, jprogramId);
auto file_name = GetJString(env, jfileName);
const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id);
per_game_config =
@ -249,15 +249,6 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGlobal(JNIEnv* env, jobject o
}
}
jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSaveable(JNIEnv* env, jobject obj,
jstring jkey) {
auto setting = getSetting<std::string>(env, jkey);
if (setting != nullptr) {
return setting->Save();
}
return false;
}
jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDefaultToString(JNIEnv* env, jobject obj,
jstring jkey) {
auto setting = getSetting<std::string>(env, jkey);
@ -320,7 +311,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject
jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto program_id = EmulationSession::getProgramId(env, jprogramId);
auto& disabledAddons = Settings::values.disabled_addons[program_id];
jobjectArray jdisabledAddonsArray =
env->NewObjectArray(disabledAddons.size(), IDCache::GetStringClass(), ToJString(env, ""));
@ -333,7 +324,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, jobject obj,
jstring jprogramId,
jobjectArray jdisabledAddons) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto program_id = EmulationSession::getProgramId(env, jprogramId);
Settings::values.disabled_addons[program_id].clear();
std::vector<std::string> disabled_addons;
const int size = env->GetArrayLength(jdisabledAddons);

View File

@ -1,9 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z" />
android:fillColor="@android:color/white"
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L647,120Q663,120 677.5,126Q692,132 703,143L817,257Q828,268 834,282.5Q840,297 840,313L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM760,314L646,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760L760,760Q760,760 760,760Q760,760 760,760L760,314ZM480,720Q530,720 565,685Q600,650 600,600Q600,550 565,515Q530,480 480,480Q430,480 395,515Q360,550 360,600Q360,650 395,685Q430,720 480,720ZM280,400L560,400Q577,400 588.5,388.5Q600,377 600,360L600,280Q600,263 588.5,251.5Q577,240 560,240L280,240Q263,240 251.5,251.5Q240,263 240,280L240,360Q240,377 251.5,388.5Q263,400 280,400ZM200,314L200,760Q200,760 200,760Q200,760 200,760L200,760Q200,760 200,760Q200,760 200,760L200,200Q200,200 200,200Q200,200 200,200L200,200L200,314Z"/>
</vector>

View File

@ -1,82 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?attr/materialCardViewOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
app:tint="?attr/colorOnSurface"
tools:src="@drawable/ic_settings" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/user_data"
android:textAlignment="viewStart" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/user_data_description"
android:textAlignment="viewStart" />
</LinearLayout>
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
app:icon="@drawable/ic_import"
tools:visibility="visible" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -1,89 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?attr/materialCardViewOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
app:tint="?attr/colorOnSurface"
tools:src="@drawable/ic_settings" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/user_data"
android:textAlignment="viewStart" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/user_data_description"
android:textAlignment="viewStart" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
app:icon="@drawable/ic_import"
tools:visibility="visible" />
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="8dp"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -314,7 +314,6 @@
<string name="add_ons_description">Toggle mods, updates and DLC</string>
<string name="clear_shader_cache">Clear shader cache</string>
<string name="clear_shader_cache_description">Removes all shaders built while playing this game</string>
<string name="clear_shader_cache_warning_description">You will experience more stuttering as the shader cache regenerates</string>
<string name="cleared_shaders_successfully">Cleared shaders successfully</string>
<string name="addons_game">Addons: %1$s</string>
<string name="save_data">Save data</string>
@ -335,7 +334,7 @@
<string name="addon_installed_successfully">Addon installed successfully</string>
<string name="verifying_content">Verifying content…</string>
<string name="content_install_notice">Content install notice</string>
<string name="content_install_notice_description">The content that you selected does not match this game.\nInstall anyway?</string>
<string name="content_install_notice_description">The content that you selected does not match this game.\nInstall anyways?</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Your ROM is encrypted</string>

View File

@ -253,9 +253,8 @@ CubebSink::~CubebSink() {
#endif
}
SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string& name, StreamType type) {
system_channels = system_channels_;
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>(
ctx, device_channels, system_channels, output_device, input_device, name, type, system));

View File

@ -168,9 +168,8 @@ SDLSink::SDLSink(std::string_view target_device_name) {
SDLSink::~SDLSink() = default;
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels,
const std::string&, StreamType type) {
system_channels = system_channels_;
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(
device_channels, system_channels, output_device, input_device, type, system));
return stream.get();

View File

@ -85,21 +85,9 @@ public:
*/
virtual void SetSystemVolume(f32 volume) = 0;
/**
* Get the number of channels the game has set, can be different to the host hardware's support.
* Either 2 or 6.
*
* @return Number of device channels.
*/
u32 GetSystemChannels() const {
return system_channels;
}
protected:
/// Number of device channels supported by the hardware
u32 device_channels{2};
/// Number of channels the game is sending
u32 system_channels{2};
};
using SinkPtr = std::unique_ptr<Sink>;

View File

@ -40,38 +40,29 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
if (system_channels == 6 && device_channels == 2) {
// We're given 6 channels, but our device only outputs 2, so downmix.
// Front = 1.0
// Center = 0.596
// Back = 0.707
// LFE = 0.354
// 1.0 + 0.596 + 0.707 + 0.354 = 2.657, 1/2.657 = 0.37636f downscale coefficient
static constexpr std::array<f32, 4> down_mix_coeff{0.37636f, 0.22431056f, 0.13323144f,
0.26608652f};
static constexpr std::array<f32, 4> down_mix_coeff{1.0f, 0.707f, 0.251f, 0.707f};
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
read_index += system_channels, write_index += device_channels) {
const auto fl =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::FrontLeft)]);
const auto fr =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::FrontRight)]);
const auto c =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::Center)]);
const auto lfe =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::LFE)]);
const auto bl =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::BackLeft)]);
const auto br =
static_cast<f32>(samples[read_index + static_cast<u32>(Channels::BackRight)]);
const auto left_sample{
static_cast<s32>((fl * down_mix_coeff[0] + c * down_mix_coeff[1] +
lfe * down_mix_coeff[2] + bl * down_mix_coeff[3]) *
volume)};
((Common::FixedPoint<49, 15>(
samples[read_index + static_cast<u32>(Channels::FrontLeft)]) *
down_mix_coeff[0] +
samples[read_index + static_cast<u32>(Channels::Center)] * down_mix_coeff[1] +
samples[read_index + static_cast<u32>(Channels::LFE)] * down_mix_coeff[2] +
samples[read_index + static_cast<u32>(Channels::BackLeft)] * down_mix_coeff[3]) *
volume)
.to_int()};
const auto right_sample{
static_cast<s32>((fr * down_mix_coeff[0] + c * down_mix_coeff[1] +
lfe * down_mix_coeff[2] + br * down_mix_coeff[3]) *
volume)};
((Common::FixedPoint<49, 15>(
samples[read_index + static_cast<u32>(Channels::FrontRight)]) *
down_mix_coeff[0] +
samples[read_index + static_cast<u32>(Channels::Center)] * down_mix_coeff[1] +
samples[read_index + static_cast<u32>(Channels::LFE)] * down_mix_coeff[2] +
samples[read_index + static_cast<u32>(Channels::BackRight)] * down_mix_coeff[3]) *
volume)
.to_int()};
samples[write_index + static_cast<u32>(Channels::FrontLeft)] =
static_cast<s16>(std::clamp(left_sample, min, max));

View File

@ -256,7 +256,7 @@ struct Values {
AstcDecodeMode::CpuAsynchronous,
"accelerate_astc",
Category::Renderer};
SwitchableSetting<VSyncMode, true> vsync_mode{
Setting<VSyncMode, true> vsync_mode{
linkage, VSyncMode::Fifo, VSyncMode::Immediate, VSyncMode::FifoRelaxed,
"use_vsync", Category::Renderer, Specialization::RuntimeList, true,
true};

View File

@ -947,19 +947,15 @@ if (HAS_NCE)
set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
target_sources(core PRIVATE
arm/nce/arm_nce_asm_definitions.h
arm/nce/arm_nce.cpp
arm/nce/arm_nce.h
arm/nce/arm_nce.s
arm/nce/guest_context.h
arm/nce/instructions.h
arm/nce/interpreter_visitor.cpp
arm/nce/interpreter_visitor.h
arm/nce/patcher.cpp
arm/nce/patcher.h
arm/nce/visitor_base.h
arm/nce/instructions.h
)
target_link_libraries(core PRIVATE merry::mcl merry::oaknut)
target_link_libraries(core PRIVATE merry::oaknut)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)

View File

@ -6,7 +6,7 @@
#include "common/signal_chain.h"
#include "core/arm/nce/arm_nce.h"
#include "core/arm/nce/interpreter_visitor.h"
#include "core/arm/nce/guest_context.h"
#include "core/arm/nce/patcher.h"
#include "core/core.h"
#include "core/memory.h"
@ -21,8 +21,7 @@ namespace Core {
namespace {
struct sigaction g_orig_bus_action;
struct sigaction g_orig_segv_action;
struct sigaction g_orig_action;
// Verify assembly offsets.
using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters;
@ -38,9 +37,6 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
return reinterpret_cast<fpsimd_context*>(header);
}
using namespace Common::Literals;
constexpr u32 StackSize = 32_KiB;
} // namespace
void* ArmNce::RestoreGuestContext(void* raw_context) {
@ -108,10 +104,19 @@ void ArmNce::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) {
host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0);
}
bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
bool ArmNce::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
auto* info = static_cast<siginfo_t*>(raw_info);
// Try to handle an invalid access.
// TODO: handle accesses which split a page?
const Common::ProcessAddress addr =
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
// We handled the access successfully and are returning to guest code.
return true;
}
// We can't handle the access, so determine why we crashed.
const bool is_prefetch_abort = host_ctx.pc == reinterpret_cast<u64>(info->si_addr);
@ -138,44 +143,8 @@ bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, voi
return false;
}
bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
auto* fpctx = GetFloatingPointState(host_ctx);
auto& memory = guest_ctx->system->ApplicationMemory();
// Match and execute an instruction.
auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx);
if (next_pc) {
host_ctx.pc = *next_pc;
return true;
}
// We couldn't handle the access.
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
}
bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
auto* info = static_cast<siginfo_t*>(raw_info);
// Try to handle an invalid access.
// TODO: handle accesses which split a page?
const Common::ProcessAddress addr =
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
// We handled the access successfully and are returning to guest code.
return true;
}
// We couldn't handle the access.
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
}
void ArmNce::HandleHostAlignmentFault(int sig, void* raw_info, void* raw_context) {
return g_orig_bus_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
}
void ArmNce::HandleHostAccessFault(int sig, void* raw_info, void* raw_context) {
return g_orig_segv_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
void ArmNce::HandleHostFault(int sig, void* raw_info, void* raw_context) {
return g_orig_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
}
void ArmNce::LockThread(Kernel::KThread* thread) {
@ -256,31 +225,18 @@ ArmNce::ArmNce(System& system, bool uses_wall_clock, std::size_t core_index)
ArmNce::~ArmNce() = default;
void ArmNce::Initialize() {
if (m_thread_id == -1) {
m_thread_id = gettid();
}
m_thread_id = gettid();
// Configure signal stack.
if (!m_stack) {
m_stack = std::make_unique<u8[]>(StackSize);
stack_t ss{};
ss.ss_sp = m_stack.get();
ss.ss_size = StackSize;
sigaltstack(&ss, nullptr);
}
// Set up signals.
static std::once_flag flag;
std::call_once(flag, [] {
// Setup our signals
static std::once_flag signals;
std::call_once(signals, [] {
using HandlerType = decltype(sigaction::sa_sigaction);
sigset_t signal_mask;
sigemptyset(&signal_mask);
sigaddset(&signal_mask, ReturnToRunCodeByExceptionLevelChangeSignal);
sigaddset(&signal_mask, BreakFromRunCodeSignal);
sigaddset(&signal_mask, GuestAlignmentFaultSignal);
sigaddset(&signal_mask, GuestAccessFaultSignal);
sigaddset(&signal_mask, GuestFaultSignal);
struct sigaction return_to_run_code_action {};
return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
@ -297,19 +253,18 @@ void ArmNce::Initialize() {
break_from_run_code_action.sa_mask = signal_mask;
Common::SigAction(BreakFromRunCodeSignal, &break_from_run_code_action, nullptr);
struct sigaction alignment_fault_action {};
alignment_fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
alignment_fault_action.sa_sigaction =
reinterpret_cast<HandlerType>(&ArmNce::GuestAlignmentFaultSignalHandler);
alignment_fault_action.sa_mask = signal_mask;
Common::SigAction(GuestAlignmentFaultSignal, &alignment_fault_action, nullptr);
struct sigaction fault_action {};
fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
fault_action.sa_sigaction = reinterpret_cast<HandlerType>(&ArmNce::GuestFaultSignalHandler);
fault_action.sa_mask = signal_mask;
Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action);
struct sigaction access_fault_action {};
access_fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
access_fault_action.sa_sigaction =
reinterpret_cast<HandlerType>(&ArmNce::GuestAccessFaultSignalHandler);
access_fault_action.sa_mask = signal_mask;
Common::SigAction(GuestAccessFaultSignal, &access_fault_action, &g_orig_segv_action);
// Simplify call for g_orig_action.
// These fields occupy the same space in memory, so this should be a no-op in practice.
if (!(g_orig_action.sa_flags & SA_SIGINFO)) {
g_orig_action.sa_sigaction =
reinterpret_cast<decltype(g_orig_action.sa_sigaction)>(g_orig_action.sa_handler);
}
});
}

View File

@ -61,8 +61,7 @@ private:
static void ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info,
void* raw_context);
static void BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context);
static void GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context);
static void GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context);
static void GuestFaultSignalHandler(int sig, void* info, void* raw_context);
static void LockThreadParameters(void* tpidr);
static void UnlockThreadParameters(void* tpidr);
@ -71,11 +70,8 @@ private:
// C++ implementation functions for assembly definitions.
static void* RestoreGuestContext(void* raw_context);
static void SaveGuestContext(GuestContext* ctx, void* raw_context);
static bool HandleFailedGuestFault(GuestContext* ctx, void* info, void* raw_context);
static bool HandleGuestAlignmentFault(GuestContext* ctx, void* info, void* raw_context);
static bool HandleGuestAccessFault(GuestContext* ctx, void* info, void* raw_context);
static void HandleHostAlignmentFault(int sig, void* info, void* raw_context);
static void HandleHostAccessFault(int sig, void* info, void* raw_context);
static bool HandleGuestFault(GuestContext* ctx, void* info, void* raw_context);
static void HandleHostFault(int sig, void* info, void* raw_context);
public:
Core::System& m_system;
@ -87,9 +83,6 @@ public:
// Core context.
GuestContext m_guest_ctx{};
Kernel::KThread* m_running_thread{};
// Stack for signal processing.
std::unique_ptr<u8[]> m_stack{};
};
} // namespace Core

View File

@ -130,11 +130,11 @@ _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_:
ret
/* static void Core::ArmNce::GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context) */
.section .text._ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, "ax", %progbits
.global _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_
.type _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, %function
_ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_:
/* static void Core::ArmNce::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */
.section .text._ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits
.global _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_
.type _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, %function
_ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_:
/* Check to see if we have the correct TLS magic. */
mrs x8, tpidr_el0
ldr w9, [x8, #(TpidrEl0TlsMagic)]
@ -146,7 +146,7 @@ _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_:
/* Incorrect TLS magic, so this is a host fault. */
/* Tail call the handler. */
b _ZN4Core6ArmNce24HandleHostAlignmentFaultEiPvS1_
b _ZN4Core6ArmNce15HandleHostFaultEiPvS1_
1:
/* Correct TLS magic, so this is a guest fault. */
@ -163,53 +163,7 @@ _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_:
msr tpidr_el0, x3
/* Call the handler. */
bl _ZN4Core6ArmNce25HandleGuestAlignmentFaultEPNS_12GuestContextEPvS3_
/* If the handler returned false, we want to preserve the host tpidr_el0. */
cbz x0, 2f
/* Otherwise, restore guest tpidr_el0. */
msr tpidr_el0, x19
2:
ldr x19, [sp, #0x10]
ldp x29, x30, [sp], #0x20
ret
/* static void Core::ArmNce::GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context) */
.section .text._ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, "ax", %progbits
.global _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_
.type _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, %function
_ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_:
/* Check to see if we have the correct TLS magic. */
mrs x8, tpidr_el0
ldr w9, [x8, #(TpidrEl0TlsMagic)]
LOAD_IMMEDIATE_32(w10, TlsMagic)
cmp w9, w10
b.eq 1f
/* Incorrect TLS magic, so this is a host fault. */
/* Tail call the handler. */
b _ZN4Core6ArmNce21HandleHostAccessFaultEiPvS1_
1:
/* Correct TLS magic, so this is a guest fault. */
stp x29, x30, [sp, #-0x20]!
str x19, [sp, #0x10]
mov x29, sp
/* Save the old tpidr_el0. */
mov x19, x8
/* Restore host tpidr_el0. */
ldr x0, [x8, #(TpidrEl0NativeContext)]
ldr x3, [x0, #(GuestContextHostContext + HostContextTpidrEl0)]
msr tpidr_el0, x3
/* Call the handler. */
bl _ZN4Core6ArmNce22HandleGuestAccessFaultEPNS_12GuestContextEPvS3_
bl _ZN4Core6ArmNce16HandleGuestFaultEPNS_12GuestContextEPvS3_
/* If the handler returned false, we want to preserve the host tpidr_el0. */
cbz x0, 2f

View File

@ -10,8 +10,7 @@
#define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2
#define BreakFromRunCodeSignal SIGURG
#define GuestAccessFaultSignal SIGSEGV
#define GuestAlignmentFaultSignal SIGBUS
#define GuestFaultSignal SIGSEGV
#define GuestContextSp 0xF8
#define GuestContextHostContext 0x320

View File

@ -1,825 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/bit_cast.h"
#include "core/arm/nce/interpreter_visitor.h"
#include <dynarmic/frontend/A64/decoder/a64.h>
namespace Core {
template <u32 BitSize>
u64 SignExtendToLong(u64 value) {
u64 mask = 1ULL << (BitSize - 1);
value &= (1ULL << BitSize) - 1;
return (value ^ mask) - mask;
}
static u64 SignExtendToLong(u64 value, u64 bitsize) {
switch (bitsize) {
case 8:
return SignExtendToLong<8>(value);
case 16:
return SignExtendToLong<16>(value);
case 32:
return SignExtendToLong<32>(value);
default:
return value;
}
}
template <u64 BitSize>
u32 SignExtendToWord(u32 value) {
u32 mask = 1ULL << (BitSize - 1);
value &= (1ULL << BitSize) - 1;
return (value ^ mask) - mask;
}
static u32 SignExtendToWord(u32 value, u64 bitsize) {
switch (bitsize) {
case 8:
return SignExtendToWord<8>(value);
case 16:
return SignExtendToWord<16>(value);
default:
return value;
}
}
static u64 SignExtend(u64 value, u64 bitsize, u64 regsize) {
if (regsize == 64) {
return SignExtendToLong(value, bitsize);
} else {
return SignExtendToWord(static_cast<u32>(value), bitsize);
}
}
static u128 VectorGetElement(u128 value, u64 bitsize) {
switch (bitsize) {
case 8:
return {value[0] & ((1ULL << 8) - 1), 0};
case 16:
return {value[0] & ((1ULL << 16) - 1), 0};
case 32:
return {value[0] & ((1ULL << 32) - 1), 0};
case 64:
return {value[0], 0};
default:
return value;
}
}
u64 InterpreterVisitor::ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift) {
ASSERT(shift <= 4);
ASSERT(bitsize == 32 || bitsize == 64);
u64 val = this->GetReg(reg);
size_t len;
u64 extended;
bool signed_extend;
switch (option.ZeroExtend()) {
case 0b000: { // UXTB
val &= ((1ULL << 8) - 1);
len = 8;
signed_extend = false;
break;
}
case 0b001: { // UXTH
val &= ((1ULL << 16) - 1);
len = 16;
signed_extend = false;
break;
}
case 0b010: { // UXTW
val &= ((1ULL << 32) - 1);
len = 32;
signed_extend = false;
break;
}
case 0b011: { // UXTX
len = 64;
signed_extend = false;
break;
}
case 0b100: { // SXTB
val &= ((1ULL << 8) - 1);
len = 8;
signed_extend = true;
break;
}
case 0b101: { // SXTH
val &= ((1ULL << 16) - 1);
len = 16;
signed_extend = true;
break;
}
case 0b110: { // SXTW
val &= ((1ULL << 32) - 1);
len = 32;
signed_extend = true;
break;
}
case 0b111: { // SXTX
len = 64;
signed_extend = true;
break;
}
default:
UNREACHABLE();
}
if (len < bitsize && signed_extend) {
extended = SignExtend(val, len, bitsize);
} else {
extended = val;
}
return extended << shift;
}
u128 InterpreterVisitor::GetVec(Vec v) {
return m_fpsimd_regs[static_cast<u32>(v)];
}
u64 InterpreterVisitor::GetReg(Reg r) {
return m_regs[static_cast<u32>(r)];
}
u64 InterpreterVisitor::GetSp() {
return m_sp;
}
u64 InterpreterVisitor::GetPc() {
return m_pc;
}
void InterpreterVisitor::SetVec(Vec v, u128 value) {
m_fpsimd_regs[static_cast<u32>(v)] = value;
}
void InterpreterVisitor::SetReg(Reg r, u64 value) {
m_regs[static_cast<u32>(r)] = value;
}
void InterpreterVisitor::SetSp(u64 value) {
m_sp = value;
}
bool InterpreterVisitor::Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt) {
const auto memop = L ? MemOp::Load : MemOp::Store;
const size_t elsize = 8 << size;
const size_t datasize = elsize;
// Operation
const size_t dbytes = datasize / 8;
u64 address;
if (Rn == Reg::SP) {
address = this->GetSp();
} else {
address = this->GetReg(Rn);
}
switch (memop) {
case MemOp::Store: {
std::atomic_thread_fence(std::memory_order_seq_cst);
u64 value = this->GetReg(Rt);
m_memory.WriteBlock(address, &value, dbytes);
std::atomic_thread_fence(std::memory_order_seq_cst);
break;
}
case MemOp::Load: {
u64 value = 0;
m_memory.ReadBlock(address, &value, dbytes);
this->SetReg(Rt, value);
std::atomic_thread_fence(std::memory_order_seq_cst);
break;
}
default:
UNREACHABLE();
}
return true;
}
bool InterpreterVisitor::STLLR(Imm<2> sz, Reg Rn, Reg Rt) {
const size_t size = sz.ZeroExtend<size_t>();
const bool L = 0;
const bool o0 = 0;
return this->Ordered(size, L, o0, Rn, Rt);
}
bool InterpreterVisitor::STLR(Imm<2> sz, Reg Rn, Reg Rt) {
const size_t size = sz.ZeroExtend<size_t>();
const bool L = 0;
const bool o0 = 1;
return this->Ordered(size, L, o0, Rn, Rt);
}
bool InterpreterVisitor::LDLAR(Imm<2> sz, Reg Rn, Reg Rt) {
const size_t size = sz.ZeroExtend<size_t>();
const bool L = 1;
const bool o0 = 0;
return this->Ordered(size, L, o0, Rn, Rt);
}
bool InterpreterVisitor::LDAR(Imm<2> sz, Reg Rn, Reg Rt) {
const size_t size = sz.ZeroExtend<size_t>();
const bool L = 1;
const bool o0 = 1;
return this->Ordered(size, L, o0, Rn, Rt);
}
bool InterpreterVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) {
const size_t size = opc_0 == 0 ? 4 : 8;
const s64 offset = Dynarmic::concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
const u64 address = this->GetPc() + offset;
u64 data = 0;
m_memory.ReadBlock(address, &data, size);
this->SetReg(Rt, data);
return true;
}
bool InterpreterVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
if (opc == 0b11) {
// Unallocated encoding
return false;
}
const u64 size = 4 << opc.ZeroExtend();
const u64 offset = imm19.SignExtend<u64>() << 2;
const u64 address = this->GetPc() + offset;
u128 data{};
m_memory.ReadBlock(address, &data, size);
this->SetVec(Vt, data);
return true;
}
bool InterpreterVisitor::STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L,
Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt) {
if ((L == 0 && opc.Bit<0>() == 1) || opc == 0b11) {
// Unallocated encoding
return false;
}
const auto memop = L == 1 ? MemOp::Load : MemOp::Store;
if (memop == MemOp::Load && wback && (Rt == Rn || Rt2 == Rn) && Rn != Reg::R31) {
// Unpredictable instruction
return false;
}
if (memop == MemOp::Store && wback && (Rt == Rn || Rt2 == Rn) && Rn != Reg::R31) {
// Unpredictable instruction
return false;
}
if (memop == MemOp::Load && Rt == Rt2) {
// Unpredictable instruction
return false;
}
u64 address;
if (Rn == Reg::SP) {
address = this->GetSp();
} else {
address = this->GetReg(Rn);
}
const bool postindex = !not_postindex;
const bool signed_ = opc.Bit<0>() != 0;
const size_t scale = 2 + opc.Bit<1>();
const size_t datasize = 8 << scale;
const u64 offset = imm7.SignExtend<u64>() << scale;
if (!postindex) {
address += offset;
}
const size_t dbytes = datasize / 8;
switch (memop) {
case MemOp::Store: {
u64 data1 = this->GetReg(Rt);
u64 data2 = this->GetReg(Rt2);
m_memory.WriteBlock(address, &data1, dbytes);
m_memory.WriteBlock(address + dbytes, &data2, dbytes);
break;
}
case MemOp::Load: {
u64 data1 = 0, data2 = 0;
m_memory.ReadBlock(address, &data1, dbytes);
m_memory.ReadBlock(address + dbytes, &data2, dbytes);
if (signed_) {
this->SetReg(Rt, SignExtend(data1, datasize, 64));
this->SetReg(Rt2, SignExtend(data2, datasize, 64));
} else {
this->SetReg(Rt, data1);
this->SetReg(Rt2, data2);
}
break;
}
default:
UNREACHABLE();
}
if (wback) {
if (postindex) {
address += offset;
}
if (Rn == Reg::SP) {
this->SetSp(address);
} else {
this->SetReg(Rn, address);
}
}
return true;
}
bool InterpreterVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L,
Imm<7> imm7, Vec Vt2, Reg Rn, Vec Vt) {
if (opc == 0b11) {
// Unallocated encoding
return false;
}
const auto memop = L == 1 ? MemOp::Load : MemOp::Store;
if (memop == MemOp::Load && Vt == Vt2) {
// Unpredictable instruction
return false;
}
u64 address;
if (Rn == Reg::SP) {
address = this->GetSp();
} else {
address = this->GetReg(Rn);
}
const bool postindex = !not_postindex;
const size_t scale = 2 + opc.ZeroExtend<size_t>();
const size_t datasize = 8 << scale;
const u64 offset = imm7.SignExtend<u64>() << scale;
const size_t dbytes = datasize / 8;
if (!postindex) {
address += offset;
}
switch (memop) {
case MemOp::Store: {
u128 data1 = VectorGetElement(this->GetVec(Vt), datasize);
u128 data2 = VectorGetElement(this->GetVec(Vt2), datasize);
m_memory.WriteBlock(address, &data1, dbytes);
m_memory.WriteBlock(address + dbytes, &data2, dbytes);
break;
}
case MemOp::Load: {
u128 data1{}, data2{};
m_memory.ReadBlock(address, &data1, dbytes);
m_memory.ReadBlock(address + dbytes, &data2, dbytes);
this->SetVec(Vt, data1);
this->SetVec(Vt2, data2);
break;
}
default:
UNREACHABLE();
}
if (wback) {
if (postindex) {
address += offset;
}
if (Rn == Reg::SP) {
this->SetSp(address);
} else {
this->SetReg(Rn, address);
}
}
return true;
}
bool InterpreterVisitor::RegisterImmediate(bool wback, bool postindex, size_t scale, u64 offset,
Imm<2> size, Imm<2> opc, Reg Rn, Reg Rt) {
MemOp memop;
bool signed_ = false;
size_t regsize = 0;
if (opc.Bit<1>() == 0) {
memop = opc.Bit<0>() ? MemOp::Load : MemOp::Store;
regsize = size == 0b11 ? 64 : 32;
signed_ = false;
} else if (size == 0b11) {
memop = MemOp::Prefetch;
ASSERT(!opc.Bit<0>());
} else {
memop = MemOp::Load;
ASSERT(!(size == 0b10 && opc.Bit<0>() == 1));
regsize = opc.Bit<0>() ? 32 : 64;
signed_ = true;
}
if (memop == MemOp::Load && wback && Rn == Rt && Rn != Reg::R31) {
// Unpredictable instruction
return false;
}
if (memop == MemOp::Store && wback && Rn == Rt && Rn != Reg::R31) {
// Unpredictable instruction
return false;
}
u64 address;
if (Rn == Reg::SP) {
address = this->GetSp();
} else {
address = this->GetReg(Rn);
}
if (!postindex) {
address += offset;
}
const size_t datasize = 8 << scale;
switch (memop) {
case MemOp::Store: {
u64 data = this->GetReg(Rt);
m_memory.WriteBlock(address, &data, datasize / 8);
break;
}
case MemOp::Load: {
u64 data = 0;
m_memory.ReadBlock(address, &data, datasize / 8);
if (signed_) {
this->SetReg(Rt, SignExtend(data, datasize, regsize));
} else {
this->SetReg(Rt, data);
}
break;
}
case MemOp::Prefetch:
// this->Prefetch(address, Rt)
break;
}
if (wback) {
if (postindex) {
address += offset;
}
if (Rn == Reg::SP) {
this->SetSp(address);
} else {
this->SetReg(Rn, address);
}
}
return true;
}
bool InterpreterVisitor::STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex,
Reg Rn, Reg Rt) {
const bool wback = true;
const bool postindex = !not_postindex;
const size_t scale = size.ZeroExtend<size_t>();
const u64 offset = imm9.SignExtend<u64>();
return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
}
bool InterpreterVisitor::STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) {
const bool wback = false;
const bool postindex = false;
const size_t scale = size.ZeroExtend<size_t>();
const u64 offset = imm12.ZeroExtend<u64>() << scale;
return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
}
bool InterpreterVisitor::STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) {
const bool wback = false;
const bool postindex = false;
const size_t scale = size.ZeroExtend<size_t>();
const u64 offset = imm9.SignExtend<u64>();
return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
}
bool InterpreterVisitor::SIMDImmediate(bool wback, bool postindex, size_t scale, u64 offset,
MemOp memop, Reg Rn, Vec Vt) {
const size_t datasize = 8 << scale;
u64 address;
if (Rn == Reg::SP) {
address = this->GetSp();
} else {
address = this->GetReg(Rn);
}
if (!postindex) {
address += offset;
}
switch (memop) {
case MemOp::Store: {
u128 data = VectorGetElement(this->GetVec(Vt), datasize);
m_memory.WriteBlock(address, &data, datasize / 8);
break;
}
case MemOp::Load: {
u128 data{};
m_memory.ReadBlock(address, &data, datasize);
this->SetVec(Vt, data);
break;
}
default:
UNREACHABLE();
}
if (wback) {
if (postindex) {
address += offset;
}
if (Rn == Reg::SP) {
this->SetSp(address);
} else {
this->SetReg(Rn, address);
}
}
return true;
}
bool InterpreterVisitor::STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9,
bool not_postindex, Reg Rn, Vec Vt) {
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const bool wback = true;
const bool postindex = !not_postindex;
const u64 offset = imm9.SignExtend<u64>();
return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt);
}
bool InterpreterVisitor::STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn,
Vec Vt) {
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const bool wback = false;
const bool postindex = false;
const u64 offset = imm12.ZeroExtend<u64>() << scale;
return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt);
}
bool InterpreterVisitor::LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9,
bool not_postindex, Reg Rn, Vec Vt) {
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const bool wback = true;
const bool postindex = !not_postindex;
const u64 offset = imm9.SignExtend<u64>();
return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt);
}
bool InterpreterVisitor::LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn,
Vec Vt) {
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const bool wback = false;
const bool postindex = false;
const u64 offset = imm12.ZeroExtend<u64>() << scale;
return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt);
}
bool InterpreterVisitor::STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) {
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const bool wback = false;
const bool postindex = false;
const u64 offset = imm9.SignExtend<u64>();
return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt);
}
bool InterpreterVisitor::LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) {
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const bool wback = false;
const bool postindex = false;
const u64 offset = imm9.SignExtend<u64>();
return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt);
}
bool InterpreterVisitor::RegisterOffset(size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1,
Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Reg Rt) {
MemOp memop;
size_t regsize = 64;
bool signed_ = false;
if (opc_1 == 0) {
memop = opc_0 == 1 ? MemOp::Load : MemOp::Store;
regsize = size == 0b11 ? 64 : 32;
signed_ = false;
} else if (size == 0b11) {
memop = MemOp::Prefetch;
if (opc_0 == 1) {
// Unallocated encoding
return false;
}
} else {
memop = MemOp::Load;
if (size == 0b10 && opc_0 == 1) {
// Unallocated encoding
return false;
}
regsize = opc_0 == 1 ? 32 : 64;
signed_ = true;
}
const size_t datasize = 8 << scale;
// Operation
const u64 offset = this->ExtendReg(64, Rm, option, shift);
u64 address;
if (Rn == Reg::SP) {
address = this->GetSp();
} else {
address = this->GetReg(Rn);
}
address += offset;
switch (memop) {
case MemOp::Store: {
u64 data = this->GetReg(Rt);
m_memory.WriteBlock(address, &data, datasize / 8);
break;
}
case MemOp::Load: {
u64 data = 0;
m_memory.ReadBlock(address, &data, datasize / 8);
if (signed_) {
this->SetReg(Rt, SignExtend(data, datasize, regsize));
} else {
this->SetReg(Rt, data);
}
break;
}
case MemOp::Prefetch:
break;
}
return true;
}
bool InterpreterVisitor::STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Reg Rt) {
const Imm<1> opc_0{0};
const size_t scale = size.ZeroExtend<size_t>();
const u8 shift = S ? static_cast<u8>(scale) : 0;
if (!option.Bit<1>()) {
// Unallocated encoding
return false;
}
return this->RegisterOffset(scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt);
}
bool InterpreterVisitor::LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Reg Rt) {
const Imm<1> opc_0{1};
const size_t scale = size.ZeroExtend<size_t>();
const u8 shift = S ? static_cast<u8>(scale) : 0;
if (!option.Bit<1>()) {
// Unallocated encoding
return false;
}
return this->RegisterOffset(scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt);
}
bool InterpreterVisitor::SIMDOffset(size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option,
Reg Rn, Vec Vt) {
const auto memop = opc_0 == 1 ? MemOp::Load : MemOp::Store;
const size_t datasize = 8 << scale;
// Operation
const u64 offset = this->ExtendReg(64, Rm, option, shift);
u64 address;
if (Rn == Reg::SP) {
address = this->GetSp();
} else {
address = this->GetReg(Rn);
}
address += offset;
switch (memop) {
case MemOp::Store: {
u128 data = VectorGetElement(this->GetVec(Vt), datasize);
m_memory.WriteBlock(address, &data, datasize / 8);
break;
}
case MemOp::Load: {
u128 data{};
m_memory.ReadBlock(address, &data, datasize / 8);
this->SetVec(Vt, data);
break;
}
default:
UNREACHABLE();
}
return true;
}
bool InterpreterVisitor::STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S,
Reg Rn, Vec Vt) {
const Imm<1> opc_0{0};
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const u8 shift = S ? static_cast<u8>(scale) : 0;
if (!option.Bit<1>()) {
// Unallocated encoding
return false;
}
return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt);
}
bool InterpreterVisitor::LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S,
Reg Rn, Vec Vt) {
const Imm<1> opc_0{1};
const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
if (scale > 4) {
// Unallocated encoding
return false;
}
const u8 shift = S ? static_cast<u8>(scale) : 0;
if (!option.Bit<1>()) {
// Unallocated encoding
return false;
}
return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt);
}
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
fpsimd_context* fpsimd_context) {
// Construct the interpreter.
std::span<u64, 31> regs(reinterpret_cast<u64*>(context->regs), 31);
std::span<u128, 32> vregs(reinterpret_cast<u128*>(fpsimd_context->vregs), 32);
u64& sp = *reinterpret_cast<u64*>(&context->sp);
const u64& pc = *reinterpret_cast<u64*>(&context->pc);
InterpreterVisitor visitor(memory, regs, vregs, sp, pc);
// Read the instruction at the program counter.
u32 instruction = memory.Read32(pc);
bool was_executed = false;
// Interpret the instruction.
if (auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction)) {
was_executed = decoder->get().call(visitor, instruction);
} else {
LOG_ERROR(Core_ARM, "Unallocated encoding: {:#x}", instruction);
}
if (was_executed) {
return pc + 4;
}
return std::nullopt;
}
} // namespace Core

View File

@ -1,103 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <signal.h>
#include <unistd.h>
#include "core/arm/nce/visitor_base.h"
namespace Core {
namespace Memory {
class Memory;
}
class InterpreterVisitor final : public VisitorBase {
public:
explicit InterpreterVisitor(Core::Memory::Memory& memory, std::span<u64, 31> regs,
std::span<u128, 32> fpsimd_regs, u64& sp, const u64& pc)
: m_memory(memory), m_regs(regs), m_fpsimd_regs(fpsimd_regs), m_sp(sp), m_pc(pc) {}
~InterpreterVisitor() override = default;
enum class MemOp {
Load,
Store,
Prefetch,
};
u128 GetVec(Vec v);
u64 GetReg(Reg r);
u64 GetSp();
u64 GetPc();
void SetVec(Vec v, u128 value);
void SetReg(Reg r, u64 value);
void SetSp(u64 value);
u64 ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift);
// Loads and stores - Load/Store Exclusive
bool Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt);
bool STLLR(Imm<2> size, Reg Rn, Reg Rt) override;
bool STLR(Imm<2> size, Reg Rn, Reg Rt) override;
bool LDLAR(Imm<2> size, Reg Rn, Reg Rt) override;
bool LDAR(Imm<2> size, Reg Rn, Reg Rt) override;
// Loads and stores - Load register (literal)
bool LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) override;
bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) override;
// Loads and stores - Load/Store register pair
bool STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Reg Rt2,
Reg Rn, Reg Rt) override;
bool STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Vec Vt2,
Reg Rn, Vec Vt) override;
// Loads and stores - Load/Store register (immediate)
bool RegisterImmediate(bool wback, bool postindex, size_t scale, u64 offset, Imm<2> size,
Imm<2> opc, Reg Rn, Reg Rt);
bool STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn,
Reg Rt) override;
bool STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) override;
bool STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) override;
bool SIMDImmediate(bool wback, bool postindex, size_t scale, u64 offset, MemOp memop, Reg Rn,
Vec Vt);
bool STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn,
Vec Vt) override;
bool STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override;
bool LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn,
Vec Vt) override;
bool LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override;
bool STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override;
bool LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override;
// Loads and stores - Load/Store register (register offset)
bool RegisterOffset(size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm,
Imm<3> option, Reg Rn, Reg Rt);
bool STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Reg Rt) override;
bool LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Reg Rt) override;
bool SIMDOffset(size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Vec Vt);
bool STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Vec Vt) override;
bool LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Vec Vt) override;
private:
Core::Memory::Memory& m_memory;
std::span<u64, 31> m_regs;
std::span<u128, 32> m_fpsimd_regs;
u64& m_sp;
const u64& m_pc;
};
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
fpsimd_context* fpsimd_context);
} // namespace Core

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,6 @@
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/filesystem/filesystem.h"
@ -131,8 +130,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{},
time_manager{system}, gpu_dirty_memory_write_manager{} {
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system},
gpu_dirty_memory_write_manager{} {
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
}
@ -533,7 +532,6 @@ struct System::Impl {
/// Service State
Service::Glue::ARPManager arp_manager;
Service::Account::ProfileManager profile_manager;
Service::Time::TimeManager time_manager;
/// Service manager
@ -923,14 +921,6 @@ const Service::APM::Controller& System::GetAPMController() const {
return impl->apm_controller;
}
Service::Account::ProfileManager& System::GetProfileManager() {
return impl->profile_manager;
}
const Service::Account::ProfileManager& System::GetProfileManager() const {
return impl->profile_manager;
}
Service::Time::TimeManager& System::GetTimeManager() {
return impl->time_manager;
}

View File

@ -45,10 +45,6 @@ class Memory;
namespace Service {
namespace Account {
class ProfileManager;
} // namespace Account
namespace AM::Applets {
struct AppletFrontendSet;
class AppletManager;
@ -387,9 +383,6 @@ public:
[[nodiscard]] Service::APM::Controller& GetAPMController();
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
[[nodiscard]] Service::Account::ProfileManager& GetProfileManager();
[[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const;
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;

View File

@ -359,7 +359,7 @@ private:
void GetActiveChannelCount(HLERequestContext& ctx) {
const auto& sink{system.AudioCore().GetOutputSink()};
u32 channel_count{sink.GetSystemChannels()};
u32 channel_count{sink.GetDeviceChannels()};
LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);

View File

@ -112,19 +112,6 @@ void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
}
}
void AppletResource::FreeAppletResourceId(u64 aruid) {
u64 index = GetIndexFromAruid(aruid);
if (index >= AruidIndexMax) {
return;
}
auto& aruid_data = data[index];
if (aruid_data.flag.is_assigned) {
aruid_data.shared_memory_handle = nullptr;
aruid_data.flag.is_assigned.Assign(false);
}
}
u64 AppletResource::GetActiveAruid() {
return active_aruid;
}
@ -209,80 +196,4 @@ void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) {
data[index].flag.enable_palma_boost_mode.Assign(is_enabled);
}
Result AppletResource::RegisterCoreAppletResource() {
if (ref_counter == std::numeric_limits<s32>::max() - 1) {
return ResultAppletResourceOverflow;
}
if (ref_counter == 0) {
const u64 index = GetIndexFromAruid(0);
if (index < AruidIndexMax) {
return ResultAruidAlreadyRegistered;
}
std::size_t data_index = AruidIndexMax;
for (std::size_t i = 0; i < AruidIndexMax; i++) {
if (!data[i].flag.is_initialized) {
data_index = i;
break;
}
}
if (data_index == AruidIndexMax) {
return ResultAruidNoAvailableEntries;
}
AruidData& aruid_data = data[data_index];
aruid_data.aruid = 0;
aruid_data.flag.is_initialized.Assign(true);
aruid_data.flag.enable_pad_input.Assign(true);
aruid_data.flag.enable_six_axis_sensor.Assign(true);
aruid_data.flag.bit_18.Assign(true);
aruid_data.flag.enable_touchscreen.Assign(true);
data_index = AruidIndexMax;
for (std::size_t i = 0; i < AruidIndexMax; i++) {
if (registration_list.flag[i] == RegistrationStatus::Initialized) {
if (registration_list.aruid[i] != 0) {
continue;
}
data_index = i;
break;
}
if (registration_list.flag[i] == RegistrationStatus::None) {
data_index = i;
break;
}
}
Result result = ResultSuccess;
if (data_index == AruidIndexMax) {
result = CreateAppletResource(0);
} else {
registration_list.flag[data_index] = RegistrationStatus::Initialized;
registration_list.aruid[data_index] = 0;
}
if (result.IsError()) {
UnregisterAppletResourceUserId(0);
return result;
}
}
ref_counter++;
return ResultSuccess;
}
Result AppletResource::UnregisterCoreAppletResource() {
if (ref_counter == 0) {
return ResultAppletResourceNotInitialized;
}
if (--ref_counter == 0) {
UnregisterAppletResourceUserId(0);
}
return ResultSuccess;
}
} // namespace Service::HID

View File

@ -28,8 +28,6 @@ public:
Result RegisterAppletResourceUserId(u64 aruid, bool enable_input);
void UnregisterAppletResourceUserId(u64 aruid);
void FreeAppletResourceId(u64 aruid);
u64 GetActiveAruid();
Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
@ -44,9 +42,6 @@ public:
void SetIsPalmaConnectable(u64 aruid, bool is_connectable);
void EnablePalmaBoostMode(u64 aruid, bool is_enabled);
Result RegisterCoreAppletResource();
Result UnregisterCoreAppletResource();
private:
static constexpr std::size_t AruidIndexMax = 0x20;
@ -86,7 +81,6 @@ private:
u64 active_aruid{};
AruidRegisterList registration_list{};
std::array<AruidData, AruidIndexMax> data{};
s32 ref_counter{};
Core::System& system;
};

View File

@ -20,9 +20,6 @@ constexpr Result InvalidNpadId{ErrorModule::HID, 709};
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
constexpr Result InvalidArraySize{ErrorModule::HID, 715};
constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041};
constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042};
constexpr Result ResultSharedMemoryNotInitialized{ErrorModule::HID, 1043};
constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044};
constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046};
constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047};

View File

@ -222,14 +222,16 @@ void IHidServer::CreateAppletResource(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
Result result = GetResourceManager()->CreateAppletResource(applet_resource_user_id);
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}",
applet_resource_user_id, result.raw);
Result result = GetResourceManager()->CreateAppletResource(applet_resource_user_id);
if (result.IsSuccess()) {
result = GetResourceManager()->GetNpad()->Activate(applet_resource_user_id);
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(result);
rb.PushIpcInterface<IAppletResource>(system, resource_manager, applet_resource_user_id);
rb.PushIpcInterface<IAppletResource>(system, resource_manager);
}
void IHidServer::ActivateDebugPad(HLERequestContext& ctx) {

View File

@ -146,36 +146,10 @@ std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const {
}
Result ResourceManager::CreateAppletResource(u64 aruid) {
if (aruid == 0) {
const auto result = RegisterCoreAppletResource();
if (result.IsError()) {
return result;
}
return GetNpad()->Activate();
}
const auto result = CreateAppletResourceImpl(aruid);
if (result.IsError()) {
return result;
}
return GetNpad()->Activate(aruid);
}
Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
std::scoped_lock lock{shared_mutex};
return applet_resource->CreateAppletResource(aruid);
}
Result ResourceManager::RegisterCoreAppletResource() {
std::scoped_lock lock{shared_mutex};
return applet_resource->RegisterCoreAppletResource();
}
Result ResourceManager::UnregisterCoreAppletResource() {
std::scoped_lock lock{shared_mutex};
return applet_resource->UnregisterCoreAppletResource();
}
Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) {
std::scoped_lock lock{shared_mutex};
return applet_resource->RegisterAppletResourceUserId(aruid, bool_value);
@ -191,11 +165,6 @@ Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle
return applet_resource->GetSharedMemoryHandle(out_handle, aruid);
}
void ResourceManager::FreeAppletResourceId(u64 aruid) {
std::scoped_lock lock{shared_mutex};
applet_resource->FreeAppletResourceId(aruid);
}
void ResourceManager::EnableInput(u64 aruid, bool is_enabled) {
std::scoped_lock lock{shared_mutex};
applet_resource->EnableInput(aruid, is_enabled);
@ -250,10 +219,8 @@ void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
console_six_axis->OnUpdate(core_timing);
}
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
u64 applet_resource_user_id)
: ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id},
resource_manager{resource} {
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource)
: ServiceFramework{system_, "IAppletResource"}, resource_manager{resource} {
static const FunctionInfo functions[] = {
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
};
@ -307,14 +274,14 @@ IAppletResource::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(default_update_event, 0);
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
resource_manager->FreeAppletResourceId(aruid);
}
void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
Kernel::KSharedMemory* handle;
const auto result = resource_manager->GetSharedMemoryHandle(&handle, aruid);
LOG_DEBUG(Service_HID, "called");
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw);
Kernel::KSharedMemory* handle;
const u64 applet_resource_user_id = resource_manager->GetAppletResource()->GetActiveAruid();
const auto result = resource_manager->GetSharedMemoryHandle(&handle, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(result);

View File

@ -66,13 +66,10 @@ public:
Result CreateAppletResource(u64 aruid);
Result RegisterCoreAppletResource();
Result UnregisterCoreAppletResource();
Result RegisterAppletResourceUserId(u64 aruid, bool bool_value);
void UnregisterAppletResourceUserId(u64 aruid);
Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
void FreeAppletResourceId(u64 aruid);
void EnableInput(u64 aruid, bool is_enabled);
void EnableSixAxisSensor(u64 aruid, bool is_enabled);
@ -85,8 +82,6 @@ public:
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
private:
Result CreateAppletResourceImpl(u64 aruid);
bool is_initialized{false};
mutable std::mutex shared_mutex;
@ -126,8 +121,7 @@ private:
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
u64 applet_resource_user_id);
explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource);
~IAppletResource() override;
private:
@ -138,7 +132,6 @@ private:
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
std::shared_ptr<Core::Timing::EventType> motion_update_event;
u64 aruid;
std::shared_ptr<ResourceManager> resource_manager;
};

View File

@ -102,8 +102,8 @@ PresentManager::PresentManager(const vk::Instance& instance_,
memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_},
surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(),
swapchain.GetImageViewFormat())},
use_present_thread{Settings::values.async_presentation.GetValue()} {
SetImageCount();
use_present_thread{Settings::values.async_presentation.GetValue()},
image_count{swapchain.GetImageCount()} {
auto& dld = device.GetLogical();
cmdpool = dld.CreateCommandPool({
@ -292,13 +292,6 @@ void PresentManager::RecreateSwapchain(Frame* frame) {
image_count = swapchain.GetImageCount();
}
void PresentManager::SetImageCount() {
// We cannot have more than 5 images in flight at any given time.
// FRAMES_IN_FLIGHT is 7, and the cache TICKS_TO_DESTROY is 6.
// Mali drivers will give us 6.
image_count = std::min<size_t>(swapchain.GetImageCount(), 5);
}
void PresentManager::CopyToSwapchain(Frame* frame) {
bool requires_recreation = false;

View File

@ -62,8 +62,6 @@ private:
void RecreateSwapchain(Frame* frame);
void SetImageCount();
private:
const vk::Instance& instance;
Core::Frontend::EmuWindow& render_window;

View File

@ -14,8 +14,6 @@
#include "common/fs/path_util.h"
#include "common/string_util.h"
#include "core/constants.h"
#include "core/core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "yuzu/applets/qt_profile_select.h"
#include "yuzu/main.h"
#include "yuzu/util/controller_navigation.h"
@ -49,9 +47,9 @@ QPixmap GetIcon(Common::UUID uuid) {
} // Anonymous namespace
QtProfileSelectionDialog::QtProfileSelectionDialog(
Core::System& system, QWidget* parent,
Core::HID::HIDCore& hid_core, QWidget* parent,
const Core::Frontend::ProfileSelectParameters& parameters)
: QDialog(parent), profile_manager{system.GetProfileManager()} {
: QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) {
outer_layout = new QVBoxLayout;
instruction_label = new QLabel();
@ -70,7 +68,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(
tree_view = new QTreeView;
item_model = new QStandardItemModel(tree_view);
tree_view->setModel(item_model);
controller_navigation = new ControllerNavigation(system.HIDCore(), this);
controller_navigation = new ControllerNavigation(hid_core, this);
tree_view->setAlternatingRowColors(true);
tree_view->setSelectionMode(QHeaderView::SingleSelection);
@ -108,10 +106,10 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(
SelectUser(tree_view->currentIndex());
});
const auto& profiles = profile_manager.GetAllUsers();
const auto& profiles = profile_manager->GetAllUsers();
for (const auto& user : profiles) {
Service::Account::ProfileBase profile{};
if (!profile_manager.GetProfileBase(user, profile))
if (!profile_manager->GetProfileBase(user, profile))
continue;
const auto username = Common::StringFromFixedZeroTerminatedBuffer(
@ -136,7 +134,7 @@ QtProfileSelectionDialog::~QtProfileSelectionDialog() {
int QtProfileSelectionDialog::exec() {
// Skip profile selection when there's only one.
if (profile_manager.GetUserCount() == 1) {
if (profile_manager->GetUserCount() == 1) {
user_index = 0;
return QDialog::Accepted;
}

View File

@ -7,6 +7,7 @@
#include <QDialog>
#include <QList>
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/profile_manager.h"
class ControllerNavigation;
class GMainWindow;
@ -19,19 +20,15 @@ class QStandardItemModel;
class QTreeView;
class QVBoxLayout;
namespace Core {
class System;
}
namespace Service::Account {
class ProfileManager;
}
namespace Core::HID {
class HIDCore;
} // namespace Core::HID
class QtProfileSelectionDialog final : public QDialog {
Q_OBJECT
public:
explicit QtProfileSelectionDialog(Core::System& system, QWidget* parent,
explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent,
const Core::Frontend::ProfileSelectParameters& parameters);
~QtProfileSelectionDialog() override;
@ -61,7 +58,7 @@ private:
QScrollArea* scroll_area;
QDialogButtonBox* buttons;
Service::Account::ProfileManager& profile_manager;
std::unique_ptr<Service::Account::ProfileManager> profile_manager;
ControllerNavigation* controller_navigation = nullptr;
};

View File

@ -381,7 +381,7 @@
<item row="5" column="0">
<widget class="QCheckBox" name="disable_buffer_reorder">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When checked, disables reordering of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When checked, disables reording of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Disable Buffer Reorder</string>

View File

@ -76,9 +76,9 @@ QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_t
}
} // Anonymous namespace
ConfigureProfileManager::ConfigureProfileManager(Core::System& system_, QWidget* parent)
ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureProfileManager>()},
profile_manager{system_.GetProfileManager()}, system{system_} {
profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_} {
ui->setupUi(this);
tree_view = new QTreeView;
@ -149,10 +149,10 @@ void ConfigureProfileManager::SetConfiguration() {
}
void ConfigureProfileManager::PopulateUserList() {
const auto& profiles = profile_manager.GetAllUsers();
const auto& profiles = profile_manager->GetAllUsers();
for (const auto& user : profiles) {
Service::Account::ProfileBase profile{};
if (!profile_manager.GetProfileBase(user, profile))
if (!profile_manager->GetProfileBase(user, profile))
continue;
const auto username = Common::StringFromFixedZeroTerminatedBuffer(
@ -167,11 +167,11 @@ void ConfigureProfileManager::PopulateUserList() {
}
void ConfigureProfileManager::UpdateCurrentUser() {
ui->pm_add->setEnabled(profile_manager.GetUserCount() < Service::Account::MAX_USERS);
ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS);
const auto& current_user = profile_manager.GetUser(Settings::values.current_user.GetValue());
const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
ASSERT(current_user);
const auto username = GetAccountUsername(profile_manager, *current_user);
const auto username = GetAccountUsername(*profile_manager, *current_user);
scene->clear();
scene->addPixmap(
@ -187,11 +187,11 @@ void ConfigureProfileManager::ApplyConfiguration() {
void ConfigureProfileManager::SelectUser(const QModelIndex& index) {
Settings::values.current_user =
std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager.GetUserCount() - 1));
std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager->GetUserCount() - 1));
UpdateCurrentUser();
ui->pm_remove->setEnabled(profile_manager.GetUserCount() >= 2);
ui->pm_remove->setEnabled(profile_manager->GetUserCount() >= 2);
ui->pm_rename->setEnabled(true);
ui->pm_set_image->setEnabled(true);
}
@ -204,18 +204,18 @@ void ConfigureProfileManager::AddUser() {
}
const auto uuid = Common::UUID::MakeRandom();
profile_manager.CreateNewUser(uuid, username.toStdString());
profile_manager->CreateNewUser(uuid, username.toStdString());
item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
}
void ConfigureProfileManager::RenameUser() {
const auto user = tree_view->currentIndex().row();
const auto uuid = profile_manager.GetUser(user);
const auto uuid = profile_manager->GetUser(user);
ASSERT(uuid);
Service::Account::ProfileBase profile{};
if (!profile_manager.GetProfileBase(*uuid, profile))
if (!profile_manager->GetProfileBase(*uuid, profile))
return;
const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:"));
@ -227,7 +227,7 @@ void ConfigureProfileManager::RenameUser() {
std::fill(profile.username.begin(), profile.username.end(), '\0');
std::copy(username_std.begin(), username_std.end(), profile.username.begin());
profile_manager.SetProfileBase(*uuid, profile);
profile_manager->SetProfileBase(*uuid, profile);
item_model->setItem(
user, 0,
@ -238,9 +238,9 @@ void ConfigureProfileManager::RenameUser() {
void ConfigureProfileManager::ConfirmDeleteUser() {
const auto index = tree_view->currentIndex().row();
const auto uuid = profile_manager.GetUser(index);
const auto uuid = profile_manager->GetUser(index);
ASSERT(uuid);
const auto username = GetAccountUsername(profile_manager, *uuid);
const auto username = GetAccountUsername(*profile_manager, *uuid);
confirm_dialog->SetInfo(username, *uuid, [this, uuid]() { DeleteUser(*uuid); });
confirm_dialog->show();
@ -252,7 +252,7 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) {
}
UpdateCurrentUser();
if (!profile_manager.RemoveUser(uuid)) {
if (!profile_manager->RemoveUser(uuid)) {
return;
}
@ -265,7 +265,7 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) {
void ConfigureProfileManager::SetUserImage() {
const auto index = tree_view->currentIndex().row();
const auto uuid = profile_manager.GetUser(index);
const auto uuid = profile_manager->GetUser(index);
ASSERT(uuid);
const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(),
@ -317,7 +317,7 @@ void ConfigureProfileManager::SetUserImage() {
}
}
const auto username = GetAccountUsername(profile_manager, *uuid);
const auto username = GetAccountUsername(*profile_manager, *uuid);
item_model->setItem(index, 0,
new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)});
UpdateCurrentUser();

View File

@ -52,7 +52,7 @@ class ConfigureProfileManager : public QWidget {
Q_OBJECT
public:
explicit ConfigureProfileManager(Core::System& system_, QWidget* parent = nullptr);
explicit ConfigureProfileManager(const Core::System& system_, QWidget* parent = nullptr);
~ConfigureProfileManager() override;
void ApplyConfiguration();
@ -85,6 +85,7 @@ private:
std::unique_ptr<Ui::ConfigureProfileManager> ui;
bool enabled = false;
Service::Account::ProfileManager& profile_manager;
std::unique_ptr<Service::Account::ProfileManager> profile_manager;
const Core::System& system;
};

View File

@ -346,7 +346,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
discord_rpc->Update();
play_time_manager = std::make_unique<PlayTime::PlayTimeManager>(system->GetProfileManager());
play_time_manager = std::make_unique<PlayTime::PlayTimeManager>();
system->GetRoomNetwork().Init();
@ -526,7 +526,8 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
continue;
}
if (!system->GetProfileManager().UserExistsIndex(selected_user)) {
const Service::Account::ProfileManager manager;
if (!manager.UserExistsIndex(selected_user)) {
LOG_ERROR(Frontend, "Selected user doesn't exist");
continue;
}
@ -690,7 +691,7 @@ void GMainWindow::ControllerSelectorRequestExit() {
void GMainWindow::ProfileSelectorSelectProfile(
const Core::Frontend::ProfileSelectParameters& parameters) {
profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters);
profile_select_applet = new QtProfileSelectionDialog(system->HIDCore(), this, parameters);
SCOPE_EXIT({
profile_select_applet->deleteLater();
profile_select_applet = nullptr;
@ -705,8 +706,8 @@ void GMainWindow::ProfileSelectorSelectProfile(
return;
}
const auto uuid = system->GetProfileManager().GetUser(
static_cast<std::size_t>(profile_select_applet->GetIndex()));
const Service::Account::ProfileManager manager;
const auto uuid = manager.GetUser(static_cast<std::size_t>(profile_select_applet->GetIndex()));
if (!uuid.has_value()) {
emit ProfileSelectorFinishedSelection(std::nullopt);
return;
@ -1855,7 +1856,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
bool GMainWindow::SelectAndSetCurrentUser(
const Core::Frontend::ProfileSelectParameters& parameters) {
QtProfileSelectionDialog dialog(*system, this, parameters);
QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
@ -2270,7 +2271,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
.display_options = {},
.purpose = Service::AM::Applets::UserSelectionPurpose::General,
};
QtProfileSelectionDialog dialog(*system, this, parameters);
QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
@ -2287,8 +2288,8 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
return;
}
const auto user_id =
system->GetProfileManager().GetUser(static_cast<std::size_t>(index));
Service::Account::ProfileManager manager;
const auto user_id = manager.GetUser(static_cast<std::size_t>(index));
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(

View File

@ -27,9 +27,9 @@
Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
ui(std::make_unique<Ui::Lobby>()),
announce_multiplayer_session(session), system{system_}, room_network{
system.GetRoomNetwork()} {
ui(std::make_unique<Ui::Lobby>()), announce_multiplayer_session(session),
profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_},
room_network{system.GetRoomNetwork()} {
ui->setupUi(this);
// setup the watcher for background connections
@ -299,15 +299,14 @@ void Lobby::OnRefreshLobby() {
}
std::string Lobby::GetProfileUsername() {
const auto& current_user =
system.GetProfileManager().GetUser(Settings::values.current_user.GetValue());
const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
Service::Account::ProfileBase profile{};
if (!current_user.has_value()) {
return "";
}
if (!system.GetProfileManager().GetProfileBase(*current_user, profile)) {
if (!profile_manager->GetProfileBase(*current_user, profile)) {
return "";
}

View File

@ -24,6 +24,10 @@ namespace Core {
class System;
}
namespace Service::Account {
class ProfileManager;
}
/**
* Listing of all public games pulled from services. The lobby should be simple enough for users to
* find the game they want to play, and join it.
@ -99,6 +103,7 @@ private:
QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher;
std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
std::unique_ptr<Service::Account::ProfileManager> profile_manager;
QFutureWatcher<void>* watcher;
Validation validation;
Core::System& system;

View File

@ -20,8 +20,8 @@ struct PlayTimeElement {
PlayTime play_time;
};
std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
const Service::Account::ProfileManager& manager) {
std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() {
const Service::Account::ProfileManager manager;
const auto uuid = manager.GetUser(static_cast<s32>(Settings::values.current_user));
if (!uuid.has_value()) {
return std::nullopt;
@ -30,9 +30,8 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
uuid->RawString().append(".bin");
}
[[nodiscard]] bool ReadPlayTimeFile(PlayTimeDatabase& out_play_time_db,
const Service::Account::ProfileManager& manager) {
const auto filename = GetCurrentUserPlayTimePath(manager);
[[nodiscard]] bool ReadPlayTimeFile(PlayTimeDatabase& out_play_time_db) {
const auto filename = GetCurrentUserPlayTimePath();
if (!filename.has_value()) {
LOG_ERROR(Frontend, "Failed to get current user path");
@ -67,9 +66,8 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
return true;
}
[[nodiscard]] bool WritePlayTimeFile(const PlayTimeDatabase& play_time_db,
const Service::Account::ProfileManager& manager) {
const auto filename = GetCurrentUserPlayTimePath(manager);
[[nodiscard]] bool WritePlayTimeFile(const PlayTimeDatabase& play_time_db) {
const auto filename = GetCurrentUserPlayTimePath();
if (!filename.has_value()) {
LOG_ERROR(Frontend, "Failed to get current user path");
@ -98,9 +96,8 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
} // namespace
PlayTimeManager::PlayTimeManager(Service::Account::ProfileManager& profile_manager)
: manager{profile_manager} {
if (!ReadPlayTimeFile(database, manager)) {
PlayTimeManager::PlayTimeManager() {
if (!ReadPlayTimeFile(database)) {
LOG_ERROR(Frontend, "Failed to read play time database! Resetting to default.");
}
}
@ -145,7 +142,7 @@ void PlayTimeManager::AutoTimestamp(std::stop_token stop_token) {
}
void PlayTimeManager::Save() {
if (!WritePlayTimeFile(database, manager)) {
if (!WritePlayTimeFile(database)) {
LOG_ERROR(Frontend, "Failed to update play time database!");
}
}

View File

@ -11,10 +11,6 @@
#include "common/common_types.h"
#include "common/polyfill_thread.h"
namespace Service::Account {
class ProfileManager;
}
namespace PlayTime {
using ProgramId = u64;
@ -23,7 +19,7 @@ using PlayTimeDatabase = std::map<ProgramId, PlayTime>;
class PlayTimeManager {
public:
explicit PlayTimeManager(Service::Account::ProfileManager& profile_manager);
explicit PlayTimeManager();
~PlayTimeManager();
YUZU_NON_COPYABLE(PlayTimeManager);
@ -36,13 +32,11 @@ public:
void Stop();
private:
void AutoTimestamp(std::stop_token stop_token);
void Save();
PlayTimeDatabase database;
u64 running_program_id;
std::jthread play_time_thread;
Service::Account::ProfileManager& manager;
void AutoTimestamp(std::stop_token stop_token);
void Save();
};
QString ReadablePlayTime(qulonglong time_seconds);

View File

@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "yuzu",
"builtin-baseline": "a42af01b72c28a8e1d7b48107b33e4f286a55ef6",
"builtin-baseline": "cbf56573a987527b39272e88cbdd11389b78c6e4",
"version": "1.0",
"dependencies": [
"boost-algorithm",
@ -50,7 +50,7 @@
},
{
"name": "fmt",
"version": "10.1.1"
"version": "10.0.0"
}
]
}