From e6d1905a5f6ba6aa5037790e11e76d501ed53617 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Tue, 6 Jun 2023 04:13:58 +0200 Subject: [PATCH] early-access version 3639 --- CMakeLists.txt | 4 +- README.md | 2 +- .../yuzu_emu/activities/EmulationActivity.kt | 6 + .../yuzu/yuzu_emu/adapters/LicenseAdapter.kt | 54 ++ .../keyboard/ui/KeyboardDialogFragment.kt | 2 +- .../features/settings/model/Settings.kt | 7 +- .../settings/model/view/SubmenuSetting.kt | 3 +- .../settings/ui/SettingsFragmentPresenter.kt | 61 +- .../features/settings/utils/SettingsFile.kt | 9 +- .../yuzu/yuzu_emu/fragments/AboutFragment.kt | 10 +- .../yuzu_emu/fragments/EmulationFragment.kt | 1 + .../LicenseBottomSheetDialogFragment.kt | 59 ++ .../yuzu_emu/fragments/LicensesFragment.kt | 137 ++++ .../java/org/yuzu/yuzu_emu/model/License.kt | 16 + .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 4 + .../src/main/res/layout/dialog_license.xml | 64 ++ .../src/main/res/layout/fragment_about.xml | 33 + .../src/main/res/layout/fragment_licenses.xml | 30 + .../main/res/navigation/home_navigation.xml | 11 +- .../app/src/main/res/values/arrays.xml | 52 +- .../app/src/main/res/values/strings.xml | 608 ++++++++++++++++-- .../renderer/adsp/audio_renderer.cpp | 8 +- src/audio_core/renderer/adsp/audio_renderer.h | 4 +- src/audio_core/sink/sink_stream.cpp | 5 +- src/audio_core/sink/sink_stream.h | 5 +- 25 files changed, 1068 insertions(+), 127 deletions(-) create mode 100755 src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt create mode 100755 src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt create mode 100755 src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt create mode 100755 src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt create mode 100755 src/android/app/src/main/res/layout/dialog_license.xml create mode 100755 src/android/app/src/main/res/layout/fragment_licenses.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 21965d38a..9e41cf96d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -487,7 +487,7 @@ if (ENABLE_SDL2) if (YUZU_USE_BUNDLED_SDL2) # Detect toolchain and platform if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) - set(SDL2_VER "SDL2-2.0.18") + set(SDL2_VER "SDL2-2.26.5") else() message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") endif() @@ -507,7 +507,7 @@ if (ENABLE_SDL2) elseif (YUZU_USE_EXTERNAL_SDL2) message(STATUS "Using SDL2 from externals.") else() - find_package(SDL2 2.0.18 REQUIRED) + find_package(SDL2 2.26.4 REQUIRED) endif() endif() diff --git a/README.md b/README.md index 490874d84..b2feeaefe 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3638. +This is the source code for early-access 3639. ## Legal Notice diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 901a3978d..94d5156cf 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -21,6 +21,7 @@ import android.view.MotionEvent import android.view.Surface import android.view.View import android.view.inputmethod.InputMethodManager +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.content.getSystemService import androidx.core.view.WindowCompat @@ -34,6 +35,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.fragments.EmulationFragment import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.utils.ControllerMappingHelper @@ -60,6 +62,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private lateinit var game: Game + private val settingsViewModel: SettingsViewModel by viewModels() + override fun onDestroy() { stopForegroundService(this) super.onDestroy() @@ -68,6 +72,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { override fun onCreate(savedInstanceState: Bundle?) { ThemeHelper.setTheme(this) + settingsViewModel.settings.loadSettings() + super.onCreate(savedInstanceState) if (savedInstanceState == null) { // Get params we were passed diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt new file mode 100755 index 000000000..7006651d0 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.adapters + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import org.yuzu.yuzu_emu.YuzuApplication +import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding +import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment +import org.yuzu.yuzu_emu.model.License + +class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List) : + RecyclerView.Adapter(), + View.OnClickListener { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder { + val binding = + ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false) + binding.root.setOnClickListener(this) + return LicenseViewHolder(binding) + } + + override fun getItemCount(): Int = licenses.size + + override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) { + holder.bind(licenses[position]) + } + + override fun onClick(view: View) { + val license = (view.tag as LicenseViewHolder).license + LicenseBottomSheetDialogFragment.newInstance(license) + .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG) + } + + inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) { + lateinit var license: License + + init { + itemView.tag = this + } + + fun bind(license: License) { + this.license = license + + val context = YuzuApplication.appContext + binding.textSettingName.text = context.getString(license.titleId) + binding.textSettingDescription.text = context.getString(license.descriptionId) + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt index 4b12809bc..607a3d506 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/ui/KeyboardDialogFragment.kt @@ -63,7 +63,7 @@ class KeyboardDialogFragment : DialogFragment() { val headerText = config.header_text!!.ifEmpty { resources.getString(R.string.software_keyboard) } val okText = - config.ok_text!!.ifEmpty { resources.getString(android.R.string.ok) } + config.ok_text!!.ifEmpty { resources.getString(R.string.submit) } return MaterialAlertDialogBuilder(requireContext()) .setTitle(headerText) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 23c31e13a..8df20b928 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -39,7 +39,7 @@ class Settings { val isEmpty: Boolean get() = sections.isEmpty() - fun loadSettings(view: SettingsActivityView) { + fun loadSettings(view: SettingsActivityView? = null) { sections = SettingsSectionMap() loadYuzuSettings(view) if (!TextUtils.isEmpty(gameId)) { @@ -48,13 +48,13 @@ class Settings { isLoaded = true } - private fun loadYuzuSettings(view: SettingsActivityView) { + private fun loadYuzuSettings(view: SettingsActivityView?) { for ((fileName) in configFileSectionsMap) { sections.putAll(SettingsFile.readFile(fileName, view)) } } - private fun loadCustomGameSettings(gameId: String, view: SettingsActivityView) { + private fun loadCustomGameSettings(gameId: String, view: SettingsActivityView?) { // Custom game settings mergeSections(SettingsFile.readCustomGameSettings(gameId, view)) } @@ -108,6 +108,7 @@ class Settings { const val SECTION_AUDIO = "Audio" const val SECTION_CPU = "Cpu" const val SECTION_THEME = "Theme" + const val SECTION_DEBUG = "Debug" const val PREF_OVERLAY_INIT = "OverlayInit" const val PREF_CONTROL_SCALE = "controlScale" diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt index 8c1af6396..a3ef59c2f 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt @@ -6,10 +6,9 @@ package org.yuzu.yuzu_emu.features.settings.model.view import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting class SubmenuSetting( - setting: AbstractSetting?, titleId: Int, descriptionId: Int, val menuKey: String -) : SettingsItem(setting, titleId, descriptionId) { +) : SettingsItem(null, titleId, descriptionId) { override val type = TYPE_SUBMENU } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 7d55c5b2f..061046b2e 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -68,6 +68,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) Settings.SECTION_RENDERER -> addGraphicsSettings(sl) Settings.SECTION_AUDIO -> addAudioSettings(sl) Settings.SECTION_THEME -> addThemeSettings(sl) + Settings.SECTION_DEBUG -> addDebugSettings(sl) else -> { fragmentView.showToastMessage("Unimplemented menu", false) return @@ -78,11 +79,10 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) } private fun addConfigSettings(sl: ArrayList) { - settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_advanced_settings)) + settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.advanced_settings)) sl.apply { add( SubmenuSetting( - null, R.string.preferences_general, 0, Settings.SECTION_GENERAL @@ -90,7 +90,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) add( SubmenuSetting( - null, R.string.preferences_system, 0, Settings.SECTION_SYSTEM @@ -98,7 +97,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) add( SubmenuSetting( - null, R.string.preferences_graphics, 0, Settings.SECTION_RENDERER @@ -106,12 +104,18 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) add( SubmenuSetting( - null, R.string.preferences_audio, 0, Settings.SECTION_AUDIO ) ) + add( + SubmenuSetting( + R.string.preferences_debug, + 0, + Settings.SECTION_DEBUG + ) + ) add( RunnableSetting( R.string.reset_to_default, @@ -223,17 +227,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) private fun addGraphicsSettings(sl: ArrayList) { settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_graphics)) sl.apply { - add( - SingleChoiceSetting( - IntSetting.RENDERER_BACKEND, - R.string.renderer_api, - 0, - R.array.rendererApiNames, - R.array.rendererApiValues, - IntSetting.RENDERER_BACKEND.key, - IntSetting.RENDERER_BACKEND.defaultValue - ) - ) + add( SingleChoiceSetting( IntSetting.RENDERER_ACCURACY, @@ -327,15 +321,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) IntSetting.RENDERER_ASYNCHRONOUS_SHADERS.defaultValue ) ) - add( - SwitchSetting( - IntSetting.RENDERER_DEBUG, - R.string.renderer_debug, - R.string.renderer_debug_description, - IntSetting.RENDERER_DEBUG.key, - IntSetting.RENDERER_DEBUG.defaultValue - ) - ) } } @@ -451,4 +436,30 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) ) } } + + private fun addDebugSettings(sl: ArrayList) { + settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_debug)) + sl.apply { + add( + SingleChoiceSetting( + IntSetting.RENDERER_BACKEND, + R.string.renderer_api, + 0, + R.array.rendererApiNames, + R.array.rendererApiValues, + IntSetting.RENDERER_BACKEND.key, + IntSetting.RENDERER_BACKEND.defaultValue + ) + ) + add( + SwitchSetting( + IntSetting.RENDERER_DEBUG, + R.string.renderer_debug, + R.string.renderer_debug_description, + IntSetting.RENDERER_DEBUG.key, + IntSetting.RENDERER_DEBUG.defaultValue + ) + ) + } + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt index c502fdca0..e29bca11d 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt @@ -37,7 +37,7 @@ object SettingsFile { private fun readFile( ini: File?, isCustomGame: Boolean, - view: SettingsActivityView? + view: SettingsActivityView? = null ): HashMap { val sections: HashMap = SettingsSectionMap() var reader: BufferedReader? = null @@ -74,10 +74,13 @@ object SettingsFile { return sections } - fun readFile(fileName: String, view: SettingsActivityView): HashMap { + fun readFile(fileName: String, view: SettingsActivityView?): HashMap { return readFile(getSettingsFile(fileName), false, view) } + fun readFile(fileName: String): HashMap = + readFile(getSettingsFile(fileName), false) + /** * Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it @@ -88,7 +91,7 @@ object SettingsFile { */ fun readCustomGameSettings( gameId: String, - view: SettingsActivityView + view: SettingsActivityView? ): HashMap { return readFile(getCustomGameSettingsFile(gameId), true, view) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt index 0314feff6..c92e2755c 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt @@ -15,13 +15,12 @@ import android.view.View import android.view.ViewGroup import android.view.ViewGroup.MarginLayoutParams import android.widget.Toast -import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.navigation.fragment.findNavController +import androidx.navigation.findNavController import com.google.android.material.transition.MaterialSharedAxis import org.yuzu.yuzu_emu.BuildConfig import org.yuzu.yuzu_emu.R @@ -38,6 +37,7 @@ class AboutFragment : Fragment() { super.onCreate(savedInstanceState) enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) + reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) } override fun onCreateView( @@ -54,7 +54,7 @@ class AboutFragment : Fragment() { homeViewModel.setStatusBarShadeVisibility(visible = false) binding.toolbarAbout.setNavigationOnClickListener { - parentFragmentManager.primaryNavigationFragment?.findNavController()?.popBackStack() + binding.root.findNavController().popBackStack() } binding.imageLogo.setOnLongClickListener { @@ -67,6 +67,10 @@ class AboutFragment : Fragment() { } binding.buttonContributors.setOnClickListener { openLink(getString(R.string.contributors_link)) } + binding.buttonLicenses.setOnClickListener { + exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) + binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) + } binding.textBuildHash.text = BuildConfig.GIT_HASH binding.buttonBuildHash.setOnClickListener { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 1a9843fcc..41b1a6e23 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -314,6 +314,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { .setPositiveButton(android.R.string.ok) { _, _ -> refreshInputOverlay() } + .setNegativeButton(android.R.string.cancel, null) .setNeutralButton(R.string.emulation_toggle_all) { _, _ -> } .show() diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt new file mode 100755 index 000000000..78419191c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicenseBottomSheetDialogFragment.kt @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import org.yuzu.yuzu_emu.databinding.DialogLicenseBinding +import org.yuzu.yuzu_emu.model.License +import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable + +class LicenseBottomSheetDialogFragment : BottomSheetDialogFragment() { + private var _binding: DialogLicenseBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = DialogLicenseBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + BottomSheetBehavior.from(view.parent as View).state = + BottomSheetBehavior.STATE_HALF_EXPANDED + + val license = requireArguments().parcelable(LICENSE)!! + + binding.apply { + textTitle.setText(license.titleId) + textLink.setText(license.linkId) + textCopyright.setText(license.copyrightId) + textLicense.setText(license.licenseId) + } + } + + companion object { + const val TAG = "LicenseBottomSheetDialogFragment" + + const val LICENSE = "License" + + fun newInstance( + license: License + ): LicenseBottomSheetDialogFragment { + val dialog = LicenseBottomSheetDialogFragment() + val bundle = Bundle() + bundle.putParcelable(LICENSE, license) + dialog.arguments = bundle + return dialog + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt new file mode 100755 index 000000000..59141e823 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt @@ -0,0 +1,137 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.MarginLayoutParams +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.transition.MaterialSharedAxis +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.adapters.LicenseAdapter +import org.yuzu.yuzu_emu.databinding.FragmentLicensesBinding +import org.yuzu.yuzu_emu.model.HomeViewModel +import org.yuzu.yuzu_emu.model.License + +class LicensesFragment : Fragment() { + private var _binding: FragmentLicensesBinding? = null + private val binding get() = _binding!! + + private val homeViewModel: HomeViewModel by activityViewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) + returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentLicensesBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + homeViewModel.setNavigationVisibility(visible = false, animated = true) + homeViewModel.setStatusBarShadeVisibility(visible = false) + + binding.toolbarLicenses.setNavigationOnClickListener { + binding.root.findNavController().popBackStack() + } + + val licenses = listOf( + License( + R.string.license_fidelityfx_fsr, + R.string.license_fidelityfx_fsr_description, + R.string.license_fidelityfx_fsr_link, + R.string.license_fidelityfx_fsr_copyright, + R.string.license_fidelityfx_fsr_text + ), + License( + R.string.license_cubeb, + R.string.license_cubeb_description, + R.string.license_cubeb_link, + R.string.license_cubeb_copyright, + R.string.license_cubeb_text + ), + License( + R.string.license_dynarmic, + R.string.license_dynarmic_description, + R.string.license_dynarmic_link, + R.string.license_dynarmic_copyright, + R.string.license_dynarmic_text + ), + License( + R.string.license_ffmpeg, + R.string.license_ffmpeg_description, + R.string.license_ffmpeg_link, + R.string.license_ffmpeg_copyright, + R.string.license_ffmpeg_text + ), + License( + R.string.license_opus, + R.string.license_opus_description, + R.string.license_opus_link, + R.string.license_opus_copyright, + R.string.license_opus_text + ), + License( + R.string.license_sirit, + R.string.license_sirit_description, + R.string.license_sirit_link, + R.string.license_sirit_copyright, + R.string.license_sirit_text + ), + License( + R.string.license_adreno_tools, + R.string.license_adreno_tools_description, + R.string.license_adreno_tools_link, + R.string.license_adreno_tools_copyright, + R.string.license_adreno_tools_text + ) + ) + + binding.listLicenses.apply { + layoutManager = LinearLayoutManager(requireContext()) + adapter = LicenseAdapter(requireActivity() as AppCompatActivity, licenses) + } + + setInsets() + } + + private fun setInsets() = + ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat -> + val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) + val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) + + val leftInsets = barInsets.left + cutoutInsets.left + val rightInsets = barInsets.right + cutoutInsets.right + + val mlpAppBar = binding.appbarLicenses.layoutParams as MarginLayoutParams + mlpAppBar.leftMargin = leftInsets + mlpAppBar.rightMargin = rightInsets + binding.appbarLicenses.layoutParams = mlpAppBar + + val mlpScrollAbout = binding.listLicenses.layoutParams as MarginLayoutParams + mlpScrollAbout.leftMargin = leftInsets + mlpScrollAbout.rightMargin = rightInsets + binding.listLicenses.layoutParams = mlpScrollAbout + + binding.listLicenses.updatePadding(bottom = barInsets.bottom) + + windowInsets + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt new file mode 100755 index 000000000..f24d5cf34 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/License.kt @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class License( + val titleId: Int, + val descriptionId: Int, + val linkId: Int, + val copyrightId: Int, + val licenseId: Int +) : Parcelable diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index f8bca11bb..134085210 100755 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -35,6 +35,7 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.databinding.ActivityMainBinding import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding import org.yuzu.yuzu_emu.features.settings.model.Settings +import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile import org.yuzu.yuzu_emu.fragments.MessageDialogFragment @@ -48,6 +49,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { private val homeViewModel: HomeViewModel by viewModels() private val gamesViewModel: GamesViewModel by viewModels() + private val settingsViewModel: SettingsViewModel by viewModels() override var themeId: Int = 0 @@ -55,6 +57,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { val splashScreen = installSplashScreen() splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } + settingsViewModel.settings.loadSettings() + ThemeHelper.setTheme(this) super.onCreate(savedInstanceState) diff --git a/src/android/app/src/main/res/layout/dialog_license.xml b/src/android/app/src/main/res/layout/dialog_license.xml new file mode 100755 index 000000000..866857562 --- /dev/null +++ b/src/android/app/src/main/res/layout/dialog_license.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml index 549f00aa5..3e1d98451 100755 --- a/src/android/app/src/main/res/layout/fragment_about.xml +++ b/src/android/app/src/main/res/layout/fragment_about.xml @@ -109,6 +109,39 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/android/app/src/main/res/navigation/home_navigation.xml b/src/android/app/src/main/res/navigation/home_navigation.xml index 2275ddc32..48072683e 100755 --- a/src/android/app/src/main/res/navigation/home_navigation.xml +++ b/src/android/app/src/main/res/navigation/home_navigation.xml @@ -40,11 +40,20 @@ + android:label="AboutFragment" > + + + + diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index fa88770c8..ea20cb17c 100755 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -2,67 +2,67 @@ - @string/region_auto - @string/region_japan - @string/region_usa - @string/region_europe + @string/auto @string/region_australia @string/region_china + @string/region_europe + @string/region_japan @string/region_korea @string/region_taiwan + @string/region_usa -1 - 0 - 1 - 2 3 4 + 2 + 0 5 6 + 1 - @string/language_japanese + @string/language_brazilian_portuguese + @string/language_british_english + @string/language_canadian_french + @string/language_chinese + @string/language_dutch @string/language_english @string/language_french @string/langauge_german @string/language_italian - @string/language_spanish - @string/language_chinese + @string/language_japanese @string/language_korean - @string/language_dutch + @string/language_latin_american_spanish @string/language_portuguese @string/language_russian - @string/language_taiwanese - @string/language_british_english - @string/language_canadian_french - @string/language_latin_american_spanish @string/language_simplified_chinese + @string/language_spanish + @string/language_taiwanese @string/language_traditional_chinese - @string/language_brazilian_portuguese - 0 + 17 + 12 + 13 + 6 + 8 1 2 3 4 - 5 - 6 + 0 7 - 8 + 14 9 10 - 11 - 12 - 13 - 14 15 + 5 + 11 16 - 17 @@ -166,7 +166,7 @@ - @string/cpu_accuracy_auto + @string/auto @string/cpu_accuracy_accurate @string/cpu_accuracy_unsafe @string/cpu_accuracy_paranoid diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index fc24e27f5..b86f45385 100755 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -41,7 +41,7 @@ Skip selecting games folder? Games won\'t be displayed in the Games list if a folder isn\'t selected. https://yuzu-emu.org/help/quickstart/#dumping-games - Search Games + Search games Games directory selected Install prod.keys Required to decrypt retail games @@ -77,8 +77,8 @@ Install alternative drivers for potentially better performance or accuracy Advanced settings Configure emulator settings - Recently Played - Recently Added + Recently played + Recently added Retail Homebrew Open yuzu folder @@ -104,6 +104,7 @@ Contributors Made with \u2764 from the yuzu team https://github.com/yuzu-emu/yuzu/graphs/contributors + Projects that make yuzu for Android possible Build https://discord.gg/u77vRWY https://yuzu-emu.org/ @@ -124,39 +125,39 @@ Are you interested? - Enable limit speed - When enabled, emulation speed will be limited to a specified percentage of normal speed. + Limit speed + Limits emulation speed to a specified percentage of normal speed. Limit speed percent - Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit. + Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit. CPU accuracy - Docked mode - Emulates in docked mode, which increases the resolution at the expense of performance. + Docked Mode + Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance. Emulated region Emulated language - Select RTC Date - Select RTC Time - Enable Custom RTC - This setting allows you to set a custom real time clock separate from your current system time - Set Custom RTC + Select RTC date + Select RTC time + Custom RTC + Allows you to set a custom real-time clock separate from your current system time. + Set custom RTC API Accuracy level - Resolution + Resolution (Handheld/Docked) VSync mode - Aspect Ratio - Window Adapting Filter - Anti-Aliasing Method + Aspect ratio + Window adapting filter + Anti-aliasing method Force maximum clocks (Adreno only) Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied). Use asynchronous shaders - Compiles shaders asynchronously, which will reduce stutter but may introduce glitches. - Enable graphics debugging - When checked, the graphics API enters a slower debugging mode. - Use disk shader cache - Reduce stuttering by storing and loading generated shaders to disk. + Compiles shaders asynchronously, reducing stutter but may introduce glitches. + Graphics debugging + Sets the graphics API to a slow debugging mode. + Disk shader cache + Reduces stuttering by locally storing and loading generated shaders. Volume @@ -171,10 +172,12 @@ Do you want to reset this setting back to its default value? Reset to default Reset all settings? - All Advanced Settings will be reset to their default configuration. This can not be undone. + All advanced settings will be reset to their default configuration. This can not be undone. Settings reset Close - Learn More + Learn more + Auto + Submit Select GPU driver @@ -188,13 +191,13 @@ Installing driver… - Advanced Settings Settings General System Graphics Audio Theme and color + Debug Your ROM is encrypted @@ -206,29 +209,29 @@ ROM file does not exist - Exit Emulation + Exit emulation Done - FPS Counter - Toggle Controls - Relative Stick Center - DPad Slide - Haptics - Show Overlay - Toggle All - Adjust Overlay + FPS counter + Toggle controls + Relative stick center + D-pad slide + Touch haptics + Show overlay + Toggle all + Adjust overlay Scale Opacity - Reset Overlay - Edit Overlay - Pause Emulation - Unpause Emulation - Overlay Options + Reset overlay + Edit overlay + Pause emulation + Unpause emulation + Overlay options Game loading… - Loading Settings… + Loading settings… - Software Keyboard + Software keyboard Abort @@ -242,7 +245,6 @@ Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled. - Auto-select Japan USA Europe @@ -312,18 +314,17 @@ Force 4:3 Force 21:9 Force 16:10 - Stretch to Window + Stretch to window - Auto Accurate Unsafe Paranoid (Slow) - D-Pad - Left Stick - Right Stick + D-pad + Left stick + Right stick Home Screenshot @@ -332,18 +333,525 @@ Building shaders - Change App Theme + Change app theme Default Material You - Change Theme Mode + Change theme mode Follow System Light Dark - Use Black Backgrounds + Black backgrounds When using the dark theme, apply black backgrounds. + + Licenses + FidelityFX-FSR + High-quality upscaling from AMD + https://github.com/GPUOpen-Effects/FidelityFX-FSR + Copyright © 2021 Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the \"Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:\n\n + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software.\n\n + +THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + cubeb + Cross platform audio library + https://github.com/mozilla/cubeb + Copyright © 2011 Mozilla Foundation + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies.\n\n + +THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + Dynarmic + An ARM dynamic recompiler + https://github.com/merryhime/dynarmic + Copyright © 2017 merryhime + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted.\n\n + +THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + FFmpeg + FFmpeg is a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata. + https://github.com/FFmpeg/FFmpeg + Copyright © 1991, 1999 Free Software Foundation, Inc. + +GNU LESSER GENERAL PUBLIC LICENSE\n +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called \"this License\"). +Each licensee is addressed as \"you\".\n\n + + A \"library\" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables.\n\n + + The \"Library\", below, refers to any such software library or work +which has been distributed under these terms. A \"work based on the +Library\" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term \"modification\".)\n\n + + \"Source code\" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library.\n\n + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does.\n\n + + 1. You may copy and distribute verbatim copies of the Library\'s +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library.\n\n + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee.\n\n + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions:\n\n + +a) The modified work must itself be a software library.\n\n + +b) You must cause the files modified to carry prominent notices +stating that you changed the files and the date of any change.\n\n + +c) You must cause the whole of the work to be licensed at no +charge to all third parties under the terms of this License.\n\n + +d) If a facility in the modified Library refers to a function or a +table of data to be supplied by an application program that uses +the facility, other than as an argument passed when the facility +is invoked, then you must make a good faith effort to ensure that, +in the event an application does not supply such function or +table, the facility still operates, and performs whatever part of +its purpose remains meaningful.\n\n + +(For example, a function in a library to compute square roots has +a purpose that is entirely well-defined independent of the +application. Therefore, Subsection 2d requires that any +application-supplied function or table used by this function must +be optional: if the application does not supply it, the square +root function must still compute square roots.)\n\n + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it.\n\n + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library.\n\n + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License.\n\n + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices.\n\n + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy.\n\n + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library.\n\n + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange.\n\n + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code.\n\n + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a \"work that uses the Library\". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License.\n\n + + However, linking a \"work that uses the Library\" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a \"work that uses the +library\". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables.\n\n + + When a \"work that uses the Library\" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law.\n\n + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.)\n\n + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself.\n\n + + 6. As an exception to the Sections above, you may also combine or +link a \"work that uses the Library\" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer\'s own use and reverse +engineering for debugging such modifications.\n\n + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things:\n\n + +a) Accompany the work with the complete corresponding +machine-readable source code for the Library including whatever +changes were used in the work (which must be distributed under +Sections 1 and 2 above); and, if the work is an executable linked +with the Library, with the complete machine-readable \"work that +uses the Library\", as object code and/or source code, so that the +user can modify the Library and then relink to produce a modified +executable containing the modified Library. (It is understood +that the user who changes the contents of definitions files in the +Library will not necessarily be able to recompile the application +to use the modified definitions.)\n\n + +b) Use a suitable shared library mechanism for linking with the +Library. A suitable mechanism is one that (1) uses at run time a +copy of the library already present on the user\'s computer system, +rather than copying library functions into the executable, and (2) +will operate properly with a modified version of the library, if +the user installs one, as long as the modified version is +interface-compatible with the version that the work was made with.\n\n + +c) Accompany the work with a written offer, valid for at +least three years, to give the same user the materials +specified in Subsection 6a, above, for a charge no more +than the cost of performing this distribution.\n\n + +d) If distribution of the work is made by offering access to copy +from a designated place, offer equivalent access to copy the above +specified materials from the same place.\n\n + +e) Verify that the user has already received a copy of these +materials or that you have already sent this user a copy.\n\n + + For an executable, the required form of the \"work that uses the +Library\" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable.\n\n + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute.\n\n + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things:\n\n + +a) Accompany the combined library with a copy of the same work +based on the Library, uncombined with any other library +facilities. This must be distributed under the terms of the +Sections above.\n\n + +b) Give prominent notice with the combined library of the fact +that part of it is a work based on the Library, and explaining +where to find the accompanying uncombined form of the same work.\n\n + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance.\n\n + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it.\n\n + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients\' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License.\n\n + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library.\n\n + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances.\n\n + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice.\n\n + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License.\n\n + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License.\n\n + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns.\n\n + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version\", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation.\n\n + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally.\n\n + +NO WARRANTY\n\n + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + Opus + Modern audio compression for the internet + https://github.com/xiph/opus + Copyright 2001–2011 Xiph.Org, Skype Limited, Octasic, Jean-Marc Valin, Timothy B. Terriberry, CSIRO, Gregory Maxwell, Mark Borgerding, Erik de Castro Lopo + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met:\n\n + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer.\n\n + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution.\n\n + +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission.\n\n + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n + +Opus is subject to the royalty-free patent licenses which are +specified at:\n\n + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ \n\n + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ \n\n + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ + + Sirit + A runtime SPIR-V assembler + https://github.com/ReinUsesLisp/sirit + Copyright © 2019, sirit All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:\n +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer.\n +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution.\n +* Neither the name of the organization nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission.\n\n + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Adreno Tools + A library for applying rootless Adreno GPU driver modifications/replacements + https://github.com/bylaws/libadrenotools + Copyright © 2021, Billy Laws + +BSD 2-Clause License\n\n + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:\n\n + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer.\n\n + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution.\n\n + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index f4bf09a70..727694534 100755 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp @@ -104,7 +104,7 @@ void AudioRenderer::Start(AudioRenderer_Mailbox* mailbox_) { } mailbox = mailbox_; - thread = std::thread(&AudioRenderer::ThreadFunc, this); + thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(stop_token); }); running = true; } @@ -130,7 +130,7 @@ void AudioRenderer::CreateSinkStreams() { } } -void AudioRenderer::ThreadFunc() { +void AudioRenderer::ThreadFunc(std::stop_token stop_token) { static constexpr char name[]{"AudioRenderer"}; MicroProfileOnThreadCreate(name); Common::SetCurrentThreadName(name); @@ -146,7 +146,7 @@ void AudioRenderer::ThreadFunc() { // 0.12 seconds (2304000 / 19200000) constexpr u64 max_process_time{2'304'000ULL}; - while (true) { + while (!stop_token.stop_requested()) { auto message{mailbox->ADSPWaitMessage()}; switch (message) { case RenderMessage::AudioRenderer_Shutdown: @@ -193,7 +193,7 @@ void AudioRenderer::ThreadFunc() { max_time = std::min(command_buffer.time_limit, max_time); command_list_processor.SetProcessTimeMax(max_time); - streams[index]->WaitFreeSpace(); + streams[index]->WaitFreeSpace(stop_token); // Process the command list { diff --git a/src/audio_core/renderer/adsp/audio_renderer.h b/src/audio_core/renderer/adsp/audio_renderer.h index b4fed404f..b08e22dcc 100755 --- a/src/audio_core/renderer/adsp/audio_renderer.h +++ b/src/audio_core/renderer/adsp/audio_renderer.h @@ -177,7 +177,7 @@ private: /** * Main AudioRenderer thread, responsible for processing the command lists. */ - void ThreadFunc(); + void ThreadFunc(std::stop_token stop_token); /** * Creates the streams which will receive the processed samples. @@ -187,7 +187,7 @@ private: /// Core system Core::System& system; /// Main thread - std::thread thread{}; + std::jthread thread{}; /// The current state std::atomic running{}; /// The active mailbox diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index da7b4c846..7856ffeed 100755 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -268,14 +268,15 @@ u64 SinkStream::GetExpectedPlayedSampleCount() { return std::min(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3; } -void SinkStream::WaitFreeSpace() { +void SinkStream::WaitFreeSpace(std::stop_token stop_token) { std::unique_lock lk{release_mutex}; release_cv.wait_for(lk, std::chrono::milliseconds(5), [this]() { return queued_buffers < max_queue_size; }); #ifndef ANDROID // This wait can cause a problematic shutdown hang on Android. if (queued_buffers > max_queue_size + 3) { - release_cv.wait(lk, [this]() { return queued_buffers < max_queue_size; }); + Common::CondvarWait(release_cv, lk, stop_token, + [this] { return queued_buffers < max_queue_size; }); } #endif } diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 1e7658818..7ebe7b7a1 100755 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h @@ -13,6 +13,7 @@ #include "audio_core/common/common.h" #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "common/reader_writer_queue.h" #include "common/ring_buffer.h" #include "common/thread.h" @@ -210,7 +211,7 @@ public: /** * Waits for free space in the sample ring buffer */ - void WaitFreeSpace(); + void WaitFreeSpace(std::stop_token stop_token); protected: /// Core system @@ -252,7 +253,7 @@ private: /// Set via IAudioDevice service calls f32 device_volume{1.0f}; /// Signalled when ring buffer entries are consumed - std::condition_variable release_cv; + std::condition_variable_any release_cv; std::mutex release_mutex; };